1 /* 2 * Copyright (c) 2017-2025, Arm Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <string.h> 9 10 #include <arch_helpers.h> 11 #include <common/debug.h> 12 #include <drivers/arm/css/css_scp.h> 13 #include <drivers/arm/css/scmi.h> 14 #include <lib/mmio.h> 15 #include <plat/arm/common/plat_arm.h> 16 #include <plat/arm/css/common/css_pm.h> 17 #include <plat/common/platform.h> 18 #include <platform_def.h> 19 20 /* 21 * This file implements the SCP helper functions using SCMI protocol. 22 */ 23 24 /* 25 * SCMI power state parameter bit field encoding for ARM CSS platforms. 26 * 27 * 31 20 19 16 15 12 11 8 7 4 3 0 28 * +-------------------------------------------------------------+ 29 * | SBZ | Max level | Level 3 | Level 2 | Level 1 | Level 0 | 30 * | | | state | state | state | state | 31 * +-------------------------------------------------------------+ 32 * 33 * `Max level` encodes the highest level that has a valid power state 34 * encoded in the power state. 35 */ 36 #define SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT 16 37 #define SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH 4 38 #define SCMI_PWR_STATE_MAX_PWR_LVL_MASK \ 39 ((1 << SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH) - 1) 40 #define SCMI_SET_PWR_STATE_MAX_PWR_LVL(_power_state, _max_level) \ 41 (_power_state) |= ((_max_level) & SCMI_PWR_STATE_MAX_PWR_LVL_MASK)\ 42 << SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT 43 #define SCMI_GET_PWR_STATE_MAX_PWR_LVL(_power_state) \ 44 (((_power_state) >> SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT) \ 45 & SCMI_PWR_STATE_MAX_PWR_LVL_MASK) 46 47 #define SCMI_PWR_STATE_LVL_WIDTH 4 48 #define SCMI_PWR_STATE_LVL_MASK \ 49 ((1 << SCMI_PWR_STATE_LVL_WIDTH) - 1) 50 #define SCMI_SET_PWR_STATE_LVL(_power_state, _level, _level_state) \ 51 (_power_state) |= ((_level_state) & SCMI_PWR_STATE_LVL_MASK) \ 52 << (SCMI_PWR_STATE_LVL_WIDTH * (_level)) 53 #define SCMI_GET_PWR_STATE_LVL(_power_state, _level) \ 54 (((_power_state) >> (SCMI_PWR_STATE_LVL_WIDTH * (_level))) & \ 55 SCMI_PWR_STATE_LVL_MASK) 56 57 #if CSS_SCP_SUSPEND_GRACEFUL 58 #define CSS_SCP_SUSPEND_REQ_FLAG SCMI_SYS_PWR_GRACEFUL_REQ 59 #else 60 #define CSS_SCP_SUSPEND_REQ_FLAG SCMI_SYS_PWR_FORCEFUL_REQ 61 #endif 62 63 #if CSS_SCP_SYSTEM_OFF_GRACEFUL 64 #define CSS_SCP_SYSTEM_OFF_REQ_FLAG SCMI_SYS_PWR_GRACEFUL_REQ 65 #else 66 #define CSS_SCP_SYSTEM_OFF_REQ_FLAG SCMI_SYS_PWR_FORCEFUL_REQ 67 #endif 68 69 /* 70 * The SCMI power state enumeration for a power domain level 71 */ 72 typedef enum { 73 scmi_power_state_off = 0, 74 scmi_power_state_on = 1, 75 scmi_power_state_sleep = 2, 76 } scmi_power_state_t; 77 78 /* 79 * The global handles for invoking the SCMI driver APIs after the driver 80 * has been initialized. 81 */ 82 static void *scmi_handles[PLAT_ARM_SCMI_CHANNEL_COUNT]; 83 84 /* The global SCMI channels array */ 85 static scmi_channel_t scmi_channels[PLAT_ARM_SCMI_CHANNEL_COUNT]; 86 87 /* 88 * Channel ID for the default SCMI channel. 89 * The default channel is used to issue SYSTEM level SCMI requests and is 90 * initialized to the channel which has the boot cpu as its resource. 91 */ 92 static uint32_t default_scmi_channel_id; 93 94 /* 95 * TODO: Allow use of channel specific lock instead of using a single lock for 96 * all the channels. 97 */ 98 ARM_SCMI_INSTANTIATE_LOCK; 99 100 /* 101 * Function to obtain the SCMI Domain ID and SCMI Channel number from the linear 102 * core position. The SCMI Channel number is encoded in the upper 16 bits and 103 * the Domain ID is encoded in the lower 16 bits in each entry of the mapping 104 * array exported by the platform. 105 */ 106 static void css_scp_core_pos_to_scmi_channel(unsigned int core_pos, 107 unsigned int *scmi_domain_id, unsigned int *scmi_channel_id) 108 { 109 unsigned int composite_id; 110 111 composite_id = plat_css_core_pos_to_scmi_dmn_id_map[core_pos]; 112 113 *scmi_channel_id = GET_SCMI_CHANNEL_ID(composite_id); 114 *scmi_domain_id = GET_SCMI_DOMAIN_ID(composite_id); 115 } 116 117 static inline void css_scp_set_state_pwr_lvl(uint32_t *pwr_state, unsigned int lvl) 118 { 119 unsigned int max_lvl = (lvl == 0U) ? 0U : (lvl - 1U); 120 121 SCMI_SET_PWR_STATE_MAX_PWR_LVL(*pwr_state, max_lvl); 122 } 123 124 /* 125 * Helper function to suspend a CPU power domain and its parent power domains 126 * if applicable. 127 */ 128 void css_scp_suspend(const struct psci_power_state *target_state) 129 { 130 int ret; 131 132 /* At least power domain level 0 should be specified to be suspended */ 133 assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == 134 ARM_LOCAL_STATE_OFF); 135 136 /* Check if power down at system power domain level is requested */ 137 if (css_system_pwr_state(target_state) == ARM_LOCAL_STATE_OFF) { 138 /* Issue SCMI command for SYSTEM_SUSPEND on all SCMI channels */ 139 ret = scmi_sys_pwr_state_set( 140 scmi_handles[default_scmi_channel_id], 141 CSS_SCP_SUSPEND_REQ_FLAG, SCMI_SYS_PWR_SUSPEND); 142 if (ret != SCMI_E_SUCCESS) { 143 ERROR("SCMI system power domain suspend return 0x%x unexpected\n", 144 ret); 145 panic(); 146 } 147 return; 148 } 149 #if !HW_ASSISTED_COHERENCY 150 unsigned int lvl, channel_id, domain_id; 151 uint32_t scmi_pwr_state = 0; 152 /* 153 * If we reach here, then assert that power down at system power domain 154 * level is running. 155 */ 156 assert(css_system_pwr_state(target_state) == ARM_LOCAL_STATE_RUN); 157 158 /* For level 0, specify `scmi_power_state_sleep` as the power state */ 159 SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, ARM_PWR_LVL0, 160 scmi_power_state_sleep); 161 162 for (lvl = ARM_PWR_LVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) { 163 if (target_state->pwr_domain_state[lvl] == ARM_LOCAL_STATE_RUN) 164 break; 165 166 assert(target_state->pwr_domain_state[lvl] == 167 ARM_LOCAL_STATE_OFF); 168 /* 169 * Specify `scmi_power_state_off` as power state for higher 170 * levels. 171 */ 172 SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl, 173 scmi_power_state_off); 174 } 175 176 css_scp_set_state_pwr_lvl(&scmi_pwr_state, lvl); 177 178 css_scp_core_pos_to_scmi_channel(plat_my_core_pos(), 179 &domain_id, &channel_id); 180 ret = scmi_pwr_state_set(scmi_handles[channel_id], 181 domain_id, scmi_pwr_state); 182 183 if (ret != SCMI_E_SUCCESS) { 184 ERROR("SCMI set power state command return 0x%x unexpected\n", 185 ret); 186 panic(); 187 } 188 #endif 189 } 190 191 /* 192 * Helper function to turn off a CPU power domain and its parent power domains 193 * if applicable. 194 */ 195 void css_scp_off(const struct psci_power_state *target_state) 196 { 197 unsigned int lvl = 0, channel_id, domain_id; 198 int ret; 199 uint32_t scmi_pwr_state = 0; 200 201 /* At-least the CPU level should be specified to be OFF */ 202 assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == 203 ARM_LOCAL_STATE_OFF); 204 205 /* PSCI CPU OFF cannot be used to turn OFF system power domain */ 206 assert(css_system_pwr_state(target_state) == ARM_LOCAL_STATE_RUN); 207 208 for (; lvl <= PLAT_MAX_PWR_LVL; lvl++) { 209 if (target_state->pwr_domain_state[lvl] == ARM_LOCAL_STATE_RUN) 210 break; 211 212 assert(target_state->pwr_domain_state[lvl] == 213 ARM_LOCAL_STATE_OFF); 214 SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl, 215 scmi_power_state_off); 216 } 217 218 css_scp_set_state_pwr_lvl(&scmi_pwr_state, lvl); 219 220 css_scp_core_pos_to_scmi_channel(plat_my_core_pos(), 221 &domain_id, &channel_id); 222 ret = scmi_pwr_state_set(scmi_handles[channel_id], 223 domain_id, scmi_pwr_state); 224 if (ret != SCMI_E_QUEUED && ret != SCMI_E_SUCCESS) { 225 ERROR("SCMI set power state command return 0x%x unexpected\n", 226 ret); 227 panic(); 228 } 229 } 230 231 /* 232 * Helper function to turn ON a CPU power domain and its parent power domains 233 * if applicable. 234 */ 235 void css_scp_on(u_register_t mpidr) 236 { 237 unsigned int lvl = 0, channel_id, core_pos, domain_id; 238 int ret; 239 uint32_t scmi_pwr_state = 0; 240 241 for (; lvl <= PLAT_MAX_PWR_LVL; lvl++) 242 SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl, 243 scmi_power_state_on); 244 245 css_scp_set_state_pwr_lvl(&scmi_pwr_state, lvl); 246 247 core_pos = (unsigned int)plat_core_pos_by_mpidr(mpidr); 248 assert(core_pos < PLATFORM_CORE_COUNT); 249 250 css_scp_core_pos_to_scmi_channel(core_pos, &domain_id, 251 &channel_id); 252 ret = scmi_pwr_state_set(scmi_handles[channel_id], 253 domain_id, scmi_pwr_state); 254 if (ret != SCMI_E_QUEUED && ret != SCMI_E_SUCCESS) { 255 ERROR("SCMI set power state command return 0x%x unexpected\n", 256 ret); 257 panic(); 258 } 259 } 260 261 /* 262 * Helper function to get the power state of a power domain node as reported 263 * by the SCP. 264 */ 265 int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level) 266 { 267 int ret; 268 uint32_t scmi_pwr_state = 0, lvl_state; 269 unsigned int channel_id, cpu_idx, domain_id; 270 271 /* We don't support get power state at the system power domain level */ 272 if ((power_level > PLAT_MAX_PWR_LVL) || 273 (power_level == CSS_SYSTEM_PWR_DMN_LVL)) { 274 WARN("Invalid power level %u specified for SCMI get power state\n", 275 power_level); 276 return PSCI_E_INVALID_PARAMS; 277 } 278 279 cpu_idx = (unsigned int)plat_core_pos_by_mpidr(mpidr); 280 assert(cpu_idx < PLATFORM_CORE_COUNT); 281 282 css_scp_core_pos_to_scmi_channel(cpu_idx, &domain_id, &channel_id); 283 ret = scmi_pwr_state_get(scmi_handles[channel_id], 284 domain_id, &scmi_pwr_state); 285 286 if (ret != SCMI_E_SUCCESS) { 287 WARN("SCMI get power state command return 0x%x unexpected\n", 288 ret); 289 return PSCI_E_INVALID_PARAMS; 290 } 291 292 /* 293 * Find the maximum power level described in the get power state 294 * command. If it is less than the requested power level, then assume 295 * the requested power level is ON. 296 */ 297 if (SCMI_GET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state) < power_level) 298 return HW_ON; 299 300 lvl_state = SCMI_GET_PWR_STATE_LVL(scmi_pwr_state, power_level); 301 if (lvl_state == scmi_power_state_on) 302 return HW_ON; 303 304 assert((lvl_state == scmi_power_state_off) || 305 (lvl_state == scmi_power_state_sleep)); 306 return HW_OFF; 307 } 308 309 /* 310 * Callback function to raise a SGI designated to trigger the CPU power down 311 * sequence on all the online secondary cores. 312 */ 313 static void css_raise_pwr_down_interrupt(u_register_t mpidr) 314 { 315 #if CSS_SYSTEM_GRACEFUL_RESET 316 plat_ic_raise_el3_sgi(CSS_CPU_PWR_DOWN_REQ_INTR, mpidr); 317 #endif 318 } 319 320 void css_scp_system_off(int state) 321 { 322 int ret; 323 324 /* 325 * Before issuing the system power down command, set the trusted mailbox 326 * to 0. This will ensure that in the case of a warm/cold reset, the 327 * primary CPU executes from the cold boot sequence. 328 */ 329 mmio_write_64(PLAT_ARM_TRUSTED_MAILBOX_BASE, 0U); 330 331 unsigned int core_pos = plat_my_core_pos(); 332 /* 333 * Send powerdown request to online secondary core(s) 334 */ 335 ret = psci_stop_other_cores(core_pos, 0, css_raise_pwr_down_interrupt); 336 if (ret != PSCI_E_SUCCESS) { 337 ERROR("Failed to powerdown secondary core(s)\n"); 338 } 339 340 /* 341 * Disable GIC CPU interface to prevent pending interrupt from waking 342 * up the AP from WFI. 343 */ 344 gic_cpuif_disable(core_pos); 345 gic_pcpu_off(core_pos); 346 347 /* 348 * Issue SCMI command. 349 */ 350 ret = scmi_sys_pwr_state_set(scmi_handles[default_scmi_channel_id], 351 CSS_SCP_SYSTEM_OFF_REQ_FLAG, 352 state); 353 if (ret != SCMI_E_SUCCESS) { 354 ERROR("SCMI system power state set 0x%x returns unexpected 0x%x\n", 355 state, ret); 356 panic(); 357 } 358 359 /* Powerdown of primary core */ 360 psci_pwrdown_cpu_start(PLAT_MAX_PWR_LVL); 361 } 362 363 /* 364 * Helper function to shutdown the system via SCMI. 365 */ 366 void css_scp_sys_shutdown(void) 367 { 368 css_scp_system_off(SCMI_SYS_PWR_SHUTDOWN); 369 } 370 371 /* 372 * Helper function to reset the system via SCMI. 373 */ 374 void css_scp_sys_reboot(void) 375 { 376 css_scp_system_off(SCMI_SYS_PWR_COLD_RESET); 377 } 378 379 static int scmi_ap_core_init(scmi_channel_t *ch) 380 { 381 #if PROGRAMMABLE_RESET_ADDRESS 382 uint32_t version; 383 int ret; 384 385 ret = scmi_proto_version(ch, SCMI_AP_CORE_PROTO_ID, &version); 386 if (ret != SCMI_E_SUCCESS) { 387 WARN("SCMI AP core protocol version message failed\n"); 388 return -1; 389 } 390 391 if (!is_scmi_version_compatible(SCMI_AP_CORE_PROTO_VER, version)) { 392 WARN("SCMI AP core protocol version 0x%x incompatible with driver version 0x%x\n", 393 version, SCMI_AP_CORE_PROTO_VER); 394 return -1; 395 } 396 INFO("SCMI AP core protocol version 0x%x detected\n", version); 397 #endif 398 return 0; 399 } 400 401 void __init plat_arm_pwrc_setup(void) 402 { 403 unsigned int composite_id, idx; 404 405 for (idx = 0; idx < PLAT_ARM_SCMI_CHANNEL_COUNT; idx++) { 406 INFO("Initializing SCMI driver on channel %d\n", idx); 407 408 scmi_channels[idx].info = plat_css_get_scmi_info(idx); 409 scmi_channels[idx].lock = ARM_SCMI_LOCK_GET_INSTANCE; 410 scmi_handles[idx] = scmi_init(&scmi_channels[idx]); 411 412 if (scmi_handles[idx] == NULL) { 413 ERROR("SCMI Initialization failed on channel %d\n", idx); 414 panic(); 415 } 416 417 if (scmi_ap_core_init(&scmi_channels[idx]) < 0) { 418 ERROR("SCMI AP core protocol initialization failed\n"); 419 panic(); 420 } 421 } 422 423 composite_id = plat_css_core_pos_to_scmi_dmn_id_map[plat_my_core_pos()]; 424 default_scmi_channel_id = GET_SCMI_CHANNEL_ID(composite_id); 425 } 426 427 /****************************************************************************** 428 * This function overrides the default definition for ARM platforms. Initialize 429 * the SCMI driver, query capability via SCMI and modify the PSCI capability 430 * based on that. 431 *****************************************************************************/ 432 const plat_psci_ops_t *css_scmi_override_pm_ops(plat_psci_ops_t *ops) 433 { 434 uint32_t msg_attr; 435 int ret; 436 void *scmi_handle = scmi_handles[default_scmi_channel_id]; 437 438 assert(scmi_handle); 439 440 /* Check that power domain POWER_STATE_SET message is supported */ 441 ret = scmi_proto_msg_attr(scmi_handle, SCMI_PWR_DMN_PROTO_ID, 442 SCMI_PWR_STATE_SET_MSG, &msg_attr); 443 if (ret != SCMI_E_SUCCESS) { 444 ERROR("Set power state command is not supported by SCMI\n"); 445 panic(); 446 } 447 448 /* 449 * Don't support PSCI NODE_HW_STATE call if SCMI doesn't support 450 * POWER_STATE_GET message. 451 */ 452 ret = scmi_proto_msg_attr(scmi_handle, SCMI_PWR_DMN_PROTO_ID, 453 SCMI_PWR_STATE_GET_MSG, &msg_attr); 454 if (ret != SCMI_E_SUCCESS) 455 ops->get_node_hw_state = NULL; 456 457 /* Check if the SCMI SYSTEM_POWER_STATE_SET message is supported */ 458 ret = scmi_proto_msg_attr(scmi_handle, SCMI_SYS_PWR_PROTO_ID, 459 SCMI_SYS_PWR_STATE_SET_MSG, &msg_attr); 460 if (ret != SCMI_E_SUCCESS) { 461 /* System power management operations are not supported */ 462 ops->system_off = NULL; 463 ops->system_reset = NULL; 464 ops->get_sys_suspend_power_state = NULL; 465 } else { 466 if (!(msg_attr & SCMI_SYS_PWR_SUSPEND_SUPPORTED)) { 467 /* 468 * System power management protocol is available, but 469 * it does not support SYSTEM SUSPEND. 470 */ 471 ops->get_sys_suspend_power_state = NULL; 472 } 473 if (!(msg_attr & SCMI_SYS_PWR_WARM_RESET_SUPPORTED)) { 474 /* 475 * WARM reset is not available. 476 */ 477 ops->system_reset2 = NULL; 478 } 479 } 480 481 return ops; 482 } 483 484 int css_system_reset2(int is_vendor, int reset_type, u_register_t cookie) 485 { 486 if (is_vendor || (reset_type != PSCI_RESET2_SYSTEM_WARM_RESET)) 487 return PSCI_E_INVALID_PARAMS; 488 489 css_scp_system_off(SCMI_SYS_PWR_WARM_RESET); 490 /* return SUCCESS to finish the powerdown */ 491 return PSCI_E_SUCCESS; 492 } 493 494 #if PROGRAMMABLE_RESET_ADDRESS 495 void plat_arm_program_trusted_mailbox(uintptr_t address) 496 { 497 int ret, i; 498 499 for (i = 0; i < PLAT_ARM_SCMI_CHANNEL_COUNT; i++) { 500 assert(scmi_handles[i]); 501 502 ret = scmi_ap_core_set_reset_addr(scmi_handles[i], address, 503 SCMI_AP_CORE_LOCK_ATTR); 504 if (ret != SCMI_E_SUCCESS) { 505 ERROR("CSS: Failed to program reset address: %d\n", ret); 506 panic(); 507 } 508 } 509 } 510 #endif 511