Tegra: Support for Tegra's T132 platforms

This patch implements support for T132 (Denver CPU) based Tegra
platforms.

The following features have been added:

* SiP calls to switch T132 CPU's AARCH mode
* Complete PSCI support, including 'System Suspend'
* Platform specific MMIO settings
* Locking of CPU vector registers

Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
diff --git a/plat/nvidia/tegra/common/tegra_sip_calls.c b/plat/nvidia/tegra/common/tegra_sip_calls.c
index 1d79c80..de36a3c 100644
--- a/plat/nvidia/tegra/common/tegra_sip_calls.c
+++ b/plat/nvidia/tegra/common/tegra_sip_calls.c
@@ -28,6 +28,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <arch.h>
 #include <arch_helpers.h>
 #include <assert.h>
 #include <bl_common.h>
@@ -38,7 +39,21 @@
 #include <runtime_svc.h>
 #include <tegra_private.h>
 
+#define NS_SWITCH_AARCH32	1
+#define SCR_RW_BITPOS		__builtin_ctz(SCR_RW_BIT)
+
+/*******************************************************************************
+ * Tegra SiP SMCs
+ ******************************************************************************/
 #define TEGRA_SIP_NEW_VIDEOMEM_REGION		0x82000003
+#define TEGRA_SIP_AARCH_SWITCH			0x82000004
+
+/*******************************************************************************
+ * SPSR settings for AARCH32/AARCH64 modes
+ ******************************************************************************/
+#define SPSR32		SPSR_MODE32(MODE32_svc, SPSR_T_ARM, SPSR_E_LITTLE, \
+			DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_ABT_BIT)
+#define SPSR64		SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS)
 
 /*******************************************************************************
  * This function is responsible for handling all SiP calls from the NS world
@@ -64,6 +79,10 @@
 
 	case TEGRA_SIP_NEW_VIDEOMEM_REGION:
 
+		/* clean up the high bits */
+		x1 = (uint32_t)x1;
+		x2 = (uint32_t)x2;
+
 		/*
 		 * Check if Video Memory overlaps TZDRAM (contains bl31/bl32)
 		 * or falls outside of the valid DRAM range
@@ -84,6 +103,30 @@
 		tegra_memctrl_videomem_setup(x1, x2);
 
 		SMC_RET1(handle, 0);
+		break;
+
+	case TEGRA_SIP_AARCH_SWITCH:
+
+		/* clean up the high bits */
+		x1 = (uint32_t)x1;
+		x2 = (uint32_t)x2;
+
+		if (!x1 || x2 > NS_SWITCH_AARCH32) {
+			ERROR("%s: invalid parameters\n", __func__);
+			SMC_RET1(handle, SMC_UNK);
+		}
+
+		/* x1 = ns entry point */
+		cm_set_elr_spsr_el3(NON_SECURE, x1,
+			(x2 == NS_SWITCH_AARCH32) ? SPSR32 : SPSR64);
+
+		/* switch NS world mode */
+		cm_write_scr_el3_bit(NON_SECURE, SCR_RW_BITPOS, !x2);
+
+		INFO("CPU switched to AARCH%s mode\n",
+			(x2 == NS_SWITCH_AARCH32) ? "32" : "64");
+		SMC_RET1(handle, 0);
+		break;
 
 	default:
 		ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);