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_OTG
29 //#define OMAP3_HSUSB_HOST
31 /* #define OMAP3_HSUSB_DEBUG */
33 #ifdef OMAP3_HSUSB_DEBUG
34 #define TRACE(fmt,...) fprintf(stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
39 #ifdef OMAP3_HSUSB_OTG
41 extern CPUReadMemoryFunc *musb_read[];
42 extern CPUWriteMemoryFunc *musb_write[];
44 struct omap3_hsusb_otg_s {
56 static void omap3_hsusb_otg_save_state(QEMUFile *f, void *opaque)
58 struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
60 qemu_put_be16(f, s->sysconfig);
61 qemu_put_byte(f, s->interfsel);
62 qemu_put_byte(f, s->simenable);
63 qemu_put_byte(f, s->forcestdby);
66 static int omap3_hsusb_otg_load_state(QEMUFile *f, void *opaque,
69 struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
74 s->sysconfig = qemu_get_be16(f);
75 s->interfsel = qemu_get_byte(f);
76 s->simenable = qemu_get_byte(f);
77 s->forcestdby = qemu_get_byte(f);
82 static void omap3_hsusb_otg_reset(struct omap3_hsusb_otg_s *s)
91 static uint32_t omap3_hsusb_otg_readb(void *opaque, target_phys_addr_t addr)
93 struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
95 return musb_read[0](s->musb, addr);
97 return musb_read[0](s->musb, 0x20 + ((addr >> 3 ) & 0x3c));
102 static uint32_t omap3_hsusb_otg_readh(void *opaque, target_phys_addr_t addr)
104 struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
106 return musb_read[1](s->musb, addr);
108 return musb_read[1](s->musb, 0x20 + ((addr >> 3 ) & 0x3c));
113 static uint32_t omap3_hsusb_otg_read(void *opaque, target_phys_addr_t addr)
115 struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
118 return musb_read[2](s->musb, addr);
120 return musb_read[2](s->musb, 0x20 + ((addr >> 3 ) & 0x3c));
123 case 0x400: /* OTG_REVISION */
124 TRACE("OTG_REVISION: 0x%08x", s->rev);
126 case 0x404: /* OTG_SYSCONFIG */
127 TRACE("OTG_SYSCONFIG: 0x%08x", s->sysconfig);
129 case 0x408: /* OTG_SYSSTATUS */
130 TRACE("OTG_SYSSTATUS: 0x00000001");
131 return 1; /* reset finished */
132 case 0x40c: /* OTG_INTERFSEL */
133 TRACE("OTG_INTERFSEL: 0x%08x", s->interfsel);
135 case 0x410: /* OTG_SIMENABLE */
136 TRACE("OTG_SIMENABLE: 0x%08x", s->simenable);
138 case 0x414: /* OTG_FORCESTDBY */
139 TRACE("OTG_FORCESTDBY: 0x%08x", s->forcestdby);
140 return s->forcestdby;
148 static void omap3_hsusb_otg_writeb(void *opaque, target_phys_addr_t addr,
151 struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
154 musb_write[0](s->musb, addr, value);
155 else if (addr < 0x400)
156 musb_write[0](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
161 static void omap3_hsusb_otg_writeh(void *opaque, target_phys_addr_t addr,
164 struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
167 musb_write[1](s->musb, addr, value);
168 else if (addr < 0x400)
169 musb_write[1](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
174 static void omap3_hsusb_otg_write(void *opaque, target_phys_addr_t addr,
177 struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
180 musb_write[2](s->musb, addr, value);
181 else if (addr < 0x400)
182 musb_write[2](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
184 case 0x400: /* OTG_REVISION */
185 case 0x408: /* OTG_SYSSTATUS */
186 OMAP_RO_REGV(addr, value);
188 case 0x404: /* OTG_SYSCONFIG */
189 TRACE("OTG_SYSCONFIG = 0x%08x", value);
190 if (value & 2) /* SOFTRESET */
191 omap3_hsusb_otg_reset(s);
192 s->sysconfig = value & 0x301f;
194 case 0x40c: /* OTG_INTERFSEL */
195 TRACE("OTG_INTERFSEL = 0x%08x", value);
196 s->interfsel = value & 0x3;
198 case 0x410: /* OTG_SIMENABLE */
199 TRACE("OTG_SIMENABLE = 0x%08x", value);
200 cpu_abort(cpu_single_env,
201 "%s: USB simulation mode not supported\n",
204 case 0x414: /* OTG_FORCESTDBY */
205 TRACE("OTG_FORCESTDBY = 0x%08x", value);
206 s->forcestdby = value & 1;
209 OMAP_BAD_REGV(addr, value);
214 static CPUReadMemoryFunc *omap3_hsusb_otg_readfn[] = {
215 omap3_hsusb_otg_readb,
216 omap3_hsusb_otg_readh,
217 omap3_hsusb_otg_read,
220 static CPUWriteMemoryFunc *omap3_hsusb_otg_writefn[] = {
221 omap3_hsusb_otg_writeb,
222 omap3_hsusb_otg_writeh,
223 omap3_hsusb_otg_write,
226 static void omap3_hsusb_musb_core_intr(void *opaque, int source, int level)
228 struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
229 uint32_t value = musb_core_intr_get(s->musb);
230 TRACE("intr 0x%08x, 0x%08x, 0x%08x", source, level, value);
233 TRACE("ignoring VBUS");
235 case musb_set_session:
236 TRACE("ignoring SESSION");
246 qemu_set_irq(s->mc_irq, level);
249 static void omap3_hsusb_otg_init(struct omap_target_agent_s *otg_ta,
252 struct omap3_hsusb_otg_s *s)
255 s->dma_irq = dma_irq;
257 omap_l4_attach(otg_ta, 0, l4_register_io_memory(0,
258 omap3_hsusb_otg_readfn,
259 omap3_hsusb_otg_writefn,
262 s->musb = musb_init(qemu_allocate_irqs(omap3_hsusb_musb_core_intr, s,
264 omap3_hsusb_otg_reset(s);
266 register_savevm("omap3_hsusb_otg", -1, 0,
267 omap3_hsusb_otg_save_state,
268 omap3_hsusb_otg_load_state,
273 #ifdef OMAP3_HSUSB_HOST
274 struct omap3_hsusb_host_s {
278 uint32_t uhh_sysconfig;
279 uint32_t uhh_hostconfig;
280 uint32_t uhh_debug_csr;
283 static void omap3_hsusb_host_save_state(QEMUFile *f, void *opaque)
285 struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
287 qemu_put_be32(f, s->uhh_sysconfig);
288 qemu_put_be32(f, s->uhh_hostconfig);
289 qemu_put_be32(f, s->uhh_debug_csr);
292 static int omap3_hsusb_host_load_state(QEMUFile *f, void *opaque,
295 struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
300 s->uhh_sysconfig = qemu_get_be32(f);
301 s->uhh_hostconfig = qemu_get_be32(f);
302 s->uhh_debug_csr = qemu_get_be32(f);
307 static void omap3_hsusb_host_reset(struct omap3_hsusb_host_s *s)
309 s->uhh_sysconfig = 1;
310 s->uhh_hostconfig = 0x700;
311 s->uhh_debug_csr = 0x20;
312 /* TODO: perform OHCI & EHCI reset */
315 static uint32_t omap3_hsusb_host_read(void *opaque, target_phys_addr_t addr)
317 struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
320 case 0x00: /* UHH_REVISION */
322 case 0x10: /* UHH_SYSCONFIG */
323 return s->uhh_sysconfig;
324 case 0x14: /* UHH_SYSSTATUS */
325 return 0x7; /* EHCI_RESETDONE | OHCI_RESETDONE | RESETDONE */
326 case 0x40: /* UHH_HOSTCONFIG */
327 return s->uhh_hostconfig;
328 case 0x44: /* UHH_DEBUG_CSR */
329 return s->uhh_debug_csr;
337 static void omap3_hsusb_host_write(void *opaque, target_phys_addr_t addr,
340 struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
343 case 0x00: /* UHH_REVISION */
344 case 0x14: /* UHH_SYSSTATUS */
345 OMAP_RO_REGV(addr, value);
347 case 0x10: /* UHH_SYSCONFIG */
348 s->uhh_sysconfig = value & 0x311d;
349 if (value & 2) { /* SOFTRESET */
350 omap3_hsusb_host_reset(s);
353 case 0x40: /* UHH_HOSTCONFIG */
354 s->uhh_hostconfig = value & 0x1f3d;
356 case 0x44: /* UHH_DEBUG_CSR */
357 s->uhh_debug_csr = value & 0xf00ff;
360 OMAP_BAD_REGV(addr, value);
365 static CPUReadMemoryFunc *omap3_hsusb_host_readfn[] = {
366 omap_badwidth_read32,
367 omap_badwidth_read32,
368 omap3_hsusb_host_read,
371 static CPUWriteMemoryFunc *omap3_hsusb_host_writefn[] = {
372 omap_badwidth_write32,
373 omap_badwidth_write32,
374 omap3_hsusb_host_write,
377 static uint32_t omap3_hsusb_ehci_read(void *opaque, target_phys_addr_t addr)
379 TRACE(OMAP_FMT_plx, addr);
383 static void omap3_hsusb_ehci_write(void *opaque, target_phys_addr_t addr,
386 TRACE(OMAP_FMT_plx " = 0x%08x", addr, value);
389 static CPUReadMemoryFunc *omap3_hsusb_ehci_readfn[] = {
390 omap_badwidth_read32,
391 omap_badwidth_read32,
392 omap3_hsusb_ehci_read,
395 static CPUWriteMemoryFunc *omap3_hsusb_ehci_writefn[] = {
396 omap_badwidth_write32,
397 omap_badwidth_write32,
398 omap3_hsusb_ehci_write,
401 static uint32_t omap3_hsusb_tll_read(void *opaque, target_phys_addr_t addr)
403 TRACE(OMAP_FMT_plx, addr);
407 static void omap3_hsusb_tll_write(void *opaque, target_phys_addr_t addr,
410 TRACE(OMAP_FMT_plx " = 0x%08x", addr, value);
413 static CPUReadMemoryFunc *omap3_hsusb_tll_readfn[] = {
414 omap_badwidth_read32,
415 omap_badwidth_read32,
416 omap3_hsusb_tll_read,
419 static CPUWriteMemoryFunc *omap3_hsusb_tll_writefn[] = {
420 omap_badwidth_write32,
421 omap_badwidth_write32,
422 omap3_hsusb_tll_write,
425 static void omap3_hsusb_host_init(struct omap_target_agent_s *host_ta,
426 struct omap_target_agent_s *tll_ta,
430 struct omap3_hsusb_host_s *s)
432 s->ehci_irq = ehci_irq;
433 s->tll_irq = tll_irq;
435 omap_l4_attach(tll_ta, 0, l4_register_io_memory(0,
436 omap3_hsusb_tll_readfn,
437 omap3_hsusb_tll_writefn,
439 omap_l4_attach(host_ta, 0, l4_register_io_memory(0,
440 omap3_hsusb_host_readfn,
441 omap3_hsusb_host_writefn,
443 omap_l4_attach(host_ta, 1, usb_ohci_init_omap(omap_l4_base(host_ta, 1),
444 omap_l4_size(host_ta, 1),
446 omap_l4_attach(host_ta, 2, l4_register_io_memory(0,
447 omap3_hsusb_ehci_readfn,
448 omap3_hsusb_ehci_writefn,
451 omap3_hsusb_host_reset(s);
453 register_savevm("omap3_hsusb_host", -1, 0,
454 omap3_hsusb_host_save_state,
455 omap3_hsusb_host_load_state, s);
459 struct omap3_hsusb_s {
460 #ifdef OMAP3_HSUSB_OTG
461 struct omap3_hsusb_otg_s otg;
463 #ifdef OMAP3_HSUSB_HOST
464 struct omap3_hsusb_host_s host;
468 struct omap3_hsusb_s *omap3_hsusb_init(struct omap_target_agent_s *otg_ta,
469 struct omap_target_agent_s *host_ta,
470 struct omap_target_agent_s *tll_ta,
477 struct omap3_hsusb_s *s = qemu_mallocz(sizeof(struct omap3_hsusb_s));
478 #ifdef OMAP3_HSUSB_HOST
479 omap3_hsusb_host_init(host_ta, tll_ta,
480 ohci_irq, ehci_irq, tll_irq,
483 #ifdef OMAP3_HSUSB_OTG
484 omap3_hsusb_otg_init(otg_ta, mc_irq, dma_irq, &s->otg);