hw/arm/fsl-imx8mp: Add USDHC storage controllers

The USDHC emulation allows for running real-world images such as those generated
by Buildroot. Convert the board documentation accordingly instead of running a
Linux kernel with ephemeral storage.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
Message-id: 20250223114708.1780-8-shentey@gmail.com
[PMM: drop 'static const' from usdhc_table[] for GCC 7.5]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Bernhard Beschow 2025-02-23 12:46:57 +01:00 committed by Peter Maydell
parent 487967bed6
commit a81193c3e9
5 changed files with 66 additions and 6 deletions

View File

@ -12,6 +12,7 @@ The ``imx8mp-evk`` machine implements the following devices:
* Up to 4 Cortex-A53 cores * Up to 4 Cortex-A53 cores
* Generic Interrupt Controller (GICv3) * Generic Interrupt Controller (GICv3)
* 4 UARTs * 4 UARTs
* 3 USDHC Storage Controllers
* Secure Non-Volatile Storage (SNVS) including an RTC * Secure Non-Volatile Storage (SNVS) including an RTC
* Clock Tree * Clock Tree
@ -26,18 +27,23 @@ Direct Linux Kernel Boot
Probably the easiest way to get started with a whole Linux system on the machine Probably the easiest way to get started with a whole Linux system on the machine
is to generate an image with Buildroot. Version 2024.11.1 is tested at the time is to generate an image with Buildroot. Version 2024.11.1 is tested at the time
of writing and involves two steps. First run the following commands in the of writing and involves three steps. First run the following commands in the
toplevel directory of the Buildroot source tree: toplevel directory of the Buildroot source tree:
.. code-block:: bash .. code-block:: bash
$ echo "BR2_TARGET_ROOTFS_CPIO=y" >> configs/freescale_imx8mpevk_defconfig
$ make freescale_imx8mpevk_defconfig $ make freescale_imx8mpevk_defconfig
$ make $ make
Once finished successfully there is an ``output/image`` subfolder. Navigate into Once finished successfully there is an ``output/image`` subfolder. Navigate into
it and patch the device tree with the following commands which will remove the it and resize the SD card image to a power of two:
``cpu-idle-states`` properties from CPU nodes:
.. code-block:: bash
$ qemu-img resize sdcard.img 256M
Finally, the device tree needs to be patched with the following commands which
will remove the ``cpu-idle-states`` properties from CPU nodes:
.. code-block:: bash .. code-block:: bash
@ -52,5 +58,5 @@ Now that everything is prepared the machine can be started as follows:
-display none -serial null -serial stdio \ -display none -serial null -serial stdio \
-kernel Image \ -kernel Image \
-dtb imx8mp-evk-patched.dtb \ -dtb imx8mp-evk-patched.dtb \
-initrd rootfs.cpio \ -append "root=/dev/mmcblk2p2" \
-append "root=/dev/ram" -drive file=sdcard.img,if=sd,bus=2,format=raw,id=mmcblk2

View File

@ -599,6 +599,7 @@ config FSL_IMX8MP
select FSL_IMX8MP_ANALOG select FSL_IMX8MP_ANALOG
select FSL_IMX8MP_CCM select FSL_IMX8MP_CCM
select IMX select IMX
select SDHCI
select UNIMP select UNIMP
config FSL_IMX8MP_EVK config FSL_IMX8MP_EVK

View File

@ -207,6 +207,11 @@ static void fsl_imx8mp_init(Object *obj)
g_autofree char *name = g_strdup_printf("uart%d", i + 1); g_autofree char *name = g_strdup_printf("uart%d", i + 1);
object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL); object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL);
} }
for (i = 0; i < FSL_IMX8MP_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_imx8mp_realize(DeviceState *dev, Error **errp) static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
@ -346,6 +351,28 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(gicdev, serial_table[i].irq)); qdev_get_gpio_in(gicdev, serial_table[i].irq));
} }
/* USDHCs */
for (i = 0; i < FSL_IMX8MP_NUM_USDHCS; i++) {
struct {
hwaddr addr;
unsigned int irq;
} usdhc_table[FSL_IMX8MP_NUM_USDHCS] = {
{ fsl_imx8mp_memmap[FSL_IMX8MP_USDHC1].addr, FSL_IMX8MP_USDHC1_IRQ },
{ fsl_imx8mp_memmap[FSL_IMX8MP_USDHC2].addr, FSL_IMX8MP_USDHC2_IRQ },
{ fsl_imx8mp_memmap[FSL_IMX8MP_USDHC3].addr, FSL_IMX8MP_USDHC3_IRQ },
};
object_property_set_uint(OBJECT(&s->usdhc[i]), "vendor",
SDHCI_VENDOR_IMX, &error_abort);
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 */ /* SNVS */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) { if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) {
return; return;
@ -363,6 +390,7 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
case FSL_IMX8MP_RAM: case FSL_IMX8MP_RAM:
case FSL_IMX8MP_SNVS_HP: case FSL_IMX8MP_SNVS_HP:
case FSL_IMX8MP_UART1 ... FSL_IMX8MP_UART4: case FSL_IMX8MP_UART1 ... FSL_IMX8MP_UART4:
case FSL_IMX8MP_USDHC1 ... FSL_IMX8MP_USDHC3:
/* device implemented and treated above */ /* device implemented and treated above */
break; break;

View File

@ -11,6 +11,7 @@
#include "hw/arm/boot.h" #include "hw/arm/boot.h"
#include "hw/arm/fsl-imx8mp.h" #include "hw/arm/fsl-imx8mp.h"
#include "hw/boards.h" #include "hw/boards.h"
#include "hw/qdev-properties.h"
#include "system/qtest.h" #include "system/qtest.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qapi/error.h" #include "qapi/error.h"
@ -40,6 +41,23 @@ static void imx8mp_evk_init(MachineState *machine)
memory_region_add_subregion(get_system_memory(), FSL_IMX8MP_RAM_START, memory_region_add_subregion(get_system_memory(), FSL_IMX8MP_RAM_START,
machine->ram); machine->ram);
for (int i = 0; i < FSL_IMX8MP_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()) { if (!qtest_enabled()) {
arm_load_kernel(&s->cpu[0], machine, &boot_info); arm_load_kernel(&s->cpu[0], machine, &boot_info);
} }

View File

@ -15,6 +15,7 @@
#include "hw/misc/imx7_snvs.h" #include "hw/misc/imx7_snvs.h"
#include "hw/misc/imx8mp_analog.h" #include "hw/misc/imx8mp_analog.h"
#include "hw/misc/imx8mp_ccm.h" #include "hw/misc/imx8mp_ccm.h"
#include "hw/sd/sdhci.h"
#include "qom/object.h" #include "qom/object.h"
#include "qemu/units.h" #include "qemu/units.h"
@ -28,6 +29,7 @@ enum FslImx8mpConfiguration {
FSL_IMX8MP_NUM_CPUS = 4, FSL_IMX8MP_NUM_CPUS = 4,
FSL_IMX8MP_NUM_IRQS = 160, FSL_IMX8MP_NUM_IRQS = 160,
FSL_IMX8MP_NUM_UARTS = 4, FSL_IMX8MP_NUM_UARTS = 4,
FSL_IMX8MP_NUM_USDHCS = 3,
}; };
struct FslImx8mpState { struct FslImx8mpState {
@ -39,6 +41,7 @@ struct FslImx8mpState {
IMX8MPAnalogState analog; IMX8MPAnalogState analog;
IMX7SNVSState snvs; IMX7SNVSState snvs;
IMXSerialState uart[FSL_IMX8MP_NUM_UARTS]; IMXSerialState uart[FSL_IMX8MP_NUM_UARTS];
SDHCIState usdhc[FSL_IMX8MP_NUM_USDHCS];
}; };
enum FslImx8mpMemoryRegions { enum FslImx8mpMemoryRegions {
@ -184,6 +187,10 @@ enum FslImx8mpMemoryRegions {
}; };
enum FslImx8mpIrqs { enum FslImx8mpIrqs {
FSL_IMX8MP_USDHC1_IRQ = 22,
FSL_IMX8MP_USDHC2_IRQ = 23,
FSL_IMX8MP_USDHC3_IRQ = 24,
FSL_IMX8MP_UART1_IRQ = 26, FSL_IMX8MP_UART1_IRQ = 26,
FSL_IMX8MP_UART2_IRQ = 27, FSL_IMX8MP_UART2_IRQ = 27,
FSL_IMX8MP_UART3_IRQ = 28, FSL_IMX8MP_UART3_IRQ = 28,