1 /*
2 * Copyright (c) 2022, Xilinx, Inc. All rights reserved.
3 * Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include <assert.h>
9
10 #include <common/debug.h>
11 #include <common/ep_info.h>
12 #include <drivers/delay_timer.h>
13 #include <lib/mmio.h>
14 #include <lib/psci/psci.h>
15 #include <plat/arm/common/plat_arm.h>
16 #include <plat/common/platform.h>
17 #include <plat_arm.h>
18 #include <plat_fdt.h>
19
20 #include "def.h"
21 #include <ipi.h>
22 #include <plat_private.h>
23 #include "pm_api_sys.h"
24 #include "pm_client.h"
25 #include <pm_common.h>
26 #include "pm_defs.h"
27 #include "pm_svc_main.h"
28
29 static uintptr_t sec_entry;
30
31 /* 1 sec of wait timeout for receiving idle callback */
32 #define IDLE_CB_WAIT_TIMEOUT (1000000U)
33
versal2_pwr_domain_on(u_register_t mpidr)34 static int32_t versal2_pwr_domain_on(u_register_t mpidr)
35 {
36 int32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
37 int32_t ret = (int32_t) PSCI_E_INTERN_FAIL;
38 enum pm_ret_status pm_ret;
39 const struct pm_proc *proc;
40
41 if (cpu_id != -1) {
42 proc = pm_get_proc((uint32_t)cpu_id);
43 if (proc != NULL) {
44 pm_ret = pm_req_wakeup(proc->node_id,
45 (uint32_t)
46 ((sec_entry & 0xFFFFFFFFU) | 0x1U),
47 sec_entry >> 32, 0, 0);
48
49 if (pm_ret == PM_RET_SUCCESS) {
50 /* Clear power down request */
51 pm_client_wakeup(proc);
52 ret = (int32_t) PSCI_E_SUCCESS;
53 }
54 }
55 }
56
57 return ret;
58 }
59
60 /**
61 * versal2_pwr_domain_off() - Turn off core.
62 * @target_state: Targeted state.
63 */
versal2_pwr_domain_off(const psci_power_state_t * target_state)64 static void versal2_pwr_domain_off(const psci_power_state_t *target_state)
65 {
66 const struct pm_proc *proc;
67 uint32_t cpu_id = plat_my_core_pos();
68 enum pm_ret_status pm_ret;
69 size_t i;
70
71 proc = pm_get_proc(cpu_id);
72 if (proc == NULL) {
73 ERROR("Failed to get proc %d\n", cpu_id);
74 goto err;
75 }
76
77 for (i = 0; i <= PLAT_MAX_PWR_LVL; i++) {
78 VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
79 __func__, i, target_state->pwr_domain_state[i]);
80 }
81
82 plat_gic_cpuif_disable();
83 /*
84 * Send request to PMC to power down the appropriate APU CPU
85 * core.
86 * According to PSCI specification, CPU_off function does not
87 * have resume address and CPU core can only be woken up
88 * invoking CPU_on function, during which resume address will
89 * be set.
90 */
91 pm_ret = pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_OFF, 0,
92 NON_SECURE);
93
94 if (pm_ret != PM_RET_SUCCESS) {
95 ERROR("Failed to power down CPU %d\n", cpu_id);
96 }
97 err:
98 return;
99 }
100
101 /**
102 * versal2_system_reset() - Send the reset request to firmware for the
103 * system to reset. This function does not
104 * return as it resets system.
105 */
versal2_system_reset(void)106 static void __dead2 versal2_system_reset(void)
107 {
108 uint32_t timeout = 10000U;
109 enum pm_ret_status pm_ret;
110 int32_t ret;
111
112 request_cpu_pwrdwn();
113
114 /*
115 * Send the system reset request to the firmware if power down request
116 * is not received from firmware.
117 */
118 if (pm_pwrdwn_req_status() == false) {
119 /*
120 * TODO: shutdown scope for this reset needs be revised once
121 * we have a clearer understanding of the overall reset scoping
122 * including the implementation of SYSTEM_RESET2.
123 */
124 pm_ret = pm_system_shutdown(XPM_SHUTDOWN_TYPE_RESET,
125 pm_get_shutdown_scope(), NON_SECURE);
126
127 if (pm_ret != PM_RET_SUCCESS) {
128 WARN("System shutdown failed\n");
129 }
130
131 /*
132 * Wait for system shutdown request completed and idle callback
133 * not received.
134 */
135 do {
136 ret = ipi_mb_enquire_status(primary_proc->ipi->local_ipi_id,
137 primary_proc->ipi->remote_ipi_id);
138 udelay(100);
139 timeout--;
140 } while ((ret != (int32_t)IPI_MB_STATUS_RECV_PENDING) && (timeout > 0U));
141 }
142
143 (void)psci_cpu_off();
144
145 while (true) {
146 wfi();
147 }
148 }
149
150 /**
151 * versal2_pwr_domain_suspend() - Send request to PMC to suspend core.
152 * @target_state: Targeted state.
153 */
versal2_pwr_domain_suspend(const psci_power_state_t * target_state)154 static void versal2_pwr_domain_suspend(const psci_power_state_t *target_state)
155 {
156 const struct pm_proc *proc;
157 uint32_t cpu_id = plat_my_core_pos();
158 uint32_t state;
159 enum pm_ret_status ret;
160 size_t i;
161
162 proc = pm_get_proc(cpu_id);
163 if (proc == NULL) {
164 ERROR("Failed to get proc %d\n", cpu_id);
165 goto err;
166 }
167
168 for (i = 0; i <= PLAT_MAX_PWR_LVL; i++) {
169 VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
170 __func__, i, target_state->pwr_domain_state[i]);
171 }
172
173 plat_gic_cpuif_disable();
174
175 if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
176 plat_gic_save();
177 }
178
179 state = (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) ?
180 PM_STATE_SUSPEND_TO_RAM : PM_STATE_CPU_IDLE;
181
182 /* Send request to PMC to suspend this core */
183 ret = pm_self_suspend(proc->node_id, MAX_LATENCY, state, sec_entry,
184 NON_SECURE);
185
186 if (ret != PM_RET_SUCCESS) {
187 ERROR("Failed to power down CPU %d\n", cpu_id);
188 }
189
190 err:
191 return;
192 }
193
versal2_validate_ns_entrypoint(uint64_t ns_entrypoint)194 static int32_t versal2_validate_ns_entrypoint(uint64_t ns_entrypoint)
195 {
196 int32_t ret = PSCI_E_SUCCESS;
197 struct reserve_mem_range *rmr;
198 uint32_t index = 0, counter = 0;
199
200 rmr = get_reserved_entries_fdt(&counter);
201
202 VERBOSE("Validate ns_entry point %lx\n", ns_entrypoint);
203
204 if (counter != 0) {
205 while (index < counter) {
206 if ((ns_entrypoint >= rmr[index].base) &&
207 (ns_entrypoint <= rmr[index].size)) {
208 ret = PSCI_E_INVALID_ADDRESS;
209 break;
210 }
211 index++;
212 }
213 } else {
214 if ((ns_entrypoint >= BL31_BASE) && (ns_entrypoint <= BL31_LIMIT)) {
215 ret = PSCI_E_INVALID_ADDRESS;
216 }
217 }
218
219 return ret;
220 }
221
versal2_pwr_domain_on_finish(const psci_power_state_t * target_state)222 static void versal2_pwr_domain_on_finish(const psci_power_state_t *target_state)
223 {
224 (void)target_state;
225
226 /* Enable the gic cpu interface */
227 plat_gic_pcpu_init();
228
229 /* Program the gic per-cpu distributor or re-distributor interface */
230 plat_gic_cpuif_enable();
231 }
232
233 /**
234 * versal2_pwr_domain_suspend_finish() - Performs actions to finish
235 * suspend procedure.
236 * @target_state: Targeted state.
237 */
versal2_pwr_domain_suspend_finish(const psci_power_state_t * target_state)238 static void versal2_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
239 {
240 const struct pm_proc *proc;
241 uint32_t cpu_id = plat_my_core_pos();
242 size_t i;
243
244 proc = pm_get_proc(cpu_id);
245 if (proc == NULL) {
246 ERROR("Failed to get proc %d\n", cpu_id);
247 goto err;
248 }
249
250 for (i = 0; i <= PLAT_MAX_PWR_LVL; i++) {
251 VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
252 __func__, i, target_state->pwr_domain_state[i]);
253 }
254
255 /* Clear the APU power control register for this cpu */
256 pm_client_wakeup(proc);
257
258 /* APU was turned off, so restore GIC context */
259 if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
260 plat_gic_resume();
261 }
262
263 plat_gic_cpuif_enable();
264
265 err:
266 return;
267 }
268
269 /**
270 * versal2_system_off() - Send the system off request to firmware.
271 * This function does not return as it puts core into WFI
272 */
versal2_system_off(void)273 static void __dead2 versal2_system_off(void)
274 {
275 uint64_t timeout;
276 enum pm_ret_status ret;
277
278 request_cpu_pwrdwn();
279
280 /* Send the power down request to the PMC */
281 ret = pm_system_shutdown(XPM_SHUTDOWN_TYPE_SHUTDOWN,
282 pm_get_shutdown_scope(), NON_SECURE);
283
284 if (ret != PM_RET_SUCCESS) {
285 ERROR("System shutdown failed\n");
286 }
287
288 /*
289 * Wait for system shutdown request completed and idle callback
290 * not received.
291 */
292 timeout = timeout_init_us(IDLE_CB_WAIT_TIMEOUT);
293 do {
294 ret = ipi_mb_enquire_status(primary_proc->ipi->local_ipi_id,
295 primary_proc->ipi->remote_ipi_id);
296 udelay(100);
297 } while ((ret != (int32_t)IPI_MB_STATUS_RECV_PENDING) && !timeout_elapsed(timeout));
298
299 (void)psci_cpu_off();
300
301 while (true) {
302 wfi();
303 }
304 }
305
306 /**
307 * versal2_validate_power_state() - Ensure that the power state
308 * parameter in request is valid.
309 * @power_state: Power state of core.
310 * @req_state: Requested state.
311 *
312 * Return: Returns status, either PSCI_E_SUCCESS or reason.
313 */
versal2_validate_power_state(unsigned int power_state,psci_power_state_t * req_state)314 static int32_t versal2_validate_power_state(unsigned int power_state,
315 psci_power_state_t *req_state)
316 {
317 uint32_t pstate = psci_get_pstate_type(power_state);
318 int32_t ret = PSCI_E_SUCCESS;
319
320 VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
321
322 assert(req_state);
323
324 /* Sanity check the requested state */
325 if (pstate == PSTATE_TYPE_STANDBY) {
326 req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
327 } else {
328 req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE;
329 }
330
331 /* The 'state_id' is expected to be zero */
332 if (psci_get_pstate_id(power_state) != 0U) {
333 ret = PSCI_E_INVALID_PARAMS;
334 }
335
336 return ret;
337 }
338
339 /**
340 * versal2_get_sys_suspend_power_state() - Get power state for system
341 * suspend.
342 * @req_state: Requested state.
343 */
versal2_get_sys_suspend_power_state(psci_power_state_t * req_state)344 static void versal2_get_sys_suspend_power_state(psci_power_state_t *req_state)
345 {
346 uint64_t i;
347
348 for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) {
349 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
350 }
351 }
352
353 /**
354 * Export the platform specific power ops.
355 */
356 static const struct plat_psci_ops versal2_nopmc_psci_ops = {
357 .pwr_domain_on = versal2_pwr_domain_on,
358 .pwr_domain_off = versal2_pwr_domain_off,
359 .pwr_domain_on_finish = versal2_pwr_domain_on_finish,
360 .pwr_domain_suspend = versal2_pwr_domain_suspend,
361 .pwr_domain_suspend_finish = versal2_pwr_domain_suspend_finish,
362 .system_off = versal2_system_off,
363 .system_reset = versal2_system_reset,
364 .validate_ns_entrypoint = versal2_validate_ns_entrypoint,
365 .validate_power_state = versal2_validate_power_state,
366 .get_sys_suspend_power_state = versal2_get_sys_suspend_power_state,
367 };
368
plat_setup_psci_ops(uintptr_t sec_entrypoint,const struct plat_psci_ops ** psci_ops)369 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
370 const struct plat_psci_ops **psci_ops)
371 {
372 sec_entry = sec_entrypoint;
373
374 VERBOSE("Setting up entry point %lx\n", sec_entry);
375
376 *psci_ops = &versal2_nopmc_psci_ops;
377
378 return 0;
379 }
380
sip_svc_setup_init(void)381 int32_t sip_svc_setup_init(void)
382 {
383 return pm_setup();
384 }
385
smc_handler(uint32_t smc_fid,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,const void * cookie,void * handle,uint64_t flags)386 uint64_t smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4,
387 const void *cookie, void *handle, uint64_t flags)
388 {
389 return pm_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
390 }
391