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 <ta...@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.