arm64: versal: Add new Kconfig SYS_MEM_RSVD_FOR_MMU

This patch adds new config option which is used for
reserving a specific memory for MMU Table and in this
case we are using TCM for that purpose.

Signed-off-by: Siva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
diff --git a/arch/arm/mach-versal/Kconfig b/arch/arm/mach-versal/Kconfig
index 9cee97b..f291800 100644
--- a/arch/arm/mach-versal/Kconfig
+++ b/arch/arm/mach-versal/Kconfig
@@ -41,4 +41,11 @@
 	default 0x1000
 	depends on OF_BOARD
 
+config SYS_MEM_RSVD_FOR_MMU
+	bool "Reserve memory for MMU Table"
+	help
+	  If defined this option is used to setup different space for
+	  MMU table than the one which will be allocated during
+	  relocation.
+
 endif
diff --git a/arch/arm/mach-versal/Makefile b/arch/arm/mach-versal/Makefile
index c230239..ca12e29 100644
--- a/arch/arm/mach-versal/Makefile
+++ b/arch/arm/mach-versal/Makefile
@@ -6,3 +6,4 @@
 
 obj-y	+= clk.o
 obj-y	+= cpu.o
+obj-$(CONFIG_SYS_MEM_RSVD_FOR_MMU)	+= mp.o
diff --git a/arch/arm/mach-versal/cpu.c b/arch/arm/mach-versal/cpu.c
index 1fd3c24..70c1908 100644
--- a/arch/arm/mach-versal/cpu.c
+++ b/arch/arm/mach-versal/cpu.c
@@ -7,6 +7,10 @@
 #include <common.h>
 #include <asm/armv8/mmu.h>
 #include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/sys_proto.h>
+
+DECLARE_GLOBAL_DATA_PTR;
 
 static struct mm_region versal_mem_map[] = {
 	{
@@ -67,6 +71,17 @@
 {
 	return 0x14000;
 }
+
+#if defined(CONFIG_SYS_MEM_RSVD_FOR_MMU)
+int reserve_mmu(void)
+{
+	tcm_init(TCM_LOCK);
+	gd->arch.tlb_size = PGTABLE_SIZE;
+	gd->arch.tlb_addr = VERSAL_TCM_BASE_ADDR;
+
+	return 0;
+}
+#endif
 
 #if defined(CONFIG_OF_BOARD)
 void *board_fdt_blob_setup(void)
diff --git a/arch/arm/mach-versal/include/mach/hardware.h b/arch/arm/mach-versal/include/mach/hardware.h
index aad7426..23fbc3d 100644
--- a/arch/arm/mach-versal/include/mach/hardware.h
+++ b/arch/arm/mach-versal/include/mach/hardware.h
@@ -11,11 +11,15 @@
 #define IOU_SWITCH_CTRL_DIVISOR0_SHIFT	8
 
 struct crlapb_regs {
-	u32 reserved0[69];
+	u32 reserved0[67];
+	u32 cpu_r5_ctrl;
+	u32 reserved;
 	u32 iou_switch_ctrl; /* 0x114 */
 	u32 reserved1[13];
 	u32 timestamp_ref_ctrl; /* 0x14c */
-	u32 reserved2[126];
+	u32 reserved3[108];
+	u32 rst_cpu_r5;
+	u32 reserved2[17];
 	u32 rst_timestamp; /* 0x348 */
 };
 
@@ -32,3 +36,18 @@
 };
 
 #define iou_scntr_secure ((struct iou_scntrs_regs *)VERSAL_IOU_SCNTR_SECURE)
+
+#define VERSAL_TCM_BASE_ADDR	0xFFE00000
+#define VERSAL_TCM_SIZE		0x40000
+
+#define VERSAL_RPU_BASEADDR	0xFF9A0000
+
+struct rpu_regs {
+	u32 rpu_glbl_ctrl;
+	u32 reserved0[63];
+	u32 rpu0_cfg; /* 0x100 */
+	u32 reserved1[63];
+	u32 rpu1_cfg; /* 0x200 */
+};
+
+#define rpu_base ((struct rpu_regs *)VERSAL_RPU_BASEADDR)
diff --git a/arch/arm/mach-versal/include/mach/sys_proto.h b/arch/arm/mach-versal/include/mach/sys_proto.h
index 677facb..1dc7bf6 100644
--- a/arch/arm/mach-versal/include/mach/sys_proto.h
+++ b/arch/arm/mach-versal/include/mach/sys_proto.h
@@ -3,4 +3,9 @@
  * Copyright 2016 - 2018 Xilinx, Inc.
  */
 
-/* Empty file - for compilation */
+enum {
+	TCM_LOCK,
+	TCM_SPLIT,
+};
+
+void tcm_init(u8 mode);
diff --git a/arch/arm/mach-versal/mp.c b/arch/arm/mach-versal/mp.c
new file mode 100644
index 0000000..4b434b0
--- /dev/null
+++ b/arch/arm/mach-versal/mp.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2019 Xilinx, Inc.
+ * Siva Durga Prasad <siva.durga.paladugu@xilinx.com>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/sys_proto.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define HALT		0
+#define RELEASE		1
+
+#define VERSAL_RPU_CFG_CPU_HALT_MASK		0x01
+#define VERSAL_RPU_GLBL_CTRL_SPLIT_LOCK_MASK	0x08
+#define VERSAL_RPU_GLBL_CTRL_TCM_COMB_MASK	0x40
+#define VERSAL_RPU_GLBL_CTRL_SLCLAMP_MASK	0x10
+
+#define VERSAL_CRLAPB_RST_LPD_AMBA_RST_MASK	0x04
+#define VERSAL_CRLAPB_RST_LPD_R50_RST_MASK	0x01
+#define VERSAL_CRLAPB_RST_LPD_R51_RST_MASK	0x02
+#define VERSAL_CRL_RST_CPU_R5_RESET_PGE_MASK	0x10
+#define VERSAL_CRLAPB_CPU_R5_CTRL_CLKACT_MASK	0x1000000
+
+void set_r5_halt_mode(u8 halt, u8 mode)
+{
+	u32 tmp;
+
+	tmp = readl(&rpu_base->rpu0_cfg);
+	if (halt == HALT)
+		tmp &= ~VERSAL_RPU_CFG_CPU_HALT_MASK;
+	else
+		tmp |= VERSAL_RPU_CFG_CPU_HALT_MASK;
+	writel(tmp, &rpu_base->rpu0_cfg);
+
+	if (mode == TCM_LOCK) {
+		tmp = readl(&rpu_base->rpu1_cfg);
+		if (halt == HALT)
+			tmp &= ~VERSAL_RPU_CFG_CPU_HALT_MASK;
+		else
+			tmp |= VERSAL_RPU_CFG_CPU_HALT_MASK;
+		writel(tmp, &rpu_base->rpu1_cfg);
+	}
+}
+
+void set_r5_tcm_mode(u8 mode)
+{
+	u32 tmp;
+
+	tmp = readl(&rpu_base->rpu_glbl_ctrl);
+	if (mode == TCM_LOCK) {
+		tmp &= ~VERSAL_RPU_GLBL_CTRL_SPLIT_LOCK_MASK;
+		tmp |= VERSAL_RPU_GLBL_CTRL_TCM_COMB_MASK |
+		       VERSAL_RPU_GLBL_CTRL_SLCLAMP_MASK;
+	} else {
+		tmp |= VERSAL_RPU_GLBL_CTRL_SPLIT_LOCK_MASK;
+		tmp &= ~(VERSAL_RPU_GLBL_CTRL_TCM_COMB_MASK |
+		       VERSAL_RPU_GLBL_CTRL_SLCLAMP_MASK);
+	}
+
+	writel(tmp, &rpu_base->rpu_glbl_ctrl);
+}
+
+void release_r5_reset(u8 mode)
+{
+	u32 tmp;
+
+	tmp = readl(&crlapb_base->rst_cpu_r5);
+	tmp &= ~(VERSAL_CRLAPB_RST_LPD_AMBA_RST_MASK |
+	       VERSAL_CRLAPB_RST_LPD_R50_RST_MASK |
+	       VERSAL_CRL_RST_CPU_R5_RESET_PGE_MASK);
+
+	if (mode == TCM_LOCK)
+		tmp &= ~VERSAL_CRLAPB_RST_LPD_R51_RST_MASK;
+
+	writel(tmp, &crlapb_base->rst_cpu_r5);
+}
+
+void enable_clock_r5(void)
+{
+	u32 tmp;
+
+	tmp = readl(&crlapb_base->cpu_r5_ctrl);
+	tmp |= VERSAL_CRLAPB_CPU_R5_CTRL_CLKACT_MASK;
+	writel(tmp, &crlapb_base->cpu_r5_ctrl);
+}
+
+void initialize_tcm(bool mode)
+{
+	if (!mode) {
+		set_r5_tcm_mode(TCM_LOCK);
+		set_r5_halt_mode(HALT, TCM_LOCK);
+		enable_clock_r5();
+		release_r5_reset(TCM_LOCK);
+	} else {
+		set_r5_tcm_mode(TCM_SPLIT);
+		set_r5_halt_mode(HALT, TCM_SPLIT);
+		enable_clock_r5();
+		release_r5_reset(TCM_SPLIT);
+	}
+}
+
+void tcm_init(u8 mode)
+{
+	puts("WARNING: Initializing TCM overwrites TCM content\n");
+	initialize_tcm(mode);
+	memset((void *)VERSAL_TCM_BASE_ADDR, 0, VERSAL_TCM_SIZE);
+}