Merge pull request #875 from vwadekar/tegra186-platform-support-v2

Tegra186 platform support v2
diff --git a/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c b/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c
index f020204..a03b6ef 100644
--- a/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c
+++ b/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c
@@ -45,7 +45,7 @@
 
 /* Video Memory base and size (live values) */
 static uint64_t video_mem_base;
-static uint64_t video_mem_size;
+static uint64_t video_mem_size_mb;
 
 /* array to hold stream_id override config register offsets */
 const static uint32_t streamid_overrides[] = {
@@ -144,8 +144,7 @@
 	mc_make_sec_cfg(SCEDMAW, NON_SECURE, NO_OVERRIDE, ENABLE),
 	mc_make_sec_cfg(UFSHCR, NON_SECURE, OVERRIDE, ENABLE),
 	mc_make_sec_cfg(SDMMCWAA, NON_SECURE, OVERRIDE, ENABLE),
-	mc_make_sec_cfg(APEDMAW, NON_SECURE, NO_OVERRIDE, ENABLE),
-	mc_make_sec_cfg(SESWR, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(SESWR, NON_SECURE, NO_OVERRIDE, ENABLE),
 	mc_make_sec_cfg(MPCORER, NON_SECURE, OVERRIDE, ENABLE),
 	mc_make_sec_cfg(PTCR, NON_SECURE, OVERRIDE, ENABLE),
 	mc_make_sec_cfg(BPMPW, NON_SECURE, NO_OVERRIDE, ENABLE),
@@ -159,9 +158,7 @@
 	mc_make_sec_cfg(XUSB_HOSTW, NON_SECURE, OVERRIDE, ENABLE),
 	mc_make_sec_cfg(TSECSWR, NON_SECURE, NO_OVERRIDE, ENABLE),
 	mc_make_sec_cfg(SDMMCRAA, NON_SECURE, OVERRIDE, ENABLE),
-	mc_make_sec_cfg(APER, NON_SECURE, NO_OVERRIDE, ENABLE),
 	mc_make_sec_cfg(VIW, NON_SECURE, OVERRIDE, ENABLE),
-	mc_make_sec_cfg(APEW, NON_SECURE, NO_OVERRIDE, ENABLE),
 	mc_make_sec_cfg(AXISR, SECURE, NO_OVERRIDE, DISABLE),
 	mc_make_sec_cfg(SDMMCW, NON_SECURE, OVERRIDE, ENABLE),
 	mc_make_sec_cfg(BPMPDMAW, NON_SECURE, NO_OVERRIDE, ENABLE),
@@ -191,13 +188,23 @@
 	mc_make_sec_cfg(SDMMCRAB, NON_SECURE, OVERRIDE, ENABLE),
 	mc_make_sec_cfg(ETRR, NON_SECURE, OVERRIDE, ENABLE),
 	mc_make_sec_cfg(AONR, NON_SECURE, OVERRIDE, ENABLE),
-	mc_make_sec_cfg(APEDMAR, NON_SECURE, NO_OVERRIDE, ENABLE),
-	mc_make_sec_cfg(SESRD, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(SESRD, NON_SECURE, NO_OVERRIDE, ENABLE),
 	mc_make_sec_cfg(NVENCSRD, NON_SECURE, NO_OVERRIDE, ENABLE),
 	mc_make_sec_cfg(GPUSWR, SECURE, NO_OVERRIDE, DISABLE),
 	mc_make_sec_cfg(TSECSWRB, NON_SECURE, NO_OVERRIDE, ENABLE),
 	mc_make_sec_cfg(ISPWB, NON_SECURE, OVERRIDE, ENABLE),
 	mc_make_sec_cfg(GPUSRD2, SECURE, NO_OVERRIDE, DISABLE),
+#if ENABLE_CHIP_VERIFICATION_HARNESS
+	mc_make_sec_cfg(APEDMAW, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(APER, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(APEW, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(APEDMAR, NON_SECURE, OVERRIDE, ENABLE),
+#else
+	mc_make_sec_cfg(APEDMAW, NON_SECURE, NO_OVERRIDE, ENABLE),
+	mc_make_sec_cfg(APER, NON_SECURE, NO_OVERRIDE, ENABLE),
+	mc_make_sec_cfg(APEW, NON_SECURE, NO_OVERRIDE, ENABLE),
+	mc_make_sec_cfg(APEDMAR, NON_SECURE, NO_OVERRIDE, ENABLE),
+#endif
 };
 
 const static mc_txn_override_cfg_t mc_override_cfgs[] = {
@@ -234,6 +241,251 @@
 	mc_make_txn_override_cfg(SCEW, CGID_TAG_ADR),
 };
 
+static void tegra_memctrl_reconfig_mss_clients(void)
+{
+#if ENABLE_ROC_FOR_ORDERING_CLIENT_REQUESTS
+	uint32_t val, wdata_0, wdata_1;
+
+	/*
+	 * Assert Memory Controller's HOTRESET_FLUSH_ENABLE signal for
+	 * boot and strongly ordered MSS clients to flush existing memory
+	 * traffic and stall future requests.
+	 */
+	val = tegra_mc_read_32(MC_CLIENT_HOTRESET_CTRL0);
+	assert(val == MC_CLIENT_HOTRESET_CTRL0_RESET_VAL);
+
+	wdata_0 = MC_CLIENT_HOTRESET_CTRL0_AFI_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL0_HDA_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL0_SATA_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL0_XUSB_HOST_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL0_XUSB_DEV_FLUSH_ENB;
+	tegra_mc_write_32(MC_CLIENT_HOTRESET_CTRL0, wdata_0);
+
+	/* Wait for HOTRESET STATUS to indicate FLUSH_DONE */
+	do {
+		val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS0);
+	} while ((val & wdata_0) != wdata_0);
+
+	/* Wait one more time due to SW WAR for known legacy issue */
+	do {
+		val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS0);
+	} while ((val & wdata_0) != wdata_0);
+
+	val = tegra_mc_read_32(MC_CLIENT_HOTRESET_CTRL1);
+	assert(val == MC_CLIENT_HOTRESET_CTRL1_RESET_VAL);
+
+	wdata_1 = MC_CLIENT_HOTRESET_CTRL1_SDMMC4A_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL1_APE_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL1_SE_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL1_ETR_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL1_AXIS_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL1_EQOS_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL1_UFSHC_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL1_BPMP_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL1_AON_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL1_SCE_FLUSH_ENB;
+	tegra_mc_write_32(MC_CLIENT_HOTRESET_CTRL1, wdata_1);
+
+	/* Wait for HOTRESET STATUS to indicate FLUSH_DONE */
+	do {
+		val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS1);
+	} while ((val & wdata_1) != wdata_1);
+
+	/* Wait one more time due to SW WAR for known legacy issue */
+	do {
+		val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS1);
+	} while ((val & wdata_1) != wdata_1);
+
+	/*
+	 * Change MEMTYPE_OVERRIDE from SO_DEV -> PASSTHRU for boot and
+	 * strongly ordered MSS clients. ROC needs to be single point
+	 * of control on overriding the memory type. So, remove TSA's
+	 * memtype override.
+	 */
+	mc_set_tsa_passthrough(AFIW);
+	mc_set_tsa_passthrough(HDAW);
+	mc_set_tsa_passthrough(SATAW);
+	mc_set_tsa_passthrough(XUSB_HOSTW);
+	mc_set_tsa_passthrough(XUSB_DEVW);
+	mc_set_tsa_passthrough(SDMMCWAB);
+	mc_set_tsa_passthrough(APEDMAW);
+	mc_set_tsa_passthrough(SESWR);
+	mc_set_tsa_passthrough(ETRW);
+	mc_set_tsa_passthrough(AXISW);
+	mc_set_tsa_passthrough(EQOSW);
+	mc_set_tsa_passthrough(UFSHCW);
+	mc_set_tsa_passthrough(BPMPDMAW);
+	mc_set_tsa_passthrough(AONDMAW);
+	mc_set_tsa_passthrough(SCEDMAW);
+
+	/*
+	 * Change COH_PATH_OVERRIDE_SO_DEV from NO_OVERRIDE -> FORCE_COHERENT
+	 * for boot and strongly ordered MSS clients. This steers all sodev
+	 * transactions to ROC.
+	 *
+	 * Change AXID_OVERRIDE/AXID_OVERRIDE_SO_DEV only for some clients
+	 * whose AXI IDs we know and trust.
+	 */
+
+	/* Match AFIW */
+	mc_set_forced_coherent_so_dev_cfg(AFIR);
+
+	/*
+	 * See bug 200131110 comment #35 - there are no normal requests
+	 * and AWID for SO/DEV requests is hardcoded in RTL for a
+	 * particular PCIE controller
+	 */
+	mc_set_forced_coherent_so_dev_cfg(AFIW);
+	mc_set_forced_coherent_cfg(HDAR);
+	mc_set_forced_coherent_cfg(HDAW);
+	mc_set_forced_coherent_cfg(SATAR);
+	mc_set_forced_coherent_cfg(SATAW);
+	mc_set_forced_coherent_cfg(XUSB_HOSTR);
+	mc_set_forced_coherent_cfg(XUSB_HOSTW);
+	mc_set_forced_coherent_cfg(XUSB_DEVR);
+	mc_set_forced_coherent_cfg(XUSB_DEVW);
+	mc_set_forced_coherent_cfg(SDMMCRAB);
+	mc_set_forced_coherent_cfg(SDMMCWAB);
+
+	/* Match APEDMAW */
+	mc_set_forced_coherent_axid_so_dev_cfg(APEDMAR);
+
+	/*
+	 * See bug 200131110 comment #35 - AWID for normal requests
+	 * is 0x80 and AWID for SO/DEV requests is 0x01
+	 */
+	mc_set_forced_coherent_axid_so_dev_cfg(APEDMAW);
+	mc_set_forced_coherent_cfg(SESRD);
+	mc_set_forced_coherent_cfg(SESWR);
+	mc_set_forced_coherent_cfg(ETRR);
+	mc_set_forced_coherent_cfg(ETRW);
+	mc_set_forced_coherent_cfg(AXISR);
+	mc_set_forced_coherent_cfg(AXISW);
+	mc_set_forced_coherent_cfg(EQOSR);
+	mc_set_forced_coherent_cfg(EQOSW);
+	mc_set_forced_coherent_cfg(UFSHCR);
+	mc_set_forced_coherent_cfg(UFSHCW);
+	mc_set_forced_coherent_cfg(BPMPDMAR);
+	mc_set_forced_coherent_cfg(BPMPDMAW);
+	mc_set_forced_coherent_cfg(AONDMAR);
+	mc_set_forced_coherent_cfg(AONDMAW);
+	mc_set_forced_coherent_cfg(SCEDMAR);
+	mc_set_forced_coherent_cfg(SCEDMAW);
+
+	/*
+	 * At this point, ordering can occur at ROC. So, remove PCFIFO's
+	 * control over ordering requests.
+	 *
+	 * Change PCFIFO_*_ORDERED_CLIENT from ORDERED -> UNORDERED for
+	 * boot and strongly ordered MSS clients
+	 */
+	val = MC_PCFIFO_CLIENT_CONFIG1_RESET_VAL &
+		mc_set_pcfifo_unordered_boot_so_mss(1, AFIW) &
+		mc_set_pcfifo_unordered_boot_so_mss(1, HDAW) &
+		mc_set_pcfifo_unordered_boot_so_mss(1, SATAW);
+	tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG1, val);
+
+	val = MC_PCFIFO_CLIENT_CONFIG2_RESET_VAL &
+		mc_set_pcfifo_unordered_boot_so_mss(2, XUSB_HOSTW) &
+		mc_set_pcfifo_unordered_boot_so_mss(2, XUSB_DEVW);
+	tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG2, val);
+
+	val = MC_PCFIFO_CLIENT_CONFIG3_RESET_VAL &
+		mc_set_pcfifo_unordered_boot_so_mss(3, SDMMCWAB);
+	tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG3, val);
+
+	val = MC_PCFIFO_CLIENT_CONFIG4_RESET_VAL &
+		mc_set_pcfifo_unordered_boot_so_mss(4, SESWR) &
+		mc_set_pcfifo_unordered_boot_so_mss(4, ETRW) &
+		mc_set_pcfifo_unordered_boot_so_mss(4, AXISW) &
+		mc_set_pcfifo_unordered_boot_so_mss(4, EQOSW) &
+		mc_set_pcfifo_unordered_boot_so_mss(4, UFSHCW) &
+		mc_set_pcfifo_unordered_boot_so_mss(4, BPMPDMAW) &
+		mc_set_pcfifo_unordered_boot_so_mss(4, AONDMAW) &
+		mc_set_pcfifo_unordered_boot_so_mss(4, SCEDMAW);
+	tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG4, val);
+
+	val = MC_PCFIFO_CLIENT_CONFIG5_RESET_VAL &
+		mc_set_pcfifo_unordered_boot_so_mss(5, APEDMAW);
+	tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG5, val);
+
+	/*
+	 * At this point, ordering can occur at ROC. SMMU need not
+	 * reorder any requests.
+	 *
+	 * Change SMMU_*_ORDERED_CLIENT from ORDERED -> UNORDERED
+	 * for boot and strongly ordered MSS clients
+	 */
+	val = MC_SMMU_CLIENT_CONFIG1_RESET_VAL &
+		mc_set_smmu_unordered_boot_so_mss(1, AFIW) &
+		mc_set_smmu_unordered_boot_so_mss(1, HDAW) &
+		mc_set_smmu_unordered_boot_so_mss(1, SATAW);
+	tegra_mc_write_32(MC_SMMU_CLIENT_CONFIG1, val);
+
+	val = MC_SMMU_CLIENT_CONFIG2_RESET_VAL &
+		mc_set_smmu_unordered_boot_so_mss(2, XUSB_HOSTW) &
+		mc_set_smmu_unordered_boot_so_mss(2, XUSB_DEVW);
+	tegra_mc_write_32(MC_SMMU_CLIENT_CONFIG2, val);
+
+	val = MC_SMMU_CLIENT_CONFIG3_RESET_VAL &
+		mc_set_smmu_unordered_boot_so_mss(3, SDMMCWAB);
+	tegra_mc_write_32(MC_SMMU_CLIENT_CONFIG3, val);
+
+	val = MC_SMMU_CLIENT_CONFIG4_RESET_VAL &
+		mc_set_smmu_unordered_boot_so_mss(4, SESWR) &
+		mc_set_smmu_unordered_boot_so_mss(4, ETRW) &
+		mc_set_smmu_unordered_boot_so_mss(4, AXISW) &
+		mc_set_smmu_unordered_boot_so_mss(4, EQOSW) &
+		mc_set_smmu_unordered_boot_so_mss(4, UFSHCW) &
+		mc_set_smmu_unordered_boot_so_mss(4, BPMPDMAW) &
+		mc_set_smmu_unordered_boot_so_mss(4, AONDMAW) &
+		mc_set_smmu_unordered_boot_so_mss(4, SCEDMAW);
+	tegra_mc_write_32(MC_SMMU_CLIENT_CONFIG4, val);
+
+	val = MC_SMMU_CLIENT_CONFIG5_RESET_VAL &
+		mc_set_smmu_unordered_boot_so_mss(5, APEDMAW);
+	tegra_mc_write_32(MC_SMMU_CLIENT_CONFIG5, val);
+
+	/*
+	 * Deassert HOTRESET FLUSH_ENABLE for boot and strongly ordered MSS
+	 * clients to allow memory traffic from all clients to start passing
+	 * through ROC
+	 */
+	val = tegra_mc_read_32(MC_CLIENT_HOTRESET_CTRL0);
+	assert(val == wdata_0);
+
+	wdata_0 = MC_CLIENT_HOTRESET_CTRL0_RESET_VAL;
+	tegra_mc_write_32(MC_CLIENT_HOTRESET_CTRL0, wdata_0);
+
+	/* Wait for HOTRESET STATUS to indicate FLUSH_DONE */
+	do {
+		val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS0);
+	} while ((val & wdata_0) != wdata_0);
+
+	/* Wait one more time due to SW WAR for known legacy issue */
+	do {
+		val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS0);
+	} while ((val & wdata_0) != wdata_0);
+
+	val = tegra_mc_read_32(MC_CLIENT_HOTRESET_CTRL1);
+	assert(val == wdata_1);
+
+	wdata_1 = MC_CLIENT_HOTRESET_CTRL1_RESET_VAL;
+	tegra_mc_write_32(MC_CLIENT_HOTRESET_CTRL1, wdata_1);
+
+	/* Wait for HOTRESET STATUS to indicate FLUSH_DONE */
+	do {
+		val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS1);
+	} while ((val & wdata_1) != wdata_1);
+
+	/* Wait one more time due to SW WAR for known legacy issue */
+	do {
+		val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS1);
+	} while ((val & wdata_1) != wdata_1);
+
+#endif
+}
+
 /*
  * Init Memory controller during boot.
  */
@@ -243,7 +495,7 @@
 	uint32_t num_overrides = sizeof(streamid_overrides) / sizeof(uint32_t);
 	uint32_t num_sec_cfgs = sizeof(sec_cfgs) / sizeof(mc_streamid_security_cfg_t);
 	uint32_t num_txn_overrides = sizeof(mc_override_cfgs) / sizeof(mc_txn_override_cfg_t);
-	uint32_t tegra_rev;
+	uint32_t chip_minor, chip_major;
 	int i;
 
 	INFO("Tegra Memory Controller (v2)\n");
@@ -281,12 +533,22 @@
 		MC_SMMU_BYPASS_CONFIG_SETTINGS);
 
 	/*
+	 * Re-configure MSS to allow ROC to deal with ordering of the
+	 * Memory Controller traffic. This is needed as the Memory Controller
+	 * boots with MSS having all control, but ROC provides a performance
+	 * boost as compared to MSS.
+	 */
+	tegra_memctrl_reconfig_mss_clients();
+
+	/*
 	 * Set the MC_TXN_OVERRIDE registers for write clients.
 	 */
-	tegra_rev = (mmio_read_32(TEGRA_MISC_BASE + HARDWARE_REVISION_OFFSET) &
-			HARDWARE_MINOR_REVISION_MASK) >> HARDWARE_MINOR_REVISION_SHIFT;
+	chip_major = (mmio_read_32(TEGRA_MISC_BASE + HARDWARE_REVISION_OFFSET) >>
+			MAJOR_VERSION_SHIFT) & MAJOR_VERSION_MASK;
+	chip_minor = (mmio_read_32(TEGRA_MISC_BASE + HARDWARE_REVISION_OFFSET) >>
+			MINOR_VERSION_SHIFT) & MINOR_VERSION_MASK;
 
-	if (tegra_rev == HARDWARE_REVISION_A01) {
+	if ((chip_major == 0) || (chip_major > 0 && chip_minor == 1)) {
 
 		/* GPU and NVENC settings for rev. A01 */
 		val = tegra_mc_read_32(MC_TXN_OVERRIDE_CONFIG_GPUSWR);
@@ -322,13 +584,21 @@
  */
 void tegra_memctrl_restore_settings(void)
 {
+	/*
+	 * Re-configure MSS to allow ROC to deal with ordering of the
+	 * Memory Controller traffic. This is needed as the Memory Controller
+	 * resets during System Suspend with MSS having all control, but ROC
+	 * provides a performance boost as compared to MSS.
+	 */
+	tegra_memctrl_reconfig_mss_clients();
+
 	/* video memory carveout region */
 	if (video_mem_base) {
 		tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_LO,
 				  (uint32_t)video_mem_base);
 		tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_HI,
 				  (uint32_t)(video_mem_base >> 32));
-		tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB, video_mem_size);
+		tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB, video_mem_size_mb);
 
 		/*
 		 * MCE propogates the VideoMem configuration values across the
@@ -436,11 +706,11 @@
 	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);
+	tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB, size_in_bytes >> 20);
 
 	/* store new values */
 	video_mem_base = phys_base;
-	video_mem_size = size_in_bytes >> 20;
+	video_mem_size_mb = size_in_bytes >> 20;
 
 	/*
 	 * MCE propogates the VideoMem configuration values across the
diff --git a/plat/nvidia/tegra/include/drivers/memctrl_v2.h b/plat/nvidia/tegra/include/drivers/memctrl_v2.h
index 9623e25..a7ab650 100644
--- a/plat/nvidia/tegra/include/drivers/memctrl_v2.h
+++ b/plat/nvidia/tegra/include/drivers/memctrl_v2.h
@@ -31,7 +31,6 @@
 #ifndef __MEMCTRLV2_H__
 #define __MEMCTRLV2_H__
 
-#include <mmio.h>
 #include <tegra_def.h>
 
 /*******************************************************************************
@@ -283,6 +282,10 @@
 #define MC_TXN_OVERRIDE_CONFIG_AFIW		0x1188
 #define MC_TXN_OVERRIDE_CONFIG_SCEW		0x14e0
 
+#define MC_TXN_OVERRIDE_CONFIG_AXID_OVERRIDE_CGID	(1 << 0)
+#define MC_TXN_OVERRIDE_CONFIG_COH_PATH_OVERRIDE_SO_DEV	(2 << 4)
+#define MC_TXN_OVERRIDE_CONFIG_AXID_OVERRIDE_SO_DEV_CGID_SO_DEV_CLIENT	(1 << 12)
+
 /*******************************************************************************
  * Non-SO_DEV transactions override values for CGID_TAG bitfield for the
  * MC_TXN_OVERRIDE_CONFIG_{module} registers
@@ -293,6 +296,10 @@
 #define MC_TXN_OVERRIDE_CGID_TAG_ADR		3
 #define MC_TXN_OVERRIDE_CGID_TAG_MASK		3
 
+#ifndef __ASSEMBLY__
+
+#include <sys/types.h>
+
 /*******************************************************************************
  * Structure to hold the transaction override settings to use to override
  * client inputs
@@ -327,12 +334,12 @@
 	int override_client_ns_flag;
 } mc_streamid_security_cfg_t;
 
-#define OVERRIDE_DISABLE			1
-#define OVERRIDE_ENABLE				0
-#define CLIENT_FLAG_SECURE			0
-#define CLIENT_FLAG_NON_SECURE			1
-#define CLIENT_INPUTS_OVERRIDE			1
-#define CLIENT_INPUTS_NO_OVERRIDE		0
+#define OVERRIDE_DISABLE				1
+#define OVERRIDE_ENABLE					0
+#define CLIENT_FLAG_SECURE				0
+#define CLIENT_FLAG_NON_SECURE				1
+#define CLIENT_INPUTS_OVERRIDE				1
+#define CLIENT_INPUTS_NO_OVERRIDE			0
 
 #define mc_make_sec_cfg(off, ns, ovrrd, access) \
 		{ \
@@ -343,30 +350,209 @@
 			.override_enable = OVERRIDE_ ## access \
 		}
 
+#endif /* __ASSMEBLY__ */
+
 /*******************************************************************************
  * TZDRAM carveout configuration registers
  ******************************************************************************/
-#define MC_SECURITY_CFG0_0			0x70
-#define MC_SECURITY_CFG1_0			0x74
-#define MC_SECURITY_CFG3_0			0x9BC
+#define MC_SECURITY_CFG0_0				0x70
+#define MC_SECURITY_CFG1_0				0x74
+#define MC_SECURITY_CFG3_0				0x9BC
 
 /*******************************************************************************
  * 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_BASE_HI			0x978
+#define MC_VIDEO_PROTECT_BASE_LO			0x648
+#define MC_VIDEO_PROTECT_SIZE_MB			0x64c
 
 /*******************************************************************************
  * TZRAM carveout configuration registers
  ******************************************************************************/
+#define MC_TZRAM_BASE					0x1850
+#define MC_TZRAM_END					0x1854
+#define MC_TZRAM_HI_ADDR_BITS				0x1588
+ #define TZRAM_ADDR_HI_BITS_MASK			0x3
+ #define TZRAM_END_HI_BITS_SHIFT			8
+#define MC_TZRAM_REG_CTRL				0x185c
+ #define DISABLE_TZRAM_ACCESS				1
+
+/*******************************************************************************
+ * Memory Controller Reset Control registers
+ ******************************************************************************/
+#define MC_CLIENT_HOTRESET_CTRL0			0x200
+#define  MC_CLIENT_HOTRESET_CTRL0_RESET_VAL		0
+#define  MC_CLIENT_HOTRESET_CTRL0_AFI_FLUSH_ENB		(1 << 0)
+#define  MC_CLIENT_HOTRESET_CTRL0_HC_FLUSH_ENB		(1 << 6)
+#define  MC_CLIENT_HOTRESET_CTRL0_HDA_FLUSH_ENB		(1 << 7)
+#define  MC_CLIENT_HOTRESET_CTRL0_ISP2_FLUSH_ENB	(1 << 8)
+#define  MC_CLIENT_HOTRESET_CTRL0_MPCORE_FLUSH_ENB	(1 << 9)
+#define  MC_CLIENT_HOTRESET_CTRL0_NVENC_FLUSH_ENB	(1 << 11)
+#define  MC_CLIENT_HOTRESET_CTRL0_SATA_FLUSH_ENB	(1 << 15)
+#define  MC_CLIENT_HOTRESET_CTRL0_VI_FLUSH_ENB		(1 << 17)
+#define  MC_CLIENT_HOTRESET_CTRL0_VIC_FLUSH_ENB		(1 << 18)
+#define  MC_CLIENT_HOTRESET_CTRL0_XUSB_HOST_FLUSH_ENB	(1 << 19)
+#define  MC_CLIENT_HOTRESET_CTRL0_XUSB_DEV_FLUSH_ENB	(1 << 20)
+#define  MC_CLIENT_HOTRESET_CTRL0_TSEC_FLUSH_ENB	(1 << 22)
+#define  MC_CLIENT_HOTRESET_CTRL0_SDMMC1A_FLUSH_ENB	(1 << 29)
+#define  MC_CLIENT_HOTRESET_CTRL0_SDMMC2A_FLUSH_ENB	(1 << 30)
+#define  MC_CLIENT_HOTRESET_CTRL0_SDMMC3A_FLUSH_ENB	(1 << 31)
+#define MC_CLIENT_HOTRESET_STATUS0			0x204
+#define MC_CLIENT_HOTRESET_CTRL1			0x970
+#define  MC_CLIENT_HOTRESET_CTRL1_RESET_VAL		0
+#define  MC_CLIENT_HOTRESET_CTRL1_SDMMC4A_FLUSH_ENB	(1 << 0)
+#define  MC_CLIENT_HOTRESET_CTRL1_GPU_FLUSH_ENB		(1 << 2)
+#define  MC_CLIENT_HOTRESET_CTRL1_NVDEC_FLUSH_ENB	(1 << 5)
+#define  MC_CLIENT_HOTRESET_CTRL1_APE_FLUSH_ENB		(1 << 6)
+#define  MC_CLIENT_HOTRESET_CTRL1_SE_FLUSH_ENB		(1 << 7)
+#define  MC_CLIENT_HOTRESET_CTRL1_NVJPG_FLUSH_ENB	(1 << 8)
+#define  MC_CLIENT_HOTRESET_CTRL1_ETR_FLUSH_ENB		(1 << 12)
+#define  MC_CLIENT_HOTRESET_CTRL1_TSECB_FLUSH_ENB	(1 << 13)
+#define  MC_CLIENT_HOTRESET_CTRL1_AXIS_FLUSH_ENB	(1 << 18)
+#define  MC_CLIENT_HOTRESET_CTRL1_EQOS_FLUSH_ENB	(1 << 19)
+#define  MC_CLIENT_HOTRESET_CTRL1_UFSHC_FLUSH_ENB	(1 << 20)
+#define  MC_CLIENT_HOTRESET_CTRL1_NVDISPLAY_FLUSH_ENB	(1 << 21)
+#define  MC_CLIENT_HOTRESET_CTRL1_BPMP_FLUSH_ENB	(1 << 22)
+#define  MC_CLIENT_HOTRESET_CTRL1_AON_FLUSH_ENB		(1 << 23)
+#define  MC_CLIENT_HOTRESET_CTRL1_SCE_FLUSH_ENB		(1 << 24)
+#define MC_CLIENT_HOTRESET_STATUS1			0x974
+
+/*******************************************************************************
+ * TSA configuration registers
+ ******************************************************************************/
-#define MC_TZRAM_BASE				0x1850
-#define MC_TZRAM_END				0x1854
-#define MC_TZRAM_HI_ADDR_BITS			0x1588
- #define TZRAM_ADDR_HI_BITS_MASK		0x3
- #define TZRAM_END_HI_BITS_SHIFT		8
-#define MC_TZRAM_REG_CTRL			0x185c
- #define DISABLE_TZRAM_ACCESS			1
+#define TSA_CONFIG_STATIC0_CSW_SESWR			0x4010
+#define  TSA_CONFIG_STATIC0_CSW_SESWR_RESET		0x1100
+#define TSA_CONFIG_STATIC0_CSW_ETRW			0x4038
+#define  TSA_CONFIG_STATIC0_CSW_ETRW_RESET		0x1100
+#define TSA_CONFIG_STATIC0_CSW_SDMMCWAB			0x5010
+#define  TSA_CONFIG_STATIC0_CSW_SDMMCWAB_RESET		0x1100
+#define TSA_CONFIG_STATIC0_CSW_AXISW			0x7008
+#define  TSA_CONFIG_STATIC0_CSW_AXISW_RESET		0x1100
+#define TSA_CONFIG_STATIC0_CSW_HDAW			0xA008
+#define  TSA_CONFIG_STATIC0_CSW_HDAW_RESET		0x100
+#define TSA_CONFIG_STATIC0_CSW_AONDMAW			0xB018
+#define  TSA_CONFIG_STATIC0_CSW_AONDMAW_RESET		0x1100
+#define TSA_CONFIG_STATIC0_CSW_SCEDMAW			0xD018
+#define  TSA_CONFIG_STATIC0_CSW_SCEDMAW_RESET		0x1100
+#define TSA_CONFIG_STATIC0_CSW_BPMPDMAW			0xD028
+#define  TSA_CONFIG_STATIC0_CSW_BPMPDMAW_RESET		0x1100
+#define TSA_CONFIG_STATIC0_CSW_APEDMAW			0x12018
+#define  TSA_CONFIG_STATIC0_CSW_APEDMAW_RESET		0x1100
+#define TSA_CONFIG_STATIC0_CSW_UFSHCW			0x13008
+#define  TSA_CONFIG_STATIC0_CSW_UFSHCW_RESET		0x1100
+#define TSA_CONFIG_STATIC0_CSW_AFIW			0x13018
+#define  TSA_CONFIG_STATIC0_CSW_AFIW_RESET		0x1100
+#define TSA_CONFIG_STATIC0_CSW_SATAW			0x13028
+#define  TSA_CONFIG_STATIC0_CSW_SATAW_RESET		0x1100
+#define TSA_CONFIG_STATIC0_CSW_EQOSW			0x13038
+#define  TSA_CONFIG_STATIC0_CSW_EQOSW_RESET		0x1100
+#define TSA_CONFIG_STATIC0_CSW_XUSB_DEVW		0x15008
+#define  TSA_CONFIG_STATIC0_CSW_XUSB_DEVW_RESET		0x1100
+#define TSA_CONFIG_STATIC0_CSW_XUSB_HOSTW		0x15018
+#define  TSA_CONFIG_STATIC0_CSW_XUSB_HOSTW_RESET	0x1100
+
+#define TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_MASK		(0x3 << 11)
+#define TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_PASTHRU		(0 << 11)
+
+/*******************************************************************************
+ * Memory Controller's PCFIFO client configuration registers
+ ******************************************************************************/
+#define MC_PCFIFO_CLIENT_CONFIG1			0xdd4
+#define  MC_PCFIFO_CLIENT_CONFIG1_RESET_VAL		0x20000
+#define  MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_AFIW_UNORDERED	(0 << 17)
+#define  MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_AFIW_MASK	(1 << 17)
+#define  MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_HDAW_UNORDERED	(0 << 21)
+#define  MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_HDAW_MASK	(1 << 21)
+#define  MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_SATAW_UNORDERED (0 << 29)
+#define  MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_SATAW_MASK	(1 << 29)
+
+#define MC_PCFIFO_CLIENT_CONFIG2			0xdd8
+#define  MC_PCFIFO_CLIENT_CONFIG2_RESET_VAL		0x20000
+#define  MC_PCFIFO_CLIENT_CONFIG2_PCFIFO_XUSB_HOSTW_UNORDERED	(0 << 11)
+#define  MC_PCFIFO_CLIENT_CONFIG2_PCFIFO_XUSB_HOSTW_MASK	(1 << 11)
+#define  MC_PCFIFO_CLIENT_CONFIG2_PCFIFO_XUSB_DEVW_UNORDERED	(0 << 13)
+#define  MC_PCFIFO_CLIENT_CONFIG2_PCFIFO_XUSB_DEVW_MASK	(1 << 13)
+
+#define MC_PCFIFO_CLIENT_CONFIG3			0xddc
+#define  MC_PCFIFO_CLIENT_CONFIG3_RESET_VAL		0
+#define  MC_PCFIFO_CLIENT_CONFIG3_PCFIFO_SDMMCWAB_UNORDERED	(0 << 7)
+#define  MC_PCFIFO_CLIENT_CONFIG3_PCFIFO_SDMMCWAB_MASK	(1 << 7)
+
+#define MC_PCFIFO_CLIENT_CONFIG4		0xde0
+#define  MC_PCFIFO_CLIENT_CONFIG4_RESET_VAL	0
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_SESWR_UNORDERED (0 << 1)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_SESWR_MASK	(1 << 1)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_ETRW_UNORDERED	(0 << 5)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_ETRW_MASK	(1 << 5)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_AXISW_UNORDERED (0 << 13)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_AXISW_MASK	(1 << 13)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_EQOSW_UNORDERED (0 << 15)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_EQOSW_MASK	(1 << 15)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_UFSHCW_UNORDERED	(0 << 17)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_UFSHCW_MASK	(1 << 17)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_BPMPDMAW_UNORDERED	(0 << 22)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_BPMPDMAW_MASK	(1 << 22)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_AONDMAW_UNORDERED	(0 << 26)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_AONDMAW_MASK	(1 << 26)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_SCEDMAW_UNORDERED	(0 << 30)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_SCEDMAW_MASK	(1 << 30)
+
+#define MC_PCFIFO_CLIENT_CONFIG5		0xbf4
+#define  MC_PCFIFO_CLIENT_CONFIG5_RESET_VAL	0
+#define  MC_PCFIFO_CLIENT_CONFIG5_PCFIFO_APEDMAW_UNORDERED	(0 << 0)
+#define  MC_PCFIFO_CLIENT_CONFIG5_PCFIFO_APEDMAW_MASK	(1 << 0)
+
+/*******************************************************************************
+ * Memory Controller's SMMU client configuration registers
+ ******************************************************************************/
+#define MC_SMMU_CLIENT_CONFIG1				0x44
+#define  MC_SMMU_CLIENT_CONFIG1_RESET_VAL		0x20000
+#define  MC_SMMU_CLIENT_CONFIG1_AFIW_UNORDERED		(0 << 17)
+#define  MC_SMMU_CLIENT_CONFIG1_AFIW_MASK		(1 << 17)
+#define  MC_SMMU_CLIENT_CONFIG1_HDAW_UNORDERED		(0 << 21)
+#define  MC_SMMU_CLIENT_CONFIG1_HDAW_MASK		(1 << 21)
+#define  MC_SMMU_CLIENT_CONFIG1_SATAW_UNORDERED		(0 << 29)
+#define  MC_SMMU_CLIENT_CONFIG1_SATAW_MASK		(1 << 29)
+
+#define MC_SMMU_CLIENT_CONFIG2				0x48
+#define  MC_SMMU_CLIENT_CONFIG2_RESET_VAL		0x20000
+#define  MC_SMMU_CLIENT_CONFIG2_XUSB_HOSTW_UNORDERED	(0 << 11)
+#define  MC_SMMU_CLIENT_CONFIG2_XUSB_HOSTW_MASK		(1 << 11)
+#define  MC_SMMU_CLIENT_CONFIG2_XUSB_DEVW_UNORDERED	(0 << 13)
+#define  MC_SMMU_CLIENT_CONFIG2_XUSB_DEVW_MASK		(1 << 13)
+
+#define MC_SMMU_CLIENT_CONFIG3				0x4c
+#define  MC_SMMU_CLIENT_CONFIG3_RESET_VAL		0
+#define  MC_SMMU_CLIENT_CONFIG3_SDMMCWAB_UNORDERED	(0 << 7)
+#define  MC_SMMU_CLIENT_CONFIG3_SDMMCWAB_MASK		(1 << 7)
+
+#define MC_SMMU_CLIENT_CONFIG4				0xb9c
+#define  MC_SMMU_CLIENT_CONFIG4_RESET_VAL		0
+#define  MC_SMMU_CLIENT_CONFIG4_SESWR_UNORDERED		(0 << 1)
+#define  MC_SMMU_CLIENT_CONFIG4_SESWR_MASK		(1 << 1)
+#define  MC_SMMU_CLIENT_CONFIG4_ETRW_UNORDERED		(0 << 5)
+#define  MC_SMMU_CLIENT_CONFIG4_ETRW_MASK		(1 << 5)
+#define  MC_SMMU_CLIENT_CONFIG4_AXISW_UNORDERED		(0 << 13)
+#define  MC_SMMU_CLIENT_CONFIG4_AXISW_MASK		(1 << 13)
+#define  MC_SMMU_CLIENT_CONFIG4_EQOSW_UNORDERED		(0 << 15)
+#define  MC_SMMU_CLIENT_CONFIG4_EQOSW_MASK		(1 << 15)
+#define  MC_SMMU_CLIENT_CONFIG4_UFSHCW_UNORDERED	(0 << 17)
+#define  MC_SMMU_CLIENT_CONFIG4_UFSHCW_MASK		(1 << 17)
+#define  MC_SMMU_CLIENT_CONFIG4_BPMPDMAW_UNORDERED	(0 << 22)
+#define  MC_SMMU_CLIENT_CONFIG4_BPMPDMAW_MASK		(1 << 22)
+#define  MC_SMMU_CLIENT_CONFIG4_AONDMAW_UNORDERED	(0 << 26)
+#define  MC_SMMU_CLIENT_CONFIG4_AONDMAW_MASK		(1 << 26)
+#define  MC_SMMU_CLIENT_CONFIG4_SCEDMAW_UNORDERED	(0 << 30)
+#define  MC_SMMU_CLIENT_CONFIG4_SCEDMAW_MASK		(1 << 30)
+
+#define MC_SMMU_CLIENT_CONFIG5				0xbac
+#define  MC_SMMU_CLIENT_CONFIG5_RESET_VAL		0
+#define  MC_SMMU_CLIENT_CONFIG5_APEDMAW_UNORDERED	(0 << 0)
+#define  MC_SMMU_CLIENT_CONFIG5_APEDMAW_MASK	(1 << 0)
+
+#ifndef __ASSEMBLY__
+
+#include <mmio.h>
 
 static inline uint32_t tegra_mc_read_32(uint32_t off)
 {
@@ -388,4 +574,42 @@
 	mmio_write_32(TEGRA_MC_STREAMID_BASE + off, val);
 }
 
+#define mc_set_pcfifo_unordered_boot_so_mss(id, client) \
+	(~MC_PCFIFO_CLIENT_CONFIG##id##_PCFIFO_##client##_MASK | \
+	 MC_PCFIFO_CLIENT_CONFIG##id##_PCFIFO_##client##_UNORDERED)
+
+#define mc_set_smmu_unordered_boot_so_mss(id, client) \
+	(~MC_PCFIFO_CLIENT_CONFIG##id##_PCFIFO_##client##_MASK | \
+	 MC_PCFIFO_CLIENT_CONFIG##id##_PCFIFO_##client##_UNORDERED)
+
+#define mc_set_tsa_passthrough(client) \
+	{ \
+		mmio_write_32(TEGRA_TSA_BASE + TSA_CONFIG_STATIC0_CSW_##client, \
+			(TSA_CONFIG_STATIC0_CSW_##client##_RESET & \
+			 ~TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_MASK) | \
+			TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_PASTHRU); \
+	}
+
+#define mc_set_forced_coherent_cfg(client) \
+	{ \
+		tegra_mc_write_32(MC_TXN_OVERRIDE_CONFIG_##client, \
+			MC_TXN_OVERRIDE_CONFIG_COH_PATH_OVERRIDE_SO_DEV); \
+	}
+
+#define mc_set_forced_coherent_so_dev_cfg(client) \
+	{ \
+		tegra_mc_write_32(MC_TXN_OVERRIDE_CONFIG_##client, \
+			MC_TXN_OVERRIDE_CONFIG_COH_PATH_OVERRIDE_SO_DEV | \
+			MC_TXN_OVERRIDE_CONFIG_AXID_OVERRIDE_SO_DEV_CGID_SO_DEV_CLIENT); \
+	}
+
+#define mc_set_forced_coherent_axid_so_dev_cfg(client) \
+	{ \
+		tegra_mc_write_32(MC_TXN_OVERRIDE_CONFIG_##client, \
+			MC_TXN_OVERRIDE_CONFIG_COH_PATH_OVERRIDE_SO_DEV | \
+			MC_TXN_OVERRIDE_CONFIG_AXID_OVERRIDE_CGID | \
+			MC_TXN_OVERRIDE_CONFIG_AXID_OVERRIDE_SO_DEV_CGID_SO_DEV_CLIENT); \
+	}
+#endif /* __ASSMEBLY__ */
+
 #endif /* __MEMCTRLV2_H__ */
diff --git a/plat/nvidia/tegra/include/drivers/smmu.h b/plat/nvidia/tegra/include/drivers/smmu.h
index bb08a55..0867c11 100644
--- a/plat/nvidia/tegra/include/drivers/smmu.h
+++ b/plat/nvidia/tegra/include/drivers/smmu.h
@@ -627,6 +627,6 @@
 }
 
 void tegra_smmu_init(void);
-void tegra_smmu_save_context(void);
+void tegra_smmu_save_context(uint64_t smmu_ctx_addr);
 
 #endif /*__SMMU_H */
diff --git a/plat/nvidia/tegra/include/t186/tegra_def.h b/plat/nvidia/tegra/include/t186/tegra_def.h
index f3fbb89..7f85351 100644
--- a/plat/nvidia/tegra/include/t186/tegra_def.h
+++ b/plat/nvidia/tegra/include/t186/tegra_def.h
@@ -31,8 +31,6 @@
 #ifndef __TEGRA_DEF_H__
 #define __TEGRA_DEF_H__
 
-#include <platform_def.h>
-
 /*******************************************************************************
  * 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'
@@ -78,12 +76,19 @@
  ******************************************************************************/
 #define TEGRA_MISC_BASE			0x00100000
 #define  HARDWARE_REVISION_OFFSET	0x4
-#define  HARDWARE_MINOR_REVISION_MASK	0xf0000
-#define  HARDWARE_MINOR_REVISION_SHIFT	0x10
-#define  HARDWARE_REVISION_A01		1
+#define  MAJOR_VERSION_SHIFT		0x4
+#define  MAJOR_VERSION_MASK		0xF
+#define  MINOR_VERSION_SHIFT		0x10
+#define  MINOR_VERSION_MASK		0xF
+
 #define  MISCREG_PFCFG			0x200C
 
 /*******************************************************************************
+ * Tegra TSA Controller constants
+ ******************************************************************************/
+#define TEGRA_TSA_BASE			0x02400000
+
+/*******************************************************************************
  * Tegra Memory Controller constants
  ******************************************************************************/
 #define TEGRA_MC_STREAMID_BASE		0x02C00000
diff --git a/plat/nvidia/tegra/include/tegra_private.h b/plat/nvidia/tegra/include/tegra_private.h
index 012bfd7..39006f6 100644
--- a/plat/nvidia/tegra/include/tegra_private.h
+++ b/plat/nvidia/tegra/include/tegra_private.h
@@ -119,4 +119,7 @@
 /* Declarations for tegra_delay_timer.c */
 void tegra_delay_timer_init(void);
 
+void tegra_secure_entrypoint(void);
+void tegra186_cpu_reset_handler(void);
+
 #endif /* __TEGRA_PRIVATE_H__ */
diff --git a/plat/nvidia/tegra/soc/t186/drivers/include/mce.h b/plat/nvidia/tegra/soc/t186/drivers/include/mce.h
index 7078b8b..6065692 100644
--- a/plat/nvidia/tegra/soc/t186/drivers/include/mce.h
+++ b/plat/nvidia/tegra/soc/t186/drivers/include/mce.h
@@ -94,6 +94,7 @@
 	MCE_CMD_ENUM_WRITE_MCA,
 	MCE_CMD_ROC_FLUSH_CACHE,
 	MCE_CMD_ROC_CLEAN_CACHE,
+	MCE_CMD_ENABLE_LATIC,
 	MCE_CMD_IS_CCX_ALLOWED = 0xFE,
 	MCE_CMD_MAX = 0xFF,
 } mce_cmd_t;
@@ -321,6 +322,7 @@
 int mce_update_gsc_tzdram(void);
 int mce_update_gsc_tzram(void);
 __dead2 void mce_enter_ccplex_state(uint32_t state_idx);
+void mce_verify_firmware_version(void);
 
 /* declarations for ARI/NVG handler functions */
 int ari_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time);
diff --git a/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c b/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c
index 745b6f4..9d0d71f 100644
--- a/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c
+++ b/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c
@@ -356,6 +356,24 @@
 
 		break;
 
+#if ENABLE_CHIP_VERIFICATION_HARNESS
+	case MCE_CMD_ENABLE_LATIC:
+		/*
+		 * This call is not for production use. The constant value,
+		 * 0xFFFF0000, is specific to allowing for enabling LATIC on
+		 * pre-production parts for the chip verification harness.
+		 *
+		 * Enabling LATIC allows S/W to read the MINI ISPs in the
+		 * CCPLEX. The ISMs are used for various measurements relevant
+		 * to particular locations in the Silicon. They are small
+		 * counters which can be polled to determine how fast a
+		 * particular location in the Silicon is.
+		 */
+		ops->enter_ccplex_state(mce_get_curr_cpu_ari_base(),
+			0xFFFF0000);
+
+		break;
+#endif
 	default:
 		ERROR("unknown MCE command (%d)\n", cmd);
 		return EINVAL;
@@ -429,3 +447,57 @@
 
 	panic();
 }
+
+/*******************************************************************************
+ * Handler to read the MCE firmware version and check if it is compatible
+ * with interface header the BL3-1 was compiled against
+ ******************************************************************************/
+void mce_verify_firmware_version(void)
+{
+	arch_mce_ops_t *ops;
+	uint32_t cpu_ari_base;
+	uint64_t version;
+	uint32_t major, minor, chip_minor, chip_major;
+
+	/* get a pointer to the CPU's arch_mce_ops_t struct */
+	ops = mce_get_curr_cpu_ops();
+
+	/* get the CPU's ARI base address */
+	cpu_ari_base = mce_get_curr_cpu_ari_base();
+
+	/*
+	 * Read the MCE firmware version and extract the major and minor
+	 * version fields
+	 */
+	version = ops->call_enum_misc(cpu_ari_base, TEGRA_ARI_MISC_VERSION, 0);
+	major = (uint32_t)version;
+	minor = (uint32_t)(version >> 32);
+
+	INFO("MCE Version - HW=%d:%d, SW=%d:%d\n", major, minor,
+		TEGRA_ARI_VERSION_MAJOR, TEGRA_ARI_VERSION_MINOR);
+
+	/*
+	 * MCE firmware is not running on simulation platforms. Simulation
+	 * platforms are identified by v0.3 from the Tegra Chip ID value.
+	 */
+	chip_major = (mmio_read_32(TEGRA_MISC_BASE + HARDWARE_REVISION_OFFSET) >>
+			MAJOR_VERSION_SHIFT) & MAJOR_VERSION_MASK;
+	chip_minor = (mmio_read_32(TEGRA_MISC_BASE + HARDWARE_REVISION_OFFSET) >>
+			MINOR_VERSION_SHIFT) & MINOR_VERSION_MASK;
+	if ((chip_major == 0) && (chip_minor == 3))
+		return;
+
+	/*
+	 * Verify that the MCE firmware version and the interface header
+	 * match
+	 */
+	if (major != TEGRA_ARI_VERSION_MAJOR) {
+		ERROR("ARI major version mismatch\n");
+		panic();
+	}
+
+	if (minor < TEGRA_ARI_VERSION_MINOR) {
+		ERROR("ARI minor version mismatch\n");
+		panic();
+	}
+}
diff --git a/plat/nvidia/tegra/soc/t186/drivers/smmu/smmu.c b/plat/nvidia/tegra/soc/t186/drivers/smmu/smmu.c
index 2940f58..d1e1804 100644
--- a/plat/nvidia/tegra/soc/t186/drivers/smmu/smmu.c
+++ b/plat/nvidia/tegra/soc/t186/drivers/smmu/smmu.c
@@ -29,9 +29,13 @@
  */
 
 #include <assert.h>
+#include <bl_common.h>
 #include <debug.h>
 #include <memctrl_v2.h>
+#include <platform_def.h>
 #include <smmu.h>
+#include <string.h>
+#include <tegra_private.h>
 
 typedef struct smmu_regs {
 	uint32_t reg;
@@ -133,7 +137,7 @@
 		.val = 0xFFFFFFFF, \
 	}
 
-static smmu_regs_t smmu_ctx_regs[] = {
+static __attribute__((aligned(16))) smmu_regs_t smmu_ctx_regs[] = {
 	_START_OF_TABLE_,
 	mc_make_sid_security_cfg(SCEW),
 	mc_make_sid_security_cfg(AFIR),
@@ -421,12 +425,15 @@
 };
 
 /*
- * Save SMMU settings before "System Suspend"
+ * Save SMMU settings before "System Suspend" to TZDRAM
  */
-void tegra_smmu_save_context(void)
+void tegra_smmu_save_context(uint64_t smmu_ctx_addr)
 {
 	uint32_t i;
 #if DEBUG
+	plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
+	uint64_t tzdram_base = params_from_bl2->tzdram_base;
+	uint64_t tzdram_end = tzdram_base + params_from_bl2->tzdram_size;
 	uint32_t reg_id1, pgshift, cb_size;
 
 	/* sanity check SMMU settings c*/
@@ -438,6 +445,8 @@
 	assert(!((pgshift != PGSHIFT) || (cb_size != CB_SIZE)));
 #endif
 
+	assert((smmu_ctx_addr >= tzdram_base) && (smmu_ctx_addr <= tzdram_end));
+
 	/* index of _END_OF_TABLE_ */
 	smmu_ctx_regs[0].val = ARRAY_SIZE(smmu_ctx_regs) - 1;
 
@@ -445,11 +454,15 @@
 	for (i = 1; i < ARRAY_SIZE(smmu_ctx_regs) - 1; i++)
 		smmu_ctx_regs[i].val = mmio_read_32(smmu_ctx_regs[i].reg);
 
+	/* Save SMMU config settings */
+	memcpy16((void *)(uintptr_t)smmu_ctx_addr, (void *)smmu_ctx_regs,
+		 sizeof(smmu_ctx_regs));
+
 	/* save the SMMU table address */
 	mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV11_LO,
-		(uint32_t)(unsigned long)smmu_ctx_regs);
+		(uint32_t)smmu_ctx_addr);
 	mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV11_HI,
-		(uint32_t)(((unsigned long)smmu_ctx_regs) >> 32));
+		(uint32_t)(smmu_ctx_addr >> 32));
 }
 
 /*
diff --git a/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c
index 7e35cc6..8355270 100644
--- a/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c
+++ b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c
@@ -39,18 +39,27 @@
 #include <mce.h>
 #include <psci.h>
 #include <smmu.h>
+#include <string.h>
 #include <t18x_ari.h>
 #include <tegra_private.h>
 
 extern void prepare_cpu_pwr_dwn(void);
+extern void tegra186_cpu_reset_handler(void);
+extern uint32_t __tegra186_cpu_reset_handler_data,
+		__tegra186_cpu_reset_handler_end;
+
+/* TZDRAM offset for saving SMMU context */
+#define TEGRA186_SMMU_CTX_OFFSET	16
 
 /* 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
+/* default core wake mask for CPU_SUSPEND */
+#define TEGRA186_CORE_WAKE_MASK		0x180c
 /* context size to save during system suspend */
-#define TEGRA186_SE_CONTEXT_SIZE		3
+#define TEGRA186_SE_CONTEXT_SIZE	3
 
 static uint32_t se_regs[TEGRA186_SE_CONTEXT_SIZE];
 static unsigned int wake_time[PLATFORM_CORE_COUNT];
@@ -98,6 +107,8 @@
 	int impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
 	cpu_context_t *ctx = cm_get_context(NON_SECURE);
 	gp_regs_t *gp_regs = get_gpregs_ctx(ctx);
+	plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
+	uint64_t smmu_ctx_base;
 	uint32_t val;
 
 	assert(ctx);
@@ -115,26 +126,30 @@
 
 	if (stateid_afflvl0 == PSTATE_ID_CORE_IDLE) {
 
+		/* Program default wake mask */
+		write_ctx_reg(gp_regs, CTX_GPREG_X4, 0);
+		write_ctx_reg(gp_regs, CTX_GPREG_X5, TEGRA186_CORE_WAKE_MASK);
+		write_ctx_reg(gp_regs, CTX_GPREG_X6, 1);
+		(void)mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO, 0, 0, 0);
+
 		/* 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) {
 
+		/* Program default wake mask */
+		write_ctx_reg(gp_regs, CTX_GPREG_X4, 0);
+		write_ctx_reg(gp_regs, CTX_GPREG_X5, TEGRA186_CORE_WAKE_MASK);
+		write_ctx_reg(gp_regs, CTX_GPREG_X6, 1);
+		(void)mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO, 0, 0, 0);
+
 		/* Prepare for cpu powerdn */
 		(void)mce_command_handler(MCE_CMD_ENTER_CSTATE,
 			TEGRA_ARI_CORE_C7, wake_time[cpu], 0);
 
 	} else if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
 
-		/* loop until SC7 is allowed */
-		do {
-			val = mce_command_handler(MCE_CMD_IS_SC7_ALLOWED,
-					TEGRA_ARI_CORE_C7,
-					MCE_CORE_SLEEP_TIME_INFINITE,
-					0);
-		} while (val == 0);
-
 		/* save SE registers */
 		se_regs[0] = mmio_read_32(TEGRA_SE0_BASE +
 				SE_MUTEX_WATCHDOG_NS_LIMIT);
@@ -147,8 +162,12 @@
 		val = mmio_read_32(TEGRA_MISC_BASE + MISCREG_PFCFG);
 		mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV6, val);
 
-		/* save SMMU context */
-		tegra_smmu_save_context();
+		/* save SMMU context to TZDRAM */
+		smmu_ctx_base = params_from_bl2->tzdram_base +
+			((uintptr_t)&__tegra186_cpu_reset_handler_data -
+			 (uintptr_t)tegra186_cpu_reset_handler) +
+			TEGRA186_SMMU_CTX_OFFSET;
+		tegra_smmu_save_context((uintptr_t)smmu_ctx_base);
 
 		/* Prepare for system suspend */
 		write_ctx_reg(gp_regs, CTX_GPREG_X4, 1);
@@ -157,7 +176,15 @@
 		(void)mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO,
 			TEGRA_ARI_CLUSTER_CC7, 0, TEGRA_ARI_SYSTEM_SC7);
 
+		/* Loop until system suspend is allowed */
+		do {
+			val = mce_command_handler(MCE_CMD_IS_SC7_ALLOWED,
+					TEGRA_ARI_CORE_C7,
+					MCE_CORE_SLEEP_TIME_INFINITE,
+					0);
+		} while (val == 0);
+
-		/* Enter system suspend state */
+		/* Instruct the MCE to enter system suspend state */
 		(void)mce_command_handler(MCE_CMD_ENTER_CSTATE,
 			TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0);
 
@@ -169,6 +196,31 @@
 	return PSCI_E_SUCCESS;
 }
 
+int tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
+{
+	const plat_local_state_t *pwr_domain_state =
+		target_state->pwr_domain_state;
+	plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
+	unsigned int stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
+		TEGRA186_STATE_ID_MASK;
+	uint32_t val;
+
+	if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
+		/*
+		 * The TZRAM loses power when we enter system suspend. To
+		 * allow graceful exit from system suspend, we need to copy
+		 * BL3-1 over to TZDRAM.
+		 */
+		val = params_from_bl2->tzdram_base +
+			((uintptr_t)&__tegra186_cpu_reset_handler_end -
+			 (uintptr_t)tegra186_cpu_reset_handler);
+		memcpy16((void *)(uintptr_t)val, (void *)(uintptr_t)BL31_BASE,
+			 (uintptr_t)&__BL31_END__ - (uintptr_t)BL31_BASE);
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
 int tegra_soc_pwr_domain_on(u_register_t mpidr)
 {
 	int target_cpu = mpidr & MPIDR_CPU_MASK;
@@ -190,13 +242,33 @@
 
 int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
 {
-	int state_id = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL];
+	int stateid_afflvl2 = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL];
+	int stateid_afflvl0 = target_state->pwr_domain_state[MPIDR_AFFLVL0];
+	cpu_context_t *ctx = cm_get_context(NON_SECURE);
+	gp_regs_t *gp_regs = get_gpregs_ctx(ctx);
 
 	/*
+	 * Reset power state info for CPUs when onlining, we set
+	 * deepest power when offlining a core but that may not be
+	 * requested by non-secure sw which controls idle states. It
+	 * will re-init this info from non-secure software when the
+	 * core come online.
+	 */
+	if (stateid_afflvl0 == PLAT_MAX_OFF_STATE) {
+
+		write_ctx_reg(gp_regs, CTX_GPREG_X4, 0);
+		write_ctx_reg(gp_regs, CTX_GPREG_X5, 0);
+		write_ctx_reg(gp_regs, CTX_GPREG_X6, 1);
+		mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO,
+			TEGRA_ARI_CLUSTER_CC1, 0, 0);
+	}
+
+	/*
 	 * Check if we are exiting from deep sleep and restore SE
 	 * context if we are.
 	 */
-	if (state_id == PSTATE_ID_SOC_POWERDN) {
+	if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
+
 		mmio_write_32(TEGRA_SE0_BASE + SE_MUTEX_WATCHDOG_NS_LIMIT,
 			se_regs[0]);
 		mmio_write_32(TEGRA_RNG1_BASE + RNG_MUTEX_WATCHDOG_NS_LIMIT,
@@ -206,6 +278,17 @@
 
 		/* Init SMMU */
 		tegra_smmu_init();
+
+		/*
+		 * Reset power state info for the last core doing SC7 entry and exit,
+		 * we set deepest power state as CC7 and SC7 for SC7 entry which
+		 * may not be requested by non-secure SW which controls idle states.
+		 */
+		write_ctx_reg(gp_regs, CTX_GPREG_X4, 0);
+		write_ctx_reg(gp_regs, CTX_GPREG_X5, 0);
+		write_ctx_reg(gp_regs, CTX_GPREG_X6, 1);
+		(void)mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO,
+			TEGRA_ARI_CLUSTER_CC7, 0, TEGRA_ARI_SYSTEM_SC1);
 	}
 
 	return PSCI_E_SUCCESS;
@@ -225,7 +308,7 @@
 	write_ctx_reg(gp_regs, CTX_GPREG_X5, 0);
 	write_ctx_reg(gp_regs, CTX_GPREG_X6, 1);
 	mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO, TEGRA_ARI_CLUSTER_CC7,
-		0, TEGRA_ARI_SYSTEM_SC7);
+		0, 0);
 
 	/* Disable Denver's DCO operations */
 	if (impl == DENVER_IMPL)
@@ -249,6 +332,13 @@
 
 	} else if (tegra186_system_powerdn_state == TEGRA_ARI_SYSTEM_SC8) {
 
+		/* Prepare for quasi power down */
+		write_ctx_reg(gp_regs, CTX_GPREG_X4, 1);
+		write_ctx_reg(gp_regs, CTX_GPREG_X5, 0);
+		write_ctx_reg(gp_regs, CTX_GPREG_X6, 1);
+		(void)mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO,
+			TEGRA_ARI_CLUSTER_CC7, 0, TEGRA_ARI_SYSTEM_SC8);
+
 		/* loop until other CPUs power down */
 		do {
 			val = mce_command_handler(MCE_CMD_IS_SC7_ALLOWED,
@@ -257,13 +347,6 @@
 					0);
 		} while (val == 0);
 
-		/* Prepare for quasi power down */
-		write_ctx_reg(gp_regs, CTX_GPREG_X4, 1);
-		write_ctx_reg(gp_regs, CTX_GPREG_X5, 0);
-		write_ctx_reg(gp_regs, CTX_GPREG_X6, 1);
-		(void)mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO,
-			TEGRA_ARI_CLUSTER_CC7, 0, TEGRA_ARI_SYSTEM_SC8);
-
 		/* Enter quasi power down state */
 		(void)mce_command_handler(MCE_CMD_ENTER_CSTATE,
 			TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0);
diff --git a/plat/nvidia/tegra/soc/t186/plat_secondary.c b/plat/nvidia/tegra/soc/t186/plat_secondary.c
index df80289..406c1e0 100644
--- a/plat/nvidia/tegra/soc/t186/plat_secondary.c
+++ b/plat/nvidia/tegra/soc/t186/plat_secondary.c
@@ -28,10 +28,13 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <arch_helpers.h>
 #include <debug.h>
 #include <mce.h>
 #include <mmio.h>
+#include <string.h>
 #include <tegra_def.h>
+#include <tegra_private.h>
 
 #define MISCREG_CPU_RESET_VECTOR	0x2000
 #define MISCREG_AA64_RST_LOW		0x2004
@@ -42,7 +45,8 @@
 
 #define CPU_RESET_MODE_AA64		1
 
-extern void tegra_secure_entrypoint(void);
+extern uint64_t tegra_bl31_phys_base;
+extern uint64_t __tegra186_cpu_reset_handler_end;
 
 /*******************************************************************************
  * Setup secondary CPU vectors
@@ -50,12 +54,31 @@
 void plat_secondary_setup(void)
 {
 	uint32_t addr_low, addr_high;
-	uint64_t reset_addr = (uint64_t)tegra_secure_entrypoint;
+	plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
+	uint64_t cpu_reset_handler_base;
 
 	INFO("Setting up secondary CPU boot\n");
 
-	addr_low = (uint32_t)reset_addr | CPU_RESET_MODE_AA64;
-	addr_high = (uint32_t)((reset_addr >> 32) & 0x7ff);
+	if ((tegra_bl31_phys_base >= TEGRA_TZRAM_BASE) &&
+	    (tegra_bl31_phys_base <= (TEGRA_TZRAM_BASE + TEGRA_TZRAM_SIZE))) {
+
+		/*
+		 * The BL31 code resides in the TZSRAM which loses state
+		 * when we enter System Suspend. Copy the wakeup trampoline
+		 * code to TZDRAM to help us exit from System Suspend.
+		 */
+		cpu_reset_handler_base = params_from_bl2->tzdram_base;
+		memcpy16((void *)((uintptr_t)cpu_reset_handler_base),
+			 (void *)(uintptr_t)tegra186_cpu_reset_handler,
+			 (uintptr_t)&__tegra186_cpu_reset_handler_end -
+			 (uintptr_t)tegra186_cpu_reset_handler);
+
+	} else {
+		cpu_reset_handler_base = (uintptr_t)tegra_secure_entrypoint;
+	}
+
+	addr_low = (uint32_t)cpu_reset_handler_base | CPU_RESET_MODE_AA64;
+	addr_high = (uint32_t)((cpu_reset_handler_base >> 32) & 0x7ff);
 
 	/* write lower 32 bits first, then the upper 11 bits */
 	mmio_write_32(TEGRA_MISC_BASE + MISCREG_AA64_RST_LOW, addr_low);
diff --git a/plat/nvidia/tegra/soc/t186/plat_setup.c b/plat/nvidia/tegra/soc/t186/plat_setup.c
index d6b8bc3..49f4589 100644
--- a/plat/nvidia/tegra/soc/t186/plat_setup.c
+++ b/plat/nvidia/tegra/soc/t186/plat_setup.c
@@ -37,6 +37,7 @@
 #include <debug.h>
 #include <denver.h>
 #include <interrupt_mgmt.h>
+#include <mce.h>
 #include <platform.h>
 #include <tegra_def.h>
 #include <tegra_private.h>
@@ -65,6 +66,8 @@
 static const mmap_region_t tegra_mmap[] = {
 	MAP_REGION_FLAT(TEGRA_MISC_BASE, 0x10000, /* 64KB */
 			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(TEGRA_TSA_BASE, 0x20000, /* 128KB */
+			MT_DEVICE | MT_RW | MT_SECURE),
 	MAP_REGION_FLAT(TEGRA_MC_STREAMID_BASE, 0x10000, /* 64KB */
 			MT_DEVICE | MT_RW | MT_SECURE),
 	MAP_REGION_FLAT(TEGRA_MC_BASE, 0x10000, /* 64KB */
@@ -168,3 +171,11 @@
 	if (sizeof(tegra186_sec_irqs) > 0)
 		tegra_fiq_handler_setup();
 }
+
+/*******************************************************************************
+ * Handler for early platform setup
+ ******************************************************************************/
+void plat_early_platform_setup(void)
+{
+	mce_verify_firmware_version();
+}
diff --git a/plat/nvidia/tegra/soc/t186/plat_sip_calls.c b/plat/nvidia/tegra/soc/t186/plat_sip_calls.c
index fabab01..c7a2c41 100644
--- a/plat/nvidia/tegra/soc/t186/plat_sip_calls.c
+++ b/plat/nvidia/tegra/soc/t186/plat_sip_calls.c
@@ -64,6 +64,7 @@
 #define TEGRA_SIP_MCE_CMD_ENUM_WRITE_MCA		0x82FFFF0D
 #define TEGRA_SIP_MCE_CMD_ROC_FLUSH_CACHE		0x82FFFF0E
 #define TEGRA_SIP_MCE_CMD_ROC_CLEAN_CACHE		0x82FFFF0F
+#define TEGRA_SIP_MCE_CMD_ENABLE_LATIC			0x82FFFF10
 
 /*******************************************************************************
  * This function is responsible for handling all T186 SiP calls
@@ -100,6 +101,7 @@
 	case TEGRA_SIP_MCE_CMD_ENUM_WRITE_MCA:
 	case TEGRA_SIP_MCE_CMD_ROC_FLUSH_CACHE:
 	case TEGRA_SIP_MCE_CMD_ROC_CLEAN_CACHE:
+	case TEGRA_SIP_MCE_CMD_ENABLE_LATIC:
 
 		/* clean up the high bits */
 		smc_fid &= MCE_CMD_MASK;
diff --git a/plat/nvidia/tegra/soc/t186/plat_trampoline.S b/plat/nvidia/tegra/soc/t186/plat_trampoline.S
new file mode 100644
index 0000000..7619ed0
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/plat_trampoline.S
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2016, 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:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common_def.h>
+#include <memctrl_v2.h>
+#include <tegra_def.h>
+
+#define TEGRA186_SMMU_CTX_SIZE		0x420
+
+	.align 4
+	.globl	tegra186_cpu_reset_handler
+
+/* CPU reset handler routine */
+func tegra186_cpu_reset_handler
+	/*
+	 * The Memory Controller loses state during System Suspend. We
+	 * use this information to decide if the reset handler is running
+	 * after a System Suspend. Resume from system suspend requires
+	 * restoring the entire state from TZDRAM to TZRAM.
+	 */
+	mov	x1, #TEGRA_MC_BASE
+	ldr	w0, [x1, #MC_SECURITY_CFG3_0]
+	lsl	x0, x0, #32
+	ldr	w0, [x1, #MC_SECURITY_CFG0_0]
+	adr	x1, tegra186_cpu_reset_handler
+	cmp	x0, x1
+	beq	boot_cpu
+
+	/* resume from system suspend */
+	mov	x0, #BL31_BASE
+	adr	x1, __tegra186_cpu_reset_handler_end
+	adr	x2, __tegra186_cpu_reset_handler_data
+	ldr	x2, [x2, #8]
+
+	/* memcpy16 */
+m_loop16:
+	cmp	x2, #16
+	b.lt	m_loop1
+	ldp	x3, x4, [x1], #16
+	stp	x3, x4, [x0], #16
+	sub	x2, x2, #16
+	b	m_loop16
+	/* copy byte per byte */
+m_loop1:
+	cbz	x2, boot_cpu
+	ldrb	w3, [x1], #1
+	strb	w3, [x0], #1
+	subs	x2, x2, #1
+	b.ne	m_loop1
+
+boot_cpu:
+	adr	x0, __tegra186_cpu_reset_handler_data
+	ldr	x0, [x0]
+	br	x0
+endfunc tegra186_cpu_reset_handler
+
+	/*
+	 * Tegra186 reset data (offset 0x0 - 0x430)
+	 *
+	 * 0x000: secure world's entrypoint
+	 * 0x008: BL31 size (RO + RW)
+	 * 0x00C: SMMU context start
+	 * 0x42C: SMMU context end
+	 */
+
+	.align 4
+	.type	__tegra186_cpu_reset_handler_data, %object
+	.globl	__tegra186_cpu_reset_handler_data
+__tegra186_cpu_reset_handler_data:
+	.quad	tegra_secure_entrypoint
+	.quad	__BL31_END__ - BL31_BASE
+	.rept	TEGRA186_SMMU_CTX_SIZE
+	.quad	0
+	.endr
+	.size	__tegra186_cpu_reset_handler_data, \
+		. - __tegra186_cpu_reset_handler_data
+
+	.align 4
+	.globl	__tegra186_cpu_reset_handler_end
+__tegra186_cpu_reset_handler_end:
diff --git a/plat/nvidia/tegra/soc/t186/platform_t186.mk b/plat/nvidia/tegra/soc/t186/platform_t186.mk
index adc4a9e..4a4d9bb 100644
--- a/plat/nvidia/tegra/soc/t186/platform_t186.mk
+++ b/plat/nvidia/tegra/soc/t186/platform_t186.mk
@@ -29,8 +29,11 @@
 #
 
 # platform configs
-ENABLE_NS_L2_CPUECTRL_RW_ACCESS		:= 1
-$(eval $(call add_define,ENABLE_NS_L2_CPUECTRL_RW_ACCESS))
+ENABLE_ROC_FOR_ORDERING_CLIENT_REQUESTS	:= 1
+$(eval $(call add_define,ENABLE_ROC_FOR_ORDERING_CLIENT_REQUESTS))
+
+ENABLE_CHIP_VERIFICATION_HARNESS	:= 0
+$(eval $(call add_define,ENABLE_CHIP_VERIFICATION_HARNESS))
 
 # platform settings
 TZDRAM_BASE				:= 0x30000000
@@ -42,10 +45,10 @@
 PLATFORM_MAX_CPUS_PER_CLUSTER		:= 4
 $(eval $(call add_define,PLATFORM_MAX_CPUS_PER_CLUSTER))
 
-MAX_XLAT_TABLES				:= 15
+MAX_XLAT_TABLES				:= 20
 $(eval $(call add_define,MAX_XLAT_TABLES))
 
-MAX_MMAP_REGIONS			:= 15
+MAX_MMAP_REGIONS			:= 20
 $(eval $(call add_define,MAX_MMAP_REGIONS))
 
 # platform files
@@ -62,4 +65,5 @@
 				${SOC_DIR}/plat_psci_handlers.c		\
 				${SOC_DIR}/plat_setup.c			\
 				${SOC_DIR}/plat_secondary.c		\
-				${SOC_DIR}/plat_sip_calls.c
+				${SOC_DIR}/plat_sip_calls.c		\
+				${SOC_DIR}/plat_trampoline.S