Merge pull request #455 from jcastillo-arm/jc/fvp_delay_timer

Fix SP804 delay timer on FVP
diff --git a/include/drivers/arm/cci400.h b/include/drivers/arm/cci400.h
index 620221a..a5dc9a0 100644
--- a/include/drivers/arm/cci400.h
+++ b/include/drivers/arm/cci400.h
@@ -31,6 +31,14 @@
 #ifndef __CCI_400_H__
 #define __CCI_400_H__
 
+/**************************************************************
+ * THIS DRIVER IS DEPRECATED. Please use the driver in cci.h
+ **************************************************************/
+#if ERROR_DEPRECATED
+#error " The CCI-400 specific driver is deprecated."
+#endif
+
+
 /* Slave interface offsets from PERIPHBASE */
 #define SLAVE_IFACE4_OFFSET		0x5000
 #define SLAVE_IFACE3_OFFSET		0x4000
@@ -68,6 +76,7 @@
 
 #ifndef __ASSEMBLY__
 
+#include <common_def.h>
 #include <stdint.h>
 
 /* Function declarations */
@@ -83,10 +92,10 @@
  */
 void cci_init(uintptr_t cci_base,
 		int slave_iface3_cluster_ix,
-		int slave_iface4_cluster_ix);
+		int slave_iface4_cluster_ix) __warn_deprecated;
 
-void cci_enable_cluster_coherency(unsigned long mpidr);
-void cci_disable_cluster_coherency(unsigned long mpidr);
+void cci_enable_cluster_coherency(unsigned long mpidr) __warn_deprecated;
+void cci_disable_cluster_coherency(unsigned long mpidr) __warn_deprecated;
 
 #endif /* __ASSEMBLY__ */
 #endif /* __CCI_400_H__ */
diff --git a/plat/nvidia/tegra/common/aarch64/tegra_helpers.S b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S
index d9f287c..a4caf5e 100644
--- a/plat/nvidia/tegra/common/aarch64/tegra_helpers.S
+++ b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S
@@ -36,9 +36,9 @@
 #include <tegra_def.h>
 
 	/* Global functions */
-	.globl	platform_is_primary_cpu
-	.globl	platform_get_core_pos
-	.globl	platform_get_entrypoint
+	.globl	plat_is_my_cpu_primary
+	.globl	plat_my_core_pos
+	.globl	plat_get_my_entrypoint
 	.globl	plat_secondary_cold_boot_setup
 	.globl	platform_mem_init
 	.globl	plat_crash_console_init
@@ -47,7 +47,7 @@
 	.globl	plat_reset_handler
 
 	/* Global variables */
-	.globl	sec_entry_point
+	.globl	tegra_sec_entry_point
 	.globl	ns_image_entrypoint
 	.globl	tegra_bl31_phys_base
 
@@ -115,28 +115,47 @@
 .endm
 
 	/* -----------------------------------------------------
-	 * int platform_is_primary_cpu(int mpidr);
+	 * unsigned int plat_is_my_cpu_primary(void);
 	 *
 	 * This function checks if this is the Primary CPU
 	 * -----------------------------------------------------
 	 */
-func platform_is_primary_cpu
+func plat_is_my_cpu_primary
+	mrs	x0, mpidr_el1
 	and	x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
 	cmp	x0, #TEGRA_PRIMARY_CPU
 	cset	x0, eq
 	ret
-endfunc platform_is_primary_cpu
+endfunc plat_is_my_cpu_primary
 
 	/* -----------------------------------------------------
-	 * int platform_get_core_pos(int mpidr);
+	 * unsigned int plat_my_core_pos(void);
+	 *
+	 * result: CorePos = CoreId + (ClusterId << 2)
+	 * -----------------------------------------------------
+	 */
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	add	x0, x1, x0, LSR #6
+	ret
+endfunc plat_my_core_pos
+
+	/* -----------------------------------------------------
+	 * unsigned long plat_get_my_entrypoint (void);
+	 *
+	 * Main job of this routine is to distinguish between
+	 * a cold and warm boot. If the tegra_sec_entry_point for
+	 * this CPU is present, then it's a warm boot.
 	 *
-	 * With this function: CorePos = CoreId
 	 * -----------------------------------------------------
 	 */
-func platform_get_core_pos
-	and	x0, x0, #MPIDR_CPU_MASK
+func plat_get_my_entrypoint
+	adr	x1, tegra_sec_entry_point
+	ldr	x0, [x1]
 	ret
-endfunc platform_get_core_pos
+endfunc plat_get_my_entrypoint
 
 	/* -----------------------------------------------------
 	 * void plat_secondary_cold_boot_setup (void);
@@ -151,22 +170,6 @@
 	ret
 endfunc plat_secondary_cold_boot_setup
 
-	/* -----------------------------------------------------
-	 * void platform_get_entrypoint (unsigned int mpidr);
-	 *
-	 * Main job of this routine is to distinguish between
-	 * a cold and warm boot. If the sec_entry_point for
-	 * this CPU is present, then it's a warm boot.
-	 *
-	 * -----------------------------------------------------
-	 */
-func platform_get_entrypoint
-	and	x0, x0, #MPIDR_CPU_MASK
-	adr	x1, sec_entry_point
-	ldr	x0, [x1, x0, lsl #3]
-	ret
-endfunc platform_get_entrypoint
-
 	/* --------------------------------------------------------
 	 * void platform_mem_init (void);
 	 *
@@ -336,8 +339,7 @@
 	 * Get secure world's entry point and jump to it
 	 * --------------------------------------------------
 	 */
-	mrs	x0, mpidr_el1
-	bl	platform_get_entrypoint
+	bl	plat_get_my_entrypoint
 	br	x0
 endfunc tegra_secure_entrypoint
 
@@ -345,13 +347,11 @@
 	.align 3
 
 	/* --------------------------------------------------
-	 * Per-CPU Secure entry point - resume from suspend
+	 * CPU Secure entry point - resume from suspend
 	 * --------------------------------------------------
 	 */
-sec_entry_point:
-	.rept	PLATFORM_CORE_COUNT
+tegra_sec_entry_point:
 	.quad	0
-	.endr
 
 	/* --------------------------------------------------
 	 * NS world's cold boot entry point
diff --git a/plat/nvidia/tegra/common/drivers/flowctrl/flowctrl.c b/plat/nvidia/tegra/common/drivers/flowctrl/flowctrl.c
index b473dd6..3571758 100644
--- a/plat/nvidia/tegra/common/drivers/flowctrl/flowctrl.c
+++ b/plat/nvidia/tegra/common/drivers/flowctrl/flowctrl.c
@@ -98,9 +98,9 @@
 }
 
 /*******************************************************************************
- * Suspend the current CPU
+ * Powerdn the current CPU
  ******************************************************************************/
-void tegra_fc_cpu_idle(uint32_t mpidr)
+void tegra_fc_cpu_powerdn(uint32_t mpidr)
 {
 	int cpu = mpidr & MPIDR_CPU_MASK;
 
diff --git a/plat/nvidia/tegra/common/tegra_common.mk b/plat/nvidia/tegra/common/tegra_common.mk
index e1c0d84..fcebde3 100644
--- a/plat/nvidia/tegra/common/tegra_common.mk
+++ b/plat/nvidia/tegra/common/tegra_common.mk
@@ -51,6 +51,7 @@
 				drivers/delay_timer/delay_timer.c		\
 				drivers/ti/uart/16550_console.S			\
 				plat/common/aarch64/platform_mp_stack.S		\
+				plat/common/aarch64/plat_psci_common.c		\
 				${COMMON_DIR}/aarch64/tegra_helpers.S		\
 				${COMMON_DIR}/drivers/memctrl/memctrl.c		\
 				${COMMON_DIR}/drivers/pmc/pmc.c			\
diff --git a/plat/nvidia/tegra/common/tegra_pm.c b/plat/nvidia/tegra/common/tegra_pm.c
index c2c73f6..6fb3e9c 100644
--- a/plat/nvidia/tegra/common/tegra_pm.c
+++ b/plat/nvidia/tegra/common/tegra_pm.c
@@ -44,35 +44,34 @@
 #include <tegra_private.h>
 
 extern uint64_t tegra_bl31_phys_base;
-extern uint64_t sec_entry_point[PLATFORM_CORE_COUNT];
-static int system_suspended;
+extern uint64_t tegra_sec_entry_point;
 
 /*
  * The following platform setup functions are weakly defined. They
  * provide typical implementations that will be overridden by a SoC.
  */
-#pragma weak tegra_soc_prepare_cpu_suspend
-#pragma weak tegra_soc_prepare_cpu_on
-#pragma weak tegra_soc_prepare_cpu_off
-#pragma weak tegra_soc_prepare_cpu_on_finish
+#pragma weak tegra_soc_pwr_domain_suspend
+#pragma weak tegra_soc_pwr_domain_on
+#pragma weak tegra_soc_pwr_domain_off
+#pragma weak tegra_soc_pwr_domain_on_finish
 #pragma weak tegra_soc_prepare_system_reset
 
-int tegra_soc_prepare_cpu_suspend(unsigned int id, unsigned int afflvl)
+int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
 {
 	return PSCI_E_NOT_SUPPORTED;
 }
 
-int tegra_soc_prepare_cpu_on(unsigned long mpidr)
+int tegra_soc_pwr_domain_on(u_register_t mpidr)
 {
 	return PSCI_E_SUCCESS;
 }
 
-int tegra_soc_prepare_cpu_off(unsigned long mpidr)
+int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
 {
 	return PSCI_E_SUCCESS;
 }
 
-int tegra_soc_prepare_cpu_on_finish(unsigned long mpidr)
+int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
 {
 	return PSCI_E_SUCCESS;
 }
@@ -83,33 +82,25 @@
 }
 
 /*******************************************************************************
- * Track system suspend entry.
- ******************************************************************************/
-void tegra_pm_system_suspend_entry(void)
-{
-	system_suspended = 1;
-}
-
-/*******************************************************************************
- * Track system suspend exit.
- ******************************************************************************/
-void tegra_pm_system_suspend_exit(void)
+ * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND`
+ * call to get the `power_state` parameter. This allows the platform to encode
+ * the appropriate State-ID field within the `power_state` parameter which can
+ * be utilized in `pwr_domain_suspend()` to suspend to system affinity level.
+******************************************************************************/
+void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state)
 {
-	system_suspended = 0;
-}
+	/* lower affinities use PLAT_MAX_OFF_STATE */
+	for (int i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
 
-/*******************************************************************************
- * Get the system suspend state.
- ******************************************************************************/
-int tegra_system_suspended(void)
-{
-	return system_suspended;
+	/* max affinity uses system suspend state id */
+	req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSTATE_ID_SOC_POWERDN;
 }
 
 /*******************************************************************************
  * Handler called when an affinity instance is about to enter standby.
  ******************************************************************************/
-void tegra_affinst_standby(unsigned int power_state)
+void tegra_cpu_standby(plat_local_state_t cpu_state)
 {
 	/*
 	 * Enter standby state
@@ -120,132 +111,45 @@
 }
 
 /*******************************************************************************
- * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND`
- * call to get the `power_state` parameter. This allows the platform to encode
- * the appropriate State-ID field within the `power_state` parameter which can
- * be utilized in `affinst_suspend()` to suspend to system affinity level.
-******************************************************************************/
-unsigned int tegra_get_sys_suspend_power_state(void)
-{
-	unsigned int power_state;
-
-	power_state = psci_make_powerstate(PLAT_SYS_SUSPEND_STATE_ID,
-			PSTATE_TYPE_POWERDOWN, MPIDR_AFFLVL2);
-
-	return power_state;
-}
-
-/*******************************************************************************
- * Handler called to check the validity of the power state parameter.
- ******************************************************************************/
-int32_t tegra_validate_power_state(unsigned int power_state)
-{
-	return tegra_soc_validate_power_state(power_state);
-}
-
-/*******************************************************************************
  * Handler called when an affinity instance is about to be turned on. The
  * level and mpidr determine the affinity instance.
  ******************************************************************************/
-int tegra_affinst_on(unsigned long mpidr,
-		   unsigned long sec_entrypoint,
-		   unsigned int afflvl,
-		   unsigned int state)
+int tegra_pwr_domain_on(u_register_t mpidr)
 {
-	int cpu = mpidr & MPIDR_CPU_MASK;
-
-	/*
-	 * Support individual CPU power on only.
-	 */
-	if (afflvl > MPIDR_AFFLVL0)
-		return PSCI_E_SUCCESS;
-
-	/*
-	 * Flush entrypoint variable to PoC since it will be
-	 * accessed after a reset with the caches turned off.
-	 */
-	sec_entry_point[cpu] = sec_entrypoint;
-	flush_dcache_range((uint64_t)&sec_entry_point[cpu], sizeof(uint64_t));
-
-	return tegra_soc_prepare_cpu_on(mpidr);
+	return tegra_soc_pwr_domain_on(mpidr);
 }
 
 /*******************************************************************************
- * Handler called when an affinity instance is about to be turned off. The
- * level determines the affinity instance. The 'state' arg. allows the
- * platform to decide whether the cluster is being turned off and take apt
- * actions.
- *
- * CAUTION: This function is called with coherent stacks so that caches can be
- * turned off, flushed and coherency disabled. There is no guarantee that caches
- * will remain turned on across calls to this function as each affinity level is
- * dealt with. So do not write & read global variables across calls. It will be
- * wise to do flush a write to the global to prevent unpredictable results.
+ * Handler called when a power domain is about to be turned off. The
+ * target_state encodes the power state that each level should transition to.
  ******************************************************************************/
-void tegra_affinst_off(unsigned int afflvl, unsigned int state)
+void tegra_pwr_domain_off(const psci_power_state_t *target_state)
 {
-	/*
-	 * Support individual CPU power off only.
-	 */
-	if (afflvl > MPIDR_AFFLVL0)
-		return;
-
-	tegra_soc_prepare_cpu_off(read_mpidr());
+	tegra_soc_pwr_domain_off(target_state);
 }
 
 /*******************************************************************************
- * Handler called when an affinity instance is about to be suspended. The
- * level and mpidr determine the affinity instance. The 'state' arg. allows the
- * platform to decide whether the cluster is being turned off and take apt
- * actions.
- *
- * CAUTION: This function is called with coherent stacks so that caches can be
- * turned off, flushed and coherency disabled. There is no guarantee that caches
- * will remain turned on across calls to this function as each affinity level is
- * dealt with. So do not write & read global variables across calls. It will be
- * wise to flush a write to the global variable, to prevent unpredictable
- * results.
+ * Handler called when called when a power domain is about to be suspended. The
+ * target_state encodes the power state that each level should transition to.
  ******************************************************************************/
-void tegra_affinst_suspend(unsigned long sec_entrypoint,
-			unsigned int afflvl,
-			unsigned int state)
+void tegra_pwr_domain_suspend(const psci_power_state_t *target_state)
 {
-	int id = psci_get_suspend_stateid();
-	int cpu = read_mpidr() & MPIDR_CPU_MASK;
-
-	if (afflvl > PLATFORM_MAX_AFFLVL)
-		return;
-
-	/*
-	 * Flush entrypoint variable to PoC since it will be
-	 * accessed after a reset with the caches turned off.
-	 */
-	sec_entry_point[cpu] = sec_entrypoint;
-	flush_dcache_range((uint64_t)&sec_entry_point[cpu], sizeof(uint64_t));
-
-	tegra_soc_prepare_cpu_suspend(id, afflvl);
+	tegra_soc_pwr_domain_suspend(target_state);
 
 	/* disable GICC */
 	tegra_gic_cpuif_deactivate();
 }
 
 /*******************************************************************************
- * Handler called when an affinity instance has just been powered on after
- * being turned off earlier. The level determines the affinity instance.
- * The 'state' arg. allows the platform to decide whether the cluster was
- * turned off prior to wakeup and do what's necessary to set it up.
+ * Handler called when a power domain has just been powered on after
+ * being turned off earlier. The target_state encodes the low power state that
+ * each level has woken up from.
  ******************************************************************************/
-void tegra_affinst_on_finish(unsigned int afflvl, unsigned int state)
+void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state)
 {
 	plat_params_from_bl2_t *plat_params;
 
 	/*
-	 * Support individual CPU power on only.
-	 */
-	if (afflvl > MPIDR_AFFLVL0)
-		return;
-
-	/*
 	 * Initialize the GIC cpu and distributor interfaces
 	 */
 	tegra_gic_setup();
@@ -253,7 +157,8 @@
 	/*
 	 * Check if we are exiting from deep sleep.
 	 */
-	if (tegra_system_suspended()) {
+	if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] ==
+			PSTATE_ID_SOC_POWERDN) {
 
 		/*
 		 * Lock scratch registers which hold the CPU vectors.
@@ -276,18 +181,17 @@
 	/*
 	 * Reset hardware settings.
 	 */
-	tegra_soc_prepare_cpu_on_finish(read_mpidr());
+	tegra_soc_pwr_domain_on_finish(target_state);
 }
 
 /*******************************************************************************
- * Handler called when an affinity instance has just been powered on after
- * having been suspended earlier. The level and mpidr determine the affinity
- * instance.
+ * Handler called when a power domain has just been powered on after
+ * having been suspended earlier. The target_state encodes the low power state
+ * that each level has woken up from.
  ******************************************************************************/
-void tegra_affinst_suspend_finish(unsigned int afflvl, unsigned int state)
+void tegra_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
 {
-	if (afflvl == MPIDR_AFFLVL0)
-		tegra_affinst_on_finish(afflvl, state);
+	tegra_pwr_domain_on_finish(target_state);
 }
 
 /*******************************************************************************
@@ -314,35 +218,77 @@
 }
 
 /*******************************************************************************
+ * Handler called to check the validity of the power state parameter.
+ ******************************************************************************/
+int32_t tegra_validate_power_state(unsigned int power_state,
+				   psci_power_state_t *req_state)
+{
+	int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
+
+	assert(req_state);
+
+	if (pwr_lvl > PLAT_MAX_PWR_LVL)
+		return PSCI_E_INVALID_PARAMS;
+
+	return tegra_soc_validate_power_state(power_state, req_state);
+}
+
+/*******************************************************************************
+ * Platform handler called to check the validity of the non secure entrypoint.
+ ******************************************************************************/
+int tegra_validate_ns_entrypoint(uintptr_t entrypoint)
+{
+	/*
+	 * Check if the non secure entrypoint lies within the non
+	 * secure DRAM.
+	 */
+	if ((entrypoint >= TEGRA_DRAM_BASE) && (entrypoint <= TEGRA_DRAM_END))
+		return PSCI_E_SUCCESS;
+
+	return PSCI_E_INVALID_ADDRESS;
+}
+
+/*******************************************************************************
  * Export the platform handlers to enable psci to invoke them
  ******************************************************************************/
-static const plat_pm_ops_t tegra_plat_pm_ops = {
-	.affinst_standby	= tegra_affinst_standby,
-	.affinst_on		= tegra_affinst_on,
-	.affinst_off		= tegra_affinst_off,
-	.affinst_suspend	= tegra_affinst_suspend,
-	.affinst_on_finish	= tegra_affinst_on_finish,
-	.affinst_suspend_finish	= tegra_affinst_suspend_finish,
-	.system_off		= tegra_system_off,
-	.system_reset		= tegra_system_reset,
-	.validate_power_state	= tegra_validate_power_state,
-	.get_sys_suspend_power_state = tegra_get_sys_suspend_power_state
+static const plat_psci_ops_t tegra_plat_psci_ops = {
+	.cpu_standby			= tegra_cpu_standby,
+	.pwr_domain_on			= tegra_pwr_domain_on,
+	.pwr_domain_off			= tegra_pwr_domain_off,
+	.pwr_domain_suspend		= tegra_pwr_domain_suspend,
+	.pwr_domain_on_finish		= tegra_pwr_domain_on_finish,
+	.pwr_domain_suspend_finish	= tegra_pwr_domain_suspend_finish,
+	.system_off			= tegra_system_off,
+	.system_reset			= tegra_system_reset,
+	.validate_power_state		= tegra_validate_power_state,
+	.validate_ns_entrypoint		= tegra_validate_ns_entrypoint,
+	.get_sys_suspend_power_state	= tegra_get_sys_suspend_power_state,
 };
 
 /*******************************************************************************
- * Export the platform specific power ops & initialize the fvp power controller
+ * Export the platform specific power ops and initialize Power Controller
  ******************************************************************************/
-int platform_setup_pm(const plat_pm_ops_t **plat_ops)
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
 {
+	psci_power_state_t target_state = { { PSCI_LOCAL_STATE_RUN } };
+
+	/*
+	 * Flush entrypoint variable to PoC since it will be
+	 * accessed after a reset with the caches turned off.
+	 */
+	tegra_sec_entry_point = sec_entrypoint;
+	flush_dcache_range((uint64_t)&tegra_sec_entry_point, sizeof(uint64_t));
+
 	/*
 	 * Reset hardware settings.
 	 */
-	tegra_soc_prepare_cpu_on_finish(read_mpidr());
+	tegra_soc_pwr_domain_on_finish(&target_state);
 
 	/*
-	 * Initialize PM ops struct
+	 * Initialize PSCI ops struct
 	 */
-	*plat_ops = &tegra_plat_pm_ops;
+	*psci_ops = &tegra_plat_psci_ops;
 
 	return 0;
 }
diff --git a/plat/nvidia/tegra/common/tegra_topology.c b/plat/nvidia/tegra/common/tegra_topology.c
index 220e697..0431d98 100644
--- a/plat/nvidia/tegra/common/tegra_topology.c
+++ b/plat/nvidia/tegra/common/tegra_topology.c
@@ -28,45 +28,47 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <arch_helpers.h>
+#include <arch.h>
 #include <platform_def.h>
 #include <psci.h>
 
+extern const unsigned char tegra_power_domain_tree_desc[];
+
 /*******************************************************************************
- * This function implements a part of the critical interface between the psci
- * generic layer and the platform to allow the former to detect the platform
- * topology. psci queries the platform to determine how many affinity instances
- * are present at a particular level for a given mpidr.
+ * This function returns the Tegra default topology tree information.
  ******************************************************************************/
-unsigned int plat_get_aff_count(unsigned int aff_lvl,
-				unsigned long mpidr)
+const unsigned char *plat_get_power_domain_tree_desc(void)
 {
-	switch (aff_lvl) {
-	case MPIDR_AFFLVL2:
-		/* Last supported affinity level */
-		return 1;
-
-	case MPIDR_AFFLVL1:
-		/* Return # of clusters */
-		return PLATFORM_CLUSTER_COUNT;
-
-	case MPIDR_AFFLVL0:
-		/* # of cpus per cluster */
-		return PLATFORM_MAX_CPUS_PER_CLUSTER;
-
-	default:
-		return PSCI_AFF_ABSENT;
-	}
+	return tegra_power_domain_tree_desc;
 }
 
 /*******************************************************************************
  * This function implements a part of the critical interface between the psci
- * generic layer and the platform to allow the former to detect the state of a
- * affinity instance in the platform topology. psci queries the platform to
- * determine whether an affinity instance is present or absent.
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
  ******************************************************************************/
-unsigned int plat_get_aff_state(unsigned int aff_lvl,
-				unsigned long mpidr)
+int plat_core_pos_by_mpidr(u_register_t mpidr)
 {
-	return (aff_lvl <= MPIDR_AFFLVL2) ? PSCI_AFF_PRESENT : PSCI_AFF_ABSENT;
+	unsigned int cluster_id, cpu_id;
+
+	mpidr &= MPIDR_AFFINITY_MASK;
+
+	if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK))
+		return -1;
+
+	cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+
+	if (cluster_id >= PLATFORM_CLUSTER_COUNT)
+		return -1;
+
+	/*
+	 * Validate cpu_id by checking whether it represents a CPU in
+	 * one of the two clusters present on the platform.
+	 */
+	if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER)
+		return -1;
+
+	return (cpu_id + (cluster_id * 4));
 }
diff --git a/plat/nvidia/tegra/include/drivers/flowctrl.h b/plat/nvidia/tegra/include/drivers/flowctrl.h
index 8bc821d..23909e8 100644
--- a/plat/nvidia/tegra/include/drivers/flowctrl.h
+++ b/plat/nvidia/tegra/include/drivers/flowctrl.h
@@ -73,8 +73,8 @@
 	mmio_write_32(TEGRA_FLOWCTRL_BASE + off, val);
 }
 
-void tegra_fc_cpu_idle(uint32_t mpidr);
 void tegra_fc_cluster_idle(uint32_t midr);
+void tegra_fc_cpu_powerdn(uint32_t mpidr);
 void tegra_fc_cluster_powerdn(uint32_t midr);
 void tegra_fc_soc_powerdn(uint32_t midr);
 void tegra_fc_cpu_on(int cpu);
diff --git a/plat/nvidia/tegra/include/platform_def.h b/plat/nvidia/tegra/include/platform_def.h
index c59e2be..2a7935f 100644
--- a/plat/nvidia/tegra/include/platform_def.h
+++ b/plat/nvidia/tegra/include/platform_def.h
@@ -33,6 +33,7 @@
 
 #include <arch.h>
 #include <common_def.h>
+#include <tegra_def.h>
 
 /*******************************************************************************
  * Generic platform constants
@@ -47,13 +48,19 @@
 
 #define TEGRA_PRIMARY_CPU		0x0
 
-#define PLATFORM_MAX_AFFLVL		MPIDR_AFFLVL2
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL2
 #define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER_COUNT * \
 					 PLATFORM_MAX_CPUS_PER_CLUSTER)
-#define PLATFORM_NUM_AFFS		(PLATFORM_CORE_COUNT + \
+#define PLAT_NUM_PWR_DOMAINS		(PLATFORM_CORE_COUNT + \
 					 PLATFORM_CLUSTER_COUNT + 1)
 
 /*******************************************************************************
+ * Platform power states
+ ******************************************************************************/
+#define PLAT_MAX_RET_STATE		1
+#define PLAT_MAX_OFF_STATE		(PSTATE_ID_SOC_POWERDN + 1)
+
+/*******************************************************************************
  * Platform console related constants
  ******************************************************************************/
 #define TEGRA_CONSOLE_BAUDRATE		115200
diff --git a/plat/nvidia/tegra/include/t132/tegra_def.h b/plat/nvidia/tegra/include/t132/tegra_def.h
index 2fb9ed7..683c903 100644
--- a/plat/nvidia/tegra/include/t132/tegra_def.h
+++ b/plat/nvidia/tegra/include/t132/tegra_def.h
@@ -37,7 +37,7 @@
  * This value is used by the PSCI implementation during the `SYSTEM_SUSPEND`
  * call as the `state-id` field in the 'power state' parameter.
  ******************************************************************************/
-#define PLAT_SYS_SUSPEND_STATE_ID	0xD
+#define PSTATE_ID_SOC_POWERDN	0xD
 
 /*******************************************************************************
  * GIC memory map
diff --git a/plat/nvidia/tegra/include/tegra_private.h b/plat/nvidia/tegra/include/tegra_private.h
index 952e2d8..aca9db7 100644
--- a/plat/nvidia/tegra/include/tegra_private.h
+++ b/plat/nvidia/tegra/include/tegra_private.h
@@ -31,8 +31,9 @@
 #ifndef __TEGRA_PRIVATE_H__
 #define __TEGRA_PRIVATE_H__
 
-#include <xlat_tables.h>
+#include <arch.h>
 #include <platform_def.h>
+#include <xlat_tables.h>
 
 /*******************************************************************************
  * Tegra DRAM memory base address
@@ -45,7 +46,8 @@
 } plat_params_from_bl2_t;
 
 /* Declarations for plat_psci_handlers.c */
-int32_t tegra_soc_validate_power_state(unsigned int power_state);
+int32_t tegra_soc_validate_power_state(unsigned int power_state,
+		psci_power_state_t *req_state);
 
 /* Declarations for plat_setup.c */
 const mmap_region_t *plat_get_mmio_map(void);
diff --git a/plat/nvidia/tegra/platform.mk b/plat/nvidia/tegra/platform.mk
index b909335..cec7caf 100644
--- a/plat/nvidia/tegra/platform.mk
+++ b/plat/nvidia/tegra/platform.mk
@@ -28,7 +28,10 @@
 # POSSIBILITY OF SUCH DAMAGE.
 #
 
-SOC_DIR		:=	plat/nvidia/tegra/soc/${TARGET_SOC}
+SOC_DIR			:=	plat/nvidia/tegra/soc/${TARGET_SOC}
+
+# Disable the PSCI platform compatibility layer
+ENABLE_PLAT_COMPAT	:=	0
 
 include plat/nvidia/tegra/common/tegra_common.mk
 include ${SOC_DIR}/platform_${TARGET_SOC}.mk
diff --git a/plat/nvidia/tegra/soc/t132/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t132/plat_psci_handlers.c
index 46e5940..48a2fba 100644
--- a/plat/nvidia/tegra/soc/t132/plat_psci_handlers.c
+++ b/plat/nvidia/tegra/soc/t132/plat_psci_handlers.c
@@ -56,28 +56,55 @@
 
 static int cpu_powergate_mask[PLATFORM_MAX_CPUS_PER_CLUSTER];
 
-int32_t tegra_soc_validate_power_state(unsigned int power_state)
+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);
+	int cpu = read_mpidr() & MPIDR_CPU_MASK;
+
+	if (pwr_lvl > PLAT_MAX_PWR_LVL)
+		return PSCI_E_INVALID_PARAMS;
+
 	/* Sanity check the requested afflvl */
 	if (psci_get_pstate_type(power_state) == PSTATE_TYPE_STANDBY) {
 		/*
 		 * It's possible to enter standby only on affinity level 0 i.e.
 		 * a cpu on Tegra. Ignore any other affinity level.
 		 */
-		if (psci_get_pstate_afflvl(power_state) != MPIDR_AFFLVL0)
+		if (pwr_lvl != MPIDR_AFFLVL0)
 			return PSCI_E_INVALID_PARAMS;
+
+		/* power domain in standby state */
+		req_state->pwr_domain_state[pwr_lvl] = PLAT_MAX_RET_STATE;
+
+		return PSCI_E_SUCCESS;
 	}
 
-	/* Sanity check the requested state id */
-	if (psci_get_pstate_id(power_state) != PLAT_SYS_SUSPEND_STATE_ID) {
-		ERROR("unsupported state id\n");
-		return PSCI_E_NOT_SUPPORTED;
+	/*
+	 * Sanity check the requested state id, power level and CPU number.
+	 * Currently T132 only supports SYSTEM_SUSPEND on last standing CPU
+	 * i.e. CPU 0
+	 */
+	if ((pwr_lvl != PLAT_MAX_PWR_LVL) ||
+	    (state_id != PSTATE_ID_SOC_POWERDN) ||
+	    (cpu != 0)) {
+		ERROR("unsupported state id @ power level\n");
+		return PSCI_E_INVALID_PARAMS;
 	}
 
+	/* Set lower power states to PLAT_MAX_OFF_STATE */
+	for (int i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+
+	/* Set the SYSTEM_SUSPEND state-id */
+	req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] =
+		PSTATE_ID_SOC_POWERDN;
+
 	return PSCI_E_SUCCESS;
 }
 
-int tegra_soc_prepare_cpu_on(unsigned long mpidr)
+int tegra_soc_pwr_domain_on(u_register_t mpidr)
 {
 	int cpu = mpidr & MPIDR_CPU_MASK;
 	uint32_t mask = CPU_CORE_RESET_MASK << cpu;
@@ -101,29 +128,29 @@
 	return PSCI_E_SUCCESS;
 }
 
-int tegra_soc_prepare_cpu_off(unsigned long mpidr)
+int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
 {
-	tegra_fc_cpu_off(mpidr & MPIDR_CPU_MASK);
+	tegra_fc_cpu_off(read_mpidr() & MPIDR_CPU_MASK);
 	return PSCI_E_SUCCESS;
 }
 
-int tegra_soc_prepare_cpu_suspend(unsigned int id, unsigned int afflvl)
+int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
 {
-	/* Nothing to be done for lower affinity levels */
-	if (afflvl < MPIDR_AFFLVL2)
-		return PSCI_E_SUCCESS;
+#if DEBUG
+	int cpu = read_mpidr() & MPIDR_CPU_MASK;
 
-	/* Enter system suspend state */
-	tegra_pm_system_suspend_entry();
+	/* SYSTEM_SUSPEND only on CPU0 */
+	assert(cpu == 0);
+#endif
 
 	/* Allow restarting CPU #1 using PMC on suspend exit */
 	cpu_powergate_mask[1] = 0;
 
 	/* Program FC to enter suspend state */
-	tegra_fc_cpu_idle(read_mpidr());
+	tegra_fc_cpu_powerdn(read_mpidr());
 
 	/* Suspend DCO operations */
-	write_actlr_el1(id);
+	write_actlr_el1(target_state->pwr_domain_state[PLAT_MAX_PWR_LVL]);
 
 	return PSCI_E_SUCCESS;
 }
diff --git a/plat/nvidia/tegra/soc/t132/plat_setup.c b/plat/nvidia/tegra/soc/t132/plat_setup.c
index a76999c..6ff2831 100644
--- a/plat/nvidia/tegra/soc/t132/plat_setup.c
+++ b/plat/nvidia/tegra/soc/t132/plat_setup.c
@@ -31,6 +31,21 @@
 #include <xlat_tables.h>
 #include <tegra_def.h>
 
+/*******************************************************************************
+ * The Tegra power domain tree has a single system level power domain i.e. a
+ * single root node. The first entry in the power domain descriptor specifies
+ * the number of power domains at the highest power level.
+ *******************************************************************************
+ */
+const unsigned char tegra_power_domain_tree_desc[] = {
+	/* No of root nodes */
+	1,
+	/* No of clusters */
+	PLATFORM_CLUSTER_COUNT,
+	/* No of CPU cores */
+	PLATFORM_CORE_COUNT,
+};
+
 /* sets of MMIO ranges setup */
 #define MMIO_RANGE_0_ADDR	0x50000000
 #define MMIO_RANGE_1_ADDR	0x60000000
diff --git a/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c
index 73358d4..b184063 100644
--- a/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c
+++ b/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c
@@ -55,83 +55,139 @@
 
 static int cpu_powergate_mask[PLATFORM_MAX_CPUS_PER_CLUSTER];
 
-int32_t tegra_soc_validate_power_state(unsigned int power_state)
+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);
+
+	if (pwr_lvl > PLAT_MAX_PWR_LVL) {
+		ERROR("%s: unsupported power_state (0x%x)\n", __func__,
+			power_state);
+		return PSCI_E_INVALID_PARAMS;
+	}
+
 	/* Sanity check the requested afflvl */
 	if (psci_get_pstate_type(power_state) == PSTATE_TYPE_STANDBY) {
 		/*
 		 * It's possible to enter standby only on affinity level 0 i.e.
 		 * a cpu on Tegra. Ignore any other affinity level.
 		 */
-		if (psci_get_pstate_afflvl(power_state) != MPIDR_AFFLVL0)
+		if (pwr_lvl != MPIDR_AFFLVL0)
 			return PSCI_E_INVALID_PARAMS;
+
+		/* power domain in standby state */
+		req_state->pwr_domain_state[pwr_lvl] = PLAT_MAX_RET_STATE;
+
+		return PSCI_E_SUCCESS;
 	}
 
 	/* Sanity check the requested state id */
-	switch (psci_get_pstate_id(power_state)) {
+	switch (state_id) {
 	case PSTATE_ID_CORE_POWERDN:
+		/*
+		 * Core powerdown request only for afflvl 0
+		 */
+		if (pwr_lvl != MPIDR_AFFLVL0)
+			goto error;
+
+		req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id & 0xff;
+
+		break;
+
 	case PSTATE_ID_CLUSTER_IDLE:
 	case PSTATE_ID_CLUSTER_POWERDN:
+		/*
+		 * Cluster powerdown/idle request only for afflvl 1
+		 */
+		if (pwr_lvl != MPIDR_AFFLVL1)
+			goto error;
+
+		req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id;
+		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE;
+
+		break;
+
 	case PSTATE_ID_SOC_POWERDN:
+		/*
+		 * System powerdown request only for afflvl 2
+		 */
+		if (pwr_lvl != PLAT_MAX_PWR_LVL)
+			goto error;
+
+		for (int i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
+			req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+
+		req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] =
+			PLAT_SYS_SUSPEND_STATE_ID;
+
 		break;
 
 	default:
-		ERROR("unsupported state id\n");
-		return PSCI_E_NOT_SUPPORTED;
+		ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
+		return PSCI_E_INVALID_PARAMS;
 	}
 
 	return PSCI_E_SUCCESS;
+
+error:
+	ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
+	return PSCI_E_INVALID_PARAMS;
 }
 
-int tegra_soc_prepare_cpu_suspend(unsigned int id, unsigned int afflvl)
+int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
 {
-	/* There's nothing to be done for affinity level 1 */
-	if (afflvl == MPIDR_AFFLVL1)
-		return PSCI_E_SUCCESS;
+	u_register_t mpidr = read_mpidr();
+	const plat_local_state_t *pwr_domain_state =
+		target_state->pwr_domain_state;
+	unsigned int stateid_afflvl2 = pwr_domain_state[MPIDR_AFFLVL2];
+	unsigned int stateid_afflvl1 = pwr_domain_state[MPIDR_AFFLVL1];
+	unsigned int stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0];
 
-	switch (id) {
-	/* Prepare for cpu idle */
-	case PSTATE_ID_CORE_POWERDN:
-		tegra_fc_cpu_idle(read_mpidr());
-		return PSCI_E_SUCCESS;
+	if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
 
-	/* Prepare for cluster idle */
-	case PSTATE_ID_CLUSTER_IDLE:
-		tegra_fc_cluster_idle(read_mpidr());
-		return PSCI_E_SUCCESS;
+		assert(stateid_afflvl0 == PLAT_MAX_OFF_STATE);
+		assert(stateid_afflvl1 == PLAT_MAX_OFF_STATE);
 
-	/* Prepare for cluster powerdn */
-	case PSTATE_ID_CLUSTER_POWERDN:
-		tegra_fc_cluster_powerdn(read_mpidr());
-		return PSCI_E_SUCCESS;
+		/* suspend the entire soc */
+		tegra_fc_soc_powerdn(mpidr);
 
-	/* Prepare for system idle */
-	case PSTATE_ID_SOC_POWERDN:
+	} else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_IDLE) {
 
-		/* Enter system suspend state */
-		tegra_pm_system_suspend_entry();
+		assert(stateid_afflvl0 == PLAT_MAX_OFF_STATE);
 
-		/* suspend the entire soc */
-		tegra_fc_soc_powerdn(read_mpidr());
+		/* Prepare for cluster idle */
+		tegra_fc_cluster_idle(mpidr);
 
-		return PSCI_E_SUCCESS;
+	} else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_POWERDN) {
 
-	default:
-		ERROR("Unknown state id (%d)\n", id);
-		break;
+		assert(stateid_afflvl0 == PLAT_MAX_OFF_STATE);
+
+		/* Prepare for cluster powerdn */
+		tegra_fc_cluster_powerdn(mpidr);
+
+	} else if (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN) {
+
+		/* Prepare for cpu powerdn */
+		tegra_fc_cpu_powerdn(mpidr);
+
+	} else {
+		ERROR("%s: Unknown state id\n", __func__);
+		return PSCI_E_NOT_SUPPORTED;
 	}
 
-	return PSCI_E_NOT_SUPPORTED;
+	return PSCI_E_SUCCESS;
 }
 
-int tegra_soc_prepare_cpu_on_finish(unsigned long mpidr)
+int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
 {
 	uint32_t val;
 
 	/*
 	 * Check if we are exiting from SOC_POWERDN.
 	 */
-	if (tegra_system_suspended()) {
+	if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] ==
+			PLAT_SYS_SUSPEND_STATE_ID) {
 
 		/*
 		 * Enable WRAP to INCR burst type conversions for
@@ -147,11 +203,6 @@
 		 * address and reset it.
 		 */
 		tegra_fc_reset_bpmp();
-
-		/*
-		 * System resume complete.
-		 */
-		tegra_pm_system_suspend_exit();
 	}
 
 	/*
@@ -159,13 +210,12 @@
 	 * used for power management and boot purposes. Inform the BPMP that
 	 * we have completed the cluster power up.
 	 */
-	if (psci_get_max_phys_off_afflvl() == MPIDR_AFFLVL1)
-		tegra_fc_lock_active_cluster();
+	tegra_fc_lock_active_cluster();
 
 	return PSCI_E_SUCCESS;
 }
 
-int tegra_soc_prepare_cpu_on(unsigned long mpidr)
+int tegra_soc_pwr_domain_on(u_register_t mpidr)
 {
 	int cpu = mpidr & MPIDR_CPU_MASK;
 	uint32_t mask = CPU_CORE_RESET_MASK << cpu;
@@ -184,9 +234,9 @@
 	return PSCI_E_SUCCESS;
 }
 
-int tegra_soc_prepare_cpu_off(unsigned long mpidr)
+int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
 {
-	tegra_fc_cpu_off(mpidr & MPIDR_CPU_MASK);
+	tegra_fc_cpu_off(read_mpidr() & MPIDR_CPU_MASK);
 	return PSCI_E_SUCCESS;
 }
 
diff --git a/plat/nvidia/tegra/soc/t210/plat_setup.c b/plat/nvidia/tegra/soc/t210/plat_setup.c
index cbe7a04..3fce8a2 100644
--- a/plat/nvidia/tegra/soc/t210/plat_setup.c
+++ b/plat/nvidia/tegra/soc/t210/plat_setup.c
@@ -32,6 +32,23 @@
 #include <tegra_def.h>
 #include <xlat_tables.h>
 
+/*******************************************************************************
+ * The Tegra power domain tree has a single system level power domain i.e. a
+ * single root node. The first entry in the power domain descriptor specifies
+ * the number of power domains at the highest power level.
+ *******************************************************************************
+ */
+const unsigned char tegra_power_domain_tree_desc[] = {
+	/* No of root nodes */
+	1,
+	/* No of clusters */
+	PLATFORM_CLUSTER_COUNT,
+	/* No of CPU cores - cluster0 */
+	PLATFORM_MAX_CPUS_PER_CLUSTER,
+	/* No of CPU cores - cluster1 */
+	PLATFORM_MAX_CPUS_PER_CLUSTER
+};
+
 /* sets of MMIO ranges setup */
 #define MMIO_RANGE_0_ADDR	0x50000000
 #define MMIO_RANGE_1_ADDR	0x60000000