1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <assert.h> 8*91f16700Schasinglulu 9*91f16700Schasinglulu #include <arch_features.h> 10*91f16700Schasinglulu #include <arch_helpers.h> 11*91f16700Schasinglulu #include <common/debug.h> 12*91f16700Schasinglulu #include <drivers/arm/gicv3.h> 13*91f16700Schasinglulu #include <drivers/arm/fvp/fvp_pwrc.h> 14*91f16700Schasinglulu #include <lib/extensions/spe.h> 15*91f16700Schasinglulu #include <lib/mmio.h> 16*91f16700Schasinglulu #include <lib/psci/psci.h> 17*91f16700Schasinglulu #include <plat/arm/common/arm_config.h> 18*91f16700Schasinglulu #include <plat/arm/common/plat_arm.h> 19*91f16700Schasinglulu #include <platform_def.h> 20*91f16700Schasinglulu 21*91f16700Schasinglulu #include "fvp_private.h" 22*91f16700Schasinglulu #include "../drivers/arm/gic/v3/gicv3_private.h" 23*91f16700Schasinglulu 24*91f16700Schasinglulu 25*91f16700Schasinglulu #if ARM_RECOM_STATE_ID_ENC 26*91f16700Schasinglulu /* 27*91f16700Schasinglulu * The table storing the valid idle power states. Ensure that the 28*91f16700Schasinglulu * array entries are populated in ascending order of state-id to 29*91f16700Schasinglulu * enable us to use binary search during power state validation. 30*91f16700Schasinglulu * The table must be terminated by a NULL entry. 31*91f16700Schasinglulu */ 32*91f16700Schasinglulu const unsigned int arm_pm_idle_states[] = { 33*91f16700Schasinglulu /* State-id - 0x01 */ 34*91f16700Schasinglulu arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RET, 35*91f16700Schasinglulu ARM_PWR_LVL0, PSTATE_TYPE_STANDBY), 36*91f16700Schasinglulu /* State-id - 0x02 */ 37*91f16700Schasinglulu arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_OFF, 38*91f16700Schasinglulu ARM_PWR_LVL0, PSTATE_TYPE_POWERDOWN), 39*91f16700Schasinglulu /* State-id - 0x22 */ 40*91f16700Schasinglulu arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF, 41*91f16700Schasinglulu ARM_PWR_LVL1, PSTATE_TYPE_POWERDOWN), 42*91f16700Schasinglulu /* State-id - 0x222 */ 43*91f16700Schasinglulu arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF, 44*91f16700Schasinglulu ARM_LOCAL_STATE_OFF, ARM_PWR_LVL2, PSTATE_TYPE_POWERDOWN), 45*91f16700Schasinglulu 0, 46*91f16700Schasinglulu }; 47*91f16700Schasinglulu #endif 48*91f16700Schasinglulu 49*91f16700Schasinglulu /******************************************************************************* 50*91f16700Schasinglulu * Function which implements the common FVP specific operations to power down a 51*91f16700Schasinglulu * cluster in response to a CPU_OFF or CPU_SUSPEND request. 52*91f16700Schasinglulu ******************************************************************************/ 53*91f16700Schasinglulu static void fvp_cluster_pwrdwn_common(void) 54*91f16700Schasinglulu { 55*91f16700Schasinglulu uint64_t mpidr = read_mpidr_el1(); 56*91f16700Schasinglulu 57*91f16700Schasinglulu /* 58*91f16700Schasinglulu * On power down we need to disable statistical profiling extensions 59*91f16700Schasinglulu * before exiting coherency. 60*91f16700Schasinglulu */ 61*91f16700Schasinglulu if (is_feat_spe_supported()) { 62*91f16700Schasinglulu spe_disable(); 63*91f16700Schasinglulu } 64*91f16700Schasinglulu 65*91f16700Schasinglulu /* Disable coherency if this cluster is to be turned off */ 66*91f16700Schasinglulu fvp_interconnect_disable(); 67*91f16700Schasinglulu 68*91f16700Schasinglulu /* Program the power controller to turn the cluster off */ 69*91f16700Schasinglulu fvp_pwrc_write_pcoffr(mpidr); 70*91f16700Schasinglulu } 71*91f16700Schasinglulu 72*91f16700Schasinglulu /* 73*91f16700Schasinglulu * Empty implementation of these hooks avoid setting the GICR_WAKER.Sleep bit 74*91f16700Schasinglulu * on ARM GICv3 implementations on FVP. This is required, because FVP does not 75*91f16700Schasinglulu * support SYSTEM_SUSPEND and it is `faked` in firmware. Hence, for wake up 76*91f16700Schasinglulu * from `fake` system suspend the GIC must not be powered off. 77*91f16700Schasinglulu */ 78*91f16700Schasinglulu void arm_gicv3_distif_pre_save(unsigned int rdist_proc_num) 79*91f16700Schasinglulu {} 80*91f16700Schasinglulu 81*91f16700Schasinglulu void arm_gicv3_distif_post_restore(unsigned int rdist_proc_num) 82*91f16700Schasinglulu {} 83*91f16700Schasinglulu 84*91f16700Schasinglulu static void fvp_power_domain_on_finish_common(const psci_power_state_t *target_state) 85*91f16700Schasinglulu { 86*91f16700Schasinglulu unsigned long mpidr; 87*91f16700Schasinglulu 88*91f16700Schasinglulu assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == 89*91f16700Schasinglulu ARM_LOCAL_STATE_OFF); 90*91f16700Schasinglulu 91*91f16700Schasinglulu /* Get the mpidr for this cpu */ 92*91f16700Schasinglulu mpidr = read_mpidr_el1(); 93*91f16700Schasinglulu 94*91f16700Schasinglulu /* Perform the common cluster specific operations */ 95*91f16700Schasinglulu if (target_state->pwr_domain_state[ARM_PWR_LVL1] == 96*91f16700Schasinglulu ARM_LOCAL_STATE_OFF) { 97*91f16700Schasinglulu /* 98*91f16700Schasinglulu * This CPU might have woken up whilst the cluster was 99*91f16700Schasinglulu * attempting to power down. In this case the FVP power 100*91f16700Schasinglulu * controller will have a pending cluster power off request 101*91f16700Schasinglulu * which needs to be cleared by writing to the PPONR register. 102*91f16700Schasinglulu * This prevents the power controller from interpreting a 103*91f16700Schasinglulu * subsequent entry of this cpu into a simple wfi as a power 104*91f16700Schasinglulu * down request. 105*91f16700Schasinglulu */ 106*91f16700Schasinglulu fvp_pwrc_write_pponr(mpidr); 107*91f16700Schasinglulu 108*91f16700Schasinglulu /* Enable coherency if this cluster was off */ 109*91f16700Schasinglulu fvp_interconnect_enable(); 110*91f16700Schasinglulu } 111*91f16700Schasinglulu /* Perform the common system specific operations */ 112*91f16700Schasinglulu if (target_state->pwr_domain_state[ARM_PWR_LVL2] == 113*91f16700Schasinglulu ARM_LOCAL_STATE_OFF) 114*91f16700Schasinglulu arm_system_pwr_domain_resume(); 115*91f16700Schasinglulu 116*91f16700Schasinglulu /* 117*91f16700Schasinglulu * Clear PWKUPR.WEN bit to ensure interrupts do not interfere 118*91f16700Schasinglulu * with a cpu power down unless the bit is set again 119*91f16700Schasinglulu */ 120*91f16700Schasinglulu fvp_pwrc_clr_wen(mpidr); 121*91f16700Schasinglulu } 122*91f16700Schasinglulu 123*91f16700Schasinglulu /******************************************************************************* 124*91f16700Schasinglulu * FVP handler called when a CPU is about to enter standby. 125*91f16700Schasinglulu ******************************************************************************/ 126*91f16700Schasinglulu static void fvp_cpu_standby(plat_local_state_t cpu_state) 127*91f16700Schasinglulu { 128*91f16700Schasinglulu u_register_t scr = read_scr_el3(); 129*91f16700Schasinglulu 130*91f16700Schasinglulu assert(cpu_state == ARM_LOCAL_STATE_RET); 131*91f16700Schasinglulu 132*91f16700Schasinglulu /* 133*91f16700Schasinglulu * Enable the Non-secure interrupt to wake the CPU. 134*91f16700Schasinglulu * In GICv3 affinity routing mode, the Non-secure Group 1 interrupts 135*91f16700Schasinglulu * use Physical FIQ at EL3 whereas in GICv2, Physical IRQ is used. 136*91f16700Schasinglulu * Enabling both the bits works for both GICv2 mode and GICv3 affinity 137*91f16700Schasinglulu * routing mode. 138*91f16700Schasinglulu */ 139*91f16700Schasinglulu write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT); 140*91f16700Schasinglulu isb(); 141*91f16700Schasinglulu 142*91f16700Schasinglulu /* 143*91f16700Schasinglulu * Enter standby state. 144*91f16700Schasinglulu * dsb is good practice before using wfi to enter low power states. 145*91f16700Schasinglulu */ 146*91f16700Schasinglulu dsb(); 147*91f16700Schasinglulu wfi(); 148*91f16700Schasinglulu 149*91f16700Schasinglulu /* 150*91f16700Schasinglulu * Restore SCR_EL3 to the original value, synchronisation of SCR_EL3 151*91f16700Schasinglulu * is done by eret in el3_exit() to save some execution cycles. 152*91f16700Schasinglulu */ 153*91f16700Schasinglulu write_scr_el3(scr); 154*91f16700Schasinglulu } 155*91f16700Schasinglulu 156*91f16700Schasinglulu /******************************************************************************* 157*91f16700Schasinglulu * FVP handler called when a power domain is about to be turned on. The 158*91f16700Schasinglulu * mpidr determines the CPU to be turned on. 159*91f16700Schasinglulu ******************************************************************************/ 160*91f16700Schasinglulu static int fvp_pwr_domain_on(u_register_t mpidr) 161*91f16700Schasinglulu { 162*91f16700Schasinglulu int rc = PSCI_E_SUCCESS; 163*91f16700Schasinglulu unsigned int psysr; 164*91f16700Schasinglulu 165*91f16700Schasinglulu /* 166*91f16700Schasinglulu * Ensure that we do not cancel an inflight power off request for the 167*91f16700Schasinglulu * target cpu. That would leave it in a zombie wfi. Wait for it to power 168*91f16700Schasinglulu * off and then program the power controller to turn that CPU on. 169*91f16700Schasinglulu */ 170*91f16700Schasinglulu do { 171*91f16700Schasinglulu psysr = fvp_pwrc_read_psysr(mpidr); 172*91f16700Schasinglulu } while ((psysr & PSYSR_AFF_L0) != 0U); 173*91f16700Schasinglulu 174*91f16700Schasinglulu fvp_pwrc_write_pponr(mpidr); 175*91f16700Schasinglulu return rc; 176*91f16700Schasinglulu } 177*91f16700Schasinglulu 178*91f16700Schasinglulu /******************************************************************************* 179*91f16700Schasinglulu * FVP handler called when a power domain is about to be turned off. The 180*91f16700Schasinglulu * target_state encodes the power state that each level should transition to. 181*91f16700Schasinglulu ******************************************************************************/ 182*91f16700Schasinglulu static void fvp_pwr_domain_off(const psci_power_state_t *target_state) 183*91f16700Schasinglulu { 184*91f16700Schasinglulu assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == 185*91f16700Schasinglulu ARM_LOCAL_STATE_OFF); 186*91f16700Schasinglulu 187*91f16700Schasinglulu /* 188*91f16700Schasinglulu * If execution reaches this stage then this power domain will be 189*91f16700Schasinglulu * suspended. Perform at least the cpu specific actions followed 190*91f16700Schasinglulu * by the cluster specific operations if applicable. 191*91f16700Schasinglulu */ 192*91f16700Schasinglulu 193*91f16700Schasinglulu /* Prevent interrupts from spuriously waking up this cpu */ 194*91f16700Schasinglulu plat_arm_gic_cpuif_disable(); 195*91f16700Schasinglulu 196*91f16700Schasinglulu /* Turn redistributor off */ 197*91f16700Schasinglulu plat_arm_gic_redistif_off(); 198*91f16700Schasinglulu 199*91f16700Schasinglulu /* Program the power controller to power off this cpu. */ 200*91f16700Schasinglulu fvp_pwrc_write_ppoffr(read_mpidr_el1()); 201*91f16700Schasinglulu 202*91f16700Schasinglulu if (target_state->pwr_domain_state[ARM_PWR_LVL1] == 203*91f16700Schasinglulu ARM_LOCAL_STATE_OFF) 204*91f16700Schasinglulu fvp_cluster_pwrdwn_common(); 205*91f16700Schasinglulu 206*91f16700Schasinglulu } 207*91f16700Schasinglulu 208*91f16700Schasinglulu /******************************************************************************* 209*91f16700Schasinglulu * FVP handler called when a power domain is about to be suspended. The 210*91f16700Schasinglulu * target_state encodes the power state that each level should transition to. 211*91f16700Schasinglulu ******************************************************************************/ 212*91f16700Schasinglulu static void fvp_pwr_domain_suspend(const psci_power_state_t *target_state) 213*91f16700Schasinglulu { 214*91f16700Schasinglulu unsigned long mpidr; 215*91f16700Schasinglulu 216*91f16700Schasinglulu /* 217*91f16700Schasinglulu * FVP has retention only at cpu level. Just return 218*91f16700Schasinglulu * as nothing is to be done for retention. 219*91f16700Schasinglulu */ 220*91f16700Schasinglulu if (target_state->pwr_domain_state[ARM_PWR_LVL0] == 221*91f16700Schasinglulu ARM_LOCAL_STATE_RET) 222*91f16700Schasinglulu return; 223*91f16700Schasinglulu 224*91f16700Schasinglulu assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == 225*91f16700Schasinglulu ARM_LOCAL_STATE_OFF); 226*91f16700Schasinglulu 227*91f16700Schasinglulu /* Get the mpidr for this cpu */ 228*91f16700Schasinglulu mpidr = read_mpidr_el1(); 229*91f16700Schasinglulu 230*91f16700Schasinglulu /* Program the power controller to enable wakeup interrupts. */ 231*91f16700Schasinglulu fvp_pwrc_set_wen(mpidr); 232*91f16700Schasinglulu 233*91f16700Schasinglulu /* Prevent interrupts from spuriously waking up this cpu */ 234*91f16700Schasinglulu plat_arm_gic_cpuif_disable(); 235*91f16700Schasinglulu 236*91f16700Schasinglulu /* 237*91f16700Schasinglulu * The Redistributor is not powered off as it can potentially prevent 238*91f16700Schasinglulu * wake up events reaching the CPUIF and/or might lead to losing 239*91f16700Schasinglulu * register context. 240*91f16700Schasinglulu */ 241*91f16700Schasinglulu 242*91f16700Schasinglulu /* Perform the common cluster specific operations */ 243*91f16700Schasinglulu if (target_state->pwr_domain_state[ARM_PWR_LVL1] == 244*91f16700Schasinglulu ARM_LOCAL_STATE_OFF) 245*91f16700Schasinglulu fvp_cluster_pwrdwn_common(); 246*91f16700Schasinglulu 247*91f16700Schasinglulu /* Perform the common system specific operations */ 248*91f16700Schasinglulu if (target_state->pwr_domain_state[ARM_PWR_LVL2] == 249*91f16700Schasinglulu ARM_LOCAL_STATE_OFF) 250*91f16700Schasinglulu arm_system_pwr_domain_save(); 251*91f16700Schasinglulu 252*91f16700Schasinglulu /* Program the power controller to power off this cpu. */ 253*91f16700Schasinglulu fvp_pwrc_write_ppoffr(read_mpidr_el1()); 254*91f16700Schasinglulu 255*91f16700Schasinglulu return; 256*91f16700Schasinglulu } 257*91f16700Schasinglulu 258*91f16700Schasinglulu /******************************************************************************* 259*91f16700Schasinglulu * FVP handler called when a power domain has just been powered on after 260*91f16700Schasinglulu * being turned off earlier. The target_state encodes the low power state that 261*91f16700Schasinglulu * each level has woken up from. 262*91f16700Schasinglulu ******************************************************************************/ 263*91f16700Schasinglulu static void fvp_pwr_domain_on_finish(const psci_power_state_t *target_state) 264*91f16700Schasinglulu { 265*91f16700Schasinglulu fvp_power_domain_on_finish_common(target_state); 266*91f16700Schasinglulu 267*91f16700Schasinglulu } 268*91f16700Schasinglulu 269*91f16700Schasinglulu /******************************************************************************* 270*91f16700Schasinglulu * FVP handler called when a power domain has just been powered on and the cpu 271*91f16700Schasinglulu * and its cluster are fully participating in coherent transaction on the 272*91f16700Schasinglulu * interconnect. Data cache must be enabled for CPU at this point. 273*91f16700Schasinglulu ******************************************************************************/ 274*91f16700Schasinglulu static void fvp_pwr_domain_on_finish_late(const psci_power_state_t *target_state) 275*91f16700Schasinglulu { 276*91f16700Schasinglulu /* Program GIC per-cpu distributor or re-distributor interface */ 277*91f16700Schasinglulu plat_arm_gic_pcpu_init(); 278*91f16700Schasinglulu 279*91f16700Schasinglulu /* Enable GIC CPU interface */ 280*91f16700Schasinglulu plat_arm_gic_cpuif_enable(); 281*91f16700Schasinglulu } 282*91f16700Schasinglulu 283*91f16700Schasinglulu /******************************************************************************* 284*91f16700Schasinglulu * FVP handler called when a power domain has just been powered on after 285*91f16700Schasinglulu * having been suspended earlier. The target_state encodes the low power state 286*91f16700Schasinglulu * that each level has woken up from. 287*91f16700Schasinglulu * TODO: At the moment we reuse the on finisher and reinitialize the secure 288*91f16700Schasinglulu * context. Need to implement a separate suspend finisher. 289*91f16700Schasinglulu ******************************************************************************/ 290*91f16700Schasinglulu static void fvp_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 291*91f16700Schasinglulu { 292*91f16700Schasinglulu /* 293*91f16700Schasinglulu * Nothing to be done on waking up from retention from CPU level. 294*91f16700Schasinglulu */ 295*91f16700Schasinglulu if (target_state->pwr_domain_state[ARM_PWR_LVL0] == 296*91f16700Schasinglulu ARM_LOCAL_STATE_RET) 297*91f16700Schasinglulu return; 298*91f16700Schasinglulu 299*91f16700Schasinglulu fvp_power_domain_on_finish_common(target_state); 300*91f16700Schasinglulu 301*91f16700Schasinglulu /* Enable GIC CPU interface */ 302*91f16700Schasinglulu plat_arm_gic_cpuif_enable(); 303*91f16700Schasinglulu } 304*91f16700Schasinglulu 305*91f16700Schasinglulu /******************************************************************************* 306*91f16700Schasinglulu * FVP handlers to shutdown/reboot the system 307*91f16700Schasinglulu ******************************************************************************/ 308*91f16700Schasinglulu static void __dead2 fvp_system_off(void) 309*91f16700Schasinglulu { 310*91f16700Schasinglulu /* Write the System Configuration Control Register */ 311*91f16700Schasinglulu mmio_write_32(V2M_SYSREGS_BASE + V2M_SYS_CFGCTRL, 312*91f16700Schasinglulu V2M_CFGCTRL_START | 313*91f16700Schasinglulu V2M_CFGCTRL_RW | 314*91f16700Schasinglulu V2M_CFGCTRL_FUNC(V2M_FUNC_SHUTDOWN)); 315*91f16700Schasinglulu wfi(); 316*91f16700Schasinglulu ERROR("FVP System Off: operation not handled.\n"); 317*91f16700Schasinglulu panic(); 318*91f16700Schasinglulu } 319*91f16700Schasinglulu 320*91f16700Schasinglulu static void __dead2 fvp_system_reset(void) 321*91f16700Schasinglulu { 322*91f16700Schasinglulu /* Write the System Configuration Control Register */ 323*91f16700Schasinglulu mmio_write_32(V2M_SYSREGS_BASE + V2M_SYS_CFGCTRL, 324*91f16700Schasinglulu V2M_CFGCTRL_START | 325*91f16700Schasinglulu V2M_CFGCTRL_RW | 326*91f16700Schasinglulu V2M_CFGCTRL_FUNC(V2M_FUNC_REBOOT)); 327*91f16700Schasinglulu wfi(); 328*91f16700Schasinglulu ERROR("FVP System Reset: operation not handled.\n"); 329*91f16700Schasinglulu panic(); 330*91f16700Schasinglulu } 331*91f16700Schasinglulu 332*91f16700Schasinglulu static int fvp_node_hw_state(u_register_t target_cpu, 333*91f16700Schasinglulu unsigned int power_level) 334*91f16700Schasinglulu { 335*91f16700Schasinglulu unsigned int psysr; 336*91f16700Schasinglulu int ret; 337*91f16700Schasinglulu 338*91f16700Schasinglulu /* 339*91f16700Schasinglulu * The format of 'power_level' is implementation-defined, but 0 must 340*91f16700Schasinglulu * mean a CPU. We also allow 1 to denote the cluster 341*91f16700Schasinglulu */ 342*91f16700Schasinglulu if ((power_level != ARM_PWR_LVL0) && (power_level != ARM_PWR_LVL1)) 343*91f16700Schasinglulu return PSCI_E_INVALID_PARAMS; 344*91f16700Schasinglulu 345*91f16700Schasinglulu /* 346*91f16700Schasinglulu * Read the status of the given MPDIR from FVP power controller. The 347*91f16700Schasinglulu * power controller only gives us on/off status, so map that to expected 348*91f16700Schasinglulu * return values of the PSCI call 349*91f16700Schasinglulu */ 350*91f16700Schasinglulu psysr = fvp_pwrc_read_psysr(target_cpu); 351*91f16700Schasinglulu if (psysr == PSYSR_INVALID) 352*91f16700Schasinglulu return PSCI_E_INVALID_PARAMS; 353*91f16700Schasinglulu 354*91f16700Schasinglulu if (power_level == ARM_PWR_LVL0) { 355*91f16700Schasinglulu ret = ((psysr & PSYSR_AFF_L0) != 0U) ? HW_ON : HW_OFF; 356*91f16700Schasinglulu } else { 357*91f16700Schasinglulu /* power_level == ARM_PWR_LVL1 */ 358*91f16700Schasinglulu ret = ((psysr & PSYSR_AFF_L1) != 0U) ? HW_ON : HW_OFF; 359*91f16700Schasinglulu } 360*91f16700Schasinglulu 361*91f16700Schasinglulu return ret; 362*91f16700Schasinglulu } 363*91f16700Schasinglulu 364*91f16700Schasinglulu /* 365*91f16700Schasinglulu * The FVP doesn't truly support power management at SYSTEM power domain. The 366*91f16700Schasinglulu * SYSTEM_SUSPEND will be down-graded to the cluster level within the platform 367*91f16700Schasinglulu * layer. The `fake` SYSTEM_SUSPEND allows us to validate some of the driver 368*91f16700Schasinglulu * save and restore sequences on FVP. 369*91f16700Schasinglulu */ 370*91f16700Schasinglulu #if !ARM_BL31_IN_DRAM 371*91f16700Schasinglulu static void fvp_get_sys_suspend_power_state(psci_power_state_t *req_state) 372*91f16700Schasinglulu { 373*91f16700Schasinglulu unsigned int i; 374*91f16700Schasinglulu 375*91f16700Schasinglulu for (i = ARM_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) 376*91f16700Schasinglulu req_state->pwr_domain_state[i] = ARM_LOCAL_STATE_OFF; 377*91f16700Schasinglulu 378*91f16700Schasinglulu #if PSCI_OS_INIT_MODE 379*91f16700Schasinglulu req_state->last_at_pwrlvl = PLAT_MAX_PWR_LVL; 380*91f16700Schasinglulu #endif 381*91f16700Schasinglulu } 382*91f16700Schasinglulu #endif 383*91f16700Schasinglulu 384*91f16700Schasinglulu /******************************************************************************* 385*91f16700Schasinglulu * Handler to filter PSCI requests. 386*91f16700Schasinglulu ******************************************************************************/ 387*91f16700Schasinglulu /* 388*91f16700Schasinglulu * The system power domain suspend is only supported only via 389*91f16700Schasinglulu * PSCI SYSTEM_SUSPEND API. PSCI CPU_SUSPEND request to system power domain 390*91f16700Schasinglulu * will be downgraded to the lower level. 391*91f16700Schasinglulu */ 392*91f16700Schasinglulu static int fvp_validate_power_state(unsigned int power_state, 393*91f16700Schasinglulu psci_power_state_t *req_state) 394*91f16700Schasinglulu { 395*91f16700Schasinglulu int rc; 396*91f16700Schasinglulu rc = arm_validate_power_state(power_state, req_state); 397*91f16700Schasinglulu 398*91f16700Schasinglulu /* 399*91f16700Schasinglulu * Ensure that the system power domain level is never suspended 400*91f16700Schasinglulu * via PSCI CPU SUSPEND API. Currently system suspend is only 401*91f16700Schasinglulu * supported via PSCI SYSTEM SUSPEND API. 402*91f16700Schasinglulu */ 403*91f16700Schasinglulu req_state->pwr_domain_state[ARM_PWR_LVL2] = ARM_LOCAL_STATE_RUN; 404*91f16700Schasinglulu return rc; 405*91f16700Schasinglulu } 406*91f16700Schasinglulu 407*91f16700Schasinglulu /* 408*91f16700Schasinglulu * Custom `translate_power_state_by_mpidr` handler for FVP. Unlike in the 409*91f16700Schasinglulu * `fvp_validate_power_state`, we do not downgrade the system power 410*91f16700Schasinglulu * domain level request in `power_state` as it will be used to query the 411*91f16700Schasinglulu * PSCI_STAT_COUNT/RESIDENCY at the system power domain level. 412*91f16700Schasinglulu */ 413*91f16700Schasinglulu static int fvp_translate_power_state_by_mpidr(u_register_t mpidr, 414*91f16700Schasinglulu unsigned int power_state, 415*91f16700Schasinglulu psci_power_state_t *output_state) 416*91f16700Schasinglulu { 417*91f16700Schasinglulu return arm_validate_power_state(power_state, output_state); 418*91f16700Schasinglulu } 419*91f16700Schasinglulu 420*91f16700Schasinglulu /******************************************************************************* 421*91f16700Schasinglulu * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard 422*91f16700Schasinglulu * platform layer will take care of registering the handlers with PSCI. 423*91f16700Schasinglulu ******************************************************************************/ 424*91f16700Schasinglulu plat_psci_ops_t plat_arm_psci_pm_ops = { 425*91f16700Schasinglulu .cpu_standby = fvp_cpu_standby, 426*91f16700Schasinglulu .pwr_domain_on = fvp_pwr_domain_on, 427*91f16700Schasinglulu .pwr_domain_off = fvp_pwr_domain_off, 428*91f16700Schasinglulu .pwr_domain_suspend = fvp_pwr_domain_suspend, 429*91f16700Schasinglulu .pwr_domain_on_finish = fvp_pwr_domain_on_finish, 430*91f16700Schasinglulu .pwr_domain_on_finish_late = fvp_pwr_domain_on_finish_late, 431*91f16700Schasinglulu .pwr_domain_suspend_finish = fvp_pwr_domain_suspend_finish, 432*91f16700Schasinglulu .system_off = fvp_system_off, 433*91f16700Schasinglulu .system_reset = fvp_system_reset, 434*91f16700Schasinglulu .validate_power_state = fvp_validate_power_state, 435*91f16700Schasinglulu .validate_ns_entrypoint = arm_validate_psci_entrypoint, 436*91f16700Schasinglulu .translate_power_state_by_mpidr = fvp_translate_power_state_by_mpidr, 437*91f16700Schasinglulu .get_node_hw_state = fvp_node_hw_state, 438*91f16700Schasinglulu #if !ARM_BL31_IN_DRAM 439*91f16700Schasinglulu /* 440*91f16700Schasinglulu * The TrustZone Controller is set up during the warmboot sequence after 441*91f16700Schasinglulu * resuming the CPU from a SYSTEM_SUSPEND. If BL31 is located in SRAM 442*91f16700Schasinglulu * this is not a problem but, if it is in TZC-secured DRAM, it tries to 443*91f16700Schasinglulu * reconfigure the same memory it is running on, causing an exception. 444*91f16700Schasinglulu */ 445*91f16700Schasinglulu .get_sys_suspend_power_state = fvp_get_sys_suspend_power_state, 446*91f16700Schasinglulu #endif 447*91f16700Schasinglulu .mem_protect_chk = arm_psci_mem_protect_chk, 448*91f16700Schasinglulu .read_mem_protect = arm_psci_read_mem_protect, 449*91f16700Schasinglulu .write_mem_protect = arm_nor_psci_write_mem_protect, 450*91f16700Schasinglulu }; 451*91f16700Schasinglulu 452*91f16700Schasinglulu const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops) 453*91f16700Schasinglulu { 454*91f16700Schasinglulu return ops; 455*91f16700Schasinglulu } 456