Home | History | Annotate | Download | only in psci
      1 /*
      2  * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
      3  *
      4  * SPDX-License-Identifier: BSD-3-Clause
      5  */
      6 
      7 #include <arch.h>
      8 #include <arch_helpers.h>
      9 #include <assert.h>
     10 #include <debug.h>
     11 #include <platform.h>
     12 #include <pmf.h>
     13 #include <runtime_instr.h>
     14 #include <smcc.h>
     15 #include <string.h>
     16 #include "psci_private.h"
     17 
     18 /*******************************************************************************
     19  * PSCI frontend api for servicing SMCs. Described in the PSCI spec.
     20  ******************************************************************************/
     21 int psci_cpu_on(u_register_t target_cpu,
     22 		uintptr_t entrypoint,
     23 		u_register_t context_id)
     24 
     25 {
     26 	int rc;
     27 	entry_point_info_t ep;
     28 
     29 	/* Determine if the cpu exists of not */
     30 	rc = psci_validate_mpidr(target_cpu);
     31 	if (rc != PSCI_E_SUCCESS)
     32 		return PSCI_E_INVALID_PARAMS;
     33 
     34 	/* Validate the entry point and get the entry_point_info */
     35 	rc = psci_validate_entry_point(&ep, entrypoint, context_id);
     36 	if (rc != PSCI_E_SUCCESS)
     37 		return rc;
     38 
     39 	/*
     40 	 * To turn this cpu on, specify which power
     41 	 * levels need to be turned on
     42 	 */
     43 	return psci_cpu_on_start(target_cpu, &ep);
     44 }
     45 
     46 unsigned int psci_version(void)
     47 {
     48 	return PSCI_MAJOR_VER | PSCI_MINOR_VER;
     49 }
     50 
     51 int psci_cpu_suspend(unsigned int power_state,
     52 		     uintptr_t entrypoint,
     53 		     u_register_t context_id)
     54 {
     55 	int rc;
     56 	unsigned int target_pwrlvl, is_power_down_state;
     57 	entry_point_info_t ep;
     58 	psci_power_state_t state_info = { {PSCI_LOCAL_STATE_RUN} };
     59 	plat_local_state_t cpu_pd_state;
     60 
     61 	/* Validate the power_state parameter */
     62 	rc = psci_validate_power_state(power_state, &state_info);
     63 	if (rc != PSCI_E_SUCCESS) {
     64 		assert(rc == PSCI_E_INVALID_PARAMS);
     65 		return rc;
     66 	}
     67 
     68 	/*
     69 	 * Get the value of the state type bit from the power state parameter.
     70 	 */
     71 	is_power_down_state = psci_get_pstate_type(power_state);
     72 
     73 	/* Sanity check the requested suspend levels */
     74 	assert(psci_validate_suspend_req(&state_info, is_power_down_state)
     75 			== PSCI_E_SUCCESS);
     76 
     77 	target_pwrlvl = psci_find_target_suspend_lvl(&state_info);
     78 	if (target_pwrlvl == PSCI_INVALID_PWR_LVL) {
     79 		ERROR("Invalid target power level for suspend operation\n");
     80 		panic();
     81 	}
     82 
     83 	/* Fast path for CPU standby.*/
     84 	if (is_cpu_standby_req(is_power_down_state, target_pwrlvl)) {
     85 		if  (!psci_plat_pm_ops->cpu_standby)
     86 			return PSCI_E_INVALID_PARAMS;
     87 
     88 		/*
     89 		 * Set the state of the CPU power domain to the platform
     90 		 * specific retention state and enter the standby state.
     91 		 */
     92 		cpu_pd_state = state_info.pwr_domain_state[PSCI_CPU_PWR_LVL];
     93 		psci_set_cpu_local_state(cpu_pd_state);
     94 
     95 #if ENABLE_PSCI_STAT
     96 		plat_psci_stat_accounting_start(&state_info);
     97 #endif
     98 
     99 #if ENABLE_RUNTIME_INSTRUMENTATION
    100 		PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
    101 		    RT_INSTR_ENTER_HW_LOW_PWR,
    102 		    PMF_NO_CACHE_MAINT);
    103 #endif
    104 
    105 		psci_plat_pm_ops->cpu_standby(cpu_pd_state);
    106 
    107 		/* Upon exit from standby, set the state back to RUN. */
    108 		psci_set_cpu_local_state(PSCI_LOCAL_STATE_RUN);
    109 
    110 #if ENABLE_RUNTIME_INSTRUMENTATION
    111 		PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
    112 		    RT_INSTR_EXIT_HW_LOW_PWR,
    113 		    PMF_NO_CACHE_MAINT);
    114 #endif
    115 
    116 #if ENABLE_PSCI_STAT
    117 		plat_psci_stat_accounting_stop(&state_info);
    118 
    119 		/* Update PSCI stats */
    120 		psci_stats_update_pwr_up(PSCI_CPU_PWR_LVL, &state_info);
    121 #endif
    122 
    123 		return PSCI_E_SUCCESS;
    124 	}
    125 
    126 	/*
    127 	 * If a power down state has been requested, we need to verify entry
    128 	 * point and program entry information.
    129 	 */
    130 	if (is_power_down_state) {
    131 		rc = psci_validate_entry_point(&ep, entrypoint, context_id);
    132 		if (rc != PSCI_E_SUCCESS)
    133 			return rc;
    134 	}
    135 
    136 	/*
    137 	 * Do what is needed to enter the power down state. Upon success,
    138 	 * enter the final wfi which will power down this CPU. This function
    139 	 * might return if the power down was abandoned for any reason, e.g.
    140 	 * arrival of an interrupt
    141 	 */
    142 	psci_cpu_suspend_start(&ep,
    143 			    target_pwrlvl,
    144 			    &state_info,
    145 			    is_power_down_state);
    146 
    147 	return PSCI_E_SUCCESS;
    148 }
    149 
    150 
    151 int psci_system_suspend(uintptr_t entrypoint, u_register_t context_id)
    152 {
    153 	int rc;
    154 	psci_power_state_t state_info;
    155 	entry_point_info_t ep;
    156 
    157 	/* Check if the current CPU is the last ON CPU in the system */
    158 	if (!psci_is_last_on_cpu())
    159 		return PSCI_E_DENIED;
    160 
    161 	/* Validate the entry point and get the entry_point_info */
    162 	rc = psci_validate_entry_point(&ep, entrypoint, context_id);
    163 	if (rc != PSCI_E_SUCCESS)
    164 		return rc;
    165 
    166 	/* Query the psci_power_state for system suspend */
    167 	psci_query_sys_suspend_pwrstate(&state_info);
    168 
    169 	/* Ensure that the psci_power_state makes sense */
    170 	assert(psci_find_target_suspend_lvl(&state_info) == PLAT_MAX_PWR_LVL);
    171 	assert(psci_validate_suspend_req(&state_info, PSTATE_TYPE_POWERDOWN)
    172 						== PSCI_E_SUCCESS);
    173 	assert(is_local_state_off(state_info.pwr_domain_state[PLAT_MAX_PWR_LVL]));
    174 
    175 	/*
    176 	 * Do what is needed to enter the system suspend state. This function
    177 	 * might return if the power down was abandoned for any reason, e.g.
    178 	 * arrival of an interrupt
    179 	 */
    180 	psci_cpu_suspend_start(&ep,
    181 			    PLAT_MAX_PWR_LVL,
    182 			    &state_info,
    183 			    PSTATE_TYPE_POWERDOWN);
    184 
    185 	return PSCI_E_SUCCESS;
    186 }
    187 
    188 int psci_cpu_off(void)
    189 {
    190 	int rc;
    191 	unsigned int target_pwrlvl = PLAT_MAX_PWR_LVL;
    192 
    193 	/*
    194 	 * Do what is needed to power off this CPU and possible higher power
    195 	 * levels if it able to do so. Upon success, enter the final wfi
    196 	 * which will power down this CPU.
    197 	 */
    198 	rc = psci_do_cpu_off(target_pwrlvl);
    199 
    200 	/*
    201 	 * The only error cpu_off can return is E_DENIED. So check if that's
    202 	 * indeed the case.
    203 	 */
    204 	assert(rc == PSCI_E_DENIED);
    205 
    206 	return rc;
    207 }
    208 
    209 int psci_affinity_info(u_register_t target_affinity,
    210 		       unsigned int lowest_affinity_level)
    211 {
    212 	int target_idx;
    213 
    214 	/* We dont support level higher than PSCI_CPU_PWR_LVL */
    215 	if (lowest_affinity_level > PSCI_CPU_PWR_LVL)
    216 		return PSCI_E_INVALID_PARAMS;
    217 
    218 	/* Calculate the cpu index of the target */
    219 	target_idx = plat_core_pos_by_mpidr(target_affinity);
    220 	if (target_idx == -1)
    221 		return PSCI_E_INVALID_PARAMS;
    222 
    223 	return psci_get_aff_info_state_by_idx(target_idx);
    224 }
    225 
    226 int psci_migrate(u_register_t target_cpu)
    227 {
    228 	int rc;
    229 	u_register_t resident_cpu_mpidr;
    230 
    231 	rc = psci_spd_migrate_info(&resident_cpu_mpidr);
    232 	if (rc != PSCI_TOS_UP_MIG_CAP)
    233 		return (rc == PSCI_TOS_NOT_UP_MIG_CAP) ?
    234 			  PSCI_E_DENIED : PSCI_E_NOT_SUPPORTED;
    235 
    236 	/*
    237 	 * Migrate should only be invoked on the CPU where
    238 	 * the Secure OS is resident.
    239 	 */
    240 	if (resident_cpu_mpidr != read_mpidr_el1())
    241 		return PSCI_E_NOT_PRESENT;
    242 
    243 	/* Check the validity of the specified target cpu */
    244 	rc = psci_validate_mpidr(target_cpu);
    245 	if (rc != PSCI_E_SUCCESS)
    246 		return PSCI_E_INVALID_PARAMS;
    247 
    248 	assert(psci_spd_pm && psci_spd_pm->svc_migrate);
    249 
    250 	rc = psci_spd_pm->svc_migrate(read_mpidr_el1(), target_cpu);
    251 	assert(rc == PSCI_E_SUCCESS || rc == PSCI_E_INTERN_FAIL);
    252 
    253 	return rc;
    254 }
    255 
    256 int psci_migrate_info_type(void)
    257 {
    258 	u_register_t resident_cpu_mpidr;
    259 
    260 	return psci_spd_migrate_info(&resident_cpu_mpidr);
    261 }
    262 
    263 long psci_migrate_info_up_cpu(void)
    264 {
    265 	u_register_t resident_cpu_mpidr;
    266 	int rc;
    267 
    268 	/*
    269 	 * Return value of this depends upon what
    270 	 * psci_spd_migrate_info() returns.
    271 	 */
    272 	rc = psci_spd_migrate_info(&resident_cpu_mpidr);
    273 	if (rc != PSCI_TOS_NOT_UP_MIG_CAP && rc != PSCI_TOS_UP_MIG_CAP)
    274 		return PSCI_E_INVALID_PARAMS;
    275 
    276 	return resident_cpu_mpidr;
    277 }
    278 
    279 int psci_node_hw_state(u_register_t target_cpu,
    280 		       unsigned int power_level)
    281 {
    282 	int rc;
    283 
    284 	/* Validate target_cpu */
    285 	rc = psci_validate_mpidr(target_cpu);
    286 	if (rc != PSCI_E_SUCCESS)
    287 		return PSCI_E_INVALID_PARAMS;
    288 
    289 	/* Validate power_level against PLAT_MAX_PWR_LVL */
    290 	if (power_level > PLAT_MAX_PWR_LVL)
    291 		return PSCI_E_INVALID_PARAMS;
    292 
    293 	/*
    294 	 * Dispatch this call to platform to query power controller, and pass on
    295 	 * to the caller what it returns
    296 	 */
    297 	assert(psci_plat_pm_ops->get_node_hw_state);
    298 	rc = psci_plat_pm_ops->get_node_hw_state(target_cpu, power_level);
    299 	assert((rc >= HW_ON && rc <= HW_STANDBY) || rc == PSCI_E_NOT_SUPPORTED
    300 			|| rc == PSCI_E_INVALID_PARAMS);
    301 	return rc;
    302 }
    303 
    304 int psci_features(unsigned int psci_fid)
    305 {
    306 	unsigned int local_caps = psci_caps;
    307 
    308 	/* Check if it is a 64 bit function */
    309 	if (((psci_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_64)
    310 		local_caps &= PSCI_CAP_64BIT_MASK;
    311 
    312 	/* Check for invalid fid */
    313 	if (!(is_std_svc_call(psci_fid) && is_valid_fast_smc(psci_fid)
    314 			&& is_psci_fid(psci_fid)))
    315 		return PSCI_E_NOT_SUPPORTED;
    316 
    317 
    318 	/* Check if the psci fid is supported or not */
    319 	if (!(local_caps & define_psci_cap(psci_fid)))
    320 		return PSCI_E_NOT_SUPPORTED;
    321 
    322 	/* Format the feature flags */
    323 	if (psci_fid == PSCI_CPU_SUSPEND_AARCH32 ||
    324 			psci_fid == PSCI_CPU_SUSPEND_AARCH64) {
    325 		/*
    326 		 * The trusted firmware does not support OS Initiated Mode.
    327 		 */
    328 		return (FF_PSTATE << FF_PSTATE_SHIFT) |
    329 			((!FF_SUPPORTS_OS_INIT_MODE) << FF_MODE_SUPPORT_SHIFT);
    330 	}
    331 
    332 	/* Return 0 for all other fid's */
    333 	return PSCI_E_SUCCESS;
    334 }
    335 
    336 /*******************************************************************************
    337  * PSCI top level handler for servicing SMCs.
    338  ******************************************************************************/
    339 u_register_t psci_smc_handler(uint32_t smc_fid,
    340 			  u_register_t x1,
    341 			  u_register_t x2,
    342 			  u_register_t x3,
    343 			  u_register_t x4,
    344 			  void *cookie,
    345 			  void *handle,
    346 			  u_register_t flags)
    347 {
    348 	if (is_caller_secure(flags))
    349 		return SMC_UNK;
    350 
    351 	/* Check the fid against the capabilities */
    352 	if (!(psci_caps & define_psci_cap(smc_fid)))
    353 		return SMC_UNK;
    354 
    355 	if (((smc_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_32) {
    356 		/* 32-bit PSCI function, clear top parameter bits */
    357 
    358 		x1 = (uint32_t)x1;
    359 		x2 = (uint32_t)x2;
    360 		x3 = (uint32_t)x3;
    361 
    362 		switch (smc_fid) {
    363 		case PSCI_VERSION:
    364 			return psci_version();
    365 
    366 		case PSCI_CPU_OFF:
    367 			return psci_cpu_off();
    368 
    369 		case PSCI_CPU_SUSPEND_AARCH32:
    370 			return psci_cpu_suspend(x1, x2, x3);
    371 
    372 		case PSCI_CPU_ON_AARCH32:
    373 			return psci_cpu_on(x1, x2, x3);
    374 
    375 		case PSCI_AFFINITY_INFO_AARCH32:
    376 			return psci_affinity_info(x1, x2);
    377 
    378 		case PSCI_MIG_AARCH32:
    379 			return psci_migrate(x1);
    380 
    381 		case PSCI_MIG_INFO_TYPE:
    382 			return psci_migrate_info_type();
    383 
    384 		case PSCI_MIG_INFO_UP_CPU_AARCH32:
    385 			return psci_migrate_info_up_cpu();
    386 
    387 		case PSCI_NODE_HW_STATE_AARCH32:
    388 			return psci_node_hw_state(x1, x2);
    389 
    390 		case PSCI_SYSTEM_SUSPEND_AARCH32:
    391 			return psci_system_suspend(x1, x2);
    392 
    393 		case PSCI_SYSTEM_OFF:
    394 			psci_system_off();
    395 			/* We should never return from psci_system_off() */
    396 
    397 		case PSCI_SYSTEM_RESET:
    398 			psci_system_reset();
    399 			/* We should never return from psci_system_reset() */
    400 
    401 		case PSCI_FEATURES:
    402 			return psci_features(x1);
    403 
    404 #if ENABLE_PSCI_STAT
    405 		case PSCI_STAT_RESIDENCY_AARCH32:
    406 			return psci_stat_residency(x1, x2);
    407 
    408 		case PSCI_STAT_COUNT_AARCH32:
    409 			return psci_stat_count(x1, x2);
    410 #endif
    411 		case PSCI_MEM_PROTECT:
    412 			return psci_mem_protect(x1);
    413 
    414 		case PSCI_MEM_CHK_RANGE_AARCH32:
    415 			return psci_mem_chk_range(x1, x2);
    416 
    417 		case PSCI_SYSTEM_RESET2_AARCH32:
    418 			/* We should never return from psci_system_reset2() */
    419 			return psci_system_reset2(x1, x2);
    420 
    421 		default:
    422 			break;
    423 		}
    424 	} else {
    425 		/* 64-bit PSCI function */
    426 
    427 		switch (smc_fid) {
    428 		case PSCI_CPU_SUSPEND_AARCH64:
    429 			return psci_cpu_suspend(x1, x2, x3);
    430 
    431 		case PSCI_CPU_ON_AARCH64:
    432 			return psci_cpu_on(x1, x2, x3);
    433 
    434 		case PSCI_AFFINITY_INFO_AARCH64:
    435 			return psci_affinity_info(x1, x2);
    436 
    437 		case PSCI_MIG_AARCH64:
    438 			return psci_migrate(x1);
    439 
    440 		case PSCI_MIG_INFO_UP_CPU_AARCH64:
    441 			return psci_migrate_info_up_cpu();
    442 
    443 		case PSCI_NODE_HW_STATE_AARCH64:
    444 			return psci_node_hw_state(x1, x2);
    445 
    446 		case PSCI_SYSTEM_SUSPEND_AARCH64:
    447 			return psci_system_suspend(x1, x2);
    448 
    449 #if ENABLE_PSCI_STAT
    450 		case PSCI_STAT_RESIDENCY_AARCH64:
    451 			return psci_stat_residency(x1, x2);
    452 
    453 		case PSCI_STAT_COUNT_AARCH64:
    454 			return psci_stat_count(x1, x2);
    455 #endif
    456 
    457 		case PSCI_MEM_CHK_RANGE_AARCH64:
    458 			return psci_mem_chk_range(x1, x2);
    459 
    460 		case PSCI_SYSTEM_RESET2_AARCH64:
    461 			/* We should never return from psci_system_reset2() */
    462 			return psci_system_reset2(x1, x2);
    463 
    464 		default:
    465 			break;
    466 		}
    467 	}
    468 
    469 	WARN("Unimplemented PSCI Call: 0x%x \n", smc_fid);
    470 	return SMC_UNK;
    471 }
    472