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