summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plat/nvidia/tegra/include/t186/tegra_def.h18
-rw-r--r--plat/nvidia/tegra/soc/t186/drivers/mce/aarch64/nvg_helpers.S1
-rw-r--r--plat/nvidia/tegra/soc/t186/plat_psci_handlers.c66
3 files changed, 72 insertions, 13 deletions
diff --git a/plat/nvidia/tegra/include/t186/tegra_def.h b/plat/nvidia/tegra/include/t186/tegra_def.h
index bd2c5db9..3983a6b0 100644
--- a/plat/nvidia/tegra/include/t186/tegra_def.h
+++ b/plat/nvidia/tegra/include/t186/tegra_def.h
@@ -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
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 e1398cce..b6e4b31a 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 aa4291a6..413e3f82 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;