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 * Top-level SMC handler for Versal power management calls and 10 * IPI setup functions for communication with PMC. 11 */ 12 13 #include <errno.h> 14 #include <stdbool.h> 15 16 #include "../drivers/arm/gic/v3/gicv3_private.h" 17 18 #include <common/runtime_svc.h> 19 #include <drivers/arm/gicv3.h> 20 #include <plat/common/platform.h> 21 22 #include <plat_private.h> 23 #include "pm_api_sys.h" 24 #include "pm_client.h" 25 #include "pm_ipi.h" 26 #include "pm_svc_main.h" 27 28 #define MODE 0x80000000U 29 30 #define XSCUGIC_SGIR_EL1_INITID_SHIFT 24U 31 #define INVALID_SGI 0xFFU 32 #define PM_INIT_SUSPEND_CB (30U) 33 #define PM_NOTIFY_CB (32U) 34 #define EVENT_CPU_PWRDWN (4U) 35 DEFINE_RENAME_SYSREG_RW_FUNCS(icc_asgi1r_el1, S3_0_C12_C11_6) 36 37 /* pm_up = true - UP, pm_up = false - DOWN */ 38 static bool pm_up; 39 static uint32_t sgi = (uint32_t)INVALID_SGI; 40 static bool pwrdwn_req_received; 41 42 static void notify_os(void) 43 { 44 int32_t cpu; 45 uint32_t reg; 46 47 cpu = plat_my_core_pos() + 1U; 48 49 reg = (cpu | (sgi << XSCUGIC_SGIR_EL1_INITID_SHIFT)); 50 write_icc_asgi1r_el1(reg); 51 } 52 53 static void request_cpu_pwrdwn(void) 54 { 55 VERBOSE("CPU power down request received\n"); 56 pm_ipi_irq_clear(primary_proc); 57 } 58 59 static uint64_t ipi_fiq_handler(uint32_t id, uint32_t flags, void *handle, 60 void *cookie) 61 { 62 uint32_t payload[4] = {0}; 63 enum pm_ret_status ret; 64 65 VERBOSE("Received IPI FIQ from firmware\n"); 66 67 (void)plat_ic_acknowledge_interrupt(); 68 69 ret = pm_get_callbackdata(payload, ARRAY_SIZE(payload), 0, 0); 70 if (ret != PM_RET_SUCCESS) { 71 payload[0] = ret; 72 } 73 74 switch (payload[0]) { 75 case PM_INIT_SUSPEND_CB: 76 if (sgi != INVALID_SGI) { 77 notify_os(); 78 } 79 break; 80 case PM_NOTIFY_CB: 81 if (sgi != INVALID_SGI) { 82 if (payload[2] == EVENT_CPU_PWRDWN) { 83 if (pwrdwn_req_received) { 84 pwrdwn_req_received = false; 85 request_cpu_pwrdwn(); 86 break; 87 } else { 88 pwrdwn_req_received = true; 89 } 90 } 91 notify_os(); 92 } 93 break; 94 case PM_RET_ERROR_INVALID_CRC: 95 pm_ipi_irq_clear(primary_proc); 96 WARN("Invalid CRC in the payload\n"); 97 break; 98 99 default: 100 pm_ipi_irq_clear(primary_proc); 101 WARN("Invalid IPI payload\n"); 102 break; 103 } 104 105 /* Clear FIQ */ 106 plat_ic_end_of_interrupt(id); 107 108 return 0; 109 } 110 111 /** 112 * pm_register_sgi() - PM register the IPI interrupt. 113 * @sgi_num: SGI number to be used for communication. 114 * @reset: Reset to invalid SGI when reset=1. 115 * 116 * Return: On success, the initialization function must return 0. 117 * Any other return value will cause the framework to ignore 118 * the service. 119 * 120 * Update the SGI number to be used. 121 * 122 */ 123 int32_t pm_register_sgi(uint32_t sgi_num, uint32_t reset) 124 { 125 if (reset == 1U) { 126 sgi = INVALID_SGI; 127 return 0; 128 } 129 130 if (sgi != INVALID_SGI) { 131 return -EBUSY; 132 } 133 134 if (sgi_num >= GICV3_MAX_SGI_TARGETS) { 135 return -EINVAL; 136 } 137 138 sgi = (uint32_t)sgi_num; 139 return 0; 140 } 141 142 /** 143 * pm_setup() - PM service setup. 144 * 145 * Return: On success, the initialization function must return 0. 146 * Any other return value will cause the framework to ignore 147 * the service. 148 * 149 * Initialization functions for Versal power management for 150 * communicaton with PMC. 151 * 152 * Called from sip_svc_setup initialization function with the 153 * rt_svc_init signature. 154 * 155 */ 156 int32_t pm_setup(void) 157 { 158 int32_t ret = 0; 159 160 pm_ipi_init(primary_proc); 161 pm_up = true; 162 163 /* 164 * Enable IPI IRQ 165 * assume the rich OS is OK to handle callback IRQs now. 166 * Even if we were wrong, it would not enable the IRQ in 167 * the GIC. 168 */ 169 pm_ipi_irq_enable(primary_proc); 170 171 ret = request_intr_type_el3(PLAT_VERSAL_IPI_IRQ, ipi_fiq_handler); 172 if (ret != 0) { 173 WARN("BL31: registering IPI interrupt failed\n"); 174 } 175 176 gicd_write_irouter(gicv3_driver_data->gicd_base, PLAT_VERSAL_IPI_IRQ, MODE); 177 return ret; 178 } 179 180 /** 181 * eemi_for_compatibility() - EEMI calls handler for deprecated calls. 182 * @api_id: identifier for the API being called. 183 * @pm_arg: pointer to the argument data for the API call. 184 * @handle: Pointer to caller's context structure. 185 * @security_flag: SECURE_FLAG or NON_SECURE_FLAG. 186 * 187 * Return: If EEMI API found then, uintptr_t type address, else 0. 188 * 189 * Some EEMI API's use case needs to be changed in Linux driver, so they 190 * can take advantage of common EEMI handler in TF-A. As of now the old 191 * implementation of these APIs are required to maintain backward compatibility 192 * until their use case in linux driver changes. 193 * 194 */ 195 static uintptr_t eemi_for_compatibility(uint32_t api_id, uint32_t *pm_arg, 196 void *handle, uint32_t security_flag) 197 { 198 enum pm_ret_status ret; 199 200 switch (api_id) { 201 202 case (uint32_t)PM_IOCTL: 203 { 204 uint32_t value = 0U; 205 206 ret = pm_api_ioctl(pm_arg[0], pm_arg[1], pm_arg[2], 207 pm_arg[3], pm_arg[4], 208 &value, security_flag); 209 if (ret == PM_RET_ERROR_NOTSUPPORTED) 210 return (uintptr_t)0; 211 212 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U); 213 } 214 215 case (uint32_t)PM_QUERY_DATA: 216 { 217 uint32_t data[PAYLOAD_ARG_CNT] = { 0 }; 218 219 ret = pm_query_data(pm_arg[0], pm_arg[1], pm_arg[2], 220 pm_arg[3], data, security_flag); 221 222 SMC_RET2(handle, (uint64_t)ret | ((uint64_t)data[0] << 32U), 223 (uint64_t)data[1] | ((uint64_t)data[2] << 32U)); 224 } 225 226 case (uint32_t)PM_FEATURE_CHECK: 227 { 228 uint32_t result[PAYLOAD_ARG_CNT] = {0U}; 229 230 ret = pm_feature_check(pm_arg[0], result, security_flag); 231 SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U), 232 (uint64_t)result[1] | ((uint64_t)result[2] << 32U)); 233 } 234 235 case PM_LOAD_PDI: 236 { 237 ret = pm_load_pdi(pm_arg[0], pm_arg[1], pm_arg[2], 238 security_flag); 239 SMC_RET1(handle, (uint64_t)ret); 240 } 241 242 default: 243 return (uintptr_t)0; 244 } 245 } 246 247 /** 248 * eemi_psci_debugfs_handler() - EEMI API invoked from PSCI. 249 * @api_id: identifier for the API being called. 250 * @pm_arg: pointer to the argument data for the API call. 251 * @handle: Pointer to caller's context structure. 252 * @security_flag: SECURE_FLAG or NON_SECURE_FLAG. 253 * 254 * These EEMI APIs performs CPU specific power management tasks. 255 * These EEMI APIs are invoked either from PSCI or from debugfs in kernel. 256 * These calls require CPU specific processing before sending IPI request to 257 * Platform Management Controller. For example enable/disable CPU specific 258 * interrupts. This requires separate handler for these calls and may not be 259 * handled using common eemi handler. 260 * 261 * Return: If EEMI API found then, uintptr_t type address, else 0. 262 * 263 */ 264 static uintptr_t eemi_psci_debugfs_handler(uint32_t api_id, uint32_t *pm_arg, 265 void *handle, uint32_t security_flag) 266 { 267 enum pm_ret_status ret; 268 269 switch (api_id) { 270 271 case (uint32_t)PM_SELF_SUSPEND: 272 ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2], 273 pm_arg[3], security_flag); 274 SMC_RET1(handle, (u_register_t)ret); 275 276 case (uint32_t)PM_FORCE_POWERDOWN: 277 ret = pm_force_powerdown(pm_arg[0], pm_arg[1], security_flag); 278 SMC_RET1(handle, (u_register_t)ret); 279 280 case (uint32_t)PM_REQ_SUSPEND: 281 ret = pm_req_suspend(pm_arg[0], pm_arg[1], pm_arg[2], 282 pm_arg[3], security_flag); 283 SMC_RET1(handle, (u_register_t)ret); 284 285 case (uint32_t)PM_ABORT_SUSPEND: 286 ret = pm_abort_suspend(pm_arg[0], security_flag); 287 SMC_RET1(handle, (u_register_t)ret); 288 289 case (uint32_t)PM_SYSTEM_SHUTDOWN: 290 ret = pm_system_shutdown(pm_arg[0], pm_arg[1], security_flag); 291 SMC_RET1(handle, (u_register_t)ret); 292 293 default: 294 return (uintptr_t)0; 295 } 296 } 297 298 /** 299 * TF_A_specific_handler() - SMC handler for TF-A specific functionality. 300 * @api_id: identifier for the API being called. 301 * @pm_arg: pointer to the argument data for the API call. 302 * @handle: Pointer to caller's context structure. 303 * @security_flag: SECURE_FLAG or NON_SECURE_FLAG. 304 * 305 * These EEMI calls performs functionality that does not require 306 * IPI transaction. The handler ends in TF-A and returns requested data to 307 * kernel from TF-A. 308 * 309 * Return: If TF-A specific API found then, uintptr_t type address, else 0 310 * 311 */ 312 static uintptr_t TF_A_specific_handler(uint32_t api_id, uint32_t *pm_arg, 313 void *handle, uint32_t security_flag) 314 { 315 switch (api_id) { 316 317 case TF_A_PM_REGISTER_SGI: 318 { 319 int32_t ret; 320 321 ret = pm_register_sgi(pm_arg[0], pm_arg[1]); 322 if (ret != 0) { 323 SMC_RET1(handle, (uint32_t)PM_RET_ERROR_ARGS); 324 } 325 326 SMC_RET1(handle, (uint32_t)PM_RET_SUCCESS); 327 } 328 329 case PM_GET_CALLBACK_DATA: 330 { 331 uint32_t result[4] = {0}; 332 enum pm_ret_status ret; 333 334 ret = pm_get_callbackdata(result, ARRAY_SIZE(result), security_flag, 1U); 335 if (ret != 0) { 336 result[0] = ret; 337 } 338 339 SMC_RET2(handle, 340 (uint64_t)result[0] | ((uint64_t)result[1] << 32U), 341 (uint64_t)result[2] | ((uint64_t)result[3] << 32U)); 342 } 343 344 case PM_GET_TRUSTZONE_VERSION: 345 SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS | 346 ((uint64_t)TZ_VERSION << 32U)); 347 348 default: 349 return (uintptr_t)0; 350 } 351 } 352 353 /** 354 * eemi_handler() - Prepare EEMI payload and perform IPI transaction. 355 * @api_id: identifier for the API being called. 356 * @pm_arg: pointer to the argument data for the API call. 357 * @handle: Pointer to caller's context structure. 358 * @security_flag: SECURE_FLAG or NON_SECURE_FLAG. 359 * 360 * EEMI - Embedded Energy Management Interface is Xilinx proprietary protocol 361 * to allow communication between power management controller and different 362 * processing clusters. 363 * 364 * This handler prepares EEMI protocol payload received from kernel and performs 365 * IPI transaction. 366 * 367 * Return: If EEMI API found then, uintptr_t type address, else 0 368 * 369 */ 370 static uintptr_t eemi_handler(uint32_t api_id, uint32_t *pm_arg, 371 void *handle, uint32_t security_flag) 372 { 373 enum pm_ret_status ret; 374 uint32_t buf[PAYLOAD_ARG_CNT] = {0}; 375 376 ret = pm_handle_eemi_call(security_flag, api_id, pm_arg[0], pm_arg[1], 377 pm_arg[2], pm_arg[3], pm_arg[4], 378 (uint64_t *)buf); 379 /* 380 * Two IOCTLs, to get clock name and pinctrl name of pm_query_data API 381 * receives 5 words of respoonse from firmware. Currently linux driver can 382 * receive only 4 words from TF-A. So, this needs to be handled separately 383 * than other eemi calls. 384 */ 385 if (api_id == (uint32_t)PM_QUERY_DATA) { 386 if ((pm_arg[0] == XPM_QID_CLOCK_GET_NAME || 387 pm_arg[0] == XPM_QID_PINCTRL_GET_FUNCTION_NAME) && 388 ret == PM_RET_SUCCESS) { 389 SMC_RET2(handle, (uint64_t)buf[0] | ((uint64_t)buf[1] << 32U), 390 (uint64_t)buf[2] | ((uint64_t)buf[3] << 32U)); 391 } 392 } 393 394 SMC_RET2(handle, (uint64_t)ret | ((uint64_t)buf[0] << 32U), 395 (uint64_t)buf[1] | ((uint64_t)buf[2] << 32U)); 396 } 397 398 /** 399 * pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2. 400 * @smc_fid: Function Identifier. 401 * @x1: SMC64 Arguments from kernel. 402 * @x2: SMC64 Arguments from kernel. 403 * @x3: SMC64 Arguments from kernel (upper 32-bits). 404 * @x4: Unused. 405 * @cookie: Unused. 406 * @handle: Pointer to caller's context structure. 407 * @flags: SECURE_FLAG or NON_SECURE_FLAG. 408 * 409 * Return: Unused. 410 * 411 * Determines that smc_fid is valid and supported PM SMC Function ID from the 412 * list of pm_api_ids, otherwise completes the request with 413 * the unknown SMC Function ID. 414 * 415 * The SMC calls for PM service are forwarded from SIP Service SMC handler 416 * function with rt_svc_handle signature. 417 * 418 */ 419 uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, 420 uint64_t x4, const void *cookie, void *handle, uint64_t flags) 421 { 422 uintptr_t ret; 423 uint32_t pm_arg[PAYLOAD_ARG_CNT] = {0}; 424 uint32_t security_flag = NON_SECURE_FLAG; 425 uint32_t api_id; 426 bool status = false, status_tmp = false; 427 428 /* Handle case where PM wasn't initialized properly */ 429 if (pm_up == false) { 430 SMC_RET1(handle, SMC_UNK); 431 } 432 433 /* 434 * Mark BIT24 payload (i.e 1st bit of pm_arg[3] ) as secure (0) 435 * if smc called is secure 436 * 437 * Add redundant macro call to immune the code from glitches 438 */ 439 SECURE_REDUNDANT_CALL(status, status_tmp, is_caller_secure, flags); 440 if ((status != false) && (status_tmp != false)) { 441 security_flag = SECURE_FLAG; 442 } 443 444 pm_arg[0] = (uint32_t)x1; 445 pm_arg[1] = (uint32_t)(x1 >> 32U); 446 pm_arg[2] = (uint32_t)x2; 447 pm_arg[3] = (uint32_t)(x2 >> 32U); 448 pm_arg[4] = (uint32_t)x3; 449 (void)(x4); 450 api_id = smc_fid & FUNCID_NUM_MASK; 451 452 ret = eemi_for_compatibility(api_id, pm_arg, handle, security_flag); 453 if (ret != (uintptr_t)0) { 454 return ret; 455 } 456 457 ret = eemi_psci_debugfs_handler(api_id, pm_arg, handle, flags); 458 if (ret != (uintptr_t)0) { 459 return ret; 460 } 461 462 ret = TF_A_specific_handler(api_id, pm_arg, handle, security_flag); 463 if (ret != (uintptr_t)0) { 464 return ret; 465 } 466 467 ret = eemi_handler(api_id, pm_arg, handle, security_flag); 468 469 return ret; 470 } 471