aboutsummaryrefslogtreecommitdiff
path: root/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c
diff options
context:
space:
mode:
authorVarun Wadekar <vwadekar@nvidia.com>2016-01-18 19:03:19 -0800
committerVarun Wadekar <vwadekar@nvidia.com>2017-03-20 09:13:52 -0700
commit7afd46375318bc912f6bb41362685371a003bb11 (patch)
tree611f457fb3f1dd5dbd19ec996e105d5b6ceae003 /plat/nvidia/tegra/soc/t186/plat_psci_handlers.c
parentd48c0c45de29e41bd5d464c75033f1077badea5f (diff)
downloadtrusted-firmware-a-7afd46375318bc912f6bb41362685371a003bb11.tar.gz
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>
Diffstat (limited to 'plat/nvidia/tegra/soc/t186/plat_psci_handlers.c')
-rw-r--r--plat/nvidia/tegra/soc/t186/plat_psci_handlers.c66
1 files changed, 57 insertions, 9 deletions
diff --git a/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c
index aa4291a65b..413e3f820c 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 <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;
+
+ 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);
- /* power domain in standby state */
- req_state->pwr_domain_state[pwr_lvl] = PLAT_MAX_RET_STATE;
+ } else {
+ ERROR("%s: Unknown state id\n", __func__);
+ return PSCI_E_NOT_SUPPORTED;
}
return PSCI_E_SUCCESS;