From 7e45912c10fef97d1ade487ac65a0def2c940768 Mon Sep 17 00:00:00 2001
From: Jiri Gaisler <jiri@gaisler.se>
Date: Wed, 15 Oct 2014 21:51:23 +0200
Subject: [PATCH 2/3] LEON3: Build AMBA plug and play records from high-level
 constants.

Move creation of plug and play into associated devices when possible.
This makes it easy to add new records when new devices are added.
---
 hw/sparc/grlib_ambapnp.c | 99 +++++++++++++++++++++++-------------------------
 hw/sparc/leon3.c         |  8 ++--
 include/hw/sparc/grlib.h | 55 ++++++++++++++++++++++++++-
 3 files changed, 104 insertions(+), 58 deletions(-)

diff --git a/hw/sparc/grlib_ambapnp.c b/hw/sparc/grlib_ambapnp.c
index dd53004..fb21841 100644
--- a/hw/sparc/grlib_ambapnp.c
+++ b/hw/sparc/grlib_ambapnp.c
@@ -38,42 +38,24 @@ typedef struct AMBAPNP {
 
 /* APB PNP */
 
+static uint32_t apbppmem[32*2];    /* 32-entry APB PP AREA */
+static int apbppindex;
+
+int grlib_apbpp_add(uint32_t id, uint32_t addr)
+{
+    apbppmem[apbppindex++] = id;
+    apbppmem[apbppindex++] = addr;
+    if(apbppindex >= (32*2)) apbppindex = 0; /* prevent overflow of area */
+    return(apbppindex);
+}
+
 static uint64_t grlib_apbpnp_read(void *opaque, hwaddr addr,
                                    unsigned size)
 {
     uint64_t read_data;
-    addr &= 0xfff;
+    addr &= 0xff;
+    read_data = apbppmem[addr>>2];
 
-    /* Unit registers */
-    switch (addr & 0xffc) {
-    case 0x00:
-        read_data = 0x0400f000; /* Memory controller */
-        break;
-    case 0x04:
-        read_data = 0x0000fff1;
-        break;
-    case 0x08:
-        read_data = 0x0100c023; /* APBUART */
-        break;
-    case 0x0C:
-        read_data = 0x0010fff1;
-        break;
-    case 0x10:
-        read_data = 0x0100d040; /* IRQMP */
-        break;
-    case 0x14:
-        read_data = 0x0020fff1;
-        break;
-    case 0x18:
-        read_data = 0x01011006; /* GPTIMER */
-        break;
-    case 0x1C:
-        read_data = 0x0030fff1;
-        break;
-
-    default:
-        read_data = 0;
-    }
     if (size == 1) {
         read_data >>= (24 - (addr & 3) * 8);
         read_data &= 0x0ff;
@@ -88,31 +70,44 @@ static const MemoryRegionOps grlib_apbpnp_ops = {
 
 /* AHB PNP */
 
+static uint32_t ahbppmem[128*8];    /* 128-entry AHB PP AREA */
+static int ahbmppindex;
+static int ahbsppindex = 64*8;
+
+int grlib_ahbmpp_add(uint32_t id)
+{
+    ahbppmem[ahbmppindex] = id;
+    ahbmppindex += 8;
+    if(ahbmppindex >= (64*8)) ahbmppindex = 0; /* prevent overflow of area */
+    return(ahbmppindex);
+}
+
+int grlib_ahbspp_add(uint32_t id, uint32_t addr1, uint32_t addr2,
+                     uint32_t addr3, uint32_t addr4)
+{
+    ahbppmem[ahbsppindex] = id;
+    ahbsppindex += 4;
+    ahbppmem[ahbsppindex++] = addr1;
+    ahbppmem[ahbsppindex++] = addr2;
+    ahbppmem[ahbsppindex++] = addr3;
+    ahbppmem[ahbsppindex++] = addr4;
+    if(ahbsppindex >= (128*8)) ahbsppindex = 64*8; /* prevent overflow of area */
+    return(ahbsppindex);
+}
+
 static uint64_t grlib_ahbpnp_read(void *opaque, hwaddr addr,
                                    unsigned size)
 {
-    addr &= 0xffc;
-
-    /* Unit registers */
-    switch (addr) {
-    case 0:
-        return 0x01003000;      /* LEON3 */
-    case 0x800:
-        return 0x0400f000;      /* Memory controller  */
-    case 0x810:
-        return 0x0003e002;
-    case 0x814:
-        return 0x2000e002;
-    case 0x818:
-        return 0x4003c002;
-    case 0x820:
-        return 0x01006000;      /* APB bridge @ 0x80000000 */
-    case 0x830:
-        return 0x8000fff2;
-
-    default:
-        return 0;
+    uint64_t read_data;
+
+    addr &= 0xfff;
+    read_data = ahbppmem[addr>>2];
+
+    if (size == 1) {
+        read_data >>= (24 - (addr & 3) * 8);
+        read_data &= 0x0ff;
     }
+    return read_data;
 }
 
 static const MemoryRegionOps grlib_ahbpnp_ops = {
diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c
index 2962539..0ff2b27 100644
--- a/hw/sparc/leon3.c
+++ b/hw/sparc/leon3.c
@@ -138,6 +138,9 @@ static void leon3_generic_hw_init(MachineState *machine)
     reset_info->sp    = 0x40000000 + ram_size;
     qemu_register_reset(main_cpu_reset, reset_info);
 
+    /* Allocate AHB/APB PNP */
+    grlib_ambapnp_create(0xFFFFF000 /* AHB */, 0x800FF000 /* APB */);
+
     /* Allocate IRQ manager */
     grlib_irqmp_create(0x80000200, env, &cpu_irqs, MAX_PILS, &leon3_set_pil_in);
 
@@ -207,15 +210,12 @@ static void leon3_generic_hw_init(MachineState *machine)
         }
     }
 
-    /* Allocate AHB/APB PNP */
-    grlib_ambapnp_create(0xFFFFF000 /* AHB */, 0x800FF000 /* APB */);
-
     /* Allocate timers */
     grlib_gptimer_create(0x80000300, 2, CPU_CLK, cpu_irqs, 6);
 
     /* Allocate uart */
     if (serial_hds[0]) {
-        grlib_apbuart_create(0x80000100, serial_hds[0], cpu_irqs[3]);
+        grlib_apbuart_create(0x80000100, serial_hds[0], cpu_irqs, 3);
     }
 }
 
diff --git a/include/hw/sparc/grlib.h b/include/hw/sparc/grlib.h
index 5c098df..daebb33 100644
--- a/include/hw/sparc/grlib.h
+++ b/include/hw/sparc/grlib.h
@@ -32,6 +32,33 @@
  * http://www.gaisler.com/products/grlib/grip.pdf
  */
 
+/* Definitions for AMBA PNP */
+
+/* Vendors */
+#define VENDOR_GAISLER    1
+#define VENDOR_PENDER     2
+#define VENDOR_ESA        4
+#define VENDOR_DLR       10
+
+/* Devices */
+#define GAISLER_LEON3    0x003
+#define GAISLER_APBMST   0x006
+#define GAISLER_APBUART  0x00C
+#define GAISLER_IRQMP    0x00D
+#define GAISLER_GPTIMER  0x011
+#define ESA_MCTRL        0x00F
+
+/* How to build entries in the plug&play area */
+#define GRLIB_PP_ID(v, d, x, i) ((v & 0xff) << 24) | ((d & 0x3ff) << 12) |\
+                                ((x & 0x1f) << 5) | (i & 0x1f)
+#define GRLIB_PP_AHBADDR(a, m, p, c, t) (a & 0xfff00000) | ((m & 0xfff) << 4) |\
+                         ((p & 1) << 17) | ((c & 1) << 16) | (t & 0x3)
+#define GRLIB_PP_APBADDR(a, m) ((a & 0xfff00)<< 12) | ((m & 0xfff) << 4) | 1
+
+int grlib_apbpp_add(uint32_t id, uint32_t addr);
+int grlib_ahbmpp_add(uint32_t id);
+int grlib_ahbspp_add(uint32_t id, uint32_t addr1, uint32_t addr2,
+                     uint32_t addr3, uint32_t addr4);
 /* IRQMP */
 
 typedef void (*set_pil_in_fn) (void *opaque, uint32_t pil_in);
@@ -67,6 +94,9 @@ DeviceState *grlib_irqmp_create(hwaddr   base,
                                    dev,
                                    nr_irqs);
 
+    grlib_apbpp_add(GRLIB_PP_ID(VENDOR_GAISLER, GAISLER_IRQMP, 2, 0),
+                    GRLIB_PP_APBADDR(base, 0xFFF));
+
     return dev;
 }
 
@@ -97,6 +127,9 @@ DeviceState *grlib_gptimer_create(hwaddr  base,
         sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, cpu_irqs[base_irq + i]);
     }
 
+    grlib_apbpp_add(GRLIB_PP_ID(VENDOR_GAISLER, GAISLER_GPTIMER, 0, base_irq),
+                    GRLIB_PP_APBADDR(base, 0xFFF));
+    
     return dev;
 }
 
@@ -105,7 +138,8 @@ DeviceState *grlib_gptimer_create(hwaddr  base,
 static inline
 DeviceState *grlib_apbuart_create(hwaddr  base,
                                   CharDriverState    *serial,
-                                  qemu_irq            irq)
+                                  qemu_irq           *cpu_irqs,
+                                  int                 base_irq)
 {
     DeviceState *dev;
 
@@ -118,8 +152,11 @@ DeviceState *grlib_apbuart_create(hwaddr  base,
 
     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
 
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irqs[base_irq]);
 
+    grlib_apbpp_add(GRLIB_PP_ID(VENDOR_GAISLER, GAISLER_APBUART, 1, base_irq),
+                    GRLIB_PP_APBADDR(base, 0xFFF));
+    
     return dev;
 }
 
@@ -142,6 +179,20 @@ DeviceState *grlib_ambapnp_create(hwaddr ahbpnp_base, hwaddr apbpnp_base)
     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, ahbpnp_base);
     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, apbpnp_base);
 
+    /* Add PP records for Leon3, APB bridge and memory controller
+       as this is not done elsewhere */
+
+    grlib_ahbspp_add(GRLIB_PP_ID(VENDOR_GAISLER, GAISLER_APBMST, 0, 0),
+                     GRLIB_PP_AHBADDR(0x80000000, 0xFFF, 0, 0, 2),
+                     0, 0, 0);
+    grlib_apbpp_add(GRLIB_PP_ID(VENDOR_ESA, ESA_MCTRL, 1, 0),
+                    GRLIB_PP_APBADDR(0x80000000, 0xFFF));
+    grlib_ahbmpp_add(GRLIB_PP_ID(VENDOR_GAISLER, GAISLER_LEON3, 0, 0));
+    grlib_ahbspp_add(GRLIB_PP_ID(VENDOR_ESA, ESA_MCTRL, 1, 0),
+                     GRLIB_PP_AHBADDR(0x00000000, 0xE00, 1, 1, 2),
+                     GRLIB_PP_AHBADDR(0x20000000, 0xE00, 0, 0, 2),
+                     GRLIB_PP_AHBADDR(0x40000000, 0xC00, 1, 1, 2),
+                     0);
     return dev;
 }
 
-- 
1.9.1

