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,