1 /* 2 * Copyright (c) 2015-2019, 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 <platform_def.h> 11 12 #include <arch_helpers.h> 13 #include <common/debug.h> 14 #include <drivers/arm/css/css_scp.h> 15 #include <lib/cassert.h> 16 #include <plat/arm/common/plat_arm.h> 17 #include <plat/arm/css/common/css_pm.h> 18 #include <plat/common/platform.h> 19 20 /* Allow CSS platforms to override `plat_arm_psci_pm_ops` */ 21 #pragma weak plat_arm_psci_pm_ops 22 23 #if ARM_RECOM_STATE_ID_ENC 24 /* 25 * The table storing the valid idle power states. Ensure that the 26 * array entries are populated in ascending order of state-id to 27 * enable us to use binary search during power state validation. 28 * The table must be terminated by a NULL entry. 29 */ 30 const unsigned int arm_pm_idle_states[] = { 31 /* State-id - 0x001 */ 32 arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RUN, 33 ARM_LOCAL_STATE_RET, ARM_PWR_LVL0, PSTATE_TYPE_STANDBY), 34 /* State-id - 0x002 */ 35 arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RUN, 36 ARM_LOCAL_STATE_OFF, ARM_PWR_LVL0, PSTATE_TYPE_POWERDOWN), 37 /* State-id - 0x022 */ 38 arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_OFF, 39 ARM_LOCAL_STATE_OFF, ARM_PWR_LVL1, PSTATE_TYPE_POWERDOWN), 40 #if PLAT_MAX_PWR_LVL > ARM_PWR_LVL1 41 /* State-id - 0x222 */ 42 arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF, 43 ARM_LOCAL_STATE_OFF, ARM_PWR_LVL2, PSTATE_TYPE_POWERDOWN), 44 #endif 45 0, 46 }; 47 #endif /* __ARM_RECOM_STATE_ID_ENC__ */ 48 49 /* 50 * All the power management helpers in this file assume at least cluster power 51 * level is supported. 52 */ 53 CASSERT(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL1, 54 assert_max_pwr_lvl_supported_mismatch); 55 56 /* 57 * Ensure that the PLAT_MAX_PWR_LVL is not greater than CSS_SYSTEM_PWR_DMN_LVL 58 * assumed by the CSS layer. 59 */ 60 CASSERT(PLAT_MAX_PWR_LVL <= CSS_SYSTEM_PWR_DMN_LVL, 61 assert_max_pwr_lvl_higher_than_css_sys_lvl); 62 63 /******************************************************************************* 64 * Handler called when a power domain is about to be turned on. The 65 * level and mpidr determine the affinity instance. 66 ******************************************************************************/ 67 int css_pwr_domain_on(u_register_t mpidr) 68 { 69 css_scp_on(mpidr); 70 71 return PSCI_E_SUCCESS; 72 } 73 74 static void css_pwr_domain_on_finisher_common( 75 const psci_power_state_t *target_state) 76 { 77 assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF); 78 79 /* 80 * Perform the common cluster specific operations i.e enable coherency 81 * if this cluster was off. 82 */ 83 if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) 84 plat_arm_interconnect_enter_coherency(); 85 } 86 87 /******************************************************************************* 88 * Handler called when a power level has just been powered on after 89 * being turned off earlier. The target_state encodes the low power state that 90 * each level has woken up from. This handler would never be invoked with 91 * the system power domain uninitialized as either the primary would have taken 92 * care of it as part of cold boot or the first core awakened from system 93 * suspend would have already initialized it. 94 ******************************************************************************/ 95 void css_pwr_domain_on_finish(const psci_power_state_t *target_state) 96 { 97 /* Assert that the system power domain need not be initialized */ 98 assert(css_system_pwr_state(target_state) == ARM_LOCAL_STATE_RUN); 99 100 css_pwr_domain_on_finisher_common(target_state); 101 } 102 103 /******************************************************************************* 104 * Handler called when a power domain has just been powered on and the cpu 105 * and its cluster are fully participating in coherent transaction on the 106 * interconnect. Data cache must be enabled for CPU at this point. 107 ******************************************************************************/ 108 void css_pwr_domain_on_finish_late(const psci_power_state_t *target_state) 109 { 110 /* Program the gic per-cpu distributor or re-distributor interface */ 111 plat_arm_gic_pcpu_init(); 112 113 /* Enable the gic cpu interface */ 114 plat_arm_gic_cpuif_enable(); 115 } 116 117 /******************************************************************************* 118 * Common function called while turning a cpu off or suspending it. It is called 119 * from css_off() or css_suspend() when these functions in turn are called for 120 * power domain at the highest power level which will be powered down. It 121 * performs the actions common to the OFF and SUSPEND calls. 122 ******************************************************************************/ 123 static void css_power_down_common(const psci_power_state_t *target_state) 124 { 125 /* Prevent interrupts from spuriously waking up this cpu */ 126 plat_arm_gic_cpuif_disable(); 127 128 /* Cluster is to be turned off, so disable coherency */ 129 if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) 130 plat_arm_interconnect_exit_coherency(); 131 } 132 133 /******************************************************************************* 134 * Handler called when a power domain is about to be turned off. The 135 * target_state encodes the power state that each level should transition to. 136 ******************************************************************************/ 137 void css_pwr_domain_off(const psci_power_state_t *target_state) 138 { 139 assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF); 140 css_power_down_common(target_state); 141 css_scp_off(target_state); 142 } 143 144 /******************************************************************************* 145 * Handler called when a power domain is about to be suspended. The 146 * target_state encodes the power state that each level should transition to. 147 ******************************************************************************/ 148 void css_pwr_domain_suspend(const psci_power_state_t *target_state) 149 { 150 /* 151 * CSS currently supports retention only at cpu level. Just return 152 * as nothing is to be done for retention. 153 */ 154 if (CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_RET) 155 return; 156 157 158 assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF); 159 css_power_down_common(target_state); 160 161 /* Perform system domain state saving if issuing system suspend */ 162 if (css_system_pwr_state(target_state) == ARM_LOCAL_STATE_OFF) { 163 arm_system_pwr_domain_save(); 164 165 /* Power off the Redistributor after having saved its context */ 166 plat_arm_gic_redistif_off(); 167 } 168 169 css_scp_suspend(target_state); 170 } 171 172 /******************************************************************************* 173 * Handler called when a power domain has just been powered on after 174 * having been suspended earlier. The target_state encodes the low power state 175 * that each level has woken up from. 176 * TODO: At the moment we reuse the on finisher and reinitialize the secure 177 * context. Need to implement a separate suspend finisher. 178 ******************************************************************************/ 179 void css_pwr_domain_suspend_finish( 180 const psci_power_state_t *target_state) 181 { 182 /* Return as nothing is to be done on waking up from retention. */ 183 if (CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_RET) 184 return; 185 186 /* Perform system domain restore if woken up from system suspend */ 187 if (css_system_pwr_state(target_state) == ARM_LOCAL_STATE_OFF) 188 /* 189 * At this point, the Distributor must be powered on to be ready 190 * to have its state restored. The Redistributor will be powered 191 * on as part of gicv3_rdistif_init_restore. 192 */ 193 arm_system_pwr_domain_resume(); 194 195 css_pwr_domain_on_finisher_common(target_state); 196 197 /* Enable the gic cpu interface */ 198 plat_arm_gic_cpuif_enable(); 199 } 200 201 /******************************************************************************* 202 * Handlers to shutdown/reboot the system 203 ******************************************************************************/ 204 void __dead2 css_system_off(void) 205 { 206 css_scp_sys_shutdown(); 207 } 208 209 void __dead2 css_system_reset(void) 210 { 211 css_scp_sys_reboot(); 212 } 213 214 /******************************************************************************* 215 * Handler called when the CPU power domain is about to enter standby. 216 ******************************************************************************/ 217 void css_cpu_standby(plat_local_state_t cpu_state) 218 { 219 unsigned int scr; 220 221 assert(cpu_state == ARM_LOCAL_STATE_RET); 222 223 scr = read_scr_el3(); 224 /* 225 * Enable the Non secure interrupt to wake the CPU. 226 * In GICv3 affinity routing mode, the non secure group1 interrupts use 227 * the PhysicalFIQ at EL3 whereas in GICv2, it uses the PhysicalIRQ. 228 * Enabling both the bits works for both GICv2 mode and GICv3 affinity 229 * routing mode. 230 */ 231 write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT); 232 isb(); 233 dsb(); 234 wfi(); 235 236 /* 237 * Restore SCR to the original value, synchronisation of scr_el3 is 238 * done by eret while el3_exit to save some execution cycles. 239 */ 240 write_scr_el3(scr); 241 } 242 243 /******************************************************************************* 244 * Handler called to return the 'req_state' for system suspend. 245 ******************************************************************************/ 246 void css_get_sys_suspend_power_state(psci_power_state_t *req_state) 247 { 248 unsigned int i; 249 250 /* 251 * System Suspend is supported only if the system power domain node 252 * is implemented. 253 */ 254 assert(PLAT_MAX_PWR_LVL == CSS_SYSTEM_PWR_DMN_LVL); 255 256 for (i = ARM_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) 257 req_state->pwr_domain_state[i] = ARM_LOCAL_STATE_OFF; 258 } 259 260 /******************************************************************************* 261 * Handler to query CPU/cluster power states from SCP 262 ******************************************************************************/ 263 int css_node_hw_state(u_register_t mpidr, unsigned int power_level) 264 { 265 return css_scp_get_power_state(mpidr, power_level); 266 } 267 268 /* 269 * The system power domain suspend is only supported only via 270 * PSCI SYSTEM_SUSPEND API. PSCI CPU_SUSPEND request to system power domain 271 * will be downgraded to the lower level. 272 */ 273 static int css_validate_power_state(unsigned int power_state, 274 psci_power_state_t *req_state) 275 { 276 int rc; 277 rc = arm_validate_power_state(power_state, req_state); 278 279 /* 280 * Ensure that we don't overrun the pwr_domain_state array in the case 281 * where the platform supported max power level is less than the system 282 * power level 283 */ 284 285 #if (PLAT_MAX_PWR_LVL == CSS_SYSTEM_PWR_DMN_LVL) 286 287 /* 288 * Ensure that the system power domain level is never suspended 289 * via PSCI CPU SUSPEND API. Currently system suspend is only 290 * supported via PSCI SYSTEM SUSPEND API. 291 */ 292 293 req_state->pwr_domain_state[CSS_SYSTEM_PWR_DMN_LVL] = 294 ARM_LOCAL_STATE_RUN; 295 #endif 296 297 return rc; 298 } 299 300 /* 301 * Custom `translate_power_state_by_mpidr` handler for CSS. Unlike in the 302 * `css_validate_power_state`, we do not downgrade the system power 303 * domain level request in `power_state` as it will be used to query the 304 * PSCI_STAT_COUNT/RESIDENCY at the system power domain level. 305 */ 306 static int css_translate_power_state_by_mpidr(u_register_t mpidr, 307 unsigned int power_state, 308 psci_power_state_t *output_state) 309 { 310 return arm_validate_power_state(power_state, output_state); 311 } 312 313 /******************************************************************************* 314 * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard 315 * platform will take care of registering the handlers with PSCI. 316 ******************************************************************************/ 317 plat_psci_ops_t plat_arm_psci_pm_ops = { 318 .pwr_domain_on = css_pwr_domain_on, 319 .pwr_domain_on_finish = css_pwr_domain_on_finish, 320 .pwr_domain_on_finish_late = css_pwr_domain_on_finish_late, 321 .pwr_domain_off = css_pwr_domain_off, 322 .cpu_standby = css_cpu_standby, 323 .pwr_domain_suspend = css_pwr_domain_suspend, 324 .pwr_domain_suspend_finish = css_pwr_domain_suspend_finish, 325 .system_off = css_system_off, 326 .system_reset = css_system_reset, 327 .validate_power_state = css_validate_power_state, 328 .validate_ns_entrypoint = arm_validate_psci_entrypoint, 329 .translate_power_state_by_mpidr = css_translate_power_state_by_mpidr, 330 .get_node_hw_state = css_node_hw_state, 331 .get_sys_suspend_power_state = css_get_sys_suspend_power_state, 332 333 #if defined(PLAT_ARM_MEM_PROT_ADDR) 334 .mem_protect_chk = arm_psci_mem_protect_chk, 335 .read_mem_protect = arm_psci_read_mem_protect, 336 .write_mem_protect = arm_nor_psci_write_mem_protect, 337 #endif 338 #if CSS_USE_SCMI_SDS_DRIVER 339 .system_reset2 = css_system_reset2, 340 #endif 341 }; 342