diff --git a/plat/nvidia/tegra/include/t186/tegra_def.h b/plat/nvidia/tegra/include/t186/tegra_def.h index bd2c5db9b..3983a6b03 100644 --- a/plat/nvidia/tegra/include/t186/tegra_def.h +++ b/plat/nvidia/tegra/include/t186/tegra_def.h @@ -34,10 +34,22 @@ #include /******************************************************************************* - * This value is used by the PSCI implementation during the `SYSTEM_SUSPEND` - * call as the `state-id` field in the 'power state' parameter. + * These values are used by the PSCI implementation during the `CPU_SUSPEND` + * and `SYSTEM_SUSPEND` calls as the `state-id` field in the 'power state' + * parameter. ******************************************************************************/ -#define PSTATE_ID_SOC_POWERDN 1 +#define PSTATE_ID_CORE_IDLE 6 +#define PSTATE_ID_CORE_POWERDN 7 +#define PSTATE_ID_SOC_POWERDN 2 + +/******************************************************************************* + * Platform power states (used by PSCI framework) + * + * - PLAT_MAX_RET_STATE should be less than lowest PSTATE_ID + * - PLAT_MAX_OFF_STATE should be greater than the highest PSTATE_ID + ******************************************************************************/ +#define PLAT_MAX_RET_STATE 1 +#define PLAT_MAX_OFF_STATE 8 /******************************************************************************* * Implementation defined ACTLR_EL3 bit definitions diff --git a/plat/nvidia/tegra/soc/t186/drivers/mce/aarch64/nvg_helpers.S b/plat/nvidia/tegra/soc/t186/drivers/mce/aarch64/nvg_helpers.S index e1398ccee..b6e4b31ab 100644 --- a/plat/nvidia/tegra/soc/t186/drivers/mce/aarch64/nvg_helpers.S +++ b/plat/nvidia/tegra/soc/t186/drivers/mce/aarch64/nvg_helpers.S @@ -39,7 +39,6 @@ func nvg_set_request_data msr s3_0_c15_c1_2, x0 msr s3_0_c15_c1_3, x1 - isb ret endfunc nvg_set_request_data diff --git a/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c index aa4291a65..413e3f820 100644 --- a/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c +++ b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c @@ -40,22 +40,70 @@ #include #include +/* state id mask */ +#define TEGRA186_STATE_ID_MASK 0xF +/* constants to get power state's wake time */ +#define TEGRA186_WAKE_TIME_MASK 0xFFFFFF +#define TEGRA186_WAKE_TIME_SHIFT 4 + +/* per cpu wake time value */ +static unsigned int wake_time[PLATFORM_CORE_COUNT]; + int32_t tegra_soc_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { - int pwr_lvl = psci_get_pstate_pwrlvl(power_state); + int state_id = psci_get_pstate_id(power_state) & TEGRA186_STATE_ID_MASK; + int cpu = read_mpidr() & MPIDR_CPU_MASK; - /* Sanity check the requested afflvl */ - if (psci_get_pstate_type(power_state) == PSTATE_TYPE_STANDBY) { + /* get the wake time value */ + wake_time[cpu] = (power_state & TEGRA186_WAKE_TIME_MASK) >> + TEGRA186_WAKE_TIME_SHIFT; + + /* Sanity check the requested state id */ + switch (state_id) { + case PSTATE_ID_CORE_IDLE: + case PSTATE_ID_CORE_POWERDN: /* - * It's possible to enter standby only on affinity level 0 i.e. - * a cpu on Tegra. Ignore any other affinity level. + * Core powerdown request only for afflvl 0 */ - if (pwr_lvl != MPIDR_AFFLVL0) - return PSCI_E_INVALID_PARAMS; + req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id; - /* power domain in standby state */ - req_state->pwr_domain_state[pwr_lvl] = PLAT_MAX_RET_STATE; + break; + + default: + ERROR("%s: unsupported state id (%d)\n", __func__, state_id); + return PSCI_E_INVALID_PARAMS; + } + + return PSCI_E_SUCCESS; +} + +int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) +{ + const plat_local_state_t *pwr_domain_state; + unsigned int stateid_afflvl0; + int cpu = read_mpidr() & MPIDR_CPU_MASK; + + /* get the state ID */ + pwr_domain_state = target_state->pwr_domain_state; + stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0] & + TEGRA186_STATE_ID_MASK; + + if (stateid_afflvl0 == PSTATE_ID_CORE_IDLE) { + + /* Prepare for cpu idle */ + (void)mce_command_handler(MCE_CMD_ENTER_CSTATE, + TEGRA_ARI_CORE_C6, wake_time[cpu], 0); + + } else if (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN) { + + /* Prepare for cpu powerdn */ + (void)mce_command_handler(MCE_CMD_ENTER_CSTATE, + TEGRA_ARI_CORE_C7, wake_time[cpu], 0); + + } else { + ERROR("%s: Unknown state id\n", __func__); + return PSCI_E_NOT_SUPPORTED; } return PSCI_E_SUCCESS;