2 * Copyright (c) 2018, Impinj, Inc.
4 * Chipidea USB block emulation code
6 * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
8 * This work is licensed under the terms of the GNU GPL, version 2 or later.
9 * See the COPYING file in the top-level directory.
12 #include "qemu/osdep.h"
13 #include "hw/usb/hcd-ehci.h"
14 #include "hw/usb/chipidea.h"
15 #include "qemu/module.h"
18 CHIPIDEA_USBx_DCIVERSION
= 0x000,
19 CHIPIDEA_USBx_DCCPARAMS
= 0x004,
20 CHIPIDEA_USBx_DCCPARAMS_HC
= BIT(8),
23 static uint64_t chipidea_read(void *opaque
, hwaddr offset
,
29 static void chipidea_write(void *opaque
, hwaddr offset
,
30 uint64_t value
, unsigned size
)
34 static const struct MemoryRegionOps chipidea_ops
= {
35 .read
= chipidea_read
,
36 .write
= chipidea_write
,
37 .endianness
= DEVICE_NATIVE_ENDIAN
,
40 * Our device would not work correctly if the guest was doing
41 * unaligned access. This might not be a limitation on the
42 * real device but in practice there is no reason for a guest
43 * to access this device unaligned.
51 static uint64_t chipidea_dc_read(void *opaque
, hwaddr offset
,
55 case CHIPIDEA_USBx_DCIVERSION
:
57 case CHIPIDEA_USBx_DCCPARAMS
:
59 * Real hardware (at least i.MX7) will also report the
60 * controller as "Device Capable" (and 8 supported endpoints),
61 * but there doesn't seem to be much point in doing so, since
62 * we don't emulate that part.
64 return CHIPIDEA_USBx_DCCPARAMS_HC
;
70 static void chipidea_dc_write(void *opaque
, hwaddr offset
,
71 uint64_t value
, unsigned size
)
75 static const struct MemoryRegionOps chipidea_dc_ops
= {
76 .read
= chipidea_dc_read
,
77 .write
= chipidea_dc_write
,
78 .endianness
= DEVICE_NATIVE_ENDIAN
,
81 * Our device would not work correctly if the guest was doing
82 * unaligned access. This might not be a limitation on the real
83 * device but in practice there is no reason for a guest to access
84 * this device unaligned.
92 static void chipidea_init(Object
*obj
)
94 EHCIState
*ehci
= &SYS_BUS_EHCI(obj
)->ehci
;
95 ChipideaState
*ci
= CHIPIDEA(obj
);
98 for (i
= 0; i
< ARRAY_SIZE(ci
->iomem
); i
++) {
103 const struct MemoryRegionOps
*ops
;
104 } regions
[ARRAY_SIZE(ci
->iomem
)] = {
106 * Registers located between offsets 0x000 and 0xFC
109 .name
= TYPE_CHIPIDEA
".misc",
112 .ops
= &chipidea_ops
,
115 * Registers located between offsets 0x1A4 and 0x1DC
118 .name
= TYPE_CHIPIDEA
".endpoints",
120 .size
= 0x1DC - 0x1A4 + 4,
121 .ops
= &chipidea_ops
,
124 * USB_x_DCIVERSION and USB_x_DCCPARAMS
127 .name
= TYPE_CHIPIDEA
".dc",
130 .ops
= &chipidea_dc_ops
,
134 memory_region_init_io(&ci
->iomem
[i
],
141 memory_region_add_subregion(&ehci
->mem
,
147 static void chipidea_class_init(ObjectClass
*klass
, void *data
)
149 DeviceClass
*dc
= DEVICE_CLASS(klass
);
150 SysBusEHCIClass
*sec
= SYS_BUS_EHCI_CLASS(klass
);
153 * Offsets used were taken from i.MX7Dual Applications Processor
154 * Reference Manual, Rev 0.1, p. 3177, Table 11-59
156 sec
->capsbase
= 0x100;
157 sec
->opregbase
= 0x140;
160 set_bit(DEVICE_CATEGORY_USB
, dc
->categories
);
161 dc
->desc
= "Chipidea USB Module";
164 static const TypeInfo chipidea_info
= {
165 .name
= TYPE_CHIPIDEA
,
166 .parent
= TYPE_SYS_BUS_EHCI
,
167 .instance_size
= sizeof(ChipideaState
),
168 .instance_init
= chipidea_init
,
169 .class_init
= chipidea_class_init
,
172 static void chipidea_register_type(void)
174 type_register_static(&chipidea_info
);
176 type_init(chipidea_register_type
)