mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
hw/arm/allwinner: add SD/MMC host controller
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 <nieklinnenbank@gmail.com> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com> Message-id: 20200311221854.30370-9-nieklinnenbank@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
committed by
Peter Maydell
parent
6556617ce1
commit
82e4838249
@@ -306,6 +306,7 @@ config ALLWINNER_H3
|
||||
select UNIMP
|
||||
select USB_OHCI
|
||||
select USB_EHCI_SYSBUS
|
||||
select SD
|
||||
|
||||
config RASPI
|
||||
bool
|
||||
|
||||
@@ -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)
|
||||
|
||||
+14
-1
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -4,6 +4,7 @@ common-obj-$(CONFIG_SD) += sd.o core.o sdmmc-internal.o
|
||||
common-obj-$(CONFIG_SDHCI) += sdhci.o
|
||||
common-obj-$(CONFIG_SDHCI_PCI) += sdhci-pci.o
|
||||
|
||||
common-obj-$(CONFIG_ALLWINNER_H3) += allwinner-sdhost.o
|
||||
common-obj-$(CONFIG_MILKYMIST) += milkymist-memcard.o
|
||||
common-obj-$(CONFIG_OMAP) += omap_mmc.o
|
||||
common-obj-$(CONFIG_PXA2XX) += pxa2xx_mmci.o
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,12 @@
|
||||
# See docs/devel/tracing.txt for syntax documentation.
|
||||
|
||||
# allwinner-sdhost.c
|
||||
allwinner_sdhost_set_inserted(bool inserted) "inserted %u"
|
||||
allwinner_sdhost_process_desc(uint64_t desc_addr, uint32_t desc_size, bool is_write, uint32_t max_bytes) "desc_addr 0x%" PRIx64 " desc_size %" PRIu32 " is_write %u max_bytes %" PRIu32
|
||||
allwinner_sdhost_read(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
|
||||
allwinner_sdhost_write(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
|
||||
allwinner_sdhost_update_irq(uint32_t irq) "IRQ bits 0x%" PRIx32
|
||||
|
||||
# bcm2835_sdhost.c
|
||||
bcm2835_sdhost_read(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
|
||||
bcm2835_sdhost_write(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "hw/timer/allwinner-a10-pit.h"
|
||||
#include "hw/intc/allwinner-a10-pic.h"
|
||||
#include "hw/net/allwinner_emac.h"
|
||||
#include "hw/sd/allwinner-sdhost.h"
|
||||
#include "hw/ide/ahci.h"
|
||||
#include "hw/usb/hcd-ohci.h"
|
||||
#include "hw/usb/hcd-ehci.h"
|
||||
@@ -31,6 +32,7 @@ typedef struct AwA10State {
|
||||
AwA10PICState intc;
|
||||
AwEmacState emac;
|
||||
AllwinnerAHCIState sata;
|
||||
AwSdHostState mmc0;
|
||||
MemoryRegion sram_a;
|
||||
EHCISysBusState ehci[AW_A10_NUM_USB];
|
||||
OHCISysBusState ohci[AW_A10_NUM_USB];
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "hw/misc/allwinner-cpucfg.h"
|
||||
#include "hw/misc/allwinner-h3-sysctrl.h"
|
||||
#include "hw/misc/allwinner-sid.h"
|
||||
#include "hw/sd/allwinner-sdhost.h"
|
||||
#include "target/arm/cpu.h"
|
||||
|
||||
/**
|
||||
@@ -60,6 +61,7 @@ enum {
|
||||
AW_H3_SRAM_A2,
|
||||
AW_H3_SRAM_C,
|
||||
AW_H3_SYSCTRL,
|
||||
AW_H3_MMC0,
|
||||
AW_H3_SID,
|
||||
AW_H3_EHCI0,
|
||||
AW_H3_OHCI0,
|
||||
@@ -117,6 +119,7 @@ typedef struct AwH3State {
|
||||
AwCpuCfgState cpucfg;
|
||||
AwH3SysCtrlState sysctrl;
|
||||
AwSidState sid;
|
||||
AwSdHostState mmc0;
|
||||
GICState gic;
|
||||
MemoryRegion sram_a1;
|
||||
MemoryRegion sram_a2;
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Allwinner (sun4i and above) SD Host Controller emulation
|
||||
*
|
||||
* Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef HW_SD_ALLWINNER_SDHOST_H
|
||||
#define HW_SD_ALLWINNER_SDHOST_H
|
||||
|
||||
#include "qom/object.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/sd/sd.h"
|
||||
|
||||
/**
|
||||
* Object model types
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Generic Allwinner SD Host Controller (abstract) */
|
||||
#define TYPE_AW_SDHOST "allwinner-sdhost"
|
||||
|
||||
/** Allwinner sun4i family (A10, A12) */
|
||||
#define TYPE_AW_SDHOST_SUN4I TYPE_AW_SDHOST "-sun4i"
|
||||
|
||||
/** Allwinner sun5i family and newer (A13, H2+, H3, etc) */
|
||||
#define TYPE_AW_SDHOST_SUN5I TYPE_AW_SDHOST "-sun5i"
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* Object model macros
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define AW_SDHOST(obj) \
|
||||
OBJECT_CHECK(AwSdHostState, (obj), TYPE_AW_SDHOST)
|
||||
#define AW_SDHOST_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(AwSdHostClass, (klass), TYPE_AW_SDHOST)
|
||||
#define AW_SDHOST_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(AwSdHostClass, (obj), TYPE_AW_SDHOST)
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* Allwinner SD Host Controller object instance state.
|
||||
*/
|
||||
typedef struct AwSdHostState {
|
||||
/*< private >*/
|
||||
SysBusDevice busdev;
|
||||
/*< public >*/
|
||||
|
||||
/** Secure Digital (SD) bus, which connects to SD card (if present) */
|
||||
SDBus sdbus;
|
||||
|
||||
/** Maps I/O registers in physical memory */
|
||||
MemoryRegion iomem;
|
||||
|
||||
/** Interrupt output signal to notify CPU */
|
||||
qemu_irq irq;
|
||||
|
||||
/** Number of bytes left in current DMA transfer */
|
||||
uint32_t transfer_cnt;
|
||||
|
||||
/**
|
||||
* @name Hardware Registers
|
||||
* @{
|
||||
*/
|
||||
|
||||
uint32_t global_ctl; /**< Global Control */
|
||||
uint32_t clock_ctl; /**< Clock Control */
|
||||
uint32_t timeout; /**< Timeout */
|
||||
uint32_t bus_width; /**< Bus Width */
|
||||
uint32_t block_size; /**< Block Size */
|
||||
uint32_t byte_count; /**< Byte Count */
|
||||
|
||||
uint32_t command; /**< Command */
|
||||
uint32_t command_arg; /**< Command Argument */
|
||||
uint32_t response[4]; /**< Command Response */
|
||||
|
||||
uint32_t irq_mask; /**< Interrupt Mask */
|
||||
uint32_t irq_status; /**< Raw Interrupt Status */
|
||||
uint32_t status; /**< Status */
|
||||
|
||||
uint32_t fifo_wlevel; /**< FIFO Water Level */
|
||||
uint32_t fifo_func_sel; /**< FIFO Function Select */
|
||||
uint32_t debug_enable; /**< Debug Enable */
|
||||
uint32_t auto12_arg; /**< Auto Command 12 Argument */
|
||||
uint32_t newtiming_set; /**< SD New Timing Set */
|
||||
uint32_t newtiming_debug; /**< SD New Timing Debug */
|
||||
uint32_t hardware_rst; /**< Hardware Reset */
|
||||
uint32_t dmac; /**< Internal DMA Controller Control */
|
||||
uint32_t desc_base; /**< Descriptor List Base Address */
|
||||
uint32_t dmac_status; /**< Internal DMA Controller Status */
|
||||
uint32_t dmac_irq; /**< Internal DMA Controller IRQ Enable */
|
||||
uint32_t card_threshold; /**< Card Threshold Control */
|
||||
uint32_t startbit_detect; /**< eMMC DDR Start Bit Detection Control */
|
||||
uint32_t response_crc; /**< Response CRC */
|
||||
uint32_t data_crc[8]; /**< Data CRC */
|
||||
uint32_t status_crc; /**< Status CRC */
|
||||
|
||||
/** @} */
|
||||
|
||||
} AwSdHostState;
|
||||
|
||||
/**
|
||||
* Allwinner SD Host Controller class-level struct.
|
||||
*
|
||||
* This struct is filled by each sunxi device specific code
|
||||
* such that the generic code can use this struct to support
|
||||
* all devices.
|
||||
*/
|
||||
typedef struct AwSdHostClass {
|
||||
/*< private >*/
|
||||
SysBusDeviceClass parent_class;
|
||||
/*< public >*/
|
||||
|
||||
/** Maximum buffer size in bytes per DMA descriptor */
|
||||
size_t max_desc_size;
|
||||
|
||||
} AwSdHostClass;
|
||||
|
||||
#endif /* HW_SD_ALLWINNER_SDHOST_H */
|
||||
Reference in New Issue
Block a user