xref: /arm-trusted-firmware/plat/st/stm32mp1/stm32mp1_pm.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <assert.h>
8*91f16700Schasinglulu #include <errno.h>
9*91f16700Schasinglulu 
10*91f16700Schasinglulu #include <arch_helpers.h>
11*91f16700Schasinglulu #include <bl32/sp_min/platform_sp_min.h>
12*91f16700Schasinglulu #include <common/debug.h>
13*91f16700Schasinglulu #include <drivers/arm/gic_common.h>
14*91f16700Schasinglulu #include <drivers/arm/gicv2.h>
15*91f16700Schasinglulu #include <drivers/clk.h>
16*91f16700Schasinglulu #include <dt-bindings/clock/stm32mp1-clks.h>
17*91f16700Schasinglulu #include <lib/mmio.h>
18*91f16700Schasinglulu #include <lib/psci/psci.h>
19*91f16700Schasinglulu #include <plat/common/platform.h>
20*91f16700Schasinglulu 
21*91f16700Schasinglulu #include <platform_def.h>
22*91f16700Schasinglulu 
23*91f16700Schasinglulu static uintptr_t stm32_sec_entrypoint;
24*91f16700Schasinglulu static uint32_t cntfrq_core0;
25*91f16700Schasinglulu 
26*91f16700Schasinglulu /*******************************************************************************
27*91f16700Schasinglulu  * STM32MP1 handler called when a CPU is about to enter standby.
28*91f16700Schasinglulu  * call by core 1 to enter in wfi
29*91f16700Schasinglulu  ******************************************************************************/
30*91f16700Schasinglulu static void stm32_cpu_standby(plat_local_state_t cpu_state)
31*91f16700Schasinglulu {
32*91f16700Schasinglulu 	uint32_t interrupt = GIC_SPURIOUS_INTERRUPT;
33*91f16700Schasinglulu 
34*91f16700Schasinglulu 	assert(cpu_state == ARM_LOCAL_STATE_RET);
35*91f16700Schasinglulu 
36*91f16700Schasinglulu 	/*
37*91f16700Schasinglulu 	 * Enter standby state
38*91f16700Schasinglulu 	 * dsb is good practice before using wfi to enter low power states
39*91f16700Schasinglulu 	 */
40*91f16700Schasinglulu 	isb();
41*91f16700Schasinglulu 	dsb();
42*91f16700Schasinglulu 	while (interrupt == GIC_SPURIOUS_INTERRUPT) {
43*91f16700Schasinglulu 		wfi();
44*91f16700Schasinglulu 
45*91f16700Schasinglulu 		/* Acknowledge IT */
46*91f16700Schasinglulu 		interrupt = gicv2_acknowledge_interrupt();
47*91f16700Schasinglulu 		/* If Interrupt == 1022 it will be acknowledged by non secure */
48*91f16700Schasinglulu 		if ((interrupt != PENDING_G1_INTID) &&
49*91f16700Schasinglulu 		    (interrupt != GIC_SPURIOUS_INTERRUPT)) {
50*91f16700Schasinglulu 			gicv2_end_of_interrupt(interrupt);
51*91f16700Schasinglulu 		}
52*91f16700Schasinglulu 	}
53*91f16700Schasinglulu }
54*91f16700Schasinglulu 
55*91f16700Schasinglulu /*******************************************************************************
56*91f16700Schasinglulu  * STM32MP1 handler called when a power domain is about to be turned on. The
57*91f16700Schasinglulu  * mpidr determines the CPU to be turned on.
58*91f16700Schasinglulu  * call by core 0 to activate core 1
59*91f16700Schasinglulu  ******************************************************************************/
60*91f16700Schasinglulu static int stm32_pwr_domain_on(u_register_t mpidr)
61*91f16700Schasinglulu {
62*91f16700Schasinglulu 	unsigned long current_cpu_mpidr = read_mpidr_el1();
63*91f16700Schasinglulu 	uintptr_t bkpr_core1_addr =
64*91f16700Schasinglulu 		tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX);
65*91f16700Schasinglulu 	uintptr_t bkpr_core1_magic =
66*91f16700Schasinglulu 		tamp_bkpr(BOOT_API_CORE1_MAGIC_NUMBER_TAMP_BCK_REG_IDX);
67*91f16700Schasinglulu 
68*91f16700Schasinglulu 	if (mpidr == current_cpu_mpidr) {
69*91f16700Schasinglulu 		return PSCI_E_INVALID_PARAMS;
70*91f16700Schasinglulu 	}
71*91f16700Schasinglulu 
72*91f16700Schasinglulu 	/* Only one valid entry point */
73*91f16700Schasinglulu 	if (stm32_sec_entrypoint != (uintptr_t)&sp_min_warm_entrypoint) {
74*91f16700Schasinglulu 		return PSCI_E_INVALID_ADDRESS;
75*91f16700Schasinglulu 	}
76*91f16700Schasinglulu 
77*91f16700Schasinglulu 	clk_enable(RTCAPB);
78*91f16700Schasinglulu 
79*91f16700Schasinglulu 	cntfrq_core0 = read_cntfrq_el0();
80*91f16700Schasinglulu 
81*91f16700Schasinglulu 	/* Write entrypoint in backup RAM register */
82*91f16700Schasinglulu 	mmio_write_32(bkpr_core1_addr, stm32_sec_entrypoint);
83*91f16700Schasinglulu 
84*91f16700Schasinglulu 	/* Write magic number in backup register */
85*91f16700Schasinglulu 	mmio_write_32(bkpr_core1_magic, BOOT_API_A7_CORE1_MAGIC_NUMBER);
86*91f16700Schasinglulu 
87*91f16700Schasinglulu 	clk_disable(RTCAPB);
88*91f16700Schasinglulu 
89*91f16700Schasinglulu 	/* Generate an IT to core 1 */
90*91f16700Schasinglulu 	gicv2_raise_sgi(ARM_IRQ_SEC_SGI_0, false, STM32MP_SECONDARY_CPU);
91*91f16700Schasinglulu 
92*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
93*91f16700Schasinglulu }
94*91f16700Schasinglulu 
95*91f16700Schasinglulu /*******************************************************************************
96*91f16700Schasinglulu  * STM32MP1 handler called when a power domain is about to be turned off. The
97*91f16700Schasinglulu  * target_state encodes the power state that each level should transition to.
98*91f16700Schasinglulu  ******************************************************************************/
99*91f16700Schasinglulu static void stm32_pwr_domain_off(const psci_power_state_t *target_state)
100*91f16700Schasinglulu {
101*91f16700Schasinglulu 	/* Nothing to do */
102*91f16700Schasinglulu }
103*91f16700Schasinglulu 
104*91f16700Schasinglulu /*******************************************************************************
105*91f16700Schasinglulu  * STM32MP1 handler called when a power domain is about to be suspended. The
106*91f16700Schasinglulu  * target_state encodes the power state that each level should transition to.
107*91f16700Schasinglulu  ******************************************************************************/
108*91f16700Schasinglulu static void stm32_pwr_domain_suspend(const psci_power_state_t *target_state)
109*91f16700Schasinglulu {
110*91f16700Schasinglulu 	/* Nothing to do, power domain is not disabled */
111*91f16700Schasinglulu }
112*91f16700Schasinglulu 
113*91f16700Schasinglulu /*******************************************************************************
114*91f16700Schasinglulu  * STM32MP1 handler called when a power domain has just been powered on after
115*91f16700Schasinglulu  * being turned off earlier. The target_state encodes the low power state that
116*91f16700Schasinglulu  * each level has woken up from.
117*91f16700Schasinglulu  * call by core 1 just after wake up
118*91f16700Schasinglulu  ******************************************************************************/
119*91f16700Schasinglulu static void stm32_pwr_domain_on_finish(const psci_power_state_t *target_state)
120*91f16700Schasinglulu {
121*91f16700Schasinglulu 	stm32mp_gic_pcpu_init();
122*91f16700Schasinglulu 
123*91f16700Schasinglulu 	write_cntfrq_el0(cntfrq_core0);
124*91f16700Schasinglulu }
125*91f16700Schasinglulu 
126*91f16700Schasinglulu /*******************************************************************************
127*91f16700Schasinglulu  * STM32MP1 handler called when a power domain has just been powered on after
128*91f16700Schasinglulu  * having been suspended earlier. The target_state encodes the low power state
129*91f16700Schasinglulu  * that each level has woken up from.
130*91f16700Schasinglulu  ******************************************************************************/
131*91f16700Schasinglulu static void stm32_pwr_domain_suspend_finish(const psci_power_state_t
132*91f16700Schasinglulu 					    *target_state)
133*91f16700Schasinglulu {
134*91f16700Schasinglulu 	/* Nothing to do, power domain is not disabled */
135*91f16700Schasinglulu }
136*91f16700Schasinglulu 
137*91f16700Schasinglulu static void __dead2 stm32_pwr_domain_pwr_down_wfi(const psci_power_state_t
138*91f16700Schasinglulu 						  *target_state)
139*91f16700Schasinglulu {
140*91f16700Schasinglulu 	ERROR("stm32mpu1 Power Down WFI: operation not handled.\n");
141*91f16700Schasinglulu 	panic();
142*91f16700Schasinglulu }
143*91f16700Schasinglulu 
144*91f16700Schasinglulu static void __dead2 stm32_system_off(void)
145*91f16700Schasinglulu {
146*91f16700Schasinglulu 	ERROR("stm32mpu1 System Off: operation not handled.\n");
147*91f16700Schasinglulu 	panic();
148*91f16700Schasinglulu }
149*91f16700Schasinglulu 
150*91f16700Schasinglulu static void __dead2 stm32_system_reset(void)
151*91f16700Schasinglulu {
152*91f16700Schasinglulu 	mmio_setbits_32(stm32mp_rcc_base() + RCC_MP_GRSTCSETR,
153*91f16700Schasinglulu 			RCC_MP_GRSTCSETR_MPSYSRST);
154*91f16700Schasinglulu 
155*91f16700Schasinglulu 	/* Loop in case system reset is not immediately caught */
156*91f16700Schasinglulu 	for ( ; ; ) {
157*91f16700Schasinglulu 		;
158*91f16700Schasinglulu 	}
159*91f16700Schasinglulu }
160*91f16700Schasinglulu 
161*91f16700Schasinglulu static int stm32_validate_power_state(unsigned int power_state,
162*91f16700Schasinglulu 				      psci_power_state_t *req_state)
163*91f16700Schasinglulu {
164*91f16700Schasinglulu 	if (psci_get_pstate_type(power_state) != 0U) {
165*91f16700Schasinglulu 		return PSCI_E_INVALID_PARAMS;
166*91f16700Schasinglulu 	}
167*91f16700Schasinglulu 
168*91f16700Schasinglulu 	if (psci_get_pstate_pwrlvl(power_state) != 0U) {
169*91f16700Schasinglulu 		return PSCI_E_INVALID_PARAMS;
170*91f16700Schasinglulu 	}
171*91f16700Schasinglulu 
172*91f16700Schasinglulu 	if (psci_get_pstate_id(power_state) != 0U) {
173*91f16700Schasinglulu 		return PSCI_E_INVALID_PARAMS;
174*91f16700Schasinglulu 	}
175*91f16700Schasinglulu 
176*91f16700Schasinglulu 	req_state->pwr_domain_state[0] = ARM_LOCAL_STATE_RET;
177*91f16700Schasinglulu 	req_state->pwr_domain_state[1] = ARM_LOCAL_STATE_RUN;
178*91f16700Schasinglulu 
179*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
180*91f16700Schasinglulu }
181*91f16700Schasinglulu 
182*91f16700Schasinglulu static int stm32_validate_ns_entrypoint(uintptr_t entrypoint)
183*91f16700Schasinglulu {
184*91f16700Schasinglulu 	/* The non-secure entry point must be in DDR */
185*91f16700Schasinglulu 	if (entrypoint < STM32MP_DDR_BASE) {
186*91f16700Schasinglulu 		return PSCI_E_INVALID_ADDRESS;
187*91f16700Schasinglulu 	}
188*91f16700Schasinglulu 
189*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
190*91f16700Schasinglulu }
191*91f16700Schasinglulu 
192*91f16700Schasinglulu static int stm32_node_hw_state(u_register_t target_cpu,
193*91f16700Schasinglulu 			       unsigned int power_level)
194*91f16700Schasinglulu {
195*91f16700Schasinglulu 	/*
196*91f16700Schasinglulu 	 * The format of 'power_level' is implementation-defined, but 0 must
197*91f16700Schasinglulu 	 * mean a CPU. Only allow level 0.
198*91f16700Schasinglulu 	 */
199*91f16700Schasinglulu 	if (power_level != MPIDR_AFFLVL0) {
200*91f16700Schasinglulu 		return PSCI_E_INVALID_PARAMS;
201*91f16700Schasinglulu 	}
202*91f16700Schasinglulu 
203*91f16700Schasinglulu 	/*
204*91f16700Schasinglulu 	 * From psci view the CPU 0 is always ON,
205*91f16700Schasinglulu 	 * CPU 1 can be SUSPEND or RUNNING.
206*91f16700Schasinglulu 	 * Therefore do not manage POWER OFF state and always return HW_ON.
207*91f16700Schasinglulu 	 */
208*91f16700Schasinglulu 
209*91f16700Schasinglulu 	return (int)HW_ON;
210*91f16700Schasinglulu }
211*91f16700Schasinglulu 
212*91f16700Schasinglulu /*******************************************************************************
213*91f16700Schasinglulu  * Export the platform handlers. The ARM Standard platform layer will take care
214*91f16700Schasinglulu  * of registering the handlers with PSCI.
215*91f16700Schasinglulu  ******************************************************************************/
216*91f16700Schasinglulu static const plat_psci_ops_t stm32_psci_ops = {
217*91f16700Schasinglulu 	.cpu_standby = stm32_cpu_standby,
218*91f16700Schasinglulu 	.pwr_domain_on = stm32_pwr_domain_on,
219*91f16700Schasinglulu 	.pwr_domain_off = stm32_pwr_domain_off,
220*91f16700Schasinglulu 	.pwr_domain_suspend = stm32_pwr_domain_suspend,
221*91f16700Schasinglulu 	.pwr_domain_on_finish = stm32_pwr_domain_on_finish,
222*91f16700Schasinglulu 	.pwr_domain_suspend_finish = stm32_pwr_domain_suspend_finish,
223*91f16700Schasinglulu 	.pwr_domain_pwr_down_wfi = stm32_pwr_domain_pwr_down_wfi,
224*91f16700Schasinglulu 	.system_off = stm32_system_off,
225*91f16700Schasinglulu 	.system_reset = stm32_system_reset,
226*91f16700Schasinglulu 	.validate_power_state = stm32_validate_power_state,
227*91f16700Schasinglulu 	.validate_ns_entrypoint = stm32_validate_ns_entrypoint,
228*91f16700Schasinglulu 	.get_node_hw_state = stm32_node_hw_state
229*91f16700Schasinglulu };
230*91f16700Schasinglulu 
231*91f16700Schasinglulu /*******************************************************************************
232*91f16700Schasinglulu  * Export the platform specific power ops.
233*91f16700Schasinglulu  ******************************************************************************/
234*91f16700Schasinglulu int plat_setup_psci_ops(uintptr_t sec_entrypoint,
235*91f16700Schasinglulu 			const plat_psci_ops_t **psci_ops)
236*91f16700Schasinglulu {
237*91f16700Schasinglulu 	stm32_sec_entrypoint = sec_entrypoint;
238*91f16700Schasinglulu 	*psci_ops = &stm32_psci_ops;
239*91f16700Schasinglulu 
240*91f16700Schasinglulu 	return 0;
241*91f16700Schasinglulu }
242