From 82e4838249b23c3fe20cee295f9c1b3e6abd68d1 Mon Sep 17 00:00:00 2001 From: Niek Linnenbank Date: Wed, 11 Mar 2020 23:18:44 +0100 Subject: hw/arm/allwinner: add SD/MMC host controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Allwinner System on Chip families sun4i and above contain an integrated storage controller for Secure Digital (SD) and Multi Media Card (MMC) interfaces. This commit adds support for the Allwinner SD/MMC storage controller with the following emulated features: * DMA transfers * Direct FIFO I/O * Short/Long format command responses * Auto-Stop command (CMD12) * Insert & remove card detection The following boards are extended with the SD host controller: * Cubieboard (hw/arm/cubieboard.c) * Orange Pi PC (hw/arm/orangepi.c) Signed-off-by: Niek Linnenbank Reviewed-by: Alex Bennée Tested-by: Philippe Mathieu-Daudé Message-id: 20200311221854.30370-9-nieklinnenbank@gmail.com Signed-off-by: Peter Maydell --- hw/arm/Kconfig | 1 + hw/arm/allwinner-a10.c | 11 +++++++++++ hw/arm/allwinner-h3.c | 15 ++++++++++++++- hw/arm/cubieboard.c | 15 +++++++++++++++ hw/arm/orangepi.c | 16 ++++++++++++++++ 5 files changed, 57 insertions(+), 1 deletion(-) (limited to 'hw/arm') diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index f6422d5..dd22fff 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -306,6 +306,7 @@ config ALLWINNER_H3 select UNIMP select USB_OHCI select USB_EHCI_SYSBUS + select SD config RASPI bool diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c index 2ae9c15..dc62c76 100644 --- a/hw/arm/allwinner-a10.c +++ b/hw/arm/allwinner-a10.c @@ -27,6 +27,7 @@ #include "hw/boards.h" #include "hw/usb/hcd-ohci.h" +#define AW_A10_MMC0_BASE 0x01c0f000 #define AW_A10_PIC_REG_BASE 0x01c20400 #define AW_A10_PIT_REG_BASE 0x01c20c00 #define AW_A10_UART0_REG_BASE 0x01c28000 @@ -64,6 +65,9 @@ static void aw_a10_init(Object *obj) sizeof(s->ohci[i]), TYPE_SYSBUS_OHCI); } } + + sysbus_init_child_obj(obj, "mmc0", &s->mmc0, sizeof(s->mmc0), + TYPE_AW_SDHOST_SUN4I); } static void aw_a10_realize(DeviceState *dev, Error **errp) @@ -164,6 +168,13 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(dev, 64 + i)); } } + + /* SD/MMC */ + qdev_init_nofail(DEVICE(&s->mmc0)); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->mmc0), 0, AW_A10_MMC0_BASE); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->mmc0), 0, qdev_get_gpio_in(dev, 32)); + object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->mmc0), + "sd-bus", &error_abort); } static void aw_a10_class_init(ObjectClass *oc, void *data) diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c index deeea63..8c7ac61 100644 --- a/hw/arm/allwinner-h3.c +++ b/hw/arm/allwinner-h3.c @@ -38,6 +38,7 @@ const hwaddr allwinner_h3_memmap[] = { [AW_H3_SRAM_A2] = 0x00044000, [AW_H3_SRAM_C] = 0x00010000, [AW_H3_SYSCTRL] = 0x01c00000, + [AW_H3_MMC0] = 0x01c0f000, [AW_H3_SID] = 0x01c14000, [AW_H3_EHCI0] = 0x01c1a000, [AW_H3_OHCI0] = 0x01c1a400, @@ -76,7 +77,6 @@ struct AwH3Unimplemented { { "lcd0", 0x01c0c000, 4 * KiB }, { "lcd1", 0x01c0d000, 4 * KiB }, { "ve", 0x01c0e000, 4 * KiB }, - { "mmc0", 0x01c0f000, 4 * KiB }, { "mmc1", 0x01c10000, 4 * KiB }, { "mmc2", 0x01c11000, 4 * KiB }, { "crypto", 0x01c15000, 4 * KiB }, @@ -153,6 +153,7 @@ enum { AW_H3_GIC_SPI_UART3 = 3, AW_H3_GIC_SPI_TIMER0 = 18, AW_H3_GIC_SPI_TIMER1 = 19, + AW_H3_GIC_SPI_MMC0 = 60, AW_H3_GIC_SPI_EHCI0 = 72, AW_H3_GIC_SPI_OHCI0 = 73, AW_H3_GIC_SPI_EHCI1 = 74, @@ -203,6 +204,9 @@ static void allwinner_h3_init(Object *obj) TYPE_AW_SID); object_property_add_alias(obj, "identifier", OBJECT(&s->sid), "identifier", &error_abort); + + sysbus_init_child_obj(obj, "mmc0", &s->mmc0, sizeof(s->mmc0), + TYPE_AW_SDHOST_SUN5I); } static void allwinner_h3_realize(DeviceState *dev, Error **errp) @@ -324,6 +328,15 @@ static void allwinner_h3_realize(DeviceState *dev, Error **errp) qdev_init_nofail(DEVICE(&s->sid)); sysbus_mmio_map(SYS_BUS_DEVICE(&s->sid), 0, s->memmap[AW_H3_SID]); + /* SD/MMC */ + qdev_init_nofail(DEVICE(&s->mmc0)); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->mmc0), 0, s->memmap[AW_H3_MMC0]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->mmc0), 0, + qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_MMC0)); + + object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->mmc0), + "sd-bus", &error_abort); + /* Universal Serial Bus */ sysbus_create_simple(TYPE_AW_H3_EHCI, s->memmap[AW_H3_EHCI0], qdev_get_gpio_in(DEVICE(&s->gic), diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c index d791817..0b8ba44 100644 --- a/hw/arm/cubieboard.c +++ b/hw/arm/cubieboard.c @@ -22,6 +22,7 @@ #include "sysemu/sysemu.h" #include "hw/sysbus.h" #include "hw/boards.h" +#include "hw/qdev-properties.h" #include "hw/arm/allwinner-a10.h" static struct arm_boot_info cubieboard_binfo = { @@ -33,6 +34,10 @@ static void cubieboard_init(MachineState *machine) { AwA10State *a10; Error *err = NULL; + DriveInfo *di; + BlockBackend *blk; + BusState *bus; + DeviceState *carddev; /* BIOS is not supported by this board */ if (bios_name) { @@ -82,6 +87,16 @@ static void cubieboard_init(MachineState *machine) exit(1); } + /* Retrieve SD bus */ + di = drive_get_next(IF_SD); + blk = di ? blk_by_legacy_dinfo(di) : NULL; + bus = qdev_get_child_bus(DEVICE(a10), "sd-bus"); + + /* Plug in SD card */ + carddev = qdev_create(bus, TYPE_SD_CARD); + qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); + object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal); + memory_region_add_subregion(get_system_memory(), AW_A10_SDRAM_BASE, machine->ram); diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c index 4047c4c..e7ac7b1 100644 --- a/hw/arm/orangepi.c +++ b/hw/arm/orangepi.c @@ -35,6 +35,10 @@ static struct arm_boot_info orangepi_binfo = { static void orangepi_init(MachineState *machine) { AwH3State *h3; + DriveInfo *di; + BlockBackend *blk; + BusState *bus; + DeviceState *carddev; /* BIOS is not supported by this board */ if (bios_name) { @@ -76,6 +80,16 @@ static void orangepi_init(MachineState *machine) /* Mark H3 object realized */ object_property_set_bool(OBJECT(h3), true, "realized", &error_abort); + /* Retrieve SD bus */ + di = drive_get_next(IF_SD); + blk = di ? blk_by_legacy_dinfo(di) : NULL; + bus = qdev_get_child_bus(DEVICE(h3), "sd-bus"); + + /* Plug in SD card */ + carddev = qdev_create(bus, TYPE_SD_CARD); + qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); + object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal); + /* SDRAM */ memory_region_add_subregion(get_system_memory(), h3->memmap[AW_H3_SDRAM], machine->ram); @@ -89,6 +103,8 @@ static void orangepi_machine_init(MachineClass *mc) { mc->desc = "Orange Pi PC"; mc->init = orangepi_init; + mc->block_default_type = IF_SD; + mc->units_per_default_bus = 1; mc->min_cpus = AW_H3_NUM_CPUS; mc->max_cpus = AW_H3_NUM_CPUS; mc->default_cpus = AW_H3_NUM_CPUS; -- cgit v1.1