aboutsummaryrefslogtreecommitdiff
path: root/hw/arm
diff options
context:
space:
mode:
Diffstat (limited to 'hw/arm')
-rw-r--r--hw/arm/Makefile.objs1
-rw-r--r--hw/arm/armsse.c121
-rw-r--r--hw/arm/aspeed.c2
-rw-r--r--hw/arm/musca.c669
-rw-r--r--hw/arm/pxa2xx.c2
-rw-r--r--hw/arm/stellaris.c2
-rw-r--r--hw/arm/tosa.c4
-rw-r--r--hw/arm/z2.c2
8 files changed, 758 insertions, 45 deletions
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index fa40e8d641..fa57c7c770 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -35,6 +35,7 @@ obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o
obj-$(CONFIG_MPS2) += mps2.o
obj-$(CONFIG_MPS2) += mps2-tz.o
obj-$(CONFIG_MSF2) += msf2-soc.o msf2-som.o
+obj-$(CONFIG_MUSCA) += musca.o
obj-$(CONFIG_ARMSSE) += armsse.o
obj-$(CONFIG_FSL_IMX7) += fsl-imx7.o mcimx7d-sabre.o
obj-$(CONFIG_ARM_SMMUV3) += smmu-common.o smmuv3.o
diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c
index 9a8c49547d..76cc690579 100644
--- a/hw/arm/armsse.c
+++ b/hw/arm/armsse.c
@@ -11,6 +11,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
+#include "qemu/bitops.h"
#include "qapi/error.h"
#include "trace.h"
#include "hw/sysbus.h"
@@ -29,6 +30,7 @@ struct ARMSSEInfo {
int sram_banks;
int num_cpus;
uint32_t sys_version;
+ uint32_t cpuwait_rst;
SysConfigFormat sys_config_format;
bool has_mhus;
bool has_ppus;
@@ -43,6 +45,7 @@ static const ARMSSEInfo armsse_variants[] = {
.sram_banks = 1,
.num_cpus = 1,
.sys_version = 0x41743,
+ .cpuwait_rst = 0,
.sys_config_format = IoTKitFormat,
.has_mhus = false,
.has_ppus = false,
@@ -55,6 +58,7 @@ static const ARMSSEInfo armsse_variants[] = {
.sram_banks = 4,
.num_cpus = 2,
.sys_version = 0x22041743,
+ .cpuwait_rst = 2,
.sys_config_format = SSE200Format,
.has_mhus = true,
.has_ppus = true,
@@ -110,15 +114,16 @@ static bool irq_is_common[32] = {
/* 30, 31: reserved */
};
-/* Create an alias region of @size bytes starting at @base
+/*
+ * Create an alias region in @container of @size bytes starting at @base
* which mirrors the memory starting at @orig.
*/
-static void make_alias(ARMSSE *s, MemoryRegion *mr, const char *name,
- hwaddr base, hwaddr size, hwaddr orig)
+static void make_alias(ARMSSE *s, MemoryRegion *mr, MemoryRegion *container,
+ const char *name, hwaddr base, hwaddr size, hwaddr orig)
{
- memory_region_init_alias(mr, NULL, name, &s->container, orig, size);
+ memory_region_init_alias(mr, NULL, name, container, orig, size);
/* The alias is even lower priority than unimplemented_device regions */
- memory_region_add_subregion_overlap(&s->container, base, mr, -1500);
+ memory_region_add_subregion_overlap(container, base, mr, -1500);
}
static void irq_status_forwarder(void *opaque, int n, int level)
@@ -281,9 +286,9 @@ static void armsse_init(Object *obj)
sizeof(s->sysinfo), TYPE_IOTKIT_SYSINFO);
if (info->has_mhus) {
sysbus_init_child_obj(obj, "mhu0", &s->mhu[0], sizeof(s->mhu[0]),
- TYPE_UNIMPLEMENTED_DEVICE);
+ TYPE_ARMSSE_MHU);
sysbus_init_child_obj(obj, "mhu1", &s->mhu[1], sizeof(s->mhu[1]),
- TYPE_UNIMPLEMENTED_DEVICE);
+ TYPE_ARMSSE_MHU);
}
if (info->has_ppus) {
for (i = 0; i < info->num_cpus; i++) {
@@ -494,31 +499,33 @@ static void armsse_realize(DeviceState *dev, Error **errp)
qdev_prop_set_uint32(cpudev, "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.
- * In SSE-200 the situation is similar, except that the default value
- * is a reset-time signal input. Typically a board using the SSE-200
- * will have a system control processor whose boot firmware initializes
- * the INITSVTOR* registers before powering up the CPUs in any case,
- * so the hardware's default value doesn't matter. QEMU doesn't emulate
+ * In real hardware the initial Secure VTOR is set from the INITSVTOR*
+ * registers in the IoT Kit System Control Register block. In QEMU
+ * we set the initial value here, and also the reset value of the
+ * sysctl register, from this object's QOM init-svtor property.
+ * If the guest changes the INITSVTOR* registers at runtime then the
+ * code in iotkit-sysctl.c will update the CPU init-svtor property
+ * (which will then take effect on the next CPU warm-reset).
+ *
+ * Note that typically a board using the SSE-200 will have a system
+ * control processor whose boot firmware initializes the INITSVTOR*
+ * registers before powering up the CPUs. QEMU doesn't emulate
* the control processor, so instead we behave in the way that the
- * firmware does. All boards currently known about have firmware that
- * sets the INITSVTOR0 and INITSVTOR1 registers to 0x10000000, like the
- * IoTKit default. We can make this more configurable if necessary.
+ * firmware does: the initial value should be set by the board code
+ * (using the init-svtor property on the ARMSSE object) to match
+ * whatever its firmware does.
*/
- qdev_prop_set_uint32(cpudev, "init-svtor", 0x10000000);
+ qdev_prop_set_uint32(cpudev, "init-svtor", s->init_svtor);
/*
- * Start all CPUs except CPU0 powered down. In real hardware it is
- * a configurable property of the SSE-200 which CPUs start powered up
- * (via the CPUWAIT0_RST and CPUWAIT1_RST parameters), but since all
- * the boards we care about start CPU0 and leave CPU1 powered off,
- * we hard-code that for now. We can add QOM properties for this
+ * CPUs start powered down if the corresponding bit in the CPUWAIT
+ * register is 1. In real hardware the CPUWAIT register reset value is
+ * a configurable property of the SSE-200 (via the CPUWAIT0_RST and
+ * CPUWAIT1_RST parameters), but since all the boards we care about
+ * start CPU0 and leave CPU1 powered off, we hard-code that in
+ * info->cpuwait_rst for now. We can add QOM properties for this
* later if necessary.
*/
- if (i > 0) {
+ if (extract32(info->cpuwait_rst, i, 1)) {
object_property_set_bool(cpuobj, true, "start-powered-off", &err);
if (err) {
error_propagate(errp, err);
@@ -608,16 +615,21 @@ static void armsse_realize(DeviceState *dev, Error **errp)
}
/* 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);
+ make_alias(s, &s->alias1, &s->container, "alias 1",
+ 0x10000000, 0x10000000, 0x00000000);
+ make_alias(s, &s->alias2, &s->container,
+ "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.
+ * alias MR at a higher priority. Some of the devices in this range
+ * are per-CPU, so we must put this alias in the per-cpu containers.
*/
- make_alias(s, &s->alias3, "alias 3", 0x50000000, 0x10000000, 0x40000000);
-
+ for (i = 0; i < info->num_cpus; i++) {
+ make_alias(s, &s->alias3[i], &s->cpu_container[i],
+ "alias 3", 0x50000000, 0x10000000, 0x40000000);
+ }
/* Security controller */
object_property_set_bool(OBJECT(&s->secctl), true, "realized", &err);
@@ -761,27 +773,49 @@ static void armsse_realize(DeviceState *dev, Error **errp)
}
if (info->has_mhus) {
+ /*
+ * An SSE-200 with only one CPU should have only one MHU created,
+ * with the region where the second MHU usually is being RAZ/WI.
+ * We don't implement that SSE-200 config; if we want to support
+ * it then this code needs to be enhanced to handle creating the
+ * RAZ/WI region instead of the second MHU.
+ */
+ assert(info->num_cpus == ARRAY_SIZE(s->mhu));
+
for (i = 0; i < ARRAY_SIZE(s->mhu); i++) {
- char *name = g_strdup_printf("MHU%d", i);
- char *port = g_strdup_printf("port[%d]", i + 3);
+ char *port;
+ int cpunum;
+ SysBusDevice *mhu_sbd = SYS_BUS_DEVICE(&s->mhu[i]);
- qdev_prop_set_string(DEVICE(&s->mhu[i]), "name", name);
- qdev_prop_set_uint64(DEVICE(&s->mhu[i]), "size", 0x1000);
object_property_set_bool(OBJECT(&s->mhu[i]), true,
"realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
- mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mhu[i]), 0);
+ port = g_strdup_printf("port[%d]", i + 3);
+ mr = sysbus_mmio_get_region(mhu_sbd, 0);
object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr),
port, &err);
+ g_free(port);
if (err) {
error_propagate(errp, err);
return;
}
- g_free(name);
- g_free(port);
+
+ /*
+ * Each MHU has an irq line for each CPU:
+ * MHU 0 irq line 0 -> CPU 0 IRQ 6
+ * MHU 0 irq line 1 -> CPU 1 IRQ 6
+ * MHU 1 irq line 0 -> CPU 0 IRQ 7
+ * MHU 1 irq line 1 -> CPU 1 IRQ 7
+ */
+ for (cpunum = 0; cpunum < info->num_cpus; cpunum++) {
+ DeviceState *cpudev = DEVICE(&s->armv7m[cpunum]);
+
+ sysbus_connect_irq(mhu_sbd, cpunum,
+ qdev_get_gpio_in(cpudev, 6 + i));
+ }
}
}
@@ -970,6 +1004,14 @@ static void armsse_realize(DeviceState *dev, Error **errp)
/* System information registers */
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysinfo), 0, 0x40020000);
/* System control registers */
+ object_property_set_int(OBJECT(&s->sysctl), info->sys_version,
+ "SYS_VERSION", &err);
+ object_property_set_int(OBJECT(&s->sysctl), info->cpuwait_rst,
+ "CPUWAIT_RST", &err);
+ object_property_set_int(OBJECT(&s->sysctl), s->init_svtor,
+ "INITSVTOR0_RST", &err);
+ object_property_set_int(OBJECT(&s->sysctl), s->init_svtor,
+ "INITSVTOR1_RST", &err);
object_property_set_bool(OBJECT(&s->sysctl), true, "realized", &err);
if (err) {
error_propagate(errp, err);
@@ -1185,6 +1227,7 @@ static Property armsse_properties[] = {
DEFINE_PROP_UINT32("EXP_NUMIRQ", ARMSSE, exp_numirq, 64),
DEFINE_PROP_UINT32("MAINCLK", ARMSSE, mainclk_frq, 0),
DEFINE_PROP_UINT32("SRAM_ADDR_WIDTH", ARMSSE, sram_addr_width, 15),
+ DEFINE_PROP_UINT32("init-svtor", ARMSSE, init_svtor, 0x10000000),
DEFINE_PROP_END_OF_LIST()
};
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index 5158985482..996812498d 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -18,7 +18,7 @@
#include "hw/arm/aspeed.h"
#include "hw/arm/aspeed_soc.h"
#include "hw/boards.h"
-#include "hw/i2c/smbus.h"
+#include "hw/i2c/smbus_eeprom.h"
#include "qemu/log.h"
#include "sysemu/block-backend.h"
#include "hw/loader.h"
diff --git a/hw/arm/musca.c b/hw/arm/musca.c
new file mode 100644
index 0000000000..23aff43f4b
--- /dev/null
+++ b/hw/arm/musca.c
@@ -0,0 +1,669 @@
+/*
+ * Arm Musca-B1 test chip board emulation
+ *
+ * Copyright (c) 2019 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.
+ */
+
+/*
+ * The Musca boards are a reference implementation of a system using
+ * the SSE-200 subsystem for embedded:
+ * https://developer.arm.com/products/system-design/development-boards/iot-test-chips-and-boards/musca-a-test-chip-board
+ * https://developer.arm.com/products/system-design/development-boards/iot-test-chips-and-boards/musca-b-test-chip-board
+ * We model the A and B1 variants of this board, as described in the TRMs:
+ * http://infocenter.arm.com/help/topic/com.arm.doc.101107_0000_00_en/index.html
+ * http://infocenter.arm.com/help/topic/com.arm.doc.101312_0000_00_en/index.html
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "exec/address-spaces.h"
+#include "sysemu/sysemu.h"
+#include "hw/arm/arm.h"
+#include "hw/arm/armsse.h"
+#include "hw/boards.h"
+#include "hw/char/pl011.h"
+#include "hw/core/split-irq.h"
+#include "hw/misc/tz-mpc.h"
+#include "hw/misc/tz-ppc.h"
+#include "hw/misc/unimp.h"
+#include "hw/timer/pl031.h"
+
+#define MUSCA_NUMIRQ_MAX 96
+#define MUSCA_PPC_MAX 3
+#define MUSCA_MPC_MAX 5
+
+typedef struct MPCInfo MPCInfo;
+
+typedef enum MuscaType {
+ MUSCA_A,
+ MUSCA_B1,
+} MuscaType;
+
+typedef struct {
+ MachineClass parent;
+ MuscaType type;
+ uint32_t init_svtor;
+ int sram_addr_width;
+ int num_irqs;
+ const MPCInfo *mpc_info;
+ int num_mpcs;
+} MuscaMachineClass;
+
+typedef struct {
+ MachineState parent;
+
+ ARMSSE sse;
+ /* RAM and flash */
+ MemoryRegion ram[MUSCA_MPC_MAX];
+ SplitIRQ cpu_irq_splitter[MUSCA_NUMIRQ_MAX];
+ SplitIRQ sec_resp_splitter;
+ TZPPC ppc[MUSCA_PPC_MAX];
+ MemoryRegion container;
+ UnimplementedDeviceState eflash[2];
+ UnimplementedDeviceState qspi;
+ TZMPC mpc[MUSCA_MPC_MAX];
+ UnimplementedDeviceState mhu[2];
+ UnimplementedDeviceState pwm[3];
+ UnimplementedDeviceState i2s;
+ PL011State uart[2];
+ UnimplementedDeviceState i2c[2];
+ UnimplementedDeviceState spi;
+ UnimplementedDeviceState scc;
+ UnimplementedDeviceState timer;
+ PL031State rtc;
+ UnimplementedDeviceState pvt;
+ UnimplementedDeviceState sdio;
+ UnimplementedDeviceState gpio;
+ UnimplementedDeviceState cryptoisland;
+} MuscaMachineState;
+
+#define TYPE_MUSCA_MACHINE "musca"
+#define TYPE_MUSCA_A_MACHINE MACHINE_TYPE_NAME("musca-a")
+#define TYPE_MUSCA_B1_MACHINE MACHINE_TYPE_NAME("musca-b1")
+
+#define MUSCA_MACHINE(obj) \
+ OBJECT_CHECK(MuscaMachineState, obj, TYPE_MUSCA_MACHINE)
+#define MUSCA_MACHINE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(MuscaMachineClass, obj, TYPE_MUSCA_MACHINE)
+#define MUSCA_MACHINE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(MuscaMachineClass, klass, TYPE_MUSCA_MACHINE)
+
+/*
+ * Main SYSCLK frequency in Hz
+ * TODO this should really be different for the two cores, but we
+ * don't model that in our SSE-200 model yet.
+ */
+#define SYSCLK_FRQ 40000000
+
+static qemu_irq get_sse_irq_in(MuscaMachineState *mms, int irqno)
+{
+ /* Return a qemu_irq which will signal IRQ n to all CPUs in the SSE. */
+ assert(irqno < MUSCA_NUMIRQ_MAX);
+
+ return qdev_get_gpio_in(DEVICE(&mms->cpu_irq_splitter[irqno]), 0);
+}
+
+/*
+ * Most of the devices in the Musca board sit behind Peripheral Protection
+ * Controllers. These data structures define the layout of which devices
+ * sit behind which PPCs.
+ * The devfn for each port is a function which creates, configures
+ * and initializes the device, returning the MemoryRegion which
+ * needs to be plugged into the downstream end of the PPC port.
+ */
+typedef MemoryRegion *MakeDevFn(MuscaMachineState *mms, void *opaque,
+ const char *name, hwaddr size);
+
+typedef struct PPCPortInfo {
+ const char *name;
+ MakeDevFn *devfn;
+ void *opaque;
+ hwaddr addr;
+ hwaddr size;
+} PPCPortInfo;
+
+typedef struct PPCInfo {
+ const char *name;
+ PPCPortInfo ports[TZ_NUM_PORTS];
+} PPCInfo;
+
+static MemoryRegion *make_unimp_dev(MuscaMachineState *mms,
+ void *opaque, const char *name, hwaddr size)
+{
+ /*
+ * Initialize, configure and realize a TYPE_UNIMPLEMENTED_DEVICE,
+ * and return a pointer to its MemoryRegion.
+ */
+ UnimplementedDeviceState *uds = opaque;
+
+ sysbus_init_child_obj(OBJECT(mms), name, uds,
+ sizeof(UnimplementedDeviceState),
+ TYPE_UNIMPLEMENTED_DEVICE);
+ qdev_prop_set_string(DEVICE(uds), "name", name);
+ qdev_prop_set_uint64(DEVICE(uds), "size", size);
+ object_property_set_bool(OBJECT(uds), true, "realized", &error_fatal);
+ return sysbus_mmio_get_region(SYS_BUS_DEVICE(uds), 0);
+}
+
+typedef enum MPCInfoType {
+ MPC_RAM,
+ MPC_ROM,
+ MPC_CRYPTOISLAND,
+} MPCInfoType;
+
+struct MPCInfo {
+ const char *name;
+ hwaddr addr;
+ hwaddr size;
+ MPCInfoType type;
+};
+
+/* Order of the MPCs here must match the order of the bits in SECMPCINTSTATUS */
+static const MPCInfo a_mpc_info[] = { {
+ .name = "qspi",
+ .type = MPC_ROM,
+ .addr = 0x00200000,
+ .size = 0x00800000,
+ }, {
+ .name = "sram",
+ .type = MPC_RAM,
+ .addr = 0x00000000,
+ .size = 0x00200000,
+ }
+};
+
+static const MPCInfo b1_mpc_info[] = { {
+ .name = "qspi",
+ .type = MPC_ROM,
+ .addr = 0x00000000,
+ .size = 0x02000000,
+ }, {
+ .name = "sram",
+ .type = MPC_RAM,
+ .addr = 0x0a400000,
+ .size = 0x00080000,
+ }, {
+ .name = "eflash0",
+ .type = MPC_ROM,
+ .addr = 0x0a000000,
+ .size = 0x00200000,
+ }, {
+ .name = "eflash1",
+ .type = MPC_ROM,
+ .addr = 0x0a200000,
+ .size = 0x00200000,
+ }, {
+ .name = "cryptoisland",
+ .type = MPC_CRYPTOISLAND,
+ .addr = 0x0a000000,
+ .size = 0x00200000,
+ }
+};
+
+static MemoryRegion *make_mpc(MuscaMachineState *mms, void *opaque,
+ const char *name, hwaddr size)
+{
+ /*
+ * Create an MPC and the RAM or flash behind it.
+ * MPC 0: eFlash 0
+ * MPC 1: eFlash 1
+ * MPC 2: SRAM
+ * MPC 3: QSPI flash
+ * MPC 4: CryptoIsland
+ * For now we implement the flash regions as ROM (ie not programmable)
+ * (with their control interface memory regions being unimplemented
+ * stubs behind the PPCs).
+ * The whole CryptoIsland region behind its MPC is an unimplemented stub.
+ */
+ MuscaMachineClass *mmc = MUSCA_MACHINE_GET_CLASS(mms);
+ TZMPC *mpc = opaque;
+ int i = mpc - &mms->mpc[0];
+ MemoryRegion *downstream;
+ MemoryRegion *upstream;
+ UnimplementedDeviceState *uds;
+ char *mpcname;
+ const MPCInfo *mpcinfo = mmc->mpc_info;
+
+ mpcname = g_strdup_printf("%s-mpc", mpcinfo[i].name);
+
+ switch (mpcinfo[i].type) {
+ case MPC_ROM:
+ downstream = &mms->ram[i];
+ memory_region_init_rom(downstream, NULL, mpcinfo[i].name,
+ mpcinfo[i].size, &error_fatal);
+ break;
+ case MPC_RAM:
+ downstream = &mms->ram[i];
+ memory_region_init_ram(downstream, NULL, mpcinfo[i].name,
+ mpcinfo[i].size, &error_fatal);
+ break;
+ case MPC_CRYPTOISLAND:
+ /* We don't implement the CryptoIsland yet */
+ uds = &mms->cryptoisland;
+ sysbus_init_child_obj(OBJECT(mms), name, uds,
+ sizeof(UnimplementedDeviceState),
+ TYPE_UNIMPLEMENTED_DEVICE);
+ qdev_prop_set_string(DEVICE(uds), "name", mpcinfo[i].name);
+ qdev_prop_set_uint64(DEVICE(uds), "size", mpcinfo[i].size);
+ object_property_set_bool(OBJECT(uds), true, "realized", &error_fatal);
+ downstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(uds), 0);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ sysbus_init_child_obj(OBJECT(mms), mpcname, mpc, sizeof(mms->mpc[0]),
+ TYPE_TZ_MPC);
+ object_property_set_link(OBJECT(mpc), OBJECT(downstream),
+ "downstream", &error_fatal);
+ object_property_set_bool(OBJECT(mpc), true, "realized", &error_fatal);
+ /* Map the upstream end of the MPC into system memory */
+ upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 1);
+ memory_region_add_subregion(get_system_memory(), mpcinfo[i].addr, upstream);
+ /* and connect its interrupt to the SSE-200 */
+ qdev_connect_gpio_out_named(DEVICE(mpc), "irq", 0,
+ qdev_get_gpio_in_named(DEVICE(&mms->sse),
+ "mpcexp_status", i));
+
+ g_free(mpcname);
+ /* Return the register interface MR for our caller to map behind the PPC */
+ return sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 0);
+}
+
+static MemoryRegion *make_rtc(MuscaMachineState *mms, void *opaque,
+ const char *name, hwaddr size)
+{
+ PL031State *rtc = opaque;
+
+ sysbus_init_child_obj(OBJECT(mms), name, rtc, sizeof(mms->rtc), TYPE_PL031);
+ object_property_set_bool(OBJECT(rtc), true, "realized", &error_fatal);
+ sysbus_connect_irq(SYS_BUS_DEVICE(rtc), 0, get_sse_irq_in(mms, 39));
+ return sysbus_mmio_get_region(SYS_BUS_DEVICE(rtc), 0);
+}
+
+static MemoryRegion *make_uart(MuscaMachineState *mms, void *opaque,
+ const char *name, hwaddr size)
+{
+ PL011State *uart = opaque;
+ int i = uart - &mms->uart[0];
+ int irqbase = 7 + i * 6;
+ SysBusDevice *s;
+
+ sysbus_init_child_obj(OBJECT(mms), name, uart, sizeof(mms->uart[0]),
+ TYPE_PL011);
+ qdev_prop_set_chr(DEVICE(uart), "chardev", serial_hd(i));
+ object_property_set_bool(OBJECT(uart), true, "realized", &error_fatal);
+ s = SYS_BUS_DEVICE(uart);
+ sysbus_connect_irq(s, 0, get_sse_irq_in(mms, irqbase + 5)); /* combined */
+ sysbus_connect_irq(s, 1, get_sse_irq_in(mms, irqbase + 0)); /* RX */
+ sysbus_connect_irq(s, 2, get_sse_irq_in(mms, irqbase + 1)); /* TX */
+ sysbus_connect_irq(s, 3, get_sse_irq_in(mms, irqbase + 2)); /* RT */
+ sysbus_connect_irq(s, 4, get_sse_irq_in(mms, irqbase + 3)); /* MS */
+ sysbus_connect_irq(s, 5, get_sse_irq_in(mms, irqbase + 4)); /* E */
+ return sysbus_mmio_get_region(SYS_BUS_DEVICE(uart), 0);
+}
+
+static MemoryRegion *make_musca_a_devs(MuscaMachineState *mms, void *opaque,
+ const char *name, hwaddr size)
+{
+ /*
+ * Create the container MemoryRegion for all the devices that live
+ * behind the Musca-A PPC's single port. These devices don't have a PPC
+ * port each, but we use the PPCPortInfo struct as a convenient way
+ * to describe them. Note that addresses here are relative to the base
+ * address of the PPC port region: 0x40100000, and devices appear both
+ * at the 0x4... NS region and the 0x5... S region.
+ */
+ int i;
+ MemoryRegion *container = &mms->container;
+
+ const PPCPortInfo devices[] = {
+ { "uart0", make_uart, &mms->uart[0], 0x1000, 0x1000 },
+ { "uart1", make_uart, &mms->uart[1], 0x2000, 0x1000 },
+ { "spi", make_unimp_dev, &mms->spi, 0x3000, 0x1000 },
+ { "i2c0", make_unimp_dev, &mms->i2c[0], 0x4000, 0x1000 },
+ { "i2c1", make_unimp_dev, &mms->i2c[1], 0x5000, 0x1000 },
+ { "i2s", make_unimp_dev, &mms->i2s, 0x6000, 0x1000 },
+ { "pwm0", make_unimp_dev, &mms->pwm[0], 0x7000, 0x1000 },
+ { "rtc", make_rtc, &mms->rtc, 0x8000, 0x1000 },
+ { "qspi", make_unimp_dev, &mms->qspi, 0xa000, 0x1000 },
+ { "timer", make_unimp_dev, &mms->timer, 0xb000, 0x1000 },
+ { "scc", make_unimp_dev, &mms->scc, 0xc000, 0x1000 },
+ { "pwm1", make_unimp_dev, &mms->pwm[1], 0xe000, 0x1000 },
+ { "pwm2", make_unimp_dev, &mms->pwm[2], 0xf000, 0x1000 },
+ { "gpio", make_unimp_dev, &mms->gpio, 0x10000, 0x1000 },
+ { "mpc0", make_mpc, &mms->mpc[0], 0x12000, 0x1000 },
+ { "mpc1", make_mpc, &mms->mpc[1], 0x13000, 0x1000 },
+ };
+
+ memory_region_init(container, OBJECT(mms), "musca-device-container", size);
+
+ for (i = 0; i < ARRAY_SIZE(devices); i++) {
+ const PPCPortInfo *pinfo = &devices[i];
+ MemoryRegion *mr;
+
+ mr = pinfo->devfn(mms, pinfo->opaque, pinfo->name, pinfo->size);
+ memory_region_add_subregion(container, pinfo->addr, mr);
+ }
+
+ return &mms->container;
+}
+
+static void musca_init(MachineState *machine)
+{
+ MuscaMachineState *mms = MUSCA_MACHINE(machine);
+ MuscaMachineClass *mmc = MUSCA_MACHINE_GET_CLASS(mms);
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
+ MemoryRegion *system_memory = get_system_memory();
+ DeviceState *ssedev;
+ DeviceState *dev_splitter;
+ const PPCInfo *ppcs;
+ int num_ppcs;
+ int i;
+
+ assert(mmc->num_irqs <= MUSCA_NUMIRQ_MAX);
+ assert(mmc->num_mpcs <= MUSCA_MPC_MAX);
+
+ if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
+ error_report("This board can only be used with CPU %s",
+ mc->default_cpu_type);
+ exit(1);
+ }
+
+ sysbus_init_child_obj(OBJECT(machine), "sse-200", &mms->sse,
+ sizeof(mms->sse), TYPE_SSE200);
+ ssedev = DEVICE(&mms->sse);
+ object_property_set_link(OBJECT(&mms->sse), OBJECT(system_memory),
+ "memory", &error_fatal);
+ qdev_prop_set_uint32(ssedev, "EXP_NUMIRQ", mmc->num_irqs);
+ qdev_prop_set_uint32(ssedev, "init-svtor", mmc->init_svtor);
+ qdev_prop_set_uint32(ssedev, "SRAM_ADDR_WIDTH", mmc->sram_addr_width);
+ qdev_prop_set_uint32(ssedev, "MAINCLK", SYSCLK_FRQ);
+ object_property_set_bool(OBJECT(&mms->sse), true, "realized",
+ &error_fatal);
+
+ /*
+ * We need to create splitters to feed the IRQ inputs
+ * for each CPU in the SSE-200 from each device in the board.
+ */
+ for (i = 0; i < mmc->num_irqs; i++) {
+ char *name = g_strdup_printf("musca-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(ssedev, "EXP_IRQ", i));
+ qdev_connect_gpio_out(DEVICE(splitter), 1,
+ qdev_get_gpio_in_named(ssedev,
+ "EXP_CPU1_IRQ", i));
+ }
+
+ /*
+ * The sec_resp_cfg output from the SSE-200 must be split into multiple
+ * lines, one for each of the PPCs we create here.
+ */
+ object_initialize(&mms->sec_resp_splitter, sizeof(mms->sec_resp_splitter),
+ TYPE_SPLIT_IRQ);
+ object_property_add_child(OBJECT(machine), "sec-resp-splitter",
+ OBJECT(&mms->sec_resp_splitter), &error_fatal);
+ object_property_set_int(OBJECT(&mms->sec_resp_splitter),
+ ARRAY_SIZE(mms->ppc), "num-lines", &error_fatal);
+ object_property_set_bool(OBJECT(&mms->sec_resp_splitter), true,
+ "realized", &error_fatal);
+ dev_splitter = DEVICE(&mms->sec_resp_splitter);
+ qdev_connect_gpio_out_named(ssedev, "sec_resp_cfg", 0,
+ qdev_get_gpio_in(dev_splitter, 0));
+
+ /*
+ * Most of the devices in the board are behind Peripheral Protection
+ * Controllers. The required order for initializing things is:
+ * + initialize the PPC
+ * + initialize, configure and realize downstream devices
+ * + connect downstream device MemoryRegions to the PPC
+ * + realize the PPC
+ * + map the PPC's MemoryRegions to the places in the address map
+ * where the downstream devices should appear
+ * + wire up the PPC's control lines to the SSE object
+ *
+ * The PPC mapping differs for the -A and -B1 variants; the -A version
+ * is much simpler, using only a single port of a single PPC and putting
+ * all the devices behind that.
+ */
+ const PPCInfo a_ppcs[] = { {
+ .name = "ahb_ppcexp0",
+ .ports = {
+ { "musca-devices", make_musca_a_devs, 0, 0x40100000, 0x100000 },
+ },
+ },
+ };
+
+ /*
+ * Devices listed with an 0x4.. address appear in both the NS 0x4.. region
+ * and the 0x5.. S region. Devices listed with an 0x5.. address appear
+ * only in the S region.
+ */
+ const PPCInfo b1_ppcs[] = { {
+ .name = "apb_ppcexp0",
+ .ports = {
+ { "eflash0", make_unimp_dev, &mms->eflash[0],
+ 0x52400000, 0x1000 },
+ { "eflash1", make_unimp_dev, &mms->eflash[1],
+ 0x52500000, 0x1000 },
+ { "qspi", make_unimp_dev, &mms->qspi, 0x42800000, 0x100000 },
+ { "mpc0", make_mpc, &mms->mpc[0], 0x52000000, 0x1000 },
+ { "mpc1", make_mpc, &mms->mpc[1], 0x52100000, 0x1000 },
+ { "mpc2", make_mpc, &mms->mpc[2], 0x52200000, 0x1000 },
+ { "mpc3", make_mpc, &mms->mpc[3], 0x52300000, 0x1000 },
+ { "mhu0", make_unimp_dev, &mms->mhu[0], 0x42600000, 0x100000 },
+ { "mhu1", make_unimp_dev, &mms->mhu[1], 0x42700000, 0x100000 },
+ { }, /* port 9: unused */
+ { }, /* port 10: unused */
+ { }, /* port 11: unused */
+ { }, /* port 12: unused */
+ { }, /* port 13: unused */
+ { "mpc4", make_mpc, &mms->mpc[4], 0x52e00000, 0x1000 },
+ },
+ }, {
+ .name = "apb_ppcexp1",
+ .ports = {
+ { "pwm0", make_unimp_dev, &mms->pwm[0], 0x40101000, 0x1000 },
+ { "pwm1", make_unimp_dev, &mms->pwm[1], 0x40102000, 0x1000 },
+ { "pwm2", make_unimp_dev, &mms->pwm[2], 0x40103000, 0x1000 },
+ { "i2s", make_unimp_dev, &mms->i2s, 0x40104000, 0x1000 },
+ { "uart0", make_uart, &mms->uart[0], 0x40105000, 0x1000 },
+ { "uart1", make_uart, &mms->uart[1], 0x40106000, 0x1000 },
+ { "i2c0", make_unimp_dev, &mms->i2c[0], 0x40108000, 0x1000 },
+ { "i2c1", make_unimp_dev, &mms->i2c[1], 0x40109000, 0x1000 },
+ { "spi", make_unimp_dev, &mms->spi, 0x4010a000, 0x1000 },
+ { "scc", make_unimp_dev, &mms->scc, 0x5010b000, 0x1000 },
+ { "timer", make_unimp_dev, &mms->timer, 0x4010c000, 0x1000 },
+ { "rtc", make_rtc, &mms->rtc, 0x4010d000, 0x1000 },
+ { "pvt", make_unimp_dev, &mms->pvt, 0x4010e000, 0x1000 },
+ { "sdio", make_unimp_dev, &mms->sdio, 0x4010f000, 0x1000 },
+ },
+ }, {
+ .name = "ahb_ppcexp0",
+ .ports = {
+ { }, /* port 0: unused */
+ { "gpio", make_unimp_dev, &mms->gpio, 0x41000000, 0x1000 },
+ },
+ },
+ };
+
+ switch (mmc->type) {
+ case MUSCA_A:
+ ppcs = a_ppcs;
+ num_ppcs = ARRAY_SIZE(a_ppcs);
+ break;
+ case MUSCA_B1:
+ ppcs = b1_ppcs;
+ num_ppcs = ARRAY_SIZE(b1_ppcs);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ assert(num_ppcs <= MUSCA_PPC_MAX);
+
+ for (i = 0; i < num_ppcs; i++) {
+ const PPCInfo *ppcinfo = &ppcs[i];
+ TZPPC *ppc = &mms->ppc[i];
+ DeviceState *ppcdev;
+ int port;
+ char *gpioname;
+
+ sysbus_init_child_obj(OBJECT(machine), ppcinfo->name, ppc,
+ sizeof(TZPPC), TYPE_TZ_PPC);
+ ppcdev = DEVICE(ppc);
+
+ for (port = 0; port < TZ_NUM_PORTS; port++) {
+ const PPCPortInfo *pinfo = &ppcinfo->ports[port];
+ MemoryRegion *mr;
+ char *portname;
+
+ if (!pinfo->devfn) {
+ continue;
+ }
+
+ mr = pinfo->devfn(mms, pinfo->opaque, pinfo->name, pinfo->size);
+ portname = g_strdup_printf("port[%d]", port);
+ object_property_set_link(OBJECT(ppc), OBJECT(mr),
+ portname, &error_fatal);
+ g_free(portname);
+ }
+
+ object_property_set_bool(OBJECT(ppc), true, "realized", &error_fatal);
+
+ for (port = 0; port < TZ_NUM_PORTS; port++) {
+ const PPCPortInfo *pinfo = &ppcinfo->ports[port];
+
+ if (!pinfo->devfn) {
+ continue;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(ppc), port, pinfo->addr);
+
+ gpioname = g_strdup_printf("%s_nonsec", ppcinfo->name);
+ qdev_connect_gpio_out_named(ssedev, gpioname, port,
+ qdev_get_gpio_in_named(ppcdev,
+ "cfg_nonsec",
+ port));
+ g_free(gpioname);
+ gpioname = g_strdup_printf("%s_ap", ppcinfo->name);
+ qdev_connect_gpio_out_named(ssedev, gpioname, port,
+ qdev_get_gpio_in_named(ppcdev,
+ "cfg_ap", port));
+ g_free(gpioname);
+ }
+
+ gpioname = g_strdup_printf("%s_irq_enable", ppcinfo->name);
+ qdev_connect_gpio_out_named(ssedev, gpioname, 0,
+ qdev_get_gpio_in_named(ppcdev,
+ "irq_enable", 0));
+ g_free(gpioname);
+ gpioname = g_strdup_printf("%s_irq_clear", ppcinfo->name);
+ qdev_connect_gpio_out_named(ssedev, gpioname, 0,
+ qdev_get_gpio_in_named(ppcdev,
+ "irq_clear", 0));
+ g_free(gpioname);
+ gpioname = g_strdup_printf("%s_irq_status", ppcinfo->name);
+ qdev_connect_gpio_out_named(ppcdev, "irq", 0,
+ qdev_get_gpio_in_named(ssedev,
+ gpioname, 0));
+ g_free(gpioname);
+
+ qdev_connect_gpio_out(dev_splitter, i,
+ qdev_get_gpio_in_named(ppcdev,
+ "cfg_sec_resp", 0));
+ }
+
+ armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, 0x2000000);
+}
+
+static void musca_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->default_cpus = 2;
+ mc->min_cpus = mc->default_cpus;
+ mc->max_cpus = mc->default_cpus;
+ mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33");
+ mc->init = musca_init;
+}
+
+static void musca_a_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ MuscaMachineClass *mmc = MUSCA_MACHINE_CLASS(oc);
+
+ mc->desc = "ARM Musca-A board (dual Cortex-M33)";
+ mmc->type = MUSCA_A;
+ mmc->init_svtor = 0x10200000;
+ mmc->sram_addr_width = 15;
+ mmc->num_irqs = 64;
+ mmc->mpc_info = a_mpc_info;
+ mmc->num_mpcs = ARRAY_SIZE(a_mpc_info);
+}
+
+static void musca_b1_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ MuscaMachineClass *mmc = MUSCA_MACHINE_CLASS(oc);
+
+ mc->desc = "ARM Musca-B1 board (dual Cortex-M33)";
+ mmc->type = MUSCA_B1;
+ /*
+ * This matches the DAPlink firmware which boots from QSPI. There
+ * is also a firmware blob which boots from the eFlash, which
+ * uses init_svtor = 0x1A000000. QEMU doesn't currently support that,
+ * though we could in theory expose a machine property on the command
+ * line to allow the user to request eFlash boot.
+ */
+ mmc->init_svtor = 0x10000000;
+ mmc->sram_addr_width = 17;
+ mmc->num_irqs = 96;
+ mmc->mpc_info = b1_mpc_info;
+ mmc->num_mpcs = ARRAY_SIZE(b1_mpc_info);
+}
+
+static const TypeInfo musca_info = {
+ .name = TYPE_MUSCA_MACHINE,
+ .parent = TYPE_MACHINE,
+ .abstract = true,
+ .instance_size = sizeof(MuscaMachineState),
+ .class_size = sizeof(MuscaMachineClass),
+ .class_init = musca_class_init,
+};
+
+static const TypeInfo musca_a_info = {
+ .name = TYPE_MUSCA_A_MACHINE,
+ .parent = TYPE_MUSCA_MACHINE,
+ .class_init = musca_a_class_init,
+};
+
+static const TypeInfo musca_b1_info = {
+ .name = TYPE_MUSCA_B1_MACHINE,
+ .parent = TYPE_MUSCA_MACHINE,
+ .class_init = musca_b1_class_init,
+};
+
+static void musca_machine_init(void)
+{
+ type_register_static(&musca_info);
+ type_register_static(&musca_a_info);
+ type_register_static(&musca_b1_info);
+}
+
+type_init(musca_machine_init);
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index f598a1c053..3d7c88910e 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -1286,7 +1286,7 @@ static int pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
return 0;
}
-static int pxa2xx_i2c_rx(I2CSlave *i2c)
+static uint8_t pxa2xx_i2c_rx(I2CSlave *i2c)
{
PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c);
PXA2xxI2CState *s = slave->host;
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
index 442529cc65..7b45fe3ccf 100644
--- a/hw/arm/stellaris.c
+++ b/hw/arm/stellaris.c
@@ -811,7 +811,7 @@ static void stellaris_i2c_write(void *opaque, hwaddr offset,
/* TODO: Handle errors. */
if (s->msa & 1) {
/* Recv */
- s->mdr = i2c_recv(s->bus) & 0xff;
+ s->mdr = i2c_recv(s->bus);
} else {
/* Send */
i2c_send(s->bus, s->mdr);
diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c
index 7a925fa5e6..eef9d427e7 100644
--- a/hw/arm/tosa.c
+++ b/hw/arm/tosa.c
@@ -197,10 +197,10 @@ static int tosa_dac_event(I2CSlave *i2c, enum i2c_event event)
return 0;
}
-static int tosa_dac_recv(I2CSlave *s)
+static uint8_t tosa_dac_recv(I2CSlave *s)
{
printf("%s: recv not supported!!!\n", __func__);
- return -1;
+ return 0xff;
}
static void tosa_tg_init(PXA2xxState *cpu)
diff --git a/hw/arm/z2.c b/hw/arm/z2.c
index 697a822f1e..6f18d924df 100644
--- a/hw/arm/z2.c
+++ b/hw/arm/z2.c
@@ -243,7 +243,7 @@ static int aer915_event(I2CSlave *i2c, enum i2c_event event)
return 0;
}
-static int aer915_recv(I2CSlave *slave)
+static uint8_t aer915_recv(I2CSlave *slave)
{
AER915State *s = AER915(slave);
int retval = 0x00;