1 /* 2 * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved. 3 * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved. 4 * 5 * SPDX-License-Identifier: BSD-3-Clause 6 */ 7 8 /* 9 * Versal system level PM-API functions and communication with PMC via 10 * IPI interrupts 11 */ 12 13 #include <pm_common.h> 14 #include <pm_ipi.h> 15 #include <plat/common/platform.h> 16 #include "pm_api_sys.h" 17 #include "pm_client.h" 18 #include "pm_defs.h" 19 #include "pm_svc_main.h" 20 21 /* default shutdown/reboot scope is system(2) */ 22 static uint32_t pm_shutdown_scope = XPM_SHUTDOWN_SUBTYPE_RST_SYSTEM; 23 24 /** 25 * pm_get_shutdown_scope() - Get the currently set shutdown scope 26 * 27 * @return Shutdown scope value 28 */ 29 uint32_t pm_get_shutdown_scope(void) 30 { 31 return pm_shutdown_scope; 32 } 33 34 /* PM API functions */ 35 36 /** 37 * pm_handle_eemi_call() - PM call for processor to send eemi payload 38 * @flag 0 - Call from secure source 39 * 1 - Call from non-secure source 40 * @x0 to x5 Arguments received per SMC64 standard 41 * @result Payload received from firmware 42 * 43 * @return PM_RET_SUCCESS on success or error code 44 */ 45 enum pm_ret_status pm_handle_eemi_call(uint32_t flag, uint32_t x0, uint32_t x1, 46 uint32_t x2, uint32_t x3, uint32_t x4, 47 uint32_t x5, uint64_t *result) 48 { 49 uint32_t payload[PAYLOAD_ARG_CNT] = {0}; 50 uint32_t module_id; 51 52 module_id = (x0 & MODULE_ID_MASK) >> 8U; 53 54 //default module id is for LIBPM 55 if (module_id == 0) { 56 module_id = LIBPM_MODULE_ID; 57 } 58 59 PM_PACK_PAYLOAD6(payload, module_id, flag, x0, x1, x2, x3, x4, x5); 60 return pm_ipi_send_sync(primary_proc, payload, (uint32_t *)result, PAYLOAD_ARG_CNT); 61 } 62 63 /** 64 * pm_self_suspend() - PM call for processor to suspend itself 65 * @nid Node id of the processor or subsystem 66 * @latency Requested maximum wakeup latency (not supported) 67 * @state Requested state 68 * @address Resume address 69 * @flag 0 - Call from secure source 70 * 1 - Call from non-secure source 71 * 72 * This is a blocking call, it will return only once PMU has responded. 73 * On a wakeup, resume address will be automatically set by PMU. 74 * 75 * @return Returns status, either success or error+reason 76 */ 77 enum pm_ret_status pm_self_suspend(uint32_t nid, 78 uint32_t latency, 79 uint32_t state, 80 uintptr_t address, uint32_t flag) 81 { 82 uint32_t payload[PAYLOAD_ARG_CNT]; 83 uint32_t cpuid = plat_my_core_pos(); 84 const struct pm_proc *proc = pm_get_proc(cpuid); 85 86 if (proc == NULL) { 87 WARN("Failed to get proc %d\n", cpuid); 88 return PM_RET_ERROR_INTERNAL; 89 } 90 91 /* 92 * Do client specific suspend operations 93 * (e.g. set powerdown request bit) 94 */ 95 pm_client_suspend(proc, state); 96 97 /* Send request to the PLM */ 98 PM_PACK_PAYLOAD6(payload, LIBPM_MODULE_ID, flag, PM_SELF_SUSPEND, 99 proc->node_id, latency, state, address, 100 (address >> 32)); 101 return pm_ipi_send_sync(proc, payload, NULL, 0); 102 } 103 104 /** 105 * pm_abort_suspend() - PM call to announce that a prior suspend request 106 * is to be aborted. 107 * @reason Reason for the abort 108 * @flag 0 - Call from secure source 109 * 1 - Call from non-secure source 110 * 111 * Calling PU expects the PMU to abort the initiated suspend procedure. 112 * This is a non-blocking call without any acknowledge. 113 * 114 * @return Returns status, either success or error+reason 115 */ 116 enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason, uint32_t flag) 117 { 118 uint32_t payload[PAYLOAD_ARG_CNT]; 119 120 /* 121 * Do client specific abort suspend operations 122 * (e.g. enable interrupts and clear powerdown request bit) 123 */ 124 pm_client_abort_suspend(); 125 126 /* Send request to the PLM */ 127 PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_ABORT_SUSPEND, 128 reason, primary_proc->node_id); 129 return pm_ipi_send_sync(primary_proc, payload, NULL, 0); 130 } 131 132 /** 133 * pm_req_suspend() - PM call to request for another PU or subsystem to 134 * be suspended gracefully. 135 * @target Node id of the targeted PU or subsystem 136 * @ack Flag to specify whether acknowledge is requested 137 * @latency Requested wakeup latency (not supported) 138 * @state Requested state (not supported) 139 * @flag 0 - Call from secure source 140 * 1 - Call from non-secure source 141 * 142 * @return Returns status, either success or error+reason 143 */ 144 enum pm_ret_status pm_req_suspend(uint32_t target, uint8_t ack, 145 uint32_t latency, uint32_t state, 146 uint32_t flag) 147 { 148 uint32_t payload[PAYLOAD_ARG_CNT]; 149 150 /* Send request to the PMU */ 151 PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, flag, PM_REQ_SUSPEND, target, 152 latency, state); 153 if (ack == IPI_BLOCKING) { 154 return pm_ipi_send_sync(primary_proc, payload, NULL, 0); 155 } else { 156 return pm_ipi_send(primary_proc, payload); 157 } 158 } 159 160 /** 161 * pm_req_wakeup() - PM call for processor to wake up selected processor 162 * or subsystem 163 * @target Device ID of the processor or subsystem to wake up 164 * @set_address Resume address presence indicator 165 * 1 - resume address specified, 0 - otherwise 166 * @address Resume address 167 * @ack Flag to specify whether acknowledge requested 168 * @flag 0 - Call from secure source 169 * 1 - Call from non-secure source 170 * 171 * This API function is either used to power up another APU core for SMP 172 * (by PSCI) or to power up an entirely different PU or subsystem, such 173 * as RPU0, RPU, or PL_CORE_xx. Resume address for the target PU will be 174 * automatically set by PMC. 175 * 176 * @return Returns status, either success or error+reason 177 */ 178 enum pm_ret_status pm_req_wakeup(uint32_t target, uint32_t set_address, 179 uintptr_t address, uint8_t ack, uint32_t flag) 180 { 181 uint32_t payload[PAYLOAD_ARG_CNT]; 182 183 /* Send request to the PMC to perform the wake of the PU */ 184 PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, flag, PM_REQ_WAKEUP, target, 185 set_address, address, ack); 186 187 return pm_ipi_send_sync(primary_proc, payload, NULL, 0); 188 } 189 190 /** 191 * pm_get_callbackdata() - Read from IPI response buffer 192 * @data - array of PAYLOAD_ARG_CNT elements 193 * @flag - 0 - Call from secure source 194 * 1 - Call from non-secure source 195 * @ack - 0 - Do not ack IPI after reading payload 196 * 1 - Ack IPI after reading payload 197 * 198 * Read value from ipi buffer response buffer. 199 * @return Returns status, either success or error 200 */ 201 enum pm_ret_status pm_get_callbackdata(uint32_t *data, size_t count, uint32_t flag, uint32_t ack) 202 { 203 enum pm_ret_status ret = PM_RET_SUCCESS; 204 /* Return if interrupt is not from PMU */ 205 if (pm_ipi_irq_status(primary_proc) == 0) { 206 return ret; 207 } 208 209 ret = pm_ipi_buff_read_callb(data, count); 210 211 if (ack != 0U) { 212 pm_ipi_irq_clear(primary_proc); 213 } 214 215 return ret; 216 } 217 218 /** 219 * pm_pll_set_param() - Set PLL parameter 220 * 221 * This API is deprecated and maintained here for backward compatibility. 222 * New use of this API should be avoided for versal platform. 223 * This API and its use cases will be removed for versal platform. 224 * 225 * @clk_id PLL clock ID 226 * @param PLL parameter ID 227 * @value Value to set for PLL parameter 228 * @flag 0 - Call from secure source 229 * 1 - Call from non-secure source 230 * 231 * @return Returns status, either success or error+reason 232 */ 233 enum pm_ret_status pm_pll_set_param(uint32_t clk_id, uint32_t param, 234 uint32_t value, uint32_t flag) 235 { 236 uint32_t payload[PAYLOAD_ARG_CNT]; 237 238 /* Send request to the PMC */ 239 PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, flag, PM_PLL_SET_PARAMETER, 240 clk_id, param, value); 241 242 return pm_ipi_send_sync(primary_proc, payload, NULL, 0); 243 } 244 245 /** 246 * pm_pll_get_param() - Get PLL parameter value 247 * 248 * This API is deprecated and maintained here for backward compatibility. 249 * New use of this API should be avoided for versal platform. 250 * This API and its use cases will be removed for versal platform. 251 * 252 * @clk_id PLL clock ID 253 * @param PLL parameter ID 254 * @value: Buffer to store PLL parameter value 255 * @flag 0 - Call from secure source 256 * 1 - Call from non-secure source 257 * 258 * @return Returns status, either success or error+reason 259 */ 260 enum pm_ret_status pm_pll_get_param(uint32_t clk_id, uint32_t param, 261 uint32_t *value, uint32_t flag) 262 { 263 uint32_t payload[PAYLOAD_ARG_CNT]; 264 265 /* Send request to the PMC */ 266 PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_PLL_GET_PARAMETER, 267 clk_id, param); 268 269 return pm_ipi_send_sync(primary_proc, payload, value, 1); 270 } 271 272 /** 273 * pm_pll_set_mode() - Set PLL mode 274 * 275 * This API is deprecated and maintained here for backward compatibility. 276 * New use of this API should be avoided for versal platform. 277 * This API and its use cases will be removed for versal platform. 278 * 279 * @clk_id PLL clock ID 280 * @mode PLL mode 281 * @flag 0 - Call from secure source 282 * 1 - Call from non-secure source 283 * 284 * @return Returns status, either success or error+reason 285 */ 286 enum pm_ret_status pm_pll_set_mode(uint32_t clk_id, uint32_t mode, 287 uint32_t flag) 288 { 289 uint32_t payload[PAYLOAD_ARG_CNT]; 290 291 /* Send request to the PMC */ 292 PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_PLL_SET_MODE, 293 clk_id, mode); 294 295 return pm_ipi_send_sync(primary_proc, payload, NULL, 0); 296 } 297 298 /** 299 * pm_pll_get_mode() - Get PLL mode 300 * 301 * This API is deprecated and maintained here for backward compatibility. 302 * New use of this API should be avoided for versal platform. 303 * This API and its use cases will be removed for versal platform. 304 * 305 * @clk_id PLL clock ID 306 * @mode: Buffer to store PLL mode 307 * @flag 0 - Call from secure source 308 * 1 - Call from non-secure source 309 * 310 * @return Returns status, either success or error+reason 311 */ 312 enum pm_ret_status pm_pll_get_mode(uint32_t clk_id, uint32_t *mode, 313 uint32_t flag) 314 { 315 uint32_t payload[PAYLOAD_ARG_CNT]; 316 317 /* Send request to the PMC */ 318 PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag, PM_PLL_GET_MODE, 319 clk_id); 320 321 return pm_ipi_send_sync(primary_proc, payload, mode, 1); 322 } 323 324 /** 325 * pm_force_powerdown() - PM call to request for another PU or subsystem to 326 * be powered down forcefully 327 * @target Device ID of the PU node to be forced powered down. 328 * @ack Flag to specify whether acknowledge is requested 329 * @flag 0 - Call from secure source 330 * 1 - Call from non-secure source 331 * 332 * @return Returns status, either success or error+reason 333 */ 334 enum pm_ret_status pm_force_powerdown(uint32_t target, uint8_t ack, 335 uint32_t flag) 336 { 337 uint32_t payload[PAYLOAD_ARG_CNT]; 338 339 /* Send request to the PMC */ 340 PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_FORCE_POWERDOWN, 341 target, ack); 342 343 if (ack == IPI_BLOCKING) { 344 return pm_ipi_send_sync(primary_proc, payload, NULL, 0); 345 } else { 346 return pm_ipi_send(primary_proc, payload); 347 } 348 } 349 350 /** 351 * pm_system_shutdown() - PM call to request a system shutdown or restart 352 * @type Shutdown or restart? 0=shutdown, 1=restart, 2=setscope 353 * @subtype Scope: 0=APU-subsystem, 1=PS, 2=system 354 * @flag 0 - Call from secure source 355 * 1 - Call from non-secure source 356 * 357 * @return Returns status, either success or error+reason 358 */ 359 enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype, 360 uint32_t flag) 361 { 362 uint32_t payload[PAYLOAD_ARG_CNT]; 363 364 if (type == XPM_SHUTDOWN_TYPE_SETSCOPE_ONLY) { 365 /* Setting scope for subsequent PSCI reboot or shutdown */ 366 pm_shutdown_scope = subtype; 367 return PM_RET_SUCCESS; 368 } 369 370 /* Send request to the PMC */ 371 PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_SYSTEM_SHUTDOWN, 372 type, subtype); 373 374 return pm_ipi_send_non_blocking(primary_proc, payload); 375 } 376 377 /** 378 * pm_query_data() - PM API for querying firmware data 379 * 380 * This API is deprecated and maintained here for backward compatibility. 381 * New use of this API should be avoided for versal platform. 382 * This API and its use cases will be removed for versal platform. 383 * 384 * @qid The type of data to query 385 * @arg1 Argument 1 to requested query data call 386 * @arg2 Argument 2 to requested query data call 387 * @arg3 Argument 3 to requested query data call 388 * @data Returned output data 389 * @flag 0 - Call from secure source 390 * 1 - Call from non-secure source 391 * 392 * @retur - 0 if success else non-zero error code of type 393 * enum pm_ret_status 394 */ 395 enum pm_ret_status pm_query_data(uint32_t qid, uint32_t arg1, uint32_t arg2, 396 uint32_t arg3, uint32_t *data, uint32_t flag) 397 { 398 uint32_t ret; 399 uint32_t version[PAYLOAD_ARG_CNT] = {0}; 400 uint32_t payload[PAYLOAD_ARG_CNT]; 401 uint32_t fw_api_version; 402 403 /* Send request to the PMC */ 404 PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, flag, PM_QUERY_DATA, qid, 405 arg1, arg2, arg3); 406 407 ret = pm_feature_check(PM_QUERY_DATA, &version[0], flag); 408 if (ret == PM_RET_SUCCESS) { 409 fw_api_version = version[0] & 0xFFFFU; 410 if ((fw_api_version == 2U) && 411 ((qid == XPM_QID_CLOCK_GET_NAME) || 412 (qid == XPM_QID_PINCTRL_GET_FUNCTION_NAME))) { 413 ret = pm_ipi_send_sync(primary_proc, payload, data, PAYLOAD_ARG_CNT); 414 if (ret == PM_RET_SUCCESS) { 415 ret = data[0]; 416 data[0] = data[1]; 417 data[1] = data[2]; 418 data[2] = data[3]; 419 } 420 } else { 421 ret = pm_ipi_send_sync(primary_proc, payload, data, PAYLOAD_ARG_CNT); 422 } 423 } 424 return ret; 425 } 426 /** 427 * pm_api_ioctl() - PM IOCTL API for device control and configs 428 * 429 * This API is deprecated and maintained here for backward compatibility. 430 * New use of this API should be avoided for versal platform. 431 * This API and its use cases will be removed for versal platform. 432 * 433 * @device_id Device ID 434 * @ioctl_id ID of the requested IOCTL 435 * @arg1 Argument 1 to requested IOCTL call 436 * @arg2 Argument 2 to requested IOCTL call 437 * @arg3 Argument 3 to requested IOCTL call 438 * @value Returned output value 439 * @flag 0 - Call from secure source 440 * 1 - Call from non-secure source 441 * 442 * This function calls IOCTL to firmware for device control and configuration. 443 * 444 * @return Returns status, either 0 on success or non-zero error code 445 * of type enum pm_ret_status 446 */ 447 enum pm_ret_status pm_api_ioctl(uint32_t device_id, uint32_t ioctl_id, 448 uint32_t arg1, uint32_t arg2, uint32_t arg3, 449 uint32_t *value, uint32_t flag) 450 { 451 enum pm_ret_status ret; 452 453 switch (ioctl_id) { 454 case IOCTL_SET_PLL_FRAC_MODE: 455 ret = pm_pll_set_mode(arg1, arg2, flag); 456 break; 457 case IOCTL_GET_PLL_FRAC_MODE: 458 ret = pm_pll_get_mode(arg1, value, flag); 459 break; 460 case IOCTL_SET_PLL_FRAC_DATA: 461 ret = pm_pll_set_param(arg1, PM_PLL_PARAM_DATA, arg2, flag); 462 break; 463 case IOCTL_GET_PLL_FRAC_DATA: 464 ret = pm_pll_get_param(arg1, PM_PLL_PARAM_DATA, value, flag); 465 break; 466 case IOCTL_SET_SGI: 467 /* Get the sgi number */ 468 ret = pm_register_sgi(arg1, arg2); 469 if (ret != 0) { 470 return PM_RET_ERROR_ARGS; 471 } 472 ret = PM_RET_SUCCESS; 473 break; 474 default: 475 return PM_RET_ERROR_NOTSUPPORTED; 476 } 477 478 return ret; 479 } 480 481 /** 482 * pm_set_wakeup_source() - PM call to specify the wakeup source while suspended 483 * @target Device id of the targeted PU or subsystem 484 * @wkup_node Device id of the wakeup peripheral 485 * @enable Enable or disable the specified peripheral as wake source 486 * @flag 0 - Call from secure source 487 * 1 - Call from non-secure source 488 * 489 * @return Returns status, either success or error+reason 490 */ 491 enum pm_ret_status pm_set_wakeup_source(uint32_t target, uint32_t wkup_device, 492 uint8_t enable, uint32_t flag) 493 { 494 uint32_t payload[PAYLOAD_ARG_CNT]; 495 496 PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, flag, PM_SET_WAKEUP_SOURCE, 497 target, wkup_device, enable); 498 return pm_ipi_send_sync(primary_proc, payload, NULL, 0); 499 } 500 501 /** 502 * pm_feature_check() - Returns the supported API version if supported 503 * @api_id API ID to check 504 * @flag 0 - Call from secure source 505 * 1 - Call from non-secure source 506 * @ret_payload pointer to array of PAYLOAD_ARG_CNT number of 507 * words Returned supported API version and bitmasks 508 * for IOCTL and QUERY ID 509 * 510 * @return Returns status, either success or error+reason 511 */ 512 enum pm_ret_status pm_feature_check(uint32_t api_id, uint32_t *ret_payload, 513 uint32_t flag) 514 { 515 uint32_t payload[PAYLOAD_ARG_CNT]; 516 uint32_t module_id; 517 518 /* Return version of API which are implemented in ATF only */ 519 switch (api_id) { 520 case PM_GET_CALLBACK_DATA: 521 case PM_GET_TRUSTZONE_VERSION: 522 ret_payload[0] = PM_API_VERSION_2; 523 return PM_RET_SUCCESS; 524 case TF_A_PM_REGISTER_SGI: 525 ret_payload[0] = PM_API_BASE_VERSION; 526 return PM_RET_SUCCESS; 527 default: 528 break; 529 } 530 531 module_id = (api_id & MODULE_ID_MASK) >> 8U; 532 533 /* 534 * feature check should be done only for LIBPM module 535 * If module_id is 0, then we consider it LIBPM module as default id 536 */ 537 if ((module_id > 0) && (module_id != LIBPM_MODULE_ID)) { 538 return PM_RET_SUCCESS; 539 } 540 541 PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag, 542 PM_FEATURE_CHECK, api_id); 543 return pm_ipi_send_sync(primary_proc, payload, ret_payload, PAYLOAD_ARG_CNT); 544 } 545 546 /** 547 * pm_load_pdi() - Load the PDI 548 * 549 * This function provides support to load PDI from linux 550 * 551 * src: Source device of pdi(DDR, OCM, SD etc) 552 * address_low: lower 32-bit Linear memory space address 553 * address_high: higher 32-bit Linear memory space address 554 * @flag 0 - Call from secure source 555 * 1 - Call from non-secure source 556 * 557 * @return Returns status, either success or error+reason 558 */ 559 enum pm_ret_status pm_load_pdi(uint32_t src, uint32_t address_low, 560 uint32_t address_high, uint32_t flag) 561 { 562 uint32_t payload[PAYLOAD_ARG_CNT]; 563 564 /* Send request to the PMU */ 565 PM_PACK_PAYLOAD4(payload, LOADER_MODULE_ID, flag, PM_LOAD_PDI, src, 566 address_high, address_low); 567 return pm_ipi_send_sync(primary_proc, payload, NULL, 0); 568 } 569 570 /** 571 * pm_register_notifier() - PM call to register a subsystem to be notified 572 * about the device event 573 * @device_id Device ID for the Node to which the event is related 574 * @event Event in question 575 * @wake Wake subsystem upon capturing the event if value 1 576 * @enable Enable the registration for value 1, disable for value 0 577 * @flag 0 - Call from secure source 578 * 1 - Call from non-secure source 579 * 580 * @return Returns status, either success or error+reason 581 */ 582 enum pm_ret_status pm_register_notifier(uint32_t device_id, uint32_t event, 583 uint32_t wake, uint32_t enable, 584 uint32_t flag) 585 { 586 uint32_t payload[PAYLOAD_ARG_CNT]; 587 588 /* Send request to the PMC */ 589 PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, flag, PM_REGISTER_NOTIFIER, 590 device_id, event, wake, enable); 591 592 return pm_ipi_send_sync(primary_proc, payload, NULL, 0); 593 } 594