Merge pull request #913 from vwadekar/tegra-fixes-from-downstream

Tegra fixes from downstream
diff --git a/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c b/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c
index 41a4ede..87c7ed0 100644
--- a/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c
+++ b/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c
@@ -40,7 +40,8 @@
 #include <string.h>
 #include <tegra_def.h>
 #include <tegra_platform.h>
-#include <xlat_tables.h>
+#include <utils.h>
+#include <xlat_tables_v2.h>
 
 #define TEGRA_GPU_RESET_REG_OFFSET	0x30
 #define  GPU_RESET_BIT			(1 << 0)
@@ -450,7 +451,7 @@
 		tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB, video_mem_size_mb);
 
 		/*
-		 * MCE propogates the VideoMem configuration values across the
+		 * MCE propagates the VideoMem configuration values across the
 		 * CCPLEX.
 		 */
 		mce_update_gsc_videomem();
@@ -490,7 +491,7 @@
 					tegra_mc_read_32(MC_SECURITY_CFG1_0));
 
 	/*
-	 * MCE propogates the security configuration values across the
+	 * MCE propagates the security configuration values across the
 	 * CCPLEX.
 	 */
 	mce_update_gsc_tzdram();
@@ -506,25 +507,28 @@
 {
 	uint32_t index;
 	uint32_t total_128kb_blocks = size_in_bytes >> 17;
-	uint32_t residual_4kb_blocks = (size_in_bytes & 0x1FFFF) >> 12;
+	uint32_t residual_4kb_blocks = (size_in_bytes & (uint32_t)0x1FFFF) >> 12;
 	uint32_t val;
 
+	INFO("Configuring TrustZone SRAM Memory Carveout\n");
+
 	/*
 	 * Reset the access configuration registers to restrict access
 	 * to the TZRAM aperture
 	 */
-	for (index = MC_TZRAM_CARVEOUT_CLIENT_ACCESS_CFG0;
-	     index <= MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS5;
-	     index += 4)
+	for (index = MC_TZRAM_CLIENT_ACCESS_CFG0;
+	     index < ((uint32_t)MC_TZRAM_CARVEOUT_CFG + (uint32_t)MC_GSC_CONFIG_REGS_SIZE);
+	     index += 4U) {
 		tegra_mc_write_32(index, 0);
+	}
 
 	/*
 	 * Set the TZRAM base. TZRAM base must be 4k aligned, at least.
 	 */
-	assert(!(phys_base & 0xFFF));
+	assert((phys_base & (uint64_t)0xFFF) == 0U);
 	tegra_mc_write_32(MC_TZRAM_BASE_LO, (uint32_t)phys_base);
 	tegra_mc_write_32(MC_TZRAM_BASE_HI,
-		(uint32_t)(phys_base >> 32) & TZRAM_BASE_HI_MASK);
+		(uint32_t)(phys_base >> 32) & MC_GSC_BASE_HI_MASK);
 
 	/*
 	 * Set the TZRAM size
@@ -533,7 +537,7 @@
 	 * blocks)
 	 *
 	 */
-	val = (residual_4kb_blocks << TZRAM_SIZE_RANGE_4KB_SHIFT) |
+	val = (residual_4kb_blocks << MC_GSC_SIZE_RANGE_4KB_SHIFT) |
 	      total_128kb_blocks;
 	tegra_mc_write_32(MC_TZRAM_SIZE, val);
 
@@ -543,17 +547,96 @@
 	 * at all.
 	 */
 	val = tegra_mc_read_32(MC_TZRAM_CARVEOUT_CFG);
-	val &= ~TZRAM_ENABLE_TZ_LOCK_BIT;
-	val |= TZRAM_LOCK_CFG_SETTINGS_BIT;
+	val &= ~MC_GSC_ENABLE_TZ_LOCK_BIT;
+	val |= MC_GSC_LOCK_CFG_SETTINGS_BIT;
 	tegra_mc_write_32(MC_TZRAM_CARVEOUT_CFG, val);
 
 	/*
-	 * MCE propogates the security configuration values across the
+	 * MCE propagates the security configuration values across the
 	 * CCPLEX.
 	 */
 	mce_update_gsc_tzram();
 }
 
+static void tegra_lock_videomem_nonoverlap(uint64_t phys_base,
+					   uint64_t size_in_bytes)
+{
+	uint32_t index;
+	uint64_t total_128kb_blocks = size_in_bytes >> 17;
+	uint64_t residual_4kb_blocks = (size_in_bytes & (uint32_t)0x1FFFF) >> 12;
+	uint64_t val;
+
+	/*
+	 * Reset the access configuration registers to restrict access to
+	 * old Videomem aperture
+	 */
+	for (index = MC_VIDEO_PROTECT_CLEAR_ACCESS_CFG0;
+	     index < ((uint32_t)MC_VIDEO_PROTECT_CLEAR_ACCESS_CFG0 + (uint32_t)MC_GSC_CONFIG_REGS_SIZE);
+	     index += 4U) {
+		tegra_mc_write_32(index, 0);
+	}
+
+	/*
+	 * Set the base. It must be 4k aligned, at least.
+	 */
+	assert((phys_base & (uint64_t)0xFFF) == 0U);
+	tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_LO, (uint32_t)phys_base);
+	tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_HI,
+		(uint32_t)(phys_base >> 32) & (uint32_t)MC_GSC_BASE_HI_MASK);
+
+	/*
+	 * Set the aperture size
+	 *
+	 * total size = (number of 128KB blocks) + (number of remaining 4KB
+	 * blocks)
+	 *
+	 */
+	val = (uint32_t)((residual_4kb_blocks << MC_GSC_SIZE_RANGE_4KB_SHIFT) |
+			 total_128kb_blocks);
+	tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_SIZE, (uint32_t)val);
+
+	/*
+	 * Lock the configuration settings by enabling TZ-only lock and
+	 * locking the configuration against any future changes from NS
+	 * world.
+	 */
+	tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_CFG,
+			  (uint32_t)MC_GSC_ENABLE_TZ_LOCK_BIT);
+
+	/*
+	 * MCE propagates the GSC configuration values across the
+	 * CCPLEX.
+	 */
+}
+
+static void tegra_unlock_videomem_nonoverlap(void)
+{
+	/* Clear the base */
+	tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_LO, 0);
+	tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_HI, 0);
+
+	/* Clear the size */
+	tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_SIZE, 0);
+}
+
+static void tegra_clear_videomem(uintptr_t non_overlap_area_start,
+				 unsigned long long non_overlap_area_size)
+{
+	/*
+	 * Map the NS memory first, clean it and then unmap it.
+	 */
+	mmap_add_dynamic_region(non_overlap_area_start, /* PA */
+				non_overlap_area_start, /* VA */
+				non_overlap_area_size, /* size */
+				MT_NS | MT_RW | MT_EXECUTE_NEVER); /* attrs */
+
+	zero_normalmem((void *)non_overlap_area_start, non_overlap_area_size);
+	flush_dcache_range(non_overlap_area_start, non_overlap_area_size);
+
+	mmap_remove_dynamic_region(non_overlap_area_start,
+		non_overlap_area_size);
+}
+
 /*
  * Program the Video Memory carveout region
  *
@@ -562,7 +645,10 @@
  */
 void tegra_memctrl_videomem_setup(uint64_t phys_base, uint32_t size_in_bytes)
 {
+	uintptr_t vmem_end_old = video_mem_base + (video_mem_size_mb << 20);
+	uintptr_t vmem_end_new = phys_base + size_in_bytes;
 	uint32_t regval;
+	unsigned long long non_overlap_area_size;
 
 	/*
 	 * The GPU is the user of the Video Memory region. In order to
@@ -570,7 +656,7 @@
 	 * new base/size ONLY if the GPU is in reset mode.
 	 */
 	regval = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_REG_OFFSET);
-	if ((regval & GPU_RESET_BIT) == 0) {
+	if ((regval & GPU_RESET_BIT) == 0U) {
 		ERROR("GPU not in reset! Video Memory setup failed\n");
 		return;
 	}
@@ -581,17 +667,61 @@
 	 */
 	INFO("Configuring Video Memory Carveout\n");
 
+	/*
+	 * Configure Memory Controller directly for the first time.
+	 */
+	if (video_mem_base == 0U)
+		goto done;
+
+	/*
+	 * Lock the non overlapping memory being cleared so that other masters
+	 * do not accidently write to it. The memory would be unlocked once
+	 * the non overlapping region is cleared and the new memory
+	 * settings take effect.
+	 */
+	tegra_lock_videomem_nonoverlap(video_mem_base,
+				       video_mem_size_mb << 20);
+
+	/*
+	 * Clear the old regions now being exposed. The following cases
+	 * can occur -
+	 *
+	 * 1. clear whole old region (no overlap with new region)
+	 * 2. clear old sub-region below new base
+	 * 3. clear old sub-region above new end
+	 */
+	INFO("Cleaning previous Video Memory Carveout\n");
+
+	if (phys_base > vmem_end_old || video_mem_base > vmem_end_new) {
+		tegra_clear_videomem(video_mem_base,
+				     (uint64_t)video_mem_size_mb << 20);
+	} else {
+		if (video_mem_base < phys_base) {
+			non_overlap_area_size = phys_base - video_mem_base;
+			tegra_clear_videomem(video_mem_base, non_overlap_area_size);
+		}
+		if (vmem_end_old > vmem_end_new) {
+			non_overlap_area_size = vmem_end_old - vmem_end_new;
+			tegra_clear_videomem(vmem_end_new, non_overlap_area_size);
+		}
+	}
+
+done:
+	/* program the Videomem aperture */
 	tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_LO, (uint32_t)phys_base);
 	tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_HI,
 			  (uint32_t)(phys_base >> 32));
 	tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB, size_in_bytes >> 20);
 
+	/* unlock the previous locked nonoverlapping aperture */
+	tegra_unlock_videomem_nonoverlap();
+
 	/* store new values */
 	video_mem_base = phys_base;
 	video_mem_size_mb = size_in_bytes >> 20;
 
 	/*
-	 * MCE propogates the VideoMem configuration values across the
+	 * MCE propagates the VideoMem configuration values across the
 	 * CCPLEX.
 	 */
 	mce_update_gsc_videomem();
diff --git a/plat/nvidia/tegra/common/tegra_bl31_setup.c b/plat/nvidia/tegra/common/tegra_bl31_setup.c
index 8307af7..1dc8066 100644
--- a/plat/nvidia/tegra/common/tegra_bl31_setup.c
+++ b/plat/nvidia/tegra/common/tegra_bl31_setup.c
@@ -205,6 +205,11 @@
 	}
 
 	/*
+	 * Initialize delay timer
+	 */
+	tegra_delay_timer_init();
+
+	/*
 	 * Do initial security configuration to allow DRAM/device access.
 	 */
 	tegra_memctrl_tzdram_setup(plat_bl31_params_from_bl2.tzdram_base,
@@ -264,11 +269,6 @@
 	plat_gic_setup();
 
 	/*
-	 * Initialize delay timer
-	 */
-	tegra_delay_timer_init();
-
-	/*
 	 * Setup secondary CPU POR infrastructure.
 	 */
 	plat_secondary_setup();
@@ -354,6 +354,12 @@
 			MT_DEVICE | MT_RW | MT_SECURE);
 #endif
 
+	/* map on-chip free running uS timer */
+	mmap_add_region(page_align((uint64_t)TEGRA_TMRUS_BASE, 0),
+			page_align((uint64_t)TEGRA_TMRUS_BASE, 0),
+			(uint64_t)TEGRA_TMRUS_SIZE,
+			MT_DEVICE | MT_RO | MT_SECURE);
+
 	/* add MMIO space */
 	plat_mmio_map = plat_get_mmio_map();
 	if (plat_mmio_map)
@@ -375,13 +381,12 @@
  ******************************************************************************/
 int bl31_check_ns_address(uint64_t base, uint64_t size_in_bytes)
 {
-	uint64_t end = base + size_in_bytes - 1;
+	uint64_t end = base + size_in_bytes;
 
 	/*
 	 * Check if the NS DRAM address is valid
 	 */
-	if ((base < TEGRA_DRAM_BASE) || (end > TEGRA_DRAM_END) ||
-	    (base >= end)) {
+	if ((base < TEGRA_DRAM_BASE) || (end > TEGRA_DRAM_END)) {
 		ERROR("NS address is out-of-bounds!\n");
 		return -EFAULT;
 	}
diff --git a/plat/nvidia/tegra/include/t132/tegra_def.h b/plat/nvidia/tegra/include/t132/tegra_def.h
index 4ba4f12..e488bd8 100644
--- a/plat/nvidia/tegra/include/t132/tegra_def.h
+++ b/plat/nvidia/tegra/include/t132/tegra_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -58,6 +58,7 @@
  * Tegra micro-seconds timer constants
  ******************************************************************************/
 #define TEGRA_TMRUS_BASE		0x60005010
+#define TEGRA_TMRUS_SIZE		0x1000
 
 /*******************************************************************************
  * Tegra Clock and Reset Controller constants
diff --git a/plat/nvidia/tegra/include/t186/tegra_def.h b/plat/nvidia/tegra/include/t186/tegra_def.h
index ae11d28..8d7ab6e 100644
--- a/plat/nvidia/tegra/include/t186/tegra_def.h
+++ b/plat/nvidia/tegra/include/t186/tegra_def.h
@@ -157,6 +157,16 @@
 #define TEGRA_MC_STREAMID_BASE		0x02C00000
 #define TEGRA_MC_BASE			0x02C10000
 
+/* General Security Carveout register macros */
+#define MC_GSC_CONFIG_REGS_SIZE		0x40UL
+#define MC_GSC_LOCK_CFG_SETTINGS_BIT	(1UL << 1)
+#define MC_GSC_ENABLE_TZ_LOCK_BIT	(1UL << 0)
+#define MC_GSC_SIZE_RANGE_4KB_SHIFT	27UL
+#define MC_GSC_BASE_LO_SHIFT		12UL
+#define MC_GSC_BASE_LO_MASK		0xFFFFFUL
+#define MC_GSC_BASE_HI_SHIFT		0UL
+#define MC_GSC_BASE_HI_MASK		3UL
+
 /* TZDRAM carveout configuration registers */
 #define MC_SECURITY_CFG0_0		0x70
 #define MC_SECURITY_CFG1_0		0x74
@@ -165,34 +175,24 @@
 /* Video Memory carveout configuration registers */
 #define MC_VIDEO_PROTECT_BASE_HI	0x978
 #define MC_VIDEO_PROTECT_BASE_LO	0x648
-#define MC_VIDEO_PROTECT_SIZE_MB	0x64c
+#define MC_VIDEO_PROTECT_SIZE_MB	0x64C
+
+/*
+ * Carveout (MC_SECURITY_CARVEOUT24) registers used to clear the
+ * non-overlapping Video memory region
+ */
+#define MC_VIDEO_PROTECT_CLEAR_CFG	0x25A0
+#define MC_VIDEO_PROTECT_CLEAR_BASE_LO	0x25A4
+#define MC_VIDEO_PROTECT_CLEAR_BASE_HI	0x25A8
+#define MC_VIDEO_PROTECT_CLEAR_SIZE	0x25AC
+#define MC_VIDEO_PROTECT_CLEAR_ACCESS_CFG0	0x25B0
 
 /* TZRAM carveout (MC_SECURITY_CARVEOUT11) configuration registers */
+#define MC_TZRAM_CARVEOUT_CFG		0x2190
 #define MC_TZRAM_BASE_LO		0x2194
-#define  TZRAM_BASE_LO_SHIFT		12
-#define  TZRAM_BASE_LO_MASK		0xFFFFF
 #define MC_TZRAM_BASE_HI		0x2198
-#define  TZRAM_BASE_HI_SHIFT		0
-#define  TZRAM_BASE_HI_MASK		3
 #define MC_TZRAM_SIZE			0x219C
-#define  TZRAM_SIZE_RANGE_4KB_SHIFT	27
-
-#define MC_TZRAM_CARVEOUT_CFG			0x2190
-#define  TZRAM_LOCK_CFG_SETTINGS_BIT		(1 << 1)
-#define  TZRAM_ENABLE_TZ_LOCK_BIT		(1 << 0)
-#define MC_TZRAM_CARVEOUT_CLIENT_ACCESS_CFG0	0x21A0
-#define MC_TZRAM_CARVEOUT_CLIENT_ACCESS_CFG1	0x21A4
-#define MC_TZRAM_CARVEOUT_CLIENT_ACCESS_CFG2	0x21A8
-#define MC_TZRAM_CARVEOUT_CLIENT_ACCESS_CFG3	0x21AC
-#define MC_TZRAM_CARVEOUT_CLIENT_ACCESS_CFG4	0x21B0
-#define MC_TZRAM_CARVEOUT_CLIENT_ACCESS_CFG5	0x21B4
-
-#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS0	0x21B8
-#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS1	0x21BC
-#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS2	0x21C0
-#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS3	0x21C4
-#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS4	0x21C8
-#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS5	0x21CC
+#define MC_TZRAM_CLIENT_ACCESS_CFG0	0x21A0
 
 /*******************************************************************************
  * Tegra UART Controller constants
@@ -237,6 +237,7 @@
  * Tegra micro-seconds timer constants
  ******************************************************************************/
 #define TEGRA_TMRUS_BASE		0x0C2E0000
+#define TEGRA_TMRUS_SIZE		0x1000
 
 /*******************************************************************************
  * Tegra Power Mgmt Controller constants
diff --git a/plat/nvidia/tegra/include/t210/tegra_def.h b/plat/nvidia/tegra/include/t210/tegra_def.h
index 0961355..d8ad10c 100644
--- a/plat/nvidia/tegra/include/t210/tegra_def.h
+++ b/plat/nvidia/tegra/include/t210/tegra_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -83,6 +83,7 @@
  * Tegra micro-seconds timer constants
  ******************************************************************************/
 #define TEGRA_TMRUS_BASE		0x60005010
+#define TEGRA_TMRUS_SIZE		0x1000
 
 /*******************************************************************************
  * Tegra Clock and Reset Controller constants
diff --git a/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c b/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c
index 7f711a7..87fadbe 100644
--- a/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c
+++ b/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -30,10 +30,13 @@
 
 #include <arch.h>
 #include <arch_helpers.h>
+#include <assert.h>
 #include <debug.h>
+#include <delay_timer.h>
 #include <denver.h>
 #include <mmio.h>
 #include <mce_private.h>
+#include <platform.h>
 #include <sys/errno.h>
 #include <t18x_ari.h>
 
@@ -49,10 +52,13 @@
 #define ARI_RESPONSE_DATA_HI		0x18
 
 /* Status values for the current request */
-#define ARI_REQ_PENDING			1
-#define ARI_REQ_ONGOING			3
-#define ARI_REQUEST_VALID_BIT		(1 << 8)
-#define ARI_EVT_MASK_STANDBYWFI_BIT	(1 << 7)
+#define ARI_REQ_PENDING			1U
+#define ARI_REQ_ONGOING			3U
+#define ARI_REQUEST_VALID_BIT		(1U << 8)
+#define ARI_EVT_MASK_STANDBYWFI_BIT	(1U << 7)
+
+/* default timeout (ms) to wait for ARI completion */
+#define ARI_MAX_RETRY_COUNT		2000
 
 /*******************************************************************************
  * ARI helper functions
@@ -96,7 +102,8 @@
 static int ari_request_wait(uint32_t ari_base, uint32_t evt_mask, uint32_t req,
 		uint32_t lo, uint32_t hi)
 {
-	int status;
+	uint32_t retries = ARI_MAX_RETRY_COUNT;
+	uint32_t status;
 
 	/* program the request, event_mask, hi and lo registers */
 	ari_write_32(ari_base, lo, ARI_REQUEST_DATA_LO);
@@ -112,10 +119,36 @@
 	if (evt_mask)
 		return 0;
 
+	/* For shutdown/reboot commands, we dont have to check for timeouts */
+	if ((req == (uint32_t)TEGRA_ARI_MISC_CCPLEX) &&
+	    ((lo == (uint32_t)TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF) ||
+	     (lo == (uint32_t)TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT))) {
+			return 0;
+	}
+
+	/*
+	 * Wait for the command response for not more than the timeout
+	 */
+	while (retries != 0U) {
+
-	/* NOTE: add timeout check if needed */
-	status = ari_read_32(ari_base, ARI_STATUS);
-	while (status & (ARI_REQ_ONGOING | ARI_REQ_PENDING))
+		/* read the command status */
 		status = ari_read_32(ari_base, ARI_STATUS);
+		if ((status & (ARI_REQ_ONGOING | ARI_REQ_PENDING)) == 0U)
+			break;
+
+		/* delay 1 ms */
+		mdelay(1);
+
+		/* decrement the retry count */
+		retries--;
+	}
+
+	/* assert if the command timed out */
+	if (retries == 0U) {
+		ERROR("ARI request timed out: req %d on CPU %d\n",
+			req, plat_my_core_pos());
+		assert(retries != 0U);
+	}
 
 	return 0;
 }
diff --git a/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c
index 9790b81..a7f41c1 100644
--- a/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c
+++ b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c
@@ -188,8 +188,11 @@
 	int core_pos = read_mpidr() & MPIDR_CPU_MASK;
 	mce_cstate_info_t cstate_info = { 0 };
 
-	/* get the current core's power state */
-	target = *(states + core_pos);
+	/* get the power state at this level */
+	if (lvl == MPIDR_AFFLVL1)
+		target = *(states + core_pos);
+	if (lvl == MPIDR_AFFLVL2)
+		target = *(states + cpu);
 
 	/* CPU suspend */
 	if (lvl == MPIDR_AFFLVL1 && target == PSTATE_ID_CORE_POWERDN) {
@@ -242,7 +245,8 @@
 	}
 
 	/* System Suspend */
-	if ((lvl == MPIDR_AFFLVL2) || (target == PSTATE_ID_SOC_POWERDN))
+	if (((lvl == MPIDR_AFFLVL2) || (lvl == MPIDR_AFFLVL1)) &&
+	    (target == PSTATE_ID_SOC_POWERDN))
 		return PSTATE_ID_SOC_POWERDN;
 
 	/* default state */
diff --git a/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c
index 05028a1..91a13e8 100644
--- a/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c
+++ b/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c
@@ -100,6 +100,39 @@
 	return PSCI_E_SUCCESS;
 }
 
+/*******************************************************************************
+ * Platform handler to calculate the proper target power level at the
+ * specified affinity level
+ ******************************************************************************/
+plat_local_state_t tegra_soc_get_target_pwr_state(unsigned int lvl,
+					     const plat_local_state_t *states,
+					     unsigned int ncpu)
+{
+	plat_local_state_t target = *states;
+	int cpu = plat_my_core_pos();
+	int core_pos = read_mpidr() & MPIDR_CPU_MASK;
+
+	/* get the power state at this level */
+	if (lvl == MPIDR_AFFLVL1)
+		target = *(states + core_pos);
+	if (lvl == MPIDR_AFFLVL2)
+		target = *(states + cpu);
+
+	/* Cluster idle/power-down */
+	if ((lvl == MPIDR_AFFLVL1) && ((target == PSTATE_ID_CLUSTER_IDLE) ||
+	    (target == PSTATE_ID_CLUSTER_POWERDN))) {
+		return target;
+	}
+
+	/* System Suspend */
+	if (((lvl == MPIDR_AFFLVL2) || (lvl == MPIDR_AFFLVL1)) &&
+	    (target == PSTATE_ID_SOC_POWERDN))
+		return PSTATE_ID_SOC_POWERDN;
+
+	/* default state */
+	return PSCI_LOCAL_STATE_RUN;
+}
+
 int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
 {
 	u_register_t mpidr = read_mpidr();
@@ -121,14 +154,14 @@
 
 	} else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_IDLE) {
 
-		assert(stateid_afflvl0 == PLAT_MAX_OFF_STATE);
+		assert(stateid_afflvl0 == PSTATE_ID_CLUSTER_IDLE);
 
 		/* Prepare for cluster idle */
 		tegra_fc_cluster_idle(mpidr);
 
 	} else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_POWERDN) {
 
-		assert(stateid_afflvl0 == PLAT_MAX_OFF_STATE);
+		assert(stateid_afflvl0 == PSTATE_ID_CLUSTER_POWERDN);
 
 		/* Prepare for cluster powerdn */
 		tegra_fc_cluster_powerdn(mpidr);
diff --git a/plat/nvidia/tegra/soc/t210/platform_t210.mk b/plat/nvidia/tegra/soc/t210/platform_t210.mk
index 8946869..cd26e6e 100644
--- a/plat/nvidia/tegra/soc/t210/platform_t210.mk
+++ b/plat/nvidia/tegra/soc/t210/platform_t210.mk
@@ -40,7 +40,7 @@
 PLATFORM_MAX_CPUS_PER_CLUSTER		:= 4
 $(eval $(call add_define,PLATFORM_MAX_CPUS_PER_CLUSTER))
 
-MAX_XLAT_TABLES				:= 3
+MAX_XLAT_TABLES				:= 4
 $(eval $(call add_define,MAX_XLAT_TABLES))
 
 MAX_MMAP_REGIONS			:= 8