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/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();
+	}
+}