/******************************************************************************* * This function returns highest affinity level which is in OFF * state. The affinity instance with which the level is associated is * determined by the caller. ******************************************************************************/ unsigned int psci_get_max_phys_off_afflvl(void) { psci_power_state_t state_info; memset(&state_info, 0, sizeof(state_info)); psci_get_target_local_pwr_states(PLAT_MAX_PWR_LVL, &state_info); return psci_find_target_suspend_lvl(&state_info); }
/****************************************************************************** * This function validates a suspend request by making sure that if a standby * state is requested then no power level is turned off and the highest power * level is placed in a standby/retention state. * * It also ensures that the state level X will enter is not shallower than the * state level X + 1 will enter. * * This validation will be enabled only for DEBUG builds as the platform is * expected to perform these validations as well. *****************************************************************************/ int psci_validate_suspend_req(const psci_power_state_t *state_info, unsigned int is_power_down_state) { unsigned int max_off_lvl, target_lvl, max_retn_lvl; plat_local_state_t state; plat_local_state_type_t req_state_type, deepest_state_type; int i; /* Find the target suspend power level */ target_lvl = psci_find_target_suspend_lvl(state_info); if (target_lvl == PSCI_INVALID_PWR_LVL) return PSCI_E_INVALID_PARAMS; /* All power domain levels are in a RUN state to begin with */ deepest_state_type = STATE_TYPE_RUN; for (i = target_lvl; i >= PSCI_CPU_PWR_LVL; i--) { state = state_info->pwr_domain_state[i]; req_state_type = find_local_state_type(state); /* * While traversing from the highest power level to the lowest, * the state requested for lower levels has to be the same or * deeper i.e. equal to or greater than the state at the higher * levels. If this condition is true, then the requested state * becomes the deepest state encountered so far. */ if (req_state_type < deepest_state_type) return PSCI_E_INVALID_PARAMS; deepest_state_type = req_state_type; } /* Find the highest off power level */ max_off_lvl = psci_find_max_off_lvl(state_info); /* The target_lvl is either equal to the max_off_lvl or max_retn_lvl */ max_retn_lvl = PSCI_INVALID_PWR_LVL; if (target_lvl != max_off_lvl) max_retn_lvl = target_lvl; /* * If this is not a request for a power down state then max off level * has to be invalid and max retention level has to be a valid power * level. */ if (!is_power_down_state && (max_off_lvl != PSCI_INVALID_PWR_LVL || max_retn_lvl == PSCI_INVALID_PWR_LVL)) return PSCI_E_INVALID_PARAMS; return PSCI_E_SUCCESS; }
/******************************************************************************* * This function returns the appropriate count and residency time of the * local state for the highest power level expressed in the `power_state` * for the node represented by `target_cpu`. ******************************************************************************/ int psci_get_stat(u_register_t target_cpu, unsigned int power_state, psci_stat_t *psci_stat) { int rc, pwrlvl, lvl, parent_idx, stat_idx, target_idx; psci_power_state_t state_info = { {PSCI_LOCAL_STATE_RUN} }; plat_local_state_t local_state; /* Validate the target_cpu parameter and determine the cpu index */ target_idx = plat_core_pos_by_mpidr(target_cpu); if (target_idx == -1) return PSCI_E_INVALID_PARAMS; /* Validate the power_state parameter */ if (!psci_plat_pm_ops->translate_power_state_by_mpidr) rc = psci_validate_power_state(power_state, &state_info); else rc = psci_plat_pm_ops->translate_power_state_by_mpidr( target_cpu, power_state, &state_info); if (rc != PSCI_E_SUCCESS) return PSCI_E_INVALID_PARAMS; /* Find the highest power level */ pwrlvl = psci_find_target_suspend_lvl(&state_info); if (pwrlvl == PSCI_INVALID_PWR_LVL) return PSCI_E_INVALID_PARAMS; /* Get the index into the stats array */ local_state = state_info.pwr_domain_state[pwrlvl]; stat_idx = get_stat_idx(local_state, pwrlvl); if (pwrlvl > PSCI_CPU_PWR_LVL) { /* Get the power domain index */ parent_idx = psci_cpu_pd_nodes[target_idx].parent_node; for (lvl = PSCI_CPU_PWR_LVL + 1; lvl < pwrlvl; lvl++) parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node; /* Get the non cpu power domain stats */ *psci_stat = psci_non_cpu_stat[parent_idx][stat_idx]; } else { /* Get the cpu power domain stats */ *psci_stat = psci_cpu_stat[target_idx][stat_idx]; } return PSCI_E_SUCCESS; }