From: Kuo-Jung Su <dant...@faraday-tech.com> Add Faraday FUSBH200 support, which is slightly different from EHCI spec. (Or maybe simply a bad/wrong implementation...)
Signed-off-by: Kuo-Jung Su <dant...@faraday-tech.com> Cc: Gerd Hoffmann <kra...@redhat.com> Cc: Andreas <afaer...@suse.de> Cc: Peter Crosthwaite <peter.crosthwa...@xilinx.com> --- hw/usb/hcd-ehci-sysbus.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++ hw/usb/hcd-ehci.h | 5 ++++ 2 files changed, 71 insertions(+) diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c index ae2db1a..404a227 100644 --- a/hw/usb/hcd-ehci-sysbus.c +++ b/hw/usb/hcd-ehci-sysbus.c @@ -17,6 +17,49 @@ #include "hw/usb/hcd-ehci.h" +/* + * Faraday FUSBH200 USB 2.0 EHCI + */ + +static uint64_t +ehci_fusbh200_read(void *ptr, hwaddr addr, unsigned size) +{ + hwaddr off = 0x34 + addr; + + switch (off) { + case 0x34: /* fusbh200: EOF/Async. Sleep Timer Register */ + return 0x00000041; + case 0x40: /* fusbh200: Bus Monitor Control/Status Register */ + /* High-Speed, VBUS valid, interrupt level-high active */ + return (2 << 9) | (1 << 8) | (1 << 3); + } + + return 0; +} + +static void +ehci_fusbh200_write(void *ptr, hwaddr addr, uint64_t val, unsigned size) +{ +} + +static const MemoryRegionOps ehci_mmio_fusbh200_ops = { + .read = ehci_fusbh200_read, + .write = ehci_fusbh200_write, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void +usb_ehci_fusbh200_initfn(EHCIState *s, DeviceState *dev) +{ + memory_region_init_io(&s->mem_vendor, &ehci_mmio_fusbh200_ops, s, + "fusbh200", 0x4c); + memory_region_add_subregion(&s->mem, + s->opregbase + s->portscbase + 4 * s->portnr, + &s->mem_vendor); +} + static const VMStateDescription vmstate_ehci_sysbus = { .name = "ehci-sysbus", .version_id = 2, @@ -46,6 +89,9 @@ static void usb_ehci_sysbus_realizefn(DeviceState *dev, Error **errp) s->dma = &dma_context_memory; usb_ehci_initfn(s, dev); + if (sec->vendor_init) { + sec->vendor_init(s, DEVICE(dev)); + } sysbus_init_irq(d, &s->irq); sysbus_init_mmio(d, &s->mem); } @@ -76,6 +122,7 @@ static void ehci_xlnx_class_init(ObjectClass *oc, void *data) sec->opregbase = 0x140; sec->portscbase = 0x44; sec->portnr = NB_PORTS; + sec->vendor_init = NULL; } static const TypeInfo ehci_xlnx_type_info = { @@ -92,6 +139,7 @@ static void ehci_exynos4210_class_init(ObjectClass *oc, void *data) sec->opregbase = 0x10; sec->portscbase = 0x44; sec->portnr = NB_PORTS; + sec->vendor_init = NULL; } static const TypeInfo ehci_exynos4210_type_info = { @@ -100,11 +148,29 @@ static const TypeInfo ehci_exynos4210_type_info = { .class_init = ehci_exynos4210_class_init, }; +static void ehci_fusbh200_class_init(ObjectClass *oc, void *data) +{ + SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); + + sec->capsbase = 0x0; + sec->opregbase = 0x10; + sec->portscbase = 0x20; + sec->portnr = 1; + sec->vendor_init = usb_ehci_fusbh200_initfn; +} + +static const TypeInfo ehci_fusbh200_type_info = { + .name = TYPE_FUSBH200_EHCI, + .parent = TYPE_SYS_BUS_EHCI, + .class_init = ehci_fusbh200_class_init, +}; + static void ehci_sysbus_register_types(void) { type_register_static(&ehci_type_info); type_register_static(&ehci_xlnx_type_info); type_register_static(&ehci_exynos4210_type_info); + type_register_static(&ehci_fusbh200_type_info); } type_init(ehci_sysbus_register_types) diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index e587b67..3ca9c8f 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -261,6 +261,7 @@ struct EHCIState { MemoryRegion mem_caps; MemoryRegion mem_opreg; MemoryRegion mem_ports; + MemoryRegion mem_vendor; int companion_count; uint16_t capsbase; uint16_t opregbase; @@ -336,6 +337,7 @@ typedef struct EHCIPCIState { #define TYPE_SYS_BUS_EHCI "sysbus-ehci-usb" #define TYPE_EXYNOS4210_EHCI "exynos4210-ehci-usb" +#define TYPE_FUSBH200_EHCI "fusbh200-ehci-usb" #define SYS_BUS_EHCI(obj) \ OBJECT_CHECK(EHCISysBusState, (obj), TYPE_SYS_BUS_EHCI) @@ -361,6 +363,9 @@ typedef struct SysBusEHCIClass { uint16_t opregbase; uint16_t portscbase; uint16_t portnr; + + /* vendor specific init function */ + void (*vendor_init)(EHCIState *s, DeviceState *dev); } SysBusEHCIClass; #endif -- 1.7.9.5