aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Brook <paul@codesourcery.com>2009-11-19 16:45:21 +0000
committerPaul Brook <paul@codesourcery.com>2009-11-19 16:45:21 +0000
commitf7c703250cef231085f07352b719bb91d71ea8a1 (patch)
tree8a511980622c574aba59fd41d320a94bf025b010
parent100555620f4c825c3d2d37ed4d8b921b4604c1f6 (diff)
ARM PBX-A9 board support
Implement ARM RealView PBX-A9 board support. Signed-off-by: Paul Brook <paul@codesourcery.com>
-rw-r--r--Makefile.target2
-rw-r--r--hw/a9mpcore.c29
-rw-r--r--hw/arm-misc.h1
-rw-r--r--hw/arm11mpcore.c112
-rw-r--r--hw/arm_boot.c7
-rw-r--r--hw/arm_gic.c2
-rw-r--r--hw/mpcore.c99
-rw-r--r--hw/realview.c65
-rw-r--r--qemu-doc.texi2
9 files changed, 209 insertions, 110 deletions
diff --git a/Makefile.target b/Makefile.target
index b9888f025f..ab774e529b 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -270,7 +270,7 @@ endif
obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
obj-arm-y += versatile_pci.o
-obj-arm-y += realview_gic.o realview.o arm_sysctl.o mpcore.o
+obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
obj-arm-y += pl061.o
obj-arm-y += arm-semi.o
diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c
new file mode 100644
index 0000000000..b5e5328395
--- /dev/null
+++ b/hw/a9mpcore.c
@@ -0,0 +1,29 @@
+/*
+ * Cortex-A9MPCore internal peripheral emulation.
+ *
+ * Copyright (c) 2009 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licenced under the GPL.
+ */
+
+/* 64 external IRQ lines. */
+#define GIC_NIRQ 96
+#include "mpcore.c"
+
+static SysBusDeviceInfo mpcore_priv_info = {
+ .init = mpcore_priv_init,
+ .qdev.name = "a9mpcore_priv",
+ .qdev.size = sizeof(mpcore_priv_state),
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static void a9mpcore_register_devices(void)
+{
+ sysbus_register_withprop(&mpcore_priv_info);
+}
+
+device_init(a9mpcore_register_devices)
diff --git a/hw/arm-misc.h b/hw/arm-misc.h
index e584073cb2..010acb4cf9 100644
--- a/hw/arm-misc.h
+++ b/hw/arm-misc.h
@@ -28,6 +28,7 @@ struct arm_boot_info {
const char *initrd_filename;
target_phys_addr_t loader_start;
target_phys_addr_t smp_loader_start;
+ target_phys_addr_t smp_priv_base;
int nb_cpus;
int board_id;
int (*atag_board)(struct arm_boot_info *info, void *p);
diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c
new file mode 100644
index 0000000000..3bbd8856cf
--- /dev/null
+++ b/hw/arm11mpcore.c
@@ -0,0 +1,112 @@
+/*
+ * ARM11MPCore internal peripheral emulation.
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licenced under the GPL.
+ */
+
+/* ??? The MPCore TRM says the on-chip controller has 224 external IRQ lines
+ (+ 32 internal). However my test chip only exposes/reports 32.
+ More importantly Linux falls over if more than 32 are present! */
+#define GIC_NIRQ 64
+#include "mpcore.c"
+
+/* Dummy PIC to route IRQ lines. The baseboard has 4 independent IRQ
+ controllers. The output of these, plus some of the raw input lines
+ are fed into a single SMP-aware interrupt controller on the CPU. */
+typedef struct {
+ SysBusDevice busdev;
+ SysBusDevice *priv;
+ qemu_irq cpuic[32];
+ qemu_irq rvic[4][64];
+ uint32_t num_cpu;
+} mpcore_rirq_state;
+
+/* Map baseboard IRQs onto CPU IRQ lines. */
+static const int mpcore_irq_map[32] = {
+ -1, -1, -1, -1, 1, 2, -1, -1,
+ -1, -1, 6, -1, 4, 5, -1, -1,
+ -1, 14, 15, 0, 7, 8, -1, -1,
+ -1, -1, -1, -1, 9, 3, -1, -1,
+};
+
+static void mpcore_rirq_set_irq(void *opaque, int irq, int level)
+{
+ mpcore_rirq_state *s = (mpcore_rirq_state *)opaque;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ qemu_set_irq(s->rvic[i][irq], level);
+ }
+ if (irq < 32) {
+ irq = mpcore_irq_map[irq];
+ if (irq >= 0) {
+ qemu_set_irq(s->cpuic[irq], level);
+ }
+ }
+}
+
+static void mpcore_rirq_map(SysBusDevice *dev, target_phys_addr_t base)
+{
+ mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev);
+ sysbus_mmio_map(s->priv, 0, base);
+}
+
+static int realview_mpcore_init(SysBusDevice *dev)
+{
+ mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev);
+ DeviceState *gic;
+ DeviceState *priv;
+ int n;
+ int i;
+
+ priv = qdev_create(NULL, "arm11mpcore_priv");
+ qdev_prop_set_uint32(priv, "num-cpu", s->num_cpu);
+ qdev_init_nofail(priv);
+ s->priv = sysbus_from_qdev(priv);
+ sysbus_pass_irq(dev, s->priv);
+ for (i = 0; i < 32; i++) {
+ s->cpuic[i] = qdev_get_gpio_in(priv, i);
+ }
+ /* ??? IRQ routing is hardcoded to "normal" mode. */
+ for (n = 0; n < 4; n++) {
+ gic = sysbus_create_simple("realview_gic", 0x10040000 + n * 0x10000,
+ s->cpuic[10 + n]);
+ for (i = 0; i < 64; i++) {
+ s->rvic[n][i] = qdev_get_gpio_in(gic, i);
+ }
+ }
+ qdev_init_gpio_in(&dev->qdev, mpcore_rirq_set_irq, 64);
+ sysbus_init_mmio_cb(dev, 0x2000, mpcore_rirq_map);
+ return 0;
+}
+
+static SysBusDeviceInfo mpcore_rirq_info = {
+ .init = realview_mpcore_init,
+ .qdev.name = "realview_mpcore",
+ .qdev.size = sizeof(mpcore_rirq_state),
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT32("num-cpu", mpcore_rirq_state, num_cpu, 1),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static SysBusDeviceInfo mpcore_priv_info = {
+ .init = mpcore_priv_init,
+ .qdev.name = "arm11mpcore_priv",
+ .qdev.size = sizeof(mpcore_priv_state),
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static void arm11mpcore_register_devices(void)
+{
+ sysbus_register_withprop(&mpcore_rirq_info);
+ sysbus_register_withprop(&mpcore_priv_info);
+}
+
+device_init(arm11mpcore_register_devices)
diff --git a/hw/arm_boot.c b/hw/arm_boot.c
index e273803645..30a76a56d1 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -31,8 +31,7 @@ static uint32_t bootloader[] = {
/* Entry point for secondary CPUs. Enable interrupt controller and
Issue WFI until start address is written to system controller. */
static uint32_t smpboot[] = {
- 0xe3a00201, /* mov r0, #0x10000000 */
- 0xe3800601, /* orr r0, r0, #0x001000000 */
+ 0xe59f0020, /* ldr r0, privbase */
0xe3a01001, /* mov r1, #1 */
0xe5801100, /* str r1, [r0, #0x100] */
0xe3a00201, /* mov r0, #0x10000000 */
@@ -41,7 +40,8 @@ static uint32_t smpboot[] = {
0xe5901000, /* ldr r1, [r0] */
0xe1110001, /* tst r1, r1 */
0x0afffffb, /* beq <wfi> */
- 0xe12fff11 /* bx r1 */
+ 0xe12fff11, /* bx r1 */
+ 0 /* privbase: Private memory region base address. */
};
#define WRITE_WORD(p, value) do { \
@@ -268,6 +268,7 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
rom_add_blob_fixed("bootloader", bootloader, sizeof(bootloader),
info->loader_start);
if (info->nb_cpus > 1) {
+ smpboot[10] = info->smp_priv_base;
for (n = 0; n < sizeof(smpboot) / 4; n++) {
smpboot[n] = tswap32(smpboot[n]);
}
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 536112bff5..c4afc6aeb5 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -607,7 +607,7 @@ static void gic_cpu_write(gic_state *s, int cpu, int offset, uint32_t value)
switch (offset) {
case 0x00: /* Control */
s->cpu_enabled[cpu] = (value & 1);
- DPRINTF("CPU %sabled\n", s->cpu_enabled ? "En" : "Dis");
+ DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled ? "En" : "Dis");
break;
case 0x04: /* Priority mask */
s->priority_mask[cpu] = (value & 0xff);
diff --git a/hw/mpcore.c b/hw/mpcore.c
index eccb2e188d..b4db1914b7 100644
--- a/hw/mpcore.c
+++ b/hw/mpcore.c
@@ -1,5 +1,5 @@
/*
- * ARM MPCore internal peripheral emulation.
+ * ARM MPCore internal peripheral emulation (common code).
*
* Copyright (c) 2006-2007 CodeSourcery.
* Written by Paul Brook
@@ -10,12 +10,7 @@
#include "sysbus.h"
#include "qemu-timer.h"
-#define MPCORE_PRIV_BASE 0x10100000
#define NCPU 4
-/* ??? The MPCore TRM says the on-chip controller has 224 external IRQ lines
- (+ 32 internal). However my test chip only exposes/reports 32.
- More importantly Linux falls over if more than 32 are present! */
-#define GIC_NIRQ 64
static inline int
gic_get_current_cpu(void)
@@ -288,95 +283,3 @@ static int mpcore_priv_init(SysBusDevice *dev)
}
return 0;
}
-
-/* Dummy PIC to route IRQ lines. The baseboard has 4 independent IRQ
- controllers. The output of these, plus some of the raw input lines
- are fed into a single SMP-aware interrupt controller on the CPU. */
-typedef struct {
- SysBusDevice busdev;
- qemu_irq cpuic[32];
- qemu_irq rvic[4][64];
- uint32_t num_cpu;
-} mpcore_rirq_state;
-
-/* Map baseboard IRQs onto CPU IRQ lines. */
-static const int mpcore_irq_map[32] = {
- -1, -1, -1, -1, 1, 2, -1, -1,
- -1, -1, 6, -1, 4, 5, -1, -1,
- -1, 14, 15, 0, 7, 8, -1, -1,
- -1, -1, -1, -1, 9, 3, -1, -1,
-};
-
-static void mpcore_rirq_set_irq(void *opaque, int irq, int level)
-{
- mpcore_rirq_state *s = (mpcore_rirq_state *)opaque;
- int i;
-
- for (i = 0; i < 4; i++) {
- qemu_set_irq(s->rvic[i][irq], level);
- }
- if (irq < 32) {
- irq = mpcore_irq_map[irq];
- if (irq >= 0) {
- qemu_set_irq(s->cpuic[irq], level);
- }
- }
-}
-
-static int realview_mpcore_init(SysBusDevice *dev)
-{
- mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev);
- DeviceState *gic;
- DeviceState *priv;
- SysBusDevice *bus_priv;
- int n;
- int i;
-
- priv = qdev_create(NULL, "arm11mpcore_priv");
- qdev_prop_set_uint32(priv, "num-cpu", s->num_cpu);
- qdev_init_nofail(priv);
- bus_priv = sysbus_from_qdev(priv);
- sysbus_mmio_map(bus_priv, 0, MPCORE_PRIV_BASE);
- sysbus_pass_irq(dev, bus_priv);
- for (i = 0; i < 32; i++) {
- s->cpuic[i] = qdev_get_gpio_in(priv, i);
- }
- /* ??? IRQ routing is hardcoded to "normal" mode. */
- for (n = 0; n < 4; n++) {
- gic = sysbus_create_simple("realview_gic", 0x10040000 + n * 0x10000,
- s->cpuic[10 + n]);
- for (i = 0; i < 64; i++) {
- s->rvic[n][i] = qdev_get_gpio_in(gic, i);
- }
- }
- qdev_init_gpio_in(&dev->qdev, mpcore_rirq_set_irq, 64);
- return 0;
-}
-
-static SysBusDeviceInfo mpcore_rirq_info = {
- .init = realview_mpcore_init,
- .qdev.name = "realview_mpcore",
- .qdev.size = sizeof(mpcore_rirq_state),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("num-cpu", mpcore_rirq_state, num_cpu, 1),
- DEFINE_PROP_END_OF_LIST(),
- }
-};
-
-static SysBusDeviceInfo mpcore_priv_info = {
- .init = mpcore_priv_init,
- .qdev.name = "arm11mpcore_priv",
- .qdev.size = sizeof(mpcore_priv_state),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
- DEFINE_PROP_END_OF_LIST(),
- }
-};
-
-static void mpcore_register_devices(void)
-{
- sysbus_register_withprop(&mpcore_rirq_info);
- sysbus_register_withprop(&mpcore_priv_info);
-}
-
-device_init(mpcore_register_devices)
diff --git a/hw/realview.c b/hw/realview.c
index 50386f8e0a..7aa127ee2d 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -34,10 +34,19 @@ static void secondary_cpu_reset(void *opaque)
env->regs[15] = SMP_BOOT_ADDR;
}
+/* The following two lists must be consistent. */
enum realview_board_type {
BOARD_EB,
BOARD_EB_MPCORE,
- BOARD_PB_A8
+ BOARD_PB_A8,
+ BOARD_PBX_A9,
+};
+
+int realview_board_id[] = {
+ 0x33b,
+ 0x33b,
+ 0x769,
+ 0x76d
};
static void realview_init(ram_addr_t ram_size,
@@ -57,12 +66,26 @@ static void realview_init(ram_addr_t ram_size,
int n;
int done_nic = 0;
qemu_irq cpu_irq[4];
- int is_mpcore = (board_type == BOARD_EB_MPCORE);
- int is_pb = (board_type == BOARD_PB_A8);
+ int is_mpcore = 0;
+ int is_pb = 0;
uint32_t proc_id = 0;
uint32_t sys_id;
ram_addr_t low_ram_size;
+ switch (board_type) {
+ case BOARD_EB:
+ break;
+ case BOARD_EB_MPCORE:
+ is_mpcore = 1;
+ break;
+ case BOARD_PB_A8:
+ is_pb = 1;
+ break;
+ case BOARD_PBX_A9:
+ is_mpcore = 1;
+ is_pb = 1;
+ break;
+ }
for (n = 0; n < smp_cpus; n++) {
env = cpu_init(cpu_model);
if (!env) {
@@ -76,7 +99,11 @@ static void realview_init(ram_addr_t ram_size,
}
}
if (arm_feature(env, ARM_FEATURE_V7)) {
- proc_id = 0x0e000000;
+ if (is_mpcore) {
+ proc_id = 0x0c000000;
+ } else {
+ proc_id = 0x0e000000;
+ }
} else if (arm_feature(env, ARM_FEATURE_V6K)) {
proc_id = 0x06000000;
} else if (arm_feature(env, ARM_FEATURE_V6)) {
@@ -104,10 +131,16 @@ static void realview_init(ram_addr_t ram_size,
arm_sysctl_init(0x10000000, sys_id, proc_id);
if (is_mpcore) {
- dev = qdev_create(NULL, "realview_mpcore");
+ dev = qdev_create(NULL, is_pb ? "a9mpcore_priv": "realview_mpcore");
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
qdev_init_nofail(dev);
busdev = sysbus_from_qdev(dev);
+ if (is_pb) {
+ realview_binfo.smp_priv_base = 0x1f000000;
+ } else {
+ realview_binfo.smp_priv_base = 0x10100000;
+ }
+ sysbus_mmio_map(busdev, 0, realview_binfo.smp_priv_base);
for (n = 0; n < smp_cpus; n++) {
sysbus_connect_irq(busdev, n, cpu_irq[n]);
}
@@ -238,7 +271,7 @@ static void realview_init(ram_addr_t ram_size,
realview_binfo.kernel_cmdline = kernel_cmdline;
realview_binfo.initrd_filename = initrd_filename;
realview_binfo.nb_cpus = smp_cpus;
- realview_binfo.board_id = is_pb ? 0x769 : 0x33b;
+ realview_binfo.board_id = realview_board_id[board_type];
realview_binfo.loader_start = is_pb ? 0x70000000 : 0;
arm_load_kernel(first_cpu, &realview_binfo);
}
@@ -279,6 +312,18 @@ static void realview_pb_a8_init(ram_addr_t ram_size,
initrd_filename, cpu_model, BOARD_PB_A8);
}
+static void realview_pbx_a9_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ if (!cpu_model) {
+ cpu_model = "cortex-a9";
+ }
+ realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
+ initrd_filename, cpu_model, BOARD_PBX_A9);
+}
+
static QEMUMachine realview_eb_machine = {
.name = "realview-eb",
.desc = "ARM RealView Emulation Baseboard (ARM926EJ-S)",
@@ -298,7 +343,14 @@ static QEMUMachine realview_pb_a8_machine = {
.name = "realview-pb-a8",
.desc = "ARM RealView Platform Baseboard for Cortex-A8",
.init = realview_pb_a8_init,
+};
+
+static QEMUMachine realview_pbx_a9_machine = {
+ .name = "realview-pbx-a9",
+ .desc = "ARM RealView Platform Baseboard Explore for Cortex-A9",
+ .init = realview_pbx_a9_init,
.use_scsi = 1,
+ .max_cpus = 4,
};
static void realview_machine_init(void)
@@ -306,6 +358,7 @@ static void realview_machine_init(void)
qemu_register_machine(&realview_eb_machine);
qemu_register_machine(&realview_eb_mpcore_machine);
qemu_register_machine(&realview_pb_a8_machine);
+ qemu_register_machine(&realview_pbx_a9_machine);
}
machine_init(realview_machine_init);
diff --git a/qemu-doc.texi b/qemu-doc.texi
index eca43715bf..7b8488f7f7 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -1664,7 +1664,7 @@ devices:
@itemize @minus
@item
-ARM926E, ARM1136, ARM11MPCORE or Cortex-A8 CPU
+ARM926E, ARM1136, ARM11MPCore, Cortex-A8 or Cortex-A9 MPCore CPU
@item
ARM AMBA Generic/Distributed Interrupt Controller
@item