@samitouri / QOSamiQemu / commits / 08e8608819

hw/arm/fsl-imx8mm: Adding support for USDHC storage controllers

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. Reviewed-by: Philippe Mathieu-Daude <philmd@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Gaurav Sharma committed Apr 21, 2026 at 12:22 UTC 08e8608819e22533b18a69ac678fecc2e65fb369
4 files changed +50
hw/arm/Kconfig
+1
@@ -623,6 +623,7 @@ config FSL_IMX8MM
623 select FSL_IMX8MP_ANALOG
624 select FSL_IMX8MP_CCM
625 select IMX
626 + select SDHCI
627
628 config FSL_IMX8MM_EVK
629 bool
hw/arm/fsl-imx8mm.c
+25
@@ -180,6 +180,10 @@ static void fsl_imx8mm_init(Object *obj)
180 object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL);
181 }
182
183 + for (i = 0; i < FSL_IMX8MM_NUM_USDHCS; i++) {
184 + g_autofree char *name = g_strdup_printf("usdhc%d", i + 1);
185 + object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC);
186 + }
187 }
188
189 static void fsl_imx8mm_realize(DeviceState *dev, Error **errp)
@@ -357,6 +361,26 @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp)
361 fsl_imx8mm_memmap[FSL_IMX8MM_OCRAM].addr,
362 &s->ocram);
363
364 + /* USDHCs */
365 + for (i = 0; i < FSL_IMX8MM_NUM_USDHCS; i++) {
366 + static const struct {
367 + hwaddr addr;
368 + unsigned int irq;
369 + } usdhc_table[FSL_IMX8MM_NUM_USDHCS] = {
370 + { fsl_imx8mm_memmap[FSL_IMX8MM_USDHC1].addr, FSL_IMX8MM_USDHC1_IRQ },
371 + { fsl_imx8mm_memmap[FSL_IMX8MM_USDHC2].addr, FSL_IMX8MM_USDHC2_IRQ },
372 + { fsl_imx8mm_memmap[FSL_IMX8MM_USDHC3].addr, FSL_IMX8MM_USDHC3_IRQ },
373 + };
374 +
375 + if (!sysbus_realize(SYS_BUS_DEVICE(&s->usdhc[i]), errp)) {
376 + return;
377 + }
378 +
379 + sysbus_mmio_map(SYS_BUS_DEVICE(&s->usdhc[i]), 0, usdhc_table[i].addr);
380 + sysbus_connect_irq(SYS_BUS_DEVICE(&s->usdhc[i]), 0,
381 + qdev_get_gpio_in(gicdev, usdhc_table[i].irq));
382 + }
383 +
384 /* SNVS */
385 if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) {
386 return;
@@ -375,6 +399,7 @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp)
399 case FSL_IMX8MM_OCRAM:
400 case FSL_IMX8MM_SNVS_HP:
401 case FSL_IMX8MM_UART1 ... FSL_IMX8MM_UART4:
402 + case FSL_IMX8MM_USDHC1 ... FSL_IMX8MM_USDHC3:
403 /* device implemented and treated above */
404 break;
405
hw/arm/imx8mm-evk.c
+17
@@ -84,6 +84,23 @@ static void imx8mm_evk_init(MachineState *machine)
84 memory_region_add_subregion(get_system_memory(), FSL_IMX8MM_RAM_START,
85 machine->ram);
86
87 + for (int i = 0; i < FSL_IMX8MM_NUM_USDHCS; i++) {
88 + BusState *bus;
89 + DeviceState *carddev;
90 + BlockBackend *blk;
91 + DriveInfo *di = drive_get(IF_SD, i, 0);
92 +
93 + if (!di) {
94 + continue;
95 + }
96 +
97 + blk = blk_by_legacy_dinfo(di);
98 + bus = qdev_get_child_bus(DEVICE(&s->usdhc[i]), "sd-bus");
99 + carddev = qdev_new(TYPE_SD_CARD);
100 + qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal);
101 + qdev_realize_and_unref(carddev, bus, &error_fatal);
102 + }
103 +
104 if (!qtest_enabled()) {
105 arm_load_kernel(&s->cpu[0], machine, &boot_info);
106 }
include/hw/arm/fsl-imx8mm.h
+7
@@ -16,6 +16,7 @@
16 #include "hw/misc/imx7_snvs.h"
17 #include "hw/misc/imx8mp_analog.h"
18 #include "hw/misc/imx8mp_ccm.h"
19 +#include "hw/sd/sdhci.h"
20 #include "qom/object.h"
21 #include "qemu/units.h"
22
@@ -29,6 +30,7 @@ enum FslImx8mmConfiguration {
30 FSL_IMX8MM_NUM_CPUS = 4,
31 FSL_IMX8MM_NUM_IRQS = 128,
32 FSL_IMX8MM_NUM_UARTS = 4,
33 + FSL_IMX8MM_NUM_USDHCS = 3,
34 };
35
36 struct FslImx8mmState {
@@ -41,6 +43,7 @@ struct FslImx8mmState {
43 IMX7SNVSState snvs;
44 IMXSerialState uart[FSL_IMX8MM_NUM_UARTS];
45 MemoryRegion ocram;
46 + SDHCIState usdhc[FSL_IMX8MM_NUM_USDHCS];
47 };
48
49 enum FslImx8mmMemoryRegions {
@@ -155,6 +158,10 @@ enum FslImx8mmMemoryRegions {
158 };
159
160 enum FslImx8mmIrqs {
161 + FSL_IMX8MM_USDHC1_IRQ = 22,
162 + FSL_IMX8MM_USDHC2_IRQ = 23,
163 + FSL_IMX8MM_USDHC3_IRQ = 24,
164 +
165 FSL_IMX8MM_UART1_IRQ = 26,
166 FSL_IMX8MM_UART2_IRQ = 27,
167 FSL_IMX8MM_UART3_IRQ = 28,