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