blob: 51dda9ec05210b2f50fcc61b25f29f7305b3a098 [file] [log] [blame]
Achin Gupta4f6ad662013-10-25 09:08:21 +01001/*
Alexei Fedorovd27febf2021-09-01 15:41:14 +01002 * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
Achin Gupta4f6ad662013-10-25 09:08:21 +01003 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Achin Gupta4f6ad662013-10-25 09:08:21 +01005 */
6
Dan Handley2bd4ef22014-04-09 13:14:54 +01007#include <assert.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00008
Andre Przywaraf3e8cfc2022-11-17 16:42:09 +00009#include <arch_features.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000010#include <arch_helpers.h>
11#include <common/debug.h>
12#include <drivers/arm/gicv3.h>
Antonio Nino Diazf13d09a2019-01-23 21:50:09 +000013#include <drivers/arm/fvp/fvp_pwrc.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000014#include <lib/extensions/spe.h>
15#include <lib/mmio.h>
16#include <lib/psci/psci.h>
Antonio Nino Diazbd7b7402019-01-25 14:30:04 +000017#include <plat/arm/common/arm_config.h>
18#include <plat/arm/common/plat_arm.h>
Antonio Nino Diaza320ecd2019-01-15 14:19:50 +000019#include <platform_def.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000020
Dan Handleyed6ff952014-05-14 17:44:19 +010021#include "fvp_private.h"
Ambroise Vincentb237bca2019-02-13 15:58:00 +000022#include "../drivers/arm/gic/v3/gicv3_private.h"
Achin Gupta4f6ad662013-10-25 09:08:21 +010023
Dan Handley2b6b5742015-03-19 19:17:53 +000024
Soby Mathew7799cf72015-04-16 14:49:09 +010025#if ARM_RECOM_STATE_ID_ENC
26/*
27 * The table storing the valid idle power states. Ensure that the
28 * array entries are populated in ascending order of state-id to
29 * enable us to use binary search during power state validation.
30 * The table must be terminated by a NULL entry.
31 */
32const unsigned int arm_pm_idle_states[] = {
33 /* State-id - 0x01 */
34 arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RET,
35 ARM_PWR_LVL0, PSTATE_TYPE_STANDBY),
36 /* State-id - 0x02 */
37 arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_OFF,
38 ARM_PWR_LVL0, PSTATE_TYPE_POWERDOWN),
39 /* State-id - 0x22 */
40 arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF,
41 ARM_PWR_LVL1, PSTATE_TYPE_POWERDOWN),
Soby Mathew9ca28062017-10-11 16:08:58 +010042 /* State-id - 0x222 */
43 arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF,
44 ARM_LOCAL_STATE_OFF, ARM_PWR_LVL2, PSTATE_TYPE_POWERDOWN),
Soby Mathew7799cf72015-04-16 14:49:09 +010045 0,
46};
47#endif
48
Achin Gupta4f6ad662013-10-25 09:08:21 +010049/*******************************************************************************
Achin Gupta85876392014-07-31 17:45:51 +010050 * Function which implements the common FVP specific operations to power down a
Achin Gupta85876392014-07-31 17:45:51 +010051 * cluster in response to a CPU_OFF or CPU_SUSPEND request.
52 ******************************************************************************/
Sandrine Bailleuxa64a8542015-03-05 10:54:34 +000053static void fvp_cluster_pwrdwn_common(void)
Achin Gupta85876392014-07-31 17:45:51 +010054{
55 uint64_t mpidr = read_mpidr_el1();
56
dp-armee3457b2017-05-23 09:32:49 +010057 /*
58 * On power down we need to disable statistical profiling extensions
59 * before exiting coherency.
60 */
Andre Przywaraf3e8cfc2022-11-17 16:42:09 +000061 if (is_feat_spe_supported()) {
62 spe_disable();
63 }
dp-armee3457b2017-05-23 09:32:49 +010064
Achin Gupta85876392014-07-31 17:45:51 +010065 /* Disable coherency if this cluster is to be turned off */
Vikram Kanigirifbb13012016-02-15 11:54:14 +000066 fvp_interconnect_disable();
Achin Gupta85876392014-07-31 17:45:51 +010067
68 /* Program the power controller to turn the cluster off */
69 fvp_pwrc_write_pcoffr(mpidr);
70}
71
Soby Mathew9ca28062017-10-11 16:08:58 +010072/*
73 * Empty implementation of these hooks avoid setting the GICR_WAKER.Sleep bit
74 * on ARM GICv3 implementations on FVP. This is required, because FVP does not
75 * support SYSTEM_SUSPEND and it is `faked` in firmware. Hence, for wake up
76 * from `fake` system suspend the GIC must not be powered off.
77 */
Roberto Vargas1a6eed32018-02-12 12:36:17 +000078void arm_gicv3_distif_pre_save(unsigned int rdist_proc_num)
Soby Mathew9ca28062017-10-11 16:08:58 +010079{}
80
Roberto Vargas1a6eed32018-02-12 12:36:17 +000081void arm_gicv3_distif_post_restore(unsigned int rdist_proc_num)
Soby Mathew9ca28062017-10-11 16:08:58 +010082{}
83
Soby Mathew12012dd2015-10-26 14:01:53 +000084static void fvp_power_domain_on_finish_common(const psci_power_state_t *target_state)
85{
86 unsigned long mpidr;
87
88 assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
89 ARM_LOCAL_STATE_OFF);
90
91 /* Get the mpidr for this cpu */
92 mpidr = read_mpidr_el1();
93
94 /* Perform the common cluster specific operations */
95 if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
96 ARM_LOCAL_STATE_OFF) {
97 /*
98 * This CPU might have woken up whilst the cluster was
99 * attempting to power down. In this case the FVP power
100 * controller will have a pending cluster power off request
101 * which needs to be cleared by writing to the PPONR register.
102 * This prevents the power controller from interpreting a
103 * subsequent entry of this cpu into a simple wfi as a power
104 * down request.
105 */
106 fvp_pwrc_write_pponr(mpidr);
107
108 /* Enable coherency if this cluster was off */
Vikram Kanigirifbb13012016-02-15 11:54:14 +0000109 fvp_interconnect_enable();
Soby Mathew12012dd2015-10-26 14:01:53 +0000110 }
Soby Mathew9ca28062017-10-11 16:08:58 +0100111 /* Perform the common system specific operations */
112 if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
113 ARM_LOCAL_STATE_OFF)
114 arm_system_pwr_domain_resume();
Soby Mathew12012dd2015-10-26 14:01:53 +0000115
116 /*
117 * Clear PWKUPR.WEN bit to ensure interrupts do not interfere
118 * with a cpu power down unless the bit is set again
119 */
120 fvp_pwrc_clr_wen(mpidr);
121}
122
Achin Gupta85876392014-07-31 17:45:51 +0100123/*******************************************************************************
Soby Mathewfec4eb72015-07-01 16:16:20 +0100124 * FVP handler called when a CPU is about to enter standby.
Vikram Kanigiri3b7c59b2014-03-21 11:57:10 +0000125 ******************************************************************************/
Roberto Vargas2ca18d92018-02-12 12:36:17 +0000126static void fvp_cpu_standby(plat_local_state_t cpu_state)
Vikram Kanigiri3b7c59b2014-03-21 11:57:10 +0000127{
Alexei Fedorovd27febf2021-09-01 15:41:14 +0100128 u_register_t scr = read_scr_el3();
Soby Mathewfec4eb72015-07-01 16:16:20 +0100129
130 assert(cpu_state == ARM_LOCAL_STATE_RET);
131
Andrew Thoelke42e75a72014-04-28 12:28:39 +0100132 /*
Alexei Fedorovd27febf2021-09-01 15:41:14 +0100133 * Enable the Non-secure interrupt to wake the CPU.
134 * In GICv3 affinity routing mode, the Non-secure Group 1 interrupts
135 * use Physical FIQ at EL3 whereas in GICv2, Physical IRQ is used.
136 * Enabling both the bits works for both GICv2 mode and GICv3 affinity
137 * routing mode.
138 */
139 write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
140 isb();
141
142 /*
143 * Enter standby state.
144 * dsb is good practice before using wfi to enter low power states.
Andrew Thoelke42e75a72014-04-28 12:28:39 +0100145 */
146 dsb();
Vikram Kanigiri3b7c59b2014-03-21 11:57:10 +0000147 wfi();
Alexei Fedorovd27febf2021-09-01 15:41:14 +0100148
149 /*
150 * Restore SCR_EL3 to the original value, synchronisation of SCR_EL3
151 * is done by eret in el3_exit() to save some execution cycles.
152 */
153 write_scr_el3(scr);
Vikram Kanigiri3b7c59b2014-03-21 11:57:10 +0000154}
155
156/*******************************************************************************
Soby Mathewfec4eb72015-07-01 16:16:20 +0100157 * FVP handler called when a power domain is about to be turned on. The
158 * mpidr determines the CPU to be turned on.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100159 ******************************************************************************/
Roberto Vargas2ca18d92018-02-12 12:36:17 +0000160static int fvp_pwr_domain_on(u_register_t mpidr)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100161{
162 int rc = PSCI_E_SUCCESS;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100163 unsigned int psysr;
164
Achin Gupta4f6ad662013-10-25 09:08:21 +0100165 /*
Sandrine Bailleux7175bde2015-12-08 14:18:24 +0000166 * Ensure that we do not cancel an inflight power off request for the
167 * target cpu. That would leave it in a zombie wfi. Wait for it to power
168 * off and then program the power controller to turn that CPU on.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100169 */
170 do {
171 psysr = fvp_pwrc_read_psysr(mpidr);
Sathees Balya50905c72018-10-05 13:30:59 +0100172 } while ((psysr & PSYSR_AFF_L0) != 0U);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100173
Achin Gupta4f6ad662013-10-25 09:08:21 +0100174 fvp_pwrc_write_pponr(mpidr);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100175 return rc;
176}
177
178/*******************************************************************************
Soby Mathewfec4eb72015-07-01 16:16:20 +0100179 * FVP handler called when a power domain is about to be turned off. The
180 * target_state encodes the power state that each level should transition to.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100181 ******************************************************************************/
Roberto Vargas2ca18d92018-02-12 12:36:17 +0000182static void fvp_pwr_domain_off(const psci_power_state_t *target_state)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100183{
Soby Mathewfec4eb72015-07-01 16:16:20 +0100184 assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
185 ARM_LOCAL_STATE_OFF);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100186
Achin Gupta85876392014-07-31 17:45:51 +0100187 /*
Soby Mathewfec4eb72015-07-01 16:16:20 +0100188 * If execution reaches this stage then this power domain will be
189 * suspended. Perform at least the cpu specific actions followed
190 * by the cluster specific operations if applicable.
Achin Gupta85876392014-07-31 17:45:51 +0100191 */
Jeenu Viswambharan6ad35482016-12-09 11:14:34 +0000192
193 /* Prevent interrupts from spuriously waking up this cpu */
194 plat_arm_gic_cpuif_disable();
195
196 /* Turn redistributor off */
197 plat_arm_gic_redistif_off();
198
199 /* Program the power controller to power off this cpu. */
200 fvp_pwrc_write_ppoffr(read_mpidr_el1());
Achin Gupta4f6ad662013-10-25 09:08:21 +0100201
Soby Mathewfec4eb72015-07-01 16:16:20 +0100202 if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
203 ARM_LOCAL_STATE_OFF)
Achin Gupta85876392014-07-31 17:45:51 +0100204 fvp_cluster_pwrdwn_common();
Achin Gupta4f6ad662013-10-25 09:08:21 +0100205
Achin Gupta4f6ad662013-10-25 09:08:21 +0100206}
207
208/*******************************************************************************
Soby Mathewfec4eb72015-07-01 16:16:20 +0100209 * FVP handler called when a power domain is about to be suspended. The
210 * target_state encodes the power state that each level should transition to.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100211 ******************************************************************************/
Roberto Vargas2ca18d92018-02-12 12:36:17 +0000212static void fvp_pwr_domain_suspend(const psci_power_state_t *target_state)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100213{
Soby Mathewffb4ab12014-09-26 15:08:52 +0100214 unsigned long mpidr;
215
Soby Mathewfec4eb72015-07-01 16:16:20 +0100216 /*
217 * FVP has retention only at cpu level. Just return
218 * as nothing is to be done for retention.
219 */
220 if (target_state->pwr_domain_state[ARM_PWR_LVL0] ==
221 ARM_LOCAL_STATE_RET)
Soby Mathew74e52a72014-10-02 16:56:51 +0100222 return;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100223
Soby Mathewfec4eb72015-07-01 16:16:20 +0100224 assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
225 ARM_LOCAL_STATE_OFF);
226
Soby Mathewffb4ab12014-09-26 15:08:52 +0100227 /* Get the mpidr for this cpu */
228 mpidr = read_mpidr_el1();
229
Achin Gupta85876392014-07-31 17:45:51 +0100230 /* Program the power controller to enable wakeup interrupts. */
231 fvp_pwrc_set_wen(mpidr);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100232
Jeenu Viswambharan6ad35482016-12-09 11:14:34 +0000233 /* Prevent interrupts from spuriously waking up this cpu */
234 plat_arm_gic_cpuif_disable();
235
236 /*
237 * The Redistributor is not powered off as it can potentially prevent
238 * wake up events reaching the CPUIF and/or might lead to losing
239 * register context.
240 */
241
Achin Gupta85876392014-07-31 17:45:51 +0100242 /* Perform the common cluster specific operations */
Soby Mathewfec4eb72015-07-01 16:16:20 +0100243 if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
244 ARM_LOCAL_STATE_OFF)
Achin Gupta85876392014-07-31 17:45:51 +0100245 fvp_cluster_pwrdwn_common();
Soby Mathew9ca28062017-10-11 16:08:58 +0100246
247 /* Perform the common system specific operations */
248 if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
249 ARM_LOCAL_STATE_OFF)
250 arm_system_pwr_domain_save();
251
252 /* Program the power controller to power off this cpu. */
253 fvp_pwrc_write_ppoffr(read_mpidr_el1());
Wing Li05364b92023-01-26 18:33:43 -0800254
Wing Li05364b92023-01-26 18:33:43 -0800255 return;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100256}
257
258/*******************************************************************************
Soby Mathewfec4eb72015-07-01 16:16:20 +0100259 * FVP handler called when a power domain has just been powered on after
260 * being turned off earlier. The target_state encodes the low power state that
261 * each level has woken up from.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100262 ******************************************************************************/
Roberto Vargas2ca18d92018-02-12 12:36:17 +0000263static void fvp_pwr_domain_on_finish(const psci_power_state_t *target_state)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100264{
Soby Mathew12012dd2015-10-26 14:01:53 +0000265 fvp_power_domain_on_finish_common(target_state);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100266
Madhukar Pappireddy2859b7d2019-06-10 16:54:36 -0500267}
268
269/*******************************************************************************
270 * FVP handler called when a power domain has just been powered on and the cpu
271 * and its cluster are fully participating in coherent transaction on the
272 * interconnect. Data cache must be enabled for CPU at this point.
273 ******************************************************************************/
274static void fvp_pwr_domain_on_finish_late(const psci_power_state_t *target_state)
275{
276 /* Program GIC per-cpu distributor or re-distributor interface */
Achin Gupta1fa7eb62015-11-03 14:18:34 +0000277 plat_arm_gic_pcpu_init();
278
Madhukar Pappireddy2859b7d2019-06-10 16:54:36 -0500279 /* Enable GIC CPU interface */
Achin Gupta1fa7eb62015-11-03 14:18:34 +0000280 plat_arm_gic_cpuif_enable();
Achin Gupta4f6ad662013-10-25 09:08:21 +0100281}
282
283/*******************************************************************************
Soby Mathewfec4eb72015-07-01 16:16:20 +0100284 * FVP handler called when a power domain has just been powered on after
285 * having been suspended earlier. The target_state encodes the low power state
286 * that each level has woken up from.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100287 * TODO: At the moment we reuse the on finisher and reinitialize the secure
288 * context. Need to implement a separate suspend finisher.
289 ******************************************************************************/
Roberto Vargas2ca18d92018-02-12 12:36:17 +0000290static void fvp_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100291{
Soby Mathewfec4eb72015-07-01 16:16:20 +0100292 /*
293 * Nothing to be done on waking up from retention from CPU level.
294 */
295 if (target_state->pwr_domain_state[ARM_PWR_LVL0] ==
296 ARM_LOCAL_STATE_RET)
297 return;
298
Soby Mathew12012dd2015-10-26 14:01:53 +0000299 fvp_power_domain_on_finish_common(target_state);
300
Madhukar Pappireddy2859b7d2019-06-10 16:54:36 -0500301 /* Enable GIC CPU interface */
Achin Gupta1fa7eb62015-11-03 14:18:34 +0000302 plat_arm_gic_cpuif_enable();
Achin Gupta4f6ad662013-10-25 09:08:21 +0100303}
304
Juan Castillo4dc4a472014-08-12 11:17:06 +0100305/*******************************************************************************
306 * FVP handlers to shutdown/reboot the system
307 ******************************************************************************/
308static void __dead2 fvp_system_off(void)
309{
310 /* Write the System Configuration Control Register */
Dan Handley2b6b5742015-03-19 19:17:53 +0000311 mmio_write_32(V2M_SYSREGS_BASE + V2M_SYS_CFGCTRL,
312 V2M_CFGCTRL_START |
313 V2M_CFGCTRL_RW |
314 V2M_CFGCTRL_FUNC(V2M_FUNC_SHUTDOWN));
Juan Castillo4dc4a472014-08-12 11:17:06 +0100315 wfi();
316 ERROR("FVP System Off: operation not handled.\n");
317 panic();
318}
319
320static void __dead2 fvp_system_reset(void)
321{
322 /* Write the System Configuration Control Register */
Dan Handley2b6b5742015-03-19 19:17:53 +0000323 mmio_write_32(V2M_SYSREGS_BASE + V2M_SYS_CFGCTRL,
324 V2M_CFGCTRL_START |
325 V2M_CFGCTRL_RW |
326 V2M_CFGCTRL_FUNC(V2M_FUNC_REBOOT));
Juan Castillo4dc4a472014-08-12 11:17:06 +0100327 wfi();
328 ERROR("FVP System Reset: operation not handled.\n");
329 panic();
330}
Achin Gupta4f6ad662013-10-25 09:08:21 +0100331
Jeenu Viswambharan095529a2016-08-04 09:43:15 +0100332static int fvp_node_hw_state(u_register_t target_cpu,
333 unsigned int power_level)
334{
335 unsigned int psysr;
336 int ret;
337
338 /*
339 * The format of 'power_level' is implementation-defined, but 0 must
340 * mean a CPU. We also allow 1 to denote the cluster
341 */
Sathees Balya50905c72018-10-05 13:30:59 +0100342 if ((power_level != ARM_PWR_LVL0) && (power_level != ARM_PWR_LVL1))
Jeenu Viswambharan095529a2016-08-04 09:43:15 +0100343 return PSCI_E_INVALID_PARAMS;
344
345 /*
346 * Read the status of the given MPDIR from FVP power controller. The
347 * power controller only gives us on/off status, so map that to expected
348 * return values of the PSCI call
349 */
350 psysr = fvp_pwrc_read_psysr(target_cpu);
351 if (psysr == PSYSR_INVALID)
352 return PSCI_E_INVALID_PARAMS;
353
Jonathan Wrightff957ed2018-03-14 15:24:00 +0000354 if (power_level == ARM_PWR_LVL0) {
Sathees Balya50905c72018-10-05 13:30:59 +0100355 ret = ((psysr & PSYSR_AFF_L0) != 0U) ? HW_ON : HW_OFF;
Jonathan Wrightff957ed2018-03-14 15:24:00 +0000356 } else {
357 /* power_level == ARM_PWR_LVL1 */
Sathees Balya50905c72018-10-05 13:30:59 +0100358 ret = ((psysr & PSYSR_AFF_L1) != 0U) ? HW_ON : HW_OFF;
Jeenu Viswambharan095529a2016-08-04 09:43:15 +0100359 }
360
361 return ret;
362}
363
Soby Mathew9ca28062017-10-11 16:08:58 +0100364/*
365 * The FVP doesn't truly support power management at SYSTEM power domain. The
366 * SYSTEM_SUSPEND will be down-graded to the cluster level within the platform
367 * layer. The `fake` SYSTEM_SUSPEND allows us to validate some of the driver
368 * save and restore sequences on FVP.
369 */
Roberto Vargas2ca18d92018-02-12 12:36:17 +0000370#if !ARM_BL31_IN_DRAM
371static void fvp_get_sys_suspend_power_state(psci_power_state_t *req_state)
Soby Mathew9ca28062017-10-11 16:08:58 +0100372{
373 unsigned int i;
374
375 for (i = ARM_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++)
376 req_state->pwr_domain_state[i] = ARM_LOCAL_STATE_OFF;
Wing Libcff3652023-06-28 14:03:21 -0700377
378#if PSCI_OS_INIT_MODE
379 req_state->last_at_pwrlvl = PLAT_MAX_PWR_LVL;
380#endif
Soby Mathew9ca28062017-10-11 16:08:58 +0100381}
Roberto Vargas2ca18d92018-02-12 12:36:17 +0000382#endif
Soby Mathew9ca28062017-10-11 16:08:58 +0100383
Achin Gupta4f6ad662013-10-25 09:08:21 +0100384/*******************************************************************************
Soby Mathew9ca28062017-10-11 16:08:58 +0100385 * Handler to filter PSCI requests.
386 ******************************************************************************/
387/*
388 * The system power domain suspend is only supported only via
389 * PSCI SYSTEM_SUSPEND API. PSCI CPU_SUSPEND request to system power domain
390 * will be downgraded to the lower level.
391 */
392static int fvp_validate_power_state(unsigned int power_state,
393 psci_power_state_t *req_state)
394{
395 int rc;
396 rc = arm_validate_power_state(power_state, req_state);
397
398 /*
399 * Ensure that the system power domain level is never suspended
400 * via PSCI CPU SUSPEND API. Currently system suspend is only
401 * supported via PSCI SYSTEM SUSPEND API.
402 */
403 req_state->pwr_domain_state[ARM_PWR_LVL2] = ARM_LOCAL_STATE_RUN;
404 return rc;
405}
406
407/*
408 * Custom `translate_power_state_by_mpidr` handler for FVP. Unlike in the
409 * `fvp_validate_power_state`, we do not downgrade the system power
410 * domain level request in `power_state` as it will be used to query the
411 * PSCI_STAT_COUNT/RESIDENCY at the system power domain level.
412 */
413static int fvp_translate_power_state_by_mpidr(u_register_t mpidr,
414 unsigned int power_state,
415 psci_power_state_t *output_state)
416{
417 return arm_validate_power_state(power_state, output_state);
418}
419
420/*******************************************************************************
Soby Mathewfeac8fc2015-09-29 15:47:16 +0100421 * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
422 * platform layer will take care of registering the handlers with PSCI.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100423 ******************************************************************************/
Soby Mathew0b4c5a32016-10-21 17:51:22 +0100424plat_psci_ops_t plat_arm_psci_pm_ops = {
Soby Mathewfec4eb72015-07-01 16:16:20 +0100425 .cpu_standby = fvp_cpu_standby,
426 .pwr_domain_on = fvp_pwr_domain_on,
427 .pwr_domain_off = fvp_pwr_domain_off,
428 .pwr_domain_suspend = fvp_pwr_domain_suspend,
429 .pwr_domain_on_finish = fvp_pwr_domain_on_finish,
Madhukar Pappireddy2859b7d2019-06-10 16:54:36 -0500430 .pwr_domain_on_finish_late = fvp_pwr_domain_on_finish_late,
Soby Mathewfec4eb72015-07-01 16:16:20 +0100431 .pwr_domain_suspend_finish = fvp_pwr_domain_suspend_finish,
Juan Castillo4dc4a472014-08-12 11:17:06 +0100432 .system_off = fvp_system_off,
Soby Mathew74e52a72014-10-02 16:56:51 +0100433 .system_reset = fvp_system_reset,
Soby Mathew9ca28062017-10-11 16:08:58 +0100434 .validate_power_state = fvp_validate_power_state,
Jeenu Viswambharan59424d82017-09-19 09:27:18 +0100435 .validate_ns_entrypoint = arm_validate_psci_entrypoint,
Soby Mathew9ca28062017-10-11 16:08:58 +0100436 .translate_power_state_by_mpidr = fvp_translate_power_state_by_mpidr,
Roberto Vargasa1c16b62017-08-03 09:16:43 +0100437 .get_node_hw_state = fvp_node_hw_state,
Antonio Nino Diaz0b6af832017-11-22 12:00:44 +0000438#if !ARM_BL31_IN_DRAM
439 /*
440 * The TrustZone Controller is set up during the warmboot sequence after
441 * resuming the CPU from a SYSTEM_SUSPEND. If BL31 is located in SRAM
442 * this is not a problem but, if it is in TZC-secured DRAM, it tries to
443 * reconfigure the same memory it is running on, causing an exception.
444 */
Soby Mathew9ca28062017-10-11 16:08:58 +0100445 .get_sys_suspend_power_state = fvp_get_sys_suspend_power_state,
Antonio Nino Diaz0b6af832017-11-22 12:00:44 +0000446#endif
Roberto Vargasa1c16b62017-08-03 09:16:43 +0100447 .mem_protect_chk = arm_psci_mem_protect_chk,
448 .read_mem_protect = arm_psci_read_mem_protect,
449 .write_mem_protect = arm_nor_psci_write_mem_protect,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100450};
Chandni Cherukurie4bf6a02018-11-14 13:43:59 +0530451
452const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops)
453{
454 return ops;
455}