Model the E2000 SD/MMC controller as a subclass of the reusable DesignWare MCI implementation. Supply the E2000 hardware configuration, FIFO depth, data window, clock-ready behavior, and vendor divider register while inheriting the standard command and DMA paths.
Signed-off-by: Bin Meng <[email protected]> --- hw/arm/Kconfig | 1 + hw/sd/meson.build | 1 + hw/sd/phytium_e2000_mci.c | 95 +++++++++++++++++++++++++++++++ include/hw/sd/phytium_e2000_mci.h | 21 +++++++ 4 files changed, 118 insertions(+) create mode 100644 hw/sd/phytium_e2000_mci.c create mode 100644 include/hw/sd/phytium_e2000_mci.h diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index e68f137a66..99a5799b22 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -132,6 +132,7 @@ config PHYTIUM_E2000 depends on TCG && AARCH64 imply PCI_DEVICES select ARM_GIC + select DW_MCI select PCI_EXPRESS select PCI_EXPRESS_GENERIC_BRIDGE select PL011 diff --git a/hw/sd/meson.build b/hw/sd/meson.build index d7b97cdca4..5792d0c923 100644 --- a/hw/sd/meson.build +++ b/hw/sd/meson.build @@ -6,6 +6,7 @@ system_ss.add(when: 'CONFIG_SDHCI_PCI', if_true: files('sdhci-pci.c')) system_ss.add(when: 'CONFIG_SSI_SD', if_true: files('ssi-sd.c')) system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_mmc.c')) +system_ss.add(when: 'CONFIG_PHYTIUM_E2000', if_true: files('phytium_e2000_mci.c')) system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_sdhost.c')) system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_sdhci.c')) system_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-sdhost.c')) diff --git a/hw/sd/phytium_e2000_mci.c b/hw/sd/phytium_e2000_mci.c new file mode 100644 index 0000000000..84cfc213de --- /dev/null +++ b/hw/sd/phytium_e2000_mci.c @@ -0,0 +1,95 @@ +/* + * Phytium E2000 extension to the Synopsys DesignWare MCI + * + * Copyright (c) 2026 Process Mission + * + * Author: + * Bin Meng <[email protected]> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/sd/phytium_e2000_mci.h" + +#include "qemu/bitops.h" +#include "qemu/module.h" + +#define PHYTIUM_E2000_MCI_CCLK_RDY 0x058 +#define PHYTIUM_E2000_MCI_CLK_DIVIDER 0x114 +#define PHYTIUM_E2000_MCI_VERID 0x280a +#define PHYTIUM_E2000_MCI_HCON (BIT(27) | BIT(7)) +#define PHYTIUM_E2000_MCI_DATA_OFFSET 0x200 +#define PHYTIUM_E2000_MCI_FIFO_DEPTH 512 + +struct PhytiumE2000MciState { + DwMciState parent_obj; +}; + +/* + * The vendor driver polls CCLK_RDY after programming its private divider. + * QEMU has no controller clock tree, so completion is immediate while the + * divider remains ordinary storage for firmware readback. + */ +static bool phytium_e2000_mci_read(DwMciState *s, hwaddr offset, + uint64_t *value, unsigned size) +{ + if (size != sizeof(uint32_t)) { + return false; + } + + switch (offset) { + case PHYTIUM_E2000_MCI_CCLK_RDY: + *value = 1; + return true; + case PHYTIUM_E2000_MCI_CLK_DIVIDER: + *value = s->regs[offset / sizeof(uint32_t)]; + return true; + default: + return false; + } +} + +static bool phytium_e2000_mci_write(DwMciState *s, hwaddr offset, + uint64_t value, unsigned size) +{ + if (size != sizeof(uint32_t)) { + return false; + } + + switch (offset) { + case PHYTIUM_E2000_MCI_CCLK_RDY: + return true; + case PHYTIUM_E2000_MCI_CLK_DIVIDER: + s->regs[offset / sizeof(uint32_t)] = value; + return true; + default: + return false; + } +} + +static void phytium_e2000_mci_class_init(ObjectClass *klass, const void *data) +{ + DwMciClass *dmc = DW_MCI_CLASS(klass); + + dmc->verid = PHYTIUM_E2000_MCI_VERID; + dmc->hcon = PHYTIUM_E2000_MCI_HCON; + dmc->data_offset = PHYTIUM_E2000_MCI_DATA_OFFSET; + dmc->fifo_depth = PHYTIUM_E2000_MCI_FIFO_DEPTH; + dmc->vendor_read = phytium_e2000_mci_read; + dmc->vendor_write = phytium_e2000_mci_write; +} + +static const TypeInfo phytium_e2000_mci_info = { + .name = TYPE_PHYTIUM_E2000_MCI, + .parent = TYPE_DW_MCI, + .instance_size = sizeof(PhytiumE2000MciState), + .class_init = phytium_e2000_mci_class_init, +}; + +static void phytium_e2000_mci_register_types(void) +{ + type_register_static(&phytium_e2000_mci_info); +} + +type_init(phytium_e2000_mci_register_types) diff --git a/include/hw/sd/phytium_e2000_mci.h b/include/hw/sd/phytium_e2000_mci.h new file mode 100644 index 0000000000..cc6fce06d0 --- /dev/null +++ b/include/hw/sd/phytium_e2000_mci.h @@ -0,0 +1,21 @@ +/* + * Phytium E2000 SD/MMC controller + * + * Copyright (c) 2026 Process Mission + * + * Author: + * Bin Meng <[email protected]> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_SD_PHYTIUM_E2000_MCI_H +#define HW_SD_PHYTIUM_E2000_MCI_H + +#include "hw/sd/dw_mci.h" +#include "qom/object.h" + +#define TYPE_PHYTIUM_E2000_MCI "phytium-e2000-mci" +OBJECT_DECLARE_SIMPLE_TYPE(PhytiumE2000MciState, PHYTIUM_E2000_MCI) + +#endif -- 2.53.0
