From 598edaae0509c455e06e1689fd3c50caaeef0f30 Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Fri, 7 Aug 2015 09:59:25 +0100 Subject: 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. --- src/dev/arm/RealView.py | 54 ++++++++++++- src/dev/arm/rv_ctrl.cc | 200 +++++++++++++++++++++++++++++------------------- src/dev/arm/rv_ctrl.hh | 85 +++++++++++++++++++- 3 files changed, 253 insertions(+), 86 deletions(-) (limited to 'src/dev') 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(); - 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(); + 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 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); }; -- cgit v1.2.3