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 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 */ 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 */ 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 */ 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 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 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 */ 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 */ 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 */ 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 */ 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 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 381 int32_t sip_svc_setup_init(void) 382 { 383 return pm_setup(); 384 } 385 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