qemu/hw/usb/hcd-ehci-sysbus.c
<<
>>
Prefs
   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 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 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/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/* FIXME: Add the functionality of remaining phy registers */
 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    /* Show phy in normal functioning state after init */
 132    s->ulpi_viewport = 0x8000000;
 133    /* Vendor and product ID are as per micron ulpi phy specifications */
 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        /* DCIVERSION and DCCPARAMS are mapped at 0x20 words distance from
 156         * end of capacity registers
 157         */
 158    hwaddr offset = s->capsbase + 0x20 + addr;
 159
 160    switch (offset) {
 161    case XLNX_DCIVERSION:
 162        return 0x00000001;
 163    case XLNX_DCCPARAMS:
 164        /* Host mode enabled
 165         * Number of endpoints fixed to 12 as per zynq-7000
 166         */
 167        return 0x0000010C;
 168    }
 169    return 0;
 170}
 171
 172static uint64_t xlnx_hwreg_read(void *opaque, hwaddr addr, unsigned size)
 173{
 174    /* All the following registers will just read out default values as per
 175     * dwc_usb2_hs_device_controller spec
 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    /* Clear RW feilds before writes */
 205    s->ulpi_viewport &= ~ULPIREG_RWBITS_MASK;
 206    s->ulpi_viewport |= data & ULPIREG_RWBITS_MASK;
 207
 208    /* ULPI Wake Up call : Clear the bit when set */
 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 * Faraday FUSBH200 USB 2.0 EHCI
 310 */
 311
 312/**
 313 * FUSBH200EHCIRegs:
 314 * @FUSBH200_REG_EOF_ASTR: EOF/Async. Sleep Timer Register
 315 * @FUSBH200_REG_BMCSR: Bus Monitor Control/Status Register
 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        /* High-Speed, VBUS valid, interrupt level-high active */
 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