Am 5. Dezember 2025 05:38:05 UTC schrieb Gaurav Sharma 
<[email protected]>:
>Implemented CPUs, RAM, UARTs and Interrupt Controller
>Other peripherals are represented as TYPE_UNIMPLEMENTED_DEVICE
>Complete memory map of the SoC is provided.
>
>Signed-off-by: Gaurav Sharma <[email protected]>
>---
> MAINTAINERS                    |  10 +
> docs/system/arm/imx8mm-evk.rst |  68 ++++++
> docs/system/target-arm.rst     |   1 +
> hw/arm/Kconfig                 |  12 ++
> hw/arm/fsl-imx8mm.c            | 366 +++++++++++++++++++++++++++++++++
> hw/arm/imx8mm-evk.c            | 110 ++++++++++
> hw/arm/meson.build             |   2 +
> include/hw/arm/fsl-imx8mm.h    | 157 ++++++++++++++
> 8 files changed, 726 insertions(+)
> create mode 100644 docs/system/arm/imx8mm-evk.rst
> create mode 100644 hw/arm/fsl-imx8mm.c
> create mode 100644 hw/arm/imx8mm-evk.c
> create mode 100644 include/hw/arm/fsl-imx8mm.h
>
>diff --git a/MAINTAINERS b/MAINTAINERS
>index be6efff80c..41f76c5bd0 100644
>--- a/MAINTAINERS
>+++ b/MAINTAINERS
>@@ -884,6 +884,16 @@ F: hw/pci-host/designware.c
> F: include/hw/pci-host/designware.h
> F: docs/system/arm/mcimx7d-sabre.rst
> 
>+MCIMX8MM-EVK / iMX8MM
>+M: Gaurav Sharma <[email protected]>
>+L: [email protected]
>+S: Maintained
>+F: hw/arm/fsl-imx8mm.c
>+F: hw/arm/imx8mm-evk.c
>+F: include/hw/arm/fsl-imx8mm.h
>+F: docs/system/arm/imx8mm-evk.rst
>+F: tests/functional/aarch64/test_imx8mm_evk.py
>+
> MCIMX8MP-EVK / i.MX8MP
> M: Bernhard Beschow <[email protected]>
> L: [email protected]
>diff --git a/docs/system/arm/imx8mm-evk.rst b/docs/system/arm/imx8mm-evk.rst
>new file mode 100644
>index 0000000000..408253193c
>--- /dev/null
>+++ b/docs/system/arm/imx8mm-evk.rst
>@@ -0,0 +1,68 @@
>+NXP i.MX 8MM Evaluation Kit (``imx8mm-evk``)
>+================================================
>+
>+The ``imx8mm-evk`` machine models the i.MX 8M Mini Evaluation Kit, based on an
>+i.MX 8MM SoC.

This file is basically the one from imx8mp-evk with s/imx8mp/imx8mm/ . Perhaps 
we could just list both boards in this section there and mention somewhere.that 
all the commands apply to imx8mm in an analogous fashion? That way we won't 
have to update both documents when something changes.

>+
>+Supported devices
>+-----------------
>+
>+The ``imx8mm-evk`` machine implements the following devices:
>+
>+ * Up to 4 Cortex-A53 cores
>+ * Generic Interrupt Controller (GICv3)
>+ * 4 UARTs
>+
>+Boot options
>+------------
>+
>+The ``imx8mm-evk`` machine can start a Linux kernel directly using the 
>standard
>+``-kernel`` functionality.
>+
>+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
>+toplevel directory of the Buildroot source tree:
>+
>+.. code-block:: bash
>+
>+  $ make freescale_imx8mmevk_defconfig
>+  $ make
>+
>+Once finished successfully there is an ``output/image`` subfolder. Navigate 
>into
>+it and resize the SD card image to a power of two:
>+
>+.. code-block:: bash
>+
>+  $ qemu-img resize sdcard.img 256M
>+
>+Now that everything is prepared the machine can be started as follows:
>+
>+.. code-block:: bash
>+
>+  $ qemu-system-aarch64 -M imx8mm-evk -smp 4 -m 3G \
>+      -display none -serial null -serial stdio \
>+      -kernel Image \
>+      -dtb imx8mm-evk.dtb \
>+      -append "root=/dev/mmcblk2p2" \
>+      -drive file=sdcard.img,if=sd,bus=2,format=raw,id=mmcblk2
>+
>+
>+KVM Acceleration
>+----------------
>+
>+Be aware of the following limitations:
>+
>+* The ``imx8mm-evk`` machine is not included under the "virtualization use 
>case"
>+  of :doc:`QEMU's security policy </system/security>`. This means that you
>+  should not trust that it can contain malicious guests, whether it is run
>+  using TCG or KVM. If you don't trust your guests and you're relying on QEMU 
>to
>+  be the security boundary, you want to choose another machine such as 
>``virt``.
>+* Rather than Cortex-A53 CPUs, the same CPU type as the host's will be used.
>+  This is a limitation of KVM and may not work with guests with a tight
>+  dependency on Cortex-A53.
>+* No EL2 and EL3 exception levels are available which is also a KVM 
>limitation.
>+  Direct kernel boot should work but running U-Boot, TF-A, etc. won't succeed.
>diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst
>index a96d1867df..d6a4b5bb00 100644
>--- a/docs/system/target-arm.rst
>+++ b/docs/system/target-arm.rst
>@@ -97,6 +97,7 @@ Board-specific documentation
>    arm/mcimx6ul-evk
>    arm/mcimx7d-sabre
>    arm/imx8mp-evk
>+   arm/imx8mm-evk
>    arm/orangepi
>    arm/raspi
>    arm/collie
>diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
>index 0cdeb60f1f..be38c67a1c 100644
>--- a/hw/arm/Kconfig
>+++ b/hw/arm/Kconfig
>@@ -626,6 +626,18 @@ config FSL_IMX8MP_EVK
>     depends on TCG || KVM
>     select FSL_IMX8MP
> 
>+config FSL_IMX8MM
>+    bool
>+    select ARM_GIC
>+    select IMX
>+
>+config FSL_IMX8MM_EVK
>+    bool
>+    default y
>+    depends on AARCH64
>+    depends on TCG
>+    select FSL_IMX8MM
>+
> config ARM_SMMUV3
>     bool
> 
>diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c
>new file mode 100644
>index 0000000000..fb6a78adba
>--- /dev/null
>+++ b/hw/arm/fsl-imx8mm.c
>@@ -0,0 +1,366 @@
>+/*
>+ * i.MX 8MM SoC Implementation
>+ *
>+ * Based on hw/arm/fsl-imx6.c

s/imx6/imx8mp/ ?

>+ *
>+ * Copyright (c) 2025, NXP Semiconductors
>+ * Author: Gaurav Sharma <[email protected]>
>+ *
>+ * SPDX-License-Identifier: GPL-2.0-or-later
>+ *
>+ * iMX8MM Reference Manual - https://www.nxp.com/products/i.MX8MMINI -> 
>Documentation
>+ */
>+
>+#include "qemu/osdep.h"
>+#include "system/address-spaces.h"
>+#include "hw/arm/bsa.h"
>+#include "hw/arm/fsl-imx8mm.h"
>+#include "hw/misc/unimp.h"
>+#include "hw/boards.h"
>+#include "system/kvm.h"
>+#include "system/system.h"
>+#include "target/arm/cpu.h"
>+#include "target/arm/cpu-qom.h"
>+#include "target/arm/kvm_arm.h"
>+#include "qapi/error.h"
>+#include "qobject/qlist.h"
>+
>+static const struct {
>+    hwaddr addr;
>+    size_t size;
>+    const char *name;
>+} fsl_imx8mm_memmap[] = {
>+    [FSL_IMX8MM_RAM] = { FSL_IMX8MM_RAM_START, FSL_IMX8MM_RAM_SIZE_MAX, "ram" 
>},
>+    [FSL_IMX8MM_DDR_PHY_BROADCAST] = { 0x3dc00000, 4 * MiB, 
>"ddr_phy_broadcast" },
>+    [FSL_IMX8MM_DDR_PERF_MON] = { 0x3d800000, 4 * MiB, "ddr_perf_mon" },
>+    [FSL_IMX8MM_DDR_CTL] = { 0x3d400000, 4 * MiB, "ddr_ctl" },
>+    [FSL_IMX8MM_DDR_PHY] = { 0x3c000000, 16 * MiB, "ddr_phy" },
>+    [FSL_IMX8MM_GIC_DIST] = { 0x38800000, 512 * KiB, "gic_dist" },
>+    [FSL_IMX8MM_GIC_REDIST] = { 0x38880000, 512 * KiB, "gic_redist" },
>+    [FSL_IMX8MM_VPU] = { 0x38340000, 2 * MiB, "vpu" },
>+    [FSL_IMX8MM_VPU_BLK_CTRL] = { 0x38330000, 2 * MiB, "vpu_blk_ctrl" },
>+    [FSL_IMX8MM_VPU_G2_DECODER] = { 0x38310000, 1 * MiB, "vpu_g2_decoder" },
>+    [FSL_IMX8MM_VPU_G1_DECODER] = { 0x38300000, 1 * MiB, "vpu_g1_decoder" },
>+    [FSL_IMX8MM_USB2_OTG] = { 0x32e50200, 0x200, "usb2_otg" },
>+    [FSL_IMX8MM_USB2] = { 0x32e50000, 0x200, "usb2" },
>+    [FSL_IMX8MM_USB1_OTG] = { 0x32e40200, 0x200, "usb1_otg" },
>+    [FSL_IMX8MM_USB1] = { 0x32e40000, 0x200, "usb1" },
>+    [FSL_IMX8MM_GPU2D] = { 0x38000000, 64 * KiB, "gpu2d" },
>+    [FSL_IMX8MM_QSPI1_RX_BUFFER] = { 0x34000000, 32 * MiB, "qspi1_rx_buffer" 
>},
>+    [FSL_IMX8MM_PCIE1] = { 0x33800000, 4 * MiB, "pcie1" },
>+    [FSL_IMX8MM_QSPI1_TX_BUFFER] = { 0x33008000, 32 * KiB, "qspi1_tx_buffer" 
>},
>+    [FSL_IMX8MM_APBH_DMA] = { 0x33000000, 32 * KiB, "apbh_dma" },
>+
>+    /* AIPS-4 Begin */
>+    [FSL_IMX8MM_TZASC] = { 0x32f80000, 64 * KiB, "tzasc" },
>+    [FSL_IMX8MM_PCIE_PHY1] = { 0x32f00000, 64 * KiB, "pcie_phy1" },
>+    [FSL_IMX8MM_MEDIA_BLK_CTL] = { 0x32e28000, 256, "media_blk_ctl" },
>+    [FSL_IMX8MM_LCDIF] = { 0x32e00000, 64 * KiB, "lcdif" },
>+    [FSL_IMX8MM_MIPI_DSI] = { 0x32e10000, 64 * KiB, "mipi_dsi" },
>+    [FSL_IMX8MM_MIPI_CSI] = { 0x32e30000, 64 * KiB, "mipi_csi" },
>+    [FSL_IMX8MM_AIPS4_CONFIGURATION] = { 0x32df0000, 64 * KiB, 
>"aips4_configuration" },
>+    /* AIPS-4 End */
>+
>+    [FSL_IMX8MM_INTERCONNECT] = { 0x32700000, 1 * MiB, "interconnect" },
>+
>+    /* AIPS-3 Begin */
>+    [FSL_IMX8MM_ENET1] = { 0x30be0000, 64 * KiB, "enet1" },
>+    [FSL_IMX8MM_SDMA1] = { 0x30bd0000, 64 * KiB, "sdma1" },
>+    [FSL_IMX8MM_QSPI] = { 0x30bb0000, 64 * KiB, "qspi" },
>+    [FSL_IMX8MM_USDHC3] = { 0x30b60000, 64 * KiB, "usdhc3" },
>+    [FSL_IMX8MM_USDHC2] = { 0x30b50000, 64 * KiB, "usdhc2" },
>+    [FSL_IMX8MM_USDHC1] = { 0x30b40000, 64 * KiB, "usdhc1" },
>+    [FSL_IMX8MM_SEMAPHORE_HS] = { 0x30ac0000, 64 * KiB, "semaphore_hs" },
>+    [FSL_IMX8MM_MU_B] = { 0x30ab0000, 64 * KiB, "mu_b" },
>+    [FSL_IMX8MM_MU_A] = { 0x30aa0000, 64 * KiB, "mu_a" },
>+    [FSL_IMX8MM_UART4] = { 0x30a60000, 64 * KiB, "uart4" },
>+    [FSL_IMX8MM_I2C4] = { 0x30a50000, 64 * KiB, "i2c4" },
>+    [FSL_IMX8MM_I2C3] = { 0x30a40000, 64 * KiB, "i2c3" },
>+    [FSL_IMX8MM_I2C2] = { 0x30a30000, 64 * KiB, "i2c2" },
>+    [FSL_IMX8MM_I2C1] = { 0x30a20000, 64 * KiB, "i2c1" },
>+    [FSL_IMX8MM_AIPS3_CONFIGURATION] = { 0x309f0000, 64 * KiB, 
>"aips3_configuration" },
>+    [FSL_IMX8MM_CAAM] = { 0x30900000, 256 * KiB, "caam" },
>+    [FSL_IMX8MM_SPBA1] = { 0x308f0000, 64 * KiB, "spba1" },
>+    [FSL_IMX8MM_UART2] = { 0x30890000, 64 * KiB, "uart2" },
>+    [FSL_IMX8MM_UART3] = { 0x30880000, 64 * KiB, "uart3" },
>+    [FSL_IMX8MM_UART1] = { 0x30860000, 64 * KiB, "uart1" },
>+    [FSL_IMX8MM_ECSPI3] = { 0x30840000, 64 * KiB, "ecspi3" },
>+    [FSL_IMX8MM_ECSPI2] = { 0x30830000, 64 * KiB, "ecspi2" },
>+    [FSL_IMX8MM_ECSPI1] = { 0x30820000, 64 * KiB, "ecspi1" },
>+    /* AIPS-3 End */
>+
>+    /* AIPS-2 Begin */
>+    [FSL_IMX8MM_QOSC] = { 0x307f0000, 64 * KiB, "qosc" },
>+    [FSL_IMX8MM_PERFMON2] = { 0x307d0000, 64 * KiB, "perfmon2" },
>+    [FSL_IMX8MM_PERFMON1] = { 0x307c0000, 64 * KiB, "perfmon1" },
>+    [FSL_IMX8MM_GPT4] = { 0x30700000, 64 * KiB, "gpt4" },
>+    [FSL_IMX8MM_GPT5] = { 0x306f0000, 64 * KiB, "gpt5" },
>+    [FSL_IMX8MM_GPT6] = { 0x306e0000, 64 * KiB, "gpt6" },
>+    [FSL_IMX8MM_SYSCNT_CTRL] = { 0x306c0000, 64 * KiB, "syscnt_ctrl" },
>+    [FSL_IMX8MM_SYSCNT_CMP] = { 0x306b0000, 64 * KiB, "syscnt_cmp" },
>+    [FSL_IMX8MM_SYSCNT_RD] = { 0x306a0000, 64 * KiB, "syscnt_rd" },
>+    [FSL_IMX8MM_PWM4] = { 0x30690000, 64 * KiB, "pwm4" },
>+    [FSL_IMX8MM_PWM3] = { 0x30680000, 64 * KiB, "pwm3" },
>+    [FSL_IMX8MM_PWM2] = { 0x30670000, 64 * KiB, "pwm2" },
>+    [FSL_IMX8MM_PWM1] = { 0x30660000, 64 * KiB, "pwm1" },
>+    [FSL_IMX8MM_AIPS2_CONFIGURATION] = { 0x305f0000, 64 * KiB, 
>"aips2_configuration" },
>+    /* AIPS-2 End */
>+
>+    /* AIPS-1 Begin */
>+    [FSL_IMX8MM_CSU] = { 0x303e0000, 64 * KiB, "csu" },
>+    [FSL_IMX8MM_RDC] = { 0x303d0000, 64 * KiB, "rdc" },
>+    [FSL_IMX8MM_SEMAPHORE2] = { 0x303c0000, 64 * KiB, "semaphore2" },
>+    [FSL_IMX8MM_SEMAPHORE1] = { 0x303b0000, 64 * KiB, "semaphore1" },
>+    [FSL_IMX8MM_GPC] = { 0x303a0000, 64 * KiB, "gpc" },
>+    [FSL_IMX8MM_SRC] = { 0x30390000, 64 * KiB, "src" },
>+    [FSL_IMX8MM_CCM] = { 0x30380000, 64 * KiB, "ccm" },
>+    [FSL_IMX8MM_SNVS_HP] = { 0x30370000, 64 * KiB, "snvs_hp" },
>+    [FSL_IMX8MM_ANA_PLL] = { 0x30360000, 64 * KiB, "ana_pll" },
>+    [FSL_IMX8MM_OCOTP_CTRL] = { 0x30350000, 64 * KiB, "ocotp_ctrl" },
>+    [FSL_IMX8MM_IOMUXC_GPR] = { 0x30340000, 64 * KiB, "iomuxc_gpr" },
>+    [FSL_IMX8MM_IOMUXC] = { 0x30330000, 64 * KiB, "iomuxc" },
>+    [FSL_IMX8MM_GPT3] = { 0x302f0000, 64 * KiB, "gpt3" },
>+    [FSL_IMX8MM_GPT2] = { 0x302e0000, 64 * KiB, "gpt2" },
>+    [FSL_IMX8MM_GPT1] = { 0x302d0000, 64 * KiB, "gpt1" },
>+    [FSL_IMX8MM_SDMA2] = { 0x302c0000, 64 * KiB, "sdma2" },
>+    [FSL_IMX8MM_SDMA3] = { 0x302b0000, 64 * KiB, "sdma3" },
>+    [FSL_IMX8MM_WDOG3] = { 0x302a0000, 64 * KiB, "wdog3" },
>+    [FSL_IMX8MM_WDOG2] = { 0x30290000, 64 * KiB, "wdog2" },
>+    [FSL_IMX8MM_WDOG1] = { 0x30280000, 64 * KiB, "wdog1" },
>+    [FSL_IMX8MM_ANA_OSC] = { 0x30270000, 64 * KiB, "ana_osc" },
>+    [FSL_IMX8MM_ANA_TSENSOR] = { 0x30260000, 64 * KiB, "ana_tsensor" },
>+    [FSL_IMX8MM_GPIO5] = { 0x30240000, 64 * KiB, "gpio5" },
>+    [FSL_IMX8MM_GPIO4] = { 0x30230000, 64 * KiB, "gpio4" },
>+    [FSL_IMX8MM_GPIO3] = { 0x30220000, 64 * KiB, "gpio3" },
>+    [FSL_IMX8MM_GPIO2] = { 0x30210000, 64 * KiB, "gpio2" },
>+    [FSL_IMX8MM_GPIO1] = { 0x30200000, 64 * KiB, "gpio1" },
>+    [FSL_IMX8MM_AIPS1_CONFIGURATION] = { 0x301f0000, 64 * KiB, 
>"aips1_configuration" },
>+    [FSL_IMX8MM_SAI6] = { 0x30060000, 64 * KiB, "sai6" },
>+    [FSL_IMX8MM_SAI5] = { 0x30050000, 64 * KiB, "sai5" },
>+    [FSL_IMX8MM_SAI3] = { 0x30030000, 64 * KiB, "sai3" },
>+    [FSL_IMX8MM_SAI2] = { 0x30020000, 64 * KiB, "sai2" },
>+    [FSL_IMX8MM_SAI1] = { 0x30010000, 64 * KiB, "sai1" },
>+
>+    /* AIPS-1 End */
>+
>+    [FSL_IMX8MM_A53_DAP] = { 0x28000000, 16 * MiB, "a53_dap" },
>+    [FSL_IMX8MM_PCIE1_MEM] = { 0x18000000, 128 * MiB, "pcie1_mem" },
>+    [FSL_IMX8MM_QSPI_MEM] = { 0x08000000, 256 * MiB, "qspi_mem" },
>+    [FSL_IMX8MM_OCRAM] = { 0x00900000, 256 * KiB, "ocram" },
>+    [FSL_IMX8MM_TCM_DTCM] = { 0x00800000, 128 * KiB, "tcm_dtcm" },
>+    [FSL_IMX8MM_TCM_ITCM] = { 0x007e0000, 128 * KiB, "tcm_itcm" },
>+    [FSL_IMX8MM_OCRAM_S] = { 0x00180000, 32 * KiB, "ocram_s" },
>+    [FSL_IMX8MM_CAAM_MEM] = { 0x00100000, 32 * KiB, "caam_mem" },
>+    [FSL_IMX8MM_BOOT_ROM_PROTECTED] = { 0x0003f000, 4 * KiB, 
>"boot_rom_protected" },
>+    [FSL_IMX8MM_BOOT_ROM] = { 0x00000000, 252 * KiB, "boot_rom" },
>+};
>+
>+static void fsl_imx8mm_init(Object *obj)
>+{
>+    MachineState *ms = MACHINE(qdev_get_machine());
>+    FslImx8mmState *s = FSL_IMX8MM(obj);
>+    const char *cpu_type = ms->cpu_type ?: ARM_CPU_TYPE_NAME("cortex-a53");
>+    int i;
>+
>+    for (i = 0; i < MIN(ms->smp.cpus, FSL_IMX8MM_NUM_CPUS); i++) {
>+        g_autofree char *name = g_strdup_printf("cpu%d", i);
>+        object_initialize_child(obj, name, &s->cpu[i], cpu_type);
>+    }
>+
>+    object_initialize_child(obj, "gic", &s->gic, gicv3_class_name());
>+
>+    for (i = 0; i < FSL_IMX8MM_NUM_UARTS; i++) {
>+        g_autofree char *name = g_strdup_printf("uart%d", i + 1);
>+        object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL);
>+    }
>+
>+}
>+
>+static void fsl_imx8mm_realize(DeviceState *dev, Error **errp)
>+{
>+    MachineState *ms = MACHINE(qdev_get_machine());
>+    FslImx8mmState *s = FSL_IMX8MM(dev);
>+    DeviceState *gicdev = DEVICE(&s->gic);
>+    int i;
>+
>+    if (ms->smp.cpus > FSL_IMX8MM_NUM_CPUS) {
>+        error_setg(errp, "%s: Only %d CPUs are supported (%d requested)",
>+                   TYPE_FSL_IMX8MM, FSL_IMX8MM_NUM_CPUS, ms->smp.cpus);
>+        return;
>+    }
>+
>+    /* CPUs */
>+    for (i = 0; i < ms->smp.cpus; i++) {
>+        /* On uniprocessor, the CBAR is set to 0 */
>+        if (ms->smp.cpus > 1 &&
>+                object_property_find(OBJECT(&s->cpu[i]), "reset-cbar")) {
>+            object_property_set_int(OBJECT(&s->cpu[i]), "reset-cbar",
>+                                    
>fsl_imx8mm_memmap[FSL_IMX8MM_GIC_DIST].addr,
>+                                    &error_abort);
>+        }
>+
>+        /*
>+         * CNTFID0 base frequency in Hz of system counter
>+         */
>+        object_property_set_int(OBJECT(&s->cpu[i]), "cntfrq", 8000000,
>+                                &error_abort);
>+
>+        if (object_property_find(OBJECT(&s->cpu[i]), "has_el2")) {
>+            object_property_set_bool(OBJECT(&s->cpu[i]), "has_el2",
>+                                     !kvm_enabled(), &error_abort);
>+        }
>+
>+        if (object_property_find(OBJECT(&s->cpu[i]), "has_el3")) {
>+            object_property_set_bool(OBJECT(&s->cpu[i]), "has_el3",
>+                                     !kvm_enabled(), &error_abort);
>+        }
>+
>+        if (i) {
>+            /*
>+             * Secondary CPUs start in powered-down state (and can be
>+             * powered up via the SRC system reset controller)
>+             */
>+            object_property_set_bool(OBJECT(&s->cpu[i]), "start-powered-off",
>+                                     true, &error_abort);
>+        }
>+
>+        if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) {
>+            return;
>+        }
>+    }
>+
>+    /* GIC */
>+    {
>+        SysBusDevice *gicsbd = SYS_BUS_DEVICE(&s->gic);
>+        QList *redist_region_count;
>+        bool pmu = object_property_get_bool(OBJECT(first_cpu), "pmu", NULL);
>+
>+        qdev_prop_set_uint32(gicdev, "num-cpu", ms->smp.cpus);
>+        qdev_prop_set_uint32(gicdev, "num-irq",
>+                             FSL_IMX8MM_NUM_IRQS + GIC_INTERNAL);
>+        redist_region_count = qlist_new();
>+        qlist_append_int(redist_region_count, ms->smp.cpus);
>+        qdev_prop_set_array(gicdev, "redist-region-count", 
>redist_region_count);
>+        object_property_set_link(OBJECT(&s->gic), "sysmem",
>+                                 OBJECT(get_system_memory()), &error_fatal);
>+        if (!sysbus_realize(gicsbd, errp)) {
>+            return;
>+        }
>+        sysbus_mmio_map(gicsbd, 0, 
>fsl_imx8mm_memmap[FSL_IMX8MM_GIC_DIST].addr);
>+        sysbus_mmio_map(gicsbd, 1, 
>fsl_imx8mm_memmap[FSL_IMX8MM_GIC_REDIST].addr);
>+
>+        /*
>+         * Wire the outputs from each CPU's generic timer and the GICv3
>+         * maintenance interrupt signal to the appropriate GIC PPI inputs, and
>+         * the GIC's IRQ/FIQ interrupt outputs to the CPU's inputs.
>+         */
>+        for (i = 0; i < ms->smp.cpus; i++) {
>+            DeviceState *cpudev = DEVICE(&s->cpu[i]);
>+            int intidbase = FSL_IMX8MM_NUM_IRQS + i * GIC_INTERNAL;
>+            qemu_irq irq;
>+
>+            /*
>+             * Mapping from the output timer irq lines from the CPU to the
>+             * GIC PPI inputs.
>+             */
>+            static const int timer_irqs[] = {
>+                [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ,
>+                [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ,
>+                [GTIMER_HYP]  = ARCH_TIMER_NS_EL2_IRQ,
>+                [GTIMER_SEC]  = ARCH_TIMER_S_EL1_IRQ,
>+            };
>+
>+            for (int j = 0; j < ARRAY_SIZE(timer_irqs); j++) {
>+                irq = qdev_get_gpio_in(gicdev, intidbase + timer_irqs[j]);
>+                qdev_connect_gpio_out(cpudev, j, irq);
>+            }
>+
>+            irq = qdev_get_gpio_in(gicdev, intidbase + ARCH_GIC_MAINT_IRQ);
>+            qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt",
>+                                        0, irq);
>+
>+            irq = qdev_get_gpio_in(gicdev, intidbase + VIRTUAL_PMU_IRQ);
>+            qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0, irq);
>+
>+            sysbus_connect_irq(gicsbd, i,
>+                               qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
>+            sysbus_connect_irq(gicsbd, i + ms->smp.cpus,
>+                               qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
>+            sysbus_connect_irq(gicsbd, i + 2 * ms->smp.cpus,
>+                               qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
>+            sysbus_connect_irq(gicsbd, i + 3 * ms->smp.cpus,
>+                               qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
>+
>+            if (kvm_enabled()) {
>+                if (pmu) {
>+                    assert(arm_feature(&s->cpu[i].env, ARM_FEATURE_PMU));
>+                    if (kvm_irqchip_in_kernel()) {
>+                        kvm_arm_pmu_set_irq(&s->cpu[i], VIRTUAL_PMU_IRQ);
>+                    }
>+                    kvm_arm_pmu_init(&s->cpu[i]);
>+                }
>+            }
>+        }
>+    }
>+
>+    /* UARTs */
>+    for (i = 0; i < FSL_IMX8MM_NUM_UARTS; i++) {
>+        static const struct {
>+            hwaddr addr;
>+            unsigned int irq;
>+        } serial_table[FSL_IMX8MM_NUM_UARTS] = {
>+            { fsl_imx8mm_memmap[FSL_IMX8MM_UART1].addr, FSL_IMX8MM_UART1_IRQ 
>},
>+            { fsl_imx8mm_memmap[FSL_IMX8MM_UART2].addr, FSL_IMX8MM_UART2_IRQ 
>},
>+            { fsl_imx8mm_memmap[FSL_IMX8MM_UART3].addr, FSL_IMX8MM_UART3_IRQ 
>},
>+            { fsl_imx8mm_memmap[FSL_IMX8MM_UART4].addr, FSL_IMX8MM_UART4_IRQ 
>},
>+        };
>+
>+        qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i));
>+        if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), errp)) {
>+            return;
>+        }
>+
>+        sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr);
>+        sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
>+                           qdev_get_gpio_in(gicdev, serial_table[i].irq));
>+    }
>+
>+    /* Unimplemented devices */
>+    for (i = 0; i < ARRAY_SIZE(fsl_imx8mm_memmap); i++) {
>+        switch (i) {
>+        case FSL_IMX8MM_GIC_DIST:
>+        case FSL_IMX8MM_GIC_REDIST:
>+        case FSL_IMX8MM_RAM:
>+        case FSL_IMX8MM_UART1 ... FSL_IMX8MM_UART4:
>+            /* device implemented and treated above */
>+            break;
>+
>+        default:
>+            create_unimplemented_device(fsl_imx8mm_memmap[i].name,
>+                                        fsl_imx8mm_memmap[i].addr,
>+                                        fsl_imx8mm_memmap[i].size);
>+            break;
>+        }
>+    }
>+}
>+
>+static void fsl_imx8mm_class_init(ObjectClass *oc, const void *data)
>+{
>+    DeviceClass *dc = DEVICE_CLASS(oc);
>+
>+    dc->realize = fsl_imx8mm_realize;
>+
>+    dc->desc = "i.MX 8MM SoC";
>+}
>+
>+static const TypeInfo fsl_imx8mm_types[] = {
>+    {
>+        .name = TYPE_FSL_IMX8MM,
>+        .parent = TYPE_SYS_BUS_DEVICE,
>+        .instance_size = sizeof(FslImx8mmState),
>+        .instance_init = fsl_imx8mm_init,
>+        .class_init = fsl_imx8mm_class_init,
>+    },
>+};
>+
>+DEFINE_TYPES(fsl_imx8mm_types)
>diff --git a/hw/arm/imx8mm-evk.c b/hw/arm/imx8mm-evk.c
>new file mode 100644
>index 0000000000..ffc69f1050
>--- /dev/null
>+++ b/hw/arm/imx8mm-evk.c
>@@ -0,0 +1,110 @@
>+/*
>+ * NXP i.MX 8MM Evaluation Kit System Emulation
>+ *
>+ * Copyright (c) 2025, NXP Semiconductors
>+ * Author: Gaurav Sharma <[email protected]>
>+ *
>+ * SPDX-License-Identifier: GPL-2.0-or-later
>+ */
>+
>+#include "qemu/osdep.h"
>+#include "system/address-spaces.h"
>+#include "hw/arm/boot.h"
>+#include "hw/arm/fsl-imx8mm.h"
>+#include "hw/arm/machines-qom.h"
>+#include "hw/boards.h"
>+#include "hw/qdev-properties.h"
>+#include "system/kvm.h"
>+#include "system/qtest.h"
>+#include "qemu/error-report.h"
>+#include "qapi/error.h"
>+#include <libfdt.h>

Rather than introducing a new source file I think it should be possible to 
extend imx8mp-evk instead. More comments below.

>+
>+static void imx8mm_evk_modify_dtb(const struct arm_boot_info *info, void *fdt)
>+{
>+    int i, offset;
>+
>+    /* Temporarily disable following nodes until they are implemented */
>+    const char *nodes_to_remove[] = {
>+        "nxp,imx8mm-fspi",
>+        "fsl,imx8mm-mipi-csi",
>+        "fsl,imx8mm-mipi-dsim"

You could probably just add these nodes to the list in imx8mp-evk.

>+    };
>+
>+    for (i = 0; i < ARRAY_SIZE(nodes_to_remove); i++) {
>+        const char *dev_str = nodes_to_remove[i];
>+
>+        offset = fdt_node_offset_by_compatible(fdt, -1, dev_str);
>+        while (offset >= 0) {
>+            fdt_nop_node(fdt, offset);
>+            offset = fdt_node_offset_by_compatible(fdt, offset, dev_str);
>+        }
>+    }
>+
>+    /* Remove cpu-idle-states property from CPU nodes */
>+    offset = fdt_node_offset_by_compatible(fdt, -1, "arm,cortex-a53");
>+    while (offset >= 0) {
>+        fdt_nop_property(fdt, offset, "cpu-idle-states");
>+        offset = fdt_node_offset_by_compatible(fdt, offset, "arm,cortex-a53");
>+    }
>+
>+    if (kvm_enabled()) {
>+        /* Use system counter frequency from host CPU to fix time in guest */
>+        offset = fdt_node_offset_by_compatible(fdt, -1, "arm,armv8-timer");
>+        while (offset >= 0) {
>+            fdt_nop_property(fdt, offset, "clock-frequency");
>+            offset = fdt_node_offset_by_compatible(fdt, offset, 
>"arm,armv8-timer");
>+        }
>+    }
>+}
>+
>+static void imx8mm_evk_init(MachineState *machine)
>+{
>+    static struct arm_boot_info boot_info;
>+    FslImx8mmState *s;
>+

In this function it might be possible to perform an object_dynamic_cast() on 
the MachineState to check which machine was requested by the user. Depending on 
that one could fill variables with SoC-specific values and use them below 
instead of hardcoded values.

>+    if (machine->ram_size > FSL_IMX8MM_RAM_SIZE_MAX) {
>+        error_report("RAM size " RAM_ADDR_FMT " above max supported (%08" 
>PRIx64 ")",
>+                     machine->ram_size, FSL_IMX8MM_RAM_SIZE_MAX);
>+        exit(1);
>+    }
>+
>+    boot_info = (struct arm_boot_info) {
>+        .loader_start = FSL_IMX8MM_RAM_START,
>+        .board_id = -1,
>+        .ram_size = machine->ram_size,
>+        .psci_conduit = QEMU_PSCI_CONDUIT_SMC,
>+        .modify_dtb = imx8mm_evk_modify_dtb,
>+    };
>+
>+    s = FSL_IMX8MM(object_new(TYPE_FSL_IMX8MM));
>+    object_property_add_child(OBJECT(machine), "soc", OBJECT(s));
>+    sysbus_realize_and_unref(SYS_BUS_DEVICE(s), &error_fatal);
>+
>+    memory_region_add_subregion(get_system_memory(), FSL_IMX8MM_RAM_START,
>+                                machine->ram);
>+
>+    if (!qtest_enabled()) {
>+        arm_load_kernel(&s->cpu[0], machine, &boot_info);
>+    }
>+}
>+
>+static const char *imx8mm_evk_get_default_cpu_type(const MachineState *ms)
>+{
>+    if (kvm_enabled()) {
>+        return ARM_CPU_TYPE_NAME("host");
>+    }
>+
>+    return ARM_CPU_TYPE_NAME("cortex-a53");
>+}

The code below might just be able to copied over to imx8mp-evk.c.

Does such consolidation work?

Best regards,
Bernhard

>+
>+static void imx8mm_evk_machine_init(MachineClass *mc)
>+{
>+    mc->desc = "NXP i.MX 8MM EVK Board";
>+    mc->init = imx8mm_evk_init;
>+    mc->max_cpus = FSL_IMX8MM_NUM_CPUS;
>+    mc->default_ram_id = "imx8mm-evk.ram";
>+    mc->get_default_cpu_type = imx8mm_evk_get_default_cpu_type;
>+}
>+
>+DEFINE_MACHINE_AARCH64("imx8mm-evk", imx8mm_evk_machine_init)
>diff --git a/hw/arm/meson.build b/hw/arm/meson.build
>index aeaf654790..12ecb824cc 100644
>--- a/hw/arm/meson.build
>+++ b/hw/arm/meson.build
>@@ -84,6 +84,8 @@ arm_common_ss.add(when: 'CONFIG_ARMSSE', if_true: 
>files('armsse.c'))
> arm_common_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 
> 'mcimx7d-sabre.c'))
> arm_common_ss.add(when: 'CONFIG_FSL_IMX8MP', if_true: files('fsl-imx8mp.c'))
> arm_common_ss.add(when: 'CONFIG_FSL_IMX8MP_EVK', if_true: 
> files('imx8mp-evk.c'))
>+arm_common_ss.add(when: 'CONFIG_FSL_IMX8MM', if_true: files('fsl-imx8mm.c'))
>+arm_common_ss.add(when: 'CONFIG_FSL_IMX8MM_EVK', if_true: 
>files('imx8mm-evk.c'))
> arm_common_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmuv3.c'))
> arm_common_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 
> 'mcimx6ul-evk.c'))
> arm_common_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c'))
>diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h
>new file mode 100644
>index 0000000000..133f519b7c
>--- /dev/null
>+++ b/include/hw/arm/fsl-imx8mm.h
>@@ -0,0 +1,157 @@
>+/*
>+ * i.MX 8MM SoC Definitions
>+ *
>+ * Copyright (c) 2025, NXP Semiconductors
>+ * Author: Gaurav Sharma <[email protected]>
>+ *
>+ * SPDX-License-Identifier: GPL-2.0-or-later
>+ */
>+
>+#ifndef FSL_IMX8MM_H
>+#define FSL_IMX8MM_H
>+
>+#include "cpu.h"
>+#include "hw/char/imx_serial.h"
>+#include "hw/intc/arm_gicv3_common.h"
>+#include "qom/object.h"
>+#include "qemu/units.h"
>+
>+#define TYPE_FSL_IMX8MM "fsl-imx8mm"
>+OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mmState, FSL_IMX8MM)
>+
>+#define FSL_IMX8MM_RAM_START        0x40000000
>+#define FSL_IMX8MM_RAM_SIZE_MAX     (4 * GiB)
>+
>+enum FslImx8mmConfiguration {
>+    FSL_IMX8MM_NUM_CPUS         = 4,
>+    FSL_IMX8MM_NUM_IRQS         = 128,
>+    FSL_IMX8MM_NUM_UARTS        = 4,
>+};
>+
>+struct FslImx8mmState {
>+    SysBusDevice   parent_obj;
>+
>+    ARMCPU             cpu[FSL_IMX8MM_NUM_CPUS];
>+    GICv3State         gic;
>+    IMXSerialState     uart[FSL_IMX8MM_NUM_UARTS];
>+};
>+
>+enum FslImx8mmMemoryRegions {
>+    FSL_IMX8MM_A53_DAP,
>+    FSL_IMX8MM_AIPS1_CONFIGURATION,
>+    FSL_IMX8MM_AIPS2_CONFIGURATION,
>+    FSL_IMX8MM_AIPS3_CONFIGURATION,
>+    FSL_IMX8MM_AIPS4_CONFIGURATION,
>+    FSL_IMX8MM_ANA_OSC,
>+    FSL_IMX8MM_ANA_PLL,
>+    FSL_IMX8MM_ANA_TSENSOR,
>+    FSL_IMX8MM_APBH_DMA,
>+    FSL_IMX8MM_BOOT_ROM,
>+    FSL_IMX8MM_BOOT_ROM_PROTECTED,
>+    FSL_IMX8MM_CAAM,
>+    FSL_IMX8MM_CAAM_MEM,
>+    FSL_IMX8MM_CCM,
>+    FSL_IMX8MM_CSU,
>+    FSL_IMX8MM_DDR_CTL,
>+    FSL_IMX8MM_DDR_PERF_MON,
>+    FSL_IMX8MM_DDR_PHY,
>+    FSL_IMX8MM_DDR_PHY_BROADCAST,
>+    FSL_IMX8MM_ECSPI1,
>+    FSL_IMX8MM_ECSPI2,
>+    FSL_IMX8MM_ECSPI3,
>+    FSL_IMX8MM_ENET1,
>+    FSL_IMX8MM_GIC_DIST,
>+    FSL_IMX8MM_GIC_REDIST,
>+    FSL_IMX8MM_GPC,
>+    FSL_IMX8MM_GPIO1,
>+    FSL_IMX8MM_GPIO2,
>+    FSL_IMX8MM_GPIO3,
>+    FSL_IMX8MM_GPIO4,
>+    FSL_IMX8MM_GPIO5,
>+    FSL_IMX8MM_GPT1,
>+    FSL_IMX8MM_GPT2,
>+    FSL_IMX8MM_GPT3,
>+    FSL_IMX8MM_GPT4,
>+    FSL_IMX8MM_GPT5,
>+    FSL_IMX8MM_GPT6,
>+    FSL_IMX8MM_GPU2D,
>+    FSL_IMX8MM_I2C1,
>+    FSL_IMX8MM_I2C2,
>+    FSL_IMX8MM_I2C3,
>+    FSL_IMX8MM_I2C4,
>+    FSL_IMX8MM_INTERCONNECT,
>+    FSL_IMX8MM_IOMUXC,
>+    FSL_IMX8MM_IOMUXC_GPR,
>+    FSL_IMX8MM_MEDIA_BLK_CTL,
>+    FSL_IMX8MM_LCDIF,
>+    FSL_IMX8MM_MIPI_CSI,
>+    FSL_IMX8MM_MIPI_DSI,
>+    FSL_IMX8MM_MU_A,
>+    FSL_IMX8MM_MU_B,
>+    FSL_IMX8MM_OCOTP_CTRL,
>+    FSL_IMX8MM_OCRAM,
>+    FSL_IMX8MM_OCRAM_S,
>+    FSL_IMX8MM_PCIE1,
>+    FSL_IMX8MM_PCIE1_MEM,
>+    FSL_IMX8MM_PCIE_PHY1,
>+    FSL_IMX8MM_PERFMON1,
>+    FSL_IMX8MM_PERFMON2,
>+    FSL_IMX8MM_PWM1,
>+    FSL_IMX8MM_PWM2,
>+    FSL_IMX8MM_PWM3,
>+    FSL_IMX8MM_PWM4,
>+    FSL_IMX8MM_QOSC,
>+    FSL_IMX8MM_QSPI,
>+    FSL_IMX8MM_QSPI1_RX_BUFFER,
>+    FSL_IMX8MM_QSPI1_TX_BUFFER,
>+    FSL_IMX8MM_QSPI_MEM,
>+    FSL_IMX8MM_RAM,
>+    FSL_IMX8MM_RDC,
>+    FSL_IMX8MM_SAI1,
>+    FSL_IMX8MM_SAI2,
>+    FSL_IMX8MM_SAI3,
>+    FSL_IMX8MM_SAI5,
>+    FSL_IMX8MM_SAI6,
>+    FSL_IMX8MM_SDMA1,
>+    FSL_IMX8MM_SDMA2,
>+    FSL_IMX8MM_SDMA3,
>+    FSL_IMX8MM_SEMAPHORE1,
>+    FSL_IMX8MM_SEMAPHORE2,
>+    FSL_IMX8MM_SEMAPHORE_HS,
>+    FSL_IMX8MM_SNVS_HP,
>+    FSL_IMX8MM_SPBA1,
>+    FSL_IMX8MM_SRC,
>+    FSL_IMX8MM_SYSCNT_CMP,
>+    FSL_IMX8MM_SYSCNT_CTRL,
>+    FSL_IMX8MM_SYSCNT_RD,
>+    FSL_IMX8MM_TCM_DTCM,
>+    FSL_IMX8MM_TCM_ITCM,
>+    FSL_IMX8MM_TZASC,
>+    FSL_IMX8MM_UART1,
>+    FSL_IMX8MM_UART2,
>+    FSL_IMX8MM_UART3,
>+    FSL_IMX8MM_UART4,
>+    FSL_IMX8MM_USB1,
>+    FSL_IMX8MM_USB2,
>+    FSL_IMX8MM_USB1_OTG,
>+    FSL_IMX8MM_USB2_OTG,
>+    FSL_IMX8MM_USDHC1,
>+    FSL_IMX8MM_USDHC2,
>+    FSL_IMX8MM_USDHC3,
>+    FSL_IMX8MM_VPU,
>+    FSL_IMX8MM_VPU_BLK_CTRL,
>+    FSL_IMX8MM_VPU_G1_DECODER,
>+    FSL_IMX8MM_VPU_G2_DECODER,
>+    FSL_IMX8MM_WDOG1,
>+    FSL_IMX8MM_WDOG2,
>+    FSL_IMX8MM_WDOG3,
>+};
>+
>+enum FslImx8mmIrqs {
>+    FSL_IMX8MM_UART1_IRQ    = 26,
>+    FSL_IMX8MM_UART2_IRQ    = 27,
>+    FSL_IMX8MM_UART3_IRQ    = 28,
>+    FSL_IMX8MM_UART4_IRQ    = 29,
>+};
>+
>+#endif /* FSL_IMX8MM_H */


Reply via email to