ARM PBX-A9 board support

Implement ARM RealView PBX-A9 board support.

Signed-off-by: Paul Brook <paul@codesourcery.com>
diff --git a/Makefile.target b/Makefile.target
index b9888f0..ab774e5 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -270,7 +270,7 @@
 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 0000000..b5e5328
--- /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 e584073..010acb4 100644
--- a/hw/arm-misc.h
+++ b/hw/arm-misc.h
@@ -28,6 +28,7 @@
     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 0000000..3bbd885
--- /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 e273803..30a76a5 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -31,8 +31,7 @@
 /* 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 @@
   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 @@
         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 536112b..c4afc6a 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -607,7 +607,7 @@
     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 eccb2e1..b4db191 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 @@
     }
     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 50386f8..7aa127e 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -34,10 +34,19 @@
   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 @@
     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 @@
         }
     }
     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 @@
     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 @@
     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 @@
                   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 @@
     .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 @@
     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 eca4371..7b8488f 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -1664,7 +1664,7 @@
 
 @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