We want the level, not value for intr
[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
27 #define OMAP3_HSUSB_DEBUG
28
29 #ifdef OMAP3_HSUSB_DEBUG
30 #define TRACE(fmt,...) fprintf(stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
31 #else
32 #define TRACE(...)
33 #endif
34
35 extern CPUReadMemoryFunc *musb_read[];
36 extern CPUWriteMemoryFunc *musb_write[];
37
38 struct omap3_hsusb_otg_s {
39     qemu_irq mc_irq;
40     qemu_irq dma_irq;
41     struct musb_s *musb;
42     
43     uint8_t rev;
44     uint16_t sysconfig;
45     uint8_t interfsel;
46     uint8_t simenable;
47     uint8_t forcestdby;
48 };
49
50 static void omap3_hsusb_otg_reset(struct omap3_hsusb_otg_s *s)
51 {
52     s->rev = 0x33;
53     s->sysconfig = 0;
54     s->interfsel = 0x1;
55     s->simenable = 0;
56     s->forcestdby = 1;
57 }
58
59 static uint32_t omap3_hsusb_otg_readb(void *opaque, target_phys_addr_t addr)
60 {
61     struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
62     if (addr < 0x200)
63         return musb_read[0](s->musb, addr);
64     if (addr < 0x400)
65         return musb_read[0](s->musb, 0x20 + ((addr >> 3 ) & 0x3c));
66     OMAP_BAD_REG(addr);
67     return 0;
68 }
69
70 static uint32_t omap3_hsusb_otg_readh(void *opaque, target_phys_addr_t addr)
71 {
72     struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
73     if (addr < 0x200)
74         return musb_read[1](s->musb, addr);
75     if (addr < 0x400)
76         return musb_read[1](s->musb, 0x20 + ((addr >> 3 ) & 0x3c));
77     OMAP_BAD_REG(addr);
78     return 0;
79 }
80
81 static uint32_t omap3_hsusb_otg_read(void *opaque, target_phys_addr_t addr)
82 {
83     struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
84     
85     if (addr < 0x200)
86         return musb_read[2](s->musb, addr);
87     if (addr < 0x400)
88         return musb_read[2](s->musb, 0x20 + ((addr >> 3 ) & 0x3c));
89     
90     switch (addr) {
91         case 0x400: /* OTG_REVISION */
92             TRACE("OTG_REVISION: 0x%08x", s->rev);
93             return s->rev;
94         case 0x404: /* OTG_SYSCONFIG */
95             TRACE("OTG_SYSCONFIG: 0x%08x", s->sysconfig);
96             return s->sysconfig;
97         case 0x408: /* OTG_SYSSTATUS */
98             TRACE("OTG_SYSSTATUS: 0x00000001");
99             return 1; /* reset finished */
100         case 0x40c: /* OTG_INTERFSEL */
101             TRACE("OTG_INTERFSEL: 0x%08x", s->interfsel);
102             return s->interfsel;
103         case 0x410: /* OTG_SIMENABLE */
104             TRACE("OTG_SIMENABLE: 0x%08x", s->simenable);
105             return s->simenable;
106         case 0x414: /* OTG_FORCESTDBY */
107             TRACE("OTG_FORCESTDBY: 0x%08x", s->forcestdby);
108             return s->forcestdby;
109         default:
110             break;
111     }
112     OMAP_BAD_REG(addr);
113     return 0;
114 }
115
116 static void omap3_hsusb_otg_writeb(void *opaque, target_phys_addr_t addr,
117                                    uint32_t value)
118 {
119     struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
120     
121     if (addr < 0x200)
122         musb_write[0](s->musb, addr, value);
123     else if (addr < 0x400)
124         musb_write[0](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
125     else
126         OMAP_BAD_REG(addr);
127 }
128
129 static void omap3_hsusb_otg_writeh(void *opaque, 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[1](s->musb, addr, value);
136     else if (addr < 0x400)
137         musb_write[1](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
138     else
139         OMAP_BAD_REG(addr);
140 }
141
142 static void omap3_hsusb_otg_write(void *opaque, target_phys_addr_t addr,
143                                   uint32_t value)
144 {
145     struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
146     
147     if (addr < 0x200)
148         musb_write[2](s->musb, addr, value);
149     else if (addr < 0x400)
150         musb_write[2](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
151     else switch (addr) {
152         case 0x400: /* OTG_REVISION */
153         case 0x408: /* OTG_SYSSTATUS */
154             OMAP_RO_REGV(addr, value);
155             break;
156         case 0x404: /* OTG_SYSCONFIG */
157             TRACE("OTG_SYSCONFIG = 0x%08x", value);
158             if (value & 2) /* SOFTRESET */
159                 omap3_hsusb_otg_reset(s);
160             s->sysconfig = value & 0x301f;
161             break;
162         case 0x40c: /* OTG_INTERFSEL */
163             TRACE("OTG_INTERFSEL = 0x%08x", value);
164             s->interfsel = value & 0x3;
165             break;
166         case 0x410: /* OTG_SIMENABLE */
167             TRACE("OTG_SIMENABLE = 0x%08x", value);
168             cpu_abort(cpu_single_env, "%s: USB simulation mode not supported\n",
169                       __FUNCTION__);
170             break;
171         case 0x414: /* OTG_FORCESTDBY */
172             TRACE("OTG_FORCESTDBY = 0x%08x", value);
173             s->forcestdby = value & 1;
174             break;
175         default:
176             OMAP_BAD_REGV(addr, value);
177             break;
178     }
179 }
180
181 static CPUReadMemoryFunc *omap3_hsusb_otg_readfn[] = {
182     omap3_hsusb_otg_readb,
183     omap3_hsusb_otg_readh,
184     omap3_hsusb_otg_read,
185 };
186
187 static CPUWriteMemoryFunc *omap3_hsusb_otg_writefn[] = {
188     omap3_hsusb_otg_writeb,
189     omap3_hsusb_otg_writeh,
190     omap3_hsusb_otg_write,
191 };
192
193 static void omap3_hsusb_musb_core_intr(void *opaque, int source, int level)
194 {
195     struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
196     uint32_t value = musb_core_intr_get(s->musb);
197     TRACE("intr 0x%08x, 0x%08x, 0x%08x", source, level, value);
198     switch (source) {
199     case musb_set_vbus:
200        TRACE("ignoring VBUS");
201        break;
202     case musb_set_session:
203        TRACE("ignoring SESSION");
204        break;
205     case musb_irq_tx:
206     case musb_irq_rx:
207        TRACE("rxtx");
208        break;
209        /* Fall through */
210     default:
211        TRACE("other");
212     }
213     qemu_set_irq(s->mc_irq, level);
214 }
215
216 static void omap3_hsusb_otg_init(struct omap_target_agent_s *otg_ta,
217                                  qemu_irq mc_irq,
218                                  qemu_irq dma_irq,
219                                  struct omap3_hsusb_otg_s *s)
220 {
221     s->mc_irq = mc_irq;
222     s->dma_irq = dma_irq;
223     
224     omap_l4_attach(otg_ta, 0, l4_register_io_memory(0, omap3_hsusb_otg_readfn,
225                                                     omap3_hsusb_otg_writefn, s));
226     
227     s->musb = musb_init(qemu_allocate_irqs(omap3_hsusb_musb_core_intr, s, __musb_irq_max));
228     omap3_hsusb_otg_reset(s);
229 }
230
231 struct omap3_hsusb_host_s {
232     struct {
233         qemu_irq ohci_irq;
234         qemu_irq ehci_irq;
235     } hc;
236     struct {
237         qemu_irq irq;
238     } tll;
239 };
240
241 static uint32_t omap3_hsusb_host_read(void *opaque, target_phys_addr_t addr)
242 {
243     TRACE(OMAP_FMT_plx, addr);
244     return 0;
245 }
246
247 static void omap3_hsusb_host_write(void *opaque, target_phys_addr_t addr,
248                                    uint32_t value)
249 {
250     TRACE(OMAP_FMT_plx " = 0x%08x", addr, value);
251 }
252
253 static CPUReadMemoryFunc *omap3_hsusb_host_readfn[] = {
254     omap_badwidth_read32,
255     omap_badwidth_read32,
256     omap3_hsusb_host_read,
257 };
258
259 static CPUWriteMemoryFunc *omap3_hsusb_host_writefn[] = {
260     omap_badwidth_write32,
261     omap_badwidth_write32,
262     omap3_hsusb_host_write,
263 };
264
265 static uint32_t omap3_hsusb_tll_read(void *opaque, target_phys_addr_t addr)
266 {
267     TRACE(OMAP_FMT_plx, addr);
268     return 0;
269 }
270
271 static void omap3_hsusb_tll_write(void *opaque, target_phys_addr_t addr,
272                                   uint32_t value)
273 {
274     TRACE(OMAP_FMT_plx " = 0x%08x", addr, value);
275 }
276
277 static CPUReadMemoryFunc *omap3_hsusb_tll_readfn[] = {
278     omap_badwidth_read32,
279     omap_badwidth_read32,
280     omap3_hsusb_tll_read,
281 };
282
283 static CPUWriteMemoryFunc *omap3_hsusb_tll_writefn[] = {
284     omap_badwidth_write32,
285     omap_badwidth_write32,
286     omap3_hsusb_tll_write,
287 };
288
289 static void omap3_hsusb_host_init(struct omap_target_agent_s *host_ta,
290                                   struct omap_target_agent_s *tll_ta,
291                                   qemu_irq ohci_irq,
292                                   qemu_irq ehci_irq,
293                                   qemu_irq tll_irq,
294                                   struct omap3_hsusb_host_s *s)
295 {
296     s->hc.ohci_irq = ohci_irq;
297     s->hc.ehci_irq = ehci_irq;
298     s->tll.irq     = tll_irq;
299     
300     omap_l4_attach(host_ta, 0, l4_register_io_memory(0, omap3_hsusb_host_readfn,
301                                                      omap3_hsusb_host_writefn, s));
302     omap_l4_attach(tll_ta, 0, l4_register_io_memory(0, omap3_hsusb_tll_readfn,
303                                                     omap3_hsusb_tll_writefn, s));
304 }
305
306 struct omap3_hsusb_s {
307     struct omap3_hsusb_otg_s otg;
308     struct omap3_hsusb_host_s host;
309 };
310
311 struct omap3_hsusb_s *omap3_hsusb_init(struct omap_target_agent_s *otg_ta,
312                                        struct omap_target_agent_s *host_ta,
313                                        struct omap_target_agent_s *tll_ta,
314                                        qemu_irq mc_irq,
315                                        qemu_irq dma_irq,
316                                        qemu_irq ohci_irq,
317                                        qemu_irq ehci_irq,
318                                        qemu_irq tll_irq)
319 {
320     struct omap3_hsusb_s *s = qemu_mallocz(sizeof(struct omap3_hsusb_s));
321     omap3_hsusb_otg_init(otg_ta, mc_irq, dma_irq, &s->otg);
322     omap3_hsusb_host_init(host_ta, tll_ta, ohci_irq, ehci_irq, tll_irq, &s->host);
323     return s;
324 }
325