2 * Copyright (c) 2020 ARM Limited
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 #include "dev/arm/fvp_base_pwr_ctrl.hh"
40 #include "arch/arm/faults.hh"
41 #include "arch/arm/system.hh"
42 #include "arch/arm/utility.hh"
43 #include "cpu/base.hh"
44 #include "cpu/thread_context.hh"
45 #include "debug/FVPBasePwrCtrl.hh"
46 #include "mem/packet_access.hh"
47 #include "params/FVPBasePwrCtrl.hh"
48 #include "sim/system.hh"
50 FVPBasePwrCtrl::FVPBasePwrCtrl(FVPBasePwrCtrlParams
*const params
)
51 : BasicPioDevice(params
, 0x1000),
53 system(*static_cast<ArmSystem
*>(sys
))
55 warn_if(sys
->multiThread
,
56 "Base Power Controller does not support multi-threaded systems\n");
57 system
.setPowerController(this);
61 FVPBasePwrCtrl::init()
63 // All cores are ON by default (PwrStatus.{l0,l1} = 0b1)
64 corePwrStatus
.resize(sys
->threads
.size(), 0x60000000);
65 for (const auto &tc
: sys
->threads
)
66 poweredCoresPerCluster
[tc
->socketId()] += 1;
67 BasicPioDevice::init();
71 FVPBasePwrCtrl::setStandByWfi(ThreadContext
*const tc
)
73 PwrStatus
*pwrs
= getCorePwrStatus(tc
);
76 DPRINTF(FVPBasePwrCtrl
, "FVPBasePwrCtrl::setStandByWfi: STANDBYWFI "
77 "asserted for core %d\n", tc
->contextId());
79 if (pwrs
->l0
&& (pwrs
->pp
|| pwrs
->pc
))
80 powerCoreOff(tc
, pwrs
);
84 FVPBasePwrCtrl::clearStandByWfi(ThreadContext
*const tc
)
86 PwrStatus
*pwrs
= getCorePwrStatus(tc
);
89 DPRINTF(FVPBasePwrCtrl
, "FVPBasePwrCtrl::clearStandByWfi: STANDBYWFI "
90 "deasserted for core %d\n", tc
->contextId());
95 FVPBasePwrCtrl::setWakeRequest(ThreadContext
*const tc
)
97 PwrStatus
*pwrs
= getCorePwrStatus(tc
);
100 DPRINTF(FVPBasePwrCtrl
, "FVPBasePwrCtrl::setWakeRequest: WakeRequest "
101 "asserted for core %d\n", tc
->contextId());
103 if (!pwrs
->l0
&& pwrs
->wen
) {
105 powerCoreOn(tc
, pwrs
);
112 FVPBasePwrCtrl::clearWakeRequest(ThreadContext
*const tc
)
114 PwrStatus
*pwrs
= getCorePwrStatus(tc
);
117 DPRINTF(FVPBasePwrCtrl
, "FVPBasePwrCtrl::clearWakeRequest: "
118 "WakeRequest deasserted for core %d\n", tc
->contextId());
123 FVPBasePwrCtrl::read(PacketPtr pkt
)
125 const Addr addr
= pkt
->getAddr() - pioAddr
;
126 const size_t size
= pkt
->getSize();
127 panic_if(size
!= 4, "FVPBasePwrCtrl::read: Invalid size %i\n", size
);
147 warn("FVPBasePwrCtrl::read: Unexpected address (0x%x:%i), "
148 "assuming RAZ\n", addr
, size
);
151 DPRINTF(FVPBasePwrCtrl
, "FVPBasePwrCtrl::read: 0x%x<-0x%x(%i)\n", resp
,
154 pkt
->setUintX(resp
, ByteOrder::little
);
160 FVPBasePwrCtrl::write(PacketPtr pkt
)
162 const Addr addr
= pkt
->getAddr() - pioAddr
;
163 const size_t size
= pkt
->getSize();
164 panic_if(size
!= 4, "FVPBasePwrCtrl::write: Invalid size %i\n", size
);
166 uint64_t data
= pkt
->getUintX(ByteOrder::little
);
168 // Software may use the power controller to check for core presence
169 // If core is not present, return an invalid MPID as notification
170 ThreadContext
*tc
= getThreadContextByMPID(data
& MPID_MSK
);
171 PwrStatus
*pwrs
= tc
? getCorePwrStatus(tc
) : nullptr;
176 } else if (pwrs
->l0
) {
177 // Set pending power off
179 regs
.ppoffr
= data
& MPID_MSK
;
181 regs
.ppoffr
= ~0 & MPID_MSK
;
190 powerCoreOn(tc
, pwrs
);
192 regs
.pponr
= data
& MPID_MSK
;
194 regs
.pponr
= ~0 & MPID_MSK
;
201 } else if (pwrs
->l0
) {
202 // Power off all cores in the cluster
203 for (const auto &tco
: sys
->threads
) {
204 if (tc
->socketId() == tco
->socketId()) {
205 PwrStatus
*npwrs
= getCorePwrStatus(tco
);
206 // Set pending cluster power off
208 if (npwrs
->l0
&& npwrs
->pwfi
)
209 powerCoreOff(tco
, npwrs
);
213 regs
.pcoffr
= ~0 & MPID_MSK
;
221 pwrs
->wen
= bits(data
, 31);
222 // Power-on if there is any pending Wakeup Requests
223 if (!pwrs
->l0
&& pwrs
->wen
&& pwrs
->pwk
) {
225 powerCoreOn(tc
, pwrs
);
228 regs
.pwkupr
= data
& (MPID_MSK
| (1 << 31));
235 regs
.psysr
= (data
& MPID_MSK
) | (((uint32_t) *pwrs
) & ~MPID_MSK
);
238 warn("FVPBasePwrCtrl::write: Unexpected address (0x%x:%i), "
239 "assuming WI\n", addr
, size
);
242 DPRINTF(FVPBasePwrCtrl
, "FVPBasePwrCtrl::write: 0x%x->0x%x(%i)\n", data
,
249 FVPBasePwrCtrl::PwrStatus
*
250 FVPBasePwrCtrl::getCorePwrStatus(ThreadContext
*const tc
)
252 PwrStatus
*pwrs
= &corePwrStatus
[tc
->contextId()];
253 pwrs
->l1
= poweredCoresPerCluster
[tc
->socketId()] > 0;
258 FVPBasePwrCtrl::getThreadContextByMPID(uint32_t mpid
) const
260 for (auto &tc
: sys
->threads
) {
261 if (mpid
== ArmISA::getAffinity(&system
, tc
))
268 FVPBasePwrCtrl::powerCoreOn(ThreadContext
*const tc
, PwrStatus
*const pwrs
)
270 DPRINTF(FVPBasePwrCtrl
, "FVPBasePwrCtrl::powerCoreOn: Powering ON "
271 "core %d\n", tc
->contextId());
273 poweredCoresPerCluster
[tc
->socketId()]++;
274 // Clear pending power-offs to the core
276 // Clear pending power-offs to the core's cluster
277 for (const auto &tco
: sys
->threads
) {
278 if (tc
->socketId() == tco
->socketId()) {
279 PwrStatus
*npwrs
= getCorePwrStatus(tco
);
283 tc
->getCpuPtr()->powerState
->set(Enums::PwrState::ON
);
287 FVPBasePwrCtrl::powerCoreOff(ThreadContext
*const tc
, PwrStatus
*const pwrs
)
289 DPRINTF(FVPBasePwrCtrl
, "FVPBasePwrCtrl::powerCoreOff: Powering OFF "
290 "core %d\n", tc
->contextId());
292 poweredCoresPerCluster
[tc
->socketId()]--;
293 // Clear pending power-offs to the core
296 // Clear power-on reason
298 tc
->getCpuPtr()->powerState
->set(Enums::PwrState::OFF
);
302 FVPBasePwrCtrl::startCoreUp(ThreadContext
*const tc
)
304 DPRINTF(FVPBasePwrCtrl
, "FVPBasePwrCtrl::startCoreUp: Starting core %d "
305 "from the power controller\n", tc
->contextId());
307 clearWakeRequest(tc
);
310 ArmISA::Reset().invoke(tc
);
315 FVPBasePwrCtrlParams::create()
317 return new FVPBasePwrCtrl(this);