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