19e5e54d1SPeter Maydell /* 293dbd103SPeter Maydell * Arm SSE (Subsystems for Embedded): IoTKit 39e5e54d1SPeter Maydell * 49e5e54d1SPeter Maydell * Copyright (c) 2018 Linaro Limited 59e5e54d1SPeter Maydell * Written by Peter Maydell 69e5e54d1SPeter Maydell * 79e5e54d1SPeter Maydell * This program is free software; you can redistribute it and/or modify 89e5e54d1SPeter Maydell * it under the terms of the GNU General Public License version 2 or 99e5e54d1SPeter Maydell * (at your option) any later version. 109e5e54d1SPeter Maydell */ 119e5e54d1SPeter Maydell 129e5e54d1SPeter Maydell #include "qemu/osdep.h" 139e5e54d1SPeter Maydell #include "qemu/log.h" 149e5e54d1SPeter Maydell #include "qapi/error.h" 159e5e54d1SPeter Maydell #include "trace.h" 169e5e54d1SPeter Maydell #include "hw/sysbus.h" 179e5e54d1SPeter Maydell #include "hw/registerfields.h" 186eee5d24SPeter Maydell #include "hw/arm/armsse.h" 199e5e54d1SPeter Maydell #include "hw/arm/arm.h" 209e5e54d1SPeter Maydell 214c3690b5SPeter Maydell struct ARMSSEInfo { 224c3690b5SPeter Maydell const char *name; 23f0cab7feSPeter Maydell int sram_banks; 2491c1e9fcSPeter Maydell int num_cpus; 254c3690b5SPeter Maydell }; 264c3690b5SPeter Maydell 274c3690b5SPeter Maydell static const ARMSSEInfo armsse_variants[] = { 284c3690b5SPeter Maydell { 294c3690b5SPeter Maydell .name = TYPE_IOTKIT, 30f0cab7feSPeter Maydell .sram_banks = 1, 3191c1e9fcSPeter Maydell .num_cpus = 1, 324c3690b5SPeter Maydell }, 334c3690b5SPeter Maydell }; 344c3690b5SPeter Maydell 35d61e4e1fSPeter Maydell /* Clock frequency in HZ of the 32KHz "slow clock" */ 36d61e4e1fSPeter Maydell #define S32KCLK (32 * 1000) 37d61e4e1fSPeter Maydell 3891c1e9fcSPeter Maydell /* Is internal IRQ n shared between CPUs in a multi-core SSE ? */ 3991c1e9fcSPeter Maydell static bool irq_is_common[32] = { 4091c1e9fcSPeter Maydell [0 ... 5] = true, 4191c1e9fcSPeter Maydell /* 6, 7: per-CPU MHU interrupts */ 4291c1e9fcSPeter Maydell [8 ... 12] = true, 4391c1e9fcSPeter Maydell /* 13: per-CPU icache interrupt */ 4491c1e9fcSPeter Maydell /* 14: reserved */ 4591c1e9fcSPeter Maydell [15 ... 20] = true, 4691c1e9fcSPeter Maydell /* 21: reserved */ 4791c1e9fcSPeter Maydell [22 ... 26] = true, 4891c1e9fcSPeter Maydell /* 27: reserved */ 4991c1e9fcSPeter Maydell /* 28, 29: per-CPU CTI interrupts */ 5091c1e9fcSPeter Maydell /* 30, 31: reserved */ 5191c1e9fcSPeter Maydell }; 5291c1e9fcSPeter Maydell 539e5e54d1SPeter Maydell /* Create an alias region of @size bytes starting at @base 549e5e54d1SPeter Maydell * which mirrors the memory starting at @orig. 559e5e54d1SPeter Maydell */ 5693dbd103SPeter Maydell static void make_alias(ARMSSE *s, MemoryRegion *mr, const char *name, 579e5e54d1SPeter Maydell hwaddr base, hwaddr size, hwaddr orig) 589e5e54d1SPeter Maydell { 599e5e54d1SPeter Maydell memory_region_init_alias(mr, NULL, name, &s->container, orig, size); 609e5e54d1SPeter Maydell /* The alias is even lower priority than unimplemented_device regions */ 619e5e54d1SPeter Maydell memory_region_add_subregion_overlap(&s->container, base, mr, -1500); 629e5e54d1SPeter Maydell } 639e5e54d1SPeter Maydell 649e5e54d1SPeter Maydell static void irq_status_forwarder(void *opaque, int n, int level) 659e5e54d1SPeter Maydell { 669e5e54d1SPeter Maydell qemu_irq destirq = opaque; 679e5e54d1SPeter Maydell 689e5e54d1SPeter Maydell qemu_set_irq(destirq, level); 699e5e54d1SPeter Maydell } 709e5e54d1SPeter Maydell 719e5e54d1SPeter Maydell static void nsccfg_handler(void *opaque, int n, int level) 729e5e54d1SPeter Maydell { 7393dbd103SPeter Maydell ARMSSE *s = ARMSSE(opaque); 749e5e54d1SPeter Maydell 759e5e54d1SPeter Maydell s->nsccfg = level; 769e5e54d1SPeter Maydell } 779e5e54d1SPeter Maydell 7813628891SPeter Maydell static void armsse_forward_ppc(ARMSSE *s, const char *ppcname, int ppcnum) 799e5e54d1SPeter Maydell { 809e5e54d1SPeter Maydell /* Each of the 4 AHB and 4 APB PPCs that might be present in a 8193dbd103SPeter Maydell * system using the ARMSSE has a collection of control lines which 829e5e54d1SPeter Maydell * are provided by the security controller and which we want to 8393dbd103SPeter Maydell * expose as control lines on the ARMSSE device itself, so the 8493dbd103SPeter Maydell * code using the ARMSSE can wire them up to the PPCs. 859e5e54d1SPeter Maydell */ 869e5e54d1SPeter Maydell SplitIRQ *splitter = &s->ppc_irq_splitter[ppcnum]; 8713628891SPeter Maydell DeviceState *armssedev = DEVICE(s); 889e5e54d1SPeter Maydell DeviceState *dev_secctl = DEVICE(&s->secctl); 899e5e54d1SPeter Maydell DeviceState *dev_splitter = DEVICE(splitter); 909e5e54d1SPeter Maydell char *name; 919e5e54d1SPeter Maydell 929e5e54d1SPeter Maydell name = g_strdup_printf("%s_nonsec", ppcname); 9313628891SPeter Maydell qdev_pass_gpios(dev_secctl, armssedev, name); 949e5e54d1SPeter Maydell g_free(name); 959e5e54d1SPeter Maydell name = g_strdup_printf("%s_ap", ppcname); 9613628891SPeter Maydell qdev_pass_gpios(dev_secctl, armssedev, name); 979e5e54d1SPeter Maydell g_free(name); 989e5e54d1SPeter Maydell name = g_strdup_printf("%s_irq_enable", ppcname); 9913628891SPeter Maydell qdev_pass_gpios(dev_secctl, armssedev, name); 1009e5e54d1SPeter Maydell g_free(name); 1019e5e54d1SPeter Maydell name = g_strdup_printf("%s_irq_clear", ppcname); 10213628891SPeter Maydell qdev_pass_gpios(dev_secctl, armssedev, name); 1039e5e54d1SPeter Maydell g_free(name); 1049e5e54d1SPeter Maydell 1059e5e54d1SPeter Maydell /* irq_status is a little more tricky, because we need to 1069e5e54d1SPeter Maydell * split it so we can send it both to the security controller 1079e5e54d1SPeter Maydell * and to our OR gate for the NVIC interrupt line. 1089e5e54d1SPeter Maydell * Connect up the splitter's outputs, and create a GPIO input 1099e5e54d1SPeter Maydell * which will pass the line state to the input splitter. 1109e5e54d1SPeter Maydell */ 1119e5e54d1SPeter Maydell name = g_strdup_printf("%s_irq_status", ppcname); 1129e5e54d1SPeter Maydell qdev_connect_gpio_out(dev_splitter, 0, 1139e5e54d1SPeter Maydell qdev_get_gpio_in_named(dev_secctl, 1149e5e54d1SPeter Maydell name, 0)); 1159e5e54d1SPeter Maydell qdev_connect_gpio_out(dev_splitter, 1, 1169e5e54d1SPeter Maydell qdev_get_gpio_in(DEVICE(&s->ppc_irq_orgate), ppcnum)); 1179e5e54d1SPeter Maydell s->irq_status_in[ppcnum] = qdev_get_gpio_in(dev_splitter, 0); 11813628891SPeter Maydell qdev_init_gpio_in_named_with_opaque(armssedev, irq_status_forwarder, 1199e5e54d1SPeter Maydell s->irq_status_in[ppcnum], name, 1); 1209e5e54d1SPeter Maydell g_free(name); 1219e5e54d1SPeter Maydell } 1229e5e54d1SPeter Maydell 12313628891SPeter Maydell static void armsse_forward_sec_resp_cfg(ARMSSE *s) 1249e5e54d1SPeter Maydell { 1259e5e54d1SPeter Maydell /* Forward the 3rd output from the splitter device as a 12613628891SPeter Maydell * named GPIO output of the armsse object. 1279e5e54d1SPeter Maydell */ 1289e5e54d1SPeter Maydell DeviceState *dev = DEVICE(s); 1299e5e54d1SPeter Maydell DeviceState *dev_splitter = DEVICE(&s->sec_resp_splitter); 1309e5e54d1SPeter Maydell 1319e5e54d1SPeter Maydell qdev_init_gpio_out_named(dev, &s->sec_resp_cfg, "sec_resp_cfg", 1); 1329e5e54d1SPeter Maydell s->sec_resp_cfg_in = qemu_allocate_irq(irq_status_forwarder, 1339e5e54d1SPeter Maydell s->sec_resp_cfg, 1); 1349e5e54d1SPeter Maydell qdev_connect_gpio_out(dev_splitter, 2, s->sec_resp_cfg_in); 1359e5e54d1SPeter Maydell } 1369e5e54d1SPeter Maydell 13713628891SPeter Maydell static void armsse_init(Object *obj) 1389e5e54d1SPeter Maydell { 13993dbd103SPeter Maydell ARMSSE *s = ARMSSE(obj); 140f0cab7feSPeter Maydell ARMSSEClass *asc = ARMSSE_GET_CLASS(obj); 141f0cab7feSPeter Maydell const ARMSSEInfo *info = asc->info; 1429e5e54d1SPeter Maydell int i; 1439e5e54d1SPeter Maydell 144f0cab7feSPeter Maydell assert(info->sram_banks <= MAX_SRAM_BANKS); 14591c1e9fcSPeter Maydell assert(info->num_cpus <= SSE_MAX_CPUS); 146f0cab7feSPeter Maydell 14713628891SPeter Maydell memory_region_init(&s->container, obj, "armsse-container", UINT64_MAX); 1489e5e54d1SPeter Maydell 14991c1e9fcSPeter Maydell for (i = 0; i < info->num_cpus; i++) { 15091c1e9fcSPeter Maydell char *name = g_strdup_printf("armv7m%d", i); 15191c1e9fcSPeter Maydell sysbus_init_child_obj(obj, name, &s->armv7m[i], sizeof(s->armv7m), 1529e5e54d1SPeter Maydell TYPE_ARMV7M); 15391c1e9fcSPeter Maydell qdev_prop_set_string(DEVICE(&s->armv7m[i]), "cpu-type", 1549e5e54d1SPeter Maydell ARM_CPU_TYPE_NAME("cortex-m33")); 15591c1e9fcSPeter Maydell g_free(name); 156*d847ca51SPeter Maydell name = g_strdup_printf("arm-sse-cpu-container%d", i); 157*d847ca51SPeter Maydell memory_region_init(&s->cpu_container[i], obj, name, UINT64_MAX); 158*d847ca51SPeter Maydell g_free(name); 159*d847ca51SPeter Maydell if (i > 0) { 160*d847ca51SPeter Maydell name = g_strdup_printf("arm-sse-container-alias%d", i); 161*d847ca51SPeter Maydell memory_region_init_alias(&s->container_alias[i - 1], obj, 162*d847ca51SPeter Maydell name, &s->container, 0, UINT64_MAX); 163*d847ca51SPeter Maydell g_free(name); 164*d847ca51SPeter Maydell } 16591c1e9fcSPeter Maydell } 1669e5e54d1SPeter Maydell 167955cbc6bSThomas Huth sysbus_init_child_obj(obj, "secctl", &s->secctl, sizeof(s->secctl), 1689e5e54d1SPeter Maydell TYPE_IOTKIT_SECCTL); 169955cbc6bSThomas Huth sysbus_init_child_obj(obj, "apb-ppc0", &s->apb_ppc0, sizeof(s->apb_ppc0), 1709e5e54d1SPeter Maydell TYPE_TZ_PPC); 171955cbc6bSThomas Huth sysbus_init_child_obj(obj, "apb-ppc1", &s->apb_ppc1, sizeof(s->apb_ppc1), 1729e5e54d1SPeter Maydell TYPE_TZ_PPC); 173f0cab7feSPeter Maydell for (i = 0; i < info->sram_banks; i++) { 174f0cab7feSPeter Maydell char *name = g_strdup_printf("mpc%d", i); 175f0cab7feSPeter Maydell sysbus_init_child_obj(obj, name, &s->mpc[i], 176f0cab7feSPeter Maydell sizeof(s->mpc[i]), TYPE_TZ_MPC); 177f0cab7feSPeter Maydell g_free(name); 178f0cab7feSPeter Maydell } 179955cbc6bSThomas Huth object_initialize_child(obj, "mpc-irq-orgate", &s->mpc_irq_orgate, 180955cbc6bSThomas Huth sizeof(s->mpc_irq_orgate), TYPE_OR_IRQ, 181955cbc6bSThomas Huth &error_abort, NULL); 182955cbc6bSThomas Huth 183f0cab7feSPeter Maydell for (i = 0; i < IOTS_NUM_EXP_MPC + info->sram_banks; i++) { 184bb75e16dSPeter Maydell char *name = g_strdup_printf("mpc-irq-splitter-%d", i); 185bb75e16dSPeter Maydell SplitIRQ *splitter = &s->mpc_irq_splitter[i]; 186bb75e16dSPeter Maydell 187955cbc6bSThomas Huth object_initialize_child(obj, name, splitter, sizeof(*splitter), 188955cbc6bSThomas Huth TYPE_SPLIT_IRQ, &error_abort, NULL); 189bb75e16dSPeter Maydell g_free(name); 190bb75e16dSPeter Maydell } 191955cbc6bSThomas Huth sysbus_init_child_obj(obj, "timer0", &s->timer0, sizeof(s->timer0), 1929e5e54d1SPeter Maydell TYPE_CMSDK_APB_TIMER); 193955cbc6bSThomas Huth sysbus_init_child_obj(obj, "timer1", &s->timer1, sizeof(s->timer1), 1949e5e54d1SPeter Maydell TYPE_CMSDK_APB_TIMER); 195e2d203baSPeter Maydell sysbus_init_child_obj(obj, "s32ktimer", &s->s32ktimer, sizeof(s->s32ktimer), 196e2d203baSPeter Maydell TYPE_CMSDK_APB_TIMER); 197955cbc6bSThomas Huth sysbus_init_child_obj(obj, "dualtimer", &s->dualtimer, sizeof(s->dualtimer), 198017d069dSPeter Maydell TYPE_CMSDK_APB_DUALTIMER); 199d61e4e1fSPeter Maydell sysbus_init_child_obj(obj, "s32kwatchdog", &s->s32kwatchdog, 200d61e4e1fSPeter Maydell sizeof(s->s32kwatchdog), TYPE_CMSDK_APB_WATCHDOG); 201d61e4e1fSPeter Maydell sysbus_init_child_obj(obj, "nswatchdog", &s->nswatchdog, 202d61e4e1fSPeter Maydell sizeof(s->nswatchdog), TYPE_CMSDK_APB_WATCHDOG); 203d61e4e1fSPeter Maydell sysbus_init_child_obj(obj, "swatchdog", &s->swatchdog, 204d61e4e1fSPeter Maydell sizeof(s->swatchdog), TYPE_CMSDK_APB_WATCHDOG); 20513628891SPeter Maydell sysbus_init_child_obj(obj, "armsse-sysctl", &s->sysctl, 20606e65af3SPeter Maydell sizeof(s->sysctl), TYPE_IOTKIT_SYSCTL); 20713628891SPeter Maydell sysbus_init_child_obj(obj, "armsse-sysinfo", &s->sysinfo, 20806e65af3SPeter Maydell sizeof(s->sysinfo), TYPE_IOTKIT_SYSINFO); 209d61e4e1fSPeter Maydell object_initialize_child(obj, "nmi-orgate", &s->nmi_orgate, 210d61e4e1fSPeter Maydell sizeof(s->nmi_orgate), TYPE_OR_IRQ, 211d61e4e1fSPeter Maydell &error_abort, NULL); 212955cbc6bSThomas Huth object_initialize_child(obj, "ppc-irq-orgate", &s->ppc_irq_orgate, 213955cbc6bSThomas Huth sizeof(s->ppc_irq_orgate), TYPE_OR_IRQ, 214955cbc6bSThomas Huth &error_abort, NULL); 215955cbc6bSThomas Huth object_initialize_child(obj, "sec-resp-splitter", &s->sec_resp_splitter, 216955cbc6bSThomas Huth sizeof(s->sec_resp_splitter), TYPE_SPLIT_IRQ, 217955cbc6bSThomas Huth &error_abort, NULL); 2189e5e54d1SPeter Maydell for (i = 0; i < ARRAY_SIZE(s->ppc_irq_splitter); i++) { 2199e5e54d1SPeter Maydell char *name = g_strdup_printf("ppc-irq-splitter-%d", i); 2209e5e54d1SPeter Maydell SplitIRQ *splitter = &s->ppc_irq_splitter[i]; 2219e5e54d1SPeter Maydell 222955cbc6bSThomas Huth object_initialize_child(obj, name, splitter, sizeof(*splitter), 223955cbc6bSThomas Huth TYPE_SPLIT_IRQ, &error_abort, NULL); 224955cbc6bSThomas Huth g_free(name); 2259e5e54d1SPeter Maydell } 22691c1e9fcSPeter Maydell if (info->num_cpus > 1) { 22791c1e9fcSPeter Maydell for (i = 0; i < ARRAY_SIZE(s->cpu_irq_splitter); i++) { 22891c1e9fcSPeter Maydell if (irq_is_common[i]) { 22991c1e9fcSPeter Maydell char *name = g_strdup_printf("cpu-irq-splitter%d", i); 23091c1e9fcSPeter Maydell SplitIRQ *splitter = &s->cpu_irq_splitter[i]; 23191c1e9fcSPeter Maydell 23291c1e9fcSPeter Maydell object_initialize_child(obj, name, splitter, sizeof(*splitter), 23391c1e9fcSPeter Maydell TYPE_SPLIT_IRQ, &error_abort, NULL); 23491c1e9fcSPeter Maydell g_free(name); 23591c1e9fcSPeter Maydell } 23691c1e9fcSPeter Maydell } 23791c1e9fcSPeter Maydell } 2389e5e54d1SPeter Maydell } 2399e5e54d1SPeter Maydell 24013628891SPeter Maydell static void armsse_exp_irq(void *opaque, int n, int level) 2419e5e54d1SPeter Maydell { 24291c1e9fcSPeter Maydell qemu_irq *irqarray = opaque; 2439e5e54d1SPeter Maydell 24491c1e9fcSPeter Maydell qemu_set_irq(irqarray[n], level); 2459e5e54d1SPeter Maydell } 2469e5e54d1SPeter Maydell 24713628891SPeter Maydell static void armsse_mpcexp_status(void *opaque, int n, int level) 248bb75e16dSPeter Maydell { 24993dbd103SPeter Maydell ARMSSE *s = ARMSSE(opaque); 250bb75e16dSPeter Maydell qemu_set_irq(s->mpcexp_status_in[n], level); 251bb75e16dSPeter Maydell } 252bb75e16dSPeter Maydell 25391c1e9fcSPeter Maydell static qemu_irq armsse_get_common_irq_in(ARMSSE *s, int irqno) 25491c1e9fcSPeter Maydell { 25591c1e9fcSPeter Maydell /* 25691c1e9fcSPeter Maydell * Return a qemu_irq which can be used to signal IRQ n to 25791c1e9fcSPeter Maydell * all CPUs in the SSE. 25891c1e9fcSPeter Maydell */ 25991c1e9fcSPeter Maydell ARMSSEClass *asc = ARMSSE_GET_CLASS(s); 26091c1e9fcSPeter Maydell const ARMSSEInfo *info = asc->info; 26191c1e9fcSPeter Maydell 26291c1e9fcSPeter Maydell assert(irq_is_common[irqno]); 26391c1e9fcSPeter Maydell 26491c1e9fcSPeter Maydell if (info->num_cpus == 1) { 26591c1e9fcSPeter Maydell /* Only one CPU -- just connect directly to it */ 26691c1e9fcSPeter Maydell return qdev_get_gpio_in(DEVICE(&s->armv7m[0]), irqno); 26791c1e9fcSPeter Maydell } else { 26891c1e9fcSPeter Maydell /* Connect to the splitter which feeds all CPUs */ 26991c1e9fcSPeter Maydell return qdev_get_gpio_in(DEVICE(&s->cpu_irq_splitter[irqno]), 0); 27091c1e9fcSPeter Maydell } 27191c1e9fcSPeter Maydell } 27291c1e9fcSPeter Maydell 27313628891SPeter Maydell static void armsse_realize(DeviceState *dev, Error **errp) 2749e5e54d1SPeter Maydell { 27593dbd103SPeter Maydell ARMSSE *s = ARMSSE(dev); 276f0cab7feSPeter Maydell ARMSSEClass *asc = ARMSSE_GET_CLASS(dev); 277f0cab7feSPeter Maydell const ARMSSEInfo *info = asc->info; 2789e5e54d1SPeter Maydell int i; 2799e5e54d1SPeter Maydell MemoryRegion *mr; 2809e5e54d1SPeter Maydell Error *err = NULL; 2819e5e54d1SPeter Maydell SysBusDevice *sbd_apb_ppc0; 2829e5e54d1SPeter Maydell SysBusDevice *sbd_secctl; 2839e5e54d1SPeter Maydell DeviceState *dev_apb_ppc0; 2849e5e54d1SPeter Maydell DeviceState *dev_apb_ppc1; 2859e5e54d1SPeter Maydell DeviceState *dev_secctl; 2869e5e54d1SPeter Maydell DeviceState *dev_splitter; 2874b635cf7SPeter Maydell uint32_t addr_width_max; 2889e5e54d1SPeter Maydell 2899e5e54d1SPeter Maydell if (!s->board_memory) { 2909e5e54d1SPeter Maydell error_setg(errp, "memory property was not set"); 2919e5e54d1SPeter Maydell return; 2929e5e54d1SPeter Maydell } 2939e5e54d1SPeter Maydell 2949e5e54d1SPeter Maydell if (!s->mainclk_frq) { 2959e5e54d1SPeter Maydell error_setg(errp, "MAINCLK property was not set"); 2969e5e54d1SPeter Maydell return; 2979e5e54d1SPeter Maydell } 2989e5e54d1SPeter Maydell 2994b635cf7SPeter Maydell /* max SRAM_ADDR_WIDTH: 24 - log2(SRAM_NUM_BANK) */ 3004b635cf7SPeter Maydell assert(is_power_of_2(info->sram_banks)); 3014b635cf7SPeter Maydell addr_width_max = 24 - ctz32(info->sram_banks); 3024b635cf7SPeter Maydell if (s->sram_addr_width < 1 || s->sram_addr_width > addr_width_max) { 3034b635cf7SPeter Maydell error_setg(errp, "SRAM_ADDR_WIDTH must be between 1 and %d", 3044b635cf7SPeter Maydell addr_width_max); 3054b635cf7SPeter Maydell return; 3064b635cf7SPeter Maydell } 3074b635cf7SPeter Maydell 3089e5e54d1SPeter Maydell /* Handling of which devices should be available only to secure 3099e5e54d1SPeter Maydell * code is usually done differently for M profile than for A profile. 3109e5e54d1SPeter Maydell * Instead of putting some devices only into the secure address space, 3119e5e54d1SPeter Maydell * devices exist in both address spaces but with hard-wired security 3129e5e54d1SPeter Maydell * permissions that will cause the CPU to fault for non-secure accesses. 3139e5e54d1SPeter Maydell * 31493dbd103SPeter Maydell * The ARMSSE has an IDAU (Implementation Defined Access Unit), 3159e5e54d1SPeter Maydell * which specifies hard-wired security permissions for different 31693dbd103SPeter Maydell * areas of the physical address space. For the ARMSSE IDAU, the 3179e5e54d1SPeter Maydell * top 4 bits of the physical address are the IDAU region ID, and 3189e5e54d1SPeter Maydell * if bit 28 (ie the lowest bit of the ID) is 0 then this is an NS 3199e5e54d1SPeter Maydell * region, otherwise it is an S region. 3209e5e54d1SPeter Maydell * 3219e5e54d1SPeter Maydell * The various devices and RAMs are generally all mapped twice, 3229e5e54d1SPeter Maydell * once into a region that the IDAU defines as secure and once 3239e5e54d1SPeter Maydell * into a non-secure region. They sit behind either a Memory 3249e5e54d1SPeter Maydell * Protection Controller (for RAM) or a Peripheral Protection 3259e5e54d1SPeter Maydell * Controller (for devices), which allow a more fine grained 3269e5e54d1SPeter Maydell * configuration of whether non-secure accesses are permitted. 3279e5e54d1SPeter Maydell * 3289e5e54d1SPeter Maydell * (The other place that guest software can configure security 3299e5e54d1SPeter Maydell * permissions is in the architected SAU (Security Attribution 3309e5e54d1SPeter Maydell * Unit), which is entirely inside the CPU. The IDAU can upgrade 3319e5e54d1SPeter Maydell * the security attributes for a region to more restrictive than 3329e5e54d1SPeter Maydell * the SAU specifies, but cannot downgrade them.) 3339e5e54d1SPeter Maydell * 3349e5e54d1SPeter Maydell * 0x10000000..0x1fffffff alias of 0x00000000..0x0fffffff 3359e5e54d1SPeter Maydell * 0x20000000..0x2007ffff 32KB FPGA block RAM 3369e5e54d1SPeter Maydell * 0x30000000..0x3fffffff alias of 0x20000000..0x2fffffff 3379e5e54d1SPeter Maydell * 0x40000000..0x4000ffff base peripheral region 1 33893dbd103SPeter Maydell * 0x40010000..0x4001ffff CPU peripherals (none for ARMSSE) 3399e5e54d1SPeter Maydell * 0x40020000..0x4002ffff system control element peripherals 3409e5e54d1SPeter Maydell * 0x40080000..0x400fffff base peripheral region 2 3419e5e54d1SPeter Maydell * 0x50000000..0x5fffffff alias of 0x40000000..0x4fffffff 3429e5e54d1SPeter Maydell */ 3439e5e54d1SPeter Maydell 344*d847ca51SPeter Maydell memory_region_add_subregion_overlap(&s->container, 0, s->board_memory, -2); 3459e5e54d1SPeter Maydell 34691c1e9fcSPeter Maydell for (i = 0; i < info->num_cpus; i++) { 34791c1e9fcSPeter Maydell DeviceState *cpudev = DEVICE(&s->armv7m[i]); 34891c1e9fcSPeter Maydell Object *cpuobj = OBJECT(&s->armv7m[i]); 34991c1e9fcSPeter Maydell int j; 35091c1e9fcSPeter Maydell char *gpioname; 35191c1e9fcSPeter Maydell 35291c1e9fcSPeter Maydell qdev_prop_set_uint32(cpudev, "num-irq", s->exp_numirq + 32); 35391c1e9fcSPeter Maydell /* 35491c1e9fcSPeter Maydell * In real hardware the initial Secure VTOR is set from the INITSVTOR0 3559e5e54d1SPeter Maydell * register in the IoT Kit System Control Register block, and the 3569e5e54d1SPeter Maydell * initial value of that is in turn specifiable by the FPGA that 3579e5e54d1SPeter Maydell * instantiates the IoT Kit. In QEMU we don't implement this wrinkle, 3589e5e54d1SPeter Maydell * and simply set the CPU's init-svtor to the IoT Kit default value. 35991c1e9fcSPeter Maydell * In SSE-200 the situation is similar, except that the default value 36091c1e9fcSPeter Maydell * is a reset-time signal input. Typically a board using the SSE-200 36191c1e9fcSPeter Maydell * will have a system control processor whose boot firmware initializes 36291c1e9fcSPeter Maydell * the INITSVTOR* registers before powering up the CPUs in any case, 36391c1e9fcSPeter Maydell * so the hardware's default value doesn't matter. QEMU doesn't emulate 36491c1e9fcSPeter Maydell * the control processor, so instead we behave in the way that the 36591c1e9fcSPeter Maydell * firmware does. All boards currently known about have firmware that 36691c1e9fcSPeter Maydell * sets the INITSVTOR0 and INITSVTOR1 registers to 0x10000000, like the 36791c1e9fcSPeter Maydell * IoTKit default. We can make this more configurable if necessary. 3689e5e54d1SPeter Maydell */ 36991c1e9fcSPeter Maydell qdev_prop_set_uint32(cpudev, "init-svtor", 0x10000000); 37091c1e9fcSPeter Maydell /* 37191c1e9fcSPeter Maydell * Start all CPUs except CPU0 powered down. In real hardware it is 37291c1e9fcSPeter Maydell * a configurable property of the SSE-200 which CPUs start powered up 37391c1e9fcSPeter Maydell * (via the CPUWAIT0_RST and CPUWAIT1_RST parameters), but since all 37491c1e9fcSPeter Maydell * the boards we care about start CPU0 and leave CPU1 powered off, 37591c1e9fcSPeter Maydell * we hard-code that for now. We can add QOM properties for this 37691c1e9fcSPeter Maydell * later if necessary. 37791c1e9fcSPeter Maydell */ 37891c1e9fcSPeter Maydell if (i > 0) { 37991c1e9fcSPeter Maydell object_property_set_bool(cpuobj, true, "start-powered-off", &err); 3809e5e54d1SPeter Maydell if (err) { 3819e5e54d1SPeter Maydell error_propagate(errp, err); 3829e5e54d1SPeter Maydell return; 3839e5e54d1SPeter Maydell } 38491c1e9fcSPeter Maydell } 385*d847ca51SPeter Maydell 386*d847ca51SPeter Maydell if (i > 0) { 387*d847ca51SPeter Maydell memory_region_add_subregion_overlap(&s->cpu_container[i], 0, 388*d847ca51SPeter Maydell &s->container_alias[i - 1], -1); 389*d847ca51SPeter Maydell } else { 390*d847ca51SPeter Maydell memory_region_add_subregion_overlap(&s->cpu_container[i], 0, 391*d847ca51SPeter Maydell &s->container, -1); 392*d847ca51SPeter Maydell } 393*d847ca51SPeter Maydell object_property_set_link(cpuobj, OBJECT(&s->cpu_container[i]), 394*d847ca51SPeter Maydell "memory", &err); 3959e5e54d1SPeter Maydell if (err) { 3969e5e54d1SPeter Maydell error_propagate(errp, err); 3979e5e54d1SPeter Maydell return; 3989e5e54d1SPeter Maydell } 39991c1e9fcSPeter Maydell object_property_set_link(cpuobj, OBJECT(s), "idau", &err); 40091c1e9fcSPeter Maydell if (err) { 40191c1e9fcSPeter Maydell error_propagate(errp, err); 40291c1e9fcSPeter Maydell return; 40391c1e9fcSPeter Maydell } 40491c1e9fcSPeter Maydell object_property_set_bool(cpuobj, true, "realized", &err); 4059e5e54d1SPeter Maydell if (err) { 4069e5e54d1SPeter Maydell error_propagate(errp, err); 4079e5e54d1SPeter Maydell return; 4089e5e54d1SPeter Maydell } 4099e5e54d1SPeter Maydell 41091c1e9fcSPeter Maydell /* Connect EXP_IRQ/EXP_CPUn_IRQ GPIOs to the NVIC's lines 32 and up */ 41191c1e9fcSPeter Maydell s->exp_irqs[i] = g_new(qemu_irq, s->exp_numirq); 41291c1e9fcSPeter Maydell for (j = 0; j < s->exp_numirq; j++) { 41391c1e9fcSPeter Maydell s->exp_irqs[i][j] = qdev_get_gpio_in(cpudev, i + 32); 4149e5e54d1SPeter Maydell } 41591c1e9fcSPeter Maydell if (i == 0) { 41691c1e9fcSPeter Maydell gpioname = g_strdup("EXP_IRQ"); 41791c1e9fcSPeter Maydell } else { 41891c1e9fcSPeter Maydell gpioname = g_strdup_printf("EXP_CPU%d_IRQ", i); 41991c1e9fcSPeter Maydell } 42091c1e9fcSPeter Maydell qdev_init_gpio_in_named_with_opaque(dev, armsse_exp_irq, 42191c1e9fcSPeter Maydell s->exp_irqs[i], 42291c1e9fcSPeter Maydell gpioname, s->exp_numirq); 42391c1e9fcSPeter Maydell g_free(gpioname); 42491c1e9fcSPeter Maydell } 42591c1e9fcSPeter Maydell 42691c1e9fcSPeter Maydell /* Wire up the splitters that connect common IRQs to all CPUs */ 42791c1e9fcSPeter Maydell if (info->num_cpus > 1) { 42891c1e9fcSPeter Maydell for (i = 0; i < ARRAY_SIZE(s->cpu_irq_splitter); i++) { 42991c1e9fcSPeter Maydell if (irq_is_common[i]) { 43091c1e9fcSPeter Maydell Object *splitter = OBJECT(&s->cpu_irq_splitter[i]); 43191c1e9fcSPeter Maydell DeviceState *devs = DEVICE(splitter); 43291c1e9fcSPeter Maydell int cpunum; 43391c1e9fcSPeter Maydell 43491c1e9fcSPeter Maydell object_property_set_int(splitter, info->num_cpus, 43591c1e9fcSPeter Maydell "num-lines", &err); 43691c1e9fcSPeter Maydell if (err) { 43791c1e9fcSPeter Maydell error_propagate(errp, err); 43891c1e9fcSPeter Maydell return; 43991c1e9fcSPeter Maydell } 44091c1e9fcSPeter Maydell object_property_set_bool(splitter, true, "realized", &err); 44191c1e9fcSPeter Maydell if (err) { 44291c1e9fcSPeter Maydell error_propagate(errp, err); 44391c1e9fcSPeter Maydell return; 44491c1e9fcSPeter Maydell } 44591c1e9fcSPeter Maydell for (cpunum = 0; cpunum < info->num_cpus; cpunum++) { 44691c1e9fcSPeter Maydell DeviceState *cpudev = DEVICE(&s->armv7m[cpunum]); 44791c1e9fcSPeter Maydell 44891c1e9fcSPeter Maydell qdev_connect_gpio_out(devs, cpunum, 44991c1e9fcSPeter Maydell qdev_get_gpio_in(cpudev, i)); 45091c1e9fcSPeter Maydell } 45191c1e9fcSPeter Maydell } 45291c1e9fcSPeter Maydell } 45391c1e9fcSPeter Maydell } 4549e5e54d1SPeter Maydell 4559e5e54d1SPeter Maydell /* Set up the big aliases first */ 4569e5e54d1SPeter Maydell make_alias(s, &s->alias1, "alias 1", 0x10000000, 0x10000000, 0x00000000); 4579e5e54d1SPeter Maydell make_alias(s, &s->alias2, "alias 2", 0x30000000, 0x10000000, 0x20000000); 4589e5e54d1SPeter Maydell /* The 0x50000000..0x5fffffff region is not a pure alias: it has 4599e5e54d1SPeter Maydell * a few extra devices that only appear there (generally the 4609e5e54d1SPeter Maydell * control interfaces for the protection controllers). 4619e5e54d1SPeter Maydell * We implement this by mapping those devices over the top of this 4629e5e54d1SPeter Maydell * alias MR at a higher priority. 4639e5e54d1SPeter Maydell */ 4649e5e54d1SPeter Maydell make_alias(s, &s->alias3, "alias 3", 0x50000000, 0x10000000, 0x40000000); 4659e5e54d1SPeter Maydell 4669e5e54d1SPeter Maydell 4679e5e54d1SPeter Maydell /* Security controller */ 4689e5e54d1SPeter Maydell object_property_set_bool(OBJECT(&s->secctl), true, "realized", &err); 4699e5e54d1SPeter Maydell if (err) { 4709e5e54d1SPeter Maydell error_propagate(errp, err); 4719e5e54d1SPeter Maydell return; 4729e5e54d1SPeter Maydell } 4739e5e54d1SPeter Maydell sbd_secctl = SYS_BUS_DEVICE(&s->secctl); 4749e5e54d1SPeter Maydell dev_secctl = DEVICE(&s->secctl); 4759e5e54d1SPeter Maydell sysbus_mmio_map(sbd_secctl, 0, 0x50080000); 4769e5e54d1SPeter Maydell sysbus_mmio_map(sbd_secctl, 1, 0x40080000); 4779e5e54d1SPeter Maydell 4789e5e54d1SPeter Maydell s->nsc_cfg_in = qemu_allocate_irq(nsccfg_handler, s, 1); 4799e5e54d1SPeter Maydell qdev_connect_gpio_out_named(dev_secctl, "nsc_cfg", 0, s->nsc_cfg_in); 4809e5e54d1SPeter Maydell 4819e5e54d1SPeter Maydell /* The sec_resp_cfg output from the security controller must be split into 48293dbd103SPeter Maydell * multiple lines, one for each of the PPCs within the ARMSSE and one 48393dbd103SPeter Maydell * that will be an output from the ARMSSE to the system. 4849e5e54d1SPeter Maydell */ 4859e5e54d1SPeter Maydell object_property_set_int(OBJECT(&s->sec_resp_splitter), 3, 4869e5e54d1SPeter Maydell "num-lines", &err); 4879e5e54d1SPeter Maydell if (err) { 4889e5e54d1SPeter Maydell error_propagate(errp, err); 4899e5e54d1SPeter Maydell return; 4909e5e54d1SPeter Maydell } 4919e5e54d1SPeter Maydell object_property_set_bool(OBJECT(&s->sec_resp_splitter), true, 4929e5e54d1SPeter Maydell "realized", &err); 4939e5e54d1SPeter Maydell if (err) { 4949e5e54d1SPeter Maydell error_propagate(errp, err); 4959e5e54d1SPeter Maydell return; 4969e5e54d1SPeter Maydell } 4979e5e54d1SPeter Maydell dev_splitter = DEVICE(&s->sec_resp_splitter); 4989e5e54d1SPeter Maydell qdev_connect_gpio_out_named(dev_secctl, "sec_resp_cfg", 0, 4999e5e54d1SPeter Maydell qdev_get_gpio_in(dev_splitter, 0)); 5009e5e54d1SPeter Maydell 501f0cab7feSPeter Maydell /* Each SRAM bank lives behind its own Memory Protection Controller */ 502f0cab7feSPeter Maydell for (i = 0; i < info->sram_banks; i++) { 503f0cab7feSPeter Maydell char *ramname = g_strdup_printf("armsse.sram%d", i); 504f0cab7feSPeter Maydell SysBusDevice *sbd_mpc; 5054b635cf7SPeter Maydell uint32_t sram_bank_size = 1 << s->sram_addr_width; 506f0cab7feSPeter Maydell 5074b635cf7SPeter Maydell memory_region_init_ram(&s->sram[i], NULL, ramname, 5084b635cf7SPeter Maydell sram_bank_size, &err); 509f0cab7feSPeter Maydell g_free(ramname); 510af60b291SPeter Maydell if (err) { 511af60b291SPeter Maydell error_propagate(errp, err); 512af60b291SPeter Maydell return; 513af60b291SPeter Maydell } 514f0cab7feSPeter Maydell object_property_set_link(OBJECT(&s->mpc[i]), OBJECT(&s->sram[i]), 515af60b291SPeter Maydell "downstream", &err); 516af60b291SPeter Maydell if (err) { 517af60b291SPeter Maydell error_propagate(errp, err); 518af60b291SPeter Maydell return; 519af60b291SPeter Maydell } 520f0cab7feSPeter Maydell object_property_set_bool(OBJECT(&s->mpc[i]), true, "realized", &err); 521af60b291SPeter Maydell if (err) { 522af60b291SPeter Maydell error_propagate(errp, err); 523af60b291SPeter Maydell return; 524af60b291SPeter Maydell } 525af60b291SPeter Maydell /* Map the upstream end of the MPC into the right place... */ 526f0cab7feSPeter Maydell sbd_mpc = SYS_BUS_DEVICE(&s->mpc[i]); 5274b635cf7SPeter Maydell memory_region_add_subregion(&s->container, 5284b635cf7SPeter Maydell 0x20000000 + i * sram_bank_size, 529f0cab7feSPeter Maydell sysbus_mmio_get_region(sbd_mpc, 1)); 530af60b291SPeter Maydell /* ...and its register interface */ 531f0cab7feSPeter Maydell memory_region_add_subregion(&s->container, 0x50083000 + i * 0x1000, 532f0cab7feSPeter Maydell sysbus_mmio_get_region(sbd_mpc, 0)); 533f0cab7feSPeter Maydell } 534af60b291SPeter Maydell 535bb75e16dSPeter Maydell /* We must OR together lines from the MPC splitters to go to the NVIC */ 536bb75e16dSPeter Maydell object_property_set_int(OBJECT(&s->mpc_irq_orgate), 537f0cab7feSPeter Maydell IOTS_NUM_EXP_MPC + info->sram_banks, 538f0cab7feSPeter Maydell "num-lines", &err); 539bb75e16dSPeter Maydell if (err) { 540bb75e16dSPeter Maydell error_propagate(errp, err); 541bb75e16dSPeter Maydell return; 542bb75e16dSPeter Maydell } 543bb75e16dSPeter Maydell object_property_set_bool(OBJECT(&s->mpc_irq_orgate), true, 544bb75e16dSPeter Maydell "realized", &err); 545bb75e16dSPeter Maydell if (err) { 546bb75e16dSPeter Maydell error_propagate(errp, err); 547bb75e16dSPeter Maydell return; 548bb75e16dSPeter Maydell } 549bb75e16dSPeter Maydell qdev_connect_gpio_out(DEVICE(&s->mpc_irq_orgate), 0, 55091c1e9fcSPeter Maydell armsse_get_common_irq_in(s, 9)); 551bb75e16dSPeter Maydell 5529e5e54d1SPeter Maydell /* Devices behind APB PPC0: 5539e5e54d1SPeter Maydell * 0x40000000: timer0 5549e5e54d1SPeter Maydell * 0x40001000: timer1 5559e5e54d1SPeter Maydell * 0x40002000: dual timer 5569e5e54d1SPeter Maydell * We must configure and realize each downstream device and connect 5579e5e54d1SPeter Maydell * it to the appropriate PPC port; then we can realize the PPC and 5589e5e54d1SPeter Maydell * map its upstream ends to the right place in the container. 5599e5e54d1SPeter Maydell */ 5609e5e54d1SPeter Maydell qdev_prop_set_uint32(DEVICE(&s->timer0), "pclk-frq", s->mainclk_frq); 5619e5e54d1SPeter Maydell object_property_set_bool(OBJECT(&s->timer0), true, "realized", &err); 5629e5e54d1SPeter Maydell if (err) { 5639e5e54d1SPeter Maydell error_propagate(errp, err); 5649e5e54d1SPeter Maydell return; 5659e5e54d1SPeter Maydell } 5669e5e54d1SPeter Maydell sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer0), 0, 56791c1e9fcSPeter Maydell armsse_get_common_irq_in(s, 3)); 5689e5e54d1SPeter Maydell mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->timer0), 0); 5699e5e54d1SPeter Maydell object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[0]", &err); 5709e5e54d1SPeter Maydell if (err) { 5719e5e54d1SPeter Maydell error_propagate(errp, err); 5729e5e54d1SPeter Maydell return; 5739e5e54d1SPeter Maydell } 5749e5e54d1SPeter Maydell 5759e5e54d1SPeter Maydell qdev_prop_set_uint32(DEVICE(&s->timer1), "pclk-frq", s->mainclk_frq); 5769e5e54d1SPeter Maydell object_property_set_bool(OBJECT(&s->timer1), true, "realized", &err); 5779e5e54d1SPeter Maydell if (err) { 5789e5e54d1SPeter Maydell error_propagate(errp, err); 5799e5e54d1SPeter Maydell return; 5809e5e54d1SPeter Maydell } 5819e5e54d1SPeter Maydell sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer1), 0, 58291c1e9fcSPeter Maydell armsse_get_common_irq_in(s, 4)); 5839e5e54d1SPeter Maydell mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->timer1), 0); 5849e5e54d1SPeter Maydell object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[1]", &err); 5859e5e54d1SPeter Maydell if (err) { 5869e5e54d1SPeter Maydell error_propagate(errp, err); 5879e5e54d1SPeter Maydell return; 5889e5e54d1SPeter Maydell } 5899e5e54d1SPeter Maydell 590017d069dSPeter Maydell 591017d069dSPeter Maydell qdev_prop_set_uint32(DEVICE(&s->dualtimer), "pclk-frq", s->mainclk_frq); 5929e5e54d1SPeter Maydell object_property_set_bool(OBJECT(&s->dualtimer), true, "realized", &err); 5939e5e54d1SPeter Maydell if (err) { 5949e5e54d1SPeter Maydell error_propagate(errp, err); 5959e5e54d1SPeter Maydell return; 5969e5e54d1SPeter Maydell } 597017d069dSPeter Maydell sysbus_connect_irq(SYS_BUS_DEVICE(&s->dualtimer), 0, 59891c1e9fcSPeter Maydell armsse_get_common_irq_in(s, 5)); 5999e5e54d1SPeter Maydell mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dualtimer), 0); 6009e5e54d1SPeter Maydell object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[2]", &err); 6019e5e54d1SPeter Maydell if (err) { 6029e5e54d1SPeter Maydell error_propagate(errp, err); 6039e5e54d1SPeter Maydell return; 6049e5e54d1SPeter Maydell } 6059e5e54d1SPeter Maydell 6069e5e54d1SPeter Maydell object_property_set_bool(OBJECT(&s->apb_ppc0), true, "realized", &err); 6079e5e54d1SPeter Maydell if (err) { 6089e5e54d1SPeter Maydell error_propagate(errp, err); 6099e5e54d1SPeter Maydell return; 6109e5e54d1SPeter Maydell } 6119e5e54d1SPeter Maydell 6129e5e54d1SPeter Maydell sbd_apb_ppc0 = SYS_BUS_DEVICE(&s->apb_ppc0); 6139e5e54d1SPeter Maydell dev_apb_ppc0 = DEVICE(&s->apb_ppc0); 6149e5e54d1SPeter Maydell 6159e5e54d1SPeter Maydell mr = sysbus_mmio_get_region(sbd_apb_ppc0, 0); 6169e5e54d1SPeter Maydell memory_region_add_subregion(&s->container, 0x40000000, mr); 6179e5e54d1SPeter Maydell mr = sysbus_mmio_get_region(sbd_apb_ppc0, 1); 6189e5e54d1SPeter Maydell memory_region_add_subregion(&s->container, 0x40001000, mr); 6199e5e54d1SPeter Maydell mr = sysbus_mmio_get_region(sbd_apb_ppc0, 2); 6209e5e54d1SPeter Maydell memory_region_add_subregion(&s->container, 0x40002000, mr); 6219e5e54d1SPeter Maydell for (i = 0; i < IOTS_APB_PPC0_NUM_PORTS; i++) { 6229e5e54d1SPeter Maydell qdev_connect_gpio_out_named(dev_secctl, "apb_ppc0_nonsec", i, 6239e5e54d1SPeter Maydell qdev_get_gpio_in_named(dev_apb_ppc0, 6249e5e54d1SPeter Maydell "cfg_nonsec", i)); 6259e5e54d1SPeter Maydell qdev_connect_gpio_out_named(dev_secctl, "apb_ppc0_ap", i, 6269e5e54d1SPeter Maydell qdev_get_gpio_in_named(dev_apb_ppc0, 6279e5e54d1SPeter Maydell "cfg_ap", i)); 6289e5e54d1SPeter Maydell } 6299e5e54d1SPeter Maydell qdev_connect_gpio_out_named(dev_secctl, "apb_ppc0_irq_enable", 0, 6309e5e54d1SPeter Maydell qdev_get_gpio_in_named(dev_apb_ppc0, 6319e5e54d1SPeter Maydell "irq_enable", 0)); 6329e5e54d1SPeter Maydell qdev_connect_gpio_out_named(dev_secctl, "apb_ppc0_irq_clear", 0, 6339e5e54d1SPeter Maydell qdev_get_gpio_in_named(dev_apb_ppc0, 6349e5e54d1SPeter Maydell "irq_clear", 0)); 6359e5e54d1SPeter Maydell qdev_connect_gpio_out(dev_splitter, 0, 6369e5e54d1SPeter Maydell qdev_get_gpio_in_named(dev_apb_ppc0, 6379e5e54d1SPeter Maydell "cfg_sec_resp", 0)); 6389e5e54d1SPeter Maydell 6399e5e54d1SPeter Maydell /* All the PPC irq lines (from the 2 internal PPCs and the 8 external 6409e5e54d1SPeter Maydell * ones) are sent individually to the security controller, and also 6419e5e54d1SPeter Maydell * ORed together to give a single combined PPC interrupt to the NVIC. 6429e5e54d1SPeter Maydell */ 6439e5e54d1SPeter Maydell object_property_set_int(OBJECT(&s->ppc_irq_orgate), 6449e5e54d1SPeter Maydell NUM_PPCS, "num-lines", &err); 6459e5e54d1SPeter Maydell if (err) { 6469e5e54d1SPeter Maydell error_propagate(errp, err); 6479e5e54d1SPeter Maydell return; 6489e5e54d1SPeter Maydell } 6499e5e54d1SPeter Maydell object_property_set_bool(OBJECT(&s->ppc_irq_orgate), true, 6509e5e54d1SPeter Maydell "realized", &err); 6519e5e54d1SPeter Maydell if (err) { 6529e5e54d1SPeter Maydell error_propagate(errp, err); 6539e5e54d1SPeter Maydell return; 6549e5e54d1SPeter Maydell } 6559e5e54d1SPeter Maydell qdev_connect_gpio_out(DEVICE(&s->ppc_irq_orgate), 0, 65691c1e9fcSPeter Maydell armsse_get_common_irq_in(s, 10)); 6579e5e54d1SPeter Maydell 6589e5e54d1SPeter Maydell /* 0x40010000 .. 0x4001ffff: private CPU region: unused in IoTKit */ 6599e5e54d1SPeter Maydell 66093dbd103SPeter Maydell /* 0x40020000 .. 0x4002ffff : ARMSSE system control peripheral region */ 6619e5e54d1SPeter Maydell /* Devices behind APB PPC1: 6629e5e54d1SPeter Maydell * 0x4002f000: S32K timer 6639e5e54d1SPeter Maydell */ 664e2d203baSPeter Maydell qdev_prop_set_uint32(DEVICE(&s->s32ktimer), "pclk-frq", S32KCLK); 6659e5e54d1SPeter Maydell object_property_set_bool(OBJECT(&s->s32ktimer), true, "realized", &err); 6669e5e54d1SPeter Maydell if (err) { 6679e5e54d1SPeter Maydell error_propagate(errp, err); 6689e5e54d1SPeter Maydell return; 6699e5e54d1SPeter Maydell } 670e2d203baSPeter Maydell sysbus_connect_irq(SYS_BUS_DEVICE(&s->s32ktimer), 0, 67191c1e9fcSPeter Maydell armsse_get_common_irq_in(s, 2)); 6729e5e54d1SPeter Maydell mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->s32ktimer), 0); 6739e5e54d1SPeter Maydell object_property_set_link(OBJECT(&s->apb_ppc1), OBJECT(mr), "port[0]", &err); 6749e5e54d1SPeter Maydell if (err) { 6759e5e54d1SPeter Maydell error_propagate(errp, err); 6769e5e54d1SPeter Maydell return; 6779e5e54d1SPeter Maydell } 6789e5e54d1SPeter Maydell 6799e5e54d1SPeter Maydell object_property_set_bool(OBJECT(&s->apb_ppc1), true, "realized", &err); 6809e5e54d1SPeter Maydell if (err) { 6819e5e54d1SPeter Maydell error_propagate(errp, err); 6829e5e54d1SPeter Maydell return; 6839e5e54d1SPeter Maydell } 6849e5e54d1SPeter Maydell mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->apb_ppc1), 0); 6859e5e54d1SPeter Maydell memory_region_add_subregion(&s->container, 0x4002f000, mr); 6869e5e54d1SPeter Maydell 6879e5e54d1SPeter Maydell dev_apb_ppc1 = DEVICE(&s->apb_ppc1); 6889e5e54d1SPeter Maydell qdev_connect_gpio_out_named(dev_secctl, "apb_ppc1_nonsec", 0, 6899e5e54d1SPeter Maydell qdev_get_gpio_in_named(dev_apb_ppc1, 6909e5e54d1SPeter Maydell "cfg_nonsec", 0)); 6919e5e54d1SPeter Maydell qdev_connect_gpio_out_named(dev_secctl, "apb_ppc1_ap", 0, 6929e5e54d1SPeter Maydell qdev_get_gpio_in_named(dev_apb_ppc1, 6939e5e54d1SPeter Maydell "cfg_ap", 0)); 6949e5e54d1SPeter Maydell qdev_connect_gpio_out_named(dev_secctl, "apb_ppc1_irq_enable", 0, 6959e5e54d1SPeter Maydell qdev_get_gpio_in_named(dev_apb_ppc1, 6969e5e54d1SPeter Maydell "irq_enable", 0)); 6979e5e54d1SPeter Maydell qdev_connect_gpio_out_named(dev_secctl, "apb_ppc1_irq_clear", 0, 6989e5e54d1SPeter Maydell qdev_get_gpio_in_named(dev_apb_ppc1, 6999e5e54d1SPeter Maydell "irq_clear", 0)); 7009e5e54d1SPeter Maydell qdev_connect_gpio_out(dev_splitter, 1, 7019e5e54d1SPeter Maydell qdev_get_gpio_in_named(dev_apb_ppc1, 7029e5e54d1SPeter Maydell "cfg_sec_resp", 0)); 7039e5e54d1SPeter Maydell 70406e65af3SPeter Maydell object_property_set_bool(OBJECT(&s->sysinfo), true, "realized", &err); 70506e65af3SPeter Maydell if (err) { 70606e65af3SPeter Maydell error_propagate(errp, err); 70706e65af3SPeter Maydell return; 70806e65af3SPeter Maydell } 70906e65af3SPeter Maydell /* System information registers */ 71006e65af3SPeter Maydell sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysinfo), 0, 0x40020000); 71106e65af3SPeter Maydell /* System control registers */ 71206e65af3SPeter Maydell object_property_set_bool(OBJECT(&s->sysctl), true, "realized", &err); 71306e65af3SPeter Maydell if (err) { 71406e65af3SPeter Maydell error_propagate(errp, err); 71506e65af3SPeter Maydell return; 71606e65af3SPeter Maydell } 71706e65af3SPeter Maydell sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysctl), 0, 0x50021000); 718d61e4e1fSPeter Maydell 719d61e4e1fSPeter Maydell /* This OR gate wires together outputs from the secure watchdogs to NMI */ 720d61e4e1fSPeter Maydell object_property_set_int(OBJECT(&s->nmi_orgate), 2, "num-lines", &err); 721d61e4e1fSPeter Maydell if (err) { 722d61e4e1fSPeter Maydell error_propagate(errp, err); 723d61e4e1fSPeter Maydell return; 724d61e4e1fSPeter Maydell } 725d61e4e1fSPeter Maydell object_property_set_bool(OBJECT(&s->nmi_orgate), true, "realized", &err); 726d61e4e1fSPeter Maydell if (err) { 727d61e4e1fSPeter Maydell error_propagate(errp, err); 728d61e4e1fSPeter Maydell return; 729d61e4e1fSPeter Maydell } 730d61e4e1fSPeter Maydell qdev_connect_gpio_out(DEVICE(&s->nmi_orgate), 0, 731d61e4e1fSPeter Maydell qdev_get_gpio_in_named(DEVICE(&s->armv7m), "NMI", 0)); 732d61e4e1fSPeter Maydell 733d61e4e1fSPeter Maydell qdev_prop_set_uint32(DEVICE(&s->s32kwatchdog), "wdogclk-frq", S32KCLK); 734d61e4e1fSPeter Maydell object_property_set_bool(OBJECT(&s->s32kwatchdog), true, "realized", &err); 735d61e4e1fSPeter Maydell if (err) { 736d61e4e1fSPeter Maydell error_propagate(errp, err); 737d61e4e1fSPeter Maydell return; 738d61e4e1fSPeter Maydell } 739d61e4e1fSPeter Maydell sysbus_connect_irq(SYS_BUS_DEVICE(&s->s32kwatchdog), 0, 740d61e4e1fSPeter Maydell qdev_get_gpio_in(DEVICE(&s->nmi_orgate), 0)); 741d61e4e1fSPeter Maydell sysbus_mmio_map(SYS_BUS_DEVICE(&s->s32kwatchdog), 0, 0x5002e000); 7429e5e54d1SPeter Maydell 74393dbd103SPeter Maydell /* 0x40080000 .. 0x4008ffff : ARMSSE second Base peripheral region */ 7449e5e54d1SPeter Maydell 745d61e4e1fSPeter Maydell qdev_prop_set_uint32(DEVICE(&s->nswatchdog), "wdogclk-frq", s->mainclk_frq); 746d61e4e1fSPeter Maydell object_property_set_bool(OBJECT(&s->nswatchdog), true, "realized", &err); 747d61e4e1fSPeter Maydell if (err) { 748d61e4e1fSPeter Maydell error_propagate(errp, err); 749d61e4e1fSPeter Maydell return; 750d61e4e1fSPeter Maydell } 751d61e4e1fSPeter Maydell sysbus_connect_irq(SYS_BUS_DEVICE(&s->nswatchdog), 0, 75291c1e9fcSPeter Maydell armsse_get_common_irq_in(s, 1)); 753d61e4e1fSPeter Maydell sysbus_mmio_map(SYS_BUS_DEVICE(&s->nswatchdog), 0, 0x40081000); 754d61e4e1fSPeter Maydell 755d61e4e1fSPeter Maydell qdev_prop_set_uint32(DEVICE(&s->swatchdog), "wdogclk-frq", s->mainclk_frq); 756d61e4e1fSPeter Maydell object_property_set_bool(OBJECT(&s->swatchdog), true, "realized", &err); 757d61e4e1fSPeter Maydell if (err) { 758d61e4e1fSPeter Maydell error_propagate(errp, err); 759d61e4e1fSPeter Maydell return; 760d61e4e1fSPeter Maydell } 761d61e4e1fSPeter Maydell sysbus_connect_irq(SYS_BUS_DEVICE(&s->swatchdog), 0, 762d61e4e1fSPeter Maydell qdev_get_gpio_in(DEVICE(&s->nmi_orgate), 1)); 763d61e4e1fSPeter Maydell sysbus_mmio_map(SYS_BUS_DEVICE(&s->swatchdog), 0, 0x50081000); 7649e5e54d1SPeter Maydell 7659e5e54d1SPeter Maydell for (i = 0; i < ARRAY_SIZE(s->ppc_irq_splitter); i++) { 7669e5e54d1SPeter Maydell Object *splitter = OBJECT(&s->ppc_irq_splitter[i]); 7679e5e54d1SPeter Maydell 7689e5e54d1SPeter Maydell object_property_set_int(splitter, 2, "num-lines", &err); 7699e5e54d1SPeter Maydell if (err) { 7709e5e54d1SPeter Maydell error_propagate(errp, err); 7719e5e54d1SPeter Maydell return; 7729e5e54d1SPeter Maydell } 7739e5e54d1SPeter Maydell object_property_set_bool(splitter, true, "realized", &err); 7749e5e54d1SPeter Maydell if (err) { 7759e5e54d1SPeter Maydell error_propagate(errp, err); 7769e5e54d1SPeter Maydell return; 7779e5e54d1SPeter Maydell } 7789e5e54d1SPeter Maydell } 7799e5e54d1SPeter Maydell 7809e5e54d1SPeter Maydell for (i = 0; i < IOTS_NUM_AHB_EXP_PPC; i++) { 7819e5e54d1SPeter Maydell char *ppcname = g_strdup_printf("ahb_ppcexp%d", i); 7829e5e54d1SPeter Maydell 78313628891SPeter Maydell armsse_forward_ppc(s, ppcname, i); 7849e5e54d1SPeter Maydell g_free(ppcname); 7859e5e54d1SPeter Maydell } 7869e5e54d1SPeter Maydell 7879e5e54d1SPeter Maydell for (i = 0; i < IOTS_NUM_APB_EXP_PPC; i++) { 7889e5e54d1SPeter Maydell char *ppcname = g_strdup_printf("apb_ppcexp%d", i); 7899e5e54d1SPeter Maydell 79013628891SPeter Maydell armsse_forward_ppc(s, ppcname, i + IOTS_NUM_AHB_EXP_PPC); 7919e5e54d1SPeter Maydell g_free(ppcname); 7929e5e54d1SPeter Maydell } 7939e5e54d1SPeter Maydell 7949e5e54d1SPeter Maydell for (i = NUM_EXTERNAL_PPCS; i < NUM_PPCS; i++) { 7959e5e54d1SPeter Maydell /* Wire up IRQ splitter for internal PPCs */ 7969e5e54d1SPeter Maydell DeviceState *devs = DEVICE(&s->ppc_irq_splitter[i]); 7979e5e54d1SPeter Maydell char *gpioname = g_strdup_printf("apb_ppc%d_irq_status", 7989e5e54d1SPeter Maydell i - NUM_EXTERNAL_PPCS); 7999e5e54d1SPeter Maydell TZPPC *ppc = (i == NUM_EXTERNAL_PPCS) ? &s->apb_ppc0 : &s->apb_ppc1; 8009e5e54d1SPeter Maydell 8019e5e54d1SPeter Maydell qdev_connect_gpio_out(devs, 0, 8029e5e54d1SPeter Maydell qdev_get_gpio_in_named(dev_secctl, gpioname, 0)); 8039e5e54d1SPeter Maydell qdev_connect_gpio_out(devs, 1, 8049e5e54d1SPeter Maydell qdev_get_gpio_in(DEVICE(&s->ppc_irq_orgate), i)); 8059e5e54d1SPeter Maydell qdev_connect_gpio_out_named(DEVICE(ppc), "irq", 0, 8069e5e54d1SPeter Maydell qdev_get_gpio_in(devs, 0)); 8077a35383aSPeter Maydell g_free(gpioname); 8089e5e54d1SPeter Maydell } 8099e5e54d1SPeter Maydell 810bb75e16dSPeter Maydell /* Wire up the splitters for the MPC IRQs */ 811f0cab7feSPeter Maydell for (i = 0; i < IOTS_NUM_EXP_MPC + info->sram_banks; i++) { 812bb75e16dSPeter Maydell SplitIRQ *splitter = &s->mpc_irq_splitter[i]; 813bb75e16dSPeter Maydell DeviceState *dev_splitter = DEVICE(splitter); 814bb75e16dSPeter Maydell 815bb75e16dSPeter Maydell object_property_set_int(OBJECT(splitter), 2, "num-lines", &err); 816bb75e16dSPeter Maydell if (err) { 817bb75e16dSPeter Maydell error_propagate(errp, err); 818bb75e16dSPeter Maydell return; 819bb75e16dSPeter Maydell } 820bb75e16dSPeter Maydell object_property_set_bool(OBJECT(splitter), true, "realized", &err); 821bb75e16dSPeter Maydell if (err) { 822bb75e16dSPeter Maydell error_propagate(errp, err); 823bb75e16dSPeter Maydell return; 824bb75e16dSPeter Maydell } 825bb75e16dSPeter Maydell 826bb75e16dSPeter Maydell if (i < IOTS_NUM_EXP_MPC) { 827bb75e16dSPeter Maydell /* Splitter input is from GPIO input line */ 828bb75e16dSPeter Maydell s->mpcexp_status_in[i] = qdev_get_gpio_in(dev_splitter, 0); 829bb75e16dSPeter Maydell qdev_connect_gpio_out(dev_splitter, 0, 830bb75e16dSPeter Maydell qdev_get_gpio_in_named(dev_secctl, 831bb75e16dSPeter Maydell "mpcexp_status", i)); 832bb75e16dSPeter Maydell } else { 833bb75e16dSPeter Maydell /* Splitter input is from our own MPC */ 834f0cab7feSPeter Maydell qdev_connect_gpio_out_named(DEVICE(&s->mpc[i - IOTS_NUM_EXP_MPC]), 835f0cab7feSPeter Maydell "irq", 0, 836bb75e16dSPeter Maydell qdev_get_gpio_in(dev_splitter, 0)); 837bb75e16dSPeter Maydell qdev_connect_gpio_out(dev_splitter, 0, 838bb75e16dSPeter Maydell qdev_get_gpio_in_named(dev_secctl, 839bb75e16dSPeter Maydell "mpc_status", 0)); 840bb75e16dSPeter Maydell } 841bb75e16dSPeter Maydell 842bb75e16dSPeter Maydell qdev_connect_gpio_out(dev_splitter, 1, 843bb75e16dSPeter Maydell qdev_get_gpio_in(DEVICE(&s->mpc_irq_orgate), i)); 844bb75e16dSPeter Maydell } 845bb75e16dSPeter Maydell /* Create GPIO inputs which will pass the line state for our 846bb75e16dSPeter Maydell * mpcexp_irq inputs to the correct splitter devices. 847bb75e16dSPeter Maydell */ 84813628891SPeter Maydell qdev_init_gpio_in_named(dev, armsse_mpcexp_status, "mpcexp_status", 849bb75e16dSPeter Maydell IOTS_NUM_EXP_MPC); 850bb75e16dSPeter Maydell 85113628891SPeter Maydell armsse_forward_sec_resp_cfg(s); 8529e5e54d1SPeter Maydell 853132b475aSPeter Maydell /* Forward the MSC related signals */ 854132b475aSPeter Maydell qdev_pass_gpios(dev_secctl, dev, "mscexp_status"); 855132b475aSPeter Maydell qdev_pass_gpios(dev_secctl, dev, "mscexp_clear"); 856132b475aSPeter Maydell qdev_pass_gpios(dev_secctl, dev, "mscexp_ns"); 857132b475aSPeter Maydell qdev_connect_gpio_out_named(dev_secctl, "msc_irq", 0, 85891c1e9fcSPeter Maydell armsse_get_common_irq_in(s, 11)); 859132b475aSPeter Maydell 860132b475aSPeter Maydell /* 861132b475aSPeter Maydell * Expose our container region to the board model; this corresponds 862132b475aSPeter Maydell * to the AHB Slave Expansion ports which allow bus master devices 863132b475aSPeter Maydell * (eg DMA controllers) in the board model to make transactions into 86493dbd103SPeter Maydell * devices in the ARMSSE. 865132b475aSPeter Maydell */ 866132b475aSPeter Maydell sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->container); 867132b475aSPeter Maydell 8689e5e54d1SPeter Maydell system_clock_scale = NANOSECONDS_PER_SECOND / s->mainclk_frq; 8699e5e54d1SPeter Maydell } 8709e5e54d1SPeter Maydell 87113628891SPeter Maydell static void armsse_idau_check(IDAUInterface *ii, uint32_t address, 8729e5e54d1SPeter Maydell int *iregion, bool *exempt, bool *ns, bool *nsc) 8739e5e54d1SPeter Maydell { 87493dbd103SPeter Maydell /* 87593dbd103SPeter Maydell * For ARMSSE systems the IDAU responses are simple logical functions 8769e5e54d1SPeter Maydell * of the address bits. The NSC attribute is guest-adjustable via the 8779e5e54d1SPeter Maydell * NSCCFG register in the security controller. 8789e5e54d1SPeter Maydell */ 87993dbd103SPeter Maydell ARMSSE *s = ARMSSE(ii); 8809e5e54d1SPeter Maydell int region = extract32(address, 28, 4); 8819e5e54d1SPeter Maydell 8829e5e54d1SPeter Maydell *ns = !(region & 1); 8839e5e54d1SPeter Maydell *nsc = (region == 1 && (s->nsccfg & 1)) || (region == 3 && (s->nsccfg & 2)); 8849e5e54d1SPeter Maydell /* 0xe0000000..0xe00fffff and 0xf0000000..0xf00fffff are exempt */ 8859e5e54d1SPeter Maydell *exempt = (address & 0xeff00000) == 0xe0000000; 8869e5e54d1SPeter Maydell *iregion = region; 8879e5e54d1SPeter Maydell } 8889e5e54d1SPeter Maydell 88913628891SPeter Maydell static const VMStateDescription armsse_vmstate = { 8909e5e54d1SPeter Maydell .name = "iotkit", 8919e5e54d1SPeter Maydell .version_id = 1, 8929e5e54d1SPeter Maydell .minimum_version_id = 1, 8939e5e54d1SPeter Maydell .fields = (VMStateField[]) { 89493dbd103SPeter Maydell VMSTATE_UINT32(nsccfg, ARMSSE), 8959e5e54d1SPeter Maydell VMSTATE_END_OF_LIST() 8969e5e54d1SPeter Maydell } 8979e5e54d1SPeter Maydell }; 8989e5e54d1SPeter Maydell 89913628891SPeter Maydell static Property armsse_properties[] = { 90093dbd103SPeter Maydell DEFINE_PROP_LINK("memory", ARMSSE, board_memory, TYPE_MEMORY_REGION, 9019e5e54d1SPeter Maydell MemoryRegion *), 90293dbd103SPeter Maydell DEFINE_PROP_UINT32("EXP_NUMIRQ", ARMSSE, exp_numirq, 64), 90393dbd103SPeter Maydell DEFINE_PROP_UINT32("MAINCLK", ARMSSE, mainclk_frq, 0), 9044b635cf7SPeter Maydell DEFINE_PROP_UINT32("SRAM_ADDR_WIDTH", ARMSSE, sram_addr_width, 15), 9059e5e54d1SPeter Maydell DEFINE_PROP_END_OF_LIST() 9069e5e54d1SPeter Maydell }; 9079e5e54d1SPeter Maydell 90813628891SPeter Maydell static void armsse_reset(DeviceState *dev) 9099e5e54d1SPeter Maydell { 91093dbd103SPeter Maydell ARMSSE *s = ARMSSE(dev); 9119e5e54d1SPeter Maydell 9129e5e54d1SPeter Maydell s->nsccfg = 0; 9139e5e54d1SPeter Maydell } 9149e5e54d1SPeter Maydell 91513628891SPeter Maydell static void armsse_class_init(ObjectClass *klass, void *data) 9169e5e54d1SPeter Maydell { 9179e5e54d1SPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass); 9189e5e54d1SPeter Maydell IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(klass); 9194c3690b5SPeter Maydell ARMSSEClass *asc = ARMSSE_CLASS(klass); 9209e5e54d1SPeter Maydell 92113628891SPeter Maydell dc->realize = armsse_realize; 92213628891SPeter Maydell dc->vmsd = &armsse_vmstate; 92313628891SPeter Maydell dc->props = armsse_properties; 92413628891SPeter Maydell dc->reset = armsse_reset; 92513628891SPeter Maydell iic->check = armsse_idau_check; 9264c3690b5SPeter Maydell asc->info = data; 9279e5e54d1SPeter Maydell } 9289e5e54d1SPeter Maydell 9294c3690b5SPeter Maydell static const TypeInfo armsse_info = { 93093dbd103SPeter Maydell .name = TYPE_ARMSSE, 9319e5e54d1SPeter Maydell .parent = TYPE_SYS_BUS_DEVICE, 93293dbd103SPeter Maydell .instance_size = sizeof(ARMSSE), 93313628891SPeter Maydell .instance_init = armsse_init, 9344c3690b5SPeter Maydell .abstract = true, 9359e5e54d1SPeter Maydell .interfaces = (InterfaceInfo[]) { 9369e5e54d1SPeter Maydell { TYPE_IDAU_INTERFACE }, 9379e5e54d1SPeter Maydell { } 9389e5e54d1SPeter Maydell } 9399e5e54d1SPeter Maydell }; 9409e5e54d1SPeter Maydell 9414c3690b5SPeter Maydell static void armsse_register_types(void) 9429e5e54d1SPeter Maydell { 9434c3690b5SPeter Maydell int i; 9444c3690b5SPeter Maydell 9454c3690b5SPeter Maydell type_register_static(&armsse_info); 9464c3690b5SPeter Maydell 9474c3690b5SPeter Maydell for (i = 0; i < ARRAY_SIZE(armsse_variants); i++) { 9484c3690b5SPeter Maydell TypeInfo ti = { 9494c3690b5SPeter Maydell .name = armsse_variants[i].name, 9504c3690b5SPeter Maydell .parent = TYPE_ARMSSE, 95113628891SPeter Maydell .class_init = armsse_class_init, 9524c3690b5SPeter Maydell .class_data = (void *)&armsse_variants[i], 9534c3690b5SPeter Maydell }; 9544c3690b5SPeter Maydell type_register(&ti); 9554c3690b5SPeter Maydell } 9569e5e54d1SPeter Maydell } 9579e5e54d1SPeter Maydell 9584c3690b5SPeter Maydell type_init(armsse_register_types); 959