add futex print to strace
[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_read(int access,
92                                      void *opaque,
93                                      target_phys_addr_t addr)
94 {
95     struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
96     
97     if (addr < 0x200)
98         return musb_read[access](s->musb, addr);
99     if (addr < 0x400)
100         return musb_read[access](s->musb, 0x20 + ((addr >> 3) & 0x3c));
101     switch (addr) {
102         case 0x400: /* OTG_REVISION */
103             TRACE("OTG_REVISION: 0x%08x", s->rev);
104             return s->rev;
105         case 0x404: /* OTG_SYSCONFIG */
106             TRACE("OTG_SYSCONFIG: 0x%08x", s->sysconfig);
107             return 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);
113             return s->interfsel;
114         case 0x410: /* OTG_SIMENABLE */
115             TRACE("OTG_SIMENABLE: 0x%08x", s->simenable);
116             return s->simenable;
117         case 0x414: /* OTG_FORCESTDBY */
118             TRACE("OTG_FORCESTDBY: 0x%08x", s->forcestdby);
119             return s->forcestdby;
120         default:
121             break;
122     }
123     OMAP_BAD_REG(addr);
124     return 0;
125 }
126
127 static void omap3_hsusb_otg_write(int access,
128                                   void *opaque,
129                                   target_phys_addr_t addr,
130                                   uint32_t value)
131 {
132     struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
133     
134     if (addr < 0x200)
135         musb_write[access](s->musb, addr, value);
136     else if (addr < 0x400)
137         musb_write[access](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
138     else switch (addr) {
139         case 0x400: /* OTG_REVISION */
140         case 0x408: /* OTG_SYSSTATUS */
141             OMAP_RO_REGV(addr, value);
142             break;
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;
148             break;
149         case 0x40c: /* OTG_INTERFSEL */
150             TRACE("OTG_INTERFSEL = 0x%08x", value);
151             s->interfsel = value & 0x3;
152             break;
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",
157                       __FUNCTION__);
158             break;
159         case 0x414: /* OTG_FORCESTDBY */
160             TRACE("OTG_FORCESTDBY = 0x%08x", value);
161             s->forcestdby = value & 1;
162             break;
163         default:
164             OMAP_BAD_REGV(addr, value);
165             break;
166     }
167 }
168
169 static 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
174 static 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
179 static 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
184 static 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
190 static 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
196 static 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
202 static CPUReadMemoryFunc *omap3_hsusb_otg_readfn[] = {
203     omap3_hsusb_otg_readb,
204     omap3_hsusb_otg_readh,
205     omap3_hsusb_otg_readw,
206 };
207
208 static CPUWriteMemoryFunc *omap3_hsusb_otg_writefn[] = {
209     omap3_hsusb_otg_writeb,
210     omap3_hsusb_otg_writeh,
211     omap3_hsusb_otg_writew,
212 };
213
214 static void omap3_hsusb_musb_core_intr(void *opaque, int source, int level)
215 {
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);
219 }
220
221 static void omap3_hsusb_otg_init(struct omap_target_agent_s *otg_ta,
222                                  qemu_irq mc_irq,
223                                  qemu_irq dma_irq,
224                                  struct omap3_hsusb_otg_s *s)
225 {
226     s->mc_irq = mc_irq;
227     s->dma_irq = dma_irq;
228     
229     omap_l4_attach(otg_ta, 0, l4_register_io_memory(0,
230                                                     omap3_hsusb_otg_readfn,
231                                                     omap3_hsusb_otg_writefn,
232                                                     s));
233     
234     s->musb = musb_init(qemu_allocate_irqs(omap3_hsusb_musb_core_intr, s,
235                                            __musb_irq_max));
236     omap3_hsusb_otg_reset(s);
237     
238     register_savevm("omap3_hsusb_otg", -1, 0,
239                     omap3_hsusb_otg_save_state,
240                     omap3_hsusb_otg_load_state,
241                     s);
242 }
243 #endif
244
245 #ifdef OMAP3_HSUSB_HOST
246 struct omap3_hsusb_host_s {
247     qemu_irq ehci_irq;
248     qemu_irq tll_irq;
249     
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;
255 };
256
257 static void omap3_hsusb_host_save_state(QEMUFile *f, void *opaque)
258 {
259     struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
260     
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);
266 }
267
268 static int omap3_hsusb_host_load_state(QEMUFile *f, void *opaque,
269                                        int version_id)
270 {
271     struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
272     
273     if (version_id)
274         return -EINVAL;
275     
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);
281     
282     return 0;
283 }
284
285 static void omap3_hsusb_host_reset(struct omap3_hsusb_host_s *s)
286 {
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;
292 }
293
294 static uint32_t omap3_hsusb_host_read(void *opaque, target_phys_addr_t addr)
295 {
296     struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
297     TRACE(OMAP_FMT_plx, addr);
298
299     switch (addr) {
300         case 0x00: /* UHH_REVISION */
301             return 0x10;
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;
310         default:
311             break;
312     }
313     OMAP_BAD_REG(addr);
314     return 0;
315 }
316
317 static void omap3_hsusb_host_write(void *opaque, target_phys_addr_t addr,
318                                    uint32_t value)
319 {
320     struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
321     TRACE(OMAP_FMT_plx " = 0x%08x", addr, value);
322
323     switch (addr) {
324         case 0x00: /* UHH_REVISION */
325         case 0x14: /* UHH_SYSSTATUS */
326             OMAP_RO_REGV(addr, value);
327             break;
328         case 0x10: /* UHH_SYSCONFIG */
329             s->uhh_sysconfig = value & 0x311d;
330             if (value & 2) { /* SOFTRESET */
331                 omap3_hsusb_host_reset(s);
332             }
333             break;
334         case 0x40: /* UHH_HOSTCONFIG */
335             s->uhh_hostconfig = value & 0x1f3d;
336             break;
337         case 0x44: /* UHH_DEBUG_CSR */
338             s->uhh_debug_csr = value & 0xf00ff;
339             break;
340         default:
341             OMAP_BAD_REGV(addr, value);
342             break;
343     }
344 }
345
346 static CPUReadMemoryFunc *omap3_hsusb_host_readfn[] = {
347     omap_badwidth_read32,
348     omap_badwidth_read32,
349     omap3_hsusb_host_read,
350 };
351
352 static CPUWriteMemoryFunc *omap3_hsusb_host_writefn[] = {
353     omap_badwidth_write32,
354     omap_badwidth_write32,
355     omap3_hsusb_host_write,
356 };
357
358 static uint32_t omap3_hsusb_ehci_read(void *opaque, target_phys_addr_t addr)
359 {
360     struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
361     TRACE(OMAP_FMT_plx, addr);
362     switch (addr) {
363         case 0xa4: /* INSNREG05_ULPI */
364             return s->insnreg05_ulpi;
365         default:
366             break;
367     }
368     return 0;
369 }
370
371 static void omap3_hsusb_ehci_write(void *opaque, target_phys_addr_t addr,
372                                    uint32_t value)
373 {
374     struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
375     TRACE(OMAP_FMT_plx " = 0x%08x", addr, value);
376
377     switch (addr) {
378         case 0xa4: /* INSNREG05_ULPI */
379             s->insnreg05_ulpi = value & 0xF0000000;
380         default:
381             break;
382      }
383 }
384
385 static CPUReadMemoryFunc *omap3_hsusb_ehci_readfn[] = {
386     omap_badwidth_read32,
387     omap_badwidth_read32,
388     omap3_hsusb_ehci_read,
389 };
390
391 static CPUWriteMemoryFunc *omap3_hsusb_ehci_writefn[] = {
392     omap_badwidth_write32,
393     omap_badwidth_write32,
394     omap3_hsusb_ehci_write,
395 };
396
397 static uint32_t omap3_hsusb_tll_read(void *opaque, target_phys_addr_t addr)
398 {
399     struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
400     TRACE(OMAP_FMT_plx, addr);
401
402     switch (addr) {
403         case 0x00: /* USBTLL_REVISION */
404             return 0x1;
405         case 0x10: /* USBTLL_SYSCONFIG */
406             return s->tll_sysconfig;
407         case 0x14: /* USBTLL_SYSSTATUS */
408             return 0x1; /* RESETDONE */
409         case 0x18: /* USBTLL_IRQSTATUS */
410             return 0;
411         case 0x1C: /* USBTLL_IRQENABLE */
412             return 0;
413         default:
414             break;
415     }
416     return 0;
417 }
418
419 static void omap3_hsusb_tll_write(void *opaque, target_phys_addr_t addr,
420                                   uint32_t value)
421 {
422     struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
423     TRACE(OMAP_FMT_plx " = 0x%08x", addr, value);
424
425     switch (addr) {
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;;
431         default:
432             OMAP_BAD_REGV(addr, value);
433             break;
434     }
435 }
436
437 static CPUReadMemoryFunc *omap3_hsusb_tll_readfn[] = {
438     omap_badwidth_read32,
439     omap_badwidth_read32,
440     omap3_hsusb_tll_read,
441 };
442
443 static CPUWriteMemoryFunc *omap3_hsusb_tll_writefn[] = {
444     omap_badwidth_write32,
445     omap_badwidth_write32,
446     omap3_hsusb_tll_write,
447 };
448
449 static void omap3_hsusb_host_init(struct omap_target_agent_s *host_ta,
450                                   struct omap_target_agent_s *tll_ta,
451                                   qemu_irq ohci_irq,
452                                   qemu_irq ehci_irq,
453                                   qemu_irq tll_irq,
454                                   struct omap3_hsusb_host_s *s)
455 {
456     s->ehci_irq = ehci_irq;
457     s->tll_irq  = tll_irq;
458     
459     omap_l4_attach(tll_ta, 0, l4_register_io_memory(0,
460                                                     omap3_hsusb_tll_readfn,
461                                                     omap3_hsusb_tll_writefn,
462                                                     s));
463     omap_l4_attach(host_ta, 0, l4_register_io_memory(0,
464                                                      omap3_hsusb_host_readfn,
465                                                      omap3_hsusb_host_writefn,
466                                                      s));
467 /*    omap_l4_attach(host_ta, 1, usb_ohci_init_omap(omap_l4_base(host_ta, 1),
468                                                   omap_l4_size(host_ta, 1),
469                                                   3, ohci_irq));*/
470     omap_l4_attach(host_ta, 2, l4_register_io_memory(0,
471                                                      omap3_hsusb_ehci_readfn,
472                                                      omap3_hsusb_ehci_writefn,
473                                                      s));
474     
475     omap3_hsusb_host_reset(s);
476     
477     register_savevm("omap3_hsusb_host", -1, 0,
478                     omap3_hsusb_host_save_state,
479                     omap3_hsusb_host_load_state, s);
480 }
481 #endif
482
483 struct omap3_hsusb_s {
484 #ifdef OMAP3_HSUSB_OTG
485     struct omap3_hsusb_otg_s otg;
486 #endif
487 #ifdef OMAP3_HSUSB_HOST
488     struct omap3_hsusb_host_s host;
489 #endif
490 };
491
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,
495                                        qemu_irq mc_irq,
496                                        qemu_irq dma_irq,
497                                        qemu_irq ohci_irq,
498                                        qemu_irq ehci_irq,
499                                        qemu_irq tll_irq)
500 {
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,
505                           &s->host);
506 #endif
507 #ifdef OMAP3_HSUSB_OTG
508     omap3_hsusb_otg_init(otg_ta, mc_irq, dma_irq, &s->otg);
509 #endif
510     return s;
511 }
512