1 /* 2 * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <arch_helpers.h> 8 #include <assert.h> 9 #include <css_def.h> 10 #include <css_pm.h> 11 #include <debug.h> 12 #include <plat_arm.h> 13 #include <platform.h> 14 #include <string.h> 15 #include "../scmi/scmi.h" 16 #include "css_scp.h" 17 18 /* 19 * This file implements the SCP helper functions using SCMI protocol. 20 */ 21 22 /* 23 * SCMI power state parameter bit field encoding for ARM CSS platforms. 24 * 25 * 31 20 19 16 15 12 11 8 7 4 3 0 26 * +-------------------------------------------------------------+ 27 * | SBZ | Max level | Level 3 | Level 2 | Level 1 | Level 0 | 28 * | | | state | state | state | state | 29 * +-------------------------------------------------------------+ 30 * 31 * `Max level` encodes the highest level that has a valid power state 32 * encoded in the power state. 33 */ 34 #define SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT 16 35 #define SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH 4 36 #define SCMI_PWR_STATE_MAX_PWR_LVL_MASK \ 37 ((1 << SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH) - 1) 38 #define SCMI_SET_PWR_STATE_MAX_PWR_LVL(pwr_state, max_lvl) \ 39 (pwr_state) |= ((max_lvl) & SCMI_PWR_STATE_MAX_PWR_LVL_MASK) \ 40 << SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT 41 #define SCMI_GET_PWR_STATE_MAX_PWR_LVL(pwr_state) \ 42 (((pwr_state) >> SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT) \ 43 & SCMI_PWR_STATE_MAX_PWR_LVL_MASK) 44 45 #define SCMI_PWR_STATE_LVL_WIDTH 4 46 #define SCMI_PWR_STATE_LVL_MASK \ 47 ((1 << SCMI_PWR_STATE_LVL_WIDTH) - 1) 48 #define SCMI_SET_PWR_STATE_LVL(pwr_state, lvl, lvl_state) \ 49 (pwr_state) |= ((lvl_state) & SCMI_PWR_STATE_LVL_MASK) \ 50 << (SCMI_PWR_STATE_LVL_WIDTH * (lvl)) 51 #define SCMI_GET_PWR_STATE_LVL(pwr_state, lvl) \ 52 (((pwr_state) >> (SCMI_PWR_STATE_LVL_WIDTH * (lvl))) & \ 53 SCMI_PWR_STATE_LVL_MASK) 54 55 /* 56 * The SCMI power state enumeration for a power domain level 57 */ 58 typedef enum { 59 scmi_power_state_off = 0, 60 scmi_power_state_on = 1, 61 scmi_power_state_sleep = 2, 62 } scmi_power_state_t; 63 64 /* 65 * This mapping array has to be exported by the platform. Each element at 66 * a given index maps that core to an SCMI power domain. 67 */ 68 extern uint32_t plat_css_core_pos_to_scmi_dmn_id_map[]; 69 70 /* 71 * The global handle for invoking the SCMI driver APIs after the driver 72 * has been initialized. 73 */ 74 void *scmi_handle; 75 76 /* The SCMI channel global object */ 77 static scmi_channel_t scmi_channel; 78 79 ARM_INSTANTIATE_LOCK; 80 81 /* 82 * Helper function to suspend a CPU power domain and its parent power domains 83 * if applicable. 84 */ 85 void css_scp_suspend(const psci_power_state_t *target_state) 86 { 87 int lvl, ret; 88 uint32_t scmi_pwr_state = 0; 89 90 /* At least power domain level 0 should be specified to be suspended */ 91 assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == 92 ARM_LOCAL_STATE_OFF); 93 94 /* Check if power down at system power domain level is requested */ 95 if (CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) { 96 /* Issue SCMI command for SYSTEM_SUSPEND */ 97 ret = scmi_sys_pwr_state_set(scmi_handle, 98 SCMI_SYS_PWR_FORCEFUL_REQ, 99 SCMI_SYS_PWR_SUSPEND); 100 if (ret != SCMI_E_SUCCESS) { 101 ERROR("SCMI system power domain suspend return 0x%x unexpected\n", 102 ret); 103 panic(); 104 } 105 return; 106 } 107 108 /* 109 * If we reach here, then assert that power down at system power domain 110 * level is running. 111 */ 112 assert(target_state->pwr_domain_state[CSS_SYSTEM_PWR_DMN_LVL] == 113 ARM_LOCAL_STATE_RUN); 114 115 /* For level 0, specify `scmi_power_state_sleep` as the power state */ 116 SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, ARM_PWR_LVL0, 117 scmi_power_state_sleep); 118 119 for (lvl = ARM_PWR_LVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) { 120 if (target_state->pwr_domain_state[lvl] == ARM_LOCAL_STATE_RUN) 121 break; 122 123 assert(target_state->pwr_domain_state[lvl] == 124 ARM_LOCAL_STATE_OFF); 125 /* 126 * Specify `scmi_power_state_off` as power state for higher 127 * levels. 128 */ 129 SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl, 130 scmi_power_state_off); 131 } 132 133 SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1); 134 135 ret = scmi_pwr_state_set(scmi_handle, 136 plat_css_core_pos_to_scmi_dmn_id_map[plat_my_core_pos()], 137 scmi_pwr_state); 138 139 if (ret != SCMI_E_SUCCESS) { 140 ERROR("SCMI set power state command return 0x%x unexpected\n", 141 ret); 142 panic(); 143 } 144 } 145 146 /* 147 * Helper function to turn off a CPU power domain and its parent power domains 148 * if applicable. 149 */ 150 void css_scp_off(const psci_power_state_t *target_state) 151 { 152 int lvl = 0, ret; 153 uint32_t scmi_pwr_state = 0; 154 155 /* At-least the CPU level should be specified to be OFF */ 156 assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == 157 ARM_LOCAL_STATE_OFF); 158 159 /* PSCI CPU OFF cannot be used to turn OFF system power domain */ 160 assert(target_state->pwr_domain_state[CSS_SYSTEM_PWR_DMN_LVL] == 161 ARM_LOCAL_STATE_RUN); 162 163 for (; lvl <= PLAT_MAX_PWR_LVL; lvl++) { 164 if (target_state->pwr_domain_state[lvl] == ARM_LOCAL_STATE_RUN) 165 break; 166 167 assert(target_state->pwr_domain_state[lvl] == 168 ARM_LOCAL_STATE_OFF); 169 SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl, 170 scmi_power_state_off); 171 } 172 173 SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1); 174 175 ret = scmi_pwr_state_set(scmi_handle, 176 plat_css_core_pos_to_scmi_dmn_id_map[plat_my_core_pos()], 177 scmi_pwr_state); 178 179 if (ret != SCMI_E_QUEUED && ret != SCMI_E_SUCCESS) { 180 ERROR("SCMI set power state command return 0x%x unexpected\n", 181 ret); 182 panic(); 183 } 184 } 185 186 /* 187 * Helper function to turn ON a CPU power domain and its parent power domains 188 * if applicable. 189 */ 190 void css_scp_on(u_register_t mpidr) 191 { 192 int lvl = 0, ret, core_pos; 193 uint32_t scmi_pwr_state = 0; 194 195 for (; lvl <= PLAT_MAX_PWR_LVL; lvl++) 196 SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl, 197 scmi_power_state_on); 198 199 SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1); 200 201 core_pos = plat_core_pos_by_mpidr(mpidr); 202 assert(core_pos >= 0 && core_pos < PLATFORM_CORE_COUNT); 203 204 ret = scmi_pwr_state_set(scmi_handle, 205 plat_css_core_pos_to_scmi_dmn_id_map[core_pos], 206 scmi_pwr_state); 207 208 if (ret != SCMI_E_QUEUED && ret != SCMI_E_SUCCESS) { 209 ERROR("SCMI set power state command return 0x%x unexpected\n", 210 ret); 211 panic(); 212 } 213 } 214 215 /* 216 * Helper function to get the power state of a power domain node as reported 217 * by the SCP. 218 */ 219 int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level) 220 { 221 int ret, cpu_idx; 222 uint32_t scmi_pwr_state = 0, lvl_state; 223 224 /* We don't support get power state at the system power domain level */ 225 if ((power_level > PLAT_MAX_PWR_LVL) || 226 (power_level == CSS_SYSTEM_PWR_DMN_LVL)) { 227 WARN("Invalid power level %u specified for SCMI get power state\n", 228 power_level); 229 return PSCI_E_INVALID_PARAMS; 230 } 231 232 cpu_idx = plat_core_pos_by_mpidr(mpidr); 233 assert(cpu_idx > -1); 234 235 ret = scmi_pwr_state_get(scmi_handle, 236 plat_css_core_pos_to_scmi_dmn_id_map[cpu_idx], 237 &scmi_pwr_state); 238 239 if (ret != SCMI_E_SUCCESS) { 240 WARN("SCMI get power state command return 0x%x unexpected\n", 241 ret); 242 return PSCI_E_INVALID_PARAMS; 243 } 244 245 /* 246 * Find the maximum power level described in the get power state 247 * command. If it is less than the requested power level, then assume 248 * the requested power level is ON. 249 */ 250 if (SCMI_GET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state) < power_level) 251 return HW_ON; 252 253 lvl_state = SCMI_GET_PWR_STATE_LVL(scmi_pwr_state, power_level); 254 if (lvl_state == scmi_power_state_on) 255 return HW_ON; 256 257 assert((lvl_state == scmi_power_state_off) || 258 (lvl_state == scmi_power_state_sleep)); 259 return HW_OFF; 260 } 261 262 void __dead2 css_scp_system_off(int state) 263 { 264 int ret; 265 266 /* 267 * Disable GIC CPU interface to prevent pending interrupt from waking 268 * up the AP from WFI. 269 */ 270 plat_arm_gic_cpuif_disable(); 271 272 /* 273 * Issue SCMI command. First issue a graceful 274 * request and if that fails force the request. 275 */ 276 ret = scmi_sys_pwr_state_set(scmi_handle, 277 SCMI_SYS_PWR_FORCEFUL_REQ, 278 state); 279 280 if (ret != SCMI_E_SUCCESS) { 281 ERROR("SCMI system power state set 0x%x returns unexpected 0x%x\n", 282 state, ret); 283 panic(); 284 } 285 wfi(); 286 ERROR("CSS set power state: operation not handled.\n"); 287 panic(); 288 } 289 290 /* 291 * Helper function to shutdown the system via SCMI. 292 */ 293 void __dead2 css_scp_sys_shutdown(void) 294 { 295 css_scp_system_off(SCMI_SYS_PWR_SHUTDOWN); 296 } 297 298 /* 299 * Helper function to reset the system via SCMI. 300 */ 301 void __dead2 css_scp_sys_reboot(void) 302 { 303 css_scp_system_off(SCMI_SYS_PWR_COLD_RESET); 304 } 305 306 scmi_channel_plat_info_t plat_css_scmi_plat_info = { 307 .scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE, 308 .db_reg_addr = PLAT_CSS_MHU_BASE + CSS_SCMI_MHU_DB_REG_OFF, 309 .db_preserve_mask = 0xfffffffe, 310 .db_modify_mask = 0x1, 311 }; 312 313 void plat_arm_pwrc_setup(void) 314 { 315 scmi_channel.info = &plat_css_scmi_plat_info; 316 scmi_channel.lock = ARM_LOCK_GET_INSTANCE; 317 scmi_handle = scmi_init(&scmi_channel); 318 if (scmi_handle == NULL) { 319 ERROR("SCMI Initialization failed\n"); 320 panic(); 321 } 322 } 323 324 /****************************************************************************** 325 * This function overrides the default definition for ARM platforms. Initialize 326 * the SCMI driver, query capability via SCMI and modify the PSCI capability 327 * based on that. 328 *****************************************************************************/ 329 const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops) 330 { 331 uint32_t msg_attr; 332 int ret; 333 334 assert(scmi_handle); 335 336 /* Check that power domain POWER_STATE_SET message is supported */ 337 ret = scmi_proto_msg_attr(scmi_handle, SCMI_PWR_DMN_PROTO_ID, 338 SCMI_PWR_STATE_SET_MSG, &msg_attr); 339 if (ret != SCMI_E_SUCCESS) { 340 ERROR("Set power state command is not supported by SCMI\n"); 341 panic(); 342 } 343 344 /* 345 * Don't support PSCI NODE_HW_STATE call if SCMI doesn't support 346 * POWER_STATE_GET message. 347 */ 348 ret = scmi_proto_msg_attr(scmi_handle, SCMI_PWR_DMN_PROTO_ID, 349 SCMI_PWR_STATE_GET_MSG, &msg_attr); 350 if (ret != SCMI_E_SUCCESS) 351 ops->get_node_hw_state = NULL; 352 353 /* Check if the SCMI SYSTEM_POWER_STATE_SET message is supported */ 354 ret = scmi_proto_msg_attr(scmi_handle, SCMI_SYS_PWR_PROTO_ID, 355 SCMI_SYS_PWR_STATE_SET_MSG, &msg_attr); 356 if (ret != SCMI_E_SUCCESS) { 357 /* System power management operations are not supported */ 358 ops->system_off = NULL; 359 ops->system_reset = NULL; 360 ops->get_sys_suspend_power_state = NULL; 361 } else { 362 if (!(msg_attr & SCMI_SYS_PWR_SUSPEND_SUPPORTED)) { 363 /* 364 * System power management protocol is available, but 365 * it does not support SYSTEM SUSPEND. 366 */ 367 ops->get_sys_suspend_power_state = NULL; 368 } 369 if (!(msg_attr & SCMI_SYS_PWR_WARM_RESET_SUPPORTED)) { 370 /* 371 * WARM reset is not available. 372 */ 373 ops->system_reset2 = NULL; 374 } 375 } 376 377 return ops; 378 } 379 380 int css_system_reset2(int is_vendor, int reset_type, u_register_t cookie) 381 { 382 if (is_vendor || (reset_type != PSCI_RESET2_SYSTEM_WARM_RESET)) 383 return PSCI_E_INVALID_PARAMS; 384 385 css_scp_system_off(SCMI_SYS_PWR_WARM_RESET); 386 /* 387 * css_scp_system_off cannot return (it is a __dead function), 388 * but css_system_reset2 has to return some value, even in 389 * this case. 390 */ 391 return 0; 392 } 393