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.
This commit is contained in:
parent
cd098a7e84
commit
598edaae05
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue