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 #include "qemu/module.h" 23 24 static const VMStateDescription vmstate_ehci_sysbus = { 25 .name = "ehci-sysbus", 26 .version_id = 2, 27 .minimum_version_id = 1, 28 .fields = (VMStateField[]) { 29 VMSTATE_STRUCT(ehci, EHCISysBusState, 2, vmstate_ehci, EHCIState), 30 VMSTATE_END_OF_LIST() 31 } 32 }; 33 34 static Property ehci_sysbus_properties[] = { 35 DEFINE_PROP_UINT32("maxframes", EHCISysBusState, ehci.maxframes, 128), 36 DEFINE_PROP_END_OF_LIST(), 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_class_init(ObjectClass *klass, void *data) 76 { 77 DeviceClass *dc = DEVICE_CLASS(klass); 78 SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(klass); 79 80 sec->portscbase = 0x44; 81 sec->portnr = NB_PORTS; 82 83 dc->realize = usb_ehci_sysbus_realize; 84 dc->vmsd = &vmstate_ehci_sysbus; 85 dc->props = ehci_sysbus_properties; 86 dc->reset = usb_ehci_sysbus_reset; 87 set_bit(DEVICE_CATEGORY_USB, dc->categories); 88 } 89 90 static const TypeInfo ehci_type_info = { 91 .name = TYPE_SYS_BUS_EHCI, 92 .parent = TYPE_SYS_BUS_DEVICE, 93 .instance_size = sizeof(EHCISysBusState), 94 .instance_init = ehci_sysbus_init, 95 .abstract = true, 96 .class_init = ehci_sysbus_class_init, 97 .class_size = sizeof(SysBusEHCIClass), 98 }; 99 100 static void ehci_platform_class_init(ObjectClass *oc, void *data) 101 { 102 SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); 103 DeviceClass *dc = DEVICE_CLASS(oc); 104 105 sec->capsbase = 0x0; 106 sec->opregbase = 0x20; 107 set_bit(DEVICE_CATEGORY_USB, dc->categories); 108 } 109 110 static const TypeInfo ehci_platform_type_info = { 111 .name = TYPE_PLATFORM_EHCI, 112 .parent = TYPE_SYS_BUS_EHCI, 113 .class_init = ehci_platform_class_init, 114 }; 115 116 static void ehci_xlnx_class_init(ObjectClass *oc, void *data) 117 { 118 SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); 119 DeviceClass *dc = DEVICE_CLASS(oc); 120 121 set_bit(DEVICE_CATEGORY_USB, dc->categories); 122 sec->capsbase = 0x100; 123 sec->opregbase = 0x140; 124 } 125 126 static const TypeInfo ehci_xlnx_type_info = { 127 .name = "xlnx,ps7-usb", 128 .parent = TYPE_SYS_BUS_EHCI, 129 .class_init = ehci_xlnx_class_init, 130 }; 131 132 static void ehci_exynos4210_class_init(ObjectClass *oc, void *data) 133 { 134 SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); 135 DeviceClass *dc = DEVICE_CLASS(oc); 136 137 sec->capsbase = 0x0; 138 sec->opregbase = 0x10; 139 set_bit(DEVICE_CATEGORY_USB, dc->categories); 140 } 141 142 static const TypeInfo ehci_exynos4210_type_info = { 143 .name = TYPE_EXYNOS4210_EHCI, 144 .parent = TYPE_SYS_BUS_EHCI, 145 .class_init = ehci_exynos4210_class_init, 146 }; 147 148 static void ehci_tegra2_class_init(ObjectClass *oc, void *data) 149 { 150 SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); 151 DeviceClass *dc = DEVICE_CLASS(oc); 152 153 sec->capsbase = 0x100; 154 sec->opregbase = 0x140; 155 set_bit(DEVICE_CATEGORY_USB, dc->categories); 156 } 157 158 static const TypeInfo ehci_tegra2_type_info = { 159 .name = TYPE_TEGRA2_EHCI, 160 .parent = TYPE_SYS_BUS_EHCI, 161 .class_init = ehci_tegra2_class_init, 162 }; 163 164 static void ehci_ppc4xx_init(Object *o) 165 { 166 EHCISysBusState *s = SYS_BUS_EHCI(o); 167 168 s->ehci.companion_enable = true; 169 } 170 171 static void ehci_ppc4xx_class_init(ObjectClass *oc, void *data) 172 { 173 SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); 174 DeviceClass *dc = DEVICE_CLASS(oc); 175 176 sec->capsbase = 0x0; 177 sec->opregbase = 0x10; 178 set_bit(DEVICE_CATEGORY_USB, dc->categories); 179 } 180 181 static const TypeInfo ehci_ppc4xx_type_info = { 182 .name = TYPE_PPC4xx_EHCI, 183 .parent = TYPE_SYS_BUS_EHCI, 184 .class_init = ehci_ppc4xx_class_init, 185 .instance_init = ehci_ppc4xx_init, 186 }; 187 188 /* 189 * Faraday FUSBH200 USB 2.0 EHCI 190 */ 191 192 /** 193 * FUSBH200EHCIRegs: 194 * @FUSBH200_REG_EOF_ASTR: EOF/Async. Sleep Timer Register 195 * @FUSBH200_REG_BMCSR: Bus Monitor Control/Status Register 196 */ 197 enum FUSBH200EHCIRegs { 198 FUSBH200_REG_EOF_ASTR = 0x34, 199 FUSBH200_REG_BMCSR = 0x40, 200 }; 201 202 static uint64_t fusbh200_ehci_read(void *opaque, hwaddr addr, unsigned size) 203 { 204 EHCIState *s = opaque; 205 hwaddr off = s->opregbase + s->portscbase + 4 * s->portnr + addr; 206 207 switch (off) { 208 case FUSBH200_REG_EOF_ASTR: 209 return 0x00000041; 210 case FUSBH200_REG_BMCSR: 211 /* High-Speed, VBUS valid, interrupt level-high active */ 212 return (2 << 9) | (1 << 8) | (1 << 3); 213 } 214 215 return 0; 216 } 217 218 static void fusbh200_ehci_write(void *opaque, hwaddr addr, uint64_t val, 219 unsigned size) 220 { 221 } 222 223 static const MemoryRegionOps fusbh200_ehci_mmio_ops = { 224 .read = fusbh200_ehci_read, 225 .write = fusbh200_ehci_write, 226 .valid.min_access_size = 4, 227 .valid.max_access_size = 4, 228 .endianness = DEVICE_LITTLE_ENDIAN, 229 }; 230 231 static void fusbh200_ehci_init(Object *obj) 232 { 233 EHCISysBusState *i = SYS_BUS_EHCI(obj); 234 FUSBH200EHCIState *f = FUSBH200_EHCI(obj); 235 EHCIState *s = &i->ehci; 236 237 memory_region_init_io(&f->mem_vendor, OBJECT(f), &fusbh200_ehci_mmio_ops, s, 238 "fusbh200", 0x4c); 239 memory_region_add_subregion(&s->mem, 240 s->opregbase + s->portscbase + 4 * s->portnr, 241 &f->mem_vendor); 242 } 243 244 static void fusbh200_ehci_class_init(ObjectClass *oc, void *data) 245 { 246 SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); 247 DeviceClass *dc = DEVICE_CLASS(oc); 248 249 sec->capsbase = 0x0; 250 sec->opregbase = 0x10; 251 sec->portscbase = 0x20; 252 sec->portnr = 1; 253 set_bit(DEVICE_CATEGORY_USB, dc->categories); 254 } 255 256 static const TypeInfo ehci_fusbh200_type_info = { 257 .name = TYPE_FUSBH200_EHCI, 258 .parent = TYPE_SYS_BUS_EHCI, 259 .instance_size = sizeof(FUSBH200EHCIState), 260 .instance_init = fusbh200_ehci_init, 261 .class_init = fusbh200_ehci_class_init, 262 }; 263 264 static void ehci_sysbus_register_types(void) 265 { 266 type_register_static(&ehci_type_info); 267 type_register_static(&ehci_platform_type_info); 268 type_register_static(&ehci_xlnx_type_info); 269 type_register_static(&ehci_exynos4210_type_info); 270 type_register_static(&ehci_tegra2_type_info); 271 type_register_static(&ehci_ppc4xx_type_info); 272 type_register_static(&ehci_fusbh200_type_info); 273 } 274 275 type_init(ehci_sysbus_register_types) 276