summaryrefslogtreecommitdiff
path: root/src/dev/arm/rv_ctrl.cc
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/dev/arm/rv_ctrl.cc
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/dev/arm/rv_ctrl.cc')
-rw-r--r--src/dev/arm/rv_ctrl.cc200
1 files changed, 121 insertions, 79 deletions
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);
+}