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