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