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