1 /* 2 * Copyright (c) 2013-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 <console.h> 34 #include <errno.h> 35 #include <debug.h> 36 #include <psci.h> 37 #include <delay_timer.h> 38 #include <platform_def.h> 39 #include <plat_private.h> 40 41 /* Macros to read the rk power domain state */ 42 #define RK_CORE_PWR_STATE(state) \ 43 ((state)->pwr_domain_state[MPIDR_AFFLVL0]) 44 #define RK_CLUSTER_PWR_STATE(state) \ 45 ((state)->pwr_domain_state[MPIDR_AFFLVL1]) 46 #define RK_SYSTEM_PWR_STATE(state) \ 47 ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL]) 48 49 static uintptr_t rockchip_sec_entrypoint; 50 51 #pragma weak rockchip_soc_cores_pwr_dm_on 52 #pragma weak rockchip_soc_hlvl_pwr_dm_off 53 #pragma weak rockchip_soc_cores_pwr_dm_off 54 #pragma weak rockchip_soc_sys_pwr_dm_suspend 55 #pragma weak rockchip_soc_cores_pwr_dm_suspend 56 #pragma weak rockchip_soc_hlvl_pwr_dm_suspend 57 #pragma weak rockchip_soc_hlvl_pwr_dm_on_finish 58 #pragma weak rockchip_soc_cores_pwr_dm_on_finish 59 #pragma weak rockchip_soc_sys_pwr_dm_resume 60 #pragma weak rockchip_soc_hlvl_pwr_dm_resume 61 #pragma weak rockchip_soc_cores_pwr_dm_resume 62 #pragma weak rockchip_soc_soft_reset 63 #pragma weak rockchip_soc_system_off 64 #pragma weak rockchip_soc_sys_pd_pwr_dn_wfi 65 #pragma weak rockchip_soc_cores_pd_pwr_dn_wfi 66 67 int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint) 68 { 69 return PSCI_E_NOT_SUPPORTED; 70 } 71 72 int rockchip_soc_hlvl_pwr_dm_off(uint32_t lvl, 73 plat_local_state_t lvl_state) 74 { 75 return PSCI_E_NOT_SUPPORTED; 76 } 77 78 int rockchip_soc_cores_pwr_dm_off(void) 79 { 80 return PSCI_E_NOT_SUPPORTED; 81 } 82 83 int rockchip_soc_sys_pwr_dm_suspend(void) 84 { 85 return PSCI_E_NOT_SUPPORTED; 86 } 87 88 int rockchip_soc_cores_pwr_dm_suspend(void) 89 { 90 return PSCI_E_NOT_SUPPORTED; 91 } 92 93 int rockchip_soc_hlvl_pwr_dm_suspend(uint32_t lvl, 94 plat_local_state_t lvl_state) 95 { 96 return PSCI_E_NOT_SUPPORTED; 97 } 98 99 int rockchip_soc_hlvl_pwr_dm_on_finish(uint32_t lvl, 100 plat_local_state_t lvl_state) 101 { 102 return PSCI_E_NOT_SUPPORTED; 103 } 104 105 int rockchip_soc_cores_pwr_dm_on_finish(void) 106 { 107 return PSCI_E_NOT_SUPPORTED; 108 } 109 110 int rockchip_soc_sys_pwr_dm_resume(void) 111 { 112 return PSCI_E_NOT_SUPPORTED; 113 } 114 115 int rockchip_soc_hlvl_pwr_dm_resume(uint32_t lvl, 116 plat_local_state_t lvl_state) 117 { 118 return PSCI_E_NOT_SUPPORTED; 119 } 120 121 int rockchip_soc_cores_pwr_dm_resume(void) 122 { 123 return PSCI_E_NOT_SUPPORTED; 124 } 125 126 void __dead2 rockchip_soc_soft_reset(void) 127 { 128 while (1) 129 ; 130 } 131 132 void __dead2 rockchip_soc_system_off(void) 133 { 134 while (1) 135 ; 136 } 137 138 void __dead2 rockchip_soc_cores_pd_pwr_dn_wfi( 139 const psci_power_state_t *target_state) 140 { 141 psci_power_down_wfi(); 142 } 143 144 void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void) 145 { 146 psci_power_down_wfi(); 147 } 148 149 /******************************************************************************* 150 * Rockchip standard platform handler called to check the validity of the power 151 * state parameter. 152 ******************************************************************************/ 153 int rockchip_validate_power_state(unsigned int power_state, 154 psci_power_state_t *req_state) 155 { 156 int pstate = psci_get_pstate_type(power_state); 157 int pwr_lvl = psci_get_pstate_pwrlvl(power_state); 158 int i; 159 160 assert(req_state); 161 162 if (pwr_lvl > PLAT_MAX_PWR_LVL) 163 return PSCI_E_INVALID_PARAMS; 164 165 /* Sanity check the requested state */ 166 if (pstate == PSTATE_TYPE_STANDBY) { 167 /* 168 * It's probably to enter standby only on power level 0 169 * ignore any other power level. 170 */ 171 if (pwr_lvl != MPIDR_AFFLVL0) 172 return PSCI_E_INVALID_PARAMS; 173 174 req_state->pwr_domain_state[MPIDR_AFFLVL0] = 175 PLAT_MAX_RET_STATE; 176 } else { 177 for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++) 178 req_state->pwr_domain_state[i] = 179 PLAT_MAX_OFF_STATE; 180 181 for (i = (pwr_lvl + 1); i <= PLAT_MAX_PWR_LVL; i++) 182 req_state->pwr_domain_state[i] = 183 PLAT_MAX_RET_STATE; 184 } 185 186 /* We expect the 'state id' to be zero */ 187 if (psci_get_pstate_id(power_state)) 188 return PSCI_E_INVALID_PARAMS; 189 190 return PSCI_E_SUCCESS; 191 } 192 193 void rockchip_get_sys_suspend_power_state(psci_power_state_t *req_state) 194 { 195 int i; 196 197 for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) 198 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; 199 } 200 201 /******************************************************************************* 202 * RockChip handler called when a CPU is about to enter standby. 203 ******************************************************************************/ 204 void rockchip_cpu_standby(plat_local_state_t cpu_state) 205 { 206 unsigned int scr; 207 208 assert(cpu_state == PLAT_MAX_RET_STATE); 209 210 scr = read_scr_el3(); 211 /* Enable PhysicalIRQ bit for NS world to wake the CPU */ 212 write_scr_el3(scr | SCR_IRQ_BIT); 213 isb(); 214 dsb(); 215 wfi(); 216 217 /* 218 * Restore SCR to the original value, synchronisation of scr_el3 is 219 * done by eret while el3_exit to save some execution cycles. 220 */ 221 write_scr_el3(scr); 222 } 223 224 /******************************************************************************* 225 * RockChip handler called when a power domain is about to be turned on. The 226 * mpidr determines the CPU to be turned on. 227 ******************************************************************************/ 228 int rockchip_pwr_domain_on(u_register_t mpidr) 229 { 230 return rockchip_soc_cores_pwr_dm_on(mpidr, rockchip_sec_entrypoint); 231 } 232 233 /******************************************************************************* 234 * RockChip handler called when a power domain is about to be turned off. The 235 * target_state encodes the power state that each level should transition to. 236 ******************************************************************************/ 237 void rockchip_pwr_domain_off(const psci_power_state_t *target_state) 238 { 239 uint32_t lvl; 240 plat_local_state_t lvl_state; 241 int ret; 242 243 assert(RK_CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE); 244 245 plat_rockchip_gic_cpuif_disable(); 246 247 if (RK_CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) 248 plat_cci_disable(); 249 250 rockchip_soc_cores_pwr_dm_off(); 251 252 for (lvl = MPIDR_AFFLVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) { 253 lvl_state = target_state->pwr_domain_state[lvl]; 254 ret = rockchip_soc_hlvl_pwr_dm_off(lvl, lvl_state); 255 if (ret == PSCI_E_NOT_SUPPORTED) 256 break; 257 } 258 } 259 260 /******************************************************************************* 261 * RockChip handler called when a power domain is about to be suspended. The 262 * target_state encodes the power state that each level should transition to. 263 ******************************************************************************/ 264 void rockchip_pwr_domain_suspend(const psci_power_state_t *target_state) 265 { 266 uint32_t lvl; 267 plat_local_state_t lvl_state; 268 int ret; 269 270 if (RK_CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE) 271 return; 272 273 if (RK_SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) 274 rockchip_soc_sys_pwr_dm_suspend(); 275 else 276 rockchip_soc_cores_pwr_dm_suspend(); 277 278 /* Prevent interrupts from spuriously waking up this cpu */ 279 plat_rockchip_gic_cpuif_disable(); 280 281 /* Perform the common cluster specific operations */ 282 if (RK_CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) 283 plat_cci_disable(); 284 285 if (RK_SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) 286 return; 287 288 for (lvl = MPIDR_AFFLVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) { 289 lvl_state = target_state->pwr_domain_state[lvl]; 290 ret = rockchip_soc_hlvl_pwr_dm_suspend(lvl, lvl_state); 291 if (ret == PSCI_E_NOT_SUPPORTED) 292 break; 293 } 294 } 295 296 /******************************************************************************* 297 * RockChip handler called when a power domain has just been powered on after 298 * being turned off earlier. The target_state encodes the low power state that 299 * each level has woken up from. 300 ******************************************************************************/ 301 void rockchip_pwr_domain_on_finish(const psci_power_state_t *target_state) 302 { 303 uint32_t lvl; 304 plat_local_state_t lvl_state; 305 int ret; 306 307 assert(RK_CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE); 308 309 for (lvl = MPIDR_AFFLVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) { 310 lvl_state = target_state->pwr_domain_state[lvl]; 311 ret = rockchip_soc_hlvl_pwr_dm_on_finish(lvl, lvl_state); 312 if (ret == PSCI_E_NOT_SUPPORTED) 313 break; 314 } 315 316 rockchip_soc_cores_pwr_dm_on_finish(); 317 318 /* Perform the common cluster specific operations */ 319 if (RK_CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { 320 /* Enable coherency if this cluster was off */ 321 plat_cci_enable(); 322 } 323 324 /* Enable the gic cpu interface */ 325 plat_rockchip_gic_pcpu_init(); 326 327 /* Program the gic per-cpu distributor or re-distributor interface */ 328 plat_rockchip_gic_cpuif_enable(); 329 } 330 331 /******************************************************************************* 332 * RockChip handler called when a power domain has just been powered on after 333 * having been suspended earlier. The target_state encodes the low power state 334 * that each level has woken up from. 335 * TODO: At the moment we reuse the on finisher and reinitialize the secure 336 * context. Need to implement a separate suspend finisher. 337 ******************************************************************************/ 338 void rockchip_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 339 { 340 uint32_t lvl; 341 plat_local_state_t lvl_state; 342 int ret; 343 344 /* Nothing to be done on waking up from retention from CPU level */ 345 if (RK_CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE) 346 return; 347 348 if (RK_SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { 349 rockchip_soc_sys_pwr_dm_resume(); 350 goto comm_finish; 351 } 352 353 for (lvl = MPIDR_AFFLVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) { 354 lvl_state = target_state->pwr_domain_state[lvl]; 355 ret = rockchip_soc_hlvl_pwr_dm_resume(lvl, lvl_state); 356 if (ret == PSCI_E_NOT_SUPPORTED) 357 break; 358 } 359 360 rockchip_soc_cores_pwr_dm_resume(); 361 362 /* 363 * Program the gic per-cpu distributor or re-distributor interface. 364 * For sys power domain operation, resuming of the gic needs to operate 365 * in rockchip_soc_sys_pwr_dm_resume(), according to the sys power mode 366 * implements. 367 */ 368 plat_rockchip_gic_cpuif_enable(); 369 370 comm_finish: 371 /* Perform the common cluster specific operations */ 372 if (RK_CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { 373 /* Enable coherency if this cluster was off */ 374 plat_cci_enable(); 375 } 376 } 377 378 /******************************************************************************* 379 * RockChip handlers to reboot the system 380 ******************************************************************************/ 381 static void __dead2 rockchip_system_reset(void) 382 { 383 rockchip_soc_soft_reset(); 384 } 385 386 /******************************************************************************* 387 * RockChip handlers to power off the system 388 ******************************************************************************/ 389 static void __dead2 rockchip_system_poweroff(void) 390 { 391 rockchip_soc_system_off(); 392 } 393 394 static void __dead2 rockchip_pd_pwr_down_wfi( 395 const psci_power_state_t *target_state) 396 { 397 if (RK_SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) 398 rockchip_soc_sys_pd_pwr_dn_wfi(); 399 else 400 rockchip_soc_cores_pd_pwr_dn_wfi(target_state); 401 } 402 403 /******************************************************************************* 404 * Export the platform handlers via plat_rockchip_psci_pm_ops. The rockchip 405 * standard 406 * platform layer will take care of registering the handlers with PSCI. 407 ******************************************************************************/ 408 const plat_psci_ops_t plat_rockchip_psci_pm_ops = { 409 .cpu_standby = rockchip_cpu_standby, 410 .pwr_domain_on = rockchip_pwr_domain_on, 411 .pwr_domain_off = rockchip_pwr_domain_off, 412 .pwr_domain_suspend = rockchip_pwr_domain_suspend, 413 .pwr_domain_on_finish = rockchip_pwr_domain_on_finish, 414 .pwr_domain_suspend_finish = rockchip_pwr_domain_suspend_finish, 415 .system_reset = rockchip_system_reset, 416 .system_off = rockchip_system_poweroff, 417 .validate_power_state = rockchip_validate_power_state, 418 .get_sys_suspend_power_state = rockchip_get_sys_suspend_power_state 419 }; 420 421 int plat_setup_psci_ops(uintptr_t sec_entrypoint, 422 const plat_psci_ops_t **psci_ops) 423 { 424 *psci_ops = &plat_rockchip_psci_pm_ops; 425 rockchip_sec_entrypoint = sec_entrypoint; 426 return 0; 427 } 428 429 uintptr_t plat_get_sec_entrypoint(void) 430 { 431 assert(rockchip_sec_entrypoint); 432 return rockchip_sec_entrypoint; 433 } 434