summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndreas Sandberg <Andreas.Sandberg@ARM.com>2015-08-07 09:59:25 +0100
committerAndreas Sandberg <Andreas.Sandberg@ARM.com>2015-08-07 09:59:25 +0100
commit598edaae0509c455e06e1689fd3c50caaeef0f30 (patch)
treeba594372e884ede6ae0c1674fa35519c93e3c0ec /src
parentcd098a7e84c05d67026e3812f6952fbf3b9e070e (diff)
downloadgem5-598edaae0509c455e06e1689fd3c50caaeef0f30.tar.xz
arm: Add support for programmable oscillators
Add support for oscillators that can be programmed using the RealView / Versatile Express configuration interface. These oscillators are typically used for things like the pixel clock in the display controller. The default configurations support the oscillators from a Versatile Express motherboard (V2M-P1) with a CoreTile Express A15x2.
Diffstat (limited to 'src')
-rw-r--r--src/dev/arm/RealView.py54
-rw-r--r--src/dev/arm/rv_ctrl.cc200
-rw-r--r--src/dev/arm/rv_ctrl.hh85
3 files changed, 253 insertions, 86 deletions
diff --git a/src/dev/arm/RealView.py b/src/dev/arm/RealView.py
index 5365ac9de..a9b9dede2 100644
--- a/src/dev/arm/RealView.py
+++ b/src/dev/arm/RealView.py
@@ -42,6 +42,8 @@
from m5.params import *
from m5.proxy import *
+from ClockDomain import ClockDomain
+from VoltageDomain import VoltageDomain
from Device import BasicPioDevice, PioDevice, IsaFake, BadAddr, DmaDevice
from Pci import PciConfigAll
from Ethernet import NSGigE, IGbE_igb, IGbE_e1000
@@ -89,6 +91,49 @@ class RealViewCtrl(BasicPioDevice):
proc_id1 = Param.UInt32(0x0C000222, "Processor ID, SYS_PROCID1")
idreg = Param.UInt32(0x00000000, "ID Register, SYS_ID")
+class RealViewOsc(ClockDomain):
+ type = 'RealViewOsc'
+ cxx_header = "dev/arm/rv_ctrl.hh"
+
+ parent = Param.RealViewCtrl(Parent.any, "RealView controller")
+
+ # TODO: We currently don't have the notion of a clock source,
+ # which means we have to associate oscillators with a voltage
+ # source.
+ voltage_domain = Param.VoltageDomain(Parent.voltage_domain,
+ "Voltage domain")
+
+ # See ARM DUI 0447J (ARM Motherboard Express uATX -- V2M-P1) and
+ # the individual core/logic tile reference manuals for details
+ # about the site/position/dcc/device allocation.
+ site = Param.UInt8("Board Site")
+ position = Param.UInt8("Position in device stack")
+ dcc = Param.UInt8("Daughterboard Configuration Controller")
+ device = Param.UInt8("Device ID")
+
+ freq = Param.Clock("Default frequency")
+
+class VExpressCoreTileCtrl(RealViewCtrl):
+ class MotherBoardOsc(RealViewOsc):
+ site, position, dcc = (0, 0, 0)
+
+ class CoreTileOsc(RealViewOsc):
+ site, position, dcc = (1, 0, 0)
+
+ # See ARM DUI 0447J (ARM Motherboard Express uATX -- V2M-P1)
+ osc_mcc = MotherBoardOsc(device=0, freq="50MHz")
+ osc_clcd = MotherBoardOsc(device=1, freq="23.75MHz")
+ osc_peripheral = MotherBoardOsc(device=2, freq="24MHz")
+ osc_system_bus = MotherBoardOsc(device=4, freq="24MHz")
+
+ # See Table 2.8 in ARM DUI 0604E (CoreTile Express A15x2 TRM).
+ osc_cpu = CoreTileOsc(device=0, freq="60MHz")
+ osc_hsbm = CoreTileOsc(device=4, freq="40MHz")
+ osc_pxl = CoreTileOsc(device=5, freq="23.75MHz")
+ osc_smb = CoreTileOsc(device=6, freq="50MHz")
+ osc_sys = CoreTileOsc(device=7, freq="60MHz")
+ osc_ddr = CoreTileOsc(device=8, freq="40MHz")
+
class VGic(PioDevice):
type = 'VGic'
cxx_header = "dev/arm/vgic.hh"
@@ -227,7 +272,7 @@ class RealView(Platform):
# Chapter 4: Programmer's Reference
class RealViewPBX(RealView):
uart = Pl011(pio_addr=0x10009000, int_num=44)
- realview_io = RealViewCtrl(pio_addr=0x10000000)
+ realview_io = VExpressCoreTileCtrl(pio_addr=0x10000000)
gic = Pl390()
timer0 = Sp804(int_num0=36, int_num1=36, pio_addr=0x10011000)
timer1 = Sp804(int_num0=37, int_num1=37, pio_addr=0x10012000)
@@ -354,7 +399,7 @@ class RealViewPBX(RealView):
# Chapter 4: Programmer's Reference
class RealViewEB(RealView):
uart = Pl011(pio_addr=0x10009000, int_num=44)
- realview_io = RealViewCtrl(pio_addr=0x10000000, idreg=0x01400500)
+ realview_io = VExpressCoreTileCtrl(pio_addr=0x10000000, idreg=0x01400500)
gic = Pl390(dist_addr=0x10041000, cpu_addr=0x10040000)
timer0 = Sp804(int_num0=36, int_num1=36, pio_addr=0x10011000)
timer1 = Sp804(int_num0=37, int_num1=37, pio_addr=0x10012000)
@@ -464,8 +509,9 @@ class VExpress_EMM(RealView):
_mem_regions = [(Addr('2GB'), Addr('2GB'))]
pci_cfg_base = 0x30000000
uart = Pl011(pio_addr=0x1c090000, int_num=37)
- realview_io = RealViewCtrl(proc_id0=0x14000000, proc_id1=0x14000000, \
- idreg=0x02250000, pio_addr=0x1C010000)
+ realview_io = VExpressCoreTileCtrl(
+ proc_id0=0x14000000, proc_id1=0x14000000,
+ idreg=0x02250000, pio_addr=0x1C010000)
gic = Pl390(dist_addr=0x2C001000, cpu_addr=0x2C002000)
local_cpu_timer = CpuLocalTimer(int_num_timer=29, int_num_watchdog=30, pio_addr=0x2C080000)
generic_timer = GenericTimer(int_phys=29, int_virt=27)
diff --git a/src/dev/arm/rv_ctrl.cc b/src/dev/arm/rv_ctrl.cc
index 27ba2e8a6..507def0c1 100644
--- a/src/dev/arm/rv_ctrl.cc
+++ b/src/dev/arm/rv_ctrl.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010,2013 ARM Limited
+ * Copyright (c) 2010,2013,2015 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@@ -42,6 +42,7 @@
#include "dev/arm/rv_ctrl.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
+#include "sim/voltage_domain.hh"
RealViewCtrl::RealViewCtrl(Params *p)
: BasicPioDevice(p, 0xD4), flags(0), scData(0)
@@ -155,86 +156,33 @@ RealViewCtrl::write(PacketPtr pkt)
// A request is being submitted to read/write the system control
// registers. See
// http://infocenter.arm.com/help/topic/com.arm.doc.dui0447h/CACDEFGH.html
- // For now, model as much of the OSC regs (can't find docs) as Linux
- // seems to require (can't find docs); some clocks are deemed to be 0,
- // giving all kinds of /0 problems booting Linux 3.9. Return a
- // vaguely plausible number within the range the device trees state:
- uint32_t data = pkt->get<uint32_t>();
- uint16_t dev = bits(data, 11, 0);
- uint8_t pos = bits(data, 15, 12);
- uint8_t site = bits(data, 17, 16);
- uint8_t func = bits(data, 25, 20);
- uint8_t dcc = bits(data, 29, 26);
- bool wr = bits(data, 30);
- bool start = bits(data, 31);
+ CfgCtrlReg req = pkt->get<uint32_t>();
+ if (!req.start) {
+ DPRINTF(RVCTRL, "SCReg: write %#x to ctrl but not starting\n",
+ req);
+ break;
+ }
+
+ auto it_dev(devices.find(req & CFG_CTRL_ADDR_MASK));
+ if (it_dev == devices.end()) {
+ warn_once("SCReg: Access to unknown device "
+ "dcc%d:site%d:pos%d:fn%d:dev%d\n",
+ req.dcc, req.site, req.pos, req.func, req.dev);
+ break;
+ }
+
+ // Service the request as a read or write depending on the
+ // wr bit in the control register.
+ Device &dev(*it_dev->second);
+ if (req.wr) {
+ DPRINTF(RVCTRL, "SCReg: Writing %#x (ctrlWr %#x)\n",
+ scData, req);
+ dev.write(scData);
- if (start) {
- if (wr) {
- warn_once("SCReg: Writing %#x to dcc%d:site%d:pos%d:fn%d:dev%d\n",
- scData, dcc, site, pos, func, dev);
- // Only really support reading, for now!
- } else {
- // Only deal with function 1 (oscillators) so far!
- if (dcc != 0 || pos != 0 || func != 1) {
- warn("SCReg: read from unknown area "
- "(dcc %d:site%d:pos%d:fn%d:dev%d)\n",
- dcc, site, pos, func, dev);
- } else {
- switch (site) {
- case 0: { // Motherboard regs
- switch(dev) {
- case 0: // MCC clk
- scData = 25000000;
- break;
- case 1: // CLCD clk
- scData = 25000000;
- break;
- case 2: // PeriphClk 24MHz
- scData = 24000000;
- break;
- default:
- scData = 0;
- warn("SCReg: read from unknown dev %d "
- "(site%d:pos%d:fn%d)\n",
- dev, site, pos, func);
- }
- } break;
- case 1: { // Coretile 1 regs
- switch(dev) {
- case 0: // CPU PLL ref
- scData = 50000000;
- break;
- case 4: // Muxed AXI master clock
- scData = 40000000;
- break;
- case 5: // HDLCD clk
- scData = 50000000;
- break;
- case 6: // SMB clock
- scData = 35000000;
- break;
- case 7: // SYS PLL (also used for pl011 UART!)
- scData = 40000000;
- break;
- case 8: // DDR PLL 40MHz fixed
- scData = 40000000;
- break;
- default:
- scData = 0;
- warn("SCReg: read from unknown dev %d "
- "(site%d:pos%d:fn%d)\n",
- dev, site, pos, func);
- }
- } break;
- default:
- warn("SCReg: Read from unknown site %d (pos%d:fn%d:dev%d)\n",
- site, pos, func, dev);
- }
- DPRINTF(RVCTRL, "SCReg: Will read %#x (ctrlWr %#x)\n", scData, data);
- }
- }
} else {
- DPRINTF(RVCTRL, "SCReg: write %#x to ctrl but not starting\n", data);
+ scData = dev.read();
+ DPRINTF(RVCTRL, "SCReg: Reading %#x (ctrlRd %#x)\n",
+ scData, req);
}
} break;
case CfgStat: // Weird to write this
@@ -259,8 +207,102 @@ RealViewCtrl::unserialize(CheckpointIn &cp)
UNSERIALIZE_SCALAR(flags);
}
+void
+RealViewCtrl::registerDevice(DeviceFunc func, uint8_t site, uint8_t pos,
+ uint8_t dcc, uint16_t dev,
+ Device *handler)
+{
+ CfgCtrlReg addr = 0;
+ addr.func = func;
+ addr.site = site;
+ addr.pos = pos;
+ addr.dcc = dcc;
+ addr.dev = dev;
+
+ if (devices.find(addr) != devices.end()) {
+ fatal("Platform device dcc%d:site%d:pos%d:fn%d:dev%d "
+ "already registered.",
+ addr.dcc, addr.site, addr.pos, addr.func, addr.dev);
+ }
+
+ devices[addr] = handler;
+}
+
+
+RealViewOsc::RealViewOsc(RealViewOscParams *p)
+ : ClockDomain(p, p->voltage_domain),
+ RealViewCtrl::Device(*p->parent, RealViewCtrl::FUNC_OSC,
+ p->site, p->position, p->dcc, p->device)
+{
+ if (SimClock::Float::s / p->freq > UINT32_MAX) {
+ fatal("Oscillator frequency out of range: %f\n",
+ SimClock::Float::s / p->freq / 1E6);
+ }
+
+ _clockPeriod = p->freq;
+}
+
+void
+RealViewOsc::startup()
+{
+ // Tell dependent object to set their clock frequency
+ for (auto m : members)
+ m->updateClockPeriod();
+}
+
+void
+RealViewOsc::serialize(CheckpointOut &cp) const
+{
+ SERIALIZE_SCALAR(_clockPeriod);
+}
+
+void
+RealViewOsc::unserialize(CheckpointIn &cp)
+{
+ UNSERIALIZE_SCALAR(_clockPeriod);
+}
+
+void
+RealViewOsc::clockPeriod(Tick clock_period)
+{
+ panic_if(clock_period == 0, "%s has a clock period of zero\n", name());
+
+ // Align all members to the current tick
+ for (auto m : members)
+ m->updateClockPeriod();
+
+ _clockPeriod = clock_period;
+
+ // inform any derived clocks they need to updated their period
+ for (auto m : children)
+ m->updateClockPeriod();
+}
+
+uint32_t
+RealViewOsc::read() const
+{
+ const uint32_t freq(SimClock::Float::s / _clockPeriod);
+ DPRINTF(RVCTRL, "Reading OSC frequency: %f MHz\n", freq / 1E6);
+ return freq;
+}
+
+void
+RealViewOsc::write(uint32_t freq)
+{
+ DPRINTF(RVCTRL, "Setting new OSC frequency: %f MHz\n", freq / 1E6);
+ clockPeriod(SimClock::Float::s / freq);
+}
+
+
+
RealViewCtrl *
RealViewCtrlParams::create()
{
return new RealViewCtrl(this);
}
+
+RealViewOsc *
+RealViewOscParams::create()
+{
+ return new RealViewOsc(this);
+}
diff --git a/src/dev/arm/rv_ctrl.hh b/src/dev/arm/rv_ctrl.hh
index cae5e2e2c..905fe14d9 100644
--- a/src/dev/arm/rv_ctrl.hh
+++ b/src/dev/arm/rv_ctrl.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010,2013 ARM Limited
+ * Copyright (c) 2010,2013,2015 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@@ -43,6 +43,7 @@
#include "base/bitunion.hh"
#include "dev/io_device.hh"
#include "params/RealViewCtrl.hh"
+#include "params/RealViewOsc.hh"
/** @file
* This implements the simple real view registers on a PBXA9
@@ -50,6 +51,37 @@
class RealViewCtrl : public BasicPioDevice
{
+ public:
+ enum DeviceFunc {
+ FUNC_OSC = 1,
+ FUNC_VOLT = 2,
+ FUNC_AMP = 3,
+ FUNC_TEMP = 4,
+ FUNC_RESET = 5,
+ FUNC_SCC = 6,
+ FUNC_MUXFPGA = 7,
+ FUNC_SHUTDOWN = 8,
+ FUNC_REBOOT = 9,
+ FUNC_DVIMODE = 11,
+ FUNC_POWER = 12,
+ FUNC_ENERGY = 13,
+ };
+
+ class Device
+ {
+ public:
+ Device(RealViewCtrl &parent, DeviceFunc func,
+ uint8_t site, uint8_t pos, uint8_t dcc, uint16_t dev)
+ {
+ parent.registerDevice(func, site, pos, dcc, dev, this);
+ }
+
+ virtual ~Device() {}
+
+ virtual uint32_t read() const = 0;
+ virtual void write(uint32_t value) = 0;
+ };
+
protected:
enum {
IdReg = 0x00,
@@ -96,6 +128,18 @@ class RealViewCtrl : public BasicPioDevice
Bitfield<16> locked;
EndBitUnion(SysLockReg)
+ BitUnion32(CfgCtrlReg)
+ Bitfield<11, 0> dev;
+ Bitfield<15, 12> pos;
+ Bitfield<17, 16> site;
+ Bitfield<25, 20> func;
+ Bitfield<29, 26> dcc;
+ Bitfield<30> wr;
+ Bitfield<31> start;
+ EndBitUnion(CfgCtrlReg)
+
+ static const uint32_t CFG_CTRL_ADDR_MASK = 0x3fffffffUL;
+
SysLockReg sysLock;
/** This register is used for smp booting.
@@ -127,17 +171,52 @@ class RealViewCtrl : public BasicPioDevice
* @param pkt The memory request.
* @param data Where to put the data.
*/
- virtual Tick read(PacketPtr pkt);
+ Tick read(PacketPtr pkt) M5_ATTR_OVERRIDE;
/**
* All writes are simply ignored.
* @param pkt The memory request.
* @param data the data
*/
- virtual Tick write(PacketPtr pkt);
+ Tick write(PacketPtr pkt) M5_ATTR_OVERRIDE;
void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE;
void unserialize(CheckpointIn &cp) M5_ATTR_OVERRIDE;
+
+ public:
+ void registerDevice(DeviceFunc func, uint8_t site, uint8_t pos,
+ uint8_t dcc, uint16_t dev,
+ Device *handler);
+
+ protected:
+ std::map<uint32_t, Device *> devices;
+};
+
+/**
+ * This is an implementation of a programmable oscillator on the that
+ * can be configured through the RealView/Versatile Express
+ * configuration interface.
+ *
+ * See ARM DUI 0447J (ARM Motherboard Express uATX -- V2M-P1).
+ */
+class RealViewOsc
+ : public ClockDomain, RealViewCtrl::Device
+{
+ public:
+ RealViewOsc(RealViewOscParams *p);
+ virtual ~RealViewOsc() {};
+
+ void startup() M5_ATTR_OVERRIDE;
+
+ void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE;
+ void unserialize(CheckpointIn &cp) M5_ATTR_OVERRIDE;
+
+ public: // RealViewCtrl::Device interface
+ uint32_t read() const M5_ATTR_OVERRIDE;
+ void write(uint32_t freq) M5_ATTR_OVERRIDE;
+
+ protected:
+ void clockPeriod(Tick clock_period);
};