arm: DT autogeneration - autogenerate RealView Platform devices
authorGlenn Bergmans <glenn.bergmans@arm.com>
Thu, 17 Dec 2015 11:49:51 +0000 (11:49 +0000)
committerCurtis Dunham <curtis.dunham@arm.com>
Mon, 29 Jan 2018 22:22:23 +0000 (22:22 +0000)
Implements the Device Tree generating code for devices required by the
RealView VExpress_GEM5_V1 platform

Change-Id: I14244b2f3c028cbddba3c23ce7433fe3b301a0e8
Reviewed-by: Curtis Dunham <curtis.dunham@arm.com>
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/5965
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>

src/dev/Device.py
src/dev/arm/RealView.py

index d51d7bd8d680d42bb98368a629ad3cb7126bc48d..e4656078d522813ac86b671707a40dfc39bf9147 100644 (file)
@@ -1,3 +1,15 @@
+# Copyright (c) 2012-2016 ARM Limited
+# All rights reserved.
+#
+# The license below extends only to copyright in the software and shall
+# not be construed as granting a license to any other intellectual
+# property including but not limited to intellectual property relating
+# to a hardware implementation of the functionality of the software
+# licensed hereunder.  You may use the software subject to the license
+# terms below provided that you ensure that this notice is replicated
+# unmodified and in its entirety in all distributions of the software,
+# modified or unmodified, in source code or in binary form.
+#
 # Copyright (c) 2005-2007 The Regents of The University of Michigan
 # All rights reserved.
 #
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
 # Authors: Nathan Binkert
+#          Glenn Bergmans
 
 from m5.params import *
 from m5.proxy import *
+from m5.util.fdthelper import *
 from MemObject import MemObject
 
 class PioDevice(MemObject):
@@ -37,6 +51,25 @@ class PioDevice(MemObject):
     pio = SlavePort("Programmed I/O port")
     system = Param.System(Parent.any, "System this device is part of")
 
+    def generateBasicPioDeviceNode(self, state, name, pio_addr,
+                                   size, interrupts = None):
+        node = FdtNode("%s@%x" % (name, long(pio_addr)))
+        node.append(FdtPropertyWords("reg",
+            state.addrCells(pio_addr) +
+            state.sizeCells(size) ))
+
+        if interrupts:
+            if any([i < 32 for i in interrupts]):
+                raise(("Interrupt number smaller than 32 "+
+                       " in PioDevice %s") % name)
+
+            # subtracting 32 because Linux assumes that SPIs start at 0, while
+            # gem5 uses the internal GIC numbering (SPIs start at 32)
+            node.append(FdtPropertyWords("interrupts", sum(
+                [[0, i  - 32, 4] for i in interrupts], []) ))
+
+        return node
+
 class BasicPioDevice(PioDevice):
     type = 'BasicPioDevice'
     cxx_header = "dev/io_device.hh"
index cd7772f328b41eef7adcca689026c639468ffcf8..760c3c709d5b22c327dc67ad71716d1151f5990d 100644 (file)
 # Authors: Ali Saidi
 #          Gabe Black
 #          William Wang
+#          Glenn Bergmans
 
+from m5.defines import buildEnv
 from m5.params import *
 from m5.proxy import *
+from m5.util.fdthelper import *
 from ClockDomain import ClockDomain
 from VoltageDomain import VoltageDomain
 from Device import BasicPioDevice, PioDevice, IsaFake, BadAddr, DmaDevice
@@ -58,6 +61,7 @@ from ClockedObject import ClockedObject
 from ClockDomain import SrcClockDomain
 from SubSystem import SubSystem
 from Graphics import ImageFormat
+from ClockedObject import ClockedObject
 
 # Platforms with KVM support should generally use in-kernel GIC
 # emulation. Use a GIC model that automatically switches between
@@ -121,6 +125,18 @@ class RealViewCtrl(BasicPioDevice):
     proc_id1 = Param.UInt32(0x0C000222, "Processor ID, SYS_PROCID1")
     idreg = Param.UInt32(0x00000000, "ID Register, SYS_ID")
 
+    def generateDeviceTree(self, state):
+        node = FdtNode("sysreg@%x" % long(self.pio_addr))
+        node.appendCompatible("arm,vexpress-sysreg")
+        node.append(FdtPropertyWords("reg",
+            state.addrCells(self.pio_addr) +
+            state.sizeCells(0x1000) ))
+        node.append(FdtProperty("gpio-controller"))
+        node.append(FdtPropertyWords("#gpio-cells", [2]))
+        node.appendPhandle(self)
+
+        yield node
+
 class RealViewOsc(ClockDomain):
     type = 'RealViewOsc'
     cxx_header = "dev/arm/rv_ctrl.hh"
@@ -143,6 +159,20 @@ class RealViewOsc(ClockDomain):
 
     freq = Param.Clock("Default frequency")
 
+    def generateDeviceTree(self, state):
+        phandle = state.phandle(self)
+        node = FdtNode("osc@" + format(long(phandle), 'x'))
+        node.appendCompatible("arm,vexpress-osc")
+        node.append(FdtPropertyWords("arm,vexpress-sysreg,func",
+                                     [0x1, int(self.device)]))
+        node.append(FdtPropertyWords("#clock-cells", [0]))
+        freq = int(1.0/self.freq.value) # Values are stored as a clock period
+        node.append(FdtPropertyWords("freq-range", [freq, freq]))
+        node.append(FdtPropertyStrings("clock-output-names",
+                                       ["oscclk" + str(phandle)]))
+        node.appendPhandle(self)
+        yield node
+
 class RealViewTemperatureSensor(SimObject):
     type = 'RealViewTemperatureSensor'
     cxx_header = "dev/arm/rv_ctrl.hh"
@@ -181,6 +211,20 @@ Express (V2M-P1) motherboard. See ARM DUI 0447J for details.
     # See Table 4.19 in ARM DUI 0447J (Motherboard Express uATX TRM).
     temp_crtl = Temperature(device=0)
 
+    def generateDeviceTree(self, state):
+        node = FdtNode("mcc")
+        node.appendCompatible("arm,vexpress,config-bus")
+        node.append(FdtPropertyWords("arm,vexpress,site", [0]))
+
+        for obj in self._children.values():
+            if issubclass(type(obj), SimObject):
+                node.append(obj.generateDeviceTree(state))
+
+        io_phandle = state.phandle(self.osc_mcc.parent.unproxy(self))
+        node.append(FdtPropertyWords("arm,vexpress,config-bridge", io_phandle))
+
+        yield node
+
 class CoreTile2A15DCC(SubSystem):
     """ARM CoreTile Express A15x2 Daughterboard Configuration Controller
 
@@ -200,6 +244,19 @@ ARM DUI 0604E for details.
     osc_sys = Osc(device=7, freq="60MHz")
     osc_ddr = Osc(device=8, freq="40MHz")
 
+    def generateDeviceTree(self, state):
+        node = FdtNode("dcc")
+        node.appendCompatible("arm,vexpress,config-bus")
+
+        for obj in self._children.values():
+            if isinstance(obj, SimObject):
+                node.append(obj.generateDeviceTree(state))
+
+        io_phandle = state.phandle(self.osc_cpu.parent.unproxy(self))
+        node.append(FdtPropertyWords("arm,vexpress,config-bridge", io_phandle))
+
+        yield node
+
 class VGic(PioDevice):
     type = 'VGic'
     cxx_header = "dev/arm/vgic.hh"
@@ -211,6 +268,34 @@ class VGic(PioDevice):
    # The number of list registers is not currently configurable at runtime.
     ppint = Param.UInt32("HV maintenance interrupt number")
 
+    def generateDeviceTree(self, state):
+        gic = self.gic.unproxy(self)
+
+        node = FdtNode("interrupt-controller")
+        node.appendCompatible(["gem5,gic", "arm,cortex-a15-gic",
+                               "arm,cortex-a9-gic"])
+        node.append(FdtPropertyWords("#interrupt-cells", [3]))
+        node.append(FdtPropertyWords("#address-cells", [0]))
+        node.append(FdtProperty("interrupt-controller"))
+
+        regs = (
+            state.addrCells(gic.dist_addr) +
+            state.sizeCells(0x1000) +
+            state.addrCells(gic.cpu_addr) +
+            state.sizeCells(0x1000) +
+            state.addrCells(self.hv_addr) +
+            state.sizeCells(0x2000) +
+            state.addrCells(self.vcpu_addr) +
+            state.sizeCells(0x2000) )
+
+        node.append(FdtPropertyWords("reg", regs))
+        node.append(FdtPropertyWords("interrupts",
+                                     [1, int(self.ppint)-16, 0xf04]))
+
+        node.appendPhandle(gic)
+
+        yield node
+
 class AmbaFake(AmbaPioDevice):
     type = 'AmbaFake'
     cxx_header = "dev/arm/amba_fake.hh"
@@ -225,6 +310,20 @@ class Pl011(Uart):
     end_on_eot = Param.Bool(False, "End the simulation when a EOT is received on the UART")
     int_delay = Param.Latency("100ns", "Time between action and interrupt generation by UART")
 
+    def generateDeviceTree(self, state):
+        node = self.generateBasicPioDeviceNode(state, 'uart', self.pio_addr,
+                                               0x1000, [int(self.int_num)])
+        node.appendCompatible(["arm,pl011", "arm,primecell"])
+
+        # Hardcoded reference to the realview platform clocks, because the
+        # clk_domain can only store one clock (i.e. it is not a VectorParam)
+        realview = self._parent.unproxy(self)
+        node.append(FdtPropertyWords("clocks",
+            [state.phandle(realview.mcc.osc_peripheral),
+            state.phandle(realview.dcc.osc_smb)]))
+        node.append(FdtPropertyStrings("clock-names", ["uartclk", "apb_pclk"]))
+        yield node
+
 class Sp804(AmbaPioDevice):
     type = 'Sp804'
     cxx_header = "dev/arm/timer_sp804.hh"
@@ -258,6 +357,20 @@ class GenericTimer(ClockedObject):
     int_phys = Param.UInt32("Physical timer interrupt number")
     int_virt = Param.UInt32("Virtual timer interrupt number")
 
+    def generateDeviceTree(self, state):
+        node = FdtNode("timer")
+
+        node.appendCompatible(["arm,cortex-a15-timer",
+                               "arm,armv7-timer",
+                               "arm,armv8-timer"])
+        node.append(FdtPropertyWords("interrupts",
+            [1, int(self.int_phys) - 16, 0xf08,
+            1, int(self.int_virt) - 16, 0xf08]))
+        clock = state.phandle(self.clk_domain.unproxy(self))
+        node.append(FdtPropertyWords("clocks", clock))
+
+        yield node
+
 class GenericTimerMem(PioDevice):
     type = 'GenericTimerMem'
     cxx_header = "dev/arm/generic_timer.hh"
@@ -274,6 +387,16 @@ class PL031(AmbaIntDevice):
     time = Param.Time('01/01/2009', "System time to use ('Now' for actual time)")
     amba_id = 0x00341031
 
+    def generateDeviceTree(self, state):
+        node = self.generateBasicPioDeviceNode(state, 'rtc', self.pio_addr,
+                                               0x1000, [int(self.int_num)])
+
+        node.appendCompatible(["arm,pl031", "arm,primecell"])
+        clock = state.phandle(self.clk_domain.unproxy(self))
+        node.append(FdtPropertyWords("clocks", clock))
+
+        yield node
+
 class Pl050(AmbaIntDevice):
     type = 'Pl050'
     cxx_header = "dev/arm/kmi.hh"
@@ -282,6 +405,16 @@ class Pl050(AmbaIntDevice):
     int_delay = '1us'
     amba_id = 0x00141050
 
+    def generateDeviceTree(self, state):
+        node = self.generateBasicPioDeviceNode(state, 'kmi', self.pio_addr,
+                                               0x1000, [int(self.int_num)])
+
+        node.appendCompatible(["arm,pl050", "arm,primecell"])
+        clock = state.phandle(self.clk_domain.unproxy(self))
+        node.append(FdtPropertyWords("clocks", clock))
+
+        yield node
+
 class Pl111(AmbaDmaDevice):
     type = 'Pl111'
     cxx_header = "dev/arm/pl111.hh"
@@ -312,6 +445,23 @@ class HDLcd(AmbaDmaDevice):
     virt_refresh_rate = Param.Frequency("20Hz", "Frame refresh rate "
                                         "in KVM mode")
 
+    def generateDeviceTree(self, state):
+        # Interrupt number is hardcoded; it is not a property of this class
+        node = self.generateBasicPioDeviceNode(state, 'hdlcd',
+                                               self.pio_addr, 0x1000, [63])
+
+        node.appendCompatible(["arm,hdlcd"])
+        node.append(FdtPropertyWords("clocks", state.phandle(self.pxl_clk)))
+        node.append(FdtPropertyStrings("clock-names", ["pxlclk"]))
+
+        # This driver is disabled by default since the required DT nodes
+        # haven't been standardized yet. To use it,  override this status to
+        # "ok" and add the display configuration nodes required by the driver.
+        # See the driver for more information.
+        node.append(FdtPropertyStrings("status", ["disabled"]))
+
+        yield node
+
 class RealView(Platform):
     type = 'RealView'
     cxx_header = "dev/arm/realview.hh"
@@ -372,6 +522,22 @@ class RealView(Platform):
         cur_sys.atags_addr = 0x100
         cur_sys.load_offset = 0
 
+    def generateDeviceTree(self, state):
+        node = FdtNode("/") # Things in this module need to end up in the root
+        node.append(FdtPropertyWords("interrupt-parent",
+                                     state.phandle(self.gic)))
+
+        for device in [getattr(self, c) for c in self._children]:
+            if issubclass(type(device), SimObject):
+                subnode = device.generateDeviceTree(state)
+                node.append(subnode)
+
+        yield node
+
+    def annotateCpuDeviceNode(self, cpu, state):
+        cpu.append(FdtPropertyStrings("enable-method", "spin-table"))
+        cpu.append(FdtPropertyWords("cpu-release-addr", \
+                                    state.addrCells(0x8000fff8)))
 
 # Reference for memory map and interrupt number
 # RealView Platform Baseboard Explore for Cortex-A9 User Guide(ARM DUI 0440A)
@@ -897,6 +1063,9 @@ Interrupts:
         ]
 
     ### Off-chip devices ###
+    clock24MHz = SrcClockDomain(clock="24MHz",
+        voltage_domain=VoltageDomain(voltage="3.3V"))
+
     uart0 = Pl011(pio_addr=0x1c090000, int_num=37)
 
     kmi0 = Pl050(pio_addr=0x1c060000, int_num=44)
@@ -917,10 +1086,12 @@ Interrupts:
         return [
             self.realview_io,
             self.uart0,
-            self.kmi0, self.kmi1,
+            self.kmi0,
+            self.kmi1,
             self.rtc,
             self.pci_host,
             self.energy_ctrl,
+            self.clock24MHz,
         ]
 
     def attachPciDevice(self, device, *args, **kwargs):
@@ -940,3 +1111,17 @@ Interrupts:
         #  loader, but this is the only place we can configure the
         #  system.
         cur_sys.m5ops_base = 0x10010000
+
+    def generateDeviceTree(self, state):
+        # Generate using standard RealView function
+        dt = list(super(VExpress_GEM5_V1, self).generateDeviceTree(state))
+        if len(dt) > 1:
+            raise Exception("System returned too many DT nodes")
+        node = dt[0]
+
+        node.appendCompatible(["arm,vexpress"])
+        node.append(FdtPropertyStrings("model", ["V2P-CA15"]))
+        node.append(FdtPropertyWords("arm,hbi", [0x0]))
+        node.append(FdtPropertyWords("arm,vexpress,site", [0xf]))
+
+        yield node