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-dep.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
 117DEP_REG32(ULPI_VIEWPORT, PS7USB_ULPIVP_OFFSET)
 118    DEP_FIELD(ULPI_VIEWPORT, ULPIDATWR, 8, 0)
 119    DEP_FIELD(ULPI_VIEWPORT, ULPIDATRD, 8, 8)
 120    DEP_FIELD(ULPI_VIEWPORT, ULPIADDR, 8, 16)
 121    DEP_FIELD(ULPI_VIEWPORT, ULPIPORT, 3, 24)
 122    DEP_FIELD(ULPI_VIEWPORT, ULPISS, 1, 27)
 123    DEP_FIELD(ULPI_VIEWPORT, ULPIRW, 1, 29)
 124    DEP_FIELD(ULPI_VIEWPORT, ULPIRUN, 1, 30)
 125    DEP_FIELD(ULPI_VIEWPORT, ULPIWU, 1, 31)
 126
 127static void ehci_xlnx_reset(DeviceState *dev)
 128{
 129    PS7USBState *s = XLNX_PS7_USB(dev);
 130    SysBusDevice *d = SYS_BUS_DEVICE(dev);
 131    EHCISysBusState *i = SYS_BUS_EHCI(d);
 132    EHCIState *es = &i->ehci;
 133
 134    ehci_reset(es);
 135
 136    /* Show phy in normal functioning state after init */
 137    s->ulpi_viewport = 0x8000000;
 138    /* Vendor and product ID are as per micron ulpi phy specifications */
 139    s->ulpireg[VENDOR_ID_L] = 0x24;
 140    s->ulpireg[VENDOR_ID_H] = 0x04;
 141    s->ulpireg[PRODUCT_ID_L] = 0x4;
 142    s->ulpireg[PRODUCT_ID_H] = 0x0;
 143
 144}
 145
 146static void ehci_xlnx_class_init(ObjectClass *oc, void *data)
 147{
 148    SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
 149    DeviceClass *dc = DEVICE_CLASS(oc);
 150
 151    dc->reset = ehci_xlnx_reset;
 152    set_bit(DEVICE_CATEGORY_USB, dc->categories);
 153    sec->capsbase = 0x100;
 154    sec->opregbase = 0x140;
 155}
 156
 157static uint64_t xlnx_devreg_read(void *opaque, hwaddr addr, unsigned size)
 158{
 159    EHCIState *s = opaque;
 160        /* DCIVERSION and DCCPARAMS are mapped at 0x20 words distance from
 161         * end of capacity registers
 162         */
 163    hwaddr offset = s->capsbase + 0x20 + addr;
 164
 165    switch (offset) {
 166    case XLNX_DCIVERSION:
 167        return 0x00000001;
 168    case XLNX_DCCPARAMS:
 169        /* Host mode enabled
 170         * Number of endpoints fixed to 12 as per zynq-7000
 171         */
 172        return 0x0000010C;
 173    }
 174    return 0;
 175}
 176
 177static uint64_t xlnx_hwreg_read(void *opaque, hwaddr addr, unsigned size)
 178{
 179    /* All the following registers will just read out default values as per
 180     * dwc_usb2_hs_device_controller spec
 181     */
 182    switch (addr) {
 183    case XLNX_ID:
 184        return XLNX_ID_DEFVAL;
 185    case XLNX_HWGENERAL:
 186        return XLNX_HWGENERAL_DEFVAL;
 187    case XLNX_HWHOST:
 188        return XLNX_HWHOST_DEFVAL;
 189    case XLNX_HWTXBUF:
 190        return XLNX_HWTXBUF_DEFVAL;
 191    case XLNX_HWRXBUF:
 192        return XLNX_HWRXBUF_DEFVAL;
 193    }
 194    return 0;
 195}
 196
 197static uint64_t xlnx_ulpi_read(void *opaque, hwaddr addr, unsigned size)
 198{
 199    PS7USBState *s = opaque;
 200
 201    return s->ulpi_viewport;
 202}
 203
 204static void xlnx_ulpi_write(void *opaque, hwaddr addr, uint64_t data,
 205                            unsigned size)
 206{
 207    PS7USBState *s = opaque;
 208    uint8_t ulpiaddr;
 209    /* Clear RW feilds before writes */
 210    s->ulpi_viewport &= ~ULPIREG_RWBITS_MASK;
 211    s->ulpi_viewport |= data & ULPIREG_RWBITS_MASK;
 212
 213    /* ULPI Wake Up call : Clear the bit when set */
 214    if(DEP_F_EX32(s->ulpi_viewport, ULPI_VIEWPORT, ULPIWU)) {
 215        s->ulpi_viewport = DEP_F_DP32(s->ulpi_viewport, ULPI_VIEWPORT, ULPIWU, 0);
 216    }
 217
 218    if (DEP_F_EX32(s->ulpi_viewport, ULPI_VIEWPORT, ULPIRUN)) {
 219        ulpiaddr = DEP_F_EX32(s->ulpi_viewport, ULPI_VIEWPORT, ULPIADDR);
 220
 221        if (DEP_F_EX32(s->ulpi_viewport, ULPI_VIEWPORT, ULPIRW)) {
 222            s->ulpireg[ulpiaddr] = DEP_F_EX32(s->ulpi_viewport, ULPI_VIEWPORT,
 223                                          ULPIDATWR);
 224        } else {
 225            s->ulpi_viewport = DEP_F_DP32(s->ulpi_viewport, ULPI_VIEWPORT,
 226                                      ULPIDATRD, s->ulpireg[ulpiaddr]);
 227        }
 228
 229        s->ulpi_viewport = DEP_F_DP32(s->ulpi_viewport, ULPI_VIEWPORT, ULPIRUN, 0);
 230    }
 231}
 232
 233static const MemoryRegionOps ps7usb_devreg_ops = {
 234    .read = xlnx_devreg_read,
 235    .valid.min_access_size = 4,
 236    .valid.max_access_size = 4,
 237    .endianness = DEVICE_LITTLE_ENDIAN,
 238};
 239
 240static const MemoryRegionOps ps7usb_hwreg_ops = {
 241    .read = xlnx_hwreg_read,
 242    .valid.min_access_size = 4,
 243    .valid.max_access_size = 4,
 244    .endianness = DEVICE_LITTLE_ENDIAN,
 245};
 246
 247static const MemoryRegionOps ps7usb_ulpi_ops = {
 248    .read = xlnx_ulpi_read,
 249    .write = xlnx_ulpi_write,
 250    .valid.min_access_size = 4,
 251    .valid.max_access_size = 4,
 252    .endianness = DEVICE_LITTLE_ENDIAN,
 253};
 254
 255static void ehci_xlnx_init(Object *Obj)
 256{
 257    EHCISysBusState *p = SYS_BUS_EHCI(Obj);
 258    PS7USBState *s = XLNX_PS7_USB(Obj);
 259    EHCIState *pp = &p->ehci;
 260    memory_region_init_io(&s->mem_hwreg, Obj, &ps7usb_hwreg_ops, pp,
 261                          "ps7usb_hwreg", PS7USB_HWREG_SIZE);
 262    memory_region_add_subregion(&pp->mem, PS7USB_HWREG_OFFSET, &s->mem_hwreg);
 263
 264    memory_region_init_io(&s->mem_devreg, Obj, &ps7usb_devreg_ops, pp,
 265                          "ps7usb_devicemode", PS7USB_DEVREG_SIZE);
 266    memory_region_add_subregion(&pp->mem, PS7USB_DEVREG_OFFSET, &s->mem_devreg);
 267
 268    memory_region_init_io(&s->mem_ulpi, Obj, &ps7usb_ulpi_ops, s,
 269                          "ps7usb_ulpi_viewport", PS7USB_ULPIVP_SIZE);
 270    memory_region_add_subregion(&pp->mem, PS7USB_ULPIVP_OFFSET, &s->mem_ulpi);
 271}
 272
 273static const TypeInfo ehci_xlnx_type_info = {
 274    .name          = TYPE_XLNX_PS7_USB,
 275    .parent        = TYPE_SYS_BUS_EHCI,
 276    .class_init    = ehci_xlnx_class_init,
 277    .instance_size = sizeof(PS7USBState),
 278    .instance_init = ehci_xlnx_init,
 279};
 280
 281static void ehci_exynos4210_class_init(ObjectClass *oc, void *data)
 282{
 283    SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
 284    DeviceClass *dc = DEVICE_CLASS(oc);
 285
 286    sec->capsbase = 0x0;
 287    sec->opregbase = 0x10;
 288    set_bit(DEVICE_CATEGORY_USB, dc->categories);
 289}
 290
 291static const TypeInfo ehci_exynos4210_type_info = {
 292    .name          = TYPE_EXYNOS4210_EHCI,
 293    .parent        = TYPE_SYS_BUS_EHCI,
 294    .class_init    = ehci_exynos4210_class_init,
 295};
 296
 297static void ehci_tegra2_class_init(ObjectClass *oc, void *data)
 298{
 299    SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
 300    DeviceClass *dc = DEVICE_CLASS(oc);
 301
 302    sec->capsbase = 0x100;
 303    sec->opregbase = 0x140;
 304    set_bit(DEVICE_CATEGORY_USB, dc->categories);
 305}
 306
 307static const TypeInfo ehci_tegra2_type_info = {
 308    .name          = TYPE_TEGRA2_EHCI,
 309    .parent        = TYPE_SYS_BUS_EHCI,
 310    .class_init    = ehci_tegra2_class_init,
 311};
 312
 313/*
 314 * Faraday FUSBH200 USB 2.0 EHCI
 315 */
 316
 317/**
 318 * FUSBH200EHCIRegs:
 319 * @FUSBH200_REG_EOF_ASTR: EOF/Async. Sleep Timer Register
 320 * @FUSBH200_REG_BMCSR: Bus Monitor Control/Status Register
 321 */
 322enum FUSBH200EHCIRegs {
 323    FUSBH200_REG_EOF_ASTR = 0x34,
 324    FUSBH200_REG_BMCSR    = 0x40,
 325};
 326
 327static uint64_t fusbh200_ehci_read(void *opaque, hwaddr addr, unsigned size)
 328{
 329    EHCIState *s = opaque;
 330    hwaddr off = s->opregbase + s->portscbase + 4 * s->portnr + addr;
 331
 332    switch (off) {
 333    case FUSBH200_REG_EOF_ASTR:
 334        return 0x00000041;
 335    case FUSBH200_REG_BMCSR:
 336        /* High-Speed, VBUS valid, interrupt level-high active */
 337        return (2 << 9) | (1 << 8) | (1 << 3);
 338    }
 339
 340    return 0;
 341}
 342
 343static void fusbh200_ehci_write(void *opaque, hwaddr addr, uint64_t val,
 344                                unsigned size)
 345{
 346}
 347
 348static const MemoryRegionOps fusbh200_ehci_mmio_ops = {
 349    .read = fusbh200_ehci_read,
 350    .write = fusbh200_ehci_write,
 351    .valid.min_access_size = 4,
 352    .valid.max_access_size = 4,
 353    .endianness = DEVICE_LITTLE_ENDIAN,
 354};
 355
 356static void fusbh200_ehci_init(Object *obj)
 357{
 358    EHCISysBusState *i = SYS_BUS_EHCI(obj);
 359    FUSBH200EHCIState *f = FUSBH200_EHCI(obj);
 360    EHCIState *s = &i->ehci;
 361
 362    memory_region_init_io(&f->mem_vendor, OBJECT(f), &fusbh200_ehci_mmio_ops, s,
 363                          "fusbh200", 0x4c);
 364    memory_region_add_subregion(&s->mem,
 365                                s->opregbase + s->portscbase + 4 * s->portnr,
 366                                &f->mem_vendor);
 367}
 368
 369static void fusbh200_ehci_class_init(ObjectClass *oc, void *data)
 370{
 371    SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
 372    DeviceClass *dc = DEVICE_CLASS(oc);
 373
 374    sec->capsbase = 0x0;
 375    sec->opregbase = 0x10;
 376    sec->portscbase = 0x20;
 377    sec->portnr = 1;
 378    set_bit(DEVICE_CATEGORY_USB, dc->categories);
 379}
 380
 381static const TypeInfo ehci_fusbh200_type_info = {
 382    .name          = TYPE_FUSBH200_EHCI,
 383    .parent        = TYPE_SYS_BUS_EHCI,
 384    .instance_size = sizeof(FUSBH200EHCIState),
 385    .instance_init = fusbh200_ehci_init,
 386    .class_init    = fusbh200_ehci_class_init,
 387};
 388
 389static void ehci_sysbus_register_types(void)
 390{
 391    type_register_static(&ehci_type_info);
 392    type_register_static(&ehci_xlnx_type_info);
 393    type_register_static(&ehci_exynos4210_type_info);
 394    type_register_static(&ehci_tegra2_type_info);
 395    type_register_static(&ehci_fusbh200_type_info);
 396}
 397
 398type_init(ehci_sysbus_register_types)
 399