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 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 DEFINE_PROP_END_OF_LIST(), 38 }; 39 40 static void usb_ehci_sysbus_realize(DeviceState *dev, Error **errp) 41 { 42 SysBusDevice *d = SYS_BUS_DEVICE(dev); 43 EHCISysBusState *i = SYS_BUS_EHCI(dev); 44 EHCIState *s = &i->ehci; 45 46 usb_ehci_realize(s, dev, errp); 47 sysbus_init_irq(d, &s->irq); 48 } 49 50 static void usb_ehci_sysbus_reset(DeviceState *dev) 51 { 52 SysBusDevice *d = SYS_BUS_DEVICE(dev); 53 EHCISysBusState *i = SYS_BUS_EHCI(d); 54 EHCIState *s = &i->ehci; 55 56 ehci_reset(s); 57 } 58 59 static void ehci_sysbus_init(Object *obj) 60 { 61 SysBusDevice *d = SYS_BUS_DEVICE(obj); 62 EHCISysBusState *i = SYS_BUS_EHCI(obj); 63 SysBusEHCIClass *sec = SYS_BUS_EHCI_GET_CLASS(obj); 64 EHCIState *s = &i->ehci; 65 66 s->capsbase = sec->capsbase; 67 s->opregbase = sec->opregbase; 68 s->portscbase = sec->portscbase; 69 s->portnr = sec->portnr; 70 s->as = &address_space_memory; 71 72 usb_ehci_init(s, DEVICE(obj)); 73 sysbus_init_mmio(d, &s->mem); 74 } 75 76 static void ehci_sysbus_finalize(Object *obj) 77 { 78 EHCISysBusState *i = SYS_BUS_EHCI(obj); 79 EHCIState *s = &i->ehci; 80 81 usb_ehci_finalize(s); 82 } 83 84 static void ehci_sysbus_class_init(ObjectClass *klass, void *data) 85 { 86 DeviceClass *dc = DEVICE_CLASS(klass); 87 SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(klass); 88 89 sec->portscbase = 0x44; 90 sec->portnr = EHCI_PORTS; 91 92 dc->realize = usb_ehci_sysbus_realize; 93 dc->vmsd = &vmstate_ehci_sysbus; 94 device_class_set_props(dc, ehci_sysbus_properties); 95 device_class_set_legacy_reset(dc, usb_ehci_sysbus_reset); 96 set_bit(DEVICE_CATEGORY_USB, dc->categories); 97 } 98 99 static void ehci_platform_class_init(ObjectClass *oc, void *data) 100 { 101 SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); 102 DeviceClass *dc = DEVICE_CLASS(oc); 103 104 sec->capsbase = 0x0; 105 sec->opregbase = 0x20; 106 set_bit(DEVICE_CATEGORY_USB, dc->categories); 107 } 108 109 static void ehci_exynos4210_class_init(ObjectClass *oc, void *data) 110 { 111 SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); 112 DeviceClass *dc = DEVICE_CLASS(oc); 113 114 sec->capsbase = 0x0; 115 sec->opregbase = 0x10; 116 set_bit(DEVICE_CATEGORY_USB, dc->categories); 117 } 118 119 static void ehci_aw_h3_class_init(ObjectClass *oc, void *data) 120 { 121 SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); 122 DeviceClass *dc = DEVICE_CLASS(oc); 123 124 sec->capsbase = 0x0; 125 sec->opregbase = 0x10; 126 set_bit(DEVICE_CATEGORY_USB, dc->categories); 127 } 128 129 static void ehci_npcm7xx_class_init(ObjectClass *oc, void *data) 130 { 131 SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); 132 DeviceClass *dc = DEVICE_CLASS(oc); 133 134 sec->capsbase = 0x0; 135 sec->opregbase = 0x10; 136 sec->portscbase = 0x44; 137 sec->portnr = 1; 138 set_bit(DEVICE_CATEGORY_USB, dc->categories); 139 } 140 141 static void ehci_tegra2_class_init(ObjectClass *oc, void *data) 142 { 143 SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); 144 DeviceClass *dc = DEVICE_CLASS(oc); 145 146 sec->capsbase = 0x100; 147 sec->opregbase = 0x140; 148 set_bit(DEVICE_CATEGORY_USB, dc->categories); 149 } 150 151 static void ehci_ppc4xx_init(Object *o) 152 { 153 EHCISysBusState *s = SYS_BUS_EHCI(o); 154 155 s->ehci.companion_enable = true; 156 } 157 158 static void ehci_ppc4xx_class_init(ObjectClass *oc, void *data) 159 { 160 SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); 161 DeviceClass *dc = DEVICE_CLASS(oc); 162 163 sec->capsbase = 0x0; 164 sec->opregbase = 0x10; 165 set_bit(DEVICE_CATEGORY_USB, dc->categories); 166 } 167 168 /* 169 * Faraday FUSBH200 USB 2.0 EHCI 170 */ 171 172 /** 173 * FUSBH200EHCIRegs: 174 * @FUSBH200_REG_EOF_ASTR: EOF/Async. Sleep Timer Register 175 * @FUSBH200_REG_BMCSR: Bus Monitor Control/Status Register 176 */ 177 enum FUSBH200EHCIRegs { 178 FUSBH200_REG_EOF_ASTR = 0x34, 179 FUSBH200_REG_BMCSR = 0x40, 180 }; 181 182 static uint64_t fusbh200_ehci_read(void *opaque, hwaddr addr, unsigned size) 183 { 184 EHCIState *s = opaque; 185 hwaddr off = s->opregbase + s->portscbase + 4 * s->portnr + addr; 186 187 switch (off) { 188 case FUSBH200_REG_EOF_ASTR: 189 return 0x00000041; 190 case FUSBH200_REG_BMCSR: 191 /* High-Speed, VBUS valid, interrupt level-high active */ 192 return (2 << 9) | (1 << 8) | (1 << 3); 193 } 194 195 return 0; 196 } 197 198 static void fusbh200_ehci_write(void *opaque, hwaddr addr, uint64_t val, 199 unsigned size) 200 { 201 } 202 203 static const MemoryRegionOps fusbh200_ehci_mmio_ops = { 204 .read = fusbh200_ehci_read, 205 .write = fusbh200_ehci_write, 206 .valid.min_access_size = 4, 207 .valid.max_access_size = 4, 208 .endianness = DEVICE_LITTLE_ENDIAN, 209 }; 210 211 static void fusbh200_ehci_init(Object *obj) 212 { 213 EHCISysBusState *i = SYS_BUS_EHCI(obj); 214 FUSBH200EHCIState *f = FUSBH200_EHCI(obj); 215 EHCIState *s = &i->ehci; 216 217 memory_region_init_io(&f->mem_vendor, OBJECT(f), &fusbh200_ehci_mmio_ops, s, 218 "fusbh200", 0x4c); 219 memory_region_add_subregion(&s->mem, 220 s->opregbase + s->portscbase + 4 * s->portnr, 221 &f->mem_vendor); 222 } 223 224 static void fusbh200_ehci_class_init(ObjectClass *oc, void *data) 225 { 226 SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); 227 DeviceClass *dc = DEVICE_CLASS(oc); 228 229 sec->capsbase = 0x0; 230 sec->opregbase = 0x10; 231 sec->portscbase = 0x20; 232 sec->portnr = 1; 233 set_bit(DEVICE_CATEGORY_USB, dc->categories); 234 } 235 236 static const TypeInfo ehci_sysbus_types[] = { 237 { 238 .name = TYPE_SYS_BUS_EHCI, 239 .parent = TYPE_SYS_BUS_DEVICE, 240 .instance_size = sizeof(EHCISysBusState), 241 .instance_init = ehci_sysbus_init, 242 .instance_finalize = ehci_sysbus_finalize, 243 .abstract = true, 244 .class_init = ehci_sysbus_class_init, 245 .class_size = sizeof(SysBusEHCIClass), 246 }, 247 { 248 .name = TYPE_PLATFORM_EHCI, 249 .parent = TYPE_SYS_BUS_EHCI, 250 .class_init = ehci_platform_class_init, 251 }, 252 { 253 .name = TYPE_EXYNOS4210_EHCI, 254 .parent = TYPE_SYS_BUS_EHCI, 255 .class_init = ehci_exynos4210_class_init, 256 }, 257 { 258 .name = TYPE_AW_H3_EHCI, 259 .parent = TYPE_SYS_BUS_EHCI, 260 .class_init = ehci_aw_h3_class_init, 261 }, 262 { 263 .name = TYPE_NPCM7XX_EHCI, 264 .parent = TYPE_SYS_BUS_EHCI, 265 .class_init = ehci_npcm7xx_class_init, 266 }, 267 { 268 .name = TYPE_TEGRA2_EHCI, 269 .parent = TYPE_SYS_BUS_EHCI, 270 .class_init = ehci_tegra2_class_init, 271 }, 272 { 273 .name = TYPE_PPC4xx_EHCI, 274 .parent = TYPE_SYS_BUS_EHCI, 275 .class_init = ehci_ppc4xx_class_init, 276 .instance_init = ehci_ppc4xx_init, 277 }, 278 { 279 .name = TYPE_FUSBH200_EHCI, 280 .parent = TYPE_SYS_BUS_EHCI, 281 .instance_size = sizeof(FUSBH200EHCIState), 282 .instance_init = fusbh200_ehci_init, 283 .class_init = fusbh200_ehci_class_init, 284 }, 285 }; 286 287 DEFINE_TYPES(ehci_sysbus_types) 288