1 /* 2 * Copyright (c) 2015-2016, 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 <cassert.h> 34 #include <css_pm.h> 35 #include <debug.h> 36 #include <errno.h> 37 #include <plat_arm.h> 38 #include <platform.h> 39 #include <platform_def.h> 40 #include "../drivers/scp/css_scp.h" 41 42 /* Allow CSS platforms to override `plat_arm_psci_pm_ops` */ 43 #pragma weak plat_arm_psci_pm_ops 44 45 #if ARM_RECOM_STATE_ID_ENC 46 /* 47 * The table storing the valid idle power states. Ensure that the 48 * array entries are populated in ascending order of state-id to 49 * enable us to use binary search during power state validation. 50 * The table must be terminated by a NULL entry. 51 */ 52 const unsigned int arm_pm_idle_states[] = { 53 /* State-id - 0x001 */ 54 arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RUN, 55 ARM_LOCAL_STATE_RET, ARM_PWR_LVL0, PSTATE_TYPE_STANDBY), 56 /* State-id - 0x002 */ 57 arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RUN, 58 ARM_LOCAL_STATE_OFF, ARM_PWR_LVL0, PSTATE_TYPE_POWERDOWN), 59 /* State-id - 0x022 */ 60 arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_OFF, 61 ARM_LOCAL_STATE_OFF, ARM_PWR_LVL1, PSTATE_TYPE_POWERDOWN), 62 #if PLAT_MAX_PWR_LVL > ARM_PWR_LVL1 63 /* State-id - 0x222 */ 64 arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF, 65 ARM_LOCAL_STATE_OFF, ARM_PWR_LVL2, PSTATE_TYPE_POWERDOWN), 66 #endif 67 0, 68 }; 69 #endif /* __ARM_RECOM_STATE_ID_ENC__ */ 70 71 /* 72 * All the power management helpers in this file assume at least cluster power 73 * level is supported. 74 */ 75 CASSERT(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL1, 76 assert_max_pwr_lvl_supported_mismatch); 77 78 /******************************************************************************* 79 * Handler called when a power domain is about to be turned on. The 80 * level and mpidr determine the affinity instance. 81 ******************************************************************************/ 82 int css_pwr_domain_on(u_register_t mpidr) 83 { 84 css_scp_on(mpidr); 85 86 return PSCI_E_SUCCESS; 87 } 88 89 static void css_pwr_domain_on_finisher_common( 90 const psci_power_state_t *target_state) 91 { 92 assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF); 93 94 /* 95 * Perform the common cluster specific operations i.e enable coherency 96 * if this cluster was off. 97 */ 98 if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) 99 plat_arm_interconnect_enter_coherency(); 100 } 101 102 /******************************************************************************* 103 * Handler called when a power level has just been powered on after 104 * being turned off earlier. The target_state encodes the low power state that 105 * each level has woken up from. This handler would never be invoked with 106 * the system power domain uninitialized as either the primary would have taken 107 * care of it as part of cold boot or the first core awakened from system 108 * suspend would have already initialized it. 109 ******************************************************************************/ 110 void css_pwr_domain_on_finish(const psci_power_state_t *target_state) 111 { 112 /* Assert that the system power domain need not be initialized */ 113 assert(CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_RUN); 114 115 css_pwr_domain_on_finisher_common(target_state); 116 117 /* Program the gic per-cpu distributor or re-distributor interface */ 118 plat_arm_gic_pcpu_init(); 119 120 /* Enable the gic cpu interface */ 121 plat_arm_gic_cpuif_enable(); 122 } 123 124 /******************************************************************************* 125 * Common function called while turning a cpu off or suspending it. It is called 126 * from css_off() or css_suspend() when these functions in turn are called for 127 * power domain at the highest power level which will be powered down. It 128 * performs the actions common to the OFF and SUSPEND calls. 129 ******************************************************************************/ 130 static void css_power_down_common(const psci_power_state_t *target_state) 131 { 132 /* Prevent interrupts from spuriously waking up this cpu */ 133 plat_arm_gic_cpuif_disable(); 134 135 /* Cluster is to be turned off, so disable coherency */ 136 if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) 137 plat_arm_interconnect_exit_coherency(); 138 } 139 140 /******************************************************************************* 141 * Handler called when a power domain is about to be turned off. The 142 * target_state encodes the power state that each level should transition to. 143 ******************************************************************************/ 144 void css_pwr_domain_off(const psci_power_state_t *target_state) 145 { 146 assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF); 147 css_power_down_common(target_state); 148 css_scp_off(target_state); 149 } 150 151 /******************************************************************************* 152 * Handler called when a power domain is about to be suspended. The 153 * target_state encodes the power state that each level should transition to. 154 ******************************************************************************/ 155 void css_pwr_domain_suspend(const psci_power_state_t *target_state) 156 { 157 /* 158 * CSS currently supports retention only at cpu level. Just return 159 * as nothing is to be done for retention. 160 */ 161 if (CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_RET) 162 return; 163 164 assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF); 165 css_power_down_common(target_state); 166 css_scp_suspend(target_state); 167 } 168 169 /******************************************************************************* 170 * Handler called when a power domain has just been powered on after 171 * having been suspended earlier. The target_state encodes the low power state 172 * that each level has woken up from. 173 * TODO: At the moment we reuse the on finisher and reinitialize the secure 174 * context. Need to implement a separate suspend finisher. 175 ******************************************************************************/ 176 void css_pwr_domain_suspend_finish( 177 const psci_power_state_t *target_state) 178 { 179 /* Return as nothing is to be done on waking up from retention. */ 180 if (CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_RET) 181 return; 182 183 /* Perform system domain restore if woken up from system suspend */ 184 if (CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) 185 arm_system_pwr_domain_resume(); 186 else 187 /* Enable the gic cpu interface */ 188 plat_arm_gic_cpuif_enable(); 189 190 css_pwr_domain_on_finisher_common(target_state); 191 } 192 193 /******************************************************************************* 194 * Handlers to shutdown/reboot the system 195 ******************************************************************************/ 196 void __dead2 css_system_off(void) 197 { 198 css_scp_sys_shutdown(); 199 } 200 201 void __dead2 css_system_reset(void) 202 { 203 css_scp_sys_reboot(); 204 } 205 206 /******************************************************************************* 207 * Handler called when the CPU power domain is about to enter standby. 208 ******************************************************************************/ 209 void css_cpu_standby(plat_local_state_t cpu_state) 210 { 211 unsigned int scr; 212 213 assert(cpu_state == ARM_LOCAL_STATE_RET); 214 215 scr = read_scr_el3(); 216 /* 217 * Enable the Non secure interrupt to wake the CPU. 218 * In GICv3 affinity routing mode, the non secure group1 interrupts use 219 * the PhysicalFIQ at EL3 whereas in GICv2, it uses the PhysicalIRQ. 220 * Enabling both the bits works for both GICv2 mode and GICv3 affinity 221 * routing mode. 222 */ 223 write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT); 224 isb(); 225 dsb(); 226 wfi(); 227 228 /* 229 * Restore SCR to the original value, synchronisation of scr_el3 is 230 * done by eret while el3_exit to save some execution cycles. 231 */ 232 write_scr_el3(scr); 233 } 234 235 /******************************************************************************* 236 * Handler called to return the 'req_state' for system suspend. 237 ******************************************************************************/ 238 void css_get_sys_suspend_power_state(psci_power_state_t *req_state) 239 { 240 unsigned int i; 241 242 /* 243 * System Suspend is supported only if the system power domain node 244 * is implemented. 245 */ 246 assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2); 247 248 for (i = ARM_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) 249 req_state->pwr_domain_state[i] = ARM_LOCAL_STATE_OFF; 250 } 251 252 /******************************************************************************* 253 * Handler to query CPU/cluster power states from SCP 254 ******************************************************************************/ 255 int css_node_hw_state(u_register_t mpidr, unsigned int power_level) 256 { 257 return css_scp_get_power_state(mpidr, power_level); 258 } 259 260 /******************************************************************************* 261 * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard 262 * platform will take care of registering the handlers with PSCI. 263 ******************************************************************************/ 264 plat_psci_ops_t plat_arm_psci_pm_ops = { 265 .pwr_domain_on = css_pwr_domain_on, 266 .pwr_domain_on_finish = css_pwr_domain_on_finish, 267 .pwr_domain_off = css_pwr_domain_off, 268 .cpu_standby = css_cpu_standby, 269 .pwr_domain_suspend = css_pwr_domain_suspend, 270 .pwr_domain_suspend_finish = css_pwr_domain_suspend_finish, 271 .system_off = css_system_off, 272 .system_reset = css_system_reset, 273 .validate_power_state = arm_validate_power_state, 274 .validate_ns_entrypoint = arm_validate_ns_entrypoint, 275 .get_node_hw_state = css_node_hw_state 276 }; 277