13fc4124cSDan Handley /* 2f145403cSRoberto Vargas * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. 33fc4124cSDan Handley * 482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 53fc4124cSDan Handley */ 63fc4124cSDan Handley 73fc4124cSDan Handley #include <arch_helpers.h> 83fc4124cSDan Handley #include <arm_config.h> 93fc4124cSDan Handley #include <assert.h> 103fc4124cSDan Handley #include <debug.h> 113fc4124cSDan Handley #include <errno.h> 12e35a3fb5SSoby Mathew #include <gicv3.h> 133fc4124cSDan Handley #include <mmio.h> 143fc4124cSDan Handley #include <plat_arm.h> 154adb10c1SIsla Mitchell #include <platform.h> 163fc4124cSDan Handley #include <psci.h> 17*281a08ccSDimitris Papastamos #include <spe.h> 183fc4124cSDan Handley #include <v2m_def.h> 193fc4124cSDan Handley #include "drivers/pwrc/fvp_pwrc.h" 203fc4124cSDan Handley #include "fvp_def.h" 213fc4124cSDan Handley #include "fvp_private.h" 223fc4124cSDan Handley 233fc4124cSDan Handley 242204afdeSSoby Mathew #if ARM_RECOM_STATE_ID_ENC 252204afdeSSoby Mathew /* 262204afdeSSoby Mathew * The table storing the valid idle power states. Ensure that the 272204afdeSSoby Mathew * array entries are populated in ascending order of state-id to 282204afdeSSoby Mathew * enable us to use binary search during power state validation. 292204afdeSSoby Mathew * The table must be terminated by a NULL entry. 302204afdeSSoby Mathew */ 312204afdeSSoby Mathew const unsigned int arm_pm_idle_states[] = { 322204afdeSSoby Mathew /* State-id - 0x01 */ 332204afdeSSoby Mathew arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RET, 342204afdeSSoby Mathew ARM_PWR_LVL0, PSTATE_TYPE_STANDBY), 352204afdeSSoby Mathew /* State-id - 0x02 */ 362204afdeSSoby Mathew arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_OFF, 372204afdeSSoby Mathew ARM_PWR_LVL0, PSTATE_TYPE_POWERDOWN), 382204afdeSSoby Mathew /* State-id - 0x22 */ 392204afdeSSoby Mathew arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF, 402204afdeSSoby Mathew ARM_PWR_LVL1, PSTATE_TYPE_POWERDOWN), 41e35a3fb5SSoby Mathew /* State-id - 0x222 */ 42e35a3fb5SSoby Mathew arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF, 43e35a3fb5SSoby Mathew ARM_LOCAL_STATE_OFF, ARM_PWR_LVL2, PSTATE_TYPE_POWERDOWN), 442204afdeSSoby Mathew 0, 452204afdeSSoby Mathew }; 462204afdeSSoby Mathew #endif 472204afdeSSoby Mathew 483fc4124cSDan Handley /******************************************************************************* 493fc4124cSDan Handley * Function which implements the common FVP specific operations to power down a 503fc4124cSDan Handley * cluster in response to a CPU_OFF or CPU_SUSPEND request. 513fc4124cSDan Handley ******************************************************************************/ 523fc4124cSDan Handley static void fvp_cluster_pwrdwn_common(void) 533fc4124cSDan Handley { 543fc4124cSDan Handley uint64_t mpidr = read_mpidr_el1(); 553fc4124cSDan Handley 56d832aee9Sdp-arm #if ENABLE_SPE_FOR_LOWER_ELS 57d832aee9Sdp-arm /* 58d832aee9Sdp-arm * On power down we need to disable statistical profiling extensions 59d832aee9Sdp-arm * before exiting coherency. 60d832aee9Sdp-arm */ 61*281a08ccSDimitris Papastamos spe_disable(); 62d832aee9Sdp-arm #endif 63d832aee9Sdp-arm 643fc4124cSDan Handley /* Disable coherency if this cluster is to be turned off */ 656355f234SVikram Kanigiri fvp_interconnect_disable(); 663fc4124cSDan Handley 673fc4124cSDan Handley /* Program the power controller to turn the cluster off */ 683fc4124cSDan Handley fvp_pwrc_write_pcoffr(mpidr); 693fc4124cSDan Handley } 703fc4124cSDan Handley 71e35a3fb5SSoby Mathew /* 72e35a3fb5SSoby Mathew * Empty implementation of these hooks avoid setting the GICR_WAKER.Sleep bit 73e35a3fb5SSoby Mathew * on ARM GICv3 implementations on FVP. This is required, because FVP does not 74e35a3fb5SSoby Mathew * support SYSTEM_SUSPEND and it is `faked` in firmware. Hence, for wake up 75e35a3fb5SSoby Mathew * from `fake` system suspend the GIC must not be powered off. 76e35a3fb5SSoby Mathew */ 77e35a3fb5SSoby Mathew void arm_gicv3_distif_pre_save(unsigned int proc_num) 78e35a3fb5SSoby Mathew {} 79e35a3fb5SSoby Mathew 80e35a3fb5SSoby Mathew void arm_gicv3_distif_post_restore(unsigned int proc_num) 81e35a3fb5SSoby Mathew {} 82e35a3fb5SSoby Mathew 83f14d1886SSoby Mathew static void fvp_power_domain_on_finish_common(const psci_power_state_t *target_state) 84f14d1886SSoby Mathew { 85f14d1886SSoby Mathew unsigned long mpidr; 86f14d1886SSoby Mathew 87f14d1886SSoby Mathew assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == 88f14d1886SSoby Mathew ARM_LOCAL_STATE_OFF); 89f14d1886SSoby Mathew 90f14d1886SSoby Mathew /* Get the mpidr for this cpu */ 91f14d1886SSoby Mathew mpidr = read_mpidr_el1(); 92f14d1886SSoby Mathew 93f14d1886SSoby Mathew /* Perform the common cluster specific operations */ 94f14d1886SSoby Mathew if (target_state->pwr_domain_state[ARM_PWR_LVL1] == 95f14d1886SSoby Mathew ARM_LOCAL_STATE_OFF) { 96f14d1886SSoby Mathew /* 97f14d1886SSoby Mathew * This CPU might have woken up whilst the cluster was 98f14d1886SSoby Mathew * attempting to power down. In this case the FVP power 99f14d1886SSoby Mathew * controller will have a pending cluster power off request 100f14d1886SSoby Mathew * which needs to be cleared by writing to the PPONR register. 101f14d1886SSoby Mathew * This prevents the power controller from interpreting a 102f14d1886SSoby Mathew * subsequent entry of this cpu into a simple wfi as a power 103f14d1886SSoby Mathew * down request. 104f14d1886SSoby Mathew */ 105f14d1886SSoby Mathew fvp_pwrc_write_pponr(mpidr); 106f14d1886SSoby Mathew 107f14d1886SSoby Mathew /* Enable coherency if this cluster was off */ 1086355f234SVikram Kanigiri fvp_interconnect_enable(); 109f14d1886SSoby Mathew } 110e35a3fb5SSoby Mathew /* Perform the common system specific operations */ 111e35a3fb5SSoby Mathew if (target_state->pwr_domain_state[ARM_PWR_LVL2] == 112e35a3fb5SSoby Mathew ARM_LOCAL_STATE_OFF) 113e35a3fb5SSoby Mathew arm_system_pwr_domain_resume(); 114f14d1886SSoby Mathew 115f14d1886SSoby Mathew /* 116f14d1886SSoby Mathew * Clear PWKUPR.WEN bit to ensure interrupts do not interfere 117f14d1886SSoby Mathew * with a cpu power down unless the bit is set again 118f14d1886SSoby Mathew */ 119f14d1886SSoby Mathew fvp_pwrc_clr_wen(mpidr); 120f14d1886SSoby Mathew } 121f14d1886SSoby Mathew 122f14d1886SSoby Mathew 1233fc4124cSDan Handley /******************************************************************************* 12438dce70fSSoby Mathew * FVP handler called when a CPU is about to enter standby. 1253fc4124cSDan Handley ******************************************************************************/ 12638dce70fSSoby Mathew void fvp_cpu_standby(plat_local_state_t cpu_state) 1273fc4124cSDan Handley { 12838dce70fSSoby Mathew 12938dce70fSSoby Mathew assert(cpu_state == ARM_LOCAL_STATE_RET); 13038dce70fSSoby Mathew 1313fc4124cSDan Handley /* 1323fc4124cSDan Handley * Enter standby state 1333fc4124cSDan Handley * dsb is good practice before using wfi to enter low power states 1343fc4124cSDan Handley */ 1353fc4124cSDan Handley dsb(); 1363fc4124cSDan Handley wfi(); 1373fc4124cSDan Handley } 1383fc4124cSDan Handley 1393fc4124cSDan Handley /******************************************************************************* 14038dce70fSSoby Mathew * FVP handler called when a power domain is about to be turned on. The 14138dce70fSSoby Mathew * mpidr determines the CPU to be turned on. 1423fc4124cSDan Handley ******************************************************************************/ 14338dce70fSSoby Mathew int fvp_pwr_domain_on(u_register_t mpidr) 1443fc4124cSDan Handley { 1453fc4124cSDan Handley int rc = PSCI_E_SUCCESS; 1463fc4124cSDan Handley unsigned int psysr; 1473fc4124cSDan Handley 1483fc4124cSDan Handley /* 1490f09c8f7SSandrine Bailleux * Ensure that we do not cancel an inflight power off request for the 1500f09c8f7SSandrine Bailleux * target cpu. That would leave it in a zombie wfi. Wait for it to power 1510f09c8f7SSandrine Bailleux * off and then program the power controller to turn that CPU on. 1523fc4124cSDan Handley */ 1533fc4124cSDan Handley do { 1543fc4124cSDan Handley psysr = fvp_pwrc_read_psysr(mpidr); 1553fc4124cSDan Handley } while (psysr & PSYSR_AFF_L0); 1563fc4124cSDan Handley 1573fc4124cSDan Handley fvp_pwrc_write_pponr(mpidr); 1583fc4124cSDan Handley return rc; 1593fc4124cSDan Handley } 1603fc4124cSDan Handley 1613fc4124cSDan Handley /******************************************************************************* 16238dce70fSSoby Mathew * FVP handler called when a power domain is about to be turned off. The 16338dce70fSSoby Mathew * target_state encodes the power state that each level should transition to. 1643fc4124cSDan Handley ******************************************************************************/ 16538dce70fSSoby Mathew void fvp_pwr_domain_off(const psci_power_state_t *target_state) 1663fc4124cSDan Handley { 16738dce70fSSoby Mathew assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == 16838dce70fSSoby Mathew ARM_LOCAL_STATE_OFF); 1693fc4124cSDan Handley 1703fc4124cSDan Handley /* 17138dce70fSSoby Mathew * If execution reaches this stage then this power domain will be 17238dce70fSSoby Mathew * suspended. Perform at least the cpu specific actions followed 17338dce70fSSoby Mathew * by the cluster specific operations if applicable. 1743fc4124cSDan Handley */ 17574a9578cSJeenu Viswambharan 17674a9578cSJeenu Viswambharan /* Prevent interrupts from spuriously waking up this cpu */ 17774a9578cSJeenu Viswambharan plat_arm_gic_cpuif_disable(); 17874a9578cSJeenu Viswambharan 17974a9578cSJeenu Viswambharan /* Turn redistributor off */ 18074a9578cSJeenu Viswambharan plat_arm_gic_redistif_off(); 18174a9578cSJeenu Viswambharan 18274a9578cSJeenu Viswambharan /* Program the power controller to power off this cpu. */ 18374a9578cSJeenu Viswambharan fvp_pwrc_write_ppoffr(read_mpidr_el1()); 1843fc4124cSDan Handley 18538dce70fSSoby Mathew if (target_state->pwr_domain_state[ARM_PWR_LVL1] == 18638dce70fSSoby Mathew ARM_LOCAL_STATE_OFF) 1873fc4124cSDan Handley fvp_cluster_pwrdwn_common(); 1883fc4124cSDan Handley 1893fc4124cSDan Handley } 1903fc4124cSDan Handley 1913fc4124cSDan Handley /******************************************************************************* 19238dce70fSSoby Mathew * FVP handler called when a power domain is about to be suspended. The 19338dce70fSSoby Mathew * target_state encodes the power state that each level should transition to. 1943fc4124cSDan Handley ******************************************************************************/ 19538dce70fSSoby Mathew void fvp_pwr_domain_suspend(const psci_power_state_t *target_state) 1963fc4124cSDan Handley { 1973fc4124cSDan Handley unsigned long mpidr; 1983fc4124cSDan Handley 19938dce70fSSoby Mathew /* 20038dce70fSSoby Mathew * FVP has retention only at cpu level. Just return 20138dce70fSSoby Mathew * as nothing is to be done for retention. 20238dce70fSSoby Mathew */ 20338dce70fSSoby Mathew if (target_state->pwr_domain_state[ARM_PWR_LVL0] == 20438dce70fSSoby Mathew ARM_LOCAL_STATE_RET) 2053fc4124cSDan Handley return; 2063fc4124cSDan Handley 20738dce70fSSoby Mathew assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == 20838dce70fSSoby Mathew ARM_LOCAL_STATE_OFF); 20938dce70fSSoby Mathew 2103fc4124cSDan Handley /* Get the mpidr for this cpu */ 2113fc4124cSDan Handley mpidr = read_mpidr_el1(); 2123fc4124cSDan Handley 2133fc4124cSDan Handley /* Program the power controller to enable wakeup interrupts. */ 2143fc4124cSDan Handley fvp_pwrc_set_wen(mpidr); 2153fc4124cSDan Handley 21674a9578cSJeenu Viswambharan /* Prevent interrupts from spuriously waking up this cpu */ 21774a9578cSJeenu Viswambharan plat_arm_gic_cpuif_disable(); 21874a9578cSJeenu Viswambharan 21974a9578cSJeenu Viswambharan /* 22074a9578cSJeenu Viswambharan * The Redistributor is not powered off as it can potentially prevent 22174a9578cSJeenu Viswambharan * wake up events reaching the CPUIF and/or might lead to losing 22274a9578cSJeenu Viswambharan * register context. 22374a9578cSJeenu Viswambharan */ 22474a9578cSJeenu Viswambharan 2253fc4124cSDan Handley /* Perform the common cluster specific operations */ 22638dce70fSSoby Mathew if (target_state->pwr_domain_state[ARM_PWR_LVL1] == 22738dce70fSSoby Mathew ARM_LOCAL_STATE_OFF) 2283fc4124cSDan Handley fvp_cluster_pwrdwn_common(); 229e35a3fb5SSoby Mathew 230e35a3fb5SSoby Mathew /* Perform the common system specific operations */ 231e35a3fb5SSoby Mathew if (target_state->pwr_domain_state[ARM_PWR_LVL2] == 232e35a3fb5SSoby Mathew ARM_LOCAL_STATE_OFF) 233e35a3fb5SSoby Mathew arm_system_pwr_domain_save(); 234e35a3fb5SSoby Mathew 235e35a3fb5SSoby Mathew /* Program the power controller to power off this cpu. */ 236e35a3fb5SSoby Mathew fvp_pwrc_write_ppoffr(read_mpidr_el1()); 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 ******************************************************************************/ 24438dce70fSSoby Mathew 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); 2473fc4124cSDan Handley 2483fc4124cSDan Handley /* Enable the gic cpu interface */ 24927573c59SAchin Gupta plat_arm_gic_pcpu_init(); 25027573c59SAchin Gupta 25127573c59SAchin Gupta /* Program the gic per-cpu distributor or re-distributor interface */ 25227573c59SAchin Gupta plat_arm_gic_cpuif_enable(); 2533fc4124cSDan Handley } 2543fc4124cSDan Handley 2553fc4124cSDan Handley /******************************************************************************* 25638dce70fSSoby Mathew * FVP handler called when a power domain has just been powered on after 25738dce70fSSoby Mathew * having been suspended earlier. The target_state encodes the low power state 25838dce70fSSoby Mathew * that each level has woken up from. 2593fc4124cSDan Handley * TODO: At the moment we reuse the on finisher and reinitialize the secure 2603fc4124cSDan Handley * context. Need to implement a separate suspend finisher. 2613fc4124cSDan Handley ******************************************************************************/ 26238dce70fSSoby Mathew void fvp_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 2633fc4124cSDan Handley { 26438dce70fSSoby Mathew /* 26538dce70fSSoby Mathew * Nothing to be done on waking up from retention from CPU level. 26638dce70fSSoby Mathew */ 26738dce70fSSoby Mathew if (target_state->pwr_domain_state[ARM_PWR_LVL0] == 26838dce70fSSoby Mathew ARM_LOCAL_STATE_RET) 26938dce70fSSoby Mathew return; 27038dce70fSSoby Mathew 271f14d1886SSoby Mathew fvp_power_domain_on_finish_common(target_state); 272f14d1886SSoby Mathew 273f14d1886SSoby Mathew /* Enable the gic cpu interface */ 27427573c59SAchin Gupta plat_arm_gic_cpuif_enable(); 2753fc4124cSDan Handley } 2763fc4124cSDan Handley 2773fc4124cSDan Handley /******************************************************************************* 2783fc4124cSDan Handley * FVP handlers to shutdown/reboot the system 2793fc4124cSDan Handley ******************************************************************************/ 2803fc4124cSDan Handley static void __dead2 fvp_system_off(void) 2813fc4124cSDan Handley { 2823fc4124cSDan Handley /* Write the System Configuration Control Register */ 2833fc4124cSDan Handley mmio_write_32(V2M_SYSREGS_BASE + V2M_SYS_CFGCTRL, 2843fc4124cSDan Handley V2M_CFGCTRL_START | 2853fc4124cSDan Handley V2M_CFGCTRL_RW | 2863fc4124cSDan Handley V2M_CFGCTRL_FUNC(V2M_FUNC_SHUTDOWN)); 2873fc4124cSDan Handley wfi(); 2883fc4124cSDan Handley ERROR("FVP System Off: operation not handled.\n"); 2893fc4124cSDan Handley panic(); 2903fc4124cSDan Handley } 2913fc4124cSDan Handley 2923fc4124cSDan Handley static void __dead2 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 wfi(); 3003fc4124cSDan Handley ERROR("FVP System Reset: operation not handled.\n"); 3013fc4124cSDan Handley panic(); 3023fc4124cSDan Handley } 3033fc4124cSDan Handley 3041298ae02SJeenu Viswambharan static int fvp_node_hw_state(u_register_t target_cpu, 3051298ae02SJeenu Viswambharan unsigned int power_level) 3061298ae02SJeenu Viswambharan { 3071298ae02SJeenu Viswambharan unsigned int psysr; 3081298ae02SJeenu Viswambharan int ret; 3091298ae02SJeenu Viswambharan 3101298ae02SJeenu Viswambharan /* 3111298ae02SJeenu Viswambharan * The format of 'power_level' is implementation-defined, but 0 must 3121298ae02SJeenu Viswambharan * mean a CPU. We also allow 1 to denote the cluster 3131298ae02SJeenu Viswambharan */ 3141298ae02SJeenu Viswambharan if (power_level != ARM_PWR_LVL0 && power_level != ARM_PWR_LVL1) 3151298ae02SJeenu Viswambharan return PSCI_E_INVALID_PARAMS; 3161298ae02SJeenu Viswambharan 3171298ae02SJeenu Viswambharan /* 3181298ae02SJeenu Viswambharan * Read the status of the given MPDIR from FVP power controller. The 3191298ae02SJeenu Viswambharan * power controller only gives us on/off status, so map that to expected 3201298ae02SJeenu Viswambharan * return values of the PSCI call 3211298ae02SJeenu Viswambharan */ 3221298ae02SJeenu Viswambharan psysr = fvp_pwrc_read_psysr(target_cpu); 3231298ae02SJeenu Viswambharan if (psysr == PSYSR_INVALID) 3241298ae02SJeenu Viswambharan return PSCI_E_INVALID_PARAMS; 3251298ae02SJeenu Viswambharan 3261298ae02SJeenu Viswambharan switch (power_level) { 3271298ae02SJeenu Viswambharan case ARM_PWR_LVL0: 3281298ae02SJeenu Viswambharan ret = (psysr & PSYSR_AFF_L0) ? HW_ON : HW_OFF; 3291298ae02SJeenu Viswambharan break; 3301298ae02SJeenu Viswambharan case ARM_PWR_LVL1: 3311298ae02SJeenu Viswambharan ret = (psysr & PSYSR_AFF_L1) ? HW_ON : HW_OFF; 3321298ae02SJeenu Viswambharan break; 3331298ae02SJeenu Viswambharan } 3341298ae02SJeenu Viswambharan 3351298ae02SJeenu Viswambharan return ret; 3361298ae02SJeenu Viswambharan } 3371298ae02SJeenu Viswambharan 338e35a3fb5SSoby Mathew /* 339e35a3fb5SSoby Mathew * The FVP doesn't truly support power management at SYSTEM power domain. The 340e35a3fb5SSoby Mathew * SYSTEM_SUSPEND will be down-graded to the cluster level within the platform 341e35a3fb5SSoby Mathew * layer. The `fake` SYSTEM_SUSPEND allows us to validate some of the driver 342e35a3fb5SSoby Mathew * save and restore sequences on FVP. 343e35a3fb5SSoby Mathew */ 344e35a3fb5SSoby Mathew void fvp_get_sys_suspend_power_state(psci_power_state_t *req_state) 345e35a3fb5SSoby Mathew { 346e35a3fb5SSoby Mathew unsigned int i; 347e35a3fb5SSoby Mathew 348e35a3fb5SSoby Mathew for (i = ARM_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) 349e35a3fb5SSoby Mathew req_state->pwr_domain_state[i] = ARM_LOCAL_STATE_OFF; 350e35a3fb5SSoby Mathew } 351e35a3fb5SSoby Mathew 352e35a3fb5SSoby Mathew /******************************************************************************* 353e35a3fb5SSoby Mathew * Handler to filter PSCI requests. 354e35a3fb5SSoby Mathew ******************************************************************************/ 355e35a3fb5SSoby Mathew /* 356e35a3fb5SSoby Mathew * The system power domain suspend is only supported only via 357e35a3fb5SSoby Mathew * PSCI SYSTEM_SUSPEND API. PSCI CPU_SUSPEND request to system power domain 358e35a3fb5SSoby Mathew * will be downgraded to the lower level. 359e35a3fb5SSoby Mathew */ 360e35a3fb5SSoby Mathew static int fvp_validate_power_state(unsigned int power_state, 361e35a3fb5SSoby Mathew psci_power_state_t *req_state) 362e35a3fb5SSoby Mathew { 363e35a3fb5SSoby Mathew int rc; 364e35a3fb5SSoby Mathew rc = arm_validate_power_state(power_state, req_state); 365e35a3fb5SSoby Mathew 366e35a3fb5SSoby Mathew /* 367e35a3fb5SSoby Mathew * Ensure that the system power domain level is never suspended 368e35a3fb5SSoby Mathew * via PSCI CPU SUSPEND API. Currently system suspend is only 369e35a3fb5SSoby Mathew * supported via PSCI SYSTEM SUSPEND API. 370e35a3fb5SSoby Mathew */ 371e35a3fb5SSoby Mathew req_state->pwr_domain_state[ARM_PWR_LVL2] = ARM_LOCAL_STATE_RUN; 372e35a3fb5SSoby Mathew return rc; 373e35a3fb5SSoby Mathew } 374e35a3fb5SSoby Mathew 375e35a3fb5SSoby Mathew /* 376e35a3fb5SSoby Mathew * Custom `translate_power_state_by_mpidr` handler for FVP. Unlike in the 377e35a3fb5SSoby Mathew * `fvp_validate_power_state`, we do not downgrade the system power 378e35a3fb5SSoby Mathew * domain level request in `power_state` as it will be used to query the 379e35a3fb5SSoby Mathew * PSCI_STAT_COUNT/RESIDENCY at the system power domain level. 380e35a3fb5SSoby Mathew */ 381e35a3fb5SSoby Mathew static int fvp_translate_power_state_by_mpidr(u_register_t mpidr, 382e35a3fb5SSoby Mathew unsigned int power_state, 383e35a3fb5SSoby Mathew psci_power_state_t *output_state) 384e35a3fb5SSoby Mathew { 385e35a3fb5SSoby Mathew return arm_validate_power_state(power_state, output_state); 386e35a3fb5SSoby Mathew } 387e35a3fb5SSoby Mathew 3883fc4124cSDan Handley /******************************************************************************* 389785fb92bSSoby Mathew * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard 390785fb92bSSoby Mathew * platform layer will take care of registering the handlers with PSCI. 3913fc4124cSDan Handley ******************************************************************************/ 3925486a965SSoby Mathew plat_psci_ops_t plat_arm_psci_pm_ops = { 39338dce70fSSoby Mathew .cpu_standby = fvp_cpu_standby, 39438dce70fSSoby Mathew .pwr_domain_on = fvp_pwr_domain_on, 39538dce70fSSoby Mathew .pwr_domain_off = fvp_pwr_domain_off, 39638dce70fSSoby Mathew .pwr_domain_suspend = fvp_pwr_domain_suspend, 39738dce70fSSoby Mathew .pwr_domain_on_finish = fvp_pwr_domain_on_finish, 39838dce70fSSoby Mathew .pwr_domain_suspend_finish = fvp_pwr_domain_suspend_finish, 3993fc4124cSDan Handley .system_off = fvp_system_off, 4003fc4124cSDan Handley .system_reset = fvp_system_reset, 401e35a3fb5SSoby Mathew .validate_power_state = fvp_validate_power_state, 40271e7a4e5SJeenu Viswambharan .validate_ns_entrypoint = arm_validate_psci_entrypoint, 403e35a3fb5SSoby Mathew .translate_power_state_by_mpidr = fvp_translate_power_state_by_mpidr, 404f145403cSRoberto Vargas .get_node_hw_state = fvp_node_hw_state, 405e35a3fb5SSoby Mathew .get_sys_suspend_power_state = fvp_get_sys_suspend_power_state, 406f145403cSRoberto Vargas /* 407f145403cSRoberto Vargas * mem_protect is not supported in RESET_TO_BL31 and RESET_TO_SP_MIN, 408f145403cSRoberto Vargas * as that would require mapping in all of NS DRAM into BL31 or BL32. 409f145403cSRoberto Vargas */ 410f145403cSRoberto Vargas #if !RESET_TO_BL31 && !RESET_TO_SP_MIN 411f145403cSRoberto Vargas .mem_protect_chk = arm_psci_mem_protect_chk, 412f145403cSRoberto Vargas .read_mem_protect = arm_psci_read_mem_protect, 413f145403cSRoberto Vargas .write_mem_protect = arm_nor_psci_write_mem_protect, 414f145403cSRoberto Vargas #endif 4153fc4124cSDan Handley }; 416