diff options
author | Guenter Roeck <linux@roeck-us.net> | 2024-01-15 10:27:55 -0800 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2024-01-26 11:30:47 +0000 |
commit | 43eef24f52def75df9d491788db90e11098b1f7b (patch) | |
tree | 8ff6337aaddb9147c274e9665033ff4340c1eb60 /hw/arm/allwinner-r40.c | |
parent | b8e2d3f86c79f164683b80f16ca55f093a816ab3 (diff) |
hw/arm: Add EHCI/OHCI controllers to Allwinner R40 and Bananapi board
Allwinner R40 supports two USB host ports shared between a USB 2.0 EHCI
host controller and a USB 1.1 OHCI host controller. Add support for both
of them.
If machine USB support is not enabled, create unimplemented devices
for the USB memory ranges to avoid crashes when booting Linux.
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-id: 20240115182757.1095012-2-linux@roeck-us.net
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/arm/allwinner-r40.c')
-rw-r--r-- | hw/arm/allwinner-r40.c | 47 |
1 files changed, 45 insertions, 2 deletions
diff --git a/hw/arm/allwinner-r40.c b/hw/arm/allwinner-r40.c index a0d367c60d..2e8943eff7 100644 --- a/hw/arm/allwinner-r40.c +++ b/hw/arm/allwinner-r40.c @@ -23,6 +23,7 @@ #include "qemu/bswap.h" #include "qemu/module.h" #include "qemu/units.h" +#include "hw/boards.h" #include "hw/qdev-core.h" #include "hw/sysbus.h" #include "hw/char/serial.h" @@ -45,6 +46,10 @@ const hwaddr allwinner_r40_memmap[] = { [AW_R40_DEV_MMC1] = 0x01c10000, [AW_R40_DEV_MMC2] = 0x01c11000, [AW_R40_DEV_MMC3] = 0x01c12000, + [AW_R40_DEV_EHCI1] = 0x01c19000, + [AW_R40_DEV_OHCI1] = 0x01c19400, + [AW_R40_DEV_EHCI2] = 0x01c1c000, + [AW_R40_DEV_OHCI2] = 0x01c1c400, [AW_R40_DEV_CCU] = 0x01c20000, [AW_R40_DEV_PIT] = 0x01c20c00, [AW_R40_DEV_UART0] = 0x01c28000, @@ -89,9 +94,9 @@ static struct AwR40Unimplemented r40_unimplemented[] = { { "crypto", 0x01c15000, 4 * KiB }, { "spi2", 0x01c17000, 4 * KiB }, { "sata", 0x01c18000, 4 * KiB }, - { "usb1-host", 0x01c19000, 4 * KiB }, + { "usb1-phy", 0x01c19800, 2 * KiB }, { "sid", 0x01c1b000, 4 * KiB }, - { "usb2-host", 0x01c1c000, 4 * KiB }, + { "usb2-phy", 0x01c1c800, 2 * KiB }, { "cs1", 0x01c1d000, 4 * KiB }, { "spi3", 0x01c1f000, 4 * KiB }, { "rtc", 0x01c20400, 1 * KiB }, @@ -181,6 +186,10 @@ enum { AW_R40_GIC_SPI_MMC2 = 34, AW_R40_GIC_SPI_MMC3 = 35, AW_R40_GIC_SPI_EMAC = 55, + AW_R40_GIC_SPI_OHCI1 = 64, + AW_R40_GIC_SPI_OHCI2 = 65, + AW_R40_GIC_SPI_EHCI1 = 76, + AW_R40_GIC_SPI_EHCI2 = 78, AW_R40_GIC_SPI_GMAC = 85, }; @@ -276,6 +285,13 @@ static void allwinner_r40_init(Object *obj) TYPE_AW_SDHOST_SUN50I_A64); } + for (size_t i = 0; i < AW_R40_NUM_USB; i++) { + object_initialize_child(obj, "ehci[*]", &s->ehci[i], + TYPE_PLATFORM_EHCI); + object_initialize_child(obj, "ohci[*]", &s->ohci[i], + TYPE_SYSBUS_OHCI); + } + object_initialize_child(obj, "twi0", &s->i2c0, TYPE_AW_I2C_SUN6I); object_initialize_child(obj, "emac", &s->emac, TYPE_AW_EMAC); @@ -407,6 +423,33 @@ static void allwinner_r40_realize(DeviceState *dev, Error **errp) sysbus_realize(SYS_BUS_DEVICE(&s->ccu), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccu), 0, s->memmap[AW_R40_DEV_CCU]); + /* USB */ + for (size_t i = 0; i < AW_R40_NUM_USB; i++) { + g_autofree char *bus = g_strdup_printf("usb-bus.%zu", i); + + object_property_set_bool(OBJECT(&s->ehci[i]), "companion-enable", true, + &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->ehci[i]), 0, + allwinner_r40_memmap[i ? AW_R40_DEV_EHCI2 + : AW_R40_DEV_EHCI1]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci[i]), 0, + qdev_get_gpio_in(DEVICE(&s->gic), + i ? AW_R40_GIC_SPI_EHCI2 + : AW_R40_GIC_SPI_EHCI1)); + + object_property_set_str(OBJECT(&s->ohci[i]), "masterbus", bus, + &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(&s->ohci[i]), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->ohci[i]), 0, + allwinner_r40_memmap[i ? AW_R40_DEV_OHCI2 + : AW_R40_DEV_OHCI1]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->ohci[i]), 0, + qdev_get_gpio_in(DEVICE(&s->gic), + i ? AW_R40_GIC_SPI_OHCI2 + : AW_R40_GIC_SPI_OHCI1)); + } + /* SD/MMC */ for (int i = 0; i < AW_R40_NUM_MMCS; i++) { qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->gic), |