1 /*
2  * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 
9 #include <arch_helpers.h>
10 #include <common/debug.h>
11 #include <drivers/arm/gicv3.h>
12 #include <drivers/arm/fvp/fvp_pwrc.h>
13 #include <lib/mmio.h>
14 #include <lib/psci/psci.h>
15 #include <plat/arm/common/arm_config.h>
16 #include <plat/arm/common/plat_arm.h>
17 #include <platform_def.h>
18 
19 #include "fvp_private.h"
20 #include "../drivers/arm/gic/v3/gicv3_private.h"
21 
22 
23 #if ARM_RECOM_STATE_ID_ENC
24 /*
25  *  The table storing the valid idle power states. Ensure that the
26  *  array entries are populated in ascending order of state-id to
27  *  enable us to use binary search during power state validation.
28  *  The table must be terminated by a NULL entry.
29  */
30 const unsigned int arm_pm_idle_states[] = {
31 	/* State-id - 0x01 */
32 	arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RET,
33 			ARM_PWR_LVL0, PSTATE_TYPE_STANDBY),
34 	/* State-id - 0x02 */
35 	arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_OFF,
36 			ARM_PWR_LVL0, PSTATE_TYPE_POWERDOWN),
37 	/* State-id - 0x22 */
38 	arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF,
39 			ARM_PWR_LVL1, PSTATE_TYPE_POWERDOWN),
40 	/* State-id - 0x222 */
41 	arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF,
42 		ARM_LOCAL_STATE_OFF, ARM_PWR_LVL2, PSTATE_TYPE_POWERDOWN),
43 	0,
44 };
45 #endif
46 
47 /*******************************************************************************
48  * Function which implements the common FVP specific operations to power down a
49  * cluster in response to a CPU_OFF or CPU_SUSPEND request.
50  ******************************************************************************/
fvp_cluster_pwrdwn_common(void)51 static void fvp_cluster_pwrdwn_common(void)
52 {
53 	uint64_t mpidr = read_mpidr_el1();
54 
55 	/* Disable coherency if this cluster is to be turned off */
56 	fvp_interconnect_disable();
57 
58 	/* Program the power controller to turn the cluster off */
59 	fvp_pwrc_write_pcoffr(mpidr);
60 }
61 
62 /*
63  * Empty implementation of these hooks avoid setting the GICR_WAKER.Sleep bit
64  * on ARM GICv3 implementations on FVP. This is required, because FVP does not
65  * support SYSTEM_SUSPEND and it is `faked` in firmware. Hence, for wake up
66  * from `fake` system suspend the GIC must not be powered off.
67  */
arm_gicv3_distif_pre_save(unsigned int rdist_proc_num)68 void arm_gicv3_distif_pre_save(unsigned int rdist_proc_num)
69 {}
70 
arm_gicv3_distif_post_restore(unsigned int rdist_proc_num)71 void arm_gicv3_distif_post_restore(unsigned int rdist_proc_num)
72 {}
73 
fvp_power_domain_on_finish_common(const psci_power_state_t * target_state)74 static void fvp_power_domain_on_finish_common(const psci_power_state_t *target_state)
75 {
76 	unsigned long mpidr;
77 
78 	assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
79 					ARM_LOCAL_STATE_OFF);
80 
81 	/* Get the mpidr for this cpu */
82 	mpidr = read_mpidr_el1();
83 
84 	/* Perform the common cluster specific operations */
85 	if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
86 					ARM_LOCAL_STATE_OFF) {
87 		/*
88 		 * This CPU might have woken up whilst the cluster was
89 		 * attempting to power down. In this case the FVP power
90 		 * controller will have a pending cluster power off request
91 		 * which needs to be cleared by writing to the PPONR register.
92 		 * This prevents the power controller from interpreting a
93 		 * subsequent entry of this cpu into a simple wfi as a power
94 		 * down request.
95 		 */
96 		fvp_pwrc_write_pponr(mpidr);
97 
98 		/* Enable coherency if this cluster was off */
99 		fvp_interconnect_enable();
100 	}
101 	/* Perform the common system specific operations */
102 	if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
103 						ARM_LOCAL_STATE_OFF)
104 		arm_system_pwr_domain_resume();
105 
106 	/*
107 	 * Clear PWKUPR.WEN bit to ensure interrupts do not interfere
108 	 * with a cpu power down unless the bit is set again
109 	 */
110 	fvp_pwrc_clr_wen(mpidr);
111 }
112 
113 /*******************************************************************************
114  * FVP handler called when a CPU is about to enter standby.
115  ******************************************************************************/
fvp_cpu_standby(plat_local_state_t cpu_state)116 static void fvp_cpu_standby(plat_local_state_t cpu_state)
117 {
118 	u_register_t scr = read_scr_el3();
119 
120 	assert(cpu_state == ARM_LOCAL_STATE_RET);
121 
122 	/*
123 	 * Enable the Non-secure interrupt to wake the CPU.
124 	 * In GICv3 affinity routing mode, the Non-secure Group 1 interrupts
125 	 * use Physical FIQ at EL3 whereas in GICv2, Physical IRQ is used.
126 	 * Enabling both the bits works for both GICv2 mode and GICv3 affinity
127 	 * routing mode.
128 	 */
129 	write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
130 	isb();
131 
132 	/*
133 	 * Enter standby state.
134 	 * dsb is good practice before using wfi to enter low power states.
135 	 */
136 	dsb();
137 	wfi();
138 
139 	/*
140 	 * Restore SCR_EL3 to the original value, synchronisation of SCR_EL3
141 	 * is done by eret in el3_exit() to save some execution cycles.
142 	 */
143 	write_scr_el3(scr);
144 }
145 
146 /*******************************************************************************
147  * FVP handler called when a power domain is about to be turned on. The
148  * mpidr determines the CPU to be turned on.
149  ******************************************************************************/
fvp_pwr_domain_on(u_register_t mpidr)150 static int fvp_pwr_domain_on(u_register_t mpidr)
151 {
152 	int rc = PSCI_E_SUCCESS;
153 	unsigned int psysr;
154 
155 	/*
156 	 * Ensure that we do not cancel an inflight power off request for the
157 	 * target cpu. That would leave it in a zombie wfi. Wait for it to power
158 	 * off and then program the power controller to turn that CPU on.
159 	 */
160 	do {
161 		psysr = fvp_pwrc_read_psysr(mpidr);
162 	} while ((psysr & PSYSR_AFF_L0) != 0U);
163 
164 	fvp_pwrc_write_pponr(mpidr);
165 	return rc;
166 }
167 
168 /*******************************************************************************
169  * FVP handler called when a power domain is about to be turned off. The
170  * target_state encodes the power state that each level should transition to.
171  ******************************************************************************/
fvp_pwr_domain_off(const psci_power_state_t * target_state)172 static void fvp_pwr_domain_off(const psci_power_state_t *target_state)
173 {
174 	assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
175 					ARM_LOCAL_STATE_OFF);
176 
177 	/*
178 	 * If execution reaches this stage then this power domain will be
179 	 * suspended. Perform at least the cpu specific actions followed
180 	 * by the cluster specific operations if applicable.
181 	 */
182 
183 	/* Prevent interrupts from spuriously waking up this cpu */
184 	plat_arm_gic_cpuif_disable();
185 
186 	/* Turn redistributor off */
187 	plat_arm_gic_redistif_off();
188 
189 	/* Program the power controller to power off this cpu. */
190 	fvp_pwrc_write_ppoffr(read_mpidr_el1());
191 
192 	if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
193 					ARM_LOCAL_STATE_OFF)
194 		fvp_cluster_pwrdwn_common();
195 
196 }
197 
198 /*******************************************************************************
199  * FVP handler called when a power domain is about to be suspended. The
200  * target_state encodes the power state that each level should transition to.
201  ******************************************************************************/
fvp_pwr_domain_suspend(const psci_power_state_t * target_state)202 static void fvp_pwr_domain_suspend(const psci_power_state_t *target_state)
203 {
204 	unsigned long mpidr;
205 
206 	/*
207 	 * FVP has retention only at cpu level. Just return
208 	 * as nothing is to be done for retention.
209 	 */
210 	if (target_state->pwr_domain_state[ARM_PWR_LVL0] ==
211 					ARM_LOCAL_STATE_RET)
212 		return;
213 
214 	assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
215 					ARM_LOCAL_STATE_OFF);
216 
217 	/* Get the mpidr for this cpu */
218 	mpidr = read_mpidr_el1();
219 
220 	/* Program the power controller to enable wakeup interrupts. */
221 	fvp_pwrc_set_wen(mpidr);
222 
223 	/* Prevent interrupts from spuriously waking up this cpu */
224 	plat_arm_gic_cpuif_disable();
225 
226 	/*
227 	 * The Redistributor is not powered off as it can potentially prevent
228 	 * wake up events reaching the CPUIF and/or might lead to losing
229 	 * register context.
230 	 */
231 
232 	/* Perform the common cluster specific operations */
233 	if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
234 					ARM_LOCAL_STATE_OFF)
235 		fvp_cluster_pwrdwn_common();
236 
237 	/* Perform the common system specific operations */
238 	if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
239 						ARM_LOCAL_STATE_OFF)
240 		arm_system_pwr_domain_save();
241 
242 	/* Program the power controller to power off this cpu. */
243 	fvp_pwrc_write_ppoffr(read_mpidr_el1());
244 
245 	return;
246 }
247 
248 /*******************************************************************************
249  * FVP handler called when a power domain has just been powered on after
250  * being turned off earlier. The target_state encodes the low power state that
251  * each level has woken up from.
252  ******************************************************************************/
fvp_pwr_domain_on_finish(const psci_power_state_t * target_state)253 static void fvp_pwr_domain_on_finish(const psci_power_state_t *target_state)
254 {
255 	fvp_power_domain_on_finish_common(target_state);
256 
257 }
258 
259 /*******************************************************************************
260  * FVP handler called when a power domain has just been powered on and the cpu
261  * and its cluster are fully participating in coherent transaction on the
262  * interconnect. Data cache must be enabled for CPU at this point.
263  ******************************************************************************/
fvp_pwr_domain_on_finish_late(const psci_power_state_t * target_state)264 static void fvp_pwr_domain_on_finish_late(const psci_power_state_t *target_state)
265 {
266 	/* Program GIC per-cpu distributor or re-distributor interface */
267 	plat_arm_gic_pcpu_init();
268 
269 	/* Enable GIC CPU interface */
270 	plat_arm_gic_cpuif_enable();
271 }
272 
273 /*******************************************************************************
274  * FVP handler called when a power domain has just been powered on after
275  * having been suspended earlier. The target_state encodes the low power state
276  * that each level has woken up from.
277  * TODO: At the moment we reuse the on finisher and reinitialize the secure
278  * context. Need to implement a separate suspend finisher.
279  ******************************************************************************/
fvp_pwr_domain_suspend_finish(const psci_power_state_t * target_state)280 static void fvp_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
281 {
282 	/*
283 	 * Nothing to be done on waking up from retention from CPU level.
284 	 */
285 	if (target_state->pwr_domain_state[ARM_PWR_LVL0] ==
286 					ARM_LOCAL_STATE_RET)
287 		return;
288 
289 	fvp_power_domain_on_finish_common(target_state);
290 
291 	/* Enable GIC CPU interface */
292 	plat_arm_gic_cpuif_enable();
293 }
294 
295 /*******************************************************************************
296  * FVP handlers to shutdown/reboot the system
297  ******************************************************************************/
fvp_system_off(void)298 static void __dead2 fvp_system_off(void)
299 {
300 	/* Write the System Configuration Control Register */
301 	mmio_write_32(V2M_SYSREGS_BASE + V2M_SYS_CFGCTRL,
302 		V2M_CFGCTRL_START |
303 		V2M_CFGCTRL_RW |
304 		V2M_CFGCTRL_FUNC(V2M_FUNC_SHUTDOWN));
305 	wfi();
306 	ERROR("FVP System Off: operation not handled.\n");
307 	panic();
308 }
309 
fvp_system_reset(void)310 static void __dead2 fvp_system_reset(void)
311 {
312 	/* Write the System Configuration Control Register */
313 	mmio_write_32(V2M_SYSREGS_BASE + V2M_SYS_CFGCTRL,
314 		V2M_CFGCTRL_START |
315 		V2M_CFGCTRL_RW |
316 		V2M_CFGCTRL_FUNC(V2M_FUNC_REBOOT));
317 	wfi();
318 	ERROR("FVP System Reset: operation not handled.\n");
319 	panic();
320 }
321 
fvp_node_hw_state(u_register_t target_cpu,unsigned int power_level)322 static int fvp_node_hw_state(u_register_t target_cpu,
323 			     unsigned int power_level)
324 {
325 	unsigned int psysr;
326 	int ret;
327 
328 	/*
329 	 * The format of 'power_level' is implementation-defined, but 0 must
330 	 * mean a CPU. We also allow 1 to denote the cluster
331 	 */
332 	if ((power_level != ARM_PWR_LVL0) && (power_level != ARM_PWR_LVL1))
333 		return PSCI_E_INVALID_PARAMS;
334 
335 	/*
336 	 * Read the status of the given MPDIR from FVP power controller. The
337 	 * power controller only gives us on/off status, so map that to expected
338 	 * return values of the PSCI call
339 	 */
340 	psysr = fvp_pwrc_read_psysr(target_cpu);
341 	if (psysr == PSYSR_INVALID)
342 		return PSCI_E_INVALID_PARAMS;
343 
344 	if (power_level == ARM_PWR_LVL0) {
345 		ret = ((psysr & PSYSR_AFF_L0) != 0U) ? HW_ON : HW_OFF;
346 	} else {
347 		/* power_level == ARM_PWR_LVL1 */
348 		ret = ((psysr & PSYSR_AFF_L1) != 0U) ? HW_ON : HW_OFF;
349 	}
350 
351 	return ret;
352 }
353 
354 /*
355  * The FVP doesn't truly support power management at SYSTEM power domain. The
356  * SYSTEM_SUSPEND will be down-graded to the cluster level within the platform
357  * layer. The `fake` SYSTEM_SUSPEND allows us to validate some of the driver
358  * save and restore sequences on FVP.
359  */
360 #if !ARM_BL31_IN_DRAM
fvp_get_sys_suspend_power_state(psci_power_state_t * req_state)361 static void fvp_get_sys_suspend_power_state(psci_power_state_t *req_state)
362 {
363 	unsigned int i;
364 
365 	for (i = ARM_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++)
366 		req_state->pwr_domain_state[i] = ARM_LOCAL_STATE_OFF;
367 
368 #if PSCI_OS_INIT_MODE
369 	req_state->last_at_pwrlvl = PLAT_MAX_PWR_LVL;
370 #endif
371 }
372 #endif
373 
374 /*******************************************************************************
375  * Handler to filter PSCI requests.
376  ******************************************************************************/
377 /*
378  * The system power domain suspend is only supported only via
379  * PSCI SYSTEM_SUSPEND API. PSCI CPU_SUSPEND request to system power domain
380  * will be downgraded to the lower level.
381  */
fvp_validate_power_state(unsigned int power_state,psci_power_state_t * req_state)382 static int fvp_validate_power_state(unsigned int power_state,
383 			    psci_power_state_t *req_state)
384 {
385 	int rc;
386 	rc = arm_validate_power_state(power_state, req_state);
387 
388 	/*
389 	 * Ensure that the system power domain level is never suspended
390 	 * via PSCI CPU SUSPEND API. Currently system suspend is only
391 	 * supported via PSCI SYSTEM SUSPEND API.
392 	 */
393 	req_state->pwr_domain_state[ARM_PWR_LVL2] = ARM_LOCAL_STATE_RUN;
394 	return rc;
395 }
396 
397 /*
398  * Custom `translate_power_state_by_mpidr` handler for FVP. Unlike in the
399  * `fvp_validate_power_state`, we do not downgrade the system power
400  * domain level request in `power_state` as it will be used to query the
401  * PSCI_STAT_COUNT/RESIDENCY at the system power domain level.
402  */
fvp_translate_power_state_by_mpidr(u_register_t mpidr,unsigned int power_state,psci_power_state_t * output_state)403 static int fvp_translate_power_state_by_mpidr(u_register_t mpidr,
404 		unsigned int power_state,
405 		psci_power_state_t *output_state)
406 {
407 	return arm_validate_power_state(power_state, output_state);
408 }
409 
410 /*******************************************************************************
411  * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
412  * platform layer will take care of registering the handlers with PSCI.
413  ******************************************************************************/
414 plat_psci_ops_t plat_arm_psci_pm_ops = {
415 	.cpu_standby = fvp_cpu_standby,
416 	.pwr_domain_on = fvp_pwr_domain_on,
417 	.pwr_domain_off = fvp_pwr_domain_off,
418 	.pwr_domain_suspend = fvp_pwr_domain_suspend,
419 	.pwr_domain_on_finish = fvp_pwr_domain_on_finish,
420 	.pwr_domain_on_finish_late = fvp_pwr_domain_on_finish_late,
421 	.pwr_domain_suspend_finish = fvp_pwr_domain_suspend_finish,
422 	.system_off = fvp_system_off,
423 	.system_reset = fvp_system_reset,
424 	.validate_power_state = fvp_validate_power_state,
425 	.validate_ns_entrypoint = arm_validate_psci_entrypoint,
426 	.translate_power_state_by_mpidr = fvp_translate_power_state_by_mpidr,
427 	.get_node_hw_state = fvp_node_hw_state,
428 #if !ARM_BL31_IN_DRAM
429 	/*
430 	 * The TrustZone Controller is set up during the warmboot sequence after
431 	 * resuming the CPU from a SYSTEM_SUSPEND. If BL31 is located in SRAM
432 	 * this is  not a problem but, if it is in TZC-secured DRAM, it tries to
433 	 * reconfigure the same memory it is running on, causing an exception.
434 	 */
435 	.get_sys_suspend_power_state = fvp_get_sys_suspend_power_state,
436 #endif
437 	.mem_protect_chk	= arm_psci_mem_protect_chk,
438 	.read_mem_protect	= arm_psci_read_mem_protect,
439 	.write_mem_protect	= arm_nor_psci_write_mem_protect,
440 };
441 
plat_arm_psci_override_pm_ops(plat_psci_ops_t * ops)442 const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops)
443 {
444 	return ops;
445 }
446