1 /*
2 * Copyright (c) 2022, Xilinx, Inc. All rights reserved.
3 * Copyright (c) 2022-2026, 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 (uint32_t)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 uint32_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(), (uint32_t)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 != 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 (uint32_t)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 != 0U) {
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 uint32_t uret;
276 uint64_t timeout;
277 enum pm_ret_status ret;
278
279 request_cpu_pwrdwn();
280
281 /* Send the power down request to the PMC */
282 ret = pm_system_shutdown(XPM_SHUTDOWN_TYPE_SHUTDOWN,
283 pm_get_shutdown_scope(), (uint32_t)NON_SECURE);
284
285 if (ret != PM_RET_SUCCESS) {
286 ERROR("System shutdown failed\n");
287 }
288
289 /*
290 * Wait for system shutdown request completed and idle callback
291 * not received.
292 */
293 timeout = timeout_init_us(IDLE_CB_WAIT_TIMEOUT);
294 do {
295 uret = ipi_mb_enquire_status(primary_proc->ipi->local_ipi_id,
296 primary_proc->ipi->remote_ipi_id);
297 udelay(100);
298 } while ((uret != IPI_MB_STATUS_RECV_PENDING) && !timeout_elapsed(timeout));
299
300 (void)psci_cpu_off();
301
302 while (true) {
303 wfi();
304 }
305 }
306
307 /**
308 * versal2_validate_power_state() - Ensure that the power state
309 * parameter in request is valid.
310 * @power_state: Power state of core.
311 * @req_state: Requested state.
312 *
313 * Return: Returns status, either PSCI_E_SUCCESS or reason.
314 */
versal2_validate_power_state(unsigned int power_state,psci_power_state_t * req_state)315 static int32_t versal2_validate_power_state(unsigned int power_state,
316 psci_power_state_t *req_state)
317 {
318 uint32_t pstate = psci_get_pstate_type(power_state);
319 int32_t ret = PSCI_E_SUCCESS;
320
321 VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
322
323 assert(req_state);
324
325 /* Sanity check the requested state */
326 if (pstate == PSTATE_TYPE_STANDBY) {
327 req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
328 } else {
329 req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE;
330 }
331
332 /* The 'state_id' is expected to be zero */
333 if (psci_get_pstate_id(power_state) != 0U) {
334 ret = PSCI_E_INVALID_PARAMS;
335 }
336
337 return ret;
338 }
339
340 /**
341 * versal2_get_sys_suspend_power_state() - Get power state for system
342 * suspend.
343 * @req_state: Requested state.
344 */
versal2_get_sys_suspend_power_state(psci_power_state_t * req_state)345 static void versal2_get_sys_suspend_power_state(psci_power_state_t *req_state)
346 {
347 uint64_t i;
348
349 for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) {
350 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
351 }
352 }
353
354 /**
355 * Export the platform specific power ops.
356 */
357 static const struct plat_psci_ops versal2_nopmc_psci_ops = {
358 .pwr_domain_on = versal2_pwr_domain_on,
359 .pwr_domain_off = versal2_pwr_domain_off,
360 .pwr_domain_on_finish = versal2_pwr_domain_on_finish,
361 .pwr_domain_suspend = versal2_pwr_domain_suspend,
362 .pwr_domain_suspend_finish = versal2_pwr_domain_suspend_finish,
363 .system_off = versal2_system_off,
364 .system_reset = versal2_system_reset,
365 .validate_ns_entrypoint = versal2_validate_ns_entrypoint,
366 .validate_power_state = versal2_validate_power_state,
367 .get_sys_suspend_power_state = versal2_get_sys_suspend_power_state,
368 };
369
plat_setup_psci_ops(uintptr_t sec_entrypoint,const struct plat_psci_ops ** psci_ops)370 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
371 const struct plat_psci_ops **psci_ops)
372 {
373 sec_entry = sec_entrypoint;
374
375 VERBOSE("Setting up entry point %lx\n", sec_entry);
376
377 *psci_ops = &versal2_nopmc_psci_ops;
378
379 return 0;
380 }
381
sip_svc_setup_init(void)382 int32_t sip_svc_setup_init(void)
383 {
384 return pm_setup();
385 }
386
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)387 uint64_t smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4,
388 const void *cookie, void *handle, uint64_t flags)
389 {
390 return pm_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
391 }
392