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