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
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.
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.
© 2016 - 2026 Red Hat, Inc.