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