It enables emulation of SD/MMC cards through a virtual SDHCI interface
The emulated SDHCI controller allows guest OS to use emulated storage as
a standard block device.
This will allow running the images such as those generated
by Buildroot.
Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com>
---
docs/system/arm/imx8mm-evk.rst | 1 +
hw/arm/Kconfig | 1 +
hw/arm/fsl-imx8mm.c | 25 +++++++++++++++++++++++++
hw/arm/imx8mm-evk.c | 17 +++++++++++++++++
include/hw/arm/fsl-imx8mm.h | 7 +++++++
5 files changed, 51 insertions(+)
diff --git a/docs/system/arm/imx8mm-evk.rst b/docs/system/arm/imx8mm-evk.rst
index e50e72bdcf..b6dd9e758c 100644
--- a/docs/system/arm/imx8mm-evk.rst
+++ b/docs/system/arm/imx8mm-evk.rst
@@ -12,6 +12,7 @@ The ``imx8mm-evk`` machine implements the following devices:
* Up to 4 Cortex-A53 cores
* Generic Interrupt Controller (GICv3)
* 4 UARTs
+ * 3 USDHC Storage Controllers
* Secure Non-Volatile Storage (SNVS) including an RTC
* Clock Tree
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 314ffcd315..b5eb6553f5 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -632,6 +632,7 @@ config FSL_IMX8MM
select FSL_IMX8MM_ANALOG
select FSL_IMX8MM_CCM
select IMX
+ select SDHCI
config FSL_IMX8MM_EVK
bool
diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c
index 7d9707c131..ba574fc211 100644
--- a/hw/arm/fsl-imx8mm.c
+++ b/hw/arm/fsl-imx8mm.c
@@ -177,6 +177,10 @@ static void fsl_imx8mm_init(Object *obj)
object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL);
}
+ for (i = 0; i < FSL_IMX8MM_NUM_USDHCS; i++) {
+ g_autofree char *name = g_strdup_printf("usdhc%d", i + 1);
+ object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC);
+ }
}
static void fsl_imx8mm_realize(DeviceState *dev, Error **errp)
@@ -342,6 +346,26 @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(gicdev, serial_table[i].irq));
}
+ /* USDHCs */
+ for (i = 0; i < FSL_IMX8MM_NUM_USDHCS; i++) {
+ struct {
+ hwaddr addr;
+ unsigned int irq;
+ } usdhc_table[FSL_IMX8MM_NUM_USDHCS] = {
+ { fsl_imx8mm_memmap[FSL_IMX8MM_USDHC1].addr, FSL_IMX8MM_USDHC1_IRQ },
+ { fsl_imx8mm_memmap[FSL_IMX8MM_USDHC2].addr, FSL_IMX8MM_USDHC2_IRQ },
+ { fsl_imx8mm_memmap[FSL_IMX8MM_USDHC3].addr, FSL_IMX8MM_USDHC3_IRQ },
+ };
+
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->usdhc[i]), errp)) {
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->usdhc[i]), 0, usdhc_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->usdhc[i]), 0,
+ qdev_get_gpio_in(gicdev, usdhc_table[i].irq));
+ }
+
/* SNVS */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) {
return;
@@ -359,6 +383,7 @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp)
case FSL_IMX8MM_RAM:
case FSL_IMX8MM_SNVS_HP:
case FSL_IMX8MM_UART1 ... FSL_IMX8MM_UART4:
+ case FSL_IMX8MM_USDHC1 ... FSL_IMX8MM_USDHC3:
/* device implemented and treated above */
break;
diff --git a/hw/arm/imx8mm-evk.c b/hw/arm/imx8mm-evk.c
index cfb42fe464..a4ab910ee4 100644
--- a/hw/arm/imx8mm-evk.c
+++ b/hw/arm/imx8mm-evk.c
@@ -81,6 +81,23 @@ static void imx8mm_evk_init(MachineState *machine)
memory_region_add_subregion(get_system_memory(), FSL_IMX8MM_RAM_START,
machine->ram);
+ for (int i = 0; i < FSL_IMX8MM_NUM_USDHCS; i++) {
+ BusState *bus;
+ DeviceState *carddev;
+ BlockBackend *blk;
+ DriveInfo *di = drive_get(IF_SD, i, 0);
+
+ if (!di) {
+ continue;
+ }
+
+ blk = blk_by_legacy_dinfo(di);
+ bus = qdev_get_child_bus(DEVICE(&s->usdhc[i]), "sd-bus");
+ carddev = qdev_new(TYPE_SD_CARD);
+ qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal);
+ qdev_realize_and_unref(carddev, bus, &error_fatal);
+ }
+
if (!qtest_enabled()) {
arm_load_kernel(&s->cpu[0], machine, &boot_info);
}
diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h
index 4fd11798a5..985a0a5571 100644
--- a/include/hw/arm/fsl-imx8mm.h
+++ b/include/hw/arm/fsl-imx8mm.h
@@ -15,6 +15,7 @@
#include "hw/misc/imx7_snvs.h"
#include "hw/misc/imx8mm_analog.h"
#include "hw/misc/imx8mm_ccm.h"
+#include "hw/sd/sdhci.h"
#include "qom/object.h"
#include "qemu/units.h"
@@ -28,6 +29,7 @@ enum FslImx8mmConfiguration {
FSL_IMX8MM_NUM_CPUS = 4,
FSL_IMX8MM_NUM_IRQS = 128,
FSL_IMX8MM_NUM_UARTS = 4,
+ FSL_IMX8MM_NUM_USDHCS = 3,
};
struct FslImx8mmState {
@@ -39,6 +41,7 @@ struct FslImx8mmState {
IMX8MMAnalogState analog;
IMX7SNVSState snvs;
IMXSerialState uart[FSL_IMX8MM_NUM_UARTS];
+ SDHCIState usdhc[FSL_IMX8MM_NUM_USDHCS];
};
enum FslImx8mmMemoryRegions {
@@ -153,6 +156,10 @@ enum FslImx8mmMemoryRegions {
};
enum FslImx8mmIrqs {
+ FSL_IMX8MM_USDHC1_IRQ = 22,
+ FSL_IMX8MM_USDHC2_IRQ = 23,
+ FSL_IMX8MM_USDHC3_IRQ = 24,
+
FSL_IMX8MM_UART1_IRQ = 26,
FSL_IMX8MM_UART2_IRQ = 27,
FSL_IMX8MM_UART3_IRQ = 28,
--
2.34.1
On 10/11/25 12:22, Gaurav Sharma wrote:
> It enables emulation of SD/MMC cards through a virtual SDHCI interface
> The emulated SDHCI controller allows guest OS to use emulated storage as
> a standard block device.
> This will allow running the images such as those generated
> by Buildroot.
>
> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com>
> ---
> docs/system/arm/imx8mm-evk.rst | 1 +
> hw/arm/Kconfig | 1 +
> hw/arm/fsl-imx8mm.c | 25 +++++++++++++++++++++++++
> hw/arm/imx8mm-evk.c | 17 +++++++++++++++++
> include/hw/arm/fsl-imx8mm.h | 7 +++++++
> 5 files changed, 51 insertions(+)
> @@ -342,6 +346,26 @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp)
> qdev_get_gpio_in(gicdev, serial_table[i].irq));
> }
>
> + /* USDHCs */
> + for (i = 0; i < FSL_IMX8MM_NUM_USDHCS; i++) {
static const?
> + struct {
> + hwaddr addr;
> + unsigned int irq;
> + } usdhc_table[FSL_IMX8MM_NUM_USDHCS] = {
> + { fsl_imx8mm_memmap[FSL_IMX8MM_USDHC1].addr, FSL_IMX8MM_USDHC1_IRQ },
> + { fsl_imx8mm_memmap[FSL_IMX8MM_USDHC2].addr, FSL_IMX8MM_USDHC2_IRQ },
> + { fsl_imx8mm_memmap[FSL_IMX8MM_USDHC3].addr, FSL_IMX8MM_USDHC3_IRQ },
> + };
> +
> + if (!sysbus_realize(SYS_BUS_DEVICE(&s->usdhc[i]), errp)) {
> + return;
> + }
> +
> + sysbus_mmio_map(SYS_BUS_DEVICE(&s->usdhc[i]), 0, usdhc_table[i].addr);
> + sysbus_connect_irq(SYS_BUS_DEVICE(&s->usdhc[i]), 0,
> + qdev_get_gpio_in(gicdev, usdhc_table[i].irq));
> + }
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Thanks Philippe for reviewing and catching this. Yes, it should be a 'static const' since we do not expect this struct to be modified. My bad. This pattern needs to be fixed in multiple patches. I will wait for additional review comments on the patch series before rolling out a v2. v2 will also have changes to remove iMX8MM CSI and DSI dtb nodes since they are unimplemented.
-----Original Message-----
From: Philippe Mathieu-Daudé <philmd@linaro.org>
Sent: 10 November 2025 20:35
To: Gaurav Sharma <gaurav.sharma_7@nxp.com>; qemu-devel@nongnu.org
Cc: pbonzini@redhat.com; peter.maydell@linaro.org
Subject: [EXT] Re: [PATCH 04/13] hw/arm/fsl-imx8mm: Adding support for USDHC storage controllers
[You don't often get email from philmd@linaro.org. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
Caution: This is an external email. Please take care when clicking links or opening attachments. When in doubt, report the message using the 'Report this email' button
On 10/11/25 12:22, Gaurav Sharma wrote:
> It enables emulation of SD/MMC cards through a virtual SDHCI interface
> The emulated SDHCI controller allows guest OS to use emulated storage
> as a standard block device.
> This will allow running the images such as those generated by
> Buildroot.
>
> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com>
> ---
> docs/system/arm/imx8mm-evk.rst | 1 +
> hw/arm/Kconfig | 1 +
> hw/arm/fsl-imx8mm.c | 25 +++++++++++++++++++++++++
> hw/arm/imx8mm-evk.c | 17 +++++++++++++++++
> include/hw/arm/fsl-imx8mm.h | 7 +++++++
> 5 files changed, 51 insertions(+)
> @@ -342,6 +346,26 @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp)
> qdev_get_gpio_in(gicdev, serial_table[i].irq));
> }
>
> + /* USDHCs */
> + for (i = 0; i < FSL_IMX8MM_NUM_USDHCS; i++) {
static const?
> + struct {
> + hwaddr addr;
> + unsigned int irq;
> + } usdhc_table[FSL_IMX8MM_NUM_USDHCS] = {
> + { fsl_imx8mm_memmap[FSL_IMX8MM_USDHC1].addr, FSL_IMX8MM_USDHC1_IRQ },
> + { fsl_imx8mm_memmap[FSL_IMX8MM_USDHC2].addr, FSL_IMX8MM_USDHC2_IRQ },
> + { fsl_imx8mm_memmap[FSL_IMX8MM_USDHC3].addr, FSL_IMX8MM_USDHC3_IRQ },
> + };
> +
> + if (!sysbus_realize(SYS_BUS_DEVICE(&s->usdhc[i]), errp)) {
> + return;
> + }
> +
> + sysbus_mmio_map(SYS_BUS_DEVICE(&s->usdhc[i]), 0, usdhc_table[i].addr);
> + sysbus_connect_irq(SYS_BUS_DEVICE(&s->usdhc[i]), 0,
> + qdev_get_gpio_in(gicdev, usdhc_table[i].irq));
> + }
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
© 2016 - 2025 Red Hat, Inc.