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_read(int access,
93 target_phys_addr_t addr)
95 struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
98 return musb_read[access](s->musb, addr);
100 return musb_read[access](s->musb, 0x20 + ((addr >> 3) & 0x3c));
102 case 0x400: /* OTG_REVISION */
103 TRACE("OTG_REVISION: 0x%08x", s->rev);
105 case 0x404: /* OTG_SYSCONFIG */
106 TRACE("OTG_SYSCONFIG: 0x%08x", s->sysconfig);
108 case 0x408: /* OTG_SYSSTATUS */
109 TRACE("OTG_SYSSTATUS: 0x00000001");
110 return 1; /* reset finished */
111 case 0x40c: /* OTG_INTERFSEL */
112 TRACE("OTG_INTERFSEL: 0x%08x", s->interfsel);
114 case 0x410: /* OTG_SIMENABLE */
115 TRACE("OTG_SIMENABLE: 0x%08x", s->simenable);
117 case 0x414: /* OTG_FORCESTDBY */
118 TRACE("OTG_FORCESTDBY: 0x%08x", s->forcestdby);
119 return s->forcestdby;
127 static void omap3_hsusb_otg_write(int access,
129 target_phys_addr_t addr,
132 struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
135 musb_write[access](s->musb, addr, value);
136 else if (addr < 0x400)
137 musb_write[access](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
139 case 0x400: /* OTG_REVISION */
140 case 0x408: /* OTG_SYSSTATUS */
141 OMAP_RO_REGV(addr, value);
143 case 0x404: /* OTG_SYSCONFIG */
144 TRACE("OTG_SYSCONFIG = 0x%08x", value);
145 if (value & 2) /* SOFTRESET */
146 omap3_hsusb_otg_reset(s);
147 s->sysconfig = value & 0x301f;
149 case 0x40c: /* OTG_INTERFSEL */
150 TRACE("OTG_INTERFSEL = 0x%08x", value);
151 s->interfsel = value & 0x3;
153 case 0x410: /* OTG_SIMENABLE */
154 TRACE("OTG_SIMENABLE = 0x%08x", value);
155 cpu_abort(cpu_single_env,
156 "%s: USB simulation mode not supported\n",
159 case 0x414: /* OTG_FORCESTDBY */
160 TRACE("OTG_FORCESTDBY = 0x%08x", value);
161 s->forcestdby = value & 1;
164 OMAP_BAD_REGV(addr, value);
169 static uint32_t omap3_hsusb_otg_readb(void *opaque, target_phys_addr_t addr)
171 return omap3_hsusb_otg_read(0, opaque, addr);
174 static uint32_t omap3_hsusb_otg_readh(void *opaque, target_phys_addr_t addr)
176 return omap3_hsusb_otg_read(1, opaque, addr);
179 static uint32_t omap3_hsusb_otg_readw(void *opaque, target_phys_addr_t addr)
181 return omap3_hsusb_otg_read(2, opaque, addr);
184 static void omap3_hsusb_otg_writeb(void *opaque, target_phys_addr_t addr,
187 omap3_hsusb_otg_write(0, opaque, addr, value);
190 static void omap3_hsusb_otg_writeh(void *opaque, target_phys_addr_t addr,
193 omap3_hsusb_otg_write(1, opaque, addr, value);
196 static void omap3_hsusb_otg_writew(void *opaque, target_phys_addr_t addr,
199 omap3_hsusb_otg_write(2, opaque, addr, value);
202 static CPUReadMemoryFunc *omap3_hsusb_otg_readfn[] = {
203 omap3_hsusb_otg_readb,
204 omap3_hsusb_otg_readh,
205 omap3_hsusb_otg_readw,
208 static CPUWriteMemoryFunc *omap3_hsusb_otg_writefn[] = {
209 omap3_hsusb_otg_writeb,
210 omap3_hsusb_otg_writeh,
211 omap3_hsusb_otg_writew,
214 static void omap3_hsusb_musb_core_intr(void *opaque, int source, int level)
216 struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
217 /*TRACE("intr 0x%08x, 0x%08x, 0x%08x", source, level, musb_core_intr_get(s->musb));*/
218 qemu_set_irq(s->mc_irq, level);
221 static void omap3_hsusb_otg_init(struct omap_target_agent_s *otg_ta,
224 struct omap3_hsusb_otg_s *s)
227 s->dma_irq = dma_irq;
229 omap_l4_attach(otg_ta, 0, l4_register_io_memory(0,
230 omap3_hsusb_otg_readfn,
231 omap3_hsusb_otg_writefn,
234 s->musb = musb_init(qemu_allocate_irqs(omap3_hsusb_musb_core_intr, s,
236 omap3_hsusb_otg_reset(s);
238 register_savevm("omap3_hsusb_otg", -1, 0,
239 omap3_hsusb_otg_save_state,
240 omap3_hsusb_otg_load_state,
245 #ifdef OMAP3_HSUSB_HOST
246 struct omap3_hsusb_host_s {
250 uint32_t uhh_sysconfig;
251 uint32_t uhh_hostconfig;
252 uint32_t uhh_debug_csr;
253 uint32_t tll_sysconfig;
254 uint32_t insnreg05_ulpi;
257 static void omap3_hsusb_host_save_state(QEMUFile *f, void *opaque)
259 struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
261 qemu_put_be32(f, s->uhh_sysconfig);
262 qemu_put_be32(f, s->uhh_hostconfig);
263 qemu_put_be32(f, s->uhh_debug_csr);
264 qemu_put_be32(f, s->tll_sysconfig);
265 qemu_put_be32(f, s->insnreg05_ulpi);
268 static int omap3_hsusb_host_load_state(QEMUFile *f, void *opaque,
271 struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
276 s->uhh_sysconfig = qemu_get_be32(f);
277 s->uhh_hostconfig = qemu_get_be32(f);
278 s->uhh_debug_csr = qemu_get_be32(f);
279 s->tll_sysconfig = qemu_get_be32(f);
280 s->insnreg05_ulpi = qemu_get_be32(f);
285 static void omap3_hsusb_host_reset(struct omap3_hsusb_host_s *s)
287 s->uhh_sysconfig = 1;
288 s->uhh_hostconfig = 0x700;
289 s->uhh_debug_csr = 0x20;
290 /* TODO: perform OHCI & EHCI reset */
291 s->tll_sysconfig = 1;
294 static uint32_t omap3_hsusb_host_read(void *opaque, target_phys_addr_t addr)
296 struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
297 TRACE(OMAP_FMT_plx, addr);
300 case 0x00: /* UHH_REVISION */
302 case 0x10: /* UHH_SYSCONFIG */
303 return s->uhh_sysconfig;
304 case 0x14: /* UHH_SYSSTATUS */
305 return 0x7; /* EHCI_RESETDONE | OHCI_RESETDONE | RESETDONE */
306 case 0x40: /* UHH_HOSTCONFIG */
307 return s->uhh_hostconfig;
308 case 0x44: /* UHH_DEBUG_CSR */
309 return s->uhh_debug_csr;
317 static void omap3_hsusb_host_write(void *opaque, target_phys_addr_t addr,
320 struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
321 TRACE(OMAP_FMT_plx " = 0x%08x", addr, value);
324 case 0x00: /* UHH_REVISION */
325 case 0x14: /* UHH_SYSSTATUS */
326 OMAP_RO_REGV(addr, value);
328 case 0x10: /* UHH_SYSCONFIG */
329 s->uhh_sysconfig = value & 0x311d;
330 if (value & 2) { /* SOFTRESET */
331 omap3_hsusb_host_reset(s);
334 case 0x40: /* UHH_HOSTCONFIG */
335 s->uhh_hostconfig = value & 0x1f3d;
337 case 0x44: /* UHH_DEBUG_CSR */
338 s->uhh_debug_csr = value & 0xf00ff;
341 OMAP_BAD_REGV(addr, value);
346 static CPUReadMemoryFunc *omap3_hsusb_host_readfn[] = {
347 omap_badwidth_read32,
348 omap_badwidth_read32,
349 omap3_hsusb_host_read,
352 static CPUWriteMemoryFunc *omap3_hsusb_host_writefn[] = {
353 omap_badwidth_write32,
354 omap_badwidth_write32,
355 omap3_hsusb_host_write,
358 static uint32_t omap3_hsusb_ehci_read(void *opaque, target_phys_addr_t addr)
360 struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
361 TRACE(OMAP_FMT_plx, addr);
363 case 0xa4: /* INSNREG05_ULPI */
364 return s->insnreg05_ulpi;
371 static void omap3_hsusb_ehci_write(void *opaque, target_phys_addr_t addr,
374 struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
375 TRACE(OMAP_FMT_plx " = 0x%08x", addr, value);
378 case 0xa4: /* INSNREG05_ULPI */
379 s->insnreg05_ulpi = value & 0xF0000000;
385 static CPUReadMemoryFunc *omap3_hsusb_ehci_readfn[] = {
386 omap_badwidth_read32,
387 omap_badwidth_read32,
388 omap3_hsusb_ehci_read,
391 static CPUWriteMemoryFunc *omap3_hsusb_ehci_writefn[] = {
392 omap_badwidth_write32,
393 omap_badwidth_write32,
394 omap3_hsusb_ehci_write,
397 static uint32_t omap3_hsusb_tll_read(void *opaque, target_phys_addr_t addr)
399 struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
400 TRACE(OMAP_FMT_plx, addr);
403 case 0x00: /* USBTLL_REVISION */
405 case 0x10: /* USBTLL_SYSCONFIG */
406 return s->tll_sysconfig;
407 case 0x14: /* USBTLL_SYSSTATUS */
408 return 0x1; /* RESETDONE */
409 case 0x18: /* USBTLL_IRQSTATUS */
411 case 0x1C: /* USBTLL_IRQENABLE */
419 static void omap3_hsusb_tll_write(void *opaque, target_phys_addr_t addr,
422 struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
423 TRACE(OMAP_FMT_plx " = 0x%08x", addr, value);
426 case 0x00: /* USBTLL_REVISION */
427 case 0x14: /* USBTLL_SYSSTATUS */
428 OMAP_RO_REGV(addr, value);
429 case 0x10: /* USBTLL_SYSCONFIG */
430 s->tll_sysconfig = value & 0xFFFFFEE0;;
432 OMAP_BAD_REGV(addr, value);
437 static CPUReadMemoryFunc *omap3_hsusb_tll_readfn[] = {
438 omap_badwidth_read32,
439 omap_badwidth_read32,
440 omap3_hsusb_tll_read,
443 static CPUWriteMemoryFunc *omap3_hsusb_tll_writefn[] = {
444 omap_badwidth_write32,
445 omap_badwidth_write32,
446 omap3_hsusb_tll_write,
449 static void omap3_hsusb_host_init(struct omap_target_agent_s *host_ta,
450 struct omap_target_agent_s *tll_ta,
454 struct omap3_hsusb_host_s *s)
456 s->ehci_irq = ehci_irq;
457 s->tll_irq = tll_irq;
459 omap_l4_attach(tll_ta, 0, l4_register_io_memory(0,
460 omap3_hsusb_tll_readfn,
461 omap3_hsusb_tll_writefn,
463 omap_l4_attach(host_ta, 0, l4_register_io_memory(0,
464 omap3_hsusb_host_readfn,
465 omap3_hsusb_host_writefn,
467 /* omap_l4_attach(host_ta, 1, usb_ohci_init_omap(omap_l4_base(host_ta, 1),
468 omap_l4_size(host_ta, 1),
470 omap_l4_attach(host_ta, 2, l4_register_io_memory(0,
471 omap3_hsusb_ehci_readfn,
472 omap3_hsusb_ehci_writefn,
475 omap3_hsusb_host_reset(s);
477 register_savevm("omap3_hsusb_host", -1, 0,
478 omap3_hsusb_host_save_state,
479 omap3_hsusb_host_load_state, s);
483 struct omap3_hsusb_s {
484 #ifdef OMAP3_HSUSB_OTG
485 struct omap3_hsusb_otg_s otg;
487 #ifdef OMAP3_HSUSB_HOST
488 struct omap3_hsusb_host_s host;
492 struct omap3_hsusb_s *omap3_hsusb_init(struct omap_target_agent_s *otg_ta,
493 struct omap_target_agent_s *host_ta,
494 struct omap_target_agent_s *tll_ta,
501 struct omap3_hsusb_s *s = qemu_mallocz(sizeof(struct omap3_hsusb_s));
502 #ifdef OMAP3_HSUSB_HOST
503 omap3_hsusb_host_init(host_ta, tll_ta,
504 ohci_irq, ehci_irq, tll_irq,
507 #ifdef OMAP3_HSUSB_OTG
508 omap3_hsusb_otg_init(otg_ta, mc_irq, dma_irq, &s->otg);