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