diff options
Diffstat (limited to 'hw/arm/iotkit.c')
-rw-r--r-- | hw/arm/iotkit.c | 759 |
1 files changed, 0 insertions, 759 deletions
diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c deleted file mode 100644 index 8742200..0000000 --- a/hw/arm/iotkit.c +++ /dev/null @@ -1,759 +0,0 @@ -/* - * Arm IoT Kit - * - * Copyright (c) 2018 Linaro Limited - * Written by Peter Maydell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 or - * (at your option) any later version. - */ - -#include "qemu/osdep.h" -#include "qemu/log.h" -#include "qapi/error.h" -#include "trace.h" -#include "hw/sysbus.h" -#include "hw/registerfields.h" -#include "hw/arm/iotkit.h" -#include "hw/arm/arm.h" - -/* Clock frequency in HZ of the 32KHz "slow clock" */ -#define S32KCLK (32 * 1000) - -/* Create an alias region of @size bytes starting at @base - * which mirrors the memory starting at @orig. - */ -static void make_alias(IoTKit *s, MemoryRegion *mr, const char *name, - hwaddr base, hwaddr size, hwaddr orig) -{ - memory_region_init_alias(mr, NULL, name, &s->container, orig, size); - /* The alias is even lower priority than unimplemented_device regions */ - memory_region_add_subregion_overlap(&s->container, base, mr, -1500); -} - -static void irq_status_forwarder(void *opaque, int n, int level) -{ - qemu_irq destirq = opaque; - - qemu_set_irq(destirq, level); -} - -static void nsccfg_handler(void *opaque, int n, int level) -{ - IoTKit *s = IOTKIT(opaque); - - s->nsccfg = level; -} - -static void iotkit_forward_ppc(IoTKit *s, const char *ppcname, int ppcnum) -{ - /* Each of the 4 AHB and 4 APB PPCs that might be present in a - * system using the IoTKit has a collection of control lines which - * are provided by the security controller and which we want to - * expose as control lines on the IoTKit device itself, so the - * code using the IoTKit can wire them up to the PPCs. - */ - SplitIRQ *splitter = &s->ppc_irq_splitter[ppcnum]; - DeviceState *iotkitdev = DEVICE(s); - DeviceState *dev_secctl = DEVICE(&s->secctl); - DeviceState *dev_splitter = DEVICE(splitter); - char *name; - - name = g_strdup_printf("%s_nonsec", ppcname); - qdev_pass_gpios(dev_secctl, iotkitdev, name); - g_free(name); - name = g_strdup_printf("%s_ap", ppcname); - qdev_pass_gpios(dev_secctl, iotkitdev, name); - g_free(name); - name = g_strdup_printf("%s_irq_enable", ppcname); - qdev_pass_gpios(dev_secctl, iotkitdev, name); - g_free(name); - name = g_strdup_printf("%s_irq_clear", ppcname); - qdev_pass_gpios(dev_secctl, iotkitdev, name); - g_free(name); - - /* irq_status is a little more tricky, because we need to - * split it so we can send it both to the security controller - * and to our OR gate for the NVIC interrupt line. - * Connect up the splitter's outputs, and create a GPIO input - * which will pass the line state to the input splitter. - */ - name = g_strdup_printf("%s_irq_status", ppcname); - qdev_connect_gpio_out(dev_splitter, 0, - qdev_get_gpio_in_named(dev_secctl, - name, 0)); - qdev_connect_gpio_out(dev_splitter, 1, - qdev_get_gpio_in(DEVICE(&s->ppc_irq_orgate), ppcnum)); - s->irq_status_in[ppcnum] = qdev_get_gpio_in(dev_splitter, 0); - qdev_init_gpio_in_named_with_opaque(iotkitdev, irq_status_forwarder, - s->irq_status_in[ppcnum], name, 1); - g_free(name); -} - -static void iotkit_forward_sec_resp_cfg(IoTKit *s) -{ - /* Forward the 3rd output from the splitter device as a - * named GPIO output of the iotkit object. - */ - DeviceState *dev = DEVICE(s); - DeviceState *dev_splitter = DEVICE(&s->sec_resp_splitter); - - qdev_init_gpio_out_named(dev, &s->sec_resp_cfg, "sec_resp_cfg", 1); - s->sec_resp_cfg_in = qemu_allocate_irq(irq_status_forwarder, - s->sec_resp_cfg, 1); - qdev_connect_gpio_out(dev_splitter, 2, s->sec_resp_cfg_in); -} - -static void iotkit_init(Object *obj) -{ - IoTKit *s = IOTKIT(obj); - int i; - - memory_region_init(&s->container, obj, "iotkit-container", UINT64_MAX); - - sysbus_init_child_obj(obj, "armv7m", &s->armv7m, sizeof(s->armv7m), - TYPE_ARMV7M); - qdev_prop_set_string(DEVICE(&s->armv7m), "cpu-type", - ARM_CPU_TYPE_NAME("cortex-m33")); - - sysbus_init_child_obj(obj, "secctl", &s->secctl, sizeof(s->secctl), - TYPE_IOTKIT_SECCTL); - sysbus_init_child_obj(obj, "apb-ppc0", &s->apb_ppc0, sizeof(s->apb_ppc0), - TYPE_TZ_PPC); - sysbus_init_child_obj(obj, "apb-ppc1", &s->apb_ppc1, sizeof(s->apb_ppc1), - TYPE_TZ_PPC); - sysbus_init_child_obj(obj, "mpc", &s->mpc, sizeof(s->mpc), TYPE_TZ_MPC); - object_initialize_child(obj, "mpc-irq-orgate", &s->mpc_irq_orgate, - sizeof(s->mpc_irq_orgate), TYPE_OR_IRQ, - &error_abort, NULL); - - for (i = 0; i < ARRAY_SIZE(s->mpc_irq_splitter); i++) { - char *name = g_strdup_printf("mpc-irq-splitter-%d", i); - SplitIRQ *splitter = &s->mpc_irq_splitter[i]; - - object_initialize_child(obj, name, splitter, sizeof(*splitter), - TYPE_SPLIT_IRQ, &error_abort, NULL); - g_free(name); - } - sysbus_init_child_obj(obj, "timer0", &s->timer0, sizeof(s->timer0), - TYPE_CMSDK_APB_TIMER); - sysbus_init_child_obj(obj, "timer1", &s->timer1, sizeof(s->timer1), - TYPE_CMSDK_APB_TIMER); - sysbus_init_child_obj(obj, "s32ktimer", &s->s32ktimer, sizeof(s->s32ktimer), - TYPE_CMSDK_APB_TIMER); - sysbus_init_child_obj(obj, "dualtimer", &s->dualtimer, sizeof(s->dualtimer), - TYPE_CMSDK_APB_DUALTIMER); - sysbus_init_child_obj(obj, "s32kwatchdog", &s->s32kwatchdog, - sizeof(s->s32kwatchdog), TYPE_CMSDK_APB_WATCHDOG); - sysbus_init_child_obj(obj, "nswatchdog", &s->nswatchdog, - sizeof(s->nswatchdog), TYPE_CMSDK_APB_WATCHDOG); - sysbus_init_child_obj(obj, "swatchdog", &s->swatchdog, - sizeof(s->swatchdog), TYPE_CMSDK_APB_WATCHDOG); - sysbus_init_child_obj(obj, "iotkit-sysctl", &s->sysctl, - sizeof(s->sysctl), TYPE_IOTKIT_SYSCTL); - sysbus_init_child_obj(obj, "iotkit-sysinfo", &s->sysinfo, - sizeof(s->sysinfo), TYPE_IOTKIT_SYSINFO); - object_initialize_child(obj, "nmi-orgate", &s->nmi_orgate, - sizeof(s->nmi_orgate), TYPE_OR_IRQ, - &error_abort, NULL); - object_initialize_child(obj, "ppc-irq-orgate", &s->ppc_irq_orgate, - sizeof(s->ppc_irq_orgate), TYPE_OR_IRQ, - &error_abort, NULL); - object_initialize_child(obj, "sec-resp-splitter", &s->sec_resp_splitter, - sizeof(s->sec_resp_splitter), TYPE_SPLIT_IRQ, - &error_abort, NULL); - for (i = 0; i < ARRAY_SIZE(s->ppc_irq_splitter); i++) { - char *name = g_strdup_printf("ppc-irq-splitter-%d", i); - SplitIRQ *splitter = &s->ppc_irq_splitter[i]; - - object_initialize_child(obj, name, splitter, sizeof(*splitter), - TYPE_SPLIT_IRQ, &error_abort, NULL); - g_free(name); - } -} - -static void iotkit_exp_irq(void *opaque, int n, int level) -{ - IoTKit *s = IOTKIT(opaque); - - qemu_set_irq(s->exp_irqs[n], level); -} - -static void iotkit_mpcexp_status(void *opaque, int n, int level) -{ - IoTKit *s = IOTKIT(opaque); - qemu_set_irq(s->mpcexp_status_in[n], level); -} - -static void iotkit_realize(DeviceState *dev, Error **errp) -{ - IoTKit *s = IOTKIT(dev); - int i; - MemoryRegion *mr; - Error *err = NULL; - SysBusDevice *sbd_apb_ppc0; - SysBusDevice *sbd_secctl; - DeviceState *dev_apb_ppc0; - DeviceState *dev_apb_ppc1; - DeviceState *dev_secctl; - DeviceState *dev_splitter; - - if (!s->board_memory) { - error_setg(errp, "memory property was not set"); - return; - } - - if (!s->mainclk_frq) { - error_setg(errp, "MAINCLK property was not set"); - return; - } - - /* Handling of which devices should be available only to secure - * code is usually done differently for M profile than for A profile. - * Instead of putting some devices only into the secure address space, - * devices exist in both address spaces but with hard-wired security - * permissions that will cause the CPU to fault for non-secure accesses. - * - * The IoTKit has an IDAU (Implementation Defined Access Unit), - * which specifies hard-wired security permissions for different - * areas of the physical address space. For the IoTKit IDAU, the - * top 4 bits of the physical address are the IDAU region ID, and - * if bit 28 (ie the lowest bit of the ID) is 0 then this is an NS - * region, otherwise it is an S region. - * - * The various devices and RAMs are generally all mapped twice, - * once into a region that the IDAU defines as secure and once - * into a non-secure region. They sit behind either a Memory - * Protection Controller (for RAM) or a Peripheral Protection - * Controller (for devices), which allow a more fine grained - * configuration of whether non-secure accesses are permitted. - * - * (The other place that guest software can configure security - * permissions is in the architected SAU (Security Attribution - * Unit), which is entirely inside the CPU. The IDAU can upgrade - * the security attributes for a region to more restrictive than - * the SAU specifies, but cannot downgrade them.) - * - * 0x10000000..0x1fffffff alias of 0x00000000..0x0fffffff - * 0x20000000..0x2007ffff 32KB FPGA block RAM - * 0x30000000..0x3fffffff alias of 0x20000000..0x2fffffff - * 0x40000000..0x4000ffff base peripheral region 1 - * 0x40010000..0x4001ffff CPU peripherals (none for IoTKit) - * 0x40020000..0x4002ffff system control element peripherals - * 0x40080000..0x400fffff base peripheral region 2 - * 0x50000000..0x5fffffff alias of 0x40000000..0x4fffffff - */ - - memory_region_add_subregion_overlap(&s->container, 0, s->board_memory, -1); - - qdev_prop_set_uint32(DEVICE(&s->armv7m), "num-irq", s->exp_numirq + 32); - /* In real hardware the initial Secure VTOR is set from the INITSVTOR0 - * register in the IoT Kit System Control Register block, and the - * initial value of that is in turn specifiable by the FPGA that - * instantiates the IoT Kit. In QEMU we don't implement this wrinkle, - * and simply set the CPU's init-svtor to the IoT Kit default value. - */ - qdev_prop_set_uint32(DEVICE(&s->armv7m), "init-svtor", 0x10000000); - object_property_set_link(OBJECT(&s->armv7m), OBJECT(&s->container), - "memory", &err); - if (err) { - error_propagate(errp, err); - return; - } - object_property_set_link(OBJECT(&s->armv7m), OBJECT(s), "idau", &err); - if (err) { - error_propagate(errp, err); - return; - } - object_property_set_bool(OBJECT(&s->armv7m), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - /* Connect our EXP_IRQ GPIOs to the NVIC's lines 32 and up. */ - s->exp_irqs = g_new(qemu_irq, s->exp_numirq); - for (i = 0; i < s->exp_numirq; i++) { - s->exp_irqs[i] = qdev_get_gpio_in(DEVICE(&s->armv7m), i + 32); - } - qdev_init_gpio_in_named(dev, iotkit_exp_irq, "EXP_IRQ", s->exp_numirq); - - /* Set up the big aliases first */ - make_alias(s, &s->alias1, "alias 1", 0x10000000, 0x10000000, 0x00000000); - make_alias(s, &s->alias2, "alias 2", 0x30000000, 0x10000000, 0x20000000); - /* The 0x50000000..0x5fffffff region is not a pure alias: it has - * a few extra devices that only appear there (generally the - * control interfaces for the protection controllers). - * We implement this by mapping those devices over the top of this - * alias MR at a higher priority. - */ - make_alias(s, &s->alias3, "alias 3", 0x50000000, 0x10000000, 0x40000000); - - - /* Security controller */ - object_property_set_bool(OBJECT(&s->secctl), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sbd_secctl = SYS_BUS_DEVICE(&s->secctl); - dev_secctl = DEVICE(&s->secctl); - sysbus_mmio_map(sbd_secctl, 0, 0x50080000); - sysbus_mmio_map(sbd_secctl, 1, 0x40080000); - - s->nsc_cfg_in = qemu_allocate_irq(nsccfg_handler, s, 1); - qdev_connect_gpio_out_named(dev_secctl, "nsc_cfg", 0, s->nsc_cfg_in); - - /* The sec_resp_cfg output from the security controller must be split into - * multiple lines, one for each of the PPCs within the IoTKit and one - * that will be an output from the IoTKit to the system. - */ - object_property_set_int(OBJECT(&s->sec_resp_splitter), 3, - "num-lines", &err); - if (err) { - error_propagate(errp, err); - return; - } - object_property_set_bool(OBJECT(&s->sec_resp_splitter), true, - "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - dev_splitter = DEVICE(&s->sec_resp_splitter); - qdev_connect_gpio_out_named(dev_secctl, "sec_resp_cfg", 0, - qdev_get_gpio_in(dev_splitter, 0)); - - /* This RAM lives behind the Memory Protection Controller */ - memory_region_init_ram(&s->sram0, NULL, "iotkit.sram0", 0x00008000, &err); - if (err) { - error_propagate(errp, err); - return; - } - object_property_set_link(OBJECT(&s->mpc), OBJECT(&s->sram0), - "downstream", &err); - if (err) { - error_propagate(errp, err); - return; - } - object_property_set_bool(OBJECT(&s->mpc), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - /* Map the upstream end of the MPC into the right place... */ - memory_region_add_subregion(&s->container, 0x20000000, - sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mpc), - 1)); - /* ...and its register interface */ - memory_region_add_subregion(&s->container, 0x50083000, - sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mpc), - 0)); - - /* We must OR together lines from the MPC splitters to go to the NVIC */ - object_property_set_int(OBJECT(&s->mpc_irq_orgate), - IOTS_NUM_EXP_MPC + IOTS_NUM_MPC, "num-lines", &err); - if (err) { - error_propagate(errp, err); - return; - } - object_property_set_bool(OBJECT(&s->mpc_irq_orgate), true, - "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - qdev_connect_gpio_out(DEVICE(&s->mpc_irq_orgate), 0, - qdev_get_gpio_in(DEVICE(&s->armv7m), 9)); - - /* Devices behind APB PPC0: - * 0x40000000: timer0 - * 0x40001000: timer1 - * 0x40002000: dual timer - * We must configure and realize each downstream device and connect - * 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_prop_set_uint32(DEVICE(&s->timer0), "pclk-frq", s->mainclk_frq); - object_property_set_bool(OBJECT(&s->timer0), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer0), 0, - qdev_get_gpio_in(DEVICE(&s->armv7m), 3)); - mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->timer0), 0); - object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[0]", &err); - if (err) { - error_propagate(errp, err); - return; - } - - qdev_prop_set_uint32(DEVICE(&s->timer1), "pclk-frq", s->mainclk_frq); - object_property_set_bool(OBJECT(&s->timer1), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer1), 0, - qdev_get_gpio_in(DEVICE(&s->armv7m), 4)); - mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->timer1), 0); - object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[1]", &err); - if (err) { - error_propagate(errp, err); - return; - } - - - qdev_prop_set_uint32(DEVICE(&s->dualtimer), "pclk-frq", s->mainclk_frq); - object_property_set_bool(OBJECT(&s->dualtimer), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_connect_irq(SYS_BUS_DEVICE(&s->dualtimer), 0, - qdev_get_gpio_in(DEVICE(&s->armv7m), 5)); - mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dualtimer), 0); - object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[2]", &err); - if (err) { - error_propagate(errp, err); - return; - } - - object_property_set_bool(OBJECT(&s->apb_ppc0), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - sbd_apb_ppc0 = SYS_BUS_DEVICE(&s->apb_ppc0); - dev_apb_ppc0 = DEVICE(&s->apb_ppc0); - - 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); - for (i = 0; i < IOTS_APB_PPC0_NUM_PORTS; i++) { - qdev_connect_gpio_out_named(dev_secctl, "apb_ppc0_nonsec", i, - qdev_get_gpio_in_named(dev_apb_ppc0, - "cfg_nonsec", i)); - qdev_connect_gpio_out_named(dev_secctl, "apb_ppc0_ap", i, - qdev_get_gpio_in_named(dev_apb_ppc0, - "cfg_ap", i)); - } - qdev_connect_gpio_out_named(dev_secctl, "apb_ppc0_irq_enable", 0, - qdev_get_gpio_in_named(dev_apb_ppc0, - "irq_enable", 0)); - qdev_connect_gpio_out_named(dev_secctl, "apb_ppc0_irq_clear", 0, - qdev_get_gpio_in_named(dev_apb_ppc0, - "irq_clear", 0)); - qdev_connect_gpio_out(dev_splitter, 0, - qdev_get_gpio_in_named(dev_apb_ppc0, - "cfg_sec_resp", 0)); - - /* All the PPC irq lines (from the 2 internal PPCs and the 8 external - * ones) are sent individually to the security controller, and also - * ORed together to give a single combined PPC interrupt to the NVIC. - */ - object_property_set_int(OBJECT(&s->ppc_irq_orgate), - NUM_PPCS, "num-lines", &err); - if (err) { - error_propagate(errp, err); - return; - } - object_property_set_bool(OBJECT(&s->ppc_irq_orgate), true, - "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - qdev_connect_gpio_out(DEVICE(&s->ppc_irq_orgate), 0, - qdev_get_gpio_in(DEVICE(&s->armv7m), 10)); - - /* 0x40010000 .. 0x4001ffff: private CPU region: unused in IoTKit */ - - /* 0x40020000 .. 0x4002ffff : IoTKit system control peripheral region */ - /* Devices behind APB PPC1: - * 0x4002f000: S32K timer - */ - qdev_prop_set_uint32(DEVICE(&s->s32ktimer), "pclk-frq", S32KCLK); - object_property_set_bool(OBJECT(&s->s32ktimer), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_connect_irq(SYS_BUS_DEVICE(&s->s32ktimer), 0, - qdev_get_gpio_in(DEVICE(&s->armv7m), 2)); - mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->s32ktimer), 0); - object_property_set_link(OBJECT(&s->apb_ppc1), OBJECT(mr), "port[0]", &err); - if (err) { - error_propagate(errp, err); - return; - } - - object_property_set_bool(OBJECT(&s->apb_ppc1), true, "realized", &err); - if (err) { - error_propagate(errp, err); - 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); - qdev_connect_gpio_out_named(dev_secctl, "apb_ppc1_nonsec", 0, - qdev_get_gpio_in_named(dev_apb_ppc1, - "cfg_nonsec", 0)); - qdev_connect_gpio_out_named(dev_secctl, "apb_ppc1_ap", 0, - qdev_get_gpio_in_named(dev_apb_ppc1, - "cfg_ap", 0)); - qdev_connect_gpio_out_named(dev_secctl, "apb_ppc1_irq_enable", 0, - qdev_get_gpio_in_named(dev_apb_ppc1, - "irq_enable", 0)); - qdev_connect_gpio_out_named(dev_secctl, "apb_ppc1_irq_clear", 0, - qdev_get_gpio_in_named(dev_apb_ppc1, - "irq_clear", 0)); - qdev_connect_gpio_out(dev_splitter, 1, - qdev_get_gpio_in_named(dev_apb_ppc1, - "cfg_sec_resp", 0)); - - object_property_set_bool(OBJECT(&s->sysinfo), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - /* System information registers */ - sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysinfo), 0, 0x40020000); - /* System control registers */ - object_property_set_bool(OBJECT(&s->sysctl), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysctl), 0, 0x50021000); - - /* This OR gate wires together outputs from the secure watchdogs to NMI */ - object_property_set_int(OBJECT(&s->nmi_orgate), 2, "num-lines", &err); - if (err) { - error_propagate(errp, err); - return; - } - object_property_set_bool(OBJECT(&s->nmi_orgate), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - qdev_connect_gpio_out(DEVICE(&s->nmi_orgate), 0, - qdev_get_gpio_in_named(DEVICE(&s->armv7m), "NMI", 0)); - - qdev_prop_set_uint32(DEVICE(&s->s32kwatchdog), "wdogclk-frq", S32KCLK); - object_property_set_bool(OBJECT(&s->s32kwatchdog), true, "realized", &err); - if (err) { - error_propagate(errp, err); - 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 : IoTKit second Base peripheral region */ - - qdev_prop_set_uint32(DEVICE(&s->nswatchdog), "wdogclk-frq", s->mainclk_frq); - object_property_set_bool(OBJECT(&s->nswatchdog), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_connect_irq(SYS_BUS_DEVICE(&s->nswatchdog), 0, - qdev_get_gpio_in(DEVICE(&s->armv7m), 1)); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->nswatchdog), 0, 0x40081000); - - qdev_prop_set_uint32(DEVICE(&s->swatchdog), "wdogclk-frq", s->mainclk_frq); - object_property_set_bool(OBJECT(&s->swatchdog), true, "realized", &err); - if (err) { - error_propagate(errp, err); - 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]); - - object_property_set_int(splitter, 2, "num-lines", &err); - if (err) { - error_propagate(errp, err); - return; - } - object_property_set_bool(splitter, true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - } - - for (i = 0; i < IOTS_NUM_AHB_EXP_PPC; i++) { - char *ppcname = g_strdup_printf("ahb_ppcexp%d", i); - - iotkit_forward_ppc(s, ppcname, i); - g_free(ppcname); - } - - for (i = 0; i < IOTS_NUM_APB_EXP_PPC; i++) { - char *ppcname = g_strdup_printf("apb_ppcexp%d", i); - - iotkit_forward_ppc(s, ppcname, i + IOTS_NUM_AHB_EXP_PPC); - g_free(ppcname); - } - - for (i = NUM_EXTERNAL_PPCS; i < NUM_PPCS; i++) { - /* Wire up IRQ splitter for internal PPCs */ - 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; - - qdev_connect_gpio_out(devs, 0, - qdev_get_gpio_in_named(dev_secctl, gpioname, 0)); - qdev_connect_gpio_out(devs, 1, - qdev_get_gpio_in(DEVICE(&s->ppc_irq_orgate), i)); - qdev_connect_gpio_out_named(DEVICE(ppc), "irq", 0, - qdev_get_gpio_in(devs, 0)); - g_free(gpioname); - } - - /* Wire up the splitters for the MPC IRQs */ - for (i = 0; i < IOTS_NUM_EXP_MPC + IOTS_NUM_MPC; i++) { - SplitIRQ *splitter = &s->mpc_irq_splitter[i]; - DeviceState *dev_splitter = DEVICE(splitter); - - object_property_set_int(OBJECT(splitter), 2, "num-lines", &err); - if (err) { - error_propagate(errp, err); - return; - } - object_property_set_bool(OBJECT(splitter), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - if (i < IOTS_NUM_EXP_MPC) { - /* Splitter input is from GPIO input line */ - s->mpcexp_status_in[i] = qdev_get_gpio_in(dev_splitter, 0); - qdev_connect_gpio_out(dev_splitter, 0, - qdev_get_gpio_in_named(dev_secctl, - "mpcexp_status", i)); - } else { - /* Splitter input is from our own MPC */ - qdev_connect_gpio_out_named(DEVICE(&s->mpc), "irq", 0, - qdev_get_gpio_in(dev_splitter, 0)); - qdev_connect_gpio_out(dev_splitter, 0, - qdev_get_gpio_in_named(dev_secctl, - "mpc_status", 0)); - } - - qdev_connect_gpio_out(dev_splitter, 1, - qdev_get_gpio_in(DEVICE(&s->mpc_irq_orgate), i)); - } - /* Create GPIO inputs which will pass the line state for our - * mpcexp_irq inputs to the correct splitter devices. - */ - qdev_init_gpio_in_named(dev, iotkit_mpcexp_status, "mpcexp_status", - IOTS_NUM_EXP_MPC); - - iotkit_forward_sec_resp_cfg(s); - - /* Forward the MSC related signals */ - qdev_pass_gpios(dev_secctl, dev, "mscexp_status"); - qdev_pass_gpios(dev_secctl, dev, "mscexp_clear"); - qdev_pass_gpios(dev_secctl, dev, "mscexp_ns"); - qdev_connect_gpio_out_named(dev_secctl, "msc_irq", 0, - qdev_get_gpio_in(DEVICE(&s->armv7m), 11)); - - /* - * Expose our container region to the board model; this corresponds - * to the AHB Slave Expansion ports which allow bus master devices - * (eg DMA controllers) in the board model to make transactions into - * devices in the IoTKit. - */ - sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->container); - - system_clock_scale = NANOSECONDS_PER_SECOND / s->mainclk_frq; -} - -static void iotkit_idau_check(IDAUInterface *ii, uint32_t address, - int *iregion, bool *exempt, bool *ns, bool *nsc) -{ - /* For IoTKit systems the IDAU responses are simple logical functions - * of the address bits. The NSC attribute is guest-adjustable via the - * NSCCFG register in the security controller. - */ - IoTKit *s = IOTKIT(ii); - int region = extract32(address, 28, 4); - - *ns = !(region & 1); - *nsc = (region == 1 && (s->nsccfg & 1)) || (region == 3 && (s->nsccfg & 2)); - /* 0xe0000000..0xe00fffff and 0xf0000000..0xf00fffff are exempt */ - *exempt = (address & 0xeff00000) == 0xe0000000; - *iregion = region; -} - -static const VMStateDescription iotkit_vmstate = { - .name = "iotkit", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(nsccfg, IoTKit), - VMSTATE_END_OF_LIST() - } -}; - -static Property iotkit_properties[] = { - DEFINE_PROP_LINK("memory", IoTKit, board_memory, TYPE_MEMORY_REGION, - MemoryRegion *), - DEFINE_PROP_UINT32("EXP_NUMIRQ", IoTKit, exp_numirq, 64), - DEFINE_PROP_UINT32("MAINCLK", IoTKit, mainclk_frq, 0), - DEFINE_PROP_END_OF_LIST() -}; - -static void iotkit_reset(DeviceState *dev) -{ - IoTKit *s = IOTKIT(dev); - - s->nsccfg = 0; -} - -static void iotkit_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(klass); - - dc->realize = iotkit_realize; - dc->vmsd = &iotkit_vmstate; - dc->props = iotkit_properties; - dc->reset = iotkit_reset; - iic->check = iotkit_idau_check; -} - -static const TypeInfo iotkit_info = { - .name = TYPE_IOTKIT, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(IoTKit), - .instance_init = iotkit_init, - .class_init = iotkit_class_init, - .interfaces = (InterfaceInfo[]) { - { TYPE_IDAU_INTERFACE }, - { } - } -}; - -static void iotkit_register_types(void) -{ - type_register_static(&iotkit_info); -} - -type_init(iotkit_register_types); |