xref: /rk3399_ARM-atf/plat/arm/board/fvp/fvp_pm.c (revision 281a08cc6438d868bd1b0bcf19bc6c95207b42ac)
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