diff options
Diffstat (limited to 'hw/arm/mps2-tz.c')
-rw-r--r-- | hw/arm/mps2-tz.c | 121 |
1 files changed, 97 insertions, 24 deletions
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index 82b1d02..f5f0b0e 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -15,6 +15,7 @@ * as seen by the guest depend significantly on the FPGA image. * This source file covers the following FPGA images, for TrustZone cores: * "mps2-an505" -- Cortex-M33 as documented in ARM Application Note AN505 + * "mps2-an521" -- Dual Cortex-M33 as documented in Application Note AN521 * * Links to the TRM for the board itself and to the various Application * Notes which document the FPGA images can be found here: @@ -24,10 +25,16 @@ * http://infocenter.arm.com/help/topic/com.arm.doc.100112_0200_06_en/versatile_express_cortex_m_prototyping_systems_v2m_mps2_and_v2m_mps2plus_technical_reference_100112_0200_06_en.pdf * Application Note AN505: * http://infocenter.arm.com/help/topic/com.arm.doc.dai0505b/index.html + * Application Note AN521: + * http://infocenter.arm.com/help/topic/com.arm.doc.dai0521c/index.html * * 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: * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html + * Similarly, the AN521 uses the SSE-200, and the SSE-200 TRM defines + * most of the device layout: + * http://infocenter.arm.com/help/topic/com.arm.doc.101104_0100_00_en/corelink_sse200_subsystem_for_embedded_technical_reference_manual_101104_0100_00_en.pdf + * */ #include "qemu/osdep.h" @@ -46,27 +53,31 @@ #include "hw/misc/mps2-fpgaio.h" #include "hw/misc/tz-mpc.h" #include "hw/misc/tz-msc.h" -#include "hw/arm/iotkit.h" +#include "hw/arm/armsse.h" #include "hw/dma/pl080.h" #include "hw/ssi/pl022.h" #include "hw/devices.h" #include "net/net.h" #include "hw/core/split-irq.h" +#define MPS2TZ_NUMIRQ 92 + typedef enum MPS2TZFPGAType { FPGA_AN505, + FPGA_AN521, } MPS2TZFPGAType; typedef struct { MachineClass parent; MPS2TZFPGAType fpga_type; uint32_t scc_id; + const char *armsse_type; } MPS2TZMachineClass; typedef struct { MachineState parent; - IoTKit iotkit; + ARMSSE iotkit; MemoryRegion psram; MemoryRegion ssram[3]; MemoryRegion ssram1_m; @@ -85,10 +96,12 @@ typedef struct { SplitIRQ sec_resp_splitter; qemu_or_irq uart_irq_orgate; DeviceState *lan9118; + SplitIRQ cpu_irq_splitter[MPS2TZ_NUMIRQ]; } MPS2TZMachineState; #define TYPE_MPS2TZ_MACHINE "mps2tz" #define TYPE_MPS2TZ_AN505_MACHINE MACHINE_TYPE_NAME("mps2-an505") +#define TYPE_MPS2TZ_AN521_MACHINE MACHINE_TYPE_NAME("mps2-an521") #define MPS2TZ_MACHINE(obj) \ OBJECT_CHECK(MPS2TZMachineState, obj, TYPE_MPS2TZ_MACHINE) @@ -111,6 +124,23 @@ static void make_ram_alias(MemoryRegion *mr, const char *name, memory_region_add_subregion(get_system_memory(), base, mr); } +static qemu_irq get_sse_irq_in(MPS2TZMachineState *mms, int irqno) +{ + /* Return a qemu_irq which will signal IRQ n to all CPUs in the SSE. */ + MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); + + assert(irqno < MPS2TZ_NUMIRQ); + + switch (mmc->fpga_type) { + case FPGA_AN505: + return qdev_get_gpio_in_named(DEVICE(&mms->iotkit), "EXP_IRQ", irqno); + case FPGA_AN521: + return qdev_get_gpio_in(DEVICE(&mms->cpu_irq_splitter[irqno]), 0); + default: + g_assert_not_reached(); + } +} + /* Most of the devices in the AN505 FPGA image sit behind * Peripheral Protection Controllers. These data structures * define the layout of which devices sit behind which PPCs. @@ -161,7 +191,6 @@ static MemoryRegion *make_uart(MPS2TZMachineState *mms, void *opaque, int txirqno = i * 2 + 1; int combirqno = i + 10; SysBusDevice *s; - DeviceState *iotkitdev = DEVICE(&mms->iotkit); DeviceState *orgate_dev = DEVICE(&mms->uart_irq_orgate); sysbus_init_child_obj(OBJECT(mms), name, uart, sizeof(mms->uart[0]), @@ -170,14 +199,11 @@ static MemoryRegion *make_uart(MPS2TZMachineState *mms, void *opaque, qdev_prop_set_uint32(DEVICE(uart), "pclk-frq", SYSCLK_FRQ); object_property_set_bool(OBJECT(uart), true, "realized", &error_fatal); s = SYS_BUS_DEVICE(uart); - sysbus_connect_irq(s, 0, qdev_get_gpio_in_named(iotkitdev, - "EXP_IRQ", txirqno)); - sysbus_connect_irq(s, 1, qdev_get_gpio_in_named(iotkitdev, - "EXP_IRQ", rxirqno)); + sysbus_connect_irq(s, 0, get_sse_irq_in(mms, txirqno)); + sysbus_connect_irq(s, 1, get_sse_irq_in(mms, rxirqno)); sysbus_connect_irq(s, 2, qdev_get_gpio_in(orgate_dev, i * 2)); sysbus_connect_irq(s, 3, qdev_get_gpio_in(orgate_dev, i * 2 + 1)); - sysbus_connect_irq(s, 4, qdev_get_gpio_in_named(iotkitdev, - "EXP_IRQ", combirqno)); + sysbus_connect_irq(s, 4, get_sse_irq_in(mms, combirqno)); return sysbus_mmio_get_region(SYS_BUS_DEVICE(uart), 0); } @@ -213,7 +239,6 @@ static MemoryRegion *make_eth_dev(MPS2TZMachineState *mms, void *opaque, const char *name, hwaddr size) { SysBusDevice *s; - DeviceState *iotkitdev = DEVICE(&mms->iotkit); NICInfo *nd = &nd_table[0]; /* In hardware this is a LAN9220; the LAN9118 is software compatible @@ -225,7 +250,7 @@ static MemoryRegion *make_eth_dev(MPS2TZMachineState *mms, void *opaque, qdev_init_nofail(mms->lan9118); s = SYS_BUS_DEVICE(mms->lan9118); - sysbus_connect_irq(s, 0, qdev_get_gpio_in_named(iotkitdev, "EXP_IRQ", 16)); + sysbus_connect_irq(s, 0, get_sse_irq_in(mms, 16)); return sysbus_mmio_get_region(s, 0); } @@ -315,12 +340,9 @@ static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque, s = SYS_BUS_DEVICE(dma); /* Wire up DMACINTR, DMACINTERR, DMACINTTC */ - sysbus_connect_irq(s, 0, qdev_get_gpio_in_named(iotkitdev, - "EXP_IRQ", 58 + i * 3)); - sysbus_connect_irq(s, 1, qdev_get_gpio_in_named(iotkitdev, - "EXP_IRQ", 56 + i * 3)); - sysbus_connect_irq(s, 2, qdev_get_gpio_in_named(iotkitdev, - "EXP_IRQ", 57 + i * 3)); + sysbus_connect_irq(s, 0, get_sse_irq_in(mms, 58 + i * 3)); + sysbus_connect_irq(s, 1, get_sse_irq_in(mms, 56 + i * 3)); + sysbus_connect_irq(s, 2, get_sse_irq_in(mms, 57 + i * 3)); g_free(mscname); return sysbus_mmio_get_region(s, 0); @@ -339,21 +361,20 @@ static MemoryRegion *make_spi(MPS2TZMachineState *mms, void *opaque, */ PL022State *spi = opaque; int i = spi - &mms->spi[0]; - DeviceState *iotkitdev = DEVICE(&mms->iotkit); SysBusDevice *s; sysbus_init_child_obj(OBJECT(mms), name, spi, sizeof(mms->spi[0]), TYPE_PL022); object_property_set_bool(OBJECT(spi), true, "realized", &error_fatal); s = SYS_BUS_DEVICE(spi); - sysbus_connect_irq(s, 0, - qdev_get_gpio_in_named(iotkitdev, "EXP_IRQ", 51 + i)); + sysbus_connect_irq(s, 0, get_sse_irq_in(mms, 51 + i)); return sysbus_mmio_get_region(s, 0); } static void mps2tz_common_init(MachineState *machine) { MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine); + MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); MachineClass *mc = MACHINE_GET_CLASS(machine); MemoryRegion *system_memory = get_system_memory(); DeviceState *iotkitdev; @@ -367,15 +388,42 @@ static void mps2tz_common_init(MachineState *machine) } sysbus_init_child_obj(OBJECT(machine), "iotkit", &mms->iotkit, - sizeof(mms->iotkit), TYPE_IOTKIT); + sizeof(mms->iotkit), mmc->armsse_type); iotkitdev = DEVICE(&mms->iotkit); object_property_set_link(OBJECT(&mms->iotkit), OBJECT(system_memory), "memory", &error_abort); - qdev_prop_set_uint32(iotkitdev, "EXP_NUMIRQ", 92); + qdev_prop_set_uint32(iotkitdev, "EXP_NUMIRQ", MPS2TZ_NUMIRQ); qdev_prop_set_uint32(iotkitdev, "MAINCLK", SYSCLK_FRQ); object_property_set_bool(OBJECT(&mms->iotkit), true, "realized", &error_fatal); + /* + * The AN521 needs us to create splitters to feed the IRQ inputs + * for each CPU in the SSE-200 from each device in the board. + */ + if (mmc->fpga_type == FPGA_AN521) { + for (i = 0; i < MPS2TZ_NUMIRQ; i++) { + char *name = g_strdup_printf("mps2-irq-splitter%d", i); + SplitIRQ *splitter = &mms->cpu_irq_splitter[i]; + + object_initialize_child(OBJECT(machine), name, + splitter, sizeof(*splitter), + TYPE_SPLIT_IRQ, &error_fatal, NULL); + g_free(name); + + object_property_set_int(OBJECT(splitter), 2, "num-lines", + &error_fatal); + object_property_set_bool(OBJECT(splitter), true, "realized", + &error_fatal); + qdev_connect_gpio_out(DEVICE(splitter), 0, + qdev_get_gpio_in_named(DEVICE(&mms->iotkit), + "EXP_IRQ", i)); + qdev_connect_gpio_out(DEVICE(splitter), 1, + qdev_get_gpio_in_named(DEVICE(&mms->iotkit), + "EXP_CPU1_IRQ", i)); + } + } + /* The sec_resp_cfg output from the IoTKit must be split into multiple * lines, one for each of the PPCs we create here, plus one per MSC. */ @@ -426,7 +474,7 @@ static void mps2tz_common_init(MachineState *machine) object_property_set_bool(OBJECT(&mms->uart_irq_orgate), true, "realized", &error_fatal); qdev_connect_gpio_out(DEVICE(&mms->uart_irq_orgate), 0, - qdev_get_gpio_in_named(iotkitdev, "EXP_IRQ", 15)); + get_sse_irq_in(mms, 15)); /* Most of the devices in the FPGA are behind Peripheral Protection * Controllers. The required order for initializing things is: @@ -593,7 +641,6 @@ static void mps2tz_class_init(ObjectClass *oc, void *data) IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(oc); mc->init = mps2tz_common_init; - mc->max_cpus = 1; iic->check = mps2_tz_idau_check; } @@ -603,9 +650,28 @@ static void mps2tz_an505_class_init(ObjectClass *oc, void *data) MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_CLASS(oc); mc->desc = "ARM MPS2 with AN505 FPGA image for Cortex-M33"; + mc->default_cpus = 1; + mc->min_cpus = mc->default_cpus; + mc->max_cpus = mc->default_cpus; mmc->fpga_type = FPGA_AN505; mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33"); mmc->scc_id = 0x41045050; + mmc->armsse_type = TYPE_IOTKIT; +} + +static void mps2tz_an521_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_CLASS(oc); + + mc->desc = "ARM MPS2 with AN521 FPGA image for dual Cortex-M33"; + mc->default_cpus = 2; + mc->min_cpus = mc->default_cpus; + mc->max_cpus = mc->default_cpus; + mmc->fpga_type = FPGA_AN521; + mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33"); + mmc->scc_id = 0x41045210; + mmc->armsse_type = TYPE_SSE200; } static const TypeInfo mps2tz_info = { @@ -627,10 +693,17 @@ static const TypeInfo mps2tz_an505_info = { .class_init = mps2tz_an505_class_init, }; +static const TypeInfo mps2tz_an521_info = { + .name = TYPE_MPS2TZ_AN521_MACHINE, + .parent = TYPE_MPS2TZ_MACHINE, + .class_init = mps2tz_an521_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_init(mps2tz_machine_init); |