2 * TI OMAP3 High-Speed USB Host and OTG Controller emulation.
4 * Copyright (C) 2009 Nokia Corporation
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 or
9 * (at your option) version 3 of the License.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "qemu-common.h"
21 #include "qemu-timer.h"
28 #define OMAP3_HSUSB_DEBUG
30 #ifdef OMAP3_HSUSB_DEBUG
31 #define TRACE(fmt,...) fprintf(stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
37 extern CPUReadMemoryFunc *musb_read[];
38 extern CPUWriteMemoryFunc *musb_write[];
40 struct omap3_hsusb_otg_s {
52 static void omap3_hsusb_otg_save_state(QEMUFile *f, void *opaque)
54 struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
56 qemu_put_be16(f, s->sysconfig);
57 qemu_put_byte(f, s->interfsel);
58 qemu_put_byte(f, s->simenable);
59 qemu_put_byte(f, s->forcestdby);
62 static int omap3_hsusb_otg_load_state(QEMUFile *f, void *opaque, int version_id)
64 struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
69 s->sysconfig = qemu_get_be16(f);
70 s->interfsel = qemu_get_byte(f);
71 s->simenable = qemu_get_byte(f);
72 s->forcestdby = qemu_get_byte(f);
77 static void omap3_hsusb_otg_reset(struct omap3_hsusb_otg_s *s)
86 static uint32_t omap3_hsusb_otg_readb(void *opaque, target_phys_addr_t addr)
88 struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
90 return musb_read[0](s->musb, addr);
92 return musb_read[0](s->musb, 0x20 + ((addr >> 3 ) & 0x3c));
97 static uint32_t omap3_hsusb_otg_readh(void *opaque, target_phys_addr_t addr)
99 struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
101 return musb_read[1](s->musb, addr);
103 return musb_read[1](s->musb, 0x20 + ((addr >> 3 ) & 0x3c));
108 static uint32_t omap3_hsusb_otg_read(void *opaque, target_phys_addr_t addr)
110 struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
113 return musb_read[2](s->musb, addr);
115 return musb_read[2](s->musb, 0x20 + ((addr >> 3 ) & 0x3c));
118 case 0x400: /* OTG_REVISION */
119 TRACE("OTG_REVISION: 0x%08x", s->rev);
121 case 0x404: /* OTG_SYSCONFIG */
122 TRACE("OTG_SYSCONFIG: 0x%08x", s->sysconfig);
124 case 0x408: /* OTG_SYSSTATUS */
125 TRACE("OTG_SYSSTATUS: 0x00000001");
126 return 1; /* reset finished */
127 case 0x40c: /* OTG_INTERFSEL */
128 TRACE("OTG_INTERFSEL: 0x%08x", s->interfsel);
130 case 0x410: /* OTG_SIMENABLE */
131 TRACE("OTG_SIMENABLE: 0x%08x", s->simenable);
133 case 0x414: /* OTG_FORCESTDBY */
134 TRACE("OTG_FORCESTDBY: 0x%08x", s->forcestdby);
135 return s->forcestdby;
143 static void omap3_hsusb_otg_writeb(void *opaque, target_phys_addr_t addr,
146 struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
149 musb_write[0](s->musb, addr, value);
150 else if (addr < 0x400)
151 musb_write[0](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
156 static void omap3_hsusb_otg_writeh(void *opaque, target_phys_addr_t addr,
159 struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
162 musb_write[1](s->musb, addr, value);
163 else if (addr < 0x400)
164 musb_write[1](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
169 static void omap3_hsusb_otg_write(void *opaque, target_phys_addr_t addr,
172 struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
175 musb_write[2](s->musb, addr, value);
176 else if (addr < 0x400)
177 musb_write[2](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
179 case 0x400: /* OTG_REVISION */
180 case 0x408: /* OTG_SYSSTATUS */
181 OMAP_RO_REGV(addr, value);
183 case 0x404: /* OTG_SYSCONFIG */
184 TRACE("OTG_SYSCONFIG = 0x%08x", value);
185 if (value & 2) /* SOFTRESET */
186 omap3_hsusb_otg_reset(s);
187 s->sysconfig = value & 0x301f;
189 case 0x40c: /* OTG_INTERFSEL */
190 TRACE("OTG_INTERFSEL = 0x%08x", value);
191 s->interfsel = value & 0x3;
193 case 0x410: /* OTG_SIMENABLE */
194 TRACE("OTG_SIMENABLE = 0x%08x", value);
195 cpu_abort(cpu_single_env, "%s: USB simulation mode not supported\n",
198 case 0x414: /* OTG_FORCESTDBY */
199 TRACE("OTG_FORCESTDBY = 0x%08x", value);
200 s->forcestdby = value & 1;
203 OMAP_BAD_REGV(addr, value);
208 static CPUReadMemoryFunc *omap3_hsusb_otg_readfn[] = {
209 omap3_hsusb_otg_readb,
210 omap3_hsusb_otg_readh,
211 omap3_hsusb_otg_read,
214 static CPUWriteMemoryFunc *omap3_hsusb_otg_writefn[] = {
215 omap3_hsusb_otg_writeb,
216 omap3_hsusb_otg_writeh,
217 omap3_hsusb_otg_write,
220 static void omap3_hsusb_musb_core_intr(void *opaque, int source, int level)
222 struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
223 uint32_t value = musb_core_intr_get(s->musb);
224 TRACE("intr 0x%08x, 0x%08x, 0x%08x", source, level, value);
227 TRACE("ignoring VBUS");
229 case musb_set_session:
230 TRACE("ignoring SESSION");
240 qemu_set_irq(s->mc_irq, level);
243 static void omap3_hsusb_otg_init(struct omap_target_agent_s *otg_ta,
246 struct omap3_hsusb_otg_s *s)
249 s->dma_irq = dma_irq;
251 omap_l4_attach(otg_ta, 0, l4_register_io_memory(0, omap3_hsusb_otg_readfn,
252 omap3_hsusb_otg_writefn, s));
254 s->musb = musb_init(qemu_allocate_irqs(omap3_hsusb_musb_core_intr, s, __musb_irq_max));
255 omap3_hsusb_otg_reset(s);
257 register_savevm("omap3_hsusb_otg", -1, 0,
258 omap3_hsusb_otg_save_state,
259 omap3_hsusb_otg_load_state,
263 struct omap3_hsusb_host_s {
267 uint32_t uhh_sysconfig;
268 uint32_t uhh_hostconfig;
269 uint32_t uhh_debug_csr;
272 static void omap3_hsusb_host_reset(struct omap3_hsusb_host_s *s)
274 s->uhh_sysconfig = 1;
275 s->uhh_hostconfig = 0x700;
276 s->uhh_debug_csr = 0x20;
277 /* TODO: perform OHCI & EHCI reset */
280 static uint32_t omap3_hsusb_host_read(void *opaque, target_phys_addr_t addr)
282 struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
285 case 0x00: /* UHH_REVISION */
287 case 0x10: /* UHH_SYSCONFIG */
288 return s->uhh_sysconfig;
289 case 0x14: /* UHH_SYSSTATUS */
290 return 0x7; /* EHCI_RESETDONE | OHCI_RESETDONE | RESETDONE */
291 case 0x40: /* UHH_HOSTCONFIG */
292 return s->uhh_hostconfig;
293 case 0x44: /* UHH_DEBUG_CSR */
294 return s->uhh_debug_csr;
302 static void omap3_hsusb_host_write(void *opaque, target_phys_addr_t addr,
305 struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
308 case 0x00: /* UHH_REVISION */
309 case 0x14: /* UHH_SYSSTATUS */
310 OMAP_RO_REGV(addr, value);
312 case 0x10: /* UHH_SYSCONFIG */
313 s->uhh_sysconfig = value & 0x311d;
314 if (value & 2) { /* SOFTRESET */
315 omap3_hsusb_host_reset(s);
318 case 0x40: /* UHH_HOSTCONFIG */
319 s->uhh_hostconfig = value & 0x1f3d;
321 case 0x44: /* UHH_DEBUG_CSR */
322 s->uhh_debug_csr = value & 0xf00ff;
325 OMAP_BAD_REGV(addr, value);
330 static CPUReadMemoryFunc *omap3_hsusb_host_readfn[] = {
331 omap_badwidth_read32,
332 omap_badwidth_read32,
333 omap3_hsusb_host_read,
336 static CPUWriteMemoryFunc *omap3_hsusb_host_writefn[] = {
337 omap_badwidth_write32,
338 omap_badwidth_write32,
339 omap3_hsusb_host_write,
342 static uint32_t omap3_hsusb_ehci_read(void *opaque, target_phys_addr_t addr)
344 TRACE(OMAP_FMT_plx, addr);
348 static void omap3_hsusb_ehci_write(void *opaque, target_phys_addr_t addr,
351 TRACE(OMAP_FMT_plx " = 0x%08x", addr, value);
354 static CPUReadMemoryFunc *omap3_hsusb_ehci_readfn[] = {
355 omap_badwidth_read32,
356 omap_badwidth_read32,
357 omap3_hsusb_ehci_read,
360 static CPUWriteMemoryFunc *omap3_hsusb_ehci_writefn[] = {
361 omap_badwidth_write32,
362 omap_badwidth_write32,
363 omap3_hsusb_ehci_write,
366 static uint32_t omap3_hsusb_tll_read(void *opaque, target_phys_addr_t addr)
368 TRACE(OMAP_FMT_plx, addr);
372 static void omap3_hsusb_tll_write(void *opaque, target_phys_addr_t addr,
375 TRACE(OMAP_FMT_plx " = 0x%08x", addr, value);
378 static CPUReadMemoryFunc *omap3_hsusb_tll_readfn[] = {
379 omap_badwidth_read32,
380 omap_badwidth_read32,
381 omap3_hsusb_tll_read,
384 static CPUWriteMemoryFunc *omap3_hsusb_tll_writefn[] = {
385 omap_badwidth_write32,
386 omap_badwidth_write32,
387 omap3_hsusb_tll_write,
390 static void omap3_hsusb_host_init(struct omap_target_agent_s *host_ta,
391 struct omap_target_agent_s *tll_ta,
395 struct omap3_hsusb_host_s *s)
397 s->ehci_irq = ehci_irq;
398 s->tll_irq = tll_irq;
400 omap_l4_attach(tll_ta, 0, l4_register_io_memory(0,
401 omap3_hsusb_tll_readfn,
402 omap3_hsusb_tll_writefn,
404 omap_l4_attach(host_ta, 0, l4_register_io_memory(0,
405 omap3_hsusb_host_readfn,
406 omap3_hsusb_host_writefn,
408 omap_l4_attach(host_ta, 1, usb_ohci_init_omap(omap_l4_base(host_ta, 1),
409 omap_l4_size(host_ta, 1),
411 omap_l4_attach(host_ta, 2, l4_register_io_memory(0,
412 omap3_hsusb_ehci_readfn,
413 omap3_hsusb_ehci_writefn,
416 omap3_hsusb_host_reset(s);
419 struct omap3_hsusb_s {
420 struct omap3_hsusb_otg_s otg;
421 struct omap3_hsusb_host_s host;
424 struct omap3_hsusb_s *omap3_hsusb_init(struct omap_target_agent_s *otg_ta,
425 struct omap_target_agent_s *host_ta,
426 struct omap_target_agent_s *tll_ta,
433 struct omap3_hsusb_s *s = qemu_mallocz(sizeof(struct omap3_hsusb_s));
434 omap3_hsusb_otg_init(otg_ta, mc_irq, dma_irq, &s->otg);
435 omap3_hsusb_host_init(host_ta, tll_ta, ohci_irq, ehci_irq, tll_irq, &s->host);