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