1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include "qemu/osdep.h"
19#include "hw/usb/hcd-ehci.h"
20#include "hw/register.h"
21
22static const VMStateDescription vmstate_ehci_sysbus = {
23 .name = "ehci-sysbus",
24 .version_id = 2,
25 .minimum_version_id = 1,
26 .fields = (VMStateField[]) {
27 VMSTATE_STRUCT(ehci, EHCISysBusState, 2, vmstate_ehci, EHCIState),
28 VMSTATE_END_OF_LIST()
29 }
30};
31
32static Property ehci_sysbus_properties[] = {
33 DEFINE_PROP_UINT32("maxframes", EHCISysBusState, ehci.maxframes, 128),
34 DEFINE_PROP_END_OF_LIST(),
35};
36
37static void usb_ehci_sysbus_realize(DeviceState *dev, Error **errp)
38{
39 SysBusDevice *d = SYS_BUS_DEVICE(dev);
40 EHCISysBusState *i = SYS_BUS_EHCI(dev);
41 EHCIState *s = &i->ehci;
42
43 usb_ehci_realize(s, dev, errp);
44 sysbus_init_irq(d, &s->irq);
45}
46
47static void usb_ehci_sysbus_reset(DeviceState *dev)
48{
49 SysBusDevice *d = SYS_BUS_DEVICE(dev);
50 EHCISysBusState *i = SYS_BUS_EHCI(d);
51 EHCIState *s = &i->ehci;
52
53 ehci_reset(s);
54}
55
56static void ehci_sysbus_init(Object *obj)
57{
58 SysBusDevice *d = SYS_BUS_DEVICE(obj);
59 EHCISysBusState *i = SYS_BUS_EHCI(obj);
60 SysBusEHCIClass *sec = SYS_BUS_EHCI_GET_CLASS(obj);
61 EHCIState *s = &i->ehci;
62
63 s->capsbase = sec->capsbase;
64 s->opregbase = sec->opregbase;
65 s->portscbase = sec->portscbase;
66 s->portnr = sec->portnr;
67 s->as = &address_space_memory;
68
69 usb_ehci_init(s, DEVICE(obj));
70 sysbus_init_mmio(d, &s->mem);
71}
72
73static void ehci_sysbus_class_init(ObjectClass *klass, void *data)
74{
75 DeviceClass *dc = DEVICE_CLASS(klass);
76 SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(klass);
77
78 sec->portscbase = 0x44;
79 sec->portnr = NB_PORTS;
80
81 dc->realize = usb_ehci_sysbus_realize;
82 dc->vmsd = &vmstate_ehci_sysbus;
83 dc->props = ehci_sysbus_properties;
84 dc->reset = usb_ehci_sysbus_reset;
85 set_bit(DEVICE_CATEGORY_USB, dc->categories);
86}
87
88static const TypeInfo ehci_type_info = {
89 .name = TYPE_SYS_BUS_EHCI,
90 .parent = TYPE_SYS_BUS_DEVICE,
91 .instance_size = sizeof(EHCISysBusState),
92 .instance_init = ehci_sysbus_init,
93 .abstract = true,
94 .class_init = ehci_sysbus_class_init,
95 .class_size = sizeof(SysBusEHCIClass),
96};
97
98enum PS7USBRegs {
99 XLNX_ID = 0x0,
100 XLNX_HWGENERAL = 0x4,
101 XLNX_HWHOST = 0x8,
102 XLNX_HWTXBUF = 0x10,
103 XLNX_HWRXBUF = 0x14,
104 XLNX_DCIVERSION = 0x120,
105 XLNX_DCCPARAMS = 0x124,
106};
107
108
109enum ULPIRegs {
110 VENDOR_ID_L = 0x0,
111 VENDOR_ID_H = 0x1,
112 PRODUCT_ID_L = 0x2,
113 PRODUCT_ID_H = 0x3,
114 SCRATCH_REG_0 = 0x16,
115};
116
117REG32(ULPI_VIEWPORT, PS7USB_ULPIVP_OFFSET)
118 FIELD(ULPI_VIEWPORT, ULPIDATWR, 8, 0)
119 FIELD(ULPI_VIEWPORT, ULPIDATRD, 8, 8)
120 FIELD(ULPI_VIEWPORT, ULPIADDR, 8, 16)
121 FIELD(ULPI_VIEWPORT, ULPIPORT, 3, 24)
122 FIELD(ULPI_VIEWPORT, ULPISS, 1, 27)
123 FIELD(ULPI_VIEWPORT, ULPIRW, 1, 29)
124 FIELD(ULPI_VIEWPORT, ULPIRUN, 1, 30)
125 FIELD(ULPI_VIEWPORT, ULPIWU, 1, 31)
126
127static void ehci_xlnx_reset(DeviceState *dev)
128{
129 PS7USBState *s = XLNX_PS7_USB(dev);
130
131
132 s->ulpi_viewport = 0x8000000;
133
134 s->ulpireg[VENDOR_ID_L] = 0x24;
135 s->ulpireg[VENDOR_ID_H] = 0x04;
136 s->ulpireg[PRODUCT_ID_L] = 0x4;
137 s->ulpireg[PRODUCT_ID_H] = 0x0;
138
139}
140
141static void ehci_xlnx_class_init(ObjectClass *oc, void *data)
142{
143 SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
144 DeviceClass *dc = DEVICE_CLASS(oc);
145
146 dc->reset = ehci_xlnx_reset;
147 set_bit(DEVICE_CATEGORY_USB, dc->categories);
148 sec->capsbase = 0x100;
149 sec->opregbase = 0x140;
150}
151
152static uint64_t xlnx_devreg_read(void *opaque, hwaddr addr, unsigned size)
153{
154 EHCIState *s = opaque;
155
156
157
158 hwaddr offset = s->capsbase + 0x20 + addr;
159
160 switch (offset) {
161 case XLNX_DCIVERSION:
162 return 0x00000001;
163 case XLNX_DCCPARAMS:
164
165
166
167 return 0x0000010C;
168 }
169 return 0;
170}
171
172static uint64_t xlnx_hwreg_read(void *opaque, hwaddr addr, unsigned size)
173{
174
175
176
177 switch (addr) {
178 case XLNX_ID:
179 return XLNX_ID_DEFVAL;
180 case XLNX_HWGENERAL:
181 return XLNX_HWGENERAL_DEFVAL;
182 case XLNX_HWHOST:
183 return XLNX_HWHOST_DEFVAL;
184 case XLNX_HWTXBUF:
185 return XLNX_HWTXBUF_DEFVAL;
186 case XLNX_HWRXBUF:
187 return XLNX_HWRXBUF_DEFVAL;
188 }
189 return 0;
190}
191
192static uint64_t xlnx_ulpi_read(void *opaque, hwaddr addr, unsigned size)
193{
194 PS7USBState *s = opaque;
195
196 return s->ulpi_viewport;
197}
198
199static void xlnx_ulpi_write(void *opaque, hwaddr addr, uint64_t data,
200 unsigned size)
201{
202 PS7USBState *s = opaque;
203 uint8_t ulpiaddr;
204
205 s->ulpi_viewport &= ~ULPIREG_RWBITS_MASK;
206 s->ulpi_viewport |= data & ULPIREG_RWBITS_MASK;
207
208
209 if(F_EX32(s->ulpi_viewport, ULPI_VIEWPORT, ULPIWU)) {
210 s->ulpi_viewport = F_DP32(s->ulpi_viewport, ULPI_VIEWPORT, ULPIWU, 0);
211 }
212
213 if (F_EX32(s->ulpi_viewport, ULPI_VIEWPORT, ULPIRUN)) {
214 ulpiaddr = F_EX32(s->ulpi_viewport, ULPI_VIEWPORT, ULPIADDR);
215
216 if (F_EX32(s->ulpi_viewport, ULPI_VIEWPORT, ULPIRW)) {
217 s->ulpireg[ulpiaddr] = F_EX32(s->ulpi_viewport, ULPI_VIEWPORT,
218 ULPIDATWR);
219 } else {
220 s->ulpi_viewport = F_DP32(s->ulpi_viewport, ULPI_VIEWPORT,
221 ULPIDATRD, s->ulpireg[ulpiaddr]);
222 }
223
224 s->ulpi_viewport = F_DP32(s->ulpi_viewport, ULPI_VIEWPORT, ULPIRUN, 0);
225 }
226}
227
228static const MemoryRegionOps ps7usb_devreg_ops = {
229 .read = xlnx_devreg_read,
230 .valid.min_access_size = 4,
231 .valid.max_access_size = 4,
232 .endianness = DEVICE_LITTLE_ENDIAN,
233};
234
235static const MemoryRegionOps ps7usb_hwreg_ops = {
236 .read = xlnx_hwreg_read,
237 .valid.min_access_size = 4,
238 .valid.max_access_size = 4,
239 .endianness = DEVICE_LITTLE_ENDIAN,
240};
241
242static const MemoryRegionOps ps7usb_ulpi_ops = {
243 .read = xlnx_ulpi_read,
244 .write = xlnx_ulpi_write,
245 .valid.min_access_size = 4,
246 .valid.max_access_size = 4,
247 .endianness = DEVICE_LITTLE_ENDIAN,
248};
249
250static void ehci_xlnx_init(Object *Obj)
251{
252 EHCISysBusState *p = SYS_BUS_EHCI(Obj);
253 PS7USBState *s = XLNX_PS7_USB(Obj);
254 EHCIState *pp = &p->ehci;
255 memory_region_init_io(&s->mem_hwreg, Obj, &ps7usb_hwreg_ops, pp,
256 "ps7usb_hwreg", PS7USB_HWREG_SIZE);
257 memory_region_add_subregion(&pp->mem, PS7USB_HWREG_OFFSET, &s->mem_hwreg);
258
259 memory_region_init_io(&s->mem_devreg, Obj, &ps7usb_devreg_ops, pp,
260 "ps7usb_devicemode", PS7USB_DEVREG_SIZE);
261 memory_region_add_subregion(&pp->mem, PS7USB_DEVREG_OFFSET, &s->mem_devreg);
262
263 memory_region_init_io(&s->mem_ulpi, Obj, &ps7usb_ulpi_ops, s,
264 "ps7usb_ulpi_viewport", PS7USB_ULPIVP_SIZE);
265 memory_region_add_subregion(&pp->mem, PS7USB_ULPIVP_OFFSET, &s->mem_ulpi);
266}
267
268static const TypeInfo ehci_xlnx_type_info = {
269 .name = TYPE_XLNX_PS7_USB,
270 .parent = TYPE_SYS_BUS_EHCI,
271 .class_init = ehci_xlnx_class_init,
272 .instance_size = sizeof(PS7USBState),
273 .instance_init = ehci_xlnx_init,
274};
275
276static void ehci_exynos4210_class_init(ObjectClass *oc, void *data)
277{
278 SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
279 DeviceClass *dc = DEVICE_CLASS(oc);
280
281 sec->capsbase = 0x0;
282 sec->opregbase = 0x10;
283 set_bit(DEVICE_CATEGORY_USB, dc->categories);
284}
285
286static const TypeInfo ehci_exynos4210_type_info = {
287 .name = TYPE_EXYNOS4210_EHCI,
288 .parent = TYPE_SYS_BUS_EHCI,
289 .class_init = ehci_exynos4210_class_init,
290};
291
292static void ehci_tegra2_class_init(ObjectClass *oc, void *data)
293{
294 SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
295 DeviceClass *dc = DEVICE_CLASS(oc);
296
297 sec->capsbase = 0x100;
298 sec->opregbase = 0x140;
299 set_bit(DEVICE_CATEGORY_USB, dc->categories);
300}
301
302static const TypeInfo ehci_tegra2_type_info = {
303 .name = TYPE_TEGRA2_EHCI,
304 .parent = TYPE_SYS_BUS_EHCI,
305 .class_init = ehci_tegra2_class_init,
306};
307
308
309
310
311
312
313
314
315
316
317enum FUSBH200EHCIRegs {
318 FUSBH200_REG_EOF_ASTR = 0x34,
319 FUSBH200_REG_BMCSR = 0x40,
320};
321
322static uint64_t fusbh200_ehci_read(void *opaque, hwaddr addr, unsigned size)
323{
324 EHCIState *s = opaque;
325 hwaddr off = s->opregbase + s->portscbase + 4 * s->portnr + addr;
326
327 switch (off) {
328 case FUSBH200_REG_EOF_ASTR:
329 return 0x00000041;
330 case FUSBH200_REG_BMCSR:
331
332 return (2 << 9) | (1 << 8) | (1 << 3);
333 }
334
335 return 0;
336}
337
338static void fusbh200_ehci_write(void *opaque, hwaddr addr, uint64_t val,
339 unsigned size)
340{
341}
342
343static const MemoryRegionOps fusbh200_ehci_mmio_ops = {
344 .read = fusbh200_ehci_read,
345 .write = fusbh200_ehci_write,
346 .valid.min_access_size = 4,
347 .valid.max_access_size = 4,
348 .endianness = DEVICE_LITTLE_ENDIAN,
349};
350
351static void fusbh200_ehci_init(Object *obj)
352{
353 EHCISysBusState *i = SYS_BUS_EHCI(obj);
354 FUSBH200EHCIState *f = FUSBH200_EHCI(obj);
355 EHCIState *s = &i->ehci;
356
357 memory_region_init_io(&f->mem_vendor, OBJECT(f), &fusbh200_ehci_mmio_ops, s,
358 "fusbh200", 0x4c);
359 memory_region_add_subregion(&s->mem,
360 s->opregbase + s->portscbase + 4 * s->portnr,
361 &f->mem_vendor);
362}
363
364static void fusbh200_ehci_class_init(ObjectClass *oc, void *data)
365{
366 SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
367 DeviceClass *dc = DEVICE_CLASS(oc);
368
369 sec->capsbase = 0x0;
370 sec->opregbase = 0x10;
371 sec->portscbase = 0x20;
372 sec->portnr = 1;
373 set_bit(DEVICE_CATEGORY_USB, dc->categories);
374}
375
376static const TypeInfo ehci_fusbh200_type_info = {
377 .name = TYPE_FUSBH200_EHCI,
378 .parent = TYPE_SYS_BUS_EHCI,
379 .instance_size = sizeof(FUSBH200EHCIState),
380 .instance_init = fusbh200_ehci_init,
381 .class_init = fusbh200_ehci_class_init,
382};
383
384static void ehci_sysbus_register_types(void)
385{
386 type_register_static(&ehci_type_info);
387 type_register_static(&ehci_xlnx_type_info);
388 type_register_static(&ehci_exynos4210_type_info);
389 type_register_static(&ehci_tegra2_type_info);
390 type_register_static(&ehci_fusbh200_type_info);
391}
392
393type_init(ehci_sysbus_register_types)
394