1 /* 2 * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. 9 * 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * Neither the name of ARM nor the names of its contributors may be used 15 * to endorse or promote products derived from this software without specific 16 * prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <arch_helpers.h> 32 #include <assert.h> 33 #include <arm_gic.h> 34 #include <cassert.h> 35 #include <cci.h> 36 #include <css_pm.h> 37 #include <debug.h> 38 #include <errno.h> 39 #include <plat_arm.h> 40 #include <platform.h> 41 #include <platform_def.h> 42 #include "css_scpi.h" 43 44 /* Allow CSS platforms to override `plat_arm_psci_pm_ops` */ 45 #pragma weak plat_arm_psci_pm_ops 46 47 #if ARM_RECOM_STATE_ID_ENC 48 /* 49 * The table storing the valid idle power states. Ensure that the 50 * array entries are populated in ascending order of state-id to 51 * enable us to use binary search during power state validation. 52 * The table must be terminated by a NULL entry. 53 */ 54 const unsigned int arm_pm_idle_states[] = { 55 /* State-id - 0x001 */ 56 arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RUN, 57 ARM_LOCAL_STATE_RET, ARM_PWR_LVL0, PSTATE_TYPE_STANDBY), 58 /* State-id - 0x002 */ 59 arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RUN, 60 ARM_LOCAL_STATE_OFF, ARM_PWR_LVL0, PSTATE_TYPE_POWERDOWN), 61 /* State-id - 0x022 */ 62 arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_OFF, 63 ARM_LOCAL_STATE_OFF, ARM_PWR_LVL1, PSTATE_TYPE_POWERDOWN), 64 #if PLAT_MAX_PWR_LVL > ARM_PWR_LVL1 65 /* State-id - 0x222 */ 66 arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF, 67 ARM_LOCAL_STATE_OFF, ARM_PWR_LVL2, PSTATE_TYPE_POWERDOWN), 68 #endif 69 0, 70 }; 71 #endif /* __ARM_RECOM_STATE_ID_ENC__ */ 72 73 /* 74 * All the power management helpers in this file assume at least cluster power 75 * level is supported. 76 */ 77 CASSERT(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL1, 78 assert_max_pwr_lvl_supported_mismatch); 79 80 /******************************************************************************* 81 * Handler called when a power domain is about to be turned on. The 82 * level and mpidr determine the affinity instance. 83 ******************************************************************************/ 84 int css_pwr_domain_on(u_register_t mpidr) 85 { 86 /* 87 * SCP takes care of powering up parent power domains so we 88 * only need to care about level 0 89 */ 90 scpi_set_css_power_state(mpidr, scpi_power_on, scpi_power_on, 91 scpi_power_on); 92 93 return PSCI_E_SUCCESS; 94 } 95 96 /******************************************************************************* 97 * Handler called when a power level has just been powered on after 98 * being turned off earlier. The target_state encodes the low power state that 99 * each level has woken up from. 100 ******************************************************************************/ 101 void css_pwr_domain_on_finish(const psci_power_state_t *target_state) 102 { 103 assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == 104 ARM_LOCAL_STATE_OFF); 105 106 if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) { 107 /* 108 * Perform system initialization if woken up from system 109 * suspend. 110 */ 111 if (target_state->pwr_domain_state[ARM_PWR_LVL2] == 112 ARM_LOCAL_STATE_OFF) 113 arm_system_pwr_domain_resume(); 114 } 115 116 /* 117 * Perform the common cluster specific operations i.e enable coherency 118 * if this cluster was off. 119 */ 120 if (target_state->pwr_domain_state[ARM_PWR_LVL1] == 121 ARM_LOCAL_STATE_OFF) 122 cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1())); 123 124 125 if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) { 126 /* 127 * Skip GIC CPU interface and per-CPU Distributor interface 128 * setups if woken up from system suspend as it is done as 129 * part of css_system_pwr_domain_resume(). 130 */ 131 if (target_state->pwr_domain_state[ARM_PWR_LVL2] == 132 ARM_LOCAL_STATE_OFF) 133 return; 134 } 135 136 /* Enable the gic cpu interface */ 137 arm_gic_cpuif_setup(); 138 139 /* todo: Is this setup only needed after a cold boot? */ 140 arm_gic_pcpu_distif_setup(); 141 } 142 143 /******************************************************************************* 144 * Common function called while turning a cpu off or suspending it. It is called 145 * from css_off() or css_suspend() when these functions in turn are called for 146 * power domain at the highest power level which will be powered down. It 147 * performs the actions common to the OFF and SUSPEND calls. 148 ******************************************************************************/ 149 static void css_power_down_common(const psci_power_state_t *target_state) 150 { 151 uint32_t cluster_state = scpi_power_on; 152 uint32_t system_state = scpi_power_on; 153 154 /* Prevent interrupts from spuriously waking up this cpu */ 155 arm_gic_cpuif_deactivate(); 156 157 if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) { 158 /* 159 * Check if power down at system power domain level is 160 * requested. 161 */ 162 if (target_state->pwr_domain_state[ARM_PWR_LVL2] == 163 ARM_LOCAL_STATE_OFF) 164 system_state = scpi_power_retention; 165 } 166 167 /* Cluster is to be turned off, so disable coherency */ 168 if (target_state->pwr_domain_state[ARM_PWR_LVL1] == 169 ARM_LOCAL_STATE_OFF) { 170 cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr())); 171 cluster_state = scpi_power_off; 172 } 173 174 /* 175 * Ask the SCP to power down the appropriate components depending upon 176 * their state. 177 */ 178 scpi_set_css_power_state(read_mpidr_el1(), 179 scpi_power_off, 180 cluster_state, 181 system_state); 182 } 183 184 /******************************************************************************* 185 * Handler called when a power domain is about to be turned off. The 186 * target_state encodes the power state that each level should transition to. 187 ******************************************************************************/ 188 void css_pwr_domain_off(const psci_power_state_t *target_state) 189 { 190 assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == 191 ARM_LOCAL_STATE_OFF); 192 193 css_power_down_common(target_state); 194 } 195 196 /******************************************************************************* 197 * Handler called when a power domain is about to be suspended. The 198 * target_state encodes the power state that each level should transition to. 199 ******************************************************************************/ 200 void css_pwr_domain_suspend(const psci_power_state_t *target_state) 201 { 202 /* 203 * Juno 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 css_power_down_common(target_state); 214 } 215 216 /******************************************************************************* 217 * Handler called when a power domain has just been powered on after 218 * having been suspended earlier. The target_state encodes the low power state 219 * that each level has woken up from. 220 * TODO: At the moment we reuse the on finisher and reinitialize the secure 221 * context. Need to implement a separate suspend finisher. 222 ******************************************************************************/ 223 void css_pwr_domain_suspend_finish( 224 const psci_power_state_t *target_state) 225 { 226 /* 227 * Return as nothing is to be done on waking up from retention. 228 */ 229 if (target_state->pwr_domain_state[ARM_PWR_LVL0] == 230 ARM_LOCAL_STATE_RET) 231 return; 232 233 css_pwr_domain_on_finish(target_state); 234 } 235 236 /******************************************************************************* 237 * Handlers to shutdown/reboot the system 238 ******************************************************************************/ 239 void __dead2 css_system_off(void) 240 { 241 uint32_t response; 242 243 /* Send the power down request to the SCP */ 244 response = scpi_sys_power_state(scpi_system_shutdown); 245 246 if (response != SCP_OK) { 247 ERROR("CSS System Off: SCP error %u.\n", response); 248 panic(); 249 } 250 wfi(); 251 ERROR("CSS System Off: operation not handled.\n"); 252 panic(); 253 } 254 255 void __dead2 css_system_reset(void) 256 { 257 uint32_t response; 258 259 /* Send the system reset request to the SCP */ 260 response = scpi_sys_power_state(scpi_system_reboot); 261 262 if (response != SCP_OK) { 263 ERROR("CSS System Reset: SCP error %u.\n", response); 264 panic(); 265 } 266 wfi(); 267 ERROR("CSS System Reset: operation not handled.\n"); 268 panic(); 269 } 270 271 /******************************************************************************* 272 * Handler called when the CPU power domain is about to enter standby. 273 ******************************************************************************/ 274 void css_cpu_standby(plat_local_state_t cpu_state) 275 { 276 unsigned int scr; 277 278 assert(cpu_state == ARM_LOCAL_STATE_RET); 279 280 scr = read_scr_el3(); 281 /* Enable PhysicalIRQ bit for NS world to wake the CPU */ 282 write_scr_el3(scr | SCR_IRQ_BIT); 283 isb(); 284 dsb(); 285 wfi(); 286 287 /* 288 * Restore SCR to the original value, synchronisation of scr_el3 is 289 * done by eret while el3_exit to save some execution cycles. 290 */ 291 write_scr_el3(scr); 292 } 293 294 /******************************************************************************* 295 * Handler called to return the 'req_state' for system suspend. 296 ******************************************************************************/ 297 void css_get_sys_suspend_power_state(psci_power_state_t *req_state) 298 { 299 unsigned int i; 300 301 /* 302 * System Suspend is supported only if the system power domain node 303 * is implemented. 304 */ 305 assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2); 306 307 for (i = ARM_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) 308 req_state->pwr_domain_state[i] = ARM_LOCAL_STATE_OFF; 309 } 310 311 /******************************************************************************* 312 * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard 313 * platform will take care of registering the handlers with PSCI. 314 ******************************************************************************/ 315 const plat_psci_ops_t plat_arm_psci_pm_ops = { 316 .pwr_domain_on = css_pwr_domain_on, 317 .pwr_domain_on_finish = css_pwr_domain_on_finish, 318 .pwr_domain_off = css_pwr_domain_off, 319 .cpu_standby = css_cpu_standby, 320 .pwr_domain_suspend = css_pwr_domain_suspend, 321 .pwr_domain_suspend_finish = css_pwr_domain_suspend_finish, 322 .system_off = css_system_off, 323 .system_reset = css_system_reset, 324 .validate_power_state = arm_validate_power_state, 325 .validate_ns_entrypoint = arm_validate_ns_entrypoint 326 }; 327