13fc4124cSDan Handley /* 2cb331826SBoyan Karatotev * Copyright (c) 2013-2025, Arm Limited and Contributors. All rights reserved. 33fc4124cSDan Handley * 482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 53fc4124cSDan Handley */ 63fc4124cSDan Handley 73fc4124cSDan Handley #include <assert.h> 809d40e0eSAntonio Nino Diaz 909d40e0eSAntonio Nino Diaz #include <arch_helpers.h> 1009d40e0eSAntonio Nino Diaz #include <common/debug.h> 1109d40e0eSAntonio Nino Diaz #include <drivers/arm/gicv3.h> 12560293bbSAntonio Nino Diaz #include <drivers/arm/fvp/fvp_pwrc.h> 1309d40e0eSAntonio Nino Diaz #include <lib/mmio.h> 1409d40e0eSAntonio Nino Diaz #include <lib/psci/psci.h> 15bd9344f6SAntonio Nino Diaz #include <plat/arm/common/arm_config.h> 16bd9344f6SAntonio Nino Diaz #include <plat/arm/common/plat_arm.h> 17234bc7f8SAntonio Nino Diaz #include <platform_def.h> 1809d40e0eSAntonio Nino Diaz 193fc4124cSDan Handley #include "fvp_private.h" 20609e053cSAmbroise Vincent #include "../drivers/arm/gic/v3/gicv3_private.h" 213fc4124cSDan Handley 223fc4124cSDan Handley 232204afdeSSoby Mathew #if ARM_RECOM_STATE_ID_ENC 242204afdeSSoby Mathew /* 252204afdeSSoby Mathew * The table storing the valid idle power states. Ensure that the 262204afdeSSoby Mathew * array entries are populated in ascending order of state-id to 272204afdeSSoby Mathew * enable us to use binary search during power state validation. 282204afdeSSoby Mathew * The table must be terminated by a NULL entry. 292204afdeSSoby Mathew */ 302204afdeSSoby Mathew const unsigned int arm_pm_idle_states[] = { 312204afdeSSoby Mathew /* State-id - 0x01 */ 322204afdeSSoby Mathew arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RET, 332204afdeSSoby Mathew ARM_PWR_LVL0, PSTATE_TYPE_STANDBY), 342204afdeSSoby Mathew /* State-id - 0x02 */ 352204afdeSSoby Mathew arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_OFF, 362204afdeSSoby Mathew ARM_PWR_LVL0, PSTATE_TYPE_POWERDOWN), 372204afdeSSoby Mathew /* State-id - 0x22 */ 382204afdeSSoby Mathew arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF, 392204afdeSSoby Mathew ARM_PWR_LVL1, PSTATE_TYPE_POWERDOWN), 40e35a3fb5SSoby Mathew /* State-id - 0x222 */ 41e35a3fb5SSoby Mathew arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF, 42e35a3fb5SSoby Mathew ARM_LOCAL_STATE_OFF, ARM_PWR_LVL2, PSTATE_TYPE_POWERDOWN), 432204afdeSSoby Mathew 0, 442204afdeSSoby Mathew }; 452204afdeSSoby Mathew #endif 462204afdeSSoby Mathew 473fc4124cSDan Handley /******************************************************************************* 483fc4124cSDan Handley * Function which implements the common FVP specific operations to power down a 493fc4124cSDan Handley * cluster in response to a CPU_OFF or CPU_SUSPEND request. 503fc4124cSDan Handley ******************************************************************************/ 513fc4124cSDan Handley static void fvp_cluster_pwrdwn_common(void) 523fc4124cSDan Handley { 533fc4124cSDan Handley uint64_t mpidr = read_mpidr_el1(); 543fc4124cSDan Handley 553fc4124cSDan Handley /* Disable coherency if this cluster is to be turned off */ 566355f234SVikram Kanigiri fvp_interconnect_disable(); 573fc4124cSDan Handley 583fc4124cSDan Handley /* Program the power controller to turn the cluster off */ 593fc4124cSDan Handley fvp_pwrc_write_pcoffr(mpidr); 603fc4124cSDan Handley } 613fc4124cSDan Handley 62e35a3fb5SSoby Mathew /* 63e35a3fb5SSoby Mathew * Empty implementation of these hooks avoid setting the GICR_WAKER.Sleep bit 64e35a3fb5SSoby Mathew * on ARM GICv3 implementations on FVP. This is required, because FVP does not 65e35a3fb5SSoby Mathew * support SYSTEM_SUSPEND and it is `faked` in firmware. Hence, for wake up 66e35a3fb5SSoby Mathew * from `fake` system suspend the GIC must not be powered off. 67e35a3fb5SSoby Mathew */ 68dc6aad2eSRoberto Vargas void arm_gicv3_distif_pre_save(unsigned int rdist_proc_num) 69e35a3fb5SSoby Mathew {} 70e35a3fb5SSoby Mathew 71dc6aad2eSRoberto Vargas void arm_gicv3_distif_post_restore(unsigned int rdist_proc_num) 72e35a3fb5SSoby Mathew {} 73e35a3fb5SSoby Mathew 74f14d1886SSoby Mathew static void fvp_power_domain_on_finish_common(const psci_power_state_t *target_state) 75f14d1886SSoby Mathew { 76f14d1886SSoby Mathew unsigned long mpidr; 77f14d1886SSoby Mathew 78f14d1886SSoby Mathew assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == 79f14d1886SSoby Mathew ARM_LOCAL_STATE_OFF); 80f14d1886SSoby Mathew 81f14d1886SSoby Mathew /* Get the mpidr for this cpu */ 82f14d1886SSoby Mathew mpidr = read_mpidr_el1(); 83f14d1886SSoby Mathew 84f14d1886SSoby Mathew /* Perform the common cluster specific operations */ 85f14d1886SSoby Mathew if (target_state->pwr_domain_state[ARM_PWR_LVL1] == 86f14d1886SSoby Mathew ARM_LOCAL_STATE_OFF) { 87f14d1886SSoby Mathew /* 88f14d1886SSoby Mathew * This CPU might have woken up whilst the cluster was 89f14d1886SSoby Mathew * attempting to power down. In this case the FVP power 90f14d1886SSoby Mathew * controller will have a pending cluster power off request 91f14d1886SSoby Mathew * which needs to be cleared by writing to the PPONR register. 92f14d1886SSoby Mathew * This prevents the power controller from interpreting a 93f14d1886SSoby Mathew * subsequent entry of this cpu into a simple wfi as a power 94f14d1886SSoby Mathew * down request. 95f14d1886SSoby Mathew */ 96f14d1886SSoby Mathew fvp_pwrc_write_pponr(mpidr); 97f14d1886SSoby Mathew 98f14d1886SSoby Mathew /* Enable coherency if this cluster was off */ 996355f234SVikram Kanigiri fvp_interconnect_enable(); 100f14d1886SSoby Mathew } 101e35a3fb5SSoby Mathew /* Perform the common system specific operations */ 102e35a3fb5SSoby Mathew if (target_state->pwr_domain_state[ARM_PWR_LVL2] == 103e35a3fb5SSoby Mathew ARM_LOCAL_STATE_OFF) 104e35a3fb5SSoby Mathew arm_system_pwr_domain_resume(); 105f14d1886SSoby Mathew 106f14d1886SSoby Mathew /* 107f14d1886SSoby Mathew * Clear PWKUPR.WEN bit to ensure interrupts do not interfere 108f14d1886SSoby Mathew * with a cpu power down unless the bit is set again 109f14d1886SSoby Mathew */ 110f14d1886SSoby Mathew fvp_pwrc_clr_wen(mpidr); 111f14d1886SSoby Mathew } 112f14d1886SSoby Mathew 1133fc4124cSDan Handley /******************************************************************************* 11438dce70fSSoby Mathew * FVP handler called when a CPU is about to enter standby. 1153fc4124cSDan Handley ******************************************************************************/ 1161af540efSRoberto Vargas static void fvp_cpu_standby(plat_local_state_t cpu_state) 1173fc4124cSDan Handley { 1183202ce8bSAlexei Fedorov u_register_t scr = read_scr_el3(); 11938dce70fSSoby Mathew 12038dce70fSSoby Mathew assert(cpu_state == ARM_LOCAL_STATE_RET); 12138dce70fSSoby Mathew 1223fc4124cSDan Handley /* 1233202ce8bSAlexei Fedorov * Enable the Non-secure interrupt to wake the CPU. 1243202ce8bSAlexei Fedorov * In GICv3 affinity routing mode, the Non-secure Group 1 interrupts 1253202ce8bSAlexei Fedorov * use Physical FIQ at EL3 whereas in GICv2, Physical IRQ is used. 1263202ce8bSAlexei Fedorov * Enabling both the bits works for both GICv2 mode and GICv3 affinity 1273202ce8bSAlexei Fedorov * routing mode. 1283202ce8bSAlexei Fedorov */ 1293202ce8bSAlexei Fedorov write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT); 1303202ce8bSAlexei Fedorov isb(); 1313202ce8bSAlexei Fedorov 1323202ce8bSAlexei Fedorov /* 1333202ce8bSAlexei Fedorov * Enter standby state. 1343202ce8bSAlexei Fedorov * dsb is good practice before using wfi to enter low power states. 1353fc4124cSDan Handley */ 1363fc4124cSDan Handley dsb(); 1373fc4124cSDan Handley wfi(); 1383202ce8bSAlexei Fedorov 1393202ce8bSAlexei Fedorov /* 1403202ce8bSAlexei Fedorov * Restore SCR_EL3 to the original value, synchronisation of SCR_EL3 1413202ce8bSAlexei Fedorov * is done by eret in el3_exit() to save some execution cycles. 1423202ce8bSAlexei Fedorov */ 1433202ce8bSAlexei Fedorov write_scr_el3(scr); 1443fc4124cSDan Handley } 1453fc4124cSDan Handley 1463fc4124cSDan Handley /******************************************************************************* 14738dce70fSSoby Mathew * FVP handler called when a power domain is about to be turned on. The 14838dce70fSSoby Mathew * mpidr determines the CPU to be turned on. 1493fc4124cSDan Handley ******************************************************************************/ 1501af540efSRoberto Vargas static int fvp_pwr_domain_on(u_register_t mpidr) 1513fc4124cSDan Handley { 1523fc4124cSDan Handley int rc = PSCI_E_SUCCESS; 1533fc4124cSDan Handley unsigned int psysr; 1543fc4124cSDan Handley 1553fc4124cSDan Handley /* 1560f09c8f7SSandrine Bailleux * Ensure that we do not cancel an inflight power off request for the 1570f09c8f7SSandrine Bailleux * target cpu. That would leave it in a zombie wfi. Wait for it to power 1580f09c8f7SSandrine Bailleux * off and then program the power controller to turn that CPU on. 1593fc4124cSDan Handley */ 1603fc4124cSDan Handley do { 1613fc4124cSDan Handley psysr = fvp_pwrc_read_psysr(mpidr); 162e02f469fSSathees Balya } while ((psysr & PSYSR_AFF_L0) != 0U); 1633fc4124cSDan Handley 1643fc4124cSDan Handley fvp_pwrc_write_pponr(mpidr); 1653fc4124cSDan Handley return rc; 1663fc4124cSDan Handley } 1673fc4124cSDan Handley 1683fc4124cSDan Handley /******************************************************************************* 16938dce70fSSoby Mathew * FVP handler called when a power domain is about to be turned off. The 17038dce70fSSoby Mathew * target_state encodes the power state that each level should transition to. 1713fc4124cSDan Handley ******************************************************************************/ 1721af540efSRoberto Vargas static void fvp_pwr_domain_off(const psci_power_state_t *target_state) 1733fc4124cSDan Handley { 17438dce70fSSoby Mathew assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == 17538dce70fSSoby Mathew ARM_LOCAL_STATE_OFF); 1763fc4124cSDan Handley 1773fc4124cSDan Handley /* 17838dce70fSSoby Mathew * If execution reaches this stage then this power domain will be 17938dce70fSSoby Mathew * suspended. Perform at least the cpu specific actions followed 18038dce70fSSoby Mathew * by the cluster specific operations if applicable. 1813fc4124cSDan Handley */ 18274a9578cSJeenu Viswambharan 18374a9578cSJeenu Viswambharan /* Program the power controller to power off this cpu. */ 18474a9578cSJeenu Viswambharan fvp_pwrc_write_ppoffr(read_mpidr_el1()); 1853fc4124cSDan Handley 18638dce70fSSoby Mathew if (target_state->pwr_domain_state[ARM_PWR_LVL1] == 18738dce70fSSoby Mathew ARM_LOCAL_STATE_OFF) 1883fc4124cSDan Handley fvp_cluster_pwrdwn_common(); 1893fc4124cSDan Handley 1903fc4124cSDan Handley } 1913fc4124cSDan Handley 1923fc4124cSDan Handley /******************************************************************************* 19338dce70fSSoby Mathew * FVP handler called when a power domain is about to be suspended. The 19438dce70fSSoby Mathew * target_state encodes the power state that each level should transition to. 1953fc4124cSDan Handley ******************************************************************************/ 1961af540efSRoberto Vargas static void fvp_pwr_domain_suspend(const psci_power_state_t *target_state) 1973fc4124cSDan Handley { 1983fc4124cSDan Handley unsigned long mpidr; 1993fc4124cSDan Handley 20038dce70fSSoby Mathew /* 20138dce70fSSoby Mathew * FVP has retention only at cpu level. Just return 20238dce70fSSoby Mathew * as nothing is to be done for retention. 20338dce70fSSoby Mathew */ 20438dce70fSSoby Mathew if (target_state->pwr_domain_state[ARM_PWR_LVL0] == 20538dce70fSSoby Mathew ARM_LOCAL_STATE_RET) 2063fc4124cSDan Handley return; 2073fc4124cSDan Handley 20838dce70fSSoby Mathew assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == 20938dce70fSSoby Mathew ARM_LOCAL_STATE_OFF); 21038dce70fSSoby Mathew 2113fc4124cSDan Handley /* Get the mpidr for this cpu */ 2123fc4124cSDan Handley mpidr = read_mpidr_el1(); 2133fc4124cSDan Handley 2143fc4124cSDan Handley /* Program the power controller to enable wakeup interrupts. */ 2153fc4124cSDan Handley fvp_pwrc_set_wen(mpidr); 2163fc4124cSDan Handley 21774a9578cSJeenu Viswambharan /* 21874a9578cSJeenu Viswambharan * The Redistributor is not powered off as it can potentially prevent 21974a9578cSJeenu Viswambharan * wake up events reaching the CPUIF and/or might lead to losing 22074a9578cSJeenu Viswambharan * register context. 22174a9578cSJeenu Viswambharan */ 22274a9578cSJeenu Viswambharan 2233fc4124cSDan Handley /* Perform the common cluster specific operations */ 22438dce70fSSoby Mathew if (target_state->pwr_domain_state[ARM_PWR_LVL1] == 22538dce70fSSoby Mathew ARM_LOCAL_STATE_OFF) 2263fc4124cSDan Handley fvp_cluster_pwrdwn_common(); 227e35a3fb5SSoby Mathew 228e35a3fb5SSoby Mathew /* Perform the common system specific operations */ 229e35a3fb5SSoby Mathew if (target_state->pwr_domain_state[ARM_PWR_LVL2] == 230e35a3fb5SSoby Mathew ARM_LOCAL_STATE_OFF) 231e35a3fb5SSoby Mathew arm_system_pwr_domain_save(); 232e35a3fb5SSoby Mathew 233e35a3fb5SSoby Mathew /* Program the power controller to power off this cpu. */ 234e35a3fb5SSoby Mathew fvp_pwrc_write_ppoffr(read_mpidr_el1()); 235e75cc247SWing Li 236e75cc247SWing Li return; 2373fc4124cSDan Handley } 2383fc4124cSDan Handley 2393fc4124cSDan Handley /******************************************************************************* 24038dce70fSSoby Mathew * FVP handler called when a power domain has just been powered on after 24138dce70fSSoby Mathew * being turned off earlier. The target_state encodes the low power state that 24238dce70fSSoby Mathew * each level has woken up from. 2433fc4124cSDan Handley ******************************************************************************/ 2441af540efSRoberto Vargas static void fvp_pwr_domain_on_finish(const psci_power_state_t *target_state) 2453fc4124cSDan Handley { 246f14d1886SSoby Mathew fvp_power_domain_on_finish_common(target_state); 2476806cd23SMadhukar Pappireddy } 2486806cd23SMadhukar Pappireddy 2496806cd23SMadhukar Pappireddy /******************************************************************************* 2506806cd23SMadhukar Pappireddy * FVP handler called when a power domain has just been powered on and the cpu 2516806cd23SMadhukar Pappireddy * and its cluster are fully participating in coherent transaction on the 2526806cd23SMadhukar Pappireddy * interconnect. Data cache must be enabled for CPU at this point. 2536806cd23SMadhukar Pappireddy ******************************************************************************/ 2546806cd23SMadhukar Pappireddy static void fvp_pwr_domain_on_finish_late(const psci_power_state_t *target_state) 2556806cd23SMadhukar Pappireddy { 256c5c54e20SBoyan Karatotev #if USE_GIC_DRIVER == 3 257cb331826SBoyan Karatotev fvp_pcpu_init(); 258c5c54e20SBoyan Karatotev #endif 2593fc4124cSDan Handley } 2603fc4124cSDan Handley 2613fc4124cSDan Handley /******************************************************************************* 26238dce70fSSoby Mathew * FVP handler called when a power domain has just been powered on after 26338dce70fSSoby Mathew * having been suspended earlier. The target_state encodes the low power state 26438dce70fSSoby Mathew * that each level has woken up from. 2653fc4124cSDan Handley * TODO: At the moment we reuse the on finisher and reinitialize the secure 2663fc4124cSDan Handley * context. Need to implement a separate suspend finisher. 2673fc4124cSDan Handley ******************************************************************************/ 2681af540efSRoberto Vargas static void fvp_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 2693fc4124cSDan Handley { 27038dce70fSSoby Mathew /* 27138dce70fSSoby Mathew * Nothing to be done on waking up from retention from CPU level. 27238dce70fSSoby Mathew */ 27338dce70fSSoby Mathew if (target_state->pwr_domain_state[ARM_PWR_LVL0] == 27438dce70fSSoby Mathew ARM_LOCAL_STATE_RET) 27538dce70fSSoby Mathew return; 27638dce70fSSoby Mathew 277f14d1886SSoby Mathew fvp_power_domain_on_finish_common(target_state); 2783fc4124cSDan Handley } 2793fc4124cSDan Handley 2803fc4124cSDan Handley /******************************************************************************* 2813fc4124cSDan Handley * FVP handlers to shutdown/reboot the system 2823fc4124cSDan Handley ******************************************************************************/ 283da305ec7SBoyan Karatotev static void fvp_system_off(void) 2843fc4124cSDan Handley { 2853fc4124cSDan Handley /* Write the System Configuration Control Register */ 2863fc4124cSDan Handley mmio_write_32(V2M_SYSREGS_BASE + V2M_SYS_CFGCTRL, 2873fc4124cSDan Handley V2M_CFGCTRL_START | 2883fc4124cSDan Handley V2M_CFGCTRL_RW | 2893fc4124cSDan Handley V2M_CFGCTRL_FUNC(V2M_FUNC_SHUTDOWN)); 2903fc4124cSDan Handley } 2913fc4124cSDan Handley 292da305ec7SBoyan Karatotev static void fvp_system_reset(void) 2933fc4124cSDan Handley { 2943fc4124cSDan Handley /* Write the System Configuration Control Register */ 2953fc4124cSDan Handley mmio_write_32(V2M_SYSREGS_BASE + V2M_SYS_CFGCTRL, 2963fc4124cSDan Handley V2M_CFGCTRL_START | 2973fc4124cSDan Handley V2M_CFGCTRL_RW | 2983fc4124cSDan Handley V2M_CFGCTRL_FUNC(V2M_FUNC_REBOOT)); 2993fc4124cSDan Handley } 3003fc4124cSDan Handley 3011298ae02SJeenu Viswambharan static int fvp_node_hw_state(u_register_t target_cpu, 3021298ae02SJeenu Viswambharan unsigned int power_level) 3031298ae02SJeenu Viswambharan { 3041298ae02SJeenu Viswambharan unsigned int psysr; 305b9c3a8c0SGovindraj Raja int ret = 0; 3061298ae02SJeenu Viswambharan 3071298ae02SJeenu Viswambharan /* 3081298ae02SJeenu Viswambharan * The format of 'power_level' is implementation-defined, but 0 must 3091298ae02SJeenu Viswambharan * mean a CPU. We also allow 1 to denote the cluster 3101298ae02SJeenu Viswambharan */ 311*4824e250SGovindraj Raja if (power_level > ARM_PWR_LVL1) { 3121298ae02SJeenu Viswambharan return PSCI_E_INVALID_PARAMS; 313*4824e250SGovindraj Raja } 3141298ae02SJeenu Viswambharan 3151298ae02SJeenu Viswambharan /* 3161298ae02SJeenu Viswambharan * Read the status of the given MPDIR from FVP power controller. The 3171298ae02SJeenu Viswambharan * power controller only gives us on/off status, so map that to expected 3181298ae02SJeenu Viswambharan * return values of the PSCI call 3191298ae02SJeenu Viswambharan */ 3201298ae02SJeenu Viswambharan psysr = fvp_pwrc_read_psysr(target_cpu); 3211298ae02SJeenu Viswambharan if (psysr == PSYSR_INVALID) 3221298ae02SJeenu Viswambharan return PSCI_E_INVALID_PARAMS; 3231298ae02SJeenu Viswambharan 324649c48f5SJonathan Wright if (power_level == ARM_PWR_LVL0) { 325e02f469fSSathees Balya ret = ((psysr & PSYSR_AFF_L0) != 0U) ? HW_ON : HW_OFF; 326b9c3a8c0SGovindraj Raja } else if (power_level == ARM_PWR_LVL1) { 327b9c3a8c0SGovindraj Raja /* 328b9c3a8c0SGovindraj Raja * Use L1 affinity if MPIDR_EL1.MT bit is not set else use L2 affinity. 329b9c3a8c0SGovindraj Raja */ 330b9c3a8c0SGovindraj Raja if ((read_mpidr_el1() & MPIDR_MT_MASK) == 0U) 331e02f469fSSathees Balya ret = ((psysr & PSYSR_AFF_L1) != 0U) ? HW_ON : HW_OFF; 332b9c3a8c0SGovindraj Raja else 333b9c3a8c0SGovindraj Raja ret = ((psysr & PSYSR_AFF_L2) != 0U) ? HW_ON : HW_OFF; 3341298ae02SJeenu Viswambharan } 3351298ae02SJeenu Viswambharan 3361298ae02SJeenu Viswambharan return ret; 3371298ae02SJeenu Viswambharan } 3381298ae02SJeenu Viswambharan 339e35a3fb5SSoby Mathew /* 340e35a3fb5SSoby Mathew * The FVP doesn't truly support power management at SYSTEM power domain. The 341e35a3fb5SSoby Mathew * SYSTEM_SUSPEND will be down-graded to the cluster level within the platform 342e35a3fb5SSoby Mathew * layer. The `fake` SYSTEM_SUSPEND allows us to validate some of the driver 343e35a3fb5SSoby Mathew * save and restore sequences on FVP. 344e35a3fb5SSoby Mathew */ 3451af540efSRoberto Vargas #if !ARM_BL31_IN_DRAM 3461af540efSRoberto Vargas static void fvp_get_sys_suspend_power_state(psci_power_state_t *req_state) 347e35a3fb5SSoby Mathew { 348e35a3fb5SSoby Mathew unsigned int i; 349e35a3fb5SSoby Mathew 350e35a3fb5SSoby Mathew for (i = ARM_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) 351e35a3fb5SSoby Mathew req_state->pwr_domain_state[i] = ARM_LOCAL_STATE_OFF; 352e0ef05bbSWing Li 353e0ef05bbSWing Li #if PSCI_OS_INIT_MODE 354e0ef05bbSWing Li req_state->last_at_pwrlvl = PLAT_MAX_PWR_LVL; 355e0ef05bbSWing Li #endif 356e35a3fb5SSoby Mathew } 3571af540efSRoberto Vargas #endif 358e35a3fb5SSoby Mathew 359e35a3fb5SSoby Mathew /******************************************************************************* 360e35a3fb5SSoby Mathew * Handler to filter PSCI requests. 361e35a3fb5SSoby Mathew ******************************************************************************/ 362e35a3fb5SSoby Mathew /* 363e35a3fb5SSoby Mathew * The system power domain suspend is only supported only via 364e35a3fb5SSoby Mathew * PSCI SYSTEM_SUSPEND API. PSCI CPU_SUSPEND request to system power domain 365e35a3fb5SSoby Mathew * will be downgraded to the lower level. 366e35a3fb5SSoby Mathew */ 367e35a3fb5SSoby Mathew static int fvp_validate_power_state(unsigned int power_state, 368e35a3fb5SSoby Mathew psci_power_state_t *req_state) 369e35a3fb5SSoby Mathew { 370e35a3fb5SSoby Mathew int rc; 371e35a3fb5SSoby Mathew rc = arm_validate_power_state(power_state, req_state); 372e35a3fb5SSoby Mathew 373e35a3fb5SSoby Mathew /* 374e35a3fb5SSoby Mathew * Ensure that the system power domain level is never suspended 375e35a3fb5SSoby Mathew * via PSCI CPU SUSPEND API. Currently system suspend is only 376e35a3fb5SSoby Mathew * supported via PSCI SYSTEM SUSPEND API. 377e35a3fb5SSoby Mathew */ 378e35a3fb5SSoby Mathew req_state->pwr_domain_state[ARM_PWR_LVL2] = ARM_LOCAL_STATE_RUN; 379e35a3fb5SSoby Mathew return rc; 380e35a3fb5SSoby Mathew } 381e35a3fb5SSoby Mathew 382e35a3fb5SSoby Mathew /* 383e35a3fb5SSoby Mathew * Custom `translate_power_state_by_mpidr` handler for FVP. Unlike in the 384e35a3fb5SSoby Mathew * `fvp_validate_power_state`, we do not downgrade the system power 385e35a3fb5SSoby Mathew * domain level request in `power_state` as it will be used to query the 386e35a3fb5SSoby Mathew * PSCI_STAT_COUNT/RESIDENCY at the system power domain level. 387e35a3fb5SSoby Mathew */ 388e35a3fb5SSoby Mathew static int fvp_translate_power_state_by_mpidr(u_register_t mpidr, 389e35a3fb5SSoby Mathew unsigned int power_state, 390e35a3fb5SSoby Mathew psci_power_state_t *output_state) 391e35a3fb5SSoby Mathew { 392e35a3fb5SSoby Mathew return arm_validate_power_state(power_state, output_state); 393e35a3fb5SSoby Mathew } 394e35a3fb5SSoby Mathew 3953fc4124cSDan Handley /******************************************************************************* 396785fb92bSSoby Mathew * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard 397785fb92bSSoby Mathew * platform layer will take care of registering the handlers with PSCI. 3983fc4124cSDan Handley ******************************************************************************/ 3995486a965SSoby Mathew plat_psci_ops_t plat_arm_psci_pm_ops = { 40038dce70fSSoby Mathew .cpu_standby = fvp_cpu_standby, 40138dce70fSSoby Mathew .pwr_domain_on = fvp_pwr_domain_on, 40238dce70fSSoby Mathew .pwr_domain_off = fvp_pwr_domain_off, 40338dce70fSSoby Mathew .pwr_domain_suspend = fvp_pwr_domain_suspend, 40438dce70fSSoby Mathew .pwr_domain_on_finish = fvp_pwr_domain_on_finish, 4056806cd23SMadhukar Pappireddy .pwr_domain_on_finish_late = fvp_pwr_domain_on_finish_late, 40638dce70fSSoby Mathew .pwr_domain_suspend_finish = fvp_pwr_domain_suspend_finish, 4073fc4124cSDan Handley .system_off = fvp_system_off, 4083fc4124cSDan Handley .system_reset = fvp_system_reset, 409e35a3fb5SSoby Mathew .validate_power_state = fvp_validate_power_state, 41071e7a4e5SJeenu Viswambharan .validate_ns_entrypoint = arm_validate_psci_entrypoint, 411e35a3fb5SSoby Mathew .translate_power_state_by_mpidr = fvp_translate_power_state_by_mpidr, 412f145403cSRoberto Vargas .get_node_hw_state = fvp_node_hw_state, 4137d44ac1eSAntonio Nino Diaz #if !ARM_BL31_IN_DRAM 4147d44ac1eSAntonio Nino Diaz /* 4157d44ac1eSAntonio Nino Diaz * The TrustZone Controller is set up during the warmboot sequence after 4167d44ac1eSAntonio Nino Diaz * resuming the CPU from a SYSTEM_SUSPEND. If BL31 is located in SRAM 4177d44ac1eSAntonio Nino Diaz * this is not a problem but, if it is in TZC-secured DRAM, it tries to 4187d44ac1eSAntonio Nino Diaz * reconfigure the same memory it is running on, causing an exception. 4197d44ac1eSAntonio Nino Diaz */ 420e35a3fb5SSoby Mathew .get_sys_suspend_power_state = fvp_get_sys_suspend_power_state, 4217d44ac1eSAntonio Nino Diaz #endif 422f145403cSRoberto Vargas .mem_protect_chk = arm_psci_mem_protect_chk, 423f145403cSRoberto Vargas .read_mem_protect = arm_psci_read_mem_protect, 424f145403cSRoberto Vargas .write_mem_protect = arm_nor_psci_write_mem_protect, 4253fc4124cSDan Handley }; 42689f2e589SChandni Cherukuri 42789f2e589SChandni Cherukuri const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops) 42889f2e589SChandni Cherukuri { 42989f2e589SChandni Cherukuri return ops; 43089f2e589SChandni Cherukuri } 431