[RFC PATCH 22/23] hw/arm: add basic support for the RT500 SoC

Octavian Purdila posted 23 patches 3 months, 2 weeks ago
There is a newer version of this series
[RFC PATCH 22/23] hw/arm: add basic support for the RT500 SoC
Posted by Octavian Purdila 3 months, 2 weeks ago
Add basic support for the RT500 SoC. It supports enough peripherals to
run the NXP's microXpresso SDK hello world example.

Signed-off-by: Octavian Purdila <tavip@google.com>
---
 hw/arm/Kconfig         |   8 +
 hw/arm/meson.build     |   1 +
 hw/arm/rt500.c         | 348 +++++++++++++++++++++++++++++++++++++++++
 hw/arm/svd/meson.build |   6 +
 include/hw/arm/rt500.h |  49 ++++++
 5 files changed, 412 insertions(+)
 create mode 100644 hw/arm/rt500.c
 create mode 100644 include/hw/arm/rt500.h

diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 1ad60da7aa..7ffece3dec 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -712,3 +712,11 @@ config ARMSSE
     select UNIMP
     select SSE_COUNTER
     select SSE_TIMER
+
+config RT500
+    bool
+    select FLEXCOMM
+    select RT500_CLKCTL0
+    select RT500_CLKCTL1
+    select FLEXSPI
+    select RT500_RSTCTL
diff --git a/hw/arm/meson.build b/hw/arm/meson.build
index eb604d00cf..7d827d512c 100644
--- a/hw/arm/meson.build
+++ b/hw/arm/meson.build
@@ -59,6 +59,7 @@ arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmuv3.c'))
 arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c'))
 arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c'))
 arm_ss.add(when: 'CONFIG_XEN', if_true: files('xen_arm.c'))
+arm_ss.add(when: 'CONFIG_RT500', if_true: files('rt500.c'))
 
 system_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c'))
 system_ss.add(when: 'CONFIG_CHEETAH', if_true: files('palm.c'))
diff --git a/hw/arm/rt500.c b/hw/arm/rt500.c
new file mode 100644
index 0000000000..0866ef3ef6
--- /dev/null
+++ b/hw/arm/rt500.c
@@ -0,0 +1,348 @@
+/*
+ * i.MX RT500 platforms.
+ *
+ * Copyright (c) 2024 Google LLC
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/sysbus.h"
+#include "hw/arm/boot.h"
+#include "hw/boards.h"
+#include "hw/irq.h"
+#include "qemu/log.h"
+#include "qemu/datadir.h"
+#include "exec/address-spaces.h"
+#include "sysemu/reset.h"
+#include "sysemu/runstate.h"
+#include "sysemu/sysemu.h"
+#include "hw/arm/armv7m.h"
+#include "hw/loader.h"
+#include "hw/qdev-clock.h"
+#include "hw/misc/unimp.h"
+#include "hw/arm/rt500.h"
+#include "hw/arm/svd/rt500.h"
+
+#define MMAP_SRAM_CODE_BASE   (0x0)
+#define MMAP_SRAM_DATA_BASE   (0x20000000)
+#define MMAP_SRAM_SIZE        (5 * MiB)
+#define MMAP_BOOT_ROM_BASE    (0x03000000)
+#define MMAP_BOOT_ROM_SIZE    (192 * KiB)
+#define MMAP_SDMA_RAM_BASE    (0x24100000)
+#define MMAP_SDMA_RAM_SIZE    (32 * KiB)
+#define MMAP_FLEXSPI0_BASE    (0x08000000)
+#define MMAP_FLEXSPI0_SIZE    (128 * MiB)
+#define MMAP_FLEXSPI1_BASE    (0x28000000)
+#define MMAP_FLEXSPI1_SIZE    (128 * MiB)
+
+#define SECURE_OFFSET    (0x10000000)
+
+typedef enum MemInfoType {
+    MEM_RAM,
+    MEM_ROM,
+    MEM_ALIAS
+} MemInfoType;
+
+static void do_sys_reset(void *opaque, int n, int level)
+{
+    if (level) {
+        qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+    }
+}
+
+static void rt500_init(Object *obj)
+{
+    RT500State *s = RT500(obj);
+    int i;
+
+    /* Add ARMv7-M device */
+    object_initialize_child(obj, "armv7m", &s->armv7m, TYPE_ARMV7M);
+
+    for (i = 0; i < RT500_FLEXCOMM_NUM; i++) {
+        char id[] = "flexcommXX";
+
+        snprintf(id, sizeof(id), "flexcomm%d", i);
+        object_initialize_child(obj, id, &s->flexcomm[i], TYPE_FLEXCOMM);
+        DEVICE(&s->flexcomm[i])->id = g_strdup(id);
+    }
+
+    object_initialize_child(obj, "clkctl0", &s->clkctl0, TYPE_RT500_CLKCTL0);
+    object_initialize_child(obj, "clkctl1", &s->clkctl1, TYPE_RT500_CLKCTL1);
+
+    /* Initialize clocks */
+    s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0);
+    s->refclk = qdev_init_clock_in(DEVICE(s), "refclk", NULL, NULL, 0);
+
+    for (i = 0; i < RT500_FLEXSPI_NUM; i++) {
+        char id[] = "flexspiXX";
+
+        snprintf(id, sizeof(id), "flexspi%d", i);
+        object_initialize_child(obj, id, &s->flexspi[i], TYPE_FLEXSPI);
+        DEVICE(&s->flexspi[i])->id = g_strdup(id);
+    }
+
+    for (i = 0; i < RT500_RSTCTL_NUM; i++) {
+        char id[] = "rstctlX";
+
+        snprintf(id, sizeof(id), "rstctl%d", i);
+        object_initialize_child(obj, id, &s->rstctl[i],
+                                TYPE_RT500_RSTCTL);
+        DEVICE(&s->rstctl[i])->id = g_strdup(id);
+    }
+}
+
+static void rt500_realize_memory(RT500State *s, Error **errp)
+{
+    const struct {
+        const char *name;
+        hwaddr base;
+        size_t size;
+        MemInfoType type;
+        int alias_for;
+    } mem_info[] = {
+        {
+            .name = "SRAM (code bus)",
+            .base = MMAP_SRAM_CODE_BASE,
+            .size = MMAP_SRAM_SIZE,
+            .type = MEM_RAM,
+        },
+        {
+            .name = "BOOT-ROM",
+            .base = MMAP_BOOT_ROM_BASE,
+            .size = MMAP_BOOT_ROM_SIZE,
+            .type = MEM_ROM,
+        },
+        {
+            .name = "Smart DMA RAM",
+            .base = MMAP_SDMA_RAM_BASE,
+            .size = MMAP_SDMA_RAM_SIZE,
+            .type = MEM_RAM,
+        },
+        {
+            .name = "SRAM (data bus)",
+            .base = MMAP_SRAM_DATA_BASE,
+            .size = MMAP_SRAM_SIZE,
+            .type = MEM_ALIAS,
+            .alias_for = 0
+        },
+    };
+    int i;
+
+    s->mem = g_malloc_n(2 * ARRAY_SIZE(mem_info), sizeof(MemoryRegion));
+    for (i = 0; i < ARRAY_SIZE(mem_info); i++) {
+        const char *name = mem_info[i].name;
+        int size = mem_info[i].size;
+        int type = mem_info[i].type;
+        int alias_for = mem_info[i].alias_for;
+        MemoryRegion *mem = &s->mem[i];
+        uint32_t base = mem_info[i].base;
+        MemoryRegion *sec_mem;
+        char sec_name[256];
+
+        switch (type) {
+        case MEM_RAM:
+            memory_region_init_ram(mem, OBJECT(s), name, size, errp);
+            break;
+        case MEM_ROM:
+            memory_region_init_rom(mem, OBJECT(s), name, size, errp);
+            break;
+        case MEM_ALIAS:
+        {
+            MemoryRegion *orig = &s->mem[alias_for];
+
+            memory_region_init_alias(mem, OBJECT(s), name, orig, 0, size);
+            break;
+        }
+        default:
+            g_assert_not_reached();
+        }
+
+        memory_region_add_subregion(get_system_memory(), base, mem);
+
+        /* create secure alias */
+        snprintf(sec_name, sizeof(sec_name), "SECURE %s", name);
+        sec_mem = &s->mem[ARRAY_SIZE(mem_info) + i];
+        if (type == MEM_ALIAS) {
+            mem = &s->mem[alias_for];
+        }
+        memory_region_init_alias(sec_mem, OBJECT(s), sec_name, mem, 0, size);
+        memory_region_add_subregion(get_system_memory(), base + SECURE_OFFSET,
+                                    sec_mem);
+
+        if (mem_info[i].type == MEM_ROM) {
+            char *fname = qemu_find_file(QEMU_FILE_TYPE_BIOS, "rt500.rom");
+
+            if (fname) {
+                int fsize = get_image_size(fname);
+                int ret;
+
+                if (fsize > size) {
+                    error_setg(errp, "rom file too big: %d > %d", fsize, size);
+                } else {
+                    ret = load_image_targphys(fname, base, size);
+                    if (ret < 0) {
+                        error_setg(errp, "could not load rom: %s", fname);
+                    }
+                }
+            }
+            g_free(fname);
+        }
+    }
+}
+
+static void rt500_realize(DeviceState *dev, Error **errp)
+{
+    MachineState *ms = MACHINE(qdev_get_machine());
+    RT500State *s = RT500(dev);
+    int i;
+
+    rt500_realize_memory(s, errp);
+
+    /* Setup ARMv7M CPU */
+    qdev_prop_set_uint32(DEVICE(&s->armv7m), "num-irq",
+                         RT500_FLEXCOMM16_IRQn + 1);
+    qdev_prop_set_uint8(DEVICE(&s->armv7m), "num-prio-bits", 3);
+    qdev_prop_set_string(DEVICE(&s->armv7m), "cpu-type", ms->cpu_type);
+    object_property_set_link(OBJECT(&s->armv7m), "memory",
+                             OBJECT(get_system_memory()), &error_abort);
+    if (!ms->kernel_filename) {
+        qdev_prop_set_uint32(DEVICE(&s->armv7m), "init-nsvtor",
+                             MMAP_BOOT_ROM_BASE);
+        qdev_prop_set_uint32(DEVICE(&s->armv7m), "init-svtor",
+                             MMAP_BOOT_ROM_BASE + SECURE_OFFSET);
+    }
+
+    qdev_connect_clock_in(DEVICE(&s->armv7m), "cpuclk", s->sysclk);
+    qdev_connect_clock_in(DEVICE(&s->armv7m), "refclk",
+                     qdev_get_clock_out(DEVICE(&s->clkctl0), "systick_clk"));
+
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(&s->armv7m), errp);
+    qdev_connect_gpio_out_named(DEVICE(&s->armv7m), "SYSRESETREQ", 0,
+                                qemu_allocate_irq(&do_sys_reset, NULL, 0));
+
+    /* Setup FLEXCOMM */
+    for (i = 0; i < RT500_FLEXCOMM_NUM; i++) {
+        const uint32_t addr[] = {
+            RT500_FLEXCOMM0_BASE, RT500_FLEXCOMM1_BASE, RT500_FLEXCOMM2_BASE,
+            RT500_FLEXCOMM3_BASE, RT500_FLEXCOMM4_BASE, RT500_FLEXCOMM5_BASE,
+            RT500_FLEXCOMM6_BASE, RT500_FLEXCOMM7_BASE, RT500_FLEXCOMM8_BASE,
+            RT500_FLEXCOMM8_BASE, RT500_FLEXCOMM10_BASE, RT500_FLEXCOMM11_BASE,
+            RT500_FLEXCOMM12_BASE, RT500_FLEXCOMM13_BASE, RT500_FLEXCOMM14_BASE,
+            RT500_FLEXCOMM15_BASE, RT500_FLEXCOMM16_BASE
+        };
+        const int irq[] = {
+            RT500_FLEXCOMM0_IRQn, RT500_FLEXCOMM1_IRQn, RT500_FLEXCOMM2_IRQn,
+            RT500_FLEXCOMM3_IRQn, RT500_FLEXCOMM4_IRQn, RT500_FLEXCOMM5_IRQn,
+            RT500_FLEXCOMM6_IRQn, RT500_FLEXCOMM7_IRQn, RT500_FLEXCOMM8_IRQn,
+            RT500_FLEXCOMM9_IRQn, RT500_FLEXCOMM10_IRQn, RT500_FLEXCOMM11_IRQn,
+            RT500_FLEXCOMM12_IRQn, RT500_FLEXCOMM13_IRQn, RT500_FLEXCOMM14_IRQn,
+            RT500_FLEXCOMM15_IRQn, RT500_FLEXCOMM16_IRQn
+        };
+        const int functions[] = {
+            FLEXCOMM_FULL, FLEXCOMM_FULL, FLEXCOMM_FULL,
+            FLEXCOMM_FULL, FLEXCOMM_FULL, FLEXCOMM_FULL,
+            FLEXCOMM_FULL, FLEXCOMM_FULL, FLEXCOMM_FULL,
+            FLEXCOMM_FULL, FLEXCOMM_FULL, FLEXCOMM_FULL,
+            FLEXCOMM_FULL, FLEXCOMM_FULL, FLEXCOMM_HSSPI,
+            FLEXCOMM_PMICI2C, FLEXCOMM_HSSPI
+        };
+        DeviceState *ds = DEVICE(&s->flexcomm[i]);
+        char id[] = "flexcommXX";
+
+        snprintf(id, sizeof(id), "flexcomm%d", i);
+        qdev_prop_set_uint32(ds, "functions", functions[i]);
+        qdev_prop_set_chr(ds, "chardev", qemu_chr_find(id));
+        sysbus_realize_and_unref(SYS_BUS_DEVICE(ds), errp);
+        sysbus_mmio_map(SYS_BUS_DEVICE(ds), 0, addr[i]);
+        sysbus_connect_irq(SYS_BUS_DEVICE(ds), 0,
+                           qdev_get_gpio_in(DEVICE(&s->armv7m), irq[i]));
+    }
+
+    /* Setup CTLCTL0 */
+    qdev_connect_clock_in(DEVICE(&s->clkctl0), "sysclk", s->sysclk);
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(DEVICE(&s->clkctl0)), errp);
+    sysbus_mmio_map(SYS_BUS_DEVICE(DEVICE(&s->clkctl0)), 0, RT500_CLKCTL0_BASE);
+
+    /* Setup CTLCTL1 */
+    qdev_connect_clock_in(DEVICE(&s->clkctl1), "sysclk", s->sysclk);
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(DEVICE(&s->clkctl1)), errp);
+    sysbus_mmio_map(SYS_BUS_DEVICE(DEVICE(&s->clkctl1)), 0, RT500_CLKCTL1_BASE);
+
+    /* Setup FlexSPI */
+    for (i = 0; i < RT500_FLEXSPI_NUM; i++) {
+        const uint32_t addr[] = {
+            RT500_FLEXSPI0_BASE, RT500_FLEXSPI1_BASE
+        };
+        const uint32_t mmap_base[] = {
+            MMAP_FLEXSPI0_BASE, MMAP_FLEXSPI1_BASE
+        };
+        const uint32_t mmap_size[] = {
+            MMAP_FLEXSPI0_SIZE, MMAP_FLEXSPI1_SIZE,
+        };
+        DeviceState *ds = DEVICE(&s->flexspi[i]);
+
+        qdev_prop_set_uint32(ds, "mmap_base", mmap_base[i]);
+        qdev_prop_set_uint32(ds, "mmap_size", mmap_size[i]);
+        sysbus_realize_and_unref(SYS_BUS_DEVICE(ds), errp);
+        sysbus_mmio_map(SYS_BUS_DEVICE(ds), 0, addr[i]);
+    }
+
+    /* Setup reset controllers */
+    for (i = 0; i < RT500_RSTCTL_NUM; i++) {
+        DeviceState *ds = DEVICE(&s->rstctl[i]);
+
+        const uint32_t addr[] = {
+            RT500_RSTCTL0_BASE, RT500_RSTCTL1_BASE
+        };
+
+        qdev_prop_set_uint32(ds, "num", i);
+        sysbus_realize_and_unref(SYS_BUS_DEVICE(ds), errp);
+        sysbus_mmio_map(SYS_BUS_DEVICE(ds), 0, addr[i]);
+    }
+}
+
+static void rt500_finalize(Object *obj)
+{
+    RT500State *s = RT500(obj);
+
+    g_free(s->mem);
+}
+
+static void rt500_reset(DeviceState *ds)
+{
+}
+
+static Property rt500_properties[] = {
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void rt500_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    device_class_set_props(dc, rt500_properties);
+    dc->realize = rt500_realize;
+    dc->desc = "RT500 (ARM Cortex-M33)";
+    dc->reset = rt500_reset;
+}
+
+static const TypeInfo rt500_type_info = {
+    .name = TYPE_RT500,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(RT500State),
+    .instance_init = rt500_init,
+    .instance_finalize = rt500_finalize,
+    .class_init = rt500_class_init,
+};
+
+static void rt500_register_types(void)
+{
+    type_register_static(&rt500_type_info);
+}
+
+type_init(rt500_register_types)
diff --git a/hw/arm/svd/meson.build b/hw/arm/svd/meson.build
index 72a7421c6f..930a8b7343 100644
--- a/hw/arm/svd/meson.build
+++ b/hw/arm/svd/meson.build
@@ -34,3 +34,9 @@ genh += custom_target('rt500_rstctl1.h',
                       output: 'rt500_rstctl1.h',
                       input: 'MIMXRT595S_cm33.xml',
                       command: [ svd_gen_header, '-i', '@INPUT@', '-o', '@OUTPUT@', '-p', 'RSTCTL1', '-t', 'RT500_RSTCTL1'])
+genh += custom_target('rt500.h',
+                      output: 'rt500.h',
+                      input: 'MIMXRT595S_cm33.xml',
+                      command: [ svd_gen_header,'-i', '@INPUT@', '-o', '@OUTPUT@', '-s', 'RT500',
+		                 '-p', 'FLEXCOMM0', '-p', 'CLKCTL0', '-p', 'CLKCTL1',
+				 '-p', 'FLEXSPI0', '-p', 'FLEXSPI1', '-p', 'RSTCTL0', '-p', 'RSTCTL1'])
diff --git a/include/hw/arm/rt500.h b/include/hw/arm/rt500.h
new file mode 100644
index 0000000000..8ca7972f8a
--- /dev/null
+++ b/include/hw/arm/rt500.h
@@ -0,0 +1,49 @@
+/*
+ * i.MX RT500 platforms.
+ *
+ * Copyright (c) 2024 Google LLC
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#ifndef HW_ARM_RT500_H
+#define HW_ARM_RT500_H
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "hw/arm/boot.h"
+#include "hw/arm/armv7m.h"
+#include "hw/misc/flexcomm.h"
+#include "hw/misc/rt500_clkctl0.h"
+#include "hw/misc/rt500_clkctl1.h"
+#include "hw/ssi/flexspi.h"
+#include "hw/misc/rt500_rstctl.h"
+
+#define TYPE_RT500 "rt500"
+#define RT500(obj) OBJECT_CHECK(RT500State, (obj), TYPE_RT500)
+
+#define RT500_FLEXCOMM_NUM (17)
+#define RT500_FLEXSPI_NUM (2)
+#define RT500_RSTCTL_NUM (2)
+
+typedef struct RT500State {
+    /*< private >*/
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+    ARMv7MState armv7m;
+    MemoryRegion *mem;
+    FlexcommState flexcomm[RT500_FLEXCOMM_NUM];
+    RT500ClkCtl0State clkctl0;
+    RT500ClkCtl1State clkctl1;
+    FlexSpiState flexspi[RT500_FLEXSPI_NUM];
+    RT500RstCtlState rstctl[RT500_RSTCTL_NUM];
+
+    Clock *sysclk;
+    Clock *refclk;
+} RT500State;
+
+#endif /* HW_ARM_RT500_H */
-- 
2.46.0.rc2.264.g509ed76dc8-goog
Re: [RFC PATCH 22/23] hw/arm: add basic support for the RT500 SoC
Posted by Philippe Mathieu-Daudé 3 months, 2 weeks ago
Hi Octavian,

Few comments inlined.

On 5/8/24 22:17, Octavian Purdila wrote:
> Add basic support for the RT500 SoC. It supports enough peripherals to
> run the NXP's microXpresso SDK hello world example.
> 
> Signed-off-by: Octavian Purdila <tavip@google.com>
> ---
>   hw/arm/Kconfig         |   8 +
>   hw/arm/meson.build     |   1 +
>   hw/arm/rt500.c         | 348 +++++++++++++++++++++++++++++++++++++++++
>   hw/arm/svd/meson.build |   6 +
>   include/hw/arm/rt500.h |  49 ++++++
>   5 files changed, 412 insertions(+)
>   create mode 100644 hw/arm/rt500.c
>   create mode 100644 include/hw/arm/rt500.h

If possible please setup scripts/git.orderfile, it help to
review.

> diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
> index 1ad60da7aa..7ffece3dec 100644
> --- a/hw/arm/Kconfig
> +++ b/hw/arm/Kconfig
> @@ -712,3 +712,11 @@ config ARMSSE
>       select UNIMP
>       select SSE_COUNTER
>       select SSE_TIMER
> +
> +config RT500
> +    bool
> +    select FLEXCOMM
> +    select RT500_CLKCTL0
> +    select RT500_CLKCTL1
> +    select FLEXSPI
> +    select RT500_RSTCTL
> diff --git a/hw/arm/meson.build b/hw/arm/meson.build
> index eb604d00cf..7d827d512c 100644
> --- a/hw/arm/meson.build
> +++ b/hw/arm/meson.build
> @@ -59,6 +59,7 @@ arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmuv3.c'))
>   arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c'))
>   arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c'))
>   arm_ss.add(when: 'CONFIG_XEN', if_true: files('xen_arm.c'))
> +arm_ss.add(when: 'CONFIG_RT500', if_true: files('rt500.c'))
>   
>   system_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c'))
>   system_ss.add(when: 'CONFIG_CHEETAH', if_true: files('palm.c'))
> diff --git a/hw/arm/rt500.c b/hw/arm/rt500.c
> new file mode 100644
> index 0000000000..0866ef3ef6
> --- /dev/null
> +++ b/hw/arm/rt500.c
> @@ -0,0 +1,348 @@
> +/*
> + * i.MX RT500 platforms.
> + *
> + * Copyright (c) 2024 Google LLC
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "hw/sysbus.h"
> +#include "hw/arm/boot.h"
> +#include "hw/boards.h"
> +#include "hw/irq.h"
> +#include "qemu/log.h"
> +#include "qemu/datadir.h"
> +#include "exec/address-spaces.h"
> +#include "sysemu/reset.h"
> +#include "sysemu/runstate.h"
> +#include "sysemu/sysemu.h"
> +#include "hw/arm/armv7m.h"
> +#include "hw/loader.h"
> +#include "hw/qdev-clock.h"
> +#include "hw/misc/unimp.h"
> +#include "hw/arm/rt500.h"
> +#include "hw/arm/svd/rt500.h"
> +
> +#define MMAP_SRAM_CODE_BASE   (0x0)
> +#define MMAP_SRAM_DATA_BASE   (0x20000000)
> +#define MMAP_SRAM_SIZE        (5 * MiB)
> +#define MMAP_BOOT_ROM_BASE    (0x03000000)
> +#define MMAP_BOOT_ROM_SIZE    (192 * KiB)
> +#define MMAP_SDMA_RAM_BASE    (0x24100000)
> +#define MMAP_SDMA_RAM_SIZE    (32 * KiB)
> +#define MMAP_FLEXSPI0_BASE    (0x08000000)
> +#define MMAP_FLEXSPI0_SIZE    (128 * MiB)
> +#define MMAP_FLEXSPI1_BASE    (0x28000000)
> +#define MMAP_FLEXSPI1_SIZE    (128 * MiB)
> +
> +#define SECURE_OFFSET    (0x10000000)
> +
> +typedef enum MemInfoType {
> +    MEM_RAM,
> +    MEM_ROM,
> +    MEM_ALIAS
> +} MemInfoType;
> +
> +static void do_sys_reset(void *opaque, int n, int level)
> +{
> +    if (level) {
> +        qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
> +    }
> +}
> +
> +static void rt500_init(Object *obj)
> +{
> +    RT500State *s = RT500(obj);
> +    int i;
> +
> +    /* Add ARMv7-M device */
> +    object_initialize_child(obj, "armv7m", &s->armv7m, TYPE_ARMV7M);
> +
> +    for (i = 0; i < RT500_FLEXCOMM_NUM; i++) {
> +        char id[] = "flexcommXX";
> +
> +        snprintf(id, sizeof(id), "flexcomm%d", i);
> +        object_initialize_child(obj, id, &s->flexcomm[i], TYPE_FLEXCOMM);
> +        DEVICE(&s->flexcomm[i])->id = g_strdup(id);

Directly g_strdup_printf().

> +    }
> +
> +    object_initialize_child(obj, "clkctl0", &s->clkctl0, TYPE_RT500_CLKCTL0);
> +    object_initialize_child(obj, "clkctl1", &s->clkctl1, TYPE_RT500_CLKCTL1);
> +
> +    /* Initialize clocks */
> +    s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0);
> +    s->refclk = qdev_init_clock_in(DEVICE(s), "refclk", NULL, NULL, 0);
> +
> +    for (i = 0; i < RT500_FLEXSPI_NUM; i++) {
> +        char id[] = "flexspiXX";
> +
> +        snprintf(id, sizeof(id), "flexspi%d", i);
> +        object_initialize_child(obj, id, &s->flexspi[i], TYPE_FLEXSPI);
> +        DEVICE(&s->flexspi[i])->id = g_strdup(id);
> +    }
> +
> +    for (i = 0; i < RT500_RSTCTL_NUM; i++) {
> +        char id[] = "rstctlX";
> +
> +        snprintf(id, sizeof(id), "rstctl%d", i);
> +        object_initialize_child(obj, id, &s->rstctl[i],
> +                                TYPE_RT500_RSTCTL);
> +        DEVICE(&s->rstctl[i])->id = g_strdup(id);
> +    }
> +}
> +
> +static void rt500_realize_memory(RT500State *s, Error **errp)
> +{

static

> +    const struct {
> +        const char *name;
> +        hwaddr base;
> +        size_t size;
> +        MemInfoType type;
> +        int alias_for;
> +    } mem_info[] = {
> +        {
> +            .name = "SRAM (code bus)",
> +            .base = MMAP_SRAM_CODE_BASE,
> +            .size = MMAP_SRAM_SIZE,
> +            .type = MEM_RAM,
> +        },
> +        {
> +            .name = "BOOT-ROM",
> +            .base = MMAP_BOOT_ROM_BASE,
> +            .size = MMAP_BOOT_ROM_SIZE,
> +            .type = MEM_ROM,
> +        },
> +        {
> +            .name = "Smart DMA RAM",
> +            .base = MMAP_SDMA_RAM_BASE,
> +            .size = MMAP_SDMA_RAM_SIZE,
> +            .type = MEM_RAM,
> +        },
> +        {
> +            .name = "SRAM (data bus)",
> +            .base = MMAP_SRAM_DATA_BASE,
> +            .size = MMAP_SRAM_SIZE,
> +            .type = MEM_ALIAS,
> +            .alias_for = 0
> +        },
> +    };
> +    int i;
> +
> +    s->mem = g_malloc_n(2 * ARRAY_SIZE(mem_info), sizeof(MemoryRegion));
> +    for (i = 0; i < ARRAY_SIZE(mem_info); i++) {
> +        const char *name = mem_info[i].name;
> +        int size = mem_info[i].size;
> +        int type = mem_info[i].type;
> +        int alias_for = mem_info[i].alias_for;
> +        MemoryRegion *mem = &s->mem[i];
> +        uint32_t base = mem_info[i].base;
> +        MemoryRegion *sec_mem;
> +        char sec_name[256];
> +
> +        switch (type) {
> +        case MEM_RAM:
> +            memory_region_init_ram(mem, OBJECT(s), name, size, errp);
> +            break;
> +        case MEM_ROM:
> +            memory_region_init_rom(mem, OBJECT(s), name, size, errp);
> +            break;
> +        case MEM_ALIAS:
> +        {
> +            MemoryRegion *orig = &s->mem[alias_for];
> +
> +            memory_region_init_alias(mem, OBJECT(s), name, orig, 0, size);
> +            break;
> +        }
> +        default:
> +            g_assert_not_reached();
> +        }
> +
> +        memory_region_add_subregion(get_system_memory(), base, mem);
> +
> +        /* create secure alias */
> +        snprintf(sec_name, sizeof(sec_name), "SECURE %s", name);
> +        sec_mem = &s->mem[ARRAY_SIZE(mem_info) + i];
> +        if (type == MEM_ALIAS) {
> +            mem = &s->mem[alias_for];
> +        }
> +        memory_region_init_alias(sec_mem, OBJECT(s), sec_name, mem, 0, size);
> +        memory_region_add_subregion(get_system_memory(), base + SECURE_OFFSET,
> +                                    sec_mem);
> +
> +        if (mem_info[i].type == MEM_ROM) {
> +            char *fname = qemu_find_file(QEMU_FILE_TYPE_BIOS, "rt500.rom");
> +
> +            if (fname) {
> +                int fsize = get_image_size(fname);
> +                int ret;
> +
> +                if (fsize > size) {
> +                    error_setg(errp, "rom file too big: %d > %d", fsize, size);
> +                } else {
> +                    ret = load_image_targphys(fname, base, size);
> +                    if (ret < 0) {
> +                        error_setg(errp, "could not load rom: %s", fname);
> +                    }
> +                }
> +            }
> +            g_free(fname);
> +        }
> +    }
> +}
> +
> +static void rt500_realize(DeviceState *dev, Error **errp)
> +{
> +    MachineState *ms = MACHINE(qdev_get_machine());
> +    RT500State *s = RT500(dev);
> +    int i;

Preferably reduce iterator variables scope.

> +
> +    rt500_realize_memory(s, errp);
> +
> +    /* Setup ARMv7M CPU */
> +    qdev_prop_set_uint32(DEVICE(&s->armv7m), "num-irq",
> +                         RT500_FLEXCOMM16_IRQn + 1);

Preferably a definition:

#define RT500_NUM_IRQ (RT500_FLEXCOMM16_IRQn + 1)

> +    qdev_prop_set_uint8(DEVICE(&s->armv7m), "num-prio-bits", 3);
> +    qdev_prop_set_string(DEVICE(&s->armv7m), "cpu-type", ms->cpu_type);

Do you plan to add RT500 machines not based on the Cortex-M33?
Otherwise simpler to hardcode the CPU type here.

> +    object_property_set_link(OBJECT(&s->armv7m), "memory",
> +                             OBJECT(get_system_memory()), &error_abort);
> +    if (!ms->kernel_filename) {
> +        qdev_prop_set_uint32(DEVICE(&s->armv7m), "init-nsvtor",
> +                             MMAP_BOOT_ROM_BASE);
> +        qdev_prop_set_uint32(DEVICE(&s->armv7m), "init-svtor",
> +                             MMAP_BOOT_ROM_BASE + SECURE_OFFSET);
> +    }
> +
> +    qdev_connect_clock_in(DEVICE(&s->armv7m), "cpuclk", s->sysclk);
> +    qdev_connect_clock_in(DEVICE(&s->armv7m), "refclk",
> +                     qdev_get_clock_out(DEVICE(&s->clkctl0), "systick_clk"));
> +
> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(&s->armv7m), errp);
> +    qdev_connect_gpio_out_named(DEVICE(&s->armv7m), "SYSRESETREQ", 0,
> +                                qemu_allocate_irq(&do_sys_reset, NULL, 0));
> +
> +    /* Setup FLEXCOMM */
> +    for (i = 0; i < RT500_FLEXCOMM_NUM; i++) {
> +        const uint32_t addr[] = {

static

> +            RT500_FLEXCOMM0_BASE, RT500_FLEXCOMM1_BASE, RT500_FLEXCOMM2_BASE,
> +            RT500_FLEXCOMM3_BASE, RT500_FLEXCOMM4_BASE, RT500_FLEXCOMM5_BASE,
> +            RT500_FLEXCOMM6_BASE, RT500_FLEXCOMM7_BASE, RT500_FLEXCOMM8_BASE,
> +            RT500_FLEXCOMM8_BASE, RT500_FLEXCOMM10_BASE, RT500_FLEXCOMM11_BASE,
> +            RT500_FLEXCOMM12_BASE, RT500_FLEXCOMM13_BASE, RT500_FLEXCOMM14_BASE,
> +            RT500_FLEXCOMM15_BASE, RT500_FLEXCOMM16_BASE
> +        };
> +        const int irq[] = {
> +            RT500_FLEXCOMM0_IRQn, RT500_FLEXCOMM1_IRQn, RT500_FLEXCOMM2_IRQn,
> +            RT500_FLEXCOMM3_IRQn, RT500_FLEXCOMM4_IRQn, RT500_FLEXCOMM5_IRQn,
> +            RT500_FLEXCOMM6_IRQn, RT500_FLEXCOMM7_IRQn, RT500_FLEXCOMM8_IRQn,
> +            RT500_FLEXCOMM9_IRQn, RT500_FLEXCOMM10_IRQn, RT500_FLEXCOMM11_IRQn,
> +            RT500_FLEXCOMM12_IRQn, RT500_FLEXCOMM13_IRQn, RT500_FLEXCOMM14_IRQn,
> +            RT500_FLEXCOMM15_IRQn, RT500_FLEXCOMM16_IRQn
> +        };
> +        const int functions[] = {
> +            FLEXCOMM_FULL, FLEXCOMM_FULL, FLEXCOMM_FULL,
> +            FLEXCOMM_FULL, FLEXCOMM_FULL, FLEXCOMM_FULL,
> +            FLEXCOMM_FULL, FLEXCOMM_FULL, FLEXCOMM_FULL,
> +            FLEXCOMM_FULL, FLEXCOMM_FULL, FLEXCOMM_FULL,
> +            FLEXCOMM_FULL, FLEXCOMM_FULL, FLEXCOMM_HSSPI,
> +            FLEXCOMM_PMICI2C, FLEXCOMM_HSSPI
> +        };
> +        DeviceState *ds = DEVICE(&s->flexcomm[i]);
> +        char id[] = "flexcommXX";
> +
> +        snprintf(id, sizeof(id), "flexcomm%d", i);
> +        qdev_prop_set_uint32(ds, "functions", functions[i]);
> +        qdev_prop_set_chr(ds, "chardev", qemu_chr_find(id));
> +        sysbus_realize_and_unref(SYS_BUS_DEVICE(ds), errp);
> +        sysbus_mmio_map(SYS_BUS_DEVICE(ds), 0, addr[i]);
> +        sysbus_connect_irq(SYS_BUS_DEVICE(ds), 0,
> +                           qdev_get_gpio_in(DEVICE(&s->armv7m), irq[i]));
> +    }
> +
> +    /* Setup CTLCTL0 */
> +    qdev_connect_clock_in(DEVICE(&s->clkctl0), "sysclk", s->sysclk);
> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(DEVICE(&s->clkctl0)), errp);
> +    sysbus_mmio_map(SYS_BUS_DEVICE(DEVICE(&s->clkctl0)), 0, RT500_CLKCTL0_BASE);
> +
> +    /* Setup CTLCTL1 */
> +    qdev_connect_clock_in(DEVICE(&s->clkctl1), "sysclk", s->sysclk);
> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(DEVICE(&s->clkctl1)), errp);
> +    sysbus_mmio_map(SYS_BUS_DEVICE(DEVICE(&s->clkctl1)), 0, RT500_CLKCTL1_BASE);
> +
> +    /* Setup FlexSPI */
> +    for (i = 0; i < RT500_FLEXSPI_NUM; i++) {
> +        const uint32_t addr[] = {

static

> +            RT500_FLEXSPI0_BASE, RT500_FLEXSPI1_BASE
> +        };
> +        const uint32_t mmap_base[] = {
> +            MMAP_FLEXSPI0_BASE, MMAP_FLEXSPI1_BASE
> +        };
> +        const uint32_t mmap_size[] = {
> +            MMAP_FLEXSPI0_SIZE, MMAP_FLEXSPI1_SIZE,
> +        };
> +        DeviceState *ds = DEVICE(&s->flexspi[i]);
> +
> +        qdev_prop_set_uint32(ds, "mmap_base", mmap_base[i]);
> +        qdev_prop_set_uint32(ds, "mmap_size", mmap_size[i]);
> +        sysbus_realize_and_unref(SYS_BUS_DEVICE(ds), errp);
> +        sysbus_mmio_map(SYS_BUS_DEVICE(ds), 0, addr[i]);
> +    }
> +
> +    /* Setup reset controllers */
> +    for (i = 0; i < RT500_RSTCTL_NUM; i++) {
> +        DeviceState *ds = DEVICE(&s->rstctl[i]);
> +
> +        const uint32_t addr[] = {

static

> +            RT500_RSTCTL0_BASE, RT500_RSTCTL1_BASE
> +        };
> +
> +        qdev_prop_set_uint32(ds, "num", i);
> +        sysbus_realize_and_unref(SYS_BUS_DEVICE(ds), errp);
> +        sysbus_mmio_map(SYS_BUS_DEVICE(ds), 0, addr[i]);
> +    }
> +}
> +
> +static void rt500_finalize(Object *obj)
> +{
> +    RT500State *s = RT500(obj);
> +
> +    g_free(s->mem);

Allocated via rt500_realize() -> rt500_realize_memory() so
to be released in a DeviceUnrealize() handler.

> +}
> +
> +static void rt500_reset(DeviceState *ds)
> +{
> +}
> +
> +static Property rt500_properties[] = {

To be filled later?

> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void rt500_class_init(ObjectClass *oc, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(oc);
> +
> +    device_class_set_props(dc, rt500_properties);
> +    dc->realize = rt500_realize;
> +    dc->desc = "RT500 (ARM Cortex-M33)";
> +    dc->reset = rt500_reset;
> +}
> +
> +static const TypeInfo rt500_type_info = {
> +    .name = TYPE_RT500,
> +    .parent = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(RT500State),
> +    .instance_init = rt500_init,
> +    .instance_finalize = rt500_finalize,
> +    .class_init = rt500_class_init,
> +};
> +
> +static void rt500_register_types(void)
> +{
> +    type_register_static(&rt500_type_info);

Preferably use the DEFINE_TYPES() macro.

> +}
> +
> +type_init(rt500_register_types)
> diff --git a/hw/arm/svd/meson.build b/hw/arm/svd/meson.build
> index 72a7421c6f..930a8b7343 100644
> --- a/hw/arm/svd/meson.build
> +++ b/hw/arm/svd/meson.build
> @@ -34,3 +34,9 @@ genh += custom_target('rt500_rstctl1.h',
>                         output: 'rt500_rstctl1.h',
>                         input: 'MIMXRT595S_cm33.xml',
>                         command: [ svd_gen_header, '-i', '@INPUT@', '-o', '@OUTPUT@', '-p', 'RSTCTL1', '-t', 'RT500_RSTCTL1'])
> +genh += custom_target('rt500.h',
> +                      output: 'rt500.h',
> +                      input: 'MIMXRT595S_cm33.xml',
> +                      command: [ svd_gen_header,'-i', '@INPUT@', '-o', '@OUTPUT@', '-s', 'RT500',
> +		                 '-p', 'FLEXCOMM0', '-p', 'CLKCTL0', '-p', 'CLKCTL1',
> +				 '-p', 'FLEXSPI0', '-p', 'FLEXSPI1', '-p', 'RSTCTL0', '-p', 'RSTCTL1'])
> diff --git a/include/hw/arm/rt500.h b/include/hw/arm/rt500.h
> new file mode 100644
> index 0000000000..8ca7972f8a
> --- /dev/null
> +++ b/include/hw/arm/rt500.h
> @@ -0,0 +1,49 @@
> +/*
> + * i.MX RT500 platforms.
> + *
> + * Copyright (c) 2024 Google LLC
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * Contributions after 2012-01-13 are licensed under the terms of the
> + * GNU GPL, version 2 or (at your option) any later version.
> + */
> +
> +#ifndef HW_ARM_RT500_H
> +#define HW_ARM_RT500_H
> +
> +#include "qemu/osdep.h"

No osdep.h in header.

> +#include "qemu/units.h"

Not used (move to source).

> +#include "hw/arm/boot.h"

Not used.

> +#include "hw/arm/armv7m.h"
> +#include "hw/misc/flexcomm.h"
> +#include "hw/misc/rt500_clkctl0.h"
> +#include "hw/misc/rt500_clkctl1.h"
> +#include "hw/ssi/flexspi.h"
> +#include "hw/misc/rt500_rstctl.h"
> +
> +#define TYPE_RT500 "rt500"
> +#define RT500(obj) OBJECT_CHECK(RT500State, (obj), TYPE_RT500)
> +
> +#define RT500_FLEXCOMM_NUM (17)
> +#define RT500_FLEXSPI_NUM (2)
> +#define RT500_RSTCTL_NUM (2)
> +
> +typedef struct RT500State {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/

Please drop private/public comments.

> +    ARMv7MState armv7m;
> +    MemoryRegion *mem;
> +    FlexcommState flexcomm[RT500_FLEXCOMM_NUM];
> +    RT500ClkCtl0State clkctl0;
> +    RT500ClkCtl1State clkctl1;
> +    FlexSpiState flexspi[RT500_FLEXSPI_NUM];
> +    RT500RstCtlState rstctl[RT500_RSTCTL_NUM];
> +
> +    Clock *sysclk;
> +    Clock *refclk;
> +} RT500State;
> +
> +#endif /* HW_ARM_RT500_H */

LGTM,

Phil.
Re: [RFC PATCH 22/23] hw/arm: add basic support for the RT500 SoC
Posted by Octavian Purdila 3 months, 2 weeks ago
On Tue, Aug 6, 2024 at 7:51 AM Philippe Mathieu-Daudé <philmd@linaro.org> wrote:
>
> Hi Octavian,
>
> Few comments inlined.
>

Hi Philippe,

Thank you for the review!

I have queued fixes for all of the patches in the set where
applicable, I'll wait for more feedback on the rest of the patches
before sending v2.