mips: vcoreiii: Fix cache coherency issues

This patch fixes an stability issue seen on some vcoreiii targets,
which was root caused to a cache inconsistency situation.

The inconsistency was caused by having kuseg pointing to NOR area but
used as a stack/gd/heap area during initialization, while only
relatively late remapping the RAM area into kuseg position.

The fix is to initialize the DDR right after the TLB setup, and then
remapping it into position before gd/stack/heap usage.

Reported-by: Ramin Seyed-Moussavi <ramin.moussavi@yacoub.de>
Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Reviewed-by: Horatiu Vultur <horatiu.vultur@microchip.com>
Signed-off-by: Lars Povlsen <lars.povlsen@microchip.com>
diff --git a/arch/mips/mach-mscc/cpu.c b/arch/mips/mach-mscc/cpu.c
index ac75d51..3ee5898 100644
--- a/arch/mips/mach-mscc/cpu.c
+++ b/arch/mips/mach-mscc/cpu.c
@@ -7,6 +7,7 @@
 
 #include <asm/io.h>
 #include <asm/types.h>
+#include <asm/mipsregs.h>
 
 #include <mach/tlb.h>
 #include <mach/ddr.h>
@@ -53,7 +54,6 @@
 		   MMU_REGIO_RW);
 #endif
 
-#if  CONFIG_SYS_TEXT_BASE == MSCC_FLASH_TO
 	/*
 	 * If U-Boot is located in NOR then we want to be able to use
 	 * the data cache in order to boot in a decent duration
@@ -71,9 +71,10 @@
 	create_tlb(tlbix++, MSCC_DDR_TO, MSCC_RAM_TLB_SIZE, MMU_REGIO_RW,
 		   MSCC_ATTRIB2);
 
-	/* Enable caches by clearing the bit ERL, which is set on reset */
-	write_c0_status(read_c0_status() & ~BIT(2));
-#endif /* CONFIG_SYS_TEXT_BASE */
+	/* Enable mapping (using TLB) kuseg by clearing the bit ERL,
+	 * which is set on reset.
+	 */
+	write_c0_status(read_c0_status() & ~ST0_ERL);
 }
 
 int mach_cpu_init(void)
diff --git a/arch/mips/mach-mscc/dram.c b/arch/mips/mach-mscc/dram.c
index c43f7a5..72c70c9 100644
--- a/arch/mips/mach-mscc/dram.c
+++ b/arch/mips/mach-mscc/dram.c
@@ -31,7 +31,7 @@
 
 int vcoreiii_ddr_init(void)
 {
-	int res;
+	register int res;
 
 	if (!(readl(BASE_CFG + ICPU_MEMCTRL_STAT)
 	      & ICPU_MEMCTRL_STAT_INIT_DONE)) {
@@ -40,20 +40,19 @@
 		if (hal_vcoreiii_init_dqs() || vcoreiii_train_bytelane())
 			hal_vcoreiii_ddr_failed();
 	}
-#if (CONFIG_SYS_TEXT_BASE != 0x20000000)
+
 	res = dram_check();
 	if (res == 0)
 		hal_vcoreiii_ddr_verified();
 	else
 		hal_vcoreiii_ddr_failed();
 
-	/* Clear boot-mode and read-back to activate/verify */
+	/*  Remap DDR to kuseg: Clear boot-mode */
 	clrbits_le32(BASE_CFG + ICPU_GENERAL_CTRL,
 		     ICPU_GENERAL_CTRL_BOOT_MODE_ENA);
+	/* - and read-back to activate/verify */
 	readl(BASE_CFG + ICPU_GENERAL_CTRL);
-#else
-	res = 0;
-#endif
+
 	return res;
 }
 
@@ -66,9 +65,6 @@
 
 int dram_init(void)
 {
-	while (vcoreiii_ddr_init())
-		;
-
 	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
 	return 0;
 }
diff --git a/arch/mips/mach-mscc/include/mach/ddr.h b/arch/mips/mach-mscc/include/mach/ddr.h
index d1f4287..bf75e52 100644
--- a/arch/mips/mach-mscc/include/mach/ddr.h
+++ b/arch/mips/mach-mscc/include/mach/ddr.h
@@ -435,16 +435,12 @@
 	reset = KSEG0ADDR(_machine_restart);
 	icache_lock((void *)reset, 128);
 	asm volatile ("jr %0"::"r" (reset));
-
-	panic("DDR init failed\n");
 }
 #else				/* JR2 || ServalT */
 static inline void hal_vcoreiii_ddr_failed(void)
 {
 	writel(0, BASE_CFG + ICPU_RESET);
 	writel(PERF_SOFT_RST_SOFT_CHIP_RST, BASE_CFG + PERF_SOFT_RST);
-
-	panic("DDR init failed\n");
 }
 #endif
 
diff --git a/arch/mips/mach-mscc/lowlevel_init.S b/arch/mips/mach-mscc/lowlevel_init.S
index dfbe067..91f29ae 100644
--- a/arch/mips/mach-mscc/lowlevel_init.S
+++ b/arch/mips/mach-mscc/lowlevel_init.S
@@ -8,6 +8,7 @@
 
     .set noreorder
     .extern     vcoreiii_tlb_init
+    .extern     vcoreiii_ddr_init
 #ifdef CONFIG_SOC_LUTON
     .extern     pll_init
 #endif
@@ -17,14 +18,28 @@
 	 * As we have no stack yet, we can assume the restricted
 	 * luxury of the sX-registers without saving them
 	 */
-	move	s0,ra
+
+	/* Modify ra/s0 such we return to physical NOR location */
+	li	t0, 0x0fffffff
+	li	t1, CONFIG_SYS_TEXT_BASE
+	and	s0, ra, t0
+	add	s0, s0, t1
 
 	jal	vcoreiii_tlb_init
 	 nop
+
 #ifdef CONFIG_SOC_LUTON
 	jal	pll_init
 	 nop
 #endif
+
+	/* Initialize DDR controller to enable stack/gd/heap */
+0:
+	jal	vcoreiii_ddr_init
+	 nop
+	bnez	v0, 0b		/* Retry on error */
+	 nop
+
 	jr	s0
 	 nop
 	END(lowlevel_init)