Commit 4e3d8b4b authored by Kuo-Jung Su's avatar Kuo-Jung Su Committed by Gerd Hoffmann
Browse files

usb/hcd-ehci: Add Faraday FUSBH200 support



Add Faraday FUSBH200 support, which is slightly different from EHCI spec.
(Or maybe simply a bad/wrong implementation...)

Signed-off-by: default avatarKuo-Jung Su <dantesu@faraday-tech.com>
Signed-off-by: default avatarAndreas Färber <afaerber@suse.de>
Signed-off-by: default avatarGerd Hoffmann <kraxel@redhat.com>
parent cc8d6a84
Loading
Loading
Loading
Loading
+75 −0
Original line number Diff line number Diff line
@@ -124,12 +124,87 @@ static const TypeInfo ehci_tegra2_type_info = {
    .class_init    = ehci_tegra2_class_init,
};

/*
 * Faraday FUSBH200 USB 2.0 EHCI
 */

/**
 * FUSBH200EHCIRegs:
 * @FUSBH200_REG_EOF_ASTR: EOF/Async. Sleep Timer Register
 * @FUSBH200_REG_BMCSR: Bus Monitor Control/Status Register
 */
enum FUSBH200EHCIRegs {
    FUSBH200_REG_EOF_ASTR = 0x34,
    FUSBH200_REG_BMCSR    = 0x40,
};

static uint64_t fusbh200_ehci_read(void *opaque, hwaddr addr, unsigned size)
{
    EHCIState *s = opaque;
    hwaddr off = s->opregbase + s->portscbase + 4 * s->portnr + addr;

    switch (off) {
    case FUSBH200_REG_EOF_ASTR:
        return 0x00000041;
    case FUSBH200_REG_BMCSR:
        /* High-Speed, VBUS valid, interrupt level-high active */
        return (2 << 9) | (1 << 8) | (1 << 3);
    }

    return 0;
}

static void fusbh200_ehci_write(void *opaque, hwaddr addr, uint64_t val,
                                unsigned size)
{
}

static const MemoryRegionOps fusbh200_ehci_mmio_ops = {
    .read = fusbh200_ehci_read,
    .write = fusbh200_ehci_write,
    .valid.min_access_size = 4,
    .valid.max_access_size = 4,
    .endianness = DEVICE_LITTLE_ENDIAN,
};

static void fusbh200_ehci_init(Object *obj)
{
    EHCISysBusState *i = SYS_BUS_EHCI(obj);
    FUSBH200EHCIState *f = FUSBH200_EHCI(obj);
    EHCIState *s = &i->ehci;

    memory_region_init_io(&f->mem_vendor, &fusbh200_ehci_mmio_ops, s,
                          "fusbh200", 0x4c);
    memory_region_add_subregion(&s->mem,
                                s->opregbase + s->portscbase + 4 * s->portnr,
                                &f->mem_vendor);
}

static void fusbh200_ehci_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;
}

static const TypeInfo ehci_fusbh200_type_info = {
    .name          = TYPE_FUSBH200_EHCI,
    .parent        = TYPE_SYS_BUS_EHCI,
    .instance_size = sizeof(FUSBH200EHCIState),
    .instance_init = fusbh200_ehci_init,
    .class_init    = fusbh200_ehci_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_tegra2_type_info);
    type_register_static(&ehci_fusbh200_type_info);
}

type_init(ehci_sysbus_register_types)
+12 −0
Original line number Diff line number Diff line
@@ -338,6 +338,7 @@ typedef struct EHCIPCIState {
#define TYPE_SYS_BUS_EHCI "sysbus-ehci-usb"
#define TYPE_EXYNOS4210_EHCI "exynos4210-ehci-usb"
#define TYPE_TEGRA2_EHCI "tegra2-ehci-usb"
#define TYPE_FUSBH200_EHCI "fusbh200-ehci-usb"

#define SYS_BUS_EHCI(obj) \
    OBJECT_CHECK(EHCISysBusState, (obj), TYPE_SYS_BUS_EHCI)
@@ -365,4 +366,15 @@ typedef struct SysBusEHCIClass {
    uint16_t portnr;
} SysBusEHCIClass;

#define FUSBH200_EHCI(obj) \
    OBJECT_CHECK(FUSBH200EHCIState, (obj), TYPE_FUSBH200_EHCI)

typedef struct FUSBH200EHCIState {
    /*< private >*/
    EHCISysBusState parent_obj;
    /*< public >*/

    MemoryRegion mem_vendor;
} FUSBH200EHCIState;

#endif