Tegra: smmu: add smmu_verify function

The SMMU configuration can get corrupted or updated by
external clients during boot without our knowledge.

This patch introduces a "verify" function for the SMMU
driver, to check that the boot configuration settings are
intact.  Usually, this function should be called at the
end of the boot cycle.

This function only calls panic() on silicon platforms.

Change-Id: I2ab45a7f228781e71c73ba1f4ffc49353effe146
Signed-off-by: George Bauernschmidt <georgeb@nvidia.com>
diff --git a/plat/nvidia/tegra/common/tegra_bl31_setup.c b/plat/nvidia/tegra/common/tegra_bl31_setup.c
index a787e33..d5297ee 100644
--- a/plat/nvidia/tegra/common/tegra_bl31_setup.c
+++ b/plat/nvidia/tegra/common/tegra_bl31_setup.c
@@ -28,6 +28,7 @@
 
 #include <memctrl.h>
 #include <profiler.h>
+#include <smmu.h>
 #include <tegra_def.h>
 #include <tegra_platform.h>
 #include <tegra_private.h>
@@ -272,6 +273,13 @@
 	 */
 	tegra_memctrl_disable_ahb_redirection();
 
+#if defined(TEGRA_SMMU0_BASE)
+	/*
+	 * Verify the integrity of the previously configured SMMU(s) settings
+	 */
+	tegra_smmu_verify();
+#endif
+
 	/*
 	 * Add final timestamp before exiting BL31.
 	 */
diff --git a/plat/nvidia/tegra/drivers/smmu/smmu.c b/plat/nvidia/tegra/drivers/smmu/smmu.c
index a4a4354..4189b00 100644
--- a/plat/nvidia/tegra/drivers/smmu/smmu.c
+++ b/plat/nvidia/tegra/drivers/smmu/smmu.c
@@ -14,6 +14,7 @@
 #include <common/debug.h>
 
 #include <smmu.h>
+#include <tegra_platform.h>
 #include <tegra_private.h>
 
 extern void memcpy16(void *dest, const void *src, unsigned int length);
@@ -21,15 +22,17 @@
 #define SMMU_NUM_CONTEXTS		64U
 #define SMMU_CONTEXT_BANK_MAX_IDX	64U
 
+#define MISMATCH_DETECTED		0x55AA55AAU
+
 /*
  * Init SMMU during boot or "System Suspend" exit
  */
 void tegra_smmu_init(void)
 {
 	uint32_t val, cb_idx, smmu_id, ctx_base;
-	uint32_t smmu_counter = plat_get_num_smmu_devices();
+	uint32_t num_smmu_devices = plat_get_num_smmu_devices();
 
-	for (smmu_id = 0U; smmu_id < smmu_counter; smmu_id++) {
+	for (smmu_id = 0U; smmu_id < num_smmu_devices; smmu_id++) {
 		/* Program the SMMU pagesize and reset CACHE_LOCK bit */
 		val = tegra_smmu_read_32(smmu_id, SMMU_GSR0_SECURE_ACR);
 		val |= SMMU_GSR0_PGSIZE_64K;
@@ -44,7 +47,7 @@
 		/* disable TCU prefetch for all contexts */
 		ctx_base = (SMMU_GSR0_PGSIZE_64K * SMMU_NUM_CONTEXTS)
 				+ SMMU_CBn_ACTLR;
-		for (cb_idx = 0; cb_idx < SMMU_CONTEXT_BANK_MAX_IDX; cb_idx++) {
+		for (cb_idx = 0U; cb_idx < SMMU_CONTEXT_BANK_MAX_IDX; cb_idx++) {
 			val = tegra_smmu_read_32(smmu_id,
 				ctx_base + (SMMU_GSR0_PGSIZE_64K * cb_idx));
 			val &= (uint32_t)~SMMU_CBn_ACTLR_CPRE_BIT;
@@ -63,3 +66,56 @@
 		tegra_smmu_write_32(smmu_id, SMMU_GSR0_SECURE_ACR, val);
 	}
 }
+
+/*
+ * Verify SMMU settings have not been altered during boot
+ */
+void tegra_smmu_verify(void)
+{
+	uint32_t cb_idx, ctx_base, smmu_id, val;
+	uint32_t num_smmu_devices = plat_get_num_smmu_devices();
+	uint32_t mismatch = 0U;
+
+	for (smmu_id = 0U; smmu_id < num_smmu_devices; smmu_id++) {
+		/* check PGSIZE_64K bit inr S Aux. Config. Register */
+		val = tegra_smmu_read_32(smmu_id, SMMU_GSR0_SECURE_ACR);
+		if (0U == (val & SMMU_GSR0_PGSIZE_64K)) {
+			ERROR("%s: PGSIZE_64K Mismatch - smmu_id=%d, GSR0_SECURE_ACR=%x\n",
+				__func__, smmu_id, val);
+			mismatch = MISMATCH_DETECTED;
+		}
+
+		/* check CACHE LOCK bit in S Aux. Config. Register */
+		if (0U == (val & SMMU_ACR_CACHE_LOCK_ENABLE_BIT)) {
+			ERROR("%s: CACHE_LOCK Mismatch - smmu_id=%d, GSR0_SECURE_ACR=%x\n",
+				__func__, smmu_id, val);
+			mismatch = MISMATCH_DETECTED;
+		}
+
+		/* check CACHE LOCK bit in NS Aux. Config. Register */
+		val = tegra_smmu_read_32(smmu_id, SMMU_GNSR_ACR);
+		if (0U == (val & SMMU_ACR_CACHE_LOCK_ENABLE_BIT)) {
+			ERROR("%s: Mismatch - smmu_id=%d, GNSR_ACR=%x\n",
+				__func__, smmu_id, val);
+			mismatch = MISMATCH_DETECTED;
+		}
+
+		/* verify TCU prefetch for all contexts is disabled */
+		ctx_base = (SMMU_GSR0_PGSIZE_64K * SMMU_NUM_CONTEXTS) +
+			SMMU_CBn_ACTLR;
+		for (cb_idx = 0U; cb_idx < SMMU_CONTEXT_BANK_MAX_IDX; cb_idx++) {
+			val = tegra_smmu_read_32(smmu_id,
+				ctx_base + (SMMU_GSR0_PGSIZE_64K * cb_idx));
+			if (0U != (val & SMMU_CBn_ACTLR_CPRE_BIT)) {
+				ERROR("%s: Mismatch - smmu_id=%d, cb_idx=%d, GSR0_PGSIZE_64K=%x\n",
+					__func__, smmu_id, cb_idx, val);
+				mismatch = MISMATCH_DETECTED;
+			}
+		}
+	}
+
+	/* Treat configuration mismatch as fatal */
+	if ((mismatch == MISMATCH_DETECTED) && tegra_platform_is_silicon()) {
+		panic();
+	}
+}
diff --git a/plat/nvidia/tegra/include/drivers/memctrl_v2.h b/plat/nvidia/tegra/include/drivers/memctrl_v2.h
index 509fe32..e15762b 100644
--- a/plat/nvidia/tegra/include/drivers/memctrl_v2.h
+++ b/plat/nvidia/tegra/include/drivers/memctrl_v2.h
@@ -144,6 +144,7 @@
 	mmio_write_32(TEGRA_MC_BASE + off, val);
 }
 
+#if defined(TEGRA_MC_STREAMID_BASE)
 static inline uint32_t tegra_mc_streamid_read_32(uint32_t off)
 {
 	return mmio_read_32(TEGRA_MC_STREAMID_BASE + off);
@@ -153,6 +154,7 @@
 {
 	mmio_write_32(TEGRA_MC_STREAMID_BASE + off, val);
 }
+#endif
 
 #define mc_set_pcfifo_unordered_boot_so_mss(id, client) \
 	((uint32_t)~MC_PCFIFO_CLIENT_CONFIG##id##_PCFIFO_##client##_MASK | \
diff --git a/plat/nvidia/tegra/include/drivers/smmu.h b/plat/nvidia/tegra/include/drivers/smmu.h
index 601864f..1de9af6 100644
--- a/plat/nvidia/tegra/include/drivers/smmu.h
+++ b/plat/nvidia/tegra/include/drivers/smmu.h
@@ -86,6 +86,7 @@
 }
 
 void tegra_smmu_init(void);
+void tegra_smmu_verify(void);
 uint32_t plat_get_num_smmu_devices(void);
 
 #endif /* SMMU_H */