dev-arm: Implement GIC-400 model from GicV2

Implementation registers for the GICv2 model currently hold values
referring to a GIC-400 implementation. This patch is making them
parametrizable so that it is possible to instantiate a GIC-400 model.
The patch is also modifying Realview platform to use new GIC-400 model
in lieau of GICv2.

Change-Id: I446db8c796ee3c2708af91e9139f0a6e7947321b
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/15277
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
diff --git a/src/dev/arm/Gic.py b/src/dev/arm/Gic.py
index 622dcf6..dddb7df 100644
--- a/src/dev/arm/Gic.py
+++ b/src/dev/arm/Gic.py
@@ -49,6 +49,15 @@
 
     platform = Param.Platform(Parent.any, "Platform this device is part of.")
 
+    gicd_iidr = Param.UInt32(0,
+        "Distributor Implementer Identification Register")
+    gicd_pidr = Param.UInt32(0,
+        "Peripheral Identification Register")
+    gicc_iidr = Param.UInt32(0,
+        "CPU Interface Identification Register")
+    gicv_iidr = Param.UInt32(0,
+        "VM CPU Interface Identification Register")
+
 class ArmInterruptPin(SimObject):
     type = 'ArmInterruptPin'
     cxx_header = "dev/arm/base_gic.hh"
@@ -81,6 +90,19 @@
     it_lines = Param.UInt32(128, "Number of interrupt lines supported (max = 1020)")
     gem5_extensions = Param.Bool(False, "Enable gem5 extensions")
 
+class Gic400(GicV2):
+    """
+    As defined in:
+    "ARM Generic Interrupt Controller Architecture" version 2.0
+    "CoreLink GIC-400 Generic Interrupt Controller" revision r0p1
+    """
+    gicd_pidr = 0x002bb490
+    gicd_iidr = 0x0200143B
+    gicc_iidr = 0x0202143B
+
+    # gicv_iidr same as gicc_idr
+    gicv_iidr = gicc_iidr
+
 class Gicv2mFrame(SimObject):
     type = 'Gicv2mFrame'
     cxx_header = "dev/arm/gic_v2m.hh"
@@ -107,6 +129,10 @@
    # The number of list registers is not currently configurable at runtime.
     ppint = Param.UInt32("HV maintenance interrupt number")
 
+    # gicv_iidr same as gicc_idr
+    gicv_iidr = Param.UInt32(Self.gic.gicc_iidr,
+        "VM CPU Interface Identification Register")
+
     def generateDeviceTree(self, state):
         gic = self.gic.unproxy(self)
 
diff --git a/src/dev/arm/RealView.py b/src/dev/arm/RealView.py
index ba42142..0ed7780 100644
--- a/src/dev/arm/RealView.py
+++ b/src/dev/arm/RealView.py
@@ -74,7 +74,7 @@
 except ImportError:
     # KVM support wasn't compiled into gem5. Fallback to a
     # software-only GIC.
-    kvm_gicv2_class = GicV2
+    kvm_gicv2_class = Gic400
     pass
 
 class AmbaPioDevice(BasicPioDevice):
@@ -574,7 +574,7 @@
     realview_io = RealViewCtrl(pio_addr=0x10000000)
     mcc = VExpressMCC()
     dcc = CoreTile2A15DCC()
-    gic = GicV2(cpu_addr=0x1f000100, dist_addr=0x1f001000, cpu_size=0x100)
+    gic = Gic400(cpu_addr=0x1f000100, dist_addr=0x1f001000, cpu_size=0x100)
     pci_host = GenericPciHost(
         conf_base=0x30000000, conf_size='256MB', conf_device_bits=16,
         pci_pio_base=0)
@@ -721,7 +721,7 @@
     dcc = CoreTile2A15DCC()
 
     ### On-chip devices ###
-    gic = GicV2(dist_addr=0x2C001000, cpu_addr=0x2C002000)
+    gic = Gic400(dist_addr=0x2C001000, cpu_addr=0x2C002000)
     vgic   = VGic(vcpu_addr=0x2c006000, hv_addr=0x2c004000, ppint=25)
 
     local_cpu_timer = CpuLocalTimer(int_timer=ArmPPI(num=29),
@@ -820,7 +820,8 @@
                                  InterruptLine=2, InterruptPin=2)
 
     def enableMSIX(self):
-        self.gic = GicV2(dist_addr=0x2C001000, cpu_addr=0x2C002000, it_lines=512)
+        self.gic = Gic400(dist_addr=0x2C001000, cpu_addr=0x2C002000,
+                          it_lines=512)
         self.gicv2m = Gicv2m()
         self.gicv2m.frames = [Gicv2mFrame(spi_base=256, spi_len=64, addr=0x2C1C0000)]
 
diff --git a/src/dev/arm/gic_v2.cc b/src/dev/arm/gic_v2.cc
index 1e58718..fa480a2 100644
--- a/src/dev/arm/gic_v2.cc
+++ b/src/dev/arm/gic_v2.cc
@@ -64,6 +64,9 @@
 
 GicV2::GicV2(const Params *p)
     : BaseGic(p),
+      gicdPIDR(p->gicd_pidr),
+      gicdIIDR(p->gicd_iidr),
+      giccIIDR(p->gicc_iidr),
       distRange(RangeSize(p->dist_addr, DIST_SIZE)),
       cpuRange(RangeSize(p->cpu_addr, p->cpu_size)),
       addrRanges{distRange, cpuRange},
@@ -268,16 +271,16 @@
                 (haveGem5Extensions ? 0x100 : 0x0));
       case GICD_PIDR0:
         //ARM defined DevID
-        return (GICD_400_PIDR_VALUE & 0xFF);
+        return (gicdPIDR & 0xFF);
       case GICD_PIDR1:
-        return ((GICD_400_PIDR_VALUE >> 8) & 0xFF);
+        return ((gicdPIDR >> 8) & 0xFF);
       case GICD_PIDR2:
-        return ((GICD_400_PIDR_VALUE >> 16) & 0xFF);
+        return ((gicdPIDR >> 16) & 0xFF);
       case GICD_PIDR3:
-        return ((GICD_400_PIDR_VALUE >> 24) & 0xFF);
+        return ((gicdPIDR >> 24) & 0xFF);
       case GICD_IIDR:
          /* revision id is resorted to 1 and variant to 0*/
-        return GICD_400_IIDR_VALUE;
+        return gicdIIDR;
       default:
         panic("Tried to read Gic distributor at offset %#x\n", daddr);
         break;
@@ -307,7 +310,7 @@
 {
     switch(daddr) {
       case GICC_IIDR:
-        return GICC_400_IIDR_VALUE;
+        return giccIIDR;
       case GICC_CTLR:
         return cpuControl[ctx];
       case GICC_PMR:
diff --git a/src/dev/arm/gic_v2.hh b/src/dev/arm/gic_v2.hh
index 49465ad..f9b66b8 100644
--- a/src/dev/arm/gic_v2.hh
+++ b/src/dev/arm/gic_v2.hh
@@ -75,14 +75,9 @@
         DIST_SIZE          = 0x1000,
     };
 
-    /**
-     * As defined in:
-     * "ARM Generic Interrupt Controller Architecture" version 2.0
-     * "CoreLink GIC-400 Generic Interrupt Controller" revision r0p1
-     */
-    static constexpr uint32_t  GICD_400_PIDR_VALUE = 0x002bb490;
-    static constexpr uint32_t  GICD_400_IIDR_VALUE = 0x200143B;
-    static constexpr uint32_t  GICC_400_IIDR_VALUE = 0x202143B;
+    const uint32_t gicdPIDR;
+    const uint32_t gicdIIDR;
+    const uint32_t giccIIDR;
 
     static const AddrRange GICD_IGROUPR;    // interrupt group (unimplemented)
     static const AddrRange GICD_ISENABLER;  // interrupt set enable