ebb0eefb6b0b46c7fcadf6d30e52cfb05eb09fe5
[qemu] / hw / omap3_usb.c
1 /*
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) version 3 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
28 #define OMAP3_HSUSB_OTG
29 //#define OMAP3_HSUSB_HOST
30
31 /* #define OMAP3_HSUSB_DEBUG */
32
33 #ifdef OMAP3_HSUSB_DEBUG
34 #define TRACE(fmt,...) fprintf(stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
35 #else
36 #define TRACE(...)
37 #endif
38
39 #ifdef OMAP3_HSUSB_OTG
40 /* usb-musb.c */
41 extern CPUReadMemoryFunc *musb_read[];
42 extern CPUWriteMemoryFunc *musb_write[];
43
44 struct omap3_hsusb_otg_s {
45     qemu_irq mc_irq;
46     qemu_irq dma_irq;
47     struct musb_s *musb;
48     
49     uint8_t rev;
50     uint16_t sysconfig;
51     uint8_t interfsel;
52     uint8_t simenable;
53     uint8_t forcestdby;
54 };
55
56 static void omap3_hsusb_otg_save_state(QEMUFile *f, void *opaque)
57 {
58     struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
59     
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);
64 }
65
66 static int omap3_hsusb_otg_load_state(QEMUFile *f, void *opaque,
67                                       int version_id)
68 {
69     struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
70     
71     if (version_id)
72         return -EINVAL;
73     
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);
78     
79     return 0;
80 }
81
82 static void omap3_hsusb_otg_reset(struct omap3_hsusb_otg_s *s)
83 {
84     s->rev = 0x33;
85     s->sysconfig = 0;
86     s->interfsel = 0x1;
87     s->simenable = 0;
88     s->forcestdby = 1;
89 }
90
91 static uint32_t omap3_hsusb_otg_readb(void *opaque, target_phys_addr_t addr)
92 {
93     struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
94     if (addr < 0x200)
95         return musb_read[0](s->musb, addr);
96     if (addr < 0x400)
97         return musb_read[0](s->musb, 0x20 + ((addr >> 3 ) & 0x3c));
98     OMAP_BAD_REG(addr);
99     return 0;
100 }
101
102 static uint32_t omap3_hsusb_otg_readh(void *opaque, target_phys_addr_t addr)
103 {
104     struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
105     if (addr < 0x200)
106         return musb_read[1](s->musb, addr);
107     if (addr < 0x400)
108         return musb_read[1](s->musb, 0x20 + ((addr >> 3 ) & 0x3c));
109     OMAP_BAD_REG(addr);
110     return 0;
111 }
112
113 static uint32_t omap3_hsusb_otg_read(void *opaque, target_phys_addr_t addr)
114 {
115     struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
116     
117     if (addr < 0x200)
118         return musb_read[2](s->musb, addr);
119     if (addr < 0x400)
120         return musb_read[2](s->musb, 0x20 + ((addr >> 3 ) & 0x3c));
121     
122     switch (addr) {
123         case 0x400: /* OTG_REVISION */
124             TRACE("OTG_REVISION: 0x%08x", s->rev);
125             return s->rev;
126         case 0x404: /* OTG_SYSCONFIG */
127             TRACE("OTG_SYSCONFIG: 0x%08x", s->sysconfig);
128             return 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);
134             return s->interfsel;
135         case 0x410: /* OTG_SIMENABLE */
136             TRACE("OTG_SIMENABLE: 0x%08x", s->simenable);
137             return s->simenable;
138         case 0x414: /* OTG_FORCESTDBY */
139             TRACE("OTG_FORCESTDBY: 0x%08x", s->forcestdby);
140             return s->forcestdby;
141         default:
142             break;
143     }
144     OMAP_BAD_REG(addr);
145     return 0;
146 }
147
148 static void omap3_hsusb_otg_writeb(void *opaque, target_phys_addr_t addr,
149                                    uint32_t value)
150 {
151     struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
152     
153     if (addr < 0x200)
154         musb_write[0](s->musb, addr, value);
155     else if (addr < 0x400)
156         musb_write[0](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
157     else
158         OMAP_BAD_REG(addr);
159 }
160
161 static void omap3_hsusb_otg_writeh(void *opaque, target_phys_addr_t addr,
162                                    uint32_t value)
163 {
164     struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
165     
166     if (addr < 0x200)
167         musb_write[1](s->musb, addr, value);
168     else if (addr < 0x400)
169         musb_write[1](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
170     else
171         OMAP_BAD_REG(addr);
172 }
173
174 static void omap3_hsusb_otg_write(void *opaque, target_phys_addr_t addr,
175                                   uint32_t value)
176 {
177     struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
178     
179     if (addr < 0x200)
180         musb_write[2](s->musb, addr, value);
181     else if (addr < 0x400)
182         musb_write[2](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
183     else switch (addr) {
184         case 0x400: /* OTG_REVISION */
185         case 0x408: /* OTG_SYSSTATUS */
186             OMAP_RO_REGV(addr, value);
187             break;
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;
193             break;
194         case 0x40c: /* OTG_INTERFSEL */
195             TRACE("OTG_INTERFSEL = 0x%08x", value);
196             s->interfsel = value & 0x3;
197             break;
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",
202                       __FUNCTION__);
203             break;
204         case 0x414: /* OTG_FORCESTDBY */
205             TRACE("OTG_FORCESTDBY = 0x%08x", value);
206             s->forcestdby = value & 1;
207             break;
208         default:
209             OMAP_BAD_REGV(addr, value);
210             break;
211     }
212 }
213
214 static CPUReadMemoryFunc *omap3_hsusb_otg_readfn[] = {
215     omap3_hsusb_otg_readb,
216     omap3_hsusb_otg_readh,
217     omap3_hsusb_otg_read,
218 };
219
220 static CPUWriteMemoryFunc *omap3_hsusb_otg_writefn[] = {
221     omap3_hsusb_otg_writeb,
222     omap3_hsusb_otg_writeh,
223     omap3_hsusb_otg_write,
224 };
225
226 static void omap3_hsusb_musb_core_intr(void *opaque, int source, int level)
227 {
228     struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
229     TRACE("intr 0x%08x, 0x%08x, 0x%08x", source, level, musb_core_intr_get(s->musb));
230     switch (source) {
231     case musb_set_vbus:
232        TRACE("ignoring VBUS");
233        break;
234     case musb_set_session:
235        TRACE("ignoring SESSION");
236        break;
237     case musb_irq_tx:
238     case musb_irq_rx:
239        TRACE("rxtx");
240        break;
241        /* Fall through */
242     default:
243        TRACE("other");
244     }
245     qemu_set_irq(s->mc_irq, level);
246 }
247
248 static void omap3_hsusb_otg_init(struct omap_target_agent_s *otg_ta,
249                                  qemu_irq mc_irq,
250                                  qemu_irq dma_irq,
251                                  struct omap3_hsusb_otg_s *s)
252 {
253     s->mc_irq = mc_irq;
254     s->dma_irq = dma_irq;
255     
256     omap_l4_attach(otg_ta, 0, l4_register_io_memory(0,
257                                                     omap3_hsusb_otg_readfn,
258                                                     omap3_hsusb_otg_writefn,
259                                                     s));
260     
261     s->musb = musb_init(qemu_allocate_irqs(omap3_hsusb_musb_core_intr, s,
262                                            __musb_irq_max));
263     omap3_hsusb_otg_reset(s);
264     
265     register_savevm("omap3_hsusb_otg", -1, 0,
266                     omap3_hsusb_otg_save_state,
267                     omap3_hsusb_otg_load_state,
268                     s);
269 }
270 #endif
271
272 #ifdef OMAP3_HSUSB_HOST
273 struct omap3_hsusb_host_s {
274     qemu_irq ehci_irq;
275     qemu_irq tll_irq;
276     
277     uint32_t uhh_sysconfig;
278     uint32_t uhh_hostconfig;
279     uint32_t uhh_debug_csr;
280 };
281
282 static void omap3_hsusb_host_save_state(QEMUFile *f, void *opaque)
283 {
284     struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
285     
286     qemu_put_be32(f, s->uhh_sysconfig);
287     qemu_put_be32(f, s->uhh_hostconfig);
288     qemu_put_be32(f, s->uhh_debug_csr);
289 }
290
291 static int omap3_hsusb_host_load_state(QEMUFile *f, void *opaque,
292                                        int version_id)
293 {
294     struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
295     
296     if (version_id)
297         return -EINVAL;
298     
299     s->uhh_sysconfig = qemu_get_be32(f);
300     s->uhh_hostconfig = qemu_get_be32(f);
301     s->uhh_debug_csr = qemu_get_be32(f);
302     
303     return 0;
304 }
305
306 static void omap3_hsusb_host_reset(struct omap3_hsusb_host_s *s)
307 {
308     s->uhh_sysconfig = 1;
309     s->uhh_hostconfig = 0x700;
310     s->uhh_debug_csr = 0x20;
311     /* TODO: perform OHCI & EHCI reset */
312 }
313
314 static uint32_t omap3_hsusb_host_read(void *opaque, target_phys_addr_t addr)
315 {
316     struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
317     
318     switch (addr) {
319         case 0x00: /* UHH_REVISION */
320             return 0x10;
321         case 0x10: /* UHH_SYSCONFIG */
322             return s->uhh_sysconfig;
323         case 0x14: /* UHH_SYSSTATUS */
324             return 0x7; /* EHCI_RESETDONE | OHCI_RESETDONE | RESETDONE */
325         case 0x40: /* UHH_HOSTCONFIG */
326             return s->uhh_hostconfig;
327         case 0x44: /* UHH_DEBUG_CSR */
328             return s->uhh_debug_csr;
329         default:
330             break;
331     }
332     OMAP_BAD_REG(addr);
333     return 0;
334 }
335
336 static void omap3_hsusb_host_write(void *opaque, target_phys_addr_t addr,
337                                    uint32_t value)
338 {
339     struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
340     
341     switch (addr) {
342         case 0x00: /* UHH_REVISION */
343         case 0x14: /* UHH_SYSSTATUS */
344             OMAP_RO_REGV(addr, value);
345             break;
346         case 0x10: /* UHH_SYSCONFIG */
347             s->uhh_sysconfig = value & 0x311d;
348             if (value & 2) { /* SOFTRESET */
349                 omap3_hsusb_host_reset(s);
350             }
351             break;
352         case 0x40: /* UHH_HOSTCONFIG */
353             s->uhh_hostconfig = value & 0x1f3d;
354             break;
355         case 0x44: /* UHH_DEBUG_CSR */
356             s->uhh_debug_csr = value & 0xf00ff;
357             break;
358         default:
359             OMAP_BAD_REGV(addr, value);
360             break;
361     }
362 }
363
364 static CPUReadMemoryFunc *omap3_hsusb_host_readfn[] = {
365     omap_badwidth_read32,
366     omap_badwidth_read32,
367     omap3_hsusb_host_read,
368 };
369
370 static CPUWriteMemoryFunc *omap3_hsusb_host_writefn[] = {
371     omap_badwidth_write32,
372     omap_badwidth_write32,
373     omap3_hsusb_host_write,
374 };
375
376 static uint32_t omap3_hsusb_ehci_read(void *opaque, target_phys_addr_t addr)
377 {
378     TRACE(OMAP_FMT_plx, addr);
379     return 0;
380 }
381
382 static void omap3_hsusb_ehci_write(void *opaque, target_phys_addr_t addr,
383                                    uint32_t value)
384 {
385     TRACE(OMAP_FMT_plx " = 0x%08x", addr, value);
386 }
387
388 static CPUReadMemoryFunc *omap3_hsusb_ehci_readfn[] = {
389     omap_badwidth_read32,
390     omap_badwidth_read32,
391     omap3_hsusb_ehci_read,
392 };
393
394 static CPUWriteMemoryFunc *omap3_hsusb_ehci_writefn[] = {
395     omap_badwidth_write32,
396     omap_badwidth_write32,
397     omap3_hsusb_ehci_write,
398 };
399
400 static uint32_t omap3_hsusb_tll_read(void *opaque, target_phys_addr_t addr)
401 {
402     TRACE(OMAP_FMT_plx, addr);
403     return 0;
404 }
405
406 static void omap3_hsusb_tll_write(void *opaque, target_phys_addr_t addr,
407                                   uint32_t value)
408 {
409     TRACE(OMAP_FMT_plx " = 0x%08x", addr, value);
410 }
411
412 static CPUReadMemoryFunc *omap3_hsusb_tll_readfn[] = {
413     omap_badwidth_read32,
414     omap_badwidth_read32,
415     omap3_hsusb_tll_read,
416 };
417
418 static CPUWriteMemoryFunc *omap3_hsusb_tll_writefn[] = {
419     omap_badwidth_write32,
420     omap_badwidth_write32,
421     omap3_hsusb_tll_write,
422 };
423
424 static void omap3_hsusb_host_init(struct omap_target_agent_s *host_ta,
425                                   struct omap_target_agent_s *tll_ta,
426                                   qemu_irq ohci_irq,
427                                   qemu_irq ehci_irq,
428                                   qemu_irq tll_irq,
429                                   struct omap3_hsusb_host_s *s)
430 {
431     s->ehci_irq = ehci_irq;
432     s->tll_irq  = tll_irq;
433     
434     omap_l4_attach(tll_ta, 0, l4_register_io_memory(0,
435                                                     omap3_hsusb_tll_readfn,
436                                                     omap3_hsusb_tll_writefn,
437                                                     s));
438     omap_l4_attach(host_ta, 0, l4_register_io_memory(0,
439                                                      omap3_hsusb_host_readfn,
440                                                      omap3_hsusb_host_writefn,
441                                                      s));
442     omap_l4_attach(host_ta, 1, usb_ohci_init_omap(omap_l4_base(host_ta, 1),
443                                                   omap_l4_size(host_ta, 1),
444                                                   3, ohci_irq));
445     omap_l4_attach(host_ta, 2, l4_register_io_memory(0,
446                                                      omap3_hsusb_ehci_readfn,
447                                                      omap3_hsusb_ehci_writefn,
448                                                      s));
449     
450     omap3_hsusb_host_reset(s);
451     
452     register_savevm("omap3_hsusb_host", -1, 0,
453                     omap3_hsusb_host_save_state,
454                     omap3_hsusb_host_load_state, s);
455 }
456 #endif
457
458 struct omap3_hsusb_s {
459 #ifdef OMAP3_HSUSB_OTG
460     struct omap3_hsusb_otg_s otg;
461 #endif
462 #ifdef OMAP3_HSUSB_HOST
463     struct omap3_hsusb_host_s host;
464 #endif
465 };
466
467 struct omap3_hsusb_s *omap3_hsusb_init(struct omap_target_agent_s *otg_ta,
468                                        struct omap_target_agent_s *host_ta,
469                                        struct omap_target_agent_s *tll_ta,
470                                        qemu_irq mc_irq,
471                                        qemu_irq dma_irq,
472                                        qemu_irq ohci_irq,
473                                        qemu_irq ehci_irq,
474                                        qemu_irq tll_irq)
475 {
476     struct omap3_hsusb_s *s = qemu_mallocz(sizeof(struct omap3_hsusb_s));
477 #ifdef OMAP3_HSUSB_HOST
478     omap3_hsusb_host_init(host_ta, tll_ta,
479                           ohci_irq, ehci_irq, tll_irq,
480                           &s->host);
481 #endif
482 #ifdef OMAP3_HSUSB_OTG
483     omap3_hsusb_otg_init(otg_ta, mc_irq, dma_irq, &s->otg);
484 #endif
485     return s;
486 }
487