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