summaryrefslogtreecommitdiffstats
path: root/hw/arm
diff options
context:
space:
mode:
Diffstat (limited to 'hw/arm')
-rw-r--r--hw/arm/Kconfig10
-rw-r--r--hw/arm/armsse.c944
-rw-r--r--hw/arm/mps2-tz.c168
-rw-r--r--hw/arm/xlnx-zynqmp.c21
4 files changed, 906 insertions, 237 deletions
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 4e6f4ffe90..8c37cf00da 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -353,6 +353,7 @@ config XLNX_ZYNQMP_ARM
select SSI_M25P80
select XILINX_AXI
select XILINX_SPIPS
+ select XLNX_CSU_DMA
select XLNX_ZYNQMP
select XLNX_ZDMA
@@ -505,6 +506,7 @@ config ARM11MPCORE
config ARMSSE
bool
select ARM_V7M
+ select ARMSSE_CPU_PWRCTRL
select ARMSSE_CPUID
select ARMSSE_MHU
select CMSDK_APB_TIMER
@@ -520,9 +522,5 @@ config ARMSSE
select TZ_MSC
select TZ_PPC
select UNIMP
-
-config ARMSSE_CPUID
- bool
-
-config ARMSSE_MHU
- bool
+ select SSE_COUNTER
+ select SSE_TIMER
diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c
index 26e1a8c95b..e5aeb9e485 100644
--- a/hw/arm/armsse.c
+++ b/hw/arm/armsse.c
@@ -19,29 +19,58 @@
#include "migration/vmstate.h"
#include "hw/registerfields.h"
#include "hw/arm/armsse.h"
+#include "hw/arm/armsse-version.h"
#include "hw/arm/boot.h"
#include "hw/irq.h"
#include "hw/qdev-clock.h"
-/* Format of the System Information block SYS_CONFIG register */
-typedef enum SysConfigFormat {
- IoTKitFormat,
- SSE200Format,
-} SysConfigFormat;
+/*
+ * The SSE-300 puts some devices in different places to the
+ * SSE-200 (and original IoTKit). We use an array of these structs
+ * to define how each variant lays out these devices. (Parts of the
+ * SoC that are the same for all variants aren't handled via these
+ * data structures.)
+ */
+
+#define NO_IRQ -1
+#define NO_PPC -1
+/*
+ * Special values for ARMSSEDeviceInfo::irq to indicate that this
+ * device uses one of the inputs to the OR gate that feeds into the
+ * CPU NMI input.
+ */
+#define NMI_0 10000
+#define NMI_1 10001
+
+typedef struct ARMSSEDeviceInfo {
+ const char *name; /* name to use for the QOM object; NULL terminates list */
+ const char *type; /* QOM type name */
+ unsigned int index; /* Which of the N devices of this type is this ? */
+ hwaddr addr;
+ hwaddr size; /* only needed for TYPE_UNIMPLEMENTED_DEVICE */
+ int ppc; /* Index of APB PPC this device is wired up to, or NO_PPC */
+ int ppc_port; /* Port number of this device on the PPC */
+ int irq; /* NO_IRQ, or 0..NUM_SSE_IRQS-1, or NMI_0 or NMI_1 */
+ bool slowclk; /* true if device uses the slow 32KHz clock */
+} ARMSSEDeviceInfo;
struct ARMSSEInfo {
const char *name;
+ uint32_t sse_version;
int sram_banks;
int num_cpus;
uint32_t sys_version;
+ uint32_t iidr;
uint32_t cpuwait_rst;
- SysConfigFormat sys_config_format;
bool has_mhus;
- bool has_ppus;
bool has_cachectrl;
bool has_cpusecctrl;
bool has_cpuid;
+ bool has_cpu_pwrctrl;
+ bool has_sse_counter;
Property *props;
+ const ARMSSEDeviceInfo *devinfo;
+ const bool *irq_is_common;
};
static Property iotkit_properties[] = {
@@ -68,34 +97,449 @@ static Property armsse_properties[] = {
DEFINE_PROP_END_OF_LIST()
};
+static const ARMSSEDeviceInfo iotkit_devices[] = {
+ {
+ .name = "timer0",
+ .type = TYPE_CMSDK_APB_TIMER,
+ .index = 0,
+ .addr = 0x40000000,
+ .ppc = 0,
+ .ppc_port = 0,
+ .irq = 3,
+ },
+ {
+ .name = "timer1",
+ .type = TYPE_CMSDK_APB_TIMER,
+ .index = 1,
+ .addr = 0x40001000,
+ .ppc = 0,
+ .ppc_port = 1,
+ .irq = 4,
+ },
+ {
+ .name = "s32ktimer",
+ .type = TYPE_CMSDK_APB_TIMER,
+ .index = 2,
+ .addr = 0x4002f000,
+ .ppc = 1,
+ .ppc_port = 0,
+ .irq = 2,
+ .slowclk = true,
+ },
+ {
+ .name = "dualtimer",
+ .type = TYPE_CMSDK_APB_DUALTIMER,
+ .index = 0,
+ .addr = 0x40002000,
+ .ppc = 0,
+ .ppc_port = 2,
+ .irq = 5,
+ },
+ {
+ .name = "s32kwatchdog",
+ .type = TYPE_CMSDK_APB_WATCHDOG,
+ .index = 0,
+ .addr = 0x5002e000,
+ .ppc = NO_PPC,
+ .irq = NMI_0,
+ .slowclk = true,
+ },
+ {
+ .name = "nswatchdog",
+ .type = TYPE_CMSDK_APB_WATCHDOG,
+ .index = 1,
+ .addr = 0x40081000,
+ .ppc = NO_PPC,
+ .irq = 1,
+ },
+ {
+ .name = "swatchdog",
+ .type = TYPE_CMSDK_APB_WATCHDOG,
+ .index = 2,
+ .addr = 0x50081000,
+ .ppc = NO_PPC,
+ .irq = NMI_1,
+ },
+ {
+ .name = "armsse-sysinfo",
+ .type = TYPE_IOTKIT_SYSINFO,
+ .index = 0,
+ .addr = 0x40020000,
+ .ppc = NO_PPC,
+ .irq = NO_IRQ,
+ },
+ {
+ .name = "armsse-sysctl",
+ .type = TYPE_IOTKIT_SYSCTL,
+ .index = 0,
+ .addr = 0x50021000,
+ .ppc = NO_PPC,
+ .irq = NO_IRQ,
+ },
+ {
+ .name = NULL,
+ }
+};
+
+static const ARMSSEDeviceInfo sse200_devices[] = {
+ {
+ .name = "timer0",
+ .type = TYPE_CMSDK_APB_TIMER,
+ .index = 0,
+ .addr = 0x40000000,
+ .ppc = 0,
+ .ppc_port = 0,
+ .irq = 3,
+ },
+ {
+ .name = "timer1",
+ .type = TYPE_CMSDK_APB_TIMER,
+ .index = 1,
+ .addr = 0x40001000,
+ .ppc = 0,
+ .ppc_port = 1,
+ .irq = 4,
+ },
+ {
+ .name = "s32ktimer",
+ .type = TYPE_CMSDK_APB_TIMER,
+ .index = 2,
+ .addr = 0x4002f000,
+ .ppc = 1,
+ .ppc_port = 0,
+ .irq = 2,
+ .slowclk = true,
+ },
+ {
+ .name = "dualtimer",
+ .type = TYPE_CMSDK_APB_DUALTIMER,
+ .index = 0,
+ .addr = 0x40002000,
+ .ppc = 0,
+ .ppc_port = 2,
+ .irq = 5,
+ },
+ {
+ .name = "s32kwatchdog",
+ .type = TYPE_CMSDK_APB_WATCHDOG,
+ .index = 0,
+ .addr = 0x5002e000,
+ .ppc = NO_PPC,
+ .irq = NMI_0,
+ .slowclk = true,
+ },
+ {
+ .name = "nswatchdog",
+ .type = TYPE_CMSDK_APB_WATCHDOG,
+ .index = 1,
+ .addr = 0x40081000,
+ .ppc = NO_PPC,
+ .irq = 1,
+ },
+ {
+ .name = "swatchdog",
+ .type = TYPE_CMSDK_APB_WATCHDOG,
+ .index = 2,
+ .addr = 0x50081000,
+ .ppc = NO_PPC,
+ .irq = NMI_1,
+ },
+ {
+ .name = "armsse-sysinfo",
+ .type = TYPE_IOTKIT_SYSINFO,
+ .index = 0,
+ .addr = 0x40020000,
+ .ppc = NO_PPC,
+ .irq = NO_IRQ,
+ },
+ {
+ .name = "armsse-sysctl",
+ .type = TYPE_IOTKIT_SYSCTL,
+ .index = 0,
+ .addr = 0x50021000,
+ .ppc = NO_PPC,
+ .irq = NO_IRQ,
+ },
+ {
+ .name = "CPU0CORE_PPU",
+ .type = TYPE_UNIMPLEMENTED_DEVICE,
+ .index = 0,
+ .addr = 0x50023000,
+ .size = 0x1000,
+ .ppc = NO_PPC,
+ .irq = NO_IRQ,
+ },
+ {
+ .name = "CPU1CORE_PPU",
+ .type = TYPE_UNIMPLEMENTED_DEVICE,
+ .index = 1,
+ .addr = 0x50025000,
+ .size = 0x1000,
+ .ppc = NO_PPC,
+ .irq = NO_IRQ,
+ },
+ {
+ .name = "DBG_PPU",
+ .type = TYPE_UNIMPLEMENTED_DEVICE,
+ .index = 2,
+ .addr = 0x50029000,
+ .size = 0x1000,
+ .ppc = NO_PPC,
+ .irq = NO_IRQ,
+ },
+ {
+ .name = "RAM0_PPU",
+ .type = TYPE_UNIMPLEMENTED_DEVICE,
+ .index = 3,
+ .addr = 0x5002a000,
+ .size = 0x1000,
+ .ppc = NO_PPC,
+ .irq = NO_IRQ,
+ },
+ {
+ .name = "RAM1_PPU",
+ .type = TYPE_UNIMPLEMENTED_DEVICE,
+ .index = 4,
+ .addr = 0x5002b000,
+ .size = 0x1000,
+ .ppc = NO_PPC,
+ .irq = NO_IRQ,
+ },
+ {
+ .name = "RAM2_PPU",
+ .type = TYPE_UNIMPLEMENTED_DEVICE,
+ .index = 5,
+ .addr = 0x5002c000,
+ .size = 0x1000,
+ .ppc = NO_PPC,
+ .irq = NO_IRQ,
+ },
+ {
+ .name = "RAM3_PPU",
+ .type = TYPE_UNIMPLEMENTED_DEVICE,
+ .index = 6,
+ .addr = 0x5002d000,
+ .size = 0x1000,
+ .ppc = NO_PPC,
+ .irq = NO_IRQ,
+ },
+ {
+ .name = "SYS_PPU",
+ .type = TYPE_UNIMPLEMENTED_DEVICE,
+ .index = 7,
+ .addr = 0x50022000,
+ .size = 0x1000,
+ .ppc = NO_PPC,
+ .irq = NO_IRQ,
+ },
+ {
+ .name = NULL,
+ }
+};
+
+static const ARMSSEDeviceInfo sse300_devices[] = {
+ {
+ .name = "timer0",
+ .type = TYPE_SSE_TIMER,
+ .index = 0,
+ .addr = 0x48000000,
+ .ppc = 0,
+ .ppc_port = 0,
+ .irq = 3,
+ },
+ {
+ .name = "timer1",
+ .type = TYPE_SSE_TIMER,
+ .index = 1,
+ .addr = 0x48001000,
+ .ppc = 0,
+ .ppc_port = 1,
+ .irq = 4,
+ },
+ {
+ .name = "timer2",
+ .type = TYPE_SSE_TIMER,
+ .index = 2,
+ .addr = 0x48002000,
+ .ppc = 0,
+ .ppc_port = 2,
+ .irq = 5,
+ },
+ {
+ .name = "timer3",
+ .type = TYPE_SSE_TIMER,
+ .index = 3,
+ .addr = 0x48003000,
+ .ppc = 0,
+ .ppc_port = 5,
+ .irq = 27,
+ },
+ {
+ .name = "s32ktimer",
+ .type = TYPE_CMSDK_APB_TIMER,
+ .index = 0,
+ .addr = 0x4802f000,
+ .ppc = 1,
+ .ppc_port = 0,
+ .irq = 2,
+ .slowclk = true,
+ },
+ {
+ .name = "s32kwatchdog",
+ .type = TYPE_CMSDK_APB_WATCHDOG,
+ .index = 0,
+ .addr = 0x4802e000,
+ .ppc = NO_PPC,
+ .irq = NMI_0,
+ .slowclk = true,
+ },
+ {
+ .name = "watchdog",
+ .type = TYPE_UNIMPLEMENTED_DEVICE,
+ .index = 0,
+ .addr = 0x48040000,
+ .size = 0x2000,
+ .ppc = NO_PPC,
+ .irq = NO_IRQ,
+ },
+ {
+ .name = "armsse-sysinfo",
+ .type = TYPE_IOTKIT_SYSINFO,
+ .index = 0,
+ .addr = 0x48020000,
+ .ppc = NO_PPC,
+ .irq = NO_IRQ,
+ },
+ {
+ .name = "armsse-sysctl",
+ .type = TYPE_IOTKIT_SYSCTL,
+ .index = 0,
+ .addr = 0x58021000,
+ .ppc = NO_PPC,
+ .irq = NO_IRQ,
+ },
+ {
+ .name = "SYS_PPU",
+ .type = TYPE_UNIMPLEMENTED_DEVICE,
+ .index = 1,
+ .addr = 0x58022000,
+ .size = 0x1000,
+ .ppc = NO_PPC,
+ .irq = NO_IRQ,
+ },
+ {
+ .name = "CPU0CORE_PPU",
+ .type = TYPE_UNIMPLEMENTED_DEVICE,
+ .index = 2,
+ .addr = 0x50023000,
+ .size = 0x1000,
+ .ppc = NO_PPC,
+ .irq = NO_IRQ,
+ },
+ {
+ .name = "MGMT_PPU",
+ .type = TYPE_UNIMPLEMENTED_DEVICE,
+ .index = 3,
+ .addr = 0x50028000,
+ .size = 0x1000,
+ .ppc = NO_PPC,
+ .irq = NO_IRQ,
+ },
+ {
+ .name = "DEBUG_PPU",
+ .type = TYPE_UNIMPLEMENTED_DEVICE,
+ .index = 4,
+ .addr = 0x50029000,
+ .size = 0x1000,
+ .ppc = NO_PPC,
+ .irq = NO_IRQ,
+ },
+ {
+ .name = NULL,
+ }
+};
+
+/* Is internal IRQ n shared between CPUs in a multi-core SSE ? */
+static const bool sse200_irq_is_common[32] = {
+ [0 ... 5] = true,
+ /* 6, 7: per-CPU MHU interrupts */
+ [8 ... 12] = true,
+ /* 13: per-CPU icache interrupt */
+ /* 14: reserved */
+ [15 ... 20] = true,
+ /* 21: reserved */
+ [22 ... 26] = true,
+ /* 27: reserved */
+ /* 28, 29: per-CPU CTI interrupts */
+ /* 30, 31: reserved */
+};
+
+static const bool sse300_irq_is_common[32] = {
+ [0 ... 5] = true,
+ /* 6, 7: per-CPU MHU interrupts */
+ [8 ... 12] = true,
+ /* 13: reserved */
+ [14 ... 16] = true,
+ /* 17-25: reserved */
+ [26 ... 27] = true,
+ /* 28, 29: per-CPU CTI interrupts */
+ /* 30, 31: reserved */
+};
+
static const ARMSSEInfo armsse_variants[] = {
{
.name = TYPE_IOTKIT,
+ .sse_version = ARMSSE_IOTKIT,
.sram_banks = 1,
.num_cpus = 1,
.sys_version = 0x41743,
+ .iidr = 0,
.cpuwait_rst = 0,
- .sys_config_format = IoTKitFormat,
.has_mhus = false,
- .has_ppus = false,
.has_cachectrl = false,
.has_cpusecctrl = false,
.has_cpuid = false,
+ .has_cpu_pwrctrl = false,
+ .has_sse_counter = false,
.props = iotkit_properties,
+ .devinfo = iotkit_devices,
+ .irq_is_common = sse200_irq_is_common,
},
{
.name = TYPE_SSE200,
+ .sse_version = ARMSSE_SSE200,
.sram_banks = 4,
.num_cpus = 2,
.sys_version = 0x22041743,
+ .iidr = 0,
.cpuwait_rst = 2,
- .sys_config_format = SSE200Format,
.has_mhus = true,
- .has_ppus = true,
.has_cachectrl = true,
.has_cpusecctrl = true,
.has_cpuid = true,
+ .has_cpu_pwrctrl = false,
+ .has_sse_counter = false,
+ .props = armsse_properties,
+ .devinfo = sse200_devices,
+ .irq_is_common = sse200_irq_is_common,
+ },
+ {
+ .name = TYPE_SSE300,
+ .sse_version = ARMSSE_SSE300,
+ .sram_banks = 2,
+ .num_cpus = 1,
+ .sys_version = 0x7e00043b,
+ .iidr = 0x74a0043b,
+ .cpuwait_rst = 0,
+ .has_mhus = false,
+ .has_cachectrl = false,
+ .has_cpusecctrl = true,
+ .has_cpuid = true,
+ .has_cpu_pwrctrl = true,
+ .has_sse_counter = true,
.props = armsse_properties,
+ .devinfo = sse300_devices,
+ .irq_is_common = sse300_irq_is_common,
},
};
@@ -104,13 +548,13 @@ static uint32_t armsse_sys_config_value(ARMSSE *s, const ARMSSEInfo *info)
/* Return the SYS_CONFIG value for this SSE */
uint32_t sys_config;
- switch (info->sys_config_format) {
- case IoTKitFormat:
+ switch (info->sse_version) {
+ case ARMSSE_IOTKIT:
sys_config = 0;
sys_config = deposit32(sys_config, 0, 4, info->sram_banks);
sys_config = deposit32(sys_config, 4, 4, s->sram_addr_width - 12);
break;
- case SSE200Format:
+ case ARMSSE_SSE200:
sys_config = 0;
sys_config = deposit32(sys_config, 0, 4, info->sram_banks);
sys_config = deposit32(sys_config, 4, 5, s->sram_addr_width);
@@ -121,6 +565,12 @@ static uint32_t armsse_sys_config_value(ARMSSE *s, const ARMSSEInfo *info)
sys_config = deposit32(sys_config, 28, 4, 2);
}
break;
+ case ARMSSE_SSE300:
+ sys_config = 0;
+ sys_config = deposit32(sys_config, 0, 4, info->sram_banks);
+ sys_config = deposit32(sys_config, 4, 5, s->sram_addr_width);
+ sys_config = deposit32(sys_config, 16, 3, 3); /* CPU0 = Cortex-M55 */
+ break;
default:
g_assert_not_reached();
}
@@ -130,21 +580,6 @@ static uint32_t armsse_sys_config_value(ARMSSE *s, const ARMSSEInfo *info)
/* Clock frequency in HZ of the 32KHz "slow clock" */
#define S32KCLK (32 * 1000)
-/* Is internal IRQ n shared between CPUs in a multi-core SSE ? */
-static bool irq_is_common[32] = {
- [0 ... 5] = true,
- /* 6, 7: per-CPU MHU interrupts */
- [8 ... 12] = true,
- /* 13: per-CPU icache interrupt */
- /* 14: reserved */
- [15 ... 20] = true,
- /* 21: reserved */
- [22 ... 26] = true,
- /* 27: reserved */
- /* 28, 29: per-CPU CTI interrupts */
- /* 30, 31: reserved */
-};
-
/*
* Create an alias region in @container of @size bytes starting at @base
* which mirrors the memory starting at @orig.
@@ -230,9 +665,10 @@ static void armsse_forward_sec_resp_cfg(ARMSSE *s)
qdev_connect_gpio_out(dev_splitter, 2, s->sec_resp_cfg_in);
}
-static void armsse_mainclk_update(void *opaque)
+static void armsse_mainclk_update(void *opaque, ClockEvent event)
{
ARMSSE *s = ARM_SSE(opaque);
+
/*
* Set system_clock_scale from our Clock input; this is what
* controls the tick rate of the CPU SysTick timer.
@@ -245,14 +681,15 @@ static void armsse_init(Object *obj)
ARMSSE *s = ARM_SSE(obj);
ARMSSEClass *asc = ARM_SSE_GET_CLASS(obj);
const ARMSSEInfo *info = asc->info;
+ const ARMSSEDeviceInfo *devinfo;
int i;
assert(info->sram_banks <= MAX_SRAM_BANKS);
assert(info->num_cpus <= SSE_MAX_CPUS);
s->mainclk = qdev_init_clock_in(DEVICE(s), "MAINCLK",
- armsse_mainclk_update, s);
- s->s32kclk = qdev_init_clock_in(DEVICE(s), "S32KCLK", NULL, NULL);
+ armsse_mainclk_update, s, ClockUpdate);
+ s->s32kclk = qdev_init_clock_in(DEVICE(s), "S32KCLK", NULL, NULL, 0);
memory_region_init(&s->container, obj, "armsse-container", UINT64_MAX);
@@ -285,9 +722,52 @@ static void armsse_init(Object *obj)
}
}
+ for (devinfo = info->devinfo; devinfo->name; devinfo++) {
+ assert(devinfo->ppc == NO_PPC || devinfo->ppc < ARRAY_SIZE(s->apb_ppc));
+ if (!strcmp(devinfo->type, TYPE_CMSDK_APB_TIMER)) {
+ assert(devinfo->index < ARRAY_SIZE(s->timer));
+ object_initialize_child(obj, devinfo->name,
+ &s->timer[devinfo->index],
+ TYPE_CMSDK_APB_TIMER);
+ } else if (!strcmp(devinfo->type, TYPE_CMSDK_APB_DUALTIMER)) {
+ assert(devinfo->index == 0);
+ object_initialize_child(obj, devinfo->name, &s->dualtimer,
+ TYPE_CMSDK_APB_DUALTIMER);
+ } else if (!strcmp(devinfo->type, TYPE_SSE_TIMER)) {
+ assert(devinfo->index < ARRAY_SIZE(s->sse_timer));
+ object_initialize_child(obj, devinfo->name,
+ &s->sse_timer[devinfo->index],
+ TYPE_SSE_TIMER);
+ } else if (!strcmp(devinfo->type, TYPE_CMSDK_APB_WATCHDOG)) {
+ assert(devinfo->index < ARRAY_SIZE(s->cmsdk_watchdog));
+ object_initialize_child(obj, devinfo->name,
+ &s->cmsdk_watchdog[devinfo->index],
+ TYPE_CMSDK_APB_WATCHDOG);
+ } else if (!strcmp(devinfo->type, TYPE_IOTKIT_SYSINFO)) {
+ assert(devinfo->index == 0);
+ object_initialize_child(obj, devinfo->name, &s->sysinfo,
+ TYPE_IOTKIT_SYSINFO);
+ } else if (!strcmp(devinfo->type, TYPE_IOTKIT_SYSCTL)) {
+ assert(devinfo->index == 0);
+ object_initialize_child(obj, devinfo->name, &s->sysctl,
+ TYPE_IOTKIT_SYSCTL);
+ } else if (!strcmp(devinfo->type, TYPE_UNIMPLEMENTED_DEVICE)) {
+ assert(devinfo->index < ARRAY_SIZE(s->unimp));
+ object_initialize_child(obj, devinfo->name,
+ &s->unimp[devinfo->index],
+ TYPE_UNIMPLEMENTED_DEVICE);
+ } else {
+ g_assert_not_reached();
+ }
+ }
+
object_initialize_child(obj, "secctl", &s->secctl, TYPE_IOTKIT_SECCTL);
- object_initialize_child(obj, "apb-ppc0", &s->apb_ppc0, TYPE_TZ_PPC);
- object_initialize_child(obj, "apb-ppc1", &s->apb_ppc1, TYPE_TZ_PPC);
+
+ for (i = 0; i < ARRAY_SIZE(s->apb_ppc); i++) {
+ g_autofree char *name = g_strdup_printf("apb-ppc%d", i);
+ object_initialize_child(obj, name, &s->apb_ppc[i], TYPE_TZ_PPC);
+ }
+
for (i = 0; i < info->sram_banks; i++) {
char *name = g_strdup_printf("mpc%d", i);
object_initialize_child(obj, name, &s->mpc[i], TYPE_TZ_MPC);
@@ -303,46 +783,11 @@ static void armsse_init(Object *obj)
object_initialize_child(obj, name, splitter, TYPE_SPLIT_IRQ);
g_free(name);
}
- object_initialize_child(obj, "timer0", &s->timer0, TYPE_CMSDK_APB_TIMER);
- object_initialize_child(obj, "timer1", &s->timer1, TYPE_CMSDK_APB_TIMER);
- object_initialize_child(obj, "s32ktimer", &s->s32ktimer,
- TYPE_CMSDK_APB_TIMER);
- object_initialize_child(obj, "dualtimer", &s->dualtimer,
- TYPE_CMSDK_APB_DUALTIMER);
- object_initialize_child(obj, "s32kwatchdog", &s->s32kwatchdog,
- TYPE_CMSDK_APB_WATCHDOG);
- object_initialize_child(obj, "nswatchdog", &s->nswatchdog,
- TYPE_CMSDK_APB_WATCHDOG);
- object_initialize_child(obj, "swatchdog", &s->swatchdog,
- TYPE_CMSDK_APB_WATCHDOG);
- object_initialize_child(obj, "armsse-sysctl", &s->sysctl,
- TYPE_IOTKIT_SYSCTL);
- object_initialize_child(obj, "armsse-sysinfo", &s->sysinfo,
- TYPE_IOTKIT_SYSINFO);
+
if (info->has_mhus) {
object_initialize_child(obj, "mhu0", &s->mhu[0], TYPE_ARMSSE_MHU);
object_initialize_child(obj, "mhu1", &s->mhu[1], TYPE_ARMSSE_MHU);
}
- if (info->has_ppus) {
- for (i = 0; i < info->num_cpus; i++) {
- char *name = g_strdup_printf("CPU%dCORE_PPU", i);
- int ppuidx = CPU0CORE_PPU + i;
-
- object_initialize_child(obj, name, &s->ppu[ppuidx],
- TYPE_UNIMPLEMENTED_DEVICE);
- g_free(name);
- }
- object_initialize_child(obj, "DBG_PPU", &s->ppu[DBG_PPU],
- TYPE_UNIMPLEMENTED_DEVICE);
- for (i = 0; i < info->sram_banks; i++) {
- char *name = g_strdup_printf("RAM%d_PPU", i);
- int ppuidx = RAM0_PPU + i;
-
- object_initialize_child(obj, name, &s->ppu[ppuidx],
- TYPE_UNIMPLEMENTED_DEVICE);
- g_free(name);
- }
- }
if (info->has_cachectrl) {
for (i = 0; i < info->num_cpus; i++) {
char *name = g_strdup_printf("cachectrl%d", i);
@@ -370,6 +815,20 @@ static void armsse_init(Object *obj)
g_free(name);
}
}
+ if (info->has_cpu_pwrctrl) {
+ for (i = 0; i < info->num_cpus; i++) {
+ char *name = g_strdup_printf("cpu_pwrctrl%d", i);
+
+ object_initialize_child(obj, name, &s->cpu_pwrctrl[i],
+ TYPE_ARMSSE_CPU_PWRCTRL);
+ g_free(name);
+ }
+ }
+ if (info->has_sse_counter) {
+ object_initialize_child(obj, "sse-counter", &s->sse_counter,
+ TYPE_SSE_COUNTER);
+ }
+
object_initialize_child(obj, "nmi-orgate", &s->nmi_orgate, TYPE_OR_IRQ);
object_initialize_child(obj, "ppc-irq-orgate", &s->ppc_irq_orgate,
TYPE_OR_IRQ);
@@ -384,7 +843,7 @@ static void armsse_init(Object *obj)
}
if (info->num_cpus > 1) {
for (i = 0; i < ARRAY_SIZE(s->cpu_irq_splitter); i++) {
- if (irq_is_common[i]) {
+ if (info->irq_is_common[i]) {
char *name = g_strdup_printf("cpu-irq-splitter%d", i);
SplitIRQ *splitter = &s->cpu_irq_splitter[i];
@@ -417,7 +876,7 @@ static qemu_irq armsse_get_common_irq_in(ARMSSE *s, int irqno)
ARMSSEClass *asc = ARM_SSE_GET_CLASS(s);
const ARMSSEInfo *info = asc->info;
- assert(irq_is_common[irqno]);
+ assert(info->irq_is_common[irqno]);
if (info->num_cpus == 1) {
/* Only one CPU -- just connect directly to it */
@@ -428,22 +887,12 @@ static qemu_irq armsse_get_common_irq_in(ARMSSE *s, int irqno)
}
}
-static void map_ppu(ARMSSE *s, int ppuidx, const char *name, hwaddr addr)
-{
- /* Map a PPU unimplemented device stub */
- DeviceState *dev = DEVICE(&s->ppu[ppuidx]);
-
- qdev_prop_set_string(dev, "name", name);
- qdev_prop_set_uint64(dev, "size", 0x1000);
- sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->ppu[ppuidx]), 0, addr);
-}
-
static void armsse_realize(DeviceState *dev, Error **errp)
{
ARMSSE *s = ARM_SSE(dev);
ARMSSEClass *asc = ARM_SSE_GET_CLASS(dev);
const ARMSSEInfo *info = asc->info;
+ const ARMSSEDeviceInfo *devinfo;
int i;
MemoryRegion *mr;
Error *err = NULL;
@@ -522,7 +971,7 @@ static void armsse_realize(DeviceState *dev, Error **errp)
int j;
char *gpioname;
- qdev_prop_set_uint32(cpudev, "num-irq", s->exp_numirq + 32);
+ qdev_prop_set_uint32(cpudev, "num-irq", s->exp_numirq + NUM_SSE_IRQS);
/*
* In real hardware the initial Secure VTOR is set from the INITSVTOR*
* registers in the IoT Kit System Control Register block. In QEMU
@@ -593,7 +1042,7 @@ static void armsse_realize(DeviceState *dev, Error **errp)
/* Connect EXP_IRQ/EXP_CPUn_IRQ GPIOs to the NVIC's lines 32 and up */
s->exp_irqs[i] = g_new(qemu_irq, s->exp_numirq);
for (j = 0; j < s->exp_numirq; j++) {
- s->exp_irqs[i][j] = qdev_get_gpio_in(cpudev, j + 32);
+ s->exp_irqs[i][j] = qdev_get_gpio_in(cpudev, j + NUM_SSE_IRQS);
}
if (i == 0) {
gpioname = g_strdup("EXP_IRQ");
@@ -609,7 +1058,7 @@ static void armsse_realize(DeviceState *dev, Error **errp)
/* Wire up the splitters that connect common IRQs to all CPUs */
if (info->num_cpus > 1) {
for (i = 0; i < ARRAY_SIZE(s->cpu_irq_splitter); i++) {
- if (irq_is_common[i]) {
+ if (info->irq_is_common[i]) {
Object *splitter = OBJECT(&s->cpu_irq_splitter[i]);
DeviceState *devs = DEVICE(splitter);
int cpunum;
@@ -649,6 +1098,8 @@ static void armsse_realize(DeviceState *dev, Error **errp)
}
/* Security controller */
+ object_property_set_int(OBJECT(&s->secctl), "sse-version",
+ info->sse_version, &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->secctl), errp)) {
return;
}
@@ -715,6 +1166,36 @@ static void armsse_realize(DeviceState *dev, Error **errp)
qdev_connect_gpio_out(DEVICE(&s->mpc_irq_orgate), 0,
armsse_get_common_irq_in(s, 9));
+ /* This OR gate wires together outputs from the secure watchdogs to NMI */
+ if (!object_property_set_int(OBJECT(&s->nmi_orgate), "num-lines", 2,
+ errp)) {
+ return;
+ }
+ if (!qdev_realize(DEVICE(&s->nmi_orgate), NULL, errp)) {
+ return;
+ }
+ qdev_connect_gpio_out(DEVICE(&s->nmi_orgate), 0,
+ qdev_get_gpio_in_named(DEVICE(&s->armv7m), "NMI", 0));
+
+ /* The SSE-300 has a System Counter / System Timestamp Generator */
+ if (info->has_sse_counter) {
+ SysBusDevice *sbd = SYS_BUS_DEVICE(&s->sse_counter);
+
+ qdev_connect_clock_in(DEVICE(sbd), "CLK", s->mainclk);
+ if (!sysbus_realize(sbd, errp)) {
+ return;
+ }
+ /*
+ * The control frame is only in the Secure region;
+ * the status frame is in the NS region (and visible in the
+ * S region via the alias mapping).
+ */
+ memory_region_add_subregion(&s->container, 0x58100000,
+ sysbus_mmio_get_region(sbd, 0));
+ memory_region_add_subregion(&s->container, 0x48101000,
+ sysbus_mmio_get_region(sbd, 1));
+ }
+
/* Devices behind APB PPC0:
* 0x40000000: timer0
* 0x40001000: timer1
@@ -725,35 +1206,127 @@ static void armsse_realize(DeviceState *dev, Error **errp)
* it to the appropriate PPC port; then we can realize the PPC and
* map its upstream ends to the right place in the container.
*/
- qdev_connect_clock_in(DEVICE(&s->timer0), "pclk", s->mainclk);
- if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer0), errp)) {
- return;
- }
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer0), 0,
- armsse_get_common_irq_in(s, 3));
- mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->timer0), 0);
- object_property_set_link(OBJECT(&s->apb_ppc0), "port[0]", OBJECT(mr),
- &error_abort);
-
- qdev_connect_clock_in(DEVICE(&s->timer1), "pclk", s->mainclk);
- if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer1), errp)) {
- return;
- }
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer1), 0,
- armsse_get_common_irq_in(s, 4));
- mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->timer1), 0);
- object_property_set_link(OBJECT(&s->apb_ppc0), "port[1]", OBJECT(mr),
- &error_abort);
-
- qdev_connect_clock_in(DEVICE(&s->dualtimer), "TIMCLK", s->mainclk);
- if (!sysbus_realize(SYS_BUS_DEVICE(&s->dualtimer), errp)) {
- return;
+ for (devinfo = info->devinfo; devinfo->name; devinfo++) {
+ SysBusDevice *sbd;
+ qemu_irq irq;
+
+ if (!strcmp(devinfo->type, TYPE_CMSDK_APB_TIMER)) {
+ sbd = SYS_BUS_DEVICE(&s->timer[devinfo->index]);
+
+ qdev_connect_clock_in(DEVICE(sbd), "pclk",
+ devinfo->slowclk ? s->s32kclk : s->mainclk);
+ if (!sysbus_realize(sbd, errp)) {
+ return;
+ }
+ mr = sysbus_mmio_get_region(sbd, 0);
+ } else if (!strcmp(devinfo->type, TYPE_CMSDK_APB_DUALTIMER)) {
+ sbd = SYS_BUS_DEVICE(&s->dualtimer);
+
+ qdev_connect_clock_in(DEVICE(sbd), "TIMCLK", s->mainclk);
+ if (!sysbus_realize(sbd, errp)) {
+ return;
+ }
+ mr = sysbus_mmio_get_region(sbd, 0);
+ } else if (!strcmp(devinfo->type, TYPE_SSE_TIMER)) {
+ sbd = SYS_BUS_DEVICE(&s->sse_timer[devinfo->index]);
+
+ assert(info->has_sse_counter);
+ object_property_set_link(OBJECT(sbd), "counter",
+ OBJECT(&s->sse_counter), &error_abort);
+ if (!sysbus_realize(sbd, errp)) {
+ return;
+ }
+ mr = sysbus_mmio_get_region(sbd, 0);
+ } else if (!strcmp(devinfo->type, TYPE_CMSDK_APB_WATCHDOG)) {
+ sbd = SYS_BUS_DEVICE(&s->cmsdk_watchdog[devinfo->index]);
+
+ qdev_connect_clock_in(DEVICE(sbd), "WDOGCLK",
+ devinfo->slowclk ? s->s32kclk : s->mainclk);
+ if (!sysbus_realize(sbd, errp)) {
+ return;
+ }
+ mr = sysbus_mmio_get_region(sbd, 0);
+ } else if (!strcmp(devinfo->type, TYPE_IOTKIT_SYSINFO)) {
+ sbd = SYS_BUS_DEVICE(&s->sysinfo);
+
+ object_property_set_int(OBJECT(&s->sysinfo), "SYS_VERSION",
+ info->sys_version, &error_abort);
+ object_property_set_int(OBJECT(&s->sysinfo), "SYS_CONFIG",
+ armsse_sys_config_value(s, info),
+ &error_abort);
+ object_property_set_int(OBJECT(&s->sysinfo), "sse-version",
+ info->sse_version, &error_abort);
+ object_property_set_int(OBJECT(&s->sysinfo), "IIDR",
+ info->iidr, &error_abort);
+ if (!sysbus_realize(sbd, errp)) {
+ return;
+ }
+ mr = sysbus_mmio_get_region(sbd, 0);
+ } else if (!strcmp(devinfo->type, TYPE_IOTKIT_SYSCTL)) {
+ /* System control registers */
+ sbd = SYS_BUS_DEVICE(&s->sysctl);
+
+ object_property_set_int(OBJECT(&s->sysctl), "sse-version",
+ info->sse_version, &error_abort);
+ object_property_set_int(OBJECT(&s->sysctl), "CPUWAIT_RST",
+ info->cpuwait_rst, &error_abort);
+ object_property_set_int(OBJECT(&s->sysctl), "INITSVTOR0_RST",
+ s->init_svtor, &error_abort);
+ object_property_set_int(OBJECT(&s->sysctl), "INITSVTOR1_RST",
+ s->init_svtor, &error_abort);
+ if (!sysbus_realize(sbd, errp)) {
+ return;
+ }
+ mr = sysbus_mmio_get_region(sbd, 0);
+ } else if (!strcmp(devinfo->type, TYPE_UNIMPLEMENTED_DEVICE)) {
+ sbd = SYS_BUS_DEVICE(&s->unimp[devinfo->index]);
+
+ qdev_prop_set_string(DEVICE(sbd), "name", devinfo->name);
+ qdev_prop_set_uint64(DEVICE(sbd), "size", devinfo->size);
+ if (!sysbus_realize(sbd, errp)) {
+ return;
+ }
+ mr = sysbus_mmio_get_region(sbd, 0);
+ } else {
+ g_assert_not_reached();
+ }
+
+ switch (devinfo->irq) {
+ case NO_IRQ:
+ irq = NULL;
+ break;
+ case 0 ... NUM_SSE_IRQS - 1:
+ irq = armsse_get_common_irq_in(s, devinfo->irq);
+ break;
+ case NMI_0:
+ case NMI_1:
+ irq = qdev_get_gpio_in(DEVICE(&s->nmi_orgate),
+ devinfo->irq - NMI_0);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (irq) {
+ sysbus_connect_irq(sbd, 0, irq);
+ }
+
+ /*
+ * Devices connected to a PPC are connected to the port here;
+ * we will map the upstream end of that port to the right address
+ * in the container later after the PPC has been realized.
+ * Devices not connected to a PPC can be mapped immediately.
+ */
+ if (devinfo->ppc != NO_PPC) {
+ TZPPC *ppc = &s->apb_ppc[devinfo->ppc];
+ g_autofree char *portname = g_strdup_printf("port[%d]",
+ devinfo->ppc_port);
+ object_property_set_link(OBJECT(ppc), portname, OBJECT(mr),
+ &error_abort);
+ } else {
+ memory_region_add_subregion(&s->container, devinfo->addr, mr);
+ }
}
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->dualtimer), 0,
- armsse_get_common_irq_in(s, 5));
- mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dualtimer), 0);
- object_property_set_link(OBJECT(&s->apb_ppc0), "port[2]", OBJECT(mr),
- &error_abort);
if (info->has_mhus) {
/*
@@ -775,7 +1348,7 @@ static void armsse_realize(DeviceState *dev, Error **errp)
}
port = g_strdup_printf("port[%d]", i + 3);
mr = sysbus_mmio_get_region(mhu_sbd, 0);
- object_property_set_link(OBJECT(&s->apb_ppc0), port, OBJECT(mr),
+ object_property_set_link(OBJECT(&s->apb_ppc[0]), port, OBJECT(mr),
&error_abort);
g_free(port);
@@ -795,19 +1368,13 @@ static void armsse_realize(DeviceState *dev, Error **errp)
}
}
- if (!sysbus_realize(SYS_BUS_DEVICE(&s->apb_ppc0), errp)) {
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->apb_ppc[0]), errp)) {
return;
}
- sbd_apb_ppc0 = SYS_BUS_DEVICE(&s->apb_ppc0);
- dev_apb_ppc0 = DEVICE(&s->apb_ppc0);
+ sbd_apb_ppc0 = SYS_BUS_DEVICE(&s->apb_ppc[0]);
+ dev_apb_ppc0 = DEVICE(&s->apb_ppc[0]);
- mr = sysbus_mmio_get_region(sbd_apb_ppc0, 0);
- memory_region_add_subregion(&s->container, 0x40000000, mr);
- mr = sysbus_mmio_get_region(sbd_apb_ppc0, 1);
- memory_region_add_subregion(&s->container, 0x40001000, mr);
- mr = sysbus_mmio_get_region(sbd_apb_ppc0, 2);
- memory_region_add_subregion(&s->container, 0x40002000, mr);
if (info->has_mhus) {
mr = sysbus_mmio_get_region(sbd_apb_ppc0, 3);
memory_region_add_subregion(&s->container, 0x40003000, mr);
@@ -852,6 +1419,8 @@ static void armsse_realize(DeviceState *dev, Error **errp)
* 0x50010000: L1 icache control registers
* 0x50011000: CPUSECCTRL (CPU local security control registers)
* 0x4001f000 and 0x5001f000: CPU_IDENTITY register block
+ * The SSE-300 has an extra:
+ * 0x40012000 and 0x50012000: CPU_PWRCTRL register block
*/
if (info->has_cachectrl) {
for (i = 0; i < info->num_cpus; i++) {
@@ -898,28 +1467,24 @@ static void armsse_realize(DeviceState *dev, Error **errp)
memory_region_add_subregion(&s->cpu_container[i], 0x4001F000, mr);
}
}
+ if (info->has_cpu_pwrctrl) {
+ for (i = 0; i < info->num_cpus; i++) {
+ MemoryRegion *mr;
- /* 0x40020000 .. 0x4002ffff : ARMSSE system control peripheral region */
- /* Devices behind APB PPC1:
- * 0x4002f000: S32K timer
- */
- qdev_connect_clock_in(DEVICE(&s->s32ktimer), "pclk", s->s32kclk);
- if (!sysbus_realize(SYS_BUS_DEVICE(&s->s32ktimer), errp)) {
- return;
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpu_pwrctrl[i]), errp)) {
+ return;
+ }
+
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cpu_pwrctrl[i]), 0);
+ memory_region_add_subregion(&s->cpu_container[i], 0x40012000, mr);
+ }
}
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->s32ktimer), 0,
- armsse_get_common_irq_in(s, 2));
- mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->s32ktimer), 0);
- object_property_set_link(OBJECT(&s->apb_ppc1), "port[0]", OBJECT(mr),
- &error_abort);
- if (!sysbus_realize(SYS_BUS_DEVICE(&s->apb_ppc1), errp)) {
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->apb_ppc[1]), errp)) {
return;
}
- mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->apb_ppc1), 0);
- memory_region_add_subregion(&s->container, 0x4002f000, mr);
- dev_apb_ppc1 = DEVICE(&s->apb_ppc1);
+ dev_apb_ppc1 = DEVICE(&s->apb_ppc[1]);
qdev_connect_gpio_out_named(dev_secctl, "apb_ppc1_nonsec", 0,
qdev_get_gpio_in_named(dev_apb_ppc1,
"cfg_nonsec", 0));
@@ -936,92 +1501,23 @@ static void armsse_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in_named(dev_apb_ppc1,
"cfg_sec_resp", 0));
- if (!object_property_set_int(OBJECT(&s->sysinfo), "SYS_VERSION",
- info->sys_version, errp)) {
- return;
- }
- if (!object_property_set_int(OBJECT(&s->sysinfo), "SYS_CONFIG",
- armsse_sys_config_value(s, info), errp)) {
- return;
- }
- if (!sysbus_realize(SYS_BUS_DEVICE(&s->sysinfo), errp)) {
- return;
- }
- /* System information registers */
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysinfo), 0, 0x40020000);
- /* System control registers */
- object_property_set_int(OBJECT(&s->sysctl), "SYS_VERSION",
- info->sys_version, &error_abort);
- object_property_set_int(OBJECT(&s->sysctl), "CPUWAIT_RST",
- info->cpuwait_rst, &error_abort);
- object_property_set_int(OBJECT(&s->sysctl), "INITSVTOR0_RST",
- s->init_svtor, &error_abort);
- object_property_set_int(OBJECT(&s->sysctl), "INITSVTOR1_RST",
- s->init_svtor, &error_abort);
- if (!sysbus_realize(SYS_BUS_DEVICE(&s->sysctl), errp)) {
- return;
- }
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysctl), 0, 0x50021000);
-
- if (info->has_ppus) {
- /* CPUnCORE_PPU for each CPU */
- for (i = 0; i < info->num_cpus; i++) {
- char *name = g_strdup_printf("CPU%dCORE_PPU", i);
-
- map_ppu(s, CPU0CORE_PPU + i, name, 0x50023000 + i * 0x2000);
- /*
- * We don't support CPU debug so don't create the
- * CPU0DEBUG_PPU at 0x50024000 and 0x50026000.
- */
- g_free(name);
- }
- map_ppu(s, DBG_PPU, "DBG_PPU", 0x50029000);
-
- for (i = 0; i < info->sram_banks; i++) {
- char *name = g_strdup_printf("RAM%d_PPU", i);
+ /*
+ * Now both PPCs are realized we can map the upstream ends of
+ * ports which correspond to entries in the devinfo array.
+ * The ports which are connected to non-devinfo devices have
+ * already been mapped.
+ */
+ for (devinfo = info->devinfo; devinfo->name; devinfo++) {
+ SysBusDevice *ppc_sbd;
- map_ppu(s, RAM0_PPU + i, name, 0x5002a000 + i * 0x1000);
- g_free(name);
+ if (devinfo->ppc == NO_PPC) {
+ continue;
}
+ ppc_sbd = SYS_BUS_DEVICE(&s->apb_ppc[devinfo->ppc]);
+ mr = sysbus_mmio_get_region(ppc_sbd, devinfo->ppc_port);
+ memory_region_add_subregion(&s->container, devinfo->addr, mr);
}
- /* This OR gate wires together outputs from the secure watchdogs to NMI */
- if (!object_property_set_int(OBJECT(&s->nmi_orgate), "num-lines", 2,
- errp)) {
- return;
- }
- if (!qdev_realize(DEVICE(&s->nmi_orgate), NULL, errp)) {
- return;
- }
- qdev_connect_gpio_out(DEVICE(&s->nmi_orgate), 0,
- qdev_get_gpio_in_named(DEVICE(&s->armv7m), "NMI", 0));
-
- qdev_connect_clock_in(DEVICE(&s->s32kwatchdog), "WDOGCLK", s->s32kclk);
- if (!sysbus_realize(SYS_BUS_DEVICE(&s->s32kwatchdog), errp)) {
- return;
- }
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->s32kwatchdog), 0,
- qdev_get_gpio_in(DEVICE(&s->nmi_orgate), 0));
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->s32kwatchdog), 0, 0x5002e000);
-
- /* 0x40080000 .. 0x4008ffff : ARMSSE second Base peripheral region */
-
- qdev_connect_clock_in(DEVICE(&s->nswatchdog), "WDOGCLK", s->mainclk);
- if (!sysbus_realize(SYS_BUS_DEVICE(&s->nswatchdog), errp)) {
- return;
- }
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->nswatchdog), 0,
- armsse_get_common_irq_in(s, 1));
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->nswatchdog), 0, 0x40081000);
-
- qdev_connect_clock_in(DEVICE(&s->swatchdog), "WDOGCLK", s->mainclk);
- if (!sysbus_realize(SYS_BUS_DEVICE(&s->swatchdog), errp)) {
- return;
- }
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->swatchdog), 0,
- qdev_get_gpio_in(DEVICE(&s->nmi_orgate), 1));
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->swatchdog), 0, 0x50081000);
-
for (i = 0; i < ARRAY_SIZE(s->ppc_irq_splitter); i++) {
Object *splitter = OBJECT(&s->ppc_irq_splitter[i]);
@@ -1052,7 +1548,7 @@ static void armsse_realize(DeviceState *dev, Error **errp)
DeviceState *devs = DEVICE(&s->ppc_irq_splitter[i]);
char *gpioname = g_strdup_printf("apb_ppc%d_irq_status",
i - NUM_EXTERNAL_PPCS);
- TZPPC *ppc = (i == NUM_EXTERNAL_PPCS) ? &s->apb_ppc0 : &s->apb_ppc1;
+ TZPPC *ppc = &s->apb_ppc[i - NUM_EXTERNAL_PPCS];
qdev_connect_gpio_out(devs, 0,
qdev_get_gpio_in_named(dev_secctl, gpioname, 0));
@@ -1120,7 +1616,7 @@ static void armsse_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->container);
/* Set initial system_clock_scale from MAINCLK */
- armsse_mainclk_update(s);
+ armsse_mainclk_update(s, ClockUpdate);
}
static void armsse_idau_check(IDAUInterface *ii, uint32_t address,
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
index 72da8cb1a1..3fbe3d29f9 100644
--- a/hw/arm/mps2-tz.c
+++ b/hw/arm/mps2-tz.c
@@ -17,6 +17,7 @@
* "mps2-an505" -- Cortex-M33 as documented in ARM Application Note AN505
* "mps2-an521" -- Dual Cortex-M33 as documented in Application Note AN521
* "mps2-an524" -- Dual Cortex-M33 as documented in Application Note AN524
+ * "mps2-an547" -- Single Cortex-M55 as documented in Application Note AN547
*
* Links to the TRM for the board itself and to the various Application
* Notes which document the FPGA images can be found here:
@@ -30,6 +31,8 @@
* https://developer.arm.com/documentation/dai0521/latest/
* Application Note AN524:
* https://developer.arm.com/documentation/dai0524/latest/
+ * Application Note AN547:
+ * https://developer.arm.com/-/media/Arm%20Developer%20Community/PDF/DAI0547B_SSE300_PLUS_U55_FPGA_for_mps3.pdf
*
* The AN505 defers to the Cortex-M33 processor ARMv8M IoT Kit FVP User Guide
* (ARM ECM0601256) for the details of some of the device layout:
@@ -37,6 +40,8 @@
* Similarly, the AN521 and AN524 use the SSE-200, and the SSE-200 TRM defines
* most of the device layout:
* https://developer.arm.com/documentation/101104/latest/
+ * and the AN547 uses the SSE-300, whose layout is in the SSE-300 TRM:
+ * https://developer.arm.com/documentation/101773/latest/
*/
#include "qemu/osdep.h"
@@ -68,13 +73,14 @@
#include "hw/qdev-clock.h"
#include "qom/object.h"
-#define MPS2TZ_NUMIRQ_MAX 95
-#define MPS2TZ_RAM_MAX 4
+#define MPS2TZ_NUMIRQ_MAX 96
+#define MPS2TZ_RAM_MAX 5
typedef enum MPS2TZFPGAType {
FPGA_AN505,
FPGA_AN521,
FPGA_AN524,
+ FPGA_AN547,
} MPS2TZFPGAType;
/*
@@ -106,11 +112,15 @@ struct MPS2TZMachineClass {
MPS2TZFPGAType fpga_type;
uint32_t scc_id;
uint32_t sysclk_frq; /* Main SYSCLK frequency in Hz */
+ uint32_t apb_periph_frq; /* APB peripheral frequency in Hz */
uint32_t len_oscclk;
const uint32_t *oscclk;
uint32_t fpgaio_num_leds; /* Number of LEDs in FPGAIO LED0 register */
bool fpgaio_has_switches; /* Does FPGAIO have SWITCH register? */
+ bool fpgaio_has_dbgctrl; /* Does FPGAIO have DBGCTRL register? */
int numirq; /* Number of external interrupts */
+ int uart_overflow_irq; /* number of the combined UART overflow IRQ */
+ uint32_t init_svtor; /* init-svtor setting for SSE */
const RAMInfo *raminfo;
const char *armsse_type;
};
@@ -149,6 +159,7 @@ struct MPS2TZMachineState {
#define TYPE_MPS2TZ_AN505_MACHINE MACHINE_TYPE_NAME("mps2-an505")
#define TYPE_MPS2TZ_AN521_MACHINE MACHINE_TYPE_NAME("mps2-an521")
#define TYPE_MPS3TZ_AN524_MACHINE MACHINE_TYPE_NAME("mps3-an524")
+#define TYPE_MPS3TZ_AN547_MACHINE MACHINE_TYPE_NAME("mps3-an547")
OBJECT_DECLARE_TYPE(MPS2TZMachineState, MPS2TZMachineClass, MPS2TZ_MACHINE)
@@ -248,6 +259,49 @@ static const RAMInfo an524_raminfo[] = { {
},
};
+static const RAMInfo an547_raminfo[] = { {
+ .name = "itcm",
+ .base = 0x00000000,
+ .size = 512 * KiB,
+ .mpc = -1,
+ .mrindex = 0,
+ }, {
+ .name = "sram",
+ .base = 0x01000000,
+ .size = 2 * MiB,
+ .mpc = 0,
+ .mrindex = 1,
+ }, {
+ .name = "dtcm",
+ .base = 0x20000000,
+ .size = 4 * 128 * KiB,
+ .mpc = -1,
+ .mrindex = 2,
+ }, {
+ .name = "sram 2",
+ .base = 0x21000000,
+ .size = 4 * MiB,
+ .mpc = -1,
+ .mrindex = 3,
+ }, {
+ /* We don't model QSPI flash yet; for now expose it as simple ROM */
+ .name = "QSPI",
+ .base = 0x28000000,
+ .size = 8 * MiB,
+ .mpc = 1,
+ .mrindex = 4,
+ .flags = IS_ROM,
+ }, {
+ .name = "DDR",
+ .base = 0x60000000,
+ .size = MPS3_DDR_SIZE,
+ .mpc = 2,
+ .mrindex = -1,
+ }, {
+ .name = NULL,
+ },
+};
+
static const RAMInfo *find_raminfo_for_mpc(MPS2TZMachineState *mms, int mpc)
{
MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms);
@@ -377,7 +431,7 @@ static MemoryRegion *make_uart(MPS2TZMachineState *mms, void *opaque,
object_initialize_child(OBJECT(mms), name, uart, TYPE_CMSDK_APB_UART);
qdev_prop_set_chr(DEVICE(uart), "chardev", serial_hd(i));
- qdev_prop_set_uint32(DEVICE(uart), "pclk-frq", mmc->sysclk_frq);
+ qdev_prop_set_uint32(DEVICE(uart), "pclk-frq", mmc->apb_periph_frq);
sysbus_realize(SYS_BUS_DEVICE(uart), &error_fatal);
s = SYS_BUS_DEVICE(uart);
sysbus_connect_irq(s, 0, get_sse_irq_in(mms, irqs[0]));
@@ -421,6 +475,7 @@ static MemoryRegion *make_fpgaio(MPS2TZMachineState *mms, void *opaque,
object_initialize_child(OBJECT(mms), "fpgaio", fpgaio, TYPE_MPS2_FPGAIO);
qdev_prop_set_uint32(DEVICE(fpgaio), "num-leds", mmc->fpgaio_num_leds);
qdev_prop_set_bit(DEVICE(fpgaio), "has-switches", mmc->fpgaio_has_switches);
+ qdev_prop_set_bit(DEVICE(fpgaio), "has-dbgctrl", mmc->fpgaio_has_dbgctrl);
sysbus_realize(SYS_BUS_DEVICE(fpgaio), &error_fatal);
return sysbus_mmio_get_region(SYS_BUS_DEVICE(fpgaio), 0);
}
@@ -696,6 +751,7 @@ static void mps2tz_common_init(MachineState *machine)
object_property_set_link(OBJECT(&mms->iotkit), "memory",
OBJECT(system_memory), &error_abort);
qdev_prop_set_uint32(iotkitdev, "EXP_NUMIRQ", mmc->numirq);
+ qdev_prop_set_uint32(iotkitdev, "init-svtor", mmc->init_svtor);
qdev_connect_clock_in(iotkitdev, "MAINCLK", mms->sysclk);
qdev_connect_clock_in(iotkitdev, "S32KCLK", mms->s32kclk);
sysbus_realize(SYS_BUS_DEVICE(&mms->iotkit), &error_fatal);
@@ -770,7 +826,7 @@ static void mps2tz_common_init(MachineState *machine)
&error_fatal);
qdev_realize(DEVICE(&mms->uart_irq_orgate), NULL, &error_fatal);
qdev_connect_gpio_out(DEVICE(&mms->uart_irq_orgate), 0,
- get_sse_irq_in(mms, 47));
+ get_sse_irq_in(mms, mmc->uart_overflow_irq));
/* Most of the devices in the FPGA are behind Peripheral Protection
* Controllers. The required order for initializing things is:
@@ -887,6 +943,55 @@ static void mps2tz_common_init(MachineState *machine)
},
};
+ const PPCInfo an547_ppcs[] = { {
+ .name = "apb_ppcexp0",
+ .ports = {
+ { "ssram-mpc", make_mpc, &mms->mpc[0], 0x57000000, 0x1000 },
+ { "qspi-mpc", make_mpc, &mms->mpc[1], 0x57001000, 0x1000 },
+ { "ddr-mpc", make_mpc, &mms->mpc[2], 0x57002000, 0x1000 },
+ },
+ }, {
+ .name = "apb_ppcexp1",
+ .ports = {
+ { "i2c0", make_i2c, &mms->i2c[0], 0x49200000, 0x1000 },
+ { "i2c1", make_i2c, &mms->i2c[1], 0x49201000, 0x1000 },
+ { "spi0", make_spi, &mms->spi[0], 0x49202000, 0x1000, { 53 } },
+ { "spi1", make_spi, &mms->spi[1], 0x49203000, 0x1000, { 54 } },
+ { "spi2", make_spi, &mms->spi[2], 0x49204000, 0x1000, { 55 } },
+ { "i2c2", make_i2c, &mms->i2c[2], 0x49205000, 0x1000 },
+ { "i2c3", make_i2c, &mms->i2c[3], 0x49206000, 0x1000 },
+ { /* port 7 reserved */ },
+ { "i2c4", make_i2c, &mms->i2c[4], 0x49208000, 0x1000 },
+ },
+ }, {
+ .name = "apb_ppcexp2",
+ .ports = {
+ { "scc", make_scc, &mms->scc, 0x49300000, 0x1000 },
+ { "i2s-audio", make_unimp_dev, &mms->i2s_audio, 0x49301000, 0x1000 },
+ { "fpgaio", make_fpgaio, &mms->fpgaio, 0x49302000, 0x1000 },
+ { "uart0", make_uart, &mms->uart[0], 0x49303000, 0x1000, { 33, 34, 43 } },
+ { "uart1", make_uart, &mms->uart[1], 0x49304000, 0x1000, { 35, 36, 44 } },
+ { "uart2", make_uart, &mms->uart[2], 0x49305000, 0x1000, { 37, 38, 45 } },
+ { "uart3", make_uart, &mms->uart[3], 0x49306000, 0x1000, { 39, 40, 46 } },
+ { "uart4", make_uart, &mms->uart[4], 0x49307000, 0x1000, { 41, 42, 47 } },
+ { "uart5", make_uart, &mms->uart[5], 0x49308000, 0x1000, { 125, 126, 127 } },
+
+ { /* port 9 reserved */ },
+ { "clcd", make_unimp_dev, &mms->cldc, 0x4930a000, 0x1000 },
+ { "rtc", make_rtc, &mms->rtc, 0x4930b000, 0x1000 },
+ },
+ }, {
+ .name = "ahb_ppcexp0",
+ .ports = {
+ { "gpio0", make_unimp_dev, &mms->gpio[0], 0x41100000, 0x1000 },
+ { "gpio1", make_unimp_dev, &mms->gpio[1], 0x41101000, 0x1000 },
+ { "gpio2", make_unimp_dev, &mms->gpio[2], 0x41102000, 0x1000 },
+ { "gpio3", make_unimp_dev, &mms->gpio[3], 0x41103000, 0x1000 },
+ { "eth-usb", make_eth_usb, NULL, 0x41400000, 0x200000, { 49 } },
+ },
+ },
+ };
+
switch (mmc->fpga_type) {
case FPGA_AN505:
case FPGA_AN521:
@@ -897,6 +1002,10 @@ static void mps2tz_common_init(MachineState *machine)
ppcs = an524_ppcs;
num_ppcs = ARRAY_SIZE(an524_ppcs);
break;
+ case FPGA_AN547:
+ ppcs = an547_ppcs;
+ num_ppcs = ARRAY_SIZE(an547_ppcs);
+ break;
default:
g_assert_not_reached();
}
@@ -975,6 +1084,11 @@ static void mps2tz_common_init(MachineState *machine)
create_unimplemented_device("FPGA NS PC", 0x48007000, 0x1000);
+ if (mmc->fpga_type == FPGA_AN547) {
+ create_unimplemented_device("U55 timing adapter 0", 0x48102000, 0x1000);
+ create_unimplemented_device("U55 timing adapter 1", 0x48103000, 0x1000);
+ }
+
create_non_mpc_ram(mms);
armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
@@ -1041,11 +1155,15 @@ static void mps2tz_an505_class_init(ObjectClass *oc, void *data)
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33");
mmc->scc_id = 0x41045050;
mmc->sysclk_frq = 20 * 1000 * 1000; /* 20MHz */
+ mmc->apb_periph_frq = mmc->sysclk_frq;
mmc->oscclk = an505_oscclk;
mmc->len_oscclk = ARRAY_SIZE(an505_oscclk);
mmc->fpgaio_num_leds = 2;
mmc->fpgaio_has_switches = false;
+ mmc->fpgaio_has_dbgctrl = false;
mmc->numirq = 92;
+ mmc->uart_overflow_irq = 47;
+ mmc->init_svtor = 0x10000000;
mmc->raminfo = an505_raminfo;
mmc->armsse_type = TYPE_IOTKIT;
mps2tz_set_default_ram_info(mmc);
@@ -1064,11 +1182,15 @@ static void mps2tz_an521_class_init(ObjectClass *oc, void *data)
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33");
mmc->scc_id = 0x41045210;
mmc->sysclk_frq = 20 * 1000 * 1000; /* 20MHz */
+ mmc->apb_periph_frq = mmc->sysclk_frq;
mmc->oscclk = an505_oscclk; /* AN521 is the same as AN505 here */
mmc->len_oscclk = ARRAY_SIZE(an505_oscclk);
mmc->fpgaio_num_leds = 2;
mmc->fpgaio_has_switches = false;
+ mmc->fpgaio_has_dbgctrl = false;
mmc->numirq = 92;
+ mmc->uart_overflow_irq = 47;
+ mmc->init_svtor = 0x10000000;
mmc->raminfo = an505_raminfo; /* AN521 is the same as AN505 here */
mmc->armsse_type = TYPE_SSE200;
mps2tz_set_default_ram_info(mmc);
@@ -1087,16 +1209,47 @@ static void mps3tz_an524_class_init(ObjectClass *oc, void *data)
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33");
mmc->scc_id = 0x41045240;
mmc->sysclk_frq = 32 * 1000 * 1000; /* 32MHz */
+ mmc->apb_periph_frq = mmc->sysclk_frq;
mmc->oscclk = an524_oscclk;
mmc->len_oscclk = ARRAY_SIZE(an524_oscclk);
mmc->fpgaio_num_leds = 10;
mmc->fpgaio_has_switches = true;
+ mmc->fpgaio_has_dbgctrl = false;
mmc->numirq = 95;
+ mmc->uart_overflow_irq = 47;
+ mmc->init_svtor = 0x10000000;
mmc->raminfo = an524_raminfo;
mmc->armsse_type = TYPE_SSE200;
mps2tz_set_default_ram_info(mmc);
}
+static void mps3tz_an547_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_CLASS(oc);
+
+ mc->desc = "ARM MPS3 with AN547 FPGA image for Cortex-M55";
+ mc->default_cpus = 1;
+ mc->min_cpus = mc->default_cpus;
+ mc->max_cpus = mc->default_cpus;
+ mmc->fpga_type = FPGA_AN547;
+ mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m55");
+ mmc->scc_id = 0x41055470;
+ mmc->sysclk_frq = 32 * 1000 * 1000; /* 32MHz */
+ mmc->apb_periph_frq = 25 * 1000 * 1000; /* 25MHz */
+ mmc->oscclk = an524_oscclk; /* same as AN524 */
+ mmc->len_oscclk = ARRAY_SIZE(an524_oscclk);
+ mmc->fpgaio_num_leds = 10;
+ mmc->fpgaio_has_switches = true;
+ mmc->fpgaio_has_dbgctrl = true;
+ mmc->numirq = 96;
+ mmc->uart_overflow_irq = 48;
+ mmc->init_svtor = 0x00000000;
+ mmc->raminfo = an547_raminfo;
+ mmc->armsse_type = TYPE_SSE300;
+ mps2tz_set_default_ram_info(mmc);
+}
+
static const TypeInfo mps2tz_info = {
.name = TYPE_MPS2TZ_MACHINE,
.parent = TYPE_MACHINE,
@@ -1128,12 +1281,19 @@ static const TypeInfo mps3tz_an524_info = {
.class_init = mps3tz_an524_class_init,
};
+static const TypeInfo mps3tz_an547_info = {
+ .name = TYPE_MPS3TZ_AN547_MACHINE,
+ .parent = TYPE_MPS2TZ_MACHINE,
+ .class_init = mps3tz_an547_class_init,
+};
+
static void mps2tz_machine_init(void)
{
type_register_static(&mps2tz_info);
type_register_static(&mps2tz_an505_info);
type_register_static(&mps2tz_an521_info);
type_register_static(&mps3tz_an524_info);
+ type_register_static(&mps3tz_an547_info);
}
type_init(mps2tz_machine_init);
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index 46030c1ef8..7f01284a5c 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -50,6 +50,7 @@
#define QSPI_ADDR 0xff0f0000
#define LQSPI_ADDR 0xc0000000
#define QSPI_IRQ 15
+#define QSPI_DMA_ADDR 0xff0f0800
#define DP_ADDR 0xfd4a0000
#define DP_IRQ 113
@@ -284,6 +285,8 @@ static void xlnx_zynqmp_init(Object *obj)
for (i = 0; i < XLNX_ZYNQMP_NUM_ADMA_CH; i++) {
object_initialize_child(obj, "adma[*]", &s->adma[i], TYPE_XLNX_ZDMA);
}
+
+ object_initialize_child(obj, "qspi-dma", &s->qspi_dma, TYPE_XLNX_CSU_DMA);
}
static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
@@ -301,11 +304,13 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
ram_size = memory_region_size(s->ddr_ram);
- /* Create the DDR Memory Regions. User friendly checks should happen at
+ /*
+ * Create the DDR Memory Regions. User friendly checks should happen at
* the board level
*/
if (ram_size > XLNX_ZYNQMP_MAX_LOW_RAM_SIZE) {
- /* The RAM size is above the maximum available for the low DDR.
+ /*
+ * The RAM size is above the maximum available for the low DDR.
* Create the high DDR memory region as well.
*/
assert(ram_size <= XLNX_ZYNQMP_MAX_RAM_SIZE);
@@ -521,7 +526,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
SysBusDevice *sbd = SYS_BUS_DEVICE(&s->sdhci[i]);
Object *sdhci = OBJECT(&s->sdhci[i]);
- /* Compatible with:
+ /*
+ * Compatible with:
* - SD Host Controller Specification Version 3.00
* - SDIO Specification Version 3.0
* - eMMC Specification Version 4.51
@@ -635,6 +641,15 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->adma[i]), 0,
gic_spi[adma_ch_intr[i]]);
}
+
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->qspi_dma), errp)) {
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->qspi_dma), 0, QSPI_DMA_ADDR);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->qspi_dma), 0, gic_spi[QSPI_IRQ]);
+ object_property_set_link(OBJECT(&s->qspi), "stream-connected-dma",
+ OBJECT(&s->qspi_dma), errp);
}
static Property xlnx_zynqmp_props[] = {