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