xref: /qemu/hw/usb/hcd-ehci-sysbus.c (revision 513823e7521a09ed7ad1e32e6454bac3b2cbf52d)
1 /*
2  * QEMU USB EHCI Emulation
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this program; if not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "qemu/osdep.h"
19 #include "hw/qdev-properties.h"
20 #include "hw/usb/hcd-ehci.h"
21 #include "migration/vmstate.h"
22 
23 static const VMStateDescription vmstate_ehci_sysbus = {
24     .name        = "ehci-sysbus",
25     .version_id  = 2,
26     .minimum_version_id  = 1,
27     .fields = (const VMStateField[]) {
28         VMSTATE_STRUCT(ehci, EHCISysBusState, 2, vmstate_ehci, EHCIState),
29         VMSTATE_END_OF_LIST()
30     }
31 };
32 
33 static const Property ehci_sysbus_properties[] = {
34     DEFINE_PROP_UINT32("maxframes", EHCISysBusState, ehci.maxframes, 128),
35     DEFINE_PROP_BOOL("companion-enable", EHCISysBusState, ehci.companion_enable,
36                      false),
37 };
38 
39 static void usb_ehci_sysbus_realize(DeviceState *dev, Error **errp)
40 {
41     SysBusDevice *d = SYS_BUS_DEVICE(dev);
42     EHCISysBusState *i = SYS_BUS_EHCI(dev);
43     EHCIState *s = &i->ehci;
44 
45     usb_ehci_realize(s, dev, errp);
46     sysbus_init_irq(d, &s->irq);
47 }
48 
49 static void usb_ehci_sysbus_reset(DeviceState *dev)
50 {
51     SysBusDevice *d = SYS_BUS_DEVICE(dev);
52     EHCISysBusState *i = SYS_BUS_EHCI(d);
53     EHCIState *s = &i->ehci;
54 
55     ehci_reset(s);
56 }
57 
58 static void ehci_sysbus_init(Object *obj)
59 {
60     SysBusDevice *d = SYS_BUS_DEVICE(obj);
61     EHCISysBusState *i = SYS_BUS_EHCI(obj);
62     SysBusEHCIClass *sec = SYS_BUS_EHCI_GET_CLASS(obj);
63     EHCIState *s = &i->ehci;
64 
65     s->capsbase = sec->capsbase;
66     s->opregbase = sec->opregbase;
67     s->portscbase = sec->portscbase;
68     s->portnr = sec->portnr;
69     s->as = &address_space_memory;
70 
71     usb_ehci_init(s, DEVICE(obj));
72     sysbus_init_mmio(d, &s->mem);
73 }
74 
75 static void ehci_sysbus_finalize(Object *obj)
76 {
77     EHCISysBusState *i = SYS_BUS_EHCI(obj);
78     EHCIState *s = &i->ehci;
79 
80     usb_ehci_finalize(s);
81 }
82 
83 static void ehci_sysbus_class_init(ObjectClass *klass, void *data)
84 {
85     DeviceClass *dc = DEVICE_CLASS(klass);
86     SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(klass);
87 
88     sec->portscbase = 0x44;
89     sec->portnr = EHCI_PORTS;
90 
91     dc->realize = usb_ehci_sysbus_realize;
92     dc->vmsd = &vmstate_ehci_sysbus;
93     device_class_set_props(dc, ehci_sysbus_properties);
94     device_class_set_legacy_reset(dc, usb_ehci_sysbus_reset);
95     set_bit(DEVICE_CATEGORY_USB, dc->categories);
96 }
97 
98 static void ehci_platform_class_init(ObjectClass *oc, void *data)
99 {
100     SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
101     DeviceClass *dc = DEVICE_CLASS(oc);
102 
103     sec->capsbase = 0x0;
104     sec->opregbase = 0x20;
105     set_bit(DEVICE_CATEGORY_USB, dc->categories);
106 }
107 
108 static void ehci_exynos4210_class_init(ObjectClass *oc, void *data)
109 {
110     SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
111     DeviceClass *dc = DEVICE_CLASS(oc);
112 
113     sec->capsbase = 0x0;
114     sec->opregbase = 0x10;
115     set_bit(DEVICE_CATEGORY_USB, dc->categories);
116 }
117 
118 static void ehci_aw_h3_class_init(ObjectClass *oc, void *data)
119 {
120     SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
121     DeviceClass *dc = DEVICE_CLASS(oc);
122 
123     sec->capsbase = 0x0;
124     sec->opregbase = 0x10;
125     set_bit(DEVICE_CATEGORY_USB, dc->categories);
126 }
127 
128 static void ehci_npcm7xx_class_init(ObjectClass *oc, void *data)
129 {
130     SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
131     DeviceClass *dc = DEVICE_CLASS(oc);
132 
133     sec->capsbase = 0x0;
134     sec->opregbase = 0x10;
135     sec->portscbase = 0x44;
136     sec->portnr = 1;
137     set_bit(DEVICE_CATEGORY_USB, dc->categories);
138 }
139 
140 static void ehci_tegra2_class_init(ObjectClass *oc, void *data)
141 {
142     SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
143     DeviceClass *dc = DEVICE_CLASS(oc);
144 
145     sec->capsbase = 0x100;
146     sec->opregbase = 0x140;
147     set_bit(DEVICE_CATEGORY_USB, dc->categories);
148 }
149 
150 static void ehci_ppc4xx_init(Object *o)
151 {
152     EHCISysBusState *s = SYS_BUS_EHCI(o);
153 
154     s->ehci.companion_enable = true;
155 }
156 
157 static void ehci_ppc4xx_class_init(ObjectClass *oc, void *data)
158 {
159     SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
160     DeviceClass *dc = DEVICE_CLASS(oc);
161 
162     sec->capsbase = 0x0;
163     sec->opregbase = 0x10;
164     set_bit(DEVICE_CATEGORY_USB, dc->categories);
165 }
166 
167 /*
168  * Faraday FUSBH200 USB 2.0 EHCI
169  */
170 
171 /**
172  * FUSBH200EHCIRegs:
173  * @FUSBH200_REG_EOF_ASTR: EOF/Async. Sleep Timer Register
174  * @FUSBH200_REG_BMCSR: Bus Monitor Control/Status Register
175  */
176 enum FUSBH200EHCIRegs {
177     FUSBH200_REG_EOF_ASTR = 0x34,
178     FUSBH200_REG_BMCSR    = 0x40,
179 };
180 
181 static uint64_t fusbh200_ehci_read(void *opaque, hwaddr addr, unsigned size)
182 {
183     EHCIState *s = opaque;
184     hwaddr off = s->opregbase + s->portscbase + 4 * s->portnr + addr;
185 
186     switch (off) {
187     case FUSBH200_REG_EOF_ASTR:
188         return 0x00000041;
189     case FUSBH200_REG_BMCSR:
190         /* High-Speed, VBUS valid, interrupt level-high active */
191         return (2 << 9) | (1 << 8) | (1 << 3);
192     }
193 
194     return 0;
195 }
196 
197 static void fusbh200_ehci_write(void *opaque, hwaddr addr, uint64_t val,
198                                 unsigned size)
199 {
200 }
201 
202 static const MemoryRegionOps fusbh200_ehci_mmio_ops = {
203     .read = fusbh200_ehci_read,
204     .write = fusbh200_ehci_write,
205     .valid.min_access_size = 4,
206     .valid.max_access_size = 4,
207     .endianness = DEVICE_LITTLE_ENDIAN,
208 };
209 
210 static void fusbh200_ehci_init(Object *obj)
211 {
212     EHCISysBusState *i = SYS_BUS_EHCI(obj);
213     FUSBH200EHCIState *f = FUSBH200_EHCI(obj);
214     EHCIState *s = &i->ehci;
215 
216     memory_region_init_io(&f->mem_vendor, OBJECT(f), &fusbh200_ehci_mmio_ops, s,
217                           "fusbh200", 0x4c);
218     memory_region_add_subregion(&s->mem,
219                                 s->opregbase + s->portscbase + 4 * s->portnr,
220                                 &f->mem_vendor);
221 }
222 
223 static void fusbh200_ehci_class_init(ObjectClass *oc, void *data)
224 {
225     SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
226     DeviceClass *dc = DEVICE_CLASS(oc);
227 
228     sec->capsbase = 0x0;
229     sec->opregbase = 0x10;
230     sec->portscbase = 0x20;
231     sec->portnr = 1;
232     set_bit(DEVICE_CATEGORY_USB, dc->categories);
233 }
234 
235 static const TypeInfo ehci_sysbus_types[] = {
236     {
237         .name          = TYPE_SYS_BUS_EHCI,
238         .parent        = TYPE_SYS_BUS_DEVICE,
239         .instance_size = sizeof(EHCISysBusState),
240         .instance_init = ehci_sysbus_init,
241         .instance_finalize = ehci_sysbus_finalize,
242         .abstract      = true,
243         .class_init    = ehci_sysbus_class_init,
244         .class_size    = sizeof(SysBusEHCIClass),
245     },
246     {
247         .name          = TYPE_PLATFORM_EHCI,
248         .parent        = TYPE_SYS_BUS_EHCI,
249         .class_init    = ehci_platform_class_init,
250     },
251     {
252         .name          = TYPE_EXYNOS4210_EHCI,
253         .parent        = TYPE_SYS_BUS_EHCI,
254         .class_init    = ehci_exynos4210_class_init,
255     },
256     {
257         .name          = TYPE_AW_H3_EHCI,
258         .parent        = TYPE_SYS_BUS_EHCI,
259         .class_init    = ehci_aw_h3_class_init,
260     },
261     {
262         .name          = TYPE_NPCM7XX_EHCI,
263         .parent        = TYPE_SYS_BUS_EHCI,
264         .class_init    = ehci_npcm7xx_class_init,
265     },
266     {
267         .name          = TYPE_TEGRA2_EHCI,
268         .parent        = TYPE_SYS_BUS_EHCI,
269         .class_init    = ehci_tegra2_class_init,
270     },
271     {
272         .name          = TYPE_PPC4xx_EHCI,
273         .parent        = TYPE_SYS_BUS_EHCI,
274         .class_init    = ehci_ppc4xx_class_init,
275         .instance_init = ehci_ppc4xx_init,
276     },
277     {
278         .name          = TYPE_FUSBH200_EHCI,
279         .parent        = TYPE_SYS_BUS_EHCI,
280         .instance_size = sizeof(FUSBH200EHCIState),
281         .instance_init = fusbh200_ehci_init,
282         .class_init    = fusbh200_ehci_class_init,
283     },
284 };
285 
286 DEFINE_TYPES(ehci_sysbus_types)
287