1 /* 2 * Copyright (c) 2015-2023, ARM Limited and Contributors. All rights reserved. 3 * 4 * Copyright (C) 2017-2023 Nuvoton Ltd. 5 * 6 * SPDX-License-Identifier: BSD-3-Clause 7 */ 8 9 #include <assert.h> 10 #include <stdbool.h> 11 12 #include <arch.h> 13 #include <arch_helpers.h> 14 #include <common/debug.h> 15 #include <drivers/arm/gicv2.h> 16 #include <lib/mmio.h> 17 #include <lib/psci/psci.h> 18 #include <lib/semihosting.h> 19 #include <npcm845x_clock.h> 20 #include <plat/arm/common/plat_arm.h> 21 #include <plat/common/platform.h> 22 #include <plat_npcm845x.h> 23 24 #define ADP_STOPPED_APPLICATION_EXIT 0x20026 25 26 /* Make composite power state parameter till power level 0 */ 27 #if PSCI_EXTENDED_STATE_ID 28 /* Not Extended */ 29 #define npcm845x_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \ 30 (((lvl0_state) << PSTATE_ID_SHIFT) | \ 31 ((type) << PSTATE_TYPE_SHIFT)) 32 #else 33 #define npcm845x_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \ 34 (((lvl0_state) << PSTATE_ID_SHIFT) | \ 35 ((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \ 36 ((type) << PSTATE_TYPE_SHIFT)) 37 #endif /* PSCI_EXTENDED_STATE_ID */ 38 39 #define npcm845x_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type) \ 40 (((lvl1_state) << PLAT_LOCAL_PSTATE_WIDTH) | \ 41 npcm845x_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type)) 42 43 /* 44 * The table storing the valid idle power states. Ensure that the 45 * array entries are populated in ascending order of state-id to 46 * enable us to use binary search during power state validation. 47 * The table must be terminated by a NULL entry. 48 */ 49 static const unsigned int npcm845x_pm_idle_states[] = { 50 /* 51 * Cluster = 0 (RUN) CPU=1 (RET, higest in idle) - 52 * Retention. The Power state is Stand-by 53 */ 54 55 /* State-id - 0x01 */ 56 npcm845x_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_RET, 57 MPIDR_AFFLVL0, PSTATE_TYPE_STANDBY), 58 59 /* 60 * For testing purposes. 61 * Only CPU suspend to standby is supported by NPCM845x 62 */ 63 /* State-id - 0x02 */ 64 npcm845x_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_OFF, 65 MPIDR_AFFLVL0, PSTATE_TYPE_POWERDOWN), 66 0, 67 }; 68 69 /******************************************************************************* 70 * Platform handler called to check the validity of the non secure 71 * entrypoint. 72 ******************************************************************************/ 73 int npcm845x_validate_ns_entrypoint(uintptr_t entrypoint) 74 { 75 /* 76 * Check if the non secure entrypoint lies within the non 77 * secure DRAM. 78 */ 79 NOTICE("%s() nuvoton_psci\n", __func__); 80 #ifdef PLAT_ARM_TRUSTED_DRAM_BASE 81 if ((entrypoint >= PLAT_ARM_TRUSTED_DRAM_BASE) && 82 (entrypoint < (PLAT_ARM_TRUSTED_DRAM_BASE + 83 PLAT_ARM_TRUSTED_DRAM_SIZE))) { 84 return PSCI_E_INVALID_ADDRESS; 85 } 86 #endif /* PLAT_ARM_TRUSTED_DRAM_BASE */ 87 /* For TFTS purposes, '0' is also illegal */ 88 #ifdef SPD_tspd 89 if (entrypoint == 0) { 90 return PSCI_E_INVALID_ADDRESS; 91 } 92 #endif /* SPD_tspd */ 93 return PSCI_E_SUCCESS; 94 } 95 96 /******************************************************************************* 97 * Platform handler called when a CPU is about to enter standby. 98 ******************************************************************************/ 99 void npcm845x_cpu_standby(plat_local_state_t cpu_state) 100 { 101 NOTICE("%s() nuvoton_psci\n", __func__); 102 103 uint64_t scr; 104 105 scr = read_scr_el3(); 106 write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT); 107 108 /* 109 * Enter standby state 110 * dsb is good practice before using wfi to enter low power states 111 */ 112 isb(); 113 dsb(); 114 wfi(); 115 116 /* Once awake */ 117 write_scr_el3(scr); 118 } 119 120 /******************************************************************************* 121 * Platform handler called when a power domain is about to be turned on. The 122 * mpidr determines the CPU to be turned on. 123 ******************************************************************************/ 124 int npcm845x_pwr_domain_on(u_register_t mpidr) 125 { 126 int rc = PSCI_E_SUCCESS; 127 int cpu_id = plat_core_pos_by_mpidr(mpidr); 128 129 if ((unsigned int)cpu_id >= PLATFORM_CORE_COUNT) { 130 ERROR("%s() CPU 0x%X\n", __func__, cpu_id); 131 return PSCI_E_INVALID_PARAMS; 132 } 133 134 if (cpu_id == -1) { 135 /* domain on was not called by a CPU */ 136 ERROR("%s() was not per CPU 0x%X\n", __func__, cpu_id); 137 return PSCI_E_INVALID_PARAMS; 138 } 139 140 unsigned int pos = (unsigned int)plat_core_pos_by_mpidr(mpidr); 141 uintptr_t hold_base = PLAT_NPCM_TM_HOLD_BASE; 142 143 assert(pos < PLATFORM_CORE_COUNT); 144 145 hold_base += pos * PLAT_NPCM_TM_HOLD_ENTRY_SIZE; 146 147 mmio_write_64(hold_base, PLAT_NPCM_TM_HOLD_STATE_GO); 148 /* No cache maintenance here, hold_base is mapped as device memory. */ 149 150 /* Make sure that the write has completed */ 151 dsb(); 152 isb(); 153 154 sev(); 155 156 return rc; 157 } 158 159 160 /******************************************************************************* 161 * Platform handler called when a power domain is about to be suspended. The 162 * target_state encodes the power state that each level should transition to. 163 ******************************************************************************/ 164 void npcm845x_pwr_domain_suspend(const psci_power_state_t *target_state) 165 { 166 NOTICE("%s() nuvoton_psci\n", __func__); 167 168 for (size_t i = 0; (uint64_t)i <= PLAT_MAX_PWR_LVL; i++) { 169 INFO("%s: target_state->pwr_domain_state[%lu]=%x\n", 170 __func__, i, target_state->pwr_domain_state[i]); 171 } 172 173 gicv2_cpuif_disable(); 174 175 NOTICE("%s() Out of suspend\n", __func__); 176 } 177 178 179 /******************************************************************************* 180 * Platform handler called when a power domain has just been powered on after 181 * being turned off earlier. The target_state encodes the low power state that 182 * each level has woken up from. 183 ******************************************************************************/ 184 void npcm845x_pwr_domain_on_finish(const psci_power_state_t *target_state) 185 { 186 NOTICE("%s() nuvoton_psci\n", __func__); 187 188 for (size_t i = 0; (uint64_t)i <= PLAT_MAX_PWR_LVL; i++) { 189 INFO("%s: target_state->pwr_domain_state[%lu]=%x\n", 190 __func__, i, target_state->pwr_domain_state[i]); 191 } 192 193 assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == 194 PLAT_LOCAL_STATE_OFF); 195 196 gicv2_pcpu_distif_init(); 197 gicv2_cpuif_enable(); 198 } 199 200 201 /******************************************************************************* 202 * Platform handler called when a power domain has just been powered on after 203 * having been suspended earlier. The target_state encodes the low power state 204 * that each level has woken up from. 205 ******************************************************************************/ 206 void npcm845x_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 207 { 208 NOTICE("%s() nuvoton_psci\n", __func__); 209 210 for (size_t i = 0; (uint64_t)i <= PLAT_MAX_PWR_LVL; i++) { 211 INFO("%s: target_state->pwr_domain_state[%lu]=%x\n", 212 __func__, i, target_state->pwr_domain_state[i]); 213 } 214 215 assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == 216 PLAT_LOCAL_STATE_OFF); 217 218 gicv2_pcpu_distif_init(); 219 gicv2_cpuif_enable(); 220 } 221 222 223 void __dead2 npcm845x_system_reset(void) 224 { 225 uintptr_t RESET_BASE_ADDR; 226 uint32_t val; 227 228 NOTICE("%s() nuvoton_psci\n", __func__); 229 console_flush(); 230 231 dsbsy(); 232 isb(); 233 234 /* 235 * In future - support all reset types. For now, SW1 reset 236 * Enable software reset 1 to reboot the BMC 237 */ 238 RESET_BASE_ADDR = (uintptr_t)0xF0801000; 239 240 /* Read SW1 control register */ 241 val = mmio_read_32(RESET_BASE_ADDR + 0x44); 242 /* Keep SPI BMC & MC persist*/ 243 val &= 0xFBFFFFDF; 244 /* Setting SW1 control register */ 245 mmio_write_32(RESET_BASE_ADDR + 0x44, val); 246 /* Set SW1 reset */ 247 mmio_write_32(RESET_BASE_ADDR + 0x14, 0x8); 248 dsb(); 249 250 while (1) { 251 ; 252 } 253 } 254 255 int npcm845x_validate_power_state(unsigned int power_state, 256 psci_power_state_t *req_state) 257 { 258 unsigned int state_id; 259 int i; 260 261 NOTICE("%s() nuvoton_psci\n", __func__); 262 assert(req_state); 263 264 /* 265 * Currently we are using a linear search for finding the matching 266 * entry in the idle power state array. This can be made a binary 267 * search if the number of entries justify the additional complexity. 268 */ 269 for (i = 0; !!npcm845x_pm_idle_states[i]; i++) { 270 if (power_state == npcm845x_pm_idle_states[i]) { 271 break; 272 } 273 } 274 275 /* Return error if entry not found in the idle state array */ 276 if (!npcm845x_pm_idle_states[i]) { 277 return PSCI_E_INVALID_PARAMS; 278 } 279 280 i = 0; 281 state_id = psci_get_pstate_id(power_state); 282 283 /* Parse the State ID and populate the state info parameter */ 284 while (state_id) { 285 req_state->pwr_domain_state[i++] = (uint8_t)state_id & 286 PLAT_LOCAL_PSTATE_MASK; 287 state_id >>= PLAT_LOCAL_PSTATE_WIDTH; 288 } 289 290 return PSCI_E_SUCCESS; 291 } 292 293 /* 294 * The NPCM845 doesn't truly support power management at SYSTEM power domain. 295 * The SYSTEM_SUSPEND will be down-graded to the cluster level within 296 * the platform layer. The `fake` SYSTEM_SUSPEND allows us to validate 297 * some of the driver save and restore sequences on FVP. 298 */ 299 #if !ARM_BL31_IN_DRAM 300 void npcm845x_get_sys_suspend_power_state(psci_power_state_t *req_state) 301 { 302 unsigned int i; 303 304 NOTICE("%s() nuvoton_psci\n", __func__); 305 306 for (i = ARM_PWR_LVL0; (uint64_t)i <= PLAT_MAX_PWR_LVL; i++) { 307 req_state->pwr_domain_state[i] = (uint8_t)PLAT_LOCAL_STATE_OFF; 308 } 309 } 310 #endif /* !ARM_BL31_IN_DRAM */ 311 312 /* 313 * The rest of the PSCI implementation are for testing purposes only. 314 * Not supported in Arbel 315 */ 316 void __dead2 npcm845x_system_off(void) 317 { 318 console_flush(); 319 320 dsbsy(); 321 isb(); 322 323 /* NPCM845 doesn't allow real system off, Do reaset instead */ 324 /* Do reset here TBD which, in the meanwhile SW1 reset */ 325 for (;;) { 326 wfi(); 327 } 328 } 329 330 void __dead2 plat_secondary_cold_boot_setup(void); 331 332 void __dead2 npcm845x_pwr_down_wfi( 333 const psci_power_state_t *target_state) 334 { 335 uintptr_t hold_base = PLAT_NPCM_TM_HOLD_BASE; 336 unsigned int pos = plat_my_core_pos(); 337 338 if (pos == 0) { 339 /* 340 * The secondaries will always be in a wait 341 * for warm boot on reset, but the BSP needs 342 * to be able to distinguish between waiting 343 * for warm boot (e.g. after psci_off, waiting 344 * for psci_on) and a cold boot. 345 */ 346 mmio_write_64(hold_base, PLAT_NPCM_TM_HOLD_STATE_BSP_OFF); 347 /* No cache maintenance here, we run with caches off already. */ 348 dsb(); 349 isb(); 350 } 351 352 wfe(); 353 354 while (1) { 355 ; 356 } 357 } 358 359 /******************************************************************************* 360 * Platform handler called when a power domain is about to be turned off. The 361 * target_state encodes the power state that each level should transition to. 362 ******************************************************************************/ 363 void npcm845x_pwr_domain_off(const psci_power_state_t *target_state) 364 { 365 NOTICE("%s() nuvoton_psci\n", __func__); 366 367 for (size_t i = 0; (uint64_t)i <= PLAT_MAX_PWR_LVL; i++) { 368 INFO("%s: target_state->pwr_domain_state[%lu]=%x\n", 369 __func__, i, target_state->pwr_domain_state[i]); 370 } 371 372 plat_secondary_cold_boot_setup(); 373 } 374 375 static const plat_psci_ops_t npcm845x_plat_psci_ops = { 376 .cpu_standby = npcm845x_cpu_standby, 377 .pwr_domain_on = npcm845x_pwr_domain_on, 378 .pwr_domain_suspend = npcm845x_pwr_domain_suspend, 379 .pwr_domain_on_finish = npcm845x_pwr_domain_on_finish, 380 .pwr_domain_suspend_finish = npcm845x_pwr_domain_suspend_finish, 381 .system_reset = npcm845x_system_reset, 382 .validate_power_state = npcm845x_validate_power_state, 383 .validate_ns_entrypoint = npcm845x_validate_ns_entrypoint, 384 385 /* For testing purposes only This PSCI states are not supported */ 386 .pwr_domain_off = npcm845x_pwr_domain_off, 387 .pwr_domain_pwr_down = npcm845x_pwr_down_wfi, 388 }; 389 390 /* For reference only 391 * typedef struct plat_psci_ops { 392 * void (*cpu_standby)(plat_local_state_t cpu_state); 393 * int (*pwr_domain_on)(u_register_t mpidr); 394 * void (*pwr_domain_off)(const psci_power_state_t *target_state); 395 * void (*pwr_domain_suspend_pwrdown_early)( 396 * const psci_power_state_t *target_state); 397 * void (*pwr_domain_suspend)(const psci_power_state_t *target_state); 398 * void (*pwr_domain_on_finish)(const psci_power_state_t *target_state); 399 * void (*pwr_domain_on_finish_late)( 400 * const psci_power_state_t *target_state); 401 * void (*pwr_domain_suspend_finish)( 402 * const psci_power_state_t *target_state); 403 * void __dead2 (*pwr_domain_pwr_down )( 404 * const psci_power_state_t *target_state); 405 * void __dead2 (*system_off)(void); 406 * void __dead2 (*system_reset)(void); 407 * int (*validate_power_state)(unsigned int power_state, 408 * psci_power_state_t *req_state); 409 * int (*validate_ns_entrypoint)(uintptr_t ns_entrypoint); 410 * void (*get_sys_suspend_power_state)( 411 * psci_power_state_t *req_state); 412 * int (*get_pwr_lvl_state_idx)(plat_local_state_t pwr_domain_state, 413 * int pwrlvl); 414 * int (*translate_power_state_by_mpidr)(u_register_t mpidr, 415 * unsigned int power_state, 416 * psci_power_state_t *output_state); 417 * int (*get_node_hw_state)(u_register_t mpidr, unsigned int power_level); 418 * int (*mem_protect_chk)(uintptr_t base, u_register_t length); 419 * int (*read_mem_protect)(int *val); 420 * int (*write_mem_protect)(int val); 421 * int (*system_reset2)(int is_vendor, 422 * int reset_type, u_register_t cookie); 423 * } plat_psci_ops_t; 424 */ 425 426 int plat_setup_psci_ops(uintptr_t sec_entrypoint, 427 const plat_psci_ops_t **psci_ops) 428 { 429 uintptr_t *entrypoint = (void *)PLAT_NPCM_TM_ENTRYPOINT; 430 431 *entrypoint = sec_entrypoint; 432 433 *psci_ops = &npcm845x_plat_psci_ops; 434 435 return 0; 436 } 437