xref: /arm-trusted-firmware/plat/intel/soc/common/socfpga_psci.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2019-2023, ARM Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu  * Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
4*91f16700Schasinglulu  *
5*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
6*91f16700Schasinglulu  */
7*91f16700Schasinglulu 
8*91f16700Schasinglulu #include <arch_helpers.h>
9*91f16700Schasinglulu #include <common/debug.h>
10*91f16700Schasinglulu 
11*91f16700Schasinglulu #ifndef GICV3_SUPPORT_GIC600
12*91f16700Schasinglulu #include <drivers/arm/gicv2.h>
13*91f16700Schasinglulu #else
14*91f16700Schasinglulu #include <drivers/arm/gicv3.h>
15*91f16700Schasinglulu #endif
16*91f16700Schasinglulu #include <lib/mmio.h>
17*91f16700Schasinglulu #include <lib/psci/psci.h>
18*91f16700Schasinglulu #include <plat/common/platform.h>
19*91f16700Schasinglulu #include "socfpga_mailbox.h"
20*91f16700Schasinglulu #include "socfpga_plat_def.h"
21*91f16700Schasinglulu #include "socfpga_reset_manager.h"
22*91f16700Schasinglulu #include "socfpga_sip_svc.h"
23*91f16700Schasinglulu #include "socfpga_system_manager.h"
24*91f16700Schasinglulu 
25*91f16700Schasinglulu #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5
26*91f16700Schasinglulu void socfpga_wakeup_secondary_cpu(unsigned int cpu_id);
27*91f16700Schasinglulu extern void plat_secondary_cold_boot_setup(void);
28*91f16700Schasinglulu #endif
29*91f16700Schasinglulu 
30*91f16700Schasinglulu /*******************************************************************************
31*91f16700Schasinglulu  * plat handler called when a CPU is about to enter standby.
32*91f16700Schasinglulu  ******************************************************************************/
33*91f16700Schasinglulu void socfpga_cpu_standby(plat_local_state_t cpu_state)
34*91f16700Schasinglulu {
35*91f16700Schasinglulu 	/*
36*91f16700Schasinglulu 	 * Enter standby state
37*91f16700Schasinglulu 	 * dsb is good practice before using wfi to enter low power states
38*91f16700Schasinglulu 	 */
39*91f16700Schasinglulu 	VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state);
40*91f16700Schasinglulu 	dsb();
41*91f16700Schasinglulu 	wfi();
42*91f16700Schasinglulu }
43*91f16700Schasinglulu 
44*91f16700Schasinglulu /*******************************************************************************
45*91f16700Schasinglulu  * plat handler called when a power domain is about to be turned on. The
46*91f16700Schasinglulu  * mpidr determines the CPU to be turned on.
47*91f16700Schasinglulu  ******************************************************************************/
48*91f16700Schasinglulu int socfpga_pwr_domain_on(u_register_t mpidr)
49*91f16700Schasinglulu {
50*91f16700Schasinglulu 	unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr);
51*91f16700Schasinglulu #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5
52*91f16700Schasinglulu 	/* TODO: Add in CPU FUSE from SDM */
53*91f16700Schasinglulu #else
54*91f16700Schasinglulu 	uint32_t psci_boot = 0x00;
55*91f16700Schasinglulu 
56*91f16700Schasinglulu 	VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr);
57*91f16700Schasinglulu #endif
58*91f16700Schasinglulu 
59*91f16700Schasinglulu 	if (cpu_id == -1)
60*91f16700Schasinglulu 		return PSCI_E_INTERN_FAIL;
61*91f16700Schasinglulu 
62*91f16700Schasinglulu #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5
63*91f16700Schasinglulu 	if (cpu_id == 0x00) {
64*91f16700Schasinglulu 		psci_boot = mmio_read_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8));
65*91f16700Schasinglulu 		psci_boot |= 0x80000; /* bit 19 */
66*91f16700Schasinglulu 		mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8), psci_boot);
67*91f16700Schasinglulu 	}
68*91f16700Schasinglulu 
69*91f16700Schasinglulu 	mmio_write_64(PLAT_CPUID_RELEASE, cpu_id);
70*91f16700Schasinglulu #endif
71*91f16700Schasinglulu 
72*91f16700Schasinglulu 	/* release core reset */
73*91f16700Schasinglulu #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5
74*91f16700Schasinglulu 	bl31_plat_set_secondary_cpu_entrypoint(cpu_id);
75*91f16700Schasinglulu #else
76*91f16700Schasinglulu 	mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id);
77*91f16700Schasinglulu 	mmio_write_64(PLAT_CPUID_RELEASE, cpu_id);
78*91f16700Schasinglulu #endif
79*91f16700Schasinglulu 
80*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
81*91f16700Schasinglulu }
82*91f16700Schasinglulu 
83*91f16700Schasinglulu /*******************************************************************************
84*91f16700Schasinglulu  * plat handler called when a power domain is about to be turned off. The
85*91f16700Schasinglulu  * target_state encodes the power state that each level should transition to.
86*91f16700Schasinglulu  ******************************************************************************/
87*91f16700Schasinglulu void socfpga_pwr_domain_off(const psci_power_state_t *target_state)
88*91f16700Schasinglulu {
89*91f16700Schasinglulu 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
90*91f16700Schasinglulu 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
91*91f16700Schasinglulu 			__func__, i, target_state->pwr_domain_state[i]);
92*91f16700Schasinglulu 
93*91f16700Schasinglulu 	/* Prevent interrupts from spuriously waking up this cpu */
94*91f16700Schasinglulu #ifdef GICV3_SUPPORT_GIC600
95*91f16700Schasinglulu 	gicv3_cpuif_disable(plat_my_core_pos());
96*91f16700Schasinglulu #else
97*91f16700Schasinglulu 	gicv2_cpuif_disable();
98*91f16700Schasinglulu #endif
99*91f16700Schasinglulu 
100*91f16700Schasinglulu }
101*91f16700Schasinglulu 
102*91f16700Schasinglulu /*******************************************************************************
103*91f16700Schasinglulu  * plat handler called when a power domain is about to be suspended. The
104*91f16700Schasinglulu  * target_state encodes the power state that each level should transition to.
105*91f16700Schasinglulu  ******************************************************************************/
106*91f16700Schasinglulu void socfpga_pwr_domain_suspend(const psci_power_state_t *target_state)
107*91f16700Schasinglulu {
108*91f16700Schasinglulu #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5
109*91f16700Schasinglulu 	unsigned int cpu_id = plat_my_core_pos();
110*91f16700Schasinglulu #endif
111*91f16700Schasinglulu 
112*91f16700Schasinglulu 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
113*91f16700Schasinglulu 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
114*91f16700Schasinglulu 			__func__, i, target_state->pwr_domain_state[i]);
115*91f16700Schasinglulu 
116*91f16700Schasinglulu #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5
117*91f16700Schasinglulu 	/* assert core reset */
118*91f16700Schasinglulu 	mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id);
119*91f16700Schasinglulu #endif
120*91f16700Schasinglulu }
121*91f16700Schasinglulu 
122*91f16700Schasinglulu /*******************************************************************************
123*91f16700Schasinglulu  * plat handler called when a power domain has just been powered on after
124*91f16700Schasinglulu  * being turned off earlier. The target_state encodes the low power state that
125*91f16700Schasinglulu  * each level has woken up from.
126*91f16700Schasinglulu  ******************************************************************************/
127*91f16700Schasinglulu void socfpga_pwr_domain_on_finish(const psci_power_state_t *target_state)
128*91f16700Schasinglulu {
129*91f16700Schasinglulu 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
130*91f16700Schasinglulu 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
131*91f16700Schasinglulu 			__func__, i, target_state->pwr_domain_state[i]);
132*91f16700Schasinglulu 
133*91f16700Schasinglulu 	/* Enable the gic cpu interface */
134*91f16700Schasinglulu #ifdef GICV3_SUPPORT_GIC600
135*91f16700Schasinglulu 	gicv3_rdistif_init(plat_my_core_pos());
136*91f16700Schasinglulu 	gicv3_cpuif_enable(plat_my_core_pos());
137*91f16700Schasinglulu #else
138*91f16700Schasinglulu 	/* Program the gic per-cpu distributor or re-distributor interface */
139*91f16700Schasinglulu 	gicv2_pcpu_distif_init();
140*91f16700Schasinglulu 	gicv2_set_pe_target_mask(plat_my_core_pos());
141*91f16700Schasinglulu 
142*91f16700Schasinglulu 	/* Enable the gic cpu interface */
143*91f16700Schasinglulu 	gicv2_cpuif_enable();
144*91f16700Schasinglulu #endif
145*91f16700Schasinglulu }
146*91f16700Schasinglulu 
147*91f16700Schasinglulu /*******************************************************************************
148*91f16700Schasinglulu  * plat handler called when a power domain has just been powered on after
149*91f16700Schasinglulu  * having been suspended earlier. The target_state encodes the low power state
150*91f16700Schasinglulu  * that each level has woken up from.
151*91f16700Schasinglulu  * TODO: At the moment we reuse the on finisher and reinitialize the secure
152*91f16700Schasinglulu  * context. Need to implement a separate suspend finisher.
153*91f16700Schasinglulu  ******************************************************************************/
154*91f16700Schasinglulu void socfpga_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
155*91f16700Schasinglulu {
156*91f16700Schasinglulu #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5
157*91f16700Schasinglulu 	unsigned int cpu_id = plat_my_core_pos();
158*91f16700Schasinglulu #endif
159*91f16700Schasinglulu 
160*91f16700Schasinglulu 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
161*91f16700Schasinglulu 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
162*91f16700Schasinglulu 			__func__, i, target_state->pwr_domain_state[i]);
163*91f16700Schasinglulu 
164*91f16700Schasinglulu #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5
165*91f16700Schasinglulu 	/* release core reset */
166*91f16700Schasinglulu 	mmio_clrbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id);
167*91f16700Schasinglulu #endif
168*91f16700Schasinglulu }
169*91f16700Schasinglulu 
170*91f16700Schasinglulu /*******************************************************************************
171*91f16700Schasinglulu  * plat handlers to shutdown/reboot the system
172*91f16700Schasinglulu  ******************************************************************************/
173*91f16700Schasinglulu static void __dead2 socfpga_system_off(void)
174*91f16700Schasinglulu {
175*91f16700Schasinglulu 	wfi();
176*91f16700Schasinglulu 	ERROR("System Off: operation not handled.\n");
177*91f16700Schasinglulu 	panic();
178*91f16700Schasinglulu }
179*91f16700Schasinglulu 
180*91f16700Schasinglulu extern uint64_t intel_rsu_update_address;
181*91f16700Schasinglulu 
182*91f16700Schasinglulu static void __dead2 socfpga_system_reset(void)
183*91f16700Schasinglulu {
184*91f16700Schasinglulu 	uint32_t addr_buf[2];
185*91f16700Schasinglulu 
186*91f16700Schasinglulu 	memcpy(addr_buf, &intel_rsu_update_address,
187*91f16700Schasinglulu 			sizeof(intel_rsu_update_address));
188*91f16700Schasinglulu 	if (intel_rsu_update_address) {
189*91f16700Schasinglulu 		mailbox_rsu_update(addr_buf);
190*91f16700Schasinglulu 	} else {
191*91f16700Schasinglulu 		mailbox_reset_cold();
192*91f16700Schasinglulu 	}
193*91f16700Schasinglulu 
194*91f16700Schasinglulu 	while (1)
195*91f16700Schasinglulu 		wfi();
196*91f16700Schasinglulu }
197*91f16700Schasinglulu 
198*91f16700Schasinglulu static int socfpga_system_reset2(int is_vendor, int reset_type,
199*91f16700Schasinglulu 					u_register_t cookie)
200*91f16700Schasinglulu {
201*91f16700Schasinglulu #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5
202*91f16700Schasinglulu 	mailbox_reset_warm(reset_type);
203*91f16700Schasinglulu #else
204*91f16700Schasinglulu 	if (cold_reset_for_ecc_dbe()) {
205*91f16700Schasinglulu 		mailbox_reset_cold();
206*91f16700Schasinglulu 	}
207*91f16700Schasinglulu #endif
208*91f16700Schasinglulu 
209*91f16700Schasinglulu 	/* disable cpuif */
210*91f16700Schasinglulu #ifdef GICV3_SUPPORT_GIC600
211*91f16700Schasinglulu 	gicv3_cpuif_disable(plat_my_core_pos());
212*91f16700Schasinglulu #else
213*91f16700Schasinglulu 	gicv2_cpuif_disable();
214*91f16700Schasinglulu #endif
215*91f16700Schasinglulu 
216*91f16700Schasinglulu 	/* Store magic number */
217*91f16700Schasinglulu 	mmio_write_32(L2_RESET_DONE_REG, L2_RESET_DONE_STATUS);
218*91f16700Schasinglulu 
219*91f16700Schasinglulu 	/* Increase timeout */
220*91f16700Schasinglulu 	mmio_write_32(SOCFPGA_RSTMGR(HDSKTIMEOUT), 0xffffff);
221*91f16700Schasinglulu 
222*91f16700Schasinglulu 	/* Enable handshakes */
223*91f16700Schasinglulu 	mmio_setbits_32(SOCFPGA_RSTMGR(HDSKEN), RSTMGR_HDSKEN_SET);
224*91f16700Schasinglulu 
225*91f16700Schasinglulu #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5
226*91f16700Schasinglulu 	/* Reset L2 module */
227*91f16700Schasinglulu 	mmio_setbits_32(SOCFPGA_RSTMGR(COLDMODRST), 0x100);
228*91f16700Schasinglulu #endif
229*91f16700Schasinglulu 
230*91f16700Schasinglulu 	while (1)
231*91f16700Schasinglulu 		wfi();
232*91f16700Schasinglulu 
233*91f16700Schasinglulu 	/* Should not reach here */
234*91f16700Schasinglulu 	return 0;
235*91f16700Schasinglulu }
236*91f16700Schasinglulu 
237*91f16700Schasinglulu int socfpga_validate_power_state(unsigned int power_state,
238*91f16700Schasinglulu 				psci_power_state_t *req_state)
239*91f16700Schasinglulu {
240*91f16700Schasinglulu 	VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
241*91f16700Schasinglulu 
242*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
243*91f16700Schasinglulu }
244*91f16700Schasinglulu 
245*91f16700Schasinglulu int socfpga_validate_ns_entrypoint(unsigned long ns_entrypoint)
246*91f16700Schasinglulu {
247*91f16700Schasinglulu 	VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint);
248*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
249*91f16700Schasinglulu }
250*91f16700Schasinglulu 
251*91f16700Schasinglulu void socfpga_get_sys_suspend_power_state(psci_power_state_t *req_state)
252*91f16700Schasinglulu {
253*91f16700Schasinglulu 	req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE;
254*91f16700Schasinglulu 	req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE;
255*91f16700Schasinglulu }
256*91f16700Schasinglulu 
257*91f16700Schasinglulu /*******************************************************************************
258*91f16700Schasinglulu  * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
259*91f16700Schasinglulu  * platform layer will take care of registering the handlers with PSCI.
260*91f16700Schasinglulu  ******************************************************************************/
261*91f16700Schasinglulu const plat_psci_ops_t socfpga_psci_pm_ops = {
262*91f16700Schasinglulu 	.cpu_standby = socfpga_cpu_standby,
263*91f16700Schasinglulu 	.pwr_domain_on = socfpga_pwr_domain_on,
264*91f16700Schasinglulu 	.pwr_domain_off = socfpga_pwr_domain_off,
265*91f16700Schasinglulu 	.pwr_domain_suspend = socfpga_pwr_domain_suspend,
266*91f16700Schasinglulu 	.pwr_domain_on_finish = socfpga_pwr_domain_on_finish,
267*91f16700Schasinglulu 	.pwr_domain_suspend_finish = socfpga_pwr_domain_suspend_finish,
268*91f16700Schasinglulu 	.system_off = socfpga_system_off,
269*91f16700Schasinglulu 	.system_reset = socfpga_system_reset,
270*91f16700Schasinglulu 	.system_reset2 = socfpga_system_reset2,
271*91f16700Schasinglulu 	.validate_power_state = socfpga_validate_power_state,
272*91f16700Schasinglulu 	.validate_ns_entrypoint = socfpga_validate_ns_entrypoint,
273*91f16700Schasinglulu 	.get_sys_suspend_power_state = socfpga_get_sys_suspend_power_state
274*91f16700Schasinglulu };
275*91f16700Schasinglulu 
276*91f16700Schasinglulu /*******************************************************************************
277*91f16700Schasinglulu  * Export the platform specific power ops.
278*91f16700Schasinglulu  ******************************************************************************/
279*91f16700Schasinglulu int plat_setup_psci_ops(uintptr_t sec_entrypoint,
280*91f16700Schasinglulu 			const struct plat_psci_ops **psci_ops)
281*91f16700Schasinglulu {
282*91f16700Schasinglulu 	/* Save warm boot entrypoint.*/
283*91f16700Schasinglulu 	mmio_write_64(PLAT_SEC_ENTRY, sec_entrypoint);
284*91f16700Schasinglulu 	*psci_ops = &socfpga_psci_pm_ops;
285*91f16700Schasinglulu 
286*91f16700Schasinglulu 	return 0;
287*91f16700Schasinglulu }
288