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
* Generic Interrupt Controller (GICv3)
* 4 UARTs
* 3 USDHC Storage Controllers
* Secure Non-Volatile Storage (SNVS) including an RTC
* 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
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:
.. code-block:: bash
$ echo "BR2_TARGET_ROOTFS_CPIO=y" >> configs/freescale_imx8mpevk_defconfig
$ make freescale_imx8mpevk_defconfig
$ make
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
``cpu-idle-states`` properties from CPU nodes:
it and resize the SD card image to a power of two:
.. 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
@ -52,5 +58,5 @@ Now that everything is prepared the machine can be started as follows:
-display none -serial null -serial stdio \
-kernel Image \
-dtb imx8mp-evk-patched.dtb \
-initrd rootfs.cpio \
-append "root=/dev/ram"
-append "root=/dev/mmcblk2p2" \
-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_CCM
select IMX
select SDHCI
select UNIMP
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);
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)
@ -346,6 +351,28 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
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 */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) {
return;
@ -363,6 +390,7 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
case FSL_IMX8MP_RAM:
case FSL_IMX8MP_SNVS_HP:
case FSL_IMX8MP_UART1 ... FSL_IMX8MP_UART4:
case FSL_IMX8MP_USDHC1 ... FSL_IMX8MP_USDHC3:
/* device implemented and treated above */
break;

View File

@ -11,6 +11,7 @@
#include "hw/arm/boot.h"
#include "hw/arm/fsl-imx8mp.h"
#include "hw/boards.h"
#include "hw/qdev-properties.h"
#include "system/qtest.h"
#include "qemu/error-report.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,
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()) {
arm_load_kernel(&s->cpu[0], machine, &boot_info);
}

View File

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