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 /* 118 * Helper function to suspend a CPU power domain and its parent power domains 119 * if applicable. 120 */ 121 void css_scp_suspend(const struct psci_power_state *target_state) 122 { 123 int ret; 124 125 /* At least power domain level 0 should be specified to be suspended */ 126 assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == 127 ARM_LOCAL_STATE_OFF); 128 129 /* Check if power down at system power domain level is requested */ 130 if (css_system_pwr_state(target_state) == ARM_LOCAL_STATE_OFF) { 131 /* Issue SCMI command for SYSTEM_SUSPEND on all SCMI channels */ 132 ret = scmi_sys_pwr_state_set( 133 scmi_handles[default_scmi_channel_id], 134 CSS_SCP_SUSPEND_REQ_FLAG, SCMI_SYS_PWR_SUSPEND); 135 if (ret != SCMI_E_SUCCESS) { 136 ERROR("SCMI system power domain suspend return 0x%x unexpected\n", 137 ret); 138 panic(); 139 } 140 return; 141 } 142 #if !HW_ASSISTED_COHERENCY 143 unsigned int lvl, channel_id, domain_id; 144 uint32_t scmi_pwr_state = 0; 145 /* 146 * If we reach here, then assert that power down at system power domain 147 * level is running. 148 */ 149 assert(css_system_pwr_state(target_state) == ARM_LOCAL_STATE_RUN); 150 151 /* For level 0, specify `scmi_power_state_sleep` as the power state */ 152 SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, ARM_PWR_LVL0, 153 scmi_power_state_sleep); 154 155 for (lvl = ARM_PWR_LVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) { 156 if (target_state->pwr_domain_state[lvl] == ARM_LOCAL_STATE_RUN) 157 break; 158 159 assert(target_state->pwr_domain_state[lvl] == 160 ARM_LOCAL_STATE_OFF); 161 /* 162 * Specify `scmi_power_state_off` as power state for higher 163 * levels. 164 */ 165 SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl, 166 scmi_power_state_off); 167 } 168 169 SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1); 170 171 css_scp_core_pos_to_scmi_channel(plat_my_core_pos(), 172 &domain_id, &channel_id); 173 ret = scmi_pwr_state_set(scmi_handles[channel_id], 174 domain_id, scmi_pwr_state); 175 176 if (ret != SCMI_E_SUCCESS) { 177 ERROR("SCMI set power state command return 0x%x unexpected\n", 178 ret); 179 panic(); 180 } 181 #endif 182 } 183 184 /* 185 * Helper function to turn off a CPU power domain and its parent power domains 186 * if applicable. 187 */ 188 void css_scp_off(const struct psci_power_state *target_state) 189 { 190 unsigned int lvl = 0, channel_id, domain_id; 191 int ret; 192 uint32_t scmi_pwr_state = 0; 193 194 /* At-least the CPU level should be specified to be OFF */ 195 assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == 196 ARM_LOCAL_STATE_OFF); 197 198 /* PSCI CPU OFF cannot be used to turn OFF system power domain */ 199 assert(css_system_pwr_state(target_state) == ARM_LOCAL_STATE_RUN); 200 201 for (; lvl <= PLAT_MAX_PWR_LVL; lvl++) { 202 if (target_state->pwr_domain_state[lvl] == ARM_LOCAL_STATE_RUN) 203 break; 204 205 assert(target_state->pwr_domain_state[lvl] == 206 ARM_LOCAL_STATE_OFF); 207 SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl, 208 scmi_power_state_off); 209 } 210 211 SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1); 212 213 css_scp_core_pos_to_scmi_channel(plat_my_core_pos(), 214 &domain_id, &channel_id); 215 ret = scmi_pwr_state_set(scmi_handles[channel_id], 216 domain_id, scmi_pwr_state); 217 if (ret != SCMI_E_QUEUED && ret != SCMI_E_SUCCESS) { 218 ERROR("SCMI set power state command return 0x%x unexpected\n", 219 ret); 220 panic(); 221 } 222 } 223 224 /* 225 * Helper function to turn ON a CPU power domain and its parent power domains 226 * if applicable. 227 */ 228 void css_scp_on(u_register_t mpidr) 229 { 230 unsigned int lvl = 0, channel_id, core_pos, domain_id; 231 int ret; 232 uint32_t scmi_pwr_state = 0; 233 234 for (; lvl <= PLAT_MAX_PWR_LVL; lvl++) 235 SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl, 236 scmi_power_state_on); 237 238 SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1); 239 240 core_pos = (unsigned int)plat_core_pos_by_mpidr(mpidr); 241 assert(core_pos < PLATFORM_CORE_COUNT); 242 243 css_scp_core_pos_to_scmi_channel(core_pos, &domain_id, 244 &channel_id); 245 ret = scmi_pwr_state_set(scmi_handles[channel_id], 246 domain_id, scmi_pwr_state); 247 if (ret != SCMI_E_QUEUED && ret != SCMI_E_SUCCESS) { 248 ERROR("SCMI set power state command return 0x%x unexpected\n", 249 ret); 250 panic(); 251 } 252 } 253 254 /* 255 * Helper function to get the power state of a power domain node as reported 256 * by the SCP. 257 */ 258 int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level) 259 { 260 int ret; 261 uint32_t scmi_pwr_state = 0, lvl_state; 262 unsigned int channel_id, cpu_idx, domain_id; 263 264 /* We don't support get power state at the system power domain level */ 265 if ((power_level > PLAT_MAX_PWR_LVL) || 266 (power_level == CSS_SYSTEM_PWR_DMN_LVL)) { 267 WARN("Invalid power level %u specified for SCMI get power state\n", 268 power_level); 269 return PSCI_E_INVALID_PARAMS; 270 } 271 272 cpu_idx = (unsigned int)plat_core_pos_by_mpidr(mpidr); 273 assert(cpu_idx < PLATFORM_CORE_COUNT); 274 275 css_scp_core_pos_to_scmi_channel(cpu_idx, &domain_id, &channel_id); 276 ret = scmi_pwr_state_get(scmi_handles[channel_id], 277 domain_id, &scmi_pwr_state); 278 279 if (ret != SCMI_E_SUCCESS) { 280 WARN("SCMI get power state command return 0x%x unexpected\n", 281 ret); 282 return PSCI_E_INVALID_PARAMS; 283 } 284 285 /* 286 * Find the maximum power level described in the get power state 287 * command. If it is less than the requested power level, then assume 288 * the requested power level is ON. 289 */ 290 if (SCMI_GET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state) < power_level) 291 return HW_ON; 292 293 lvl_state = SCMI_GET_PWR_STATE_LVL(scmi_pwr_state, power_level); 294 if (lvl_state == scmi_power_state_on) 295 return HW_ON; 296 297 assert((lvl_state == scmi_power_state_off) || 298 (lvl_state == scmi_power_state_sleep)); 299 return HW_OFF; 300 } 301 302 /* 303 * Callback function to raise a SGI designated to trigger the CPU power down 304 * sequence on all the online secondary cores. 305 */ 306 static void css_raise_pwr_down_interrupt(u_register_t mpidr) 307 { 308 #if CSS_SYSTEM_GRACEFUL_RESET 309 plat_ic_raise_el3_sgi(CSS_CPU_PWR_DOWN_REQ_INTR, mpidr); 310 #endif 311 } 312 313 void css_scp_system_off(int state) 314 { 315 int ret; 316 317 /* 318 * Before issuing the system power down command, set the trusted mailbox 319 * to 0. This will ensure that in the case of a warm/cold reset, the 320 * primary CPU executes from the cold boot sequence. 321 */ 322 mmio_write_64(PLAT_ARM_TRUSTED_MAILBOX_BASE, 0U); 323 324 unsigned int core_pos = plat_my_core_pos(); 325 /* 326 * Send powerdown request to online secondary core(s) 327 */ 328 ret = psci_stop_other_cores(core_pos, 0, css_raise_pwr_down_interrupt); 329 if (ret != PSCI_E_SUCCESS) { 330 ERROR("Failed to powerdown secondary core(s)\n"); 331 } 332 333 /* 334 * Disable GIC CPU interface to prevent pending interrupt from waking 335 * up the AP from WFI. 336 */ 337 gic_cpuif_disable(core_pos); 338 gic_pcpu_off(core_pos); 339 340 /* 341 * Issue SCMI command. 342 */ 343 ret = scmi_sys_pwr_state_set(scmi_handles[default_scmi_channel_id], 344 CSS_SCP_SYSTEM_OFF_REQ_FLAG, 345 state); 346 if (ret != SCMI_E_SUCCESS) { 347 ERROR("SCMI system power state set 0x%x returns unexpected 0x%x\n", 348 state, ret); 349 panic(); 350 } 351 352 /* Powerdown of primary core */ 353 psci_pwrdown_cpu_start(PLAT_MAX_PWR_LVL); 354 } 355 356 /* 357 * Helper function to shutdown the system via SCMI. 358 */ 359 void css_scp_sys_shutdown(void) 360 { 361 css_scp_system_off(SCMI_SYS_PWR_SHUTDOWN); 362 } 363 364 /* 365 * Helper function to reset the system via SCMI. 366 */ 367 void css_scp_sys_reboot(void) 368 { 369 css_scp_system_off(SCMI_SYS_PWR_COLD_RESET); 370 } 371 372 static int scmi_ap_core_init(scmi_channel_t *ch) 373 { 374 #if PROGRAMMABLE_RESET_ADDRESS 375 uint32_t version; 376 int ret; 377 378 ret = scmi_proto_version(ch, SCMI_AP_CORE_PROTO_ID, &version); 379 if (ret != SCMI_E_SUCCESS) { 380 WARN("SCMI AP core protocol version message failed\n"); 381 return -1; 382 } 383 384 if (!is_scmi_version_compatible(SCMI_AP_CORE_PROTO_VER, version)) { 385 WARN("SCMI AP core protocol version 0x%x incompatible with driver version 0x%x\n", 386 version, SCMI_AP_CORE_PROTO_VER); 387 return -1; 388 } 389 INFO("SCMI AP core protocol version 0x%x detected\n", version); 390 #endif 391 return 0; 392 } 393 394 void __init plat_arm_pwrc_setup(void) 395 { 396 unsigned int composite_id, idx; 397 398 for (idx = 0; idx < PLAT_ARM_SCMI_CHANNEL_COUNT; idx++) { 399 INFO("Initializing SCMI driver on channel %d\n", idx); 400 401 scmi_channels[idx].info = plat_css_get_scmi_info(idx); 402 scmi_channels[idx].lock = ARM_SCMI_LOCK_GET_INSTANCE; 403 scmi_handles[idx] = scmi_init(&scmi_channels[idx]); 404 405 if (scmi_handles[idx] == NULL) { 406 ERROR("SCMI Initialization failed on channel %d\n", idx); 407 panic(); 408 } 409 410 if (scmi_ap_core_init(&scmi_channels[idx]) < 0) { 411 ERROR("SCMI AP core protocol initialization failed\n"); 412 panic(); 413 } 414 } 415 416 composite_id = plat_css_core_pos_to_scmi_dmn_id_map[plat_my_core_pos()]; 417 default_scmi_channel_id = GET_SCMI_CHANNEL_ID(composite_id); 418 } 419 420 /****************************************************************************** 421 * This function overrides the default definition for ARM platforms. Initialize 422 * the SCMI driver, query capability via SCMI and modify the PSCI capability 423 * based on that. 424 *****************************************************************************/ 425 const plat_psci_ops_t *css_scmi_override_pm_ops(plat_psci_ops_t *ops) 426 { 427 uint32_t msg_attr; 428 int ret; 429 void *scmi_handle = scmi_handles[default_scmi_channel_id]; 430 431 assert(scmi_handle); 432 433 /* Check that power domain POWER_STATE_SET message is supported */ 434 ret = scmi_proto_msg_attr(scmi_handle, SCMI_PWR_DMN_PROTO_ID, 435 SCMI_PWR_STATE_SET_MSG, &msg_attr); 436 if (ret != SCMI_E_SUCCESS) { 437 ERROR("Set power state command is not supported by SCMI\n"); 438 panic(); 439 } 440 441 /* 442 * Don't support PSCI NODE_HW_STATE call if SCMI doesn't support 443 * POWER_STATE_GET message. 444 */ 445 ret = scmi_proto_msg_attr(scmi_handle, SCMI_PWR_DMN_PROTO_ID, 446 SCMI_PWR_STATE_GET_MSG, &msg_attr); 447 if (ret != SCMI_E_SUCCESS) 448 ops->get_node_hw_state = NULL; 449 450 /* Check if the SCMI SYSTEM_POWER_STATE_SET message is supported */ 451 ret = scmi_proto_msg_attr(scmi_handle, SCMI_SYS_PWR_PROTO_ID, 452 SCMI_SYS_PWR_STATE_SET_MSG, &msg_attr); 453 if (ret != SCMI_E_SUCCESS) { 454 /* System power management operations are not supported */ 455 ops->system_off = NULL; 456 ops->system_reset = NULL; 457 ops->get_sys_suspend_power_state = NULL; 458 } else { 459 if (!(msg_attr & SCMI_SYS_PWR_SUSPEND_SUPPORTED)) { 460 /* 461 * System power management protocol is available, but 462 * it does not support SYSTEM SUSPEND. 463 */ 464 ops->get_sys_suspend_power_state = NULL; 465 } 466 if (!(msg_attr & SCMI_SYS_PWR_WARM_RESET_SUPPORTED)) { 467 /* 468 * WARM reset is not available. 469 */ 470 ops->system_reset2 = NULL; 471 } 472 } 473 474 return ops; 475 } 476 477 int css_system_reset2(int is_vendor, int reset_type, u_register_t cookie) 478 { 479 if (is_vendor || (reset_type != PSCI_RESET2_SYSTEM_WARM_RESET)) 480 return PSCI_E_INVALID_PARAMS; 481 482 css_scp_system_off(SCMI_SYS_PWR_WARM_RESET); 483 /* return SUCCESS to finish the powerdown */ 484 return PSCI_E_SUCCESS; 485 } 486 487 #if PROGRAMMABLE_RESET_ADDRESS 488 void plat_arm_program_trusted_mailbox(uintptr_t address) 489 { 490 int ret, i; 491 492 for (i = 0; i < PLAT_ARM_SCMI_CHANNEL_COUNT; i++) { 493 assert(scmi_handles[i]); 494 495 ret = scmi_ap_core_set_reset_addr(scmi_handles[i], address, 496 SCMI_AP_CORE_LOCK_ATTR); 497 if (ret != SCMI_E_SUCCESS) { 498 ERROR("CSS: Failed to program reset address: %d\n", ret); 499 panic(); 500 } 501 } 502 } 503 #endif 504