dev-arm: add FVP Base Power Controller model
This is a reduced model of the FVP Base platforms Power Controller. As of now it allows the following functions from software: - Checking for core presence - Reporting the power state of a core / cluster - Explicitly powering off a core on WFI - Explicitly powering off cores in a CPU cluster on WFI - Explicitly powering on a core through writes to PPONR register Change-Id: Ia1d4d3ae8e4bfb2d23b2c6077396a4d8500e2e30 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/26463 Maintainer: Giacomo Travaglini <giacomo.travaglini@arm.com> Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com> Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
committed by
Giacomo Travaglini
parent
8cfa988335
commit
5719da9fff
@@ -762,6 +762,7 @@ let {{
|
||||
fault = trapWFx(tc, cpsr, scr, false);
|
||||
if (fault == NoFault) {
|
||||
PseudoInst::quiesce(tc);
|
||||
ArmSystem::callSetStandByWfi(tc);
|
||||
} else {
|
||||
PseudoInst::quiesceSkip(tc);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2012-2013, 2015,2017-2019 ARM Limited
|
||||
* Copyright (c) 2010, 2012-2013, 2015,2017-2020 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "base/loader/object_file.hh"
|
||||
#include "base/loader/symtab.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "dev/arm/fvp_base_pwr_ctrl.hh"
|
||||
#include "dev/arm/gic_v2.hh"
|
||||
#include "mem/fs_translating_port_proxy.hh"
|
||||
#include "mem/physical.hh"
|
||||
@@ -62,6 +63,7 @@ ArmSystem::ArmSystem(Params *p)
|
||||
_haveCrypto(p->have_crypto),
|
||||
_genericTimer(nullptr),
|
||||
_gic(nullptr),
|
||||
_pwrCtrl(nullptr),
|
||||
_highestELIs64(p->highest_el_is_64),
|
||||
_physAddrRange64(p->phys_addr_range_64),
|
||||
_haveLargeAsid64(p->have_large_asid_64),
|
||||
@@ -197,6 +199,20 @@ ArmSystem::callSemihosting32(ThreadContext *tc,
|
||||
return sys->semihosting->call32(tc, op, param);
|
||||
}
|
||||
|
||||
void
|
||||
ArmSystem::callSetStandByWfi(ThreadContext *tc)
|
||||
{
|
||||
if (FVPBasePwrCtrl *pwr_ctrl = getArmSystem(tc)->getPowerController())
|
||||
pwr_ctrl->setStandByWfi(tc);
|
||||
}
|
||||
|
||||
void
|
||||
ArmSystem::callClearStandByWfi(ThreadContext *tc)
|
||||
{
|
||||
if (FVPBasePwrCtrl *pwr_ctrl = getArmSystem(tc)->getPowerController())
|
||||
pwr_ctrl->clearStandByWfi(tc);
|
||||
}
|
||||
|
||||
ArmSystem *
|
||||
ArmSystemParams::create()
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2012-2013, 2015-2019 ARM Limited
|
||||
* Copyright (c) 2010, 2012-2013, 2015-2020 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
@@ -53,6 +53,7 @@
|
||||
|
||||
class GenericTimer;
|
||||
class BaseGic;
|
||||
class FVPBasePwrCtrl;
|
||||
class ThreadContext;
|
||||
|
||||
class ArmSystem : public System
|
||||
@@ -84,6 +85,11 @@ class ArmSystem : public System
|
||||
GenericTimer *_genericTimer;
|
||||
BaseGic *_gic;
|
||||
|
||||
/**
|
||||
* Pointer to the Power Controller (if any)
|
||||
*/
|
||||
FVPBasePwrCtrl *_pwrCtrl;
|
||||
|
||||
/**
|
||||
* Reset address (ARMv8)
|
||||
*/
|
||||
@@ -175,12 +181,21 @@ class ArmSystem : public System
|
||||
/** Sets the pointer to the GIC. */
|
||||
void setGIC(BaseGic *gic) { _gic = gic; }
|
||||
|
||||
/** Sets the pointer to the Power Controller */
|
||||
void setPowerController(FVPBasePwrCtrl *pwr_ctrl)
|
||||
{
|
||||
_pwrCtrl = pwr_ctrl;
|
||||
}
|
||||
|
||||
/** Get a pointer to the system's generic timer model */
|
||||
GenericTimer *getGenericTimer() const { return _genericTimer; }
|
||||
|
||||
/** Get a pointer to the system's GIC */
|
||||
BaseGic *getGIC() const { return _gic; }
|
||||
|
||||
/** Get a pointer to the system's power controller */
|
||||
FVPBasePwrCtrl *getPowerController() const { return _pwrCtrl; }
|
||||
|
||||
/** Returns true if the register width of the highest implemented exception
|
||||
* level is 64 bits (ARMv8) */
|
||||
bool highestELIs64() const { return _highestELIs64; }
|
||||
@@ -305,6 +320,12 @@ class ArmSystem : public System
|
||||
/** Make a Semihosting call from aarch32 */
|
||||
static uint32_t callSemihosting32(ThreadContext *tc,
|
||||
uint32_t op, uint32_t param);
|
||||
|
||||
/** Make a call to notify the power controller of STANDBYWFI assertion */
|
||||
static void callSetStandByWfi(ThreadContext *tc);
|
||||
|
||||
/** Make a call to notify the power controller of STANDBYWFI deassertion */
|
||||
static void callClearStandByWfi(ThreadContext *tc);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1159,3 +1159,14 @@ class VExpress_GEM5_V2(VExpress_GEM5_V2_Base):
|
||||
return super(VExpress_GEM5_V2,self)._on_chip_devices() + [
|
||||
self.hdlcd,
|
||||
]
|
||||
|
||||
class FVPBasePwrCtrl(BasicPioDevice):
|
||||
"""
|
||||
Based on Fast Models Base_PowerController v11.8
|
||||
Reference:
|
||||
Fast Models Reference Manual - Section 7.7.2 - Version 11.8
|
||||
Document ID: 100964_1180_00_en
|
||||
"""
|
||||
|
||||
type = 'FVPBasePwrCtrl'
|
||||
cxx_header = 'dev/arm/fvp_base_pwr_ctrl.hh'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- mode:python -*-
|
||||
|
||||
# Copyright (c) 2009, 2012-2013 ARM Limited
|
||||
# Copyright (c) 2009, 2012-2013, 2020 ARM Limited
|
||||
# All rights reserved.
|
||||
#
|
||||
# The license below extends only to copyright in the software and shall
|
||||
@@ -92,6 +92,7 @@ if env['TARGET_ISA'] == 'arm':
|
||||
Source('vio_mmio.cc')
|
||||
Source('ufs_device.cc')
|
||||
Source('energy_ctrl.cc')
|
||||
Source('fvp_base_pwr_ctrl.cc')
|
||||
|
||||
DebugFlag('AMBA')
|
||||
DebugFlag('FlashDevice')
|
||||
@@ -106,6 +107,7 @@ if env['TARGET_ISA'] == 'arm':
|
||||
DebugFlag('SMMUv3Hazard')
|
||||
DebugFlag('Sp805')
|
||||
DebugFlag('EnergyCtrl')
|
||||
DebugFlag('FVPBasePwrCtrl')
|
||||
DebugFlag('UFSHostDevice')
|
||||
DebugFlag('VGIC')
|
||||
DebugFlag('NoMali')
|
||||
|
||||
289
src/dev/arm/fvp_base_pwr_ctrl.cc
Normal file
289
src/dev/arm/fvp_base_pwr_ctrl.cc
Normal file
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
* redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution;
|
||||
* neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "dev/arm/fvp_base_pwr_ctrl.hh"
|
||||
|
||||
#include "arch/arm/faults.hh"
|
||||
#include "arch/arm/system.hh"
|
||||
#include "arch/arm/utility.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "debug/FVPBasePwrCtrl.hh"
|
||||
#include "mem/packet_access.hh"
|
||||
#include "params/FVPBasePwrCtrl.hh"
|
||||
#include "sim/system.hh"
|
||||
|
||||
FVPBasePwrCtrl::FVPBasePwrCtrl(FVPBasePwrCtrlParams *const params)
|
||||
: BasicPioDevice(params, 0x1000),
|
||||
regs(),
|
||||
system(*static_cast<ArmSystem *>(sys))
|
||||
{
|
||||
warn_if(sys->multiThread,
|
||||
"Base Power Controller does not support multi-threaded systems\n");
|
||||
system.setPowerController(this);
|
||||
}
|
||||
|
||||
void
|
||||
FVPBasePwrCtrl::init()
|
||||
{
|
||||
// All cores are ON by default (PwrStatus.{l0,l1} = 0b1)
|
||||
corePwrStatus.resize(sys->numContexts(), 0x60000000);
|
||||
for (const auto &tc : sys->threadContexts)
|
||||
poweredCoresPerCluster[tc->socketId()] += 1;
|
||||
BasicPioDevice::init();
|
||||
}
|
||||
|
||||
void
|
||||
FVPBasePwrCtrl::setStandByWfi(ThreadContext *const tc)
|
||||
{
|
||||
PwrStatus *pwrs = getCorePwrStatus(tc);
|
||||
|
||||
if (!pwrs->pwfi)
|
||||
DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::setStandByWfi: STANDBYWFI "
|
||||
"asserted for core %d\n", tc->contextId());
|
||||
pwrs->pwfi = 1;
|
||||
if (pwrs->l0 && (pwrs->pp || pwrs->pc))
|
||||
powerCoreOff(tc, pwrs);
|
||||
}
|
||||
|
||||
void
|
||||
FVPBasePwrCtrl::clearStandByWfi(ThreadContext *const tc)
|
||||
{
|
||||
PwrStatus *pwrs = getCorePwrStatus(tc);
|
||||
|
||||
if (pwrs->pwfi)
|
||||
DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::clearStandByWfi: STANDBYWFI "
|
||||
"deasserted for core %d\n", tc->contextId());
|
||||
pwrs->pwfi = 0;
|
||||
}
|
||||
|
||||
Tick
|
||||
FVPBasePwrCtrl::read(PacketPtr pkt)
|
||||
{
|
||||
const Addr addr = pkt->getAddr() - pioAddr;
|
||||
const size_t size = pkt->getSize();
|
||||
panic_if(size != 4, "FVPBasePwrCtrl::read: Invalid size %i\n", size);
|
||||
|
||||
uint64_t resp = 0;
|
||||
switch (addr) {
|
||||
case PPOFFR:
|
||||
resp = regs.ppoffr;
|
||||
break;
|
||||
case PPONR:
|
||||
resp = regs.pponr;
|
||||
break;
|
||||
case PCOFFR:
|
||||
resp = regs.pcoffr;
|
||||
break;
|
||||
case PWKUPR:
|
||||
resp = regs.pwkupr;
|
||||
break;
|
||||
case PSYSR:
|
||||
resp = regs.psysr;
|
||||
break;
|
||||
default:
|
||||
warn("FVPBasePwrCtrl::read: Unexpected address (0x%x:%i), "
|
||||
"assuming RAZ\n", addr, size);
|
||||
}
|
||||
|
||||
DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::read: 0x%x<-0x%x(%i)\n", resp,
|
||||
addr, size);
|
||||
|
||||
pkt->setUintX(resp, LittleEndianByteOrder);
|
||||
pkt->makeResponse();
|
||||
return pioDelay;
|
||||
}
|
||||
|
||||
Tick
|
||||
FVPBasePwrCtrl::write(PacketPtr pkt)
|
||||
{
|
||||
const Addr addr = pkt->getAddr() - pioAddr;
|
||||
const size_t size = pkt->getSize();
|
||||
panic_if(size != 4, "FVPBasePwrCtrl::write: Invalid size %i\n", size);
|
||||
|
||||
uint64_t data = pkt->getUintX(LittleEndianByteOrder);
|
||||
|
||||
// Software may use the power controller to check for core presence
|
||||
// If core is not present, return an invalid MPID as notification
|
||||
ThreadContext *tc = getThreadContextByMPID(data & MPID_MSK);
|
||||
PwrStatus *pwrs = tc ? getCorePwrStatus(tc) : nullptr;
|
||||
switch (addr) {
|
||||
case PPOFFR:
|
||||
if (!tc) {
|
||||
regs.ppoffr = ~0;
|
||||
} else if (pwrs->l0) {
|
||||
// Set pending power off
|
||||
pwrs->pp = 1;
|
||||
regs.ppoffr = data & MPID_MSK;
|
||||
} else {
|
||||
regs.ppoffr = ~0 & MPID_MSK;
|
||||
}
|
||||
break;
|
||||
case PPONR:
|
||||
if (!tc) {
|
||||
regs.pponr = ~0;
|
||||
} else {
|
||||
if (!pwrs->l0) {
|
||||
pwrs->wk = WK_PPONR;
|
||||
powerCoreOn(tc, pwrs);
|
||||
startCoreUp(tc);
|
||||
regs.pponr = data & MPID_MSK;
|
||||
} else {
|
||||
regs.pponr = ~0 & MPID_MSK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PCOFFR:
|
||||
if (!tc) {
|
||||
regs.pcoffr = ~0;
|
||||
} else if (pwrs->l0) {
|
||||
// Power off all cores in the cluster
|
||||
for (const auto &tco : sys->threadContexts) {
|
||||
if (tc->socketId() == tco->socketId()) {
|
||||
PwrStatus *npwrs = getCorePwrStatus(tco);
|
||||
// Set pending cluster power off
|
||||
npwrs->pc = 1;
|
||||
if (npwrs->l0 && npwrs->pwfi)
|
||||
powerCoreOff(tco, npwrs);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
regs.pcoffr = ~0 & MPID_MSK;
|
||||
}
|
||||
break;
|
||||
case PWKUPR:
|
||||
if (!tc) {
|
||||
regs.pwkupr = ~0;
|
||||
} else {
|
||||
// Update WEN value
|
||||
pwrs->wen = bits(data, 31);
|
||||
// Power-on if there is any pending Wakeup Requests
|
||||
if (!pwrs->l0 && pwrs->wen && pwrs->pwk) {
|
||||
pwrs->wk = WK_GICWR;
|
||||
powerCoreOn(tc, pwrs);
|
||||
startCoreUp(tc);
|
||||
}
|
||||
regs.pwkupr = data & (MPID_MSK | (1 << 31));
|
||||
}
|
||||
break;
|
||||
case PSYSR:
|
||||
if (!tc)
|
||||
regs.psysr = ~0;
|
||||
else
|
||||
regs.psysr = (data & MPID_MSK) | (((uint32_t) *pwrs) & ~MPID_MSK);
|
||||
break;
|
||||
default:
|
||||
warn("FVPBasePwrCtrl::write: Unexpected address (0x%x:%i), "
|
||||
"assuming WI\n", addr, size);
|
||||
}
|
||||
|
||||
DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::write: 0x%x->0x%x(%i)\n", data,
|
||||
addr, size);
|
||||
|
||||
pkt->makeResponse();
|
||||
return pioDelay;
|
||||
}
|
||||
|
||||
FVPBasePwrCtrl::PwrStatus *
|
||||
FVPBasePwrCtrl::getCorePwrStatus(ThreadContext *const tc)
|
||||
{
|
||||
PwrStatus *pwrs = &corePwrStatus[tc->contextId()];
|
||||
pwrs->l1 = poweredCoresPerCluster[tc->socketId()] > 0;
|
||||
return pwrs;
|
||||
}
|
||||
|
||||
ThreadContext *
|
||||
FVPBasePwrCtrl::getThreadContextByMPID(uint32_t mpid) const
|
||||
{
|
||||
for (auto &tc : sys->threadContexts) {
|
||||
if (mpid == ArmISA::getAffinity(&system, tc))
|
||||
return tc;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
FVPBasePwrCtrl::powerCoreOn(ThreadContext *const tc, PwrStatus *const pwrs)
|
||||
{
|
||||
DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::powerCoreOn: Powering ON "
|
||||
"core %d\n", tc->contextId());
|
||||
pwrs->l0 = 1;
|
||||
poweredCoresPerCluster[tc->socketId()]++;
|
||||
// Clear pending power-offs to the core
|
||||
pwrs->pp = 0;
|
||||
// Clear pending power-offs to the core's cluster
|
||||
for (const auto &tco : sys->threadContexts) {
|
||||
if (tc->socketId() == tco->socketId()) {
|
||||
PwrStatus *npwrs = getCorePwrStatus(tco);
|
||||
npwrs->pc = 0;
|
||||
}
|
||||
}
|
||||
tc->getCpuPtr()->pwrState(Enums::PwrState::ON);
|
||||
}
|
||||
|
||||
void
|
||||
FVPBasePwrCtrl::powerCoreOff(ThreadContext *const tc, PwrStatus *const pwrs)
|
||||
{
|
||||
DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::powerCoreOff: Powering OFF "
|
||||
"core %d\n", tc->contextId());
|
||||
pwrs->l0 = 0;
|
||||
poweredCoresPerCluster[tc->socketId()]--;
|
||||
// Clear pending power-offs to the core
|
||||
pwrs->pp = 0;
|
||||
pwrs->pc = 0;
|
||||
// Clear power-on reason
|
||||
pwrs->wk = 0;
|
||||
tc->getCpuPtr()->pwrState(Enums::PwrState::OFF);
|
||||
}
|
||||
|
||||
void
|
||||
FVPBasePwrCtrl::startCoreUp(ThreadContext *const tc)
|
||||
{
|
||||
DPRINTF(FVPBasePwrCtrl, "FVPBasePwrCtrl::startCoreUp: Starting core %d "
|
||||
"from the power controller\n", tc->contextId());
|
||||
clearStandByWfi(tc);
|
||||
|
||||
// InitCPU
|
||||
Reset().invoke(tc);
|
||||
tc->activate();
|
||||
}
|
||||
|
||||
FVPBasePwrCtrl *
|
||||
FVPBasePwrCtrlParams::create()
|
||||
{
|
||||
return new FVPBasePwrCtrl(this);
|
||||
}
|
||||
173
src/dev/arm/fvp_base_pwr_ctrl.hh
Normal file
173
src/dev/arm/fvp_base_pwr_ctrl.hh
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
* redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution;
|
||||
* neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __DEV_ARM_FVP_BASE_PWR_CTRL_HH__
|
||||
#define __DEV_ARM_FVP_BASE_PWR_CTRL_HH__
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "base/bitunion.hh"
|
||||
#include "dev/io_device.hh"
|
||||
|
||||
class ArmSystem;
|
||||
class FVPBasePwrCtrlParams;
|
||||
class ThreadContext;
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This class implements the base power controller for FVP-based
|
||||
* platforms. Based on Fast Models version 11.8.
|
||||
*
|
||||
* Limitations:
|
||||
* - Level 2 affinity is not implemented -> PSYSR.L2 is RAZ
|
||||
* - WakeRequests are not modelled by GICv3 -> PSYSR.WEN is always 0
|
||||
* - PSYSR.WK can only be 0b00 (Cold power-on) and 0b10 (Wake by PPONR)
|
||||
*/
|
||||
class FVPBasePwrCtrl : public BasicPioDevice
|
||||
{
|
||||
public:
|
||||
FVPBasePwrCtrl(FVPBasePwrCtrlParams *const params);
|
||||
|
||||
/**
|
||||
* Triggered by the ISA when a WFI instruction is executed and (1) there
|
||||
* are no pending interrupts and (2) it is not trapped. Core is set
|
||||
* to quiescent state only if there is a pending power off
|
||||
* @param tc Thread context representing the core
|
||||
*/
|
||||
void setStandByWfi(ThreadContext *const tc);
|
||||
|
||||
/**
|
||||
* Triggered when an interrupt is posted to the core. Core is brought up
|
||||
* from quiescent state if it is suspended. The latter is done by
|
||||
* BaseCPU::wakeup.
|
||||
* @param tc Thread context representing the core
|
||||
*/
|
||||
void clearStandByWfi(ThreadContext *const tc);
|
||||
|
||||
void init() override;
|
||||
|
||||
protected:
|
||||
Tick read(PacketPtr pkt) override;
|
||||
Tick write(PacketPtr pkt) override;
|
||||
|
||||
private:
|
||||
BitUnion32(PwrStatus)
|
||||
Bitfield<30> l1;
|
||||
Bitfield<29> l0;
|
||||
Bitfield<28> wen;
|
||||
Bitfield<27> pc;
|
||||
Bitfield<26> pp;
|
||||
Bitfield<25,24> wk;
|
||||
Bitfield<1> pwfi;
|
||||
Bitfield<0> pwk;
|
||||
EndBitUnion(PwrStatus)
|
||||
|
||||
enum Offset : Addr {
|
||||
PPOFFR = 0x00,
|
||||
PPONR = 0x04,
|
||||
PCOFFR = 0x08,
|
||||
PWKUPR = 0x0c,
|
||||
PSYSR = 0x10
|
||||
};
|
||||
|
||||
struct Registers {
|
||||
uint32_t ppoffr;
|
||||
uint32_t pponr;
|
||||
uint32_t pcoffr;
|
||||
uint32_t pwkupr;
|
||||
uint32_t psysr;
|
||||
} regs;
|
||||
|
||||
/** Mask for extracting the MPID from a 32-bit value */
|
||||
static constexpr uint32_t MPID_MSK = 0x00ffffff;
|
||||
/** Wake-up reasons */
|
||||
enum { WK_COLD, WK_RESET, WK_PPONR, WK_GICWR };
|
||||
|
||||
/**
|
||||
* Per-core power status. This is power related information for each core
|
||||
* that is bound to this power controller functionality
|
||||
*/
|
||||
std::vector<PwrStatus> corePwrStatus;
|
||||
|
||||
/** Number of powered cores per cluster. Helps keep track of PSYSR.L1 */
|
||||
std::unordered_map<uint32_t, size_t> poweredCoresPerCluster;
|
||||
|
||||
/**
|
||||
* Retrieves the power status of a certain core and resizes the entries
|
||||
* if needed. This is a workaround for a limitation of the System object
|
||||
* only exposing existing thread contexts after "init()"
|
||||
* @param Thread (HW) context in the core
|
||||
* @return Core power status
|
||||
*/
|
||||
PwrStatus *getCorePwrStatus(ThreadContext *const tc);
|
||||
|
||||
/**
|
||||
* Retrieves the thread context reference for a CPU core by MPID
|
||||
* @param mpid ID provided by software
|
||||
* @return valid thread context reference if valid MPID, nullptr otherwise
|
||||
*/
|
||||
ThreadContext *getThreadContextByMPID(uint32_t mpid) const;
|
||||
|
||||
/**
|
||||
* Powers on a core. A Reset fault is invoked in the core followed by
|
||||
* an activation
|
||||
* @param Thread (HW) context in the core
|
||||
* @param Core power status
|
||||
*/
|
||||
void powerCoreOn(ThreadContext *const tc, PwrStatus *const pwrs);
|
||||
|
||||
/**
|
||||
* Powers off a core. The core enters into quiescent state until
|
||||
* an explicit PPONR write or a WakeRequest from the GIC wakes it up
|
||||
* @param Thread (HW) context in the core
|
||||
* @param Core power status
|
||||
*/
|
||||
void powerCoreOff(ThreadContext *const tc, PwrStatus *const pwrs);
|
||||
|
||||
/**
|
||||
* Starts a core up. This invokes the reset vector to setup the wake-up
|
||||
* entrypoint and activates the thread context. This covers cases when
|
||||
* PSYSR.WEN is enabled or PPONR is written
|
||||
* @param Thread (HW) context in the core
|
||||
*/
|
||||
void startCoreUp(ThreadContext *const tc);
|
||||
|
||||
/** Reference to the arm system */
|
||||
ArmSystem &system;
|
||||
};
|
||||
|
||||
#endif // __DEV_ARM_FVP_BASE_PWR_CTRL_HH__
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 ARM Limited
|
||||
* Copyright (c) 2019-2020 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
@@ -205,6 +205,7 @@ void
|
||||
Gicv3::postInt(uint32_t cpu, ArmISA::InterruptTypes int_type)
|
||||
{
|
||||
platform->intrctrl->post(cpu, int_type, 0);
|
||||
ArmSystem::callClearStandByWfi(sys->getThreadContext(cpu));
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
Reference in New Issue
Block a user