Tegra186: support for C6/C7 CPU_SUSPEND states

This patch adds support for the C6 and C7 CPU_SUSPEND states. C6 is
an idle state while C7 is a powerdown state.

The MCE block takes care of the entry/exit to/from these core power
states and hence we call the corresponding MCE handler to process
these requests. The NS driver passes the tentative time that the
core is expected to stay in this state as part of the power_state
parameter, which we store in a per-cpu array and pass it to the
MCE block.

Change-Id: I152acb11ab93d91fb866da2129b1795843dfa39b
Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
This commit is contained in:
Varun Wadekar 2016-01-18 19:03:19 -08:00
parent d48c0c45de
commit 7afd463753
3 changed files with 72 additions and 13 deletions

View File

@ -34,10 +34,22 @@
#include <platform_def.h>
/*******************************************************************************
* 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

View File

@ -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

View File

@ -40,22 +40,70 @@
#include <t18x_ari.h>
#include <tegra_private.h>
/* 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;