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