Tegra: memctrl_v2: zero out NS Video memory carveout region

The video memory carveout has to be re-sized depending on the Video
content. This requires the NS world to send us new base/size values.
Before setting up the new region, we must zero out the previous memory
region, so that the video frames are not leaked to the outside world.

This patch adds the logic to zero out the previous memory carveout
region.

Change-Id: I471167ef7747154440df5c1a5e015fbeb69d9043
Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
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/include/t186/tegra_def.h b/plat/nvidia/tegra/include/t186/tegra_def.h
index 6693cb3..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