blob: 7621a3c0f793a0e2bb0eaa8448ba743a010244cf [file] [log] [blame]
Fathi Boudra07d16a92012-12-25 16:58:29 +02001/*
2 * TI OMAP3 High-Speed USB Host and OTG Controller emulation.
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 *
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) any later version of the License.
10 *
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.
15 *
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.
19 */
20#include "qemu-common.h"
21#include "qemu-timer.h"
22#include "usb.h"
23#include "omap.h"
24#include "irq.h"
25#include "devices.h"
26#include "hw.h"
27#include "sysbus.h"
28
29//#define OMAP3_HSUSB_DEBUG
30
31#ifdef OMAP3_HSUSB_DEBUG
32#define TRACE(fmt,...) fprintf(stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
33#else
34#define TRACE(...)
35#endif
36
37/* usb-musb.c */
38extern CPUReadMemoryFunc *musb_read[];
39extern CPUWriteMemoryFunc *musb_write[];
40
41typedef struct omap3_hsusb_otg_s {
42 SysBusDevice busdev;
43 MemoryRegion iomem;
44 qemu_irq mc_irq;
45 qemu_irq dma_irq;
46 qemu_irq stdby_irq;
47 MUSBState *musb;
48
49 uint8_t rev;
50 uint16_t sysconfig;
51 uint8_t interfsel;
52 uint8_t simenable;
53 uint8_t forcestdby;
54} OMAP3HSUSBOTGState;
55
56static const VMStateDescription vmstate_omap3_hsusb_otg = {
57 .name = "omap3_hsusb_otg",
58 .version_id = 1,
59 .minimum_version_id = 1,
60 .minimum_version_id_old = 1,
61 .fields = (VMStateField[]) {
62 VMSTATE_UINT16(sysconfig, OMAP3HSUSBOTGState),
63 VMSTATE_UINT8(interfsel, OMAP3HSUSBOTGState),
64 VMSTATE_UINT8(simenable, OMAP3HSUSBOTGState),
65 VMSTATE_UINT8(forcestdby, OMAP3HSUSBOTGState),
66 VMSTATE_END_OF_LIST()
67 }
68};
69
70static void omap3_hsusb_otg_stdby_update(OMAP3HSUSBOTGState *s)
71{
72 if (s->stdby_irq) {
73 qemu_set_irq(s->stdby_irq, s->forcestdby);
74 }
75}
76
77static void omap3_hsusb_otg_reset(DeviceState *dev)
78{
79 OMAP3HSUSBOTGState *s = FROM_SYSBUS(OMAP3HSUSBOTGState,
80 sysbus_from_qdev(dev));
81 s->rev = 0x33;
82 s->sysconfig = 0;
83 s->interfsel = 0x1;
84 s->simenable = 0;
85 s->forcestdby = 1;
86 musb_reset(s->musb);
87 omap3_hsusb_otg_stdby_update(s);
88}
89
90static uint32_t omap3_hsusb_otg_read(int access,
91 void *opaque,
92 target_phys_addr_t addr)
93{
94 OMAP3HSUSBOTGState *s = opaque;
95
96 if (addr < 0x200)
97 return musb_read[access](s->musb, addr);
98 if (addr < 0x400)
99 return musb_read[access](s->musb, 0x20 + ((addr >> 3) & 0x3c));
100 switch (addr) {
101 case 0x400: /* OTG_REVISION */
102 TRACE("OTG_REVISION: 0x%08x", s->rev);
103 return s->rev;
104 case 0x404: /* OTG_SYSCONFIG */
105 TRACE("OTG_SYSCONFIG: 0x%08x", s->sysconfig);
106 return s->sysconfig;
107 case 0x408: /* OTG_SYSSTATUS */
108 TRACE("OTG_SYSSTATUS: 0x00000001");
109 return 1; /* reset finished */
110 case 0x40c: /* OTG_INTERFSEL */
111 TRACE("OTG_INTERFSEL: 0x%08x", s->interfsel);
112 return s->interfsel;
113 case 0x410: /* OTG_SIMENABLE */
114 TRACE("OTG_SIMENABLE: 0x%08x", s->simenable);
115 return s->simenable;
116 case 0x414: /* OTG_FORCESTDBY */
117 TRACE("OTG_FORCESTDBY: 0x%08x", s->forcestdby);
118 return s->forcestdby;
119 default:
120 break;
121 }
122 OMAP_BAD_REG(addr);
123 return 0;
124}
125
126static void omap3_hsusb_otg_write(int access,
127 void *opaque,
128 target_phys_addr_t addr,
129 uint32_t value)
130{
131 OMAP3HSUSBOTGState *s = opaque;
132
133 if (addr < 0x200)
134 musb_write[access](s->musb, addr, value);
135 else if (addr < 0x400)
136 musb_write[access](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
137 else switch (addr) {
138 case 0x400: /* OTG_REVISION */
139 case 0x408: /* OTG_SYSSTATUS */
140 OMAP_RO_REG(addr);
141 break;
142 case 0x404: /* OTG_SYSCONFIG */
143 TRACE("OTG_SYSCONFIG = 0x%08x", value);
144 if (value & 2) /* SOFTRESET */
145 omap3_hsusb_otg_reset(&s->busdev.qdev);
146 s->sysconfig = value & 0x301f;
147 break;
148 case 0x40c: /* OTG_INTERFSEL */
149 TRACE("OTG_INTERFSEL = 0x%08x", value);
150 s->interfsel = value & 0x3;
151 break;
152 case 0x410: /* OTG_SIMENABLE */
153 TRACE("OTG_SIMENABLE = 0x%08x", value);
154 cpu_abort(cpu_single_env,
155 "%s: USB simulation mode not supported\n",
156 __FUNCTION__);
157 break;
158 case 0x414: /* OTG_FORCESTDBY */
159 TRACE("OTG_FORCESTDBY = 0x%08x", value);
160 s->forcestdby = value & 1;
161 omap3_hsusb_otg_stdby_update(s);
162 break;
163 default:
164 OMAP_BAD_REG(addr);
165 break;
166 }
167}
168
169static uint32_t omap3_hsusb_otg_readb(void *opaque, target_phys_addr_t addr)
170{
171 return omap3_hsusb_otg_read(0, opaque, addr);
172}
173
174static uint32_t omap3_hsusb_otg_readh(void *opaque, target_phys_addr_t addr)
175{
176 return omap3_hsusb_otg_read(1, opaque, addr);
177}
178
179static uint32_t omap3_hsusb_otg_readw(void *opaque, target_phys_addr_t addr)
180{
181 return omap3_hsusb_otg_read(2, opaque, addr);
182}
183
184static void omap3_hsusb_otg_writeb(void *opaque, target_phys_addr_t addr,
185 uint32_t value)
186{
187 omap3_hsusb_otg_write(0, opaque, addr, value);
188}
189
190static void omap3_hsusb_otg_writeh(void *opaque, target_phys_addr_t addr,
191 uint32_t value)
192{
193 omap3_hsusb_otg_write(1, opaque, addr, value);
194}
195
196static void omap3_hsusb_otg_writew(void *opaque, target_phys_addr_t addr,
197 uint32_t value)
198{
199 omap3_hsusb_otg_write(2, opaque, addr, value);
200}
201
202static const MemoryRegionOps omap3_hsusb_otg_ops = {
203 .old_mmio = {
204 .read = {
205 omap3_hsusb_otg_readb,
206 omap3_hsusb_otg_readh,
207 omap3_hsusb_otg_readw,
208 },
209 .write = {
210 omap3_hsusb_otg_writeb,
211 omap3_hsusb_otg_writeh,
212 omap3_hsusb_otg_writew,
213 },
214 },
215 .endianness = DEVICE_NATIVE_ENDIAN,
216};
217
218static void omap3_hsusb_musb_core_intr(void *opaque, int source, int level)
219{
220 OMAP3HSUSBOTGState *s = opaque;
221 /*TRACE("intr 0x%08x, 0x%08x, 0x%08x", source, level, musb_core_intr_get(s->musb));*/
222 qemu_set_irq(s->mc_irq, level);
223}
224
225static int omap3_hsusb_otg_init(SysBusDevice *dev)
226{
227 OMAP3HSUSBOTGState *s = FROM_SYSBUS(OMAP3HSUSBOTGState, dev);
228 sysbus_init_irq(dev, &s->mc_irq);
229 sysbus_init_irq(dev, &s->dma_irq);
230 sysbus_init_irq(dev, &s->stdby_irq);
231 memory_region_init_io(&s->iomem, &omap3_hsusb_otg_ops, s,
232 "omap3_hsusb_otg", 0x1000);
233 sysbus_init_mmio(dev, &s->iomem);
234 qdev_init_gpio_in(&dev->qdev, omap3_hsusb_musb_core_intr, musb_irq_max);
235 s->musb = musb_init(&dev->qdev, 0);
236 vmstate_register(&dev->qdev, -1, &vmstate_omap3_hsusb_otg, s);
237 return 0;
238}
239
240static void omap3_hsusb_otg_class_init(ObjectClass *klass, void *data)
241{
242 DeviceClass *dc = DEVICE_CLASS(klass);
243 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
244 k->init = omap3_hsusb_otg_init;
245 dc->reset = omap3_hsusb_otg_reset;
246}
247
248static TypeInfo omap3_hsusb_otg_info = {
249 .name = "omap3_hsusb_otg",
250 .parent = TYPE_SYS_BUS_DEVICE,
251 .instance_size = sizeof(OMAP3HSUSBOTGState),
252 .class_init = omap3_hsusb_otg_class_init,
253};
254
255typedef struct omap3_hsusb_host_s {
256 SysBusDevice busdev;
257 MemoryRegion tll_iomem;
258 MemoryRegion host_iomem;
259 MemoryRegion ehci_iomem;
260 qemu_irq ehci_irq;
261 qemu_irq tll_irq;
262
263 uint32_t uhh_sysconfig;
264 uint32_t uhh_hostconfig;
265 uint32_t uhh_debug_csr;
266 uint32_t tll_sysconfig;
267 uint32_t insnreg05_ulpi;
268} OMAP3HSUSBHostState;
269
270static const VMStateDescription vmstate_omap3_hsusb_host = {
271 .name = "omap3_hsusb_host",
272 .version_id = 1,
273 .minimum_version_id = 1,
274 .minimum_version_id_old = 1,
275 .fields = (VMStateField[]) {
276 VMSTATE_UINT32(uhh_sysconfig, OMAP3HSUSBHostState),
277 VMSTATE_UINT32(uhh_hostconfig, OMAP3HSUSBHostState),
278 VMSTATE_UINT32(uhh_debug_csr, OMAP3HSUSBHostState),
279 VMSTATE_UINT32(tll_sysconfig, OMAP3HSUSBHostState),
280 VMSTATE_UINT32(insnreg05_ulpi, OMAP3HSUSBHostState),
281 VMSTATE_END_OF_LIST()
282 }
283};
284
285static void omap3_hsusb_host_reset(DeviceState *dev)
286{
287 OMAP3HSUSBHostState *s = FROM_SYSBUS(OMAP3HSUSBHostState,
288 sysbus_from_qdev(dev));
289 s->uhh_sysconfig = 1;
290 s->uhh_hostconfig = 0x700;
291 s->uhh_debug_csr = 0x20;
292 /* TODO: perform OHCI & EHCI reset */
293 s->tll_sysconfig = 1;
294}
295
296static uint32_t omap3_hsusb_host_read(void *opaque, target_phys_addr_t addr)
297{
298 OMAP3HSUSBHostState *s = opaque;
299 TRACE(OMAP_FMT_plx, addr);
300
301 switch (addr) {
302 case 0x00: /* UHH_REVISION */
303 return 0x10;
304 case 0x10: /* UHH_SYSCONFIG */
305 return s->uhh_sysconfig;
306 case 0x14: /* UHH_SYSSTATUS */
307 return 0x7; /* EHCI_RESETDONE | OHCI_RESETDONE | RESETDONE */
308 case 0x40: /* UHH_HOSTCONFIG */
309 return s->uhh_hostconfig;
310 case 0x44: /* UHH_DEBUG_CSR */
311 return s->uhh_debug_csr;
312 default:
313 break;
314 }
315 OMAP_BAD_REG(addr);
316 return 0;
317}
318
319static void omap3_hsusb_host_write(void *opaque, target_phys_addr_t addr,
320 uint32_t value)
321{
322 OMAP3HSUSBHostState *s = opaque;
323 TRACE(OMAP_FMT_plx " = 0x%08x", addr, value);
324
325 switch (addr) {
326 case 0x00: /* UHH_REVISION */
327 case 0x14: /* UHH_SYSSTATUS */
328 OMAP_RO_REG(addr);
329 break;
330 case 0x10: /* UHH_SYSCONFIG */
331 s->uhh_sysconfig = value & 0x311d;
332 if (value & 2) { /* SOFTRESET */
333 omap3_hsusb_host_reset(&s->busdev.qdev);
334 }
335 break;
336 case 0x40: /* UHH_HOSTCONFIG */
337 s->uhh_hostconfig = value & 0x1f3d;
338 break;
339 case 0x44: /* UHH_DEBUG_CSR */
340 s->uhh_debug_csr = value & 0xf00ff;
341 break;
342 default:
343 OMAP_BAD_REG(addr);
344 break;
345 }
346}
347
348static const MemoryRegionOps omap3_hsusb_host_ops = {
349 .old_mmio = {
350 .read = {
351 omap_badwidth_read32,
352 omap_badwidth_read32,
353 omap3_hsusb_host_read,
354 },
355 .write = {
356 omap_badwidth_write32,
357 omap_badwidth_write32,
358 omap3_hsusb_host_write,
359 },
360 },
361 .endianness = DEVICE_NATIVE_ENDIAN,
362};
363
364static uint32_t omap3_hsusb_ehci_read(void *opaque, target_phys_addr_t addr)
365{
366 OMAP3HSUSBHostState *s = opaque;
367 TRACE(OMAP_FMT_plx, addr);
368 switch (addr) {
369 case 0xa4: /* INSNREG05_ULPI */
370 return s->insnreg05_ulpi;
371 default:
372 break;
373 }
374 return 0;
375}
376
377static void omap3_hsusb_ehci_write(void *opaque, target_phys_addr_t addr,
378 uint32_t value)
379{
380 OMAP3HSUSBHostState *s = opaque;
381 TRACE(OMAP_FMT_plx " = 0x%08x", addr, value);
382
383 switch (addr) {
384 case 0xa4: /* INSNREG05_ULPI */
385 s->insnreg05_ulpi = value & 0xF0000000;
386 default:
387 break;
388 }
389}
390
391static const MemoryRegionOps omap3_hsusb_ehci_ops = {
392 .old_mmio = {
393 .read = {
394 omap_badwidth_read32,
395 omap_badwidth_read32,
396 omap3_hsusb_ehci_read,
397 },
398 .write = {
399 omap_badwidth_write32,
400 omap_badwidth_write32,
401 omap3_hsusb_ehci_write,
402 },
403 },
404 .endianness = DEVICE_NATIVE_ENDIAN,
405};
406
407static uint32_t omap3_hsusb_tll_read(void *opaque, target_phys_addr_t addr)
408{
409 OMAP3HSUSBHostState *s = opaque;
410 TRACE(OMAP_FMT_plx, addr);
411
412 switch (addr) {
413 case 0x00: /* USBTLL_REVISION */
414 return 0x1;
415 case 0x10: /* USBTLL_SYSCONFIG */
416 return s->tll_sysconfig;
417 case 0x14: /* USBTLL_SYSSTATUS */
418 return 0x1; /* RESETDONE */
419 case 0x18: /* USBTLL_IRQSTATUS */
420 return 0;
421 case 0x1C: /* USBTLL_IRQENABLE */
422 return 0;
423 default:
424 break;
425 }
426 return 0;
427}
428
429static void omap3_hsusb_tll_write(void *opaque, target_phys_addr_t addr,
430 uint32_t value)
431{
432 OMAP3HSUSBHostState *s = opaque;
433 TRACE(OMAP_FMT_plx " = 0x%08x", addr, value);
434
435 switch (addr) {
436 case 0x00: /* USBTLL_REVISION */
437 case 0x14: /* USBTLL_SYSSTATUS */
438 OMAP_RO_REG(addr);
439 break;
440 case 0x10: /* USBTLL_SYSCONFIG */
441 s->tll_sysconfig = value & 0xFFFFFEE0;;
442 break;
443 default:
444 OMAP_BAD_REG(addr);
445 break;
446 }
447}
448
449static const MemoryRegionOps omap3_hsusb_tll_ops = {
450 .old_mmio = {
451 .read = {
452 omap_badwidth_read32,
453 omap_badwidth_read32,
454 omap3_hsusb_tll_read,
455 },
456 .write = {
457 omap_badwidth_write32,
458 omap_badwidth_write32,
459 omap3_hsusb_tll_write,
460 },
461 },
462 .endianness = DEVICE_NATIVE_ENDIAN,
463};
464
465static int omap3_hsusb_host_init(SysBusDevice *dev)
466{
467 OMAP3HSUSBHostState *s = FROM_SYSBUS(OMAP3HSUSBHostState, dev);
468 sysbus_init_irq(dev, &s->ehci_irq);
469 sysbus_init_irq(dev, &s->tll_irq);
470
471 memory_region_init_io(&s->tll_iomem, &omap3_hsusb_tll_ops, s,
472 "omap_usb.tll", 0x1000);
473 memory_region_init_io(&s->host_iomem, &omap3_hsusb_host_ops, s,
474 "omap_usb.tll", 0x400);
475 memory_region_init_io(&s->ehci_iomem, &omap3_hsusb_ehci_ops, s,
476 "omap_usb.tll", 0x400);
477 sysbus_init_mmio(dev, &s->tll_iomem);
478 sysbus_init_mmio(dev, &s->host_iomem);
479 sysbus_init_mmio(dev, &s->ehci_iomem);
480 /* OHCI is instantiated by omap3.c */
481 vmstate_register(&dev->qdev, -1, &vmstate_omap3_hsusb_host, s);
482 return 0;
483}
484
485static void omap3_hsusb_host_class_init(ObjectClass *klass, void *data)
486{
487 DeviceClass *dc = DEVICE_CLASS(klass);
488 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
489 k->init = omap3_hsusb_host_init;
490 dc->reset = omap3_hsusb_host_reset;
491}
492
493static TypeInfo omap3_hsusb_host_info = {
494 .name = "omap3_hsusb_host",
495 .parent = TYPE_SYS_BUS_DEVICE,
496 .instance_size = sizeof(OMAP3HSUSBHostState),
497 .class_init = omap3_hsusb_host_class_init,
498};
499
500static void omap3_hsusb_register_types(void)
501{
502 type_register_static(&omap3_hsusb_otg_info);
503 type_register_static(&omap3_hsusb_host_info);
504}
505
506type_init(omap3_hsusb_register_types)