From: Jamin Lin <[email protected]> Create the USB Device Controller (UDC) at 0x1e6a2000 on the AST2600 SoC and map its registers.
The UDC and the second EHCI host controller (EHCI2) share one SoC interrupt line. Route both through an OR gate whose output drives that GIC input, so either device can raise the interrupt without the other clobbering the line. The gadget USB device is not created by the SoC. It is a separate, user-creatable "aspeed.udc-gadget" USB device that the user plugs onto a USB host controller's bus; it finds its controller through the "udc" link property, e.g. -device aspeed.udc-gadget,udc=/machine/soc/udc Signed-off-by: Jamin Lin <[email protected]> Reviewed-by: Philippe Mathieu-Daudé <[email protected]> Reviewed-by: Cédric Le Goater <[email protected]> Link: https://lore.kernel.org/qemu-devel/[email protected] Signed-off-by: Cédric Le Goater <[email protected]> --- include/hw/arm/aspeed_soc.h | 4 ++++ hw/arm/aspeed_ast2600.c | 37 ++++++++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index cba8b7cdca58..38226d9b8049 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -37,6 +37,8 @@ #include "hw/gpio/aspeed_sgpio.h" #include "hw/sd/aspeed_sdhci.h" #include "hw/usb/hcd-ehci.h" +#include "hw/usb/aspeed-udc.h" +#include "hw/core/or-irq.h" #include "qom/object.h" #include "hw/misc/aspeed_lpc.h" #include "hw/misc/unimp.h" @@ -140,6 +142,8 @@ struct Aspeed2600SoCState { A15MPPrivState a7mpcore; ARMCPU cpu[ASPEED_CPUS_NUM]; /* XXX belong to a7mpcore */ + AspeedUDCState udc; + OrIRQState ehci2_udc_orgate; }; #define TYPE_ASPEED2600_SOC "aspeed2600-soc" diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index f7c7ec7fb1d4..1a10d0fe1ecc 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -34,6 +34,7 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = { [ASPEED_DEV_SPI1] = 0x1E630000, [ASPEED_DEV_SPI2] = 0x1E631000, [ASPEED_DEV_EHCI1] = 0x1E6A1000, + [ASPEED_DEV_UDC] = 0x1E6A2000, [ASPEED_DEV_EHCI2] = 0x1E6A3000, [ASPEED_DEV_MII1] = 0x1E650000, [ASPEED_DEV_MII2] = 0x1E650008, @@ -218,6 +219,10 @@ static void aspeed_soc_ast2600_init(Object *obj) TYPE_PLATFORM_EHCI); } + object_initialize_child(obj, "udc", &a->udc, TYPE_ASPEED_UDC); + object_initialize_child(obj, "ehci2-udc-orgate", &a->ehci2_udc_orgate, + TYPE_OR_IRQ); + snprintf(typename, sizeof(typename), "aspeed.sdmc-%s", socname); object_initialize_child(obj, "sdmc", &s->sdmc, typename); object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc), @@ -581,6 +586,16 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) aspeed_soc_ast2600_get_irq(s, ASPEED_DEV_SPI1 + i)); } + /* + * EHCI2 and the UDC share one SoC interrupt line, so OR their outputs + * together and drive that GIC input from the OR gate. + */ + object_property_set_int(OBJECT(&a->ehci2_udc_orgate), "num-lines", 2, + &error_abort); + qdev_realize(DEVICE(&a->ehci2_udc_orgate), NULL, &error_abort); + qdev_connect_gpio_out(DEVICE(&a->ehci2_udc_orgate), 0, + aspeed_soc_ast2600_get_irq(s, ASPEED_DEV_EHCI2)); + /* EHCI */ for (i = 0; i < sc->ehcis_num; i++) { if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), errp)) { @@ -588,10 +603,26 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) } aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->ehci[i]), 0, sc->memmap[ASPEED_DEV_EHCI1 + i]); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci[i]), 0, - aspeed_soc_ast2600_get_irq(s, - ASPEED_DEV_EHCI1 + i)); } + /* + * EHCI1 has its own IRQ; EHCI2 shares the UDC's IRQ, so route it through + * the OR gate. + */ + sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci[0]), 0, + aspeed_soc_ast2600_get_irq(s, ASPEED_DEV_EHCI1)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci[1]), 0, + qdev_get_gpio_in(DEVICE(&a->ehci2_udc_orgate), 0)); + + /* UDC - USB 2.0 Device Controller */ + object_property_set_link(OBJECT(&a->udc), "dram", OBJECT(s->dram_mr), + &error_abort); + if (!sysbus_realize(SYS_BUS_DEVICE(&a->udc), errp)) { + return; + } + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&a->udc), 0, + sc->memmap[ASPEED_DEV_UDC]); + sysbus_connect_irq(SYS_BUS_DEVICE(&a->udc), 0, + qdev_get_gpio_in(DEVICE(&a->ehci2_udc_orgate), 1)); /* SDMC - SDRAM Memory Controller */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), errp)) { -- 2.55.0
