diff mbox series

[U-Boot,05/13] arm: ti: Generalize cmd_ddr3 command

Message ID 20171218093425.12235-6-lokeshvutla@ti.com
State Superseded
Delegated to: Tom Rini
Headers show
Series arm: am57xx: Add support for am574-idk | expand

Commit Message

Lokesh Vutla Dec. 18, 2017, 9:34 a.m. UTC
Keystone and DRA7 based TI platforms uses same
EMIF memory controller. cmd_ddr3 command is customized
for keystone platforms, make it generic so that it can
be re used for DRA7  platforms.

Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
---
 arch/arm/include/asm/emif.h                    |   2 +
 arch/arm/mach-keystone/include/mach/hardware.h |   1 +
 board/ti/common/cmd_ddr3.c                     | 174 ++++++++++++++++++++-----
 3 files changed, 141 insertions(+), 36 deletions(-)
diff mbox series

Patch

diff --git a/arch/arm/include/asm/emif.h b/arch/arm/include/asm/emif.h
index 6a2ccd2350..b9fa3bb827 100644
--- a/arch/arm/include/asm/emif.h
+++ b/arch/arm/include/asm/emif.h
@@ -17,7 +17,9 @@ 
 #include <asm/io.h>
 
 /* Base address */
+#ifndef EMIF1_BASE
 #define EMIF1_BASE				0x4c000000
+#endif
 #define EMIF2_BASE				0x4d000000
 
 #define EMIF_4D					0x4
diff --git a/arch/arm/mach-keystone/include/mach/hardware.h b/arch/arm/mach-keystone/include/mach/hardware.h
index 1969a10ab3..6629406870 100644
--- a/arch/arm/mach-keystone/include/mach/hardware.h
+++ b/arch/arm/mach-keystone/include/mach/hardware.h
@@ -78,6 +78,7 @@  typedef volatile unsigned int   *dv_reg_p;
 #define KS2_DDR3A_EMIF_CTRL_BASE	0x21010000
 #define KS2_DDR3A_EMIF_DATA_BASE	0x80000000
 #define KS2_DDR3A_DDRPHYC		0x02329000
+#define EMIF1_BASE			KS2_DDR3A_EMIF_CTRL_BASE
 
 #define KS2_DDR3_MIDR_OFFSET            0x00
 #define KS2_DDR3_STATUS_OFFSET          0x04
diff --git a/board/ti/common/cmd_ddr3.c b/board/ti/common/cmd_ddr3.c
index b6435a43f4..0e35d5cbbd 100644
--- a/board/ti/common/cmd_ddr3.c
+++ b/board/ti/common/cmd_ddr3.c
@@ -7,23 +7,25 @@ 
  */
 
 #include <asm/arch/hardware.h>
-#include <asm/arch/ddr3.h>
+#include <asm/cache.h>
+#include <asm/emif.h>
 #include <common.h>
 #include <command.h>
 
-DECLARE_GLOBAL_DATA_PTR;
-
+#ifdef CONFIG_ARCH_KEYSTONE
+#include <asm/arch/ddr3.h>
 #define DDR_MIN_ADDR		CONFIG_SYS_SDRAM_BASE
-#define STACKSIZE		(512 << 10)     /* 512 KiB */
-
+#define STACKSIZE              (512 << 10)     /* 512 KiB */
 #define DDR_REMAP_ADDR		0x80000000
 #define ECC_START_ADDR1		((DDR_MIN_ADDR - DDR_REMAP_ADDR) >> 17)
 
-#define ECC_END_ADDR1		(((gd->start_addr_sp - DDR_REMAP_ADDR - \
-				 STACKSIZE) >> 17) - 2)
+#define ECC_END_ADDR1          (((gd->start_addr_sp - DDR_REMAP_ADDR - \
+				STACKSIZE) >> 17) - 2)
+#endif
 
 #define DDR_TEST_BURST_SIZE	1024
 
+DECLARE_GLOBAL_DATA_PTR;
 static int ddr_memory_test(u32 start_address, u32 end_address, int quick)
 {
 	u32 index_start, value, index;
@@ -153,57 +155,157 @@  static int ddr_memory_compare(u32 address1, u32 address2, u32 size)
 	return 0;
 }
 
-static int ddr_memory_ecc_err(u32 base, u32 address, u32 ecc_err)
+#ifndef CONFIG_ARCH_KEYSTONE
+static void ddr_check_ecc_status(void)
+{
+	struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
+	u32 err_1b = readl(&emif->emif_1b_ecc_err_cnt);
+	u32 int_status = readl(&emif->emif_irqstatus_raw_sys);
+	int ecc_test = 0;
+	char *env;
+
+	env = env_get("ecc_test");
+	if (env)
+		ecc_test = simple_strtol(env, NULL, 0);
+
+	puts("ECC test Status:\n");
+	if (int_status & EMIF_INT_WR_ECC_ERR_SYS_MASK)
+		puts("\tECC test: DDR ECC write error interrupted\n");
+
+	if (int_status & EMIF_INT_TWOBIT_ECC_ERR_SYS_MASK)
+		if (!ecc_test)
+			panic("\tECC test: DDR ECC 2-bit error interrupted");
+
+	if (int_status & EMIF_INT_ONEBIT_ECC_ERR_SYS_MASK)
+		puts("\tECC test: DDR ECC 1-bit error interrupted\n");
+
+	if (err_1b)
+		printf("\tECC test: 1-bit ECC err count: 0x%x\n", err_1b);
+}
+#endif
+
+static int ddr_memory_ecc_err(u32 addr, u32 ecc_err)
 {
-	u32 value1, value2, value3;
+	struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
+	u32 ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg);
+	u32 val1, val2, val3;
+
+	debug("Disabling D-Cache before ECC test\n");
+	dcache_disable();
+	invalidate_dcache_all();
+
+	puts("Testing DDR ECC:\n");
+	puts("\tECC test: Disabling DDR ECC ...\n");
+	writel(0, &emif->emif_ecc_ctrl_reg);
+
+	val1 = readl(addr);
+	val2 = val1 ^ ecc_err;
+	writel(val2, addr);
+
+	val3 = readl(addr);
+	printf("\tECC test: addr 0x%x, read data 0x%x, written data 0x%x, err pattern: 0x%x, read after write data 0x%x\n",
+	       addr, val1, val2, ecc_err, val3);
 
-	puts("Disabling DDR ECC ...\n");
-	ddr3_disable_ecc(base);
+	puts("\tECC test: Enabling DDR ECC ...\n");
+#ifdef CONFIG_ARCH_KEYSTONE
+	ecc_ctrl = ECC_START_ADDR1 | (ECC_END_ADDR1 << 16);
+	__raw_writel(ecc_ctrl, EMIF1_BASE + KS2_DDR3_ECC_ADDR_RANGE1_OFFSET);
+	ddr3_enable_ecc(EMIF1_BASE, 1);
 
-	value1 = __raw_readl(address);
-	value2 = value1 ^ ecc_err;
-	__raw_writel(value2, address);
+	val1 = __raw_readl(addr);
+	printf("ECC err test, addr 0x%x, read data 0x%x\n", addr, val1);
 
-	value3 = __raw_readl(address);
-	printf("ECC err test, addr 0x%x, read data 0x%x, wrote data 0x%x, err pattern: 0x%x, read after write data 0x%x\n",
-	       address, value1, value2, ecc_err, value3);
+	ddr3_check_ecc_int(EMIF1_BASE);
+#else
+	writel(ecc_ctrl, &emif->emif_ecc_ctrl_reg);
 
-	__raw_writel(ECC_START_ADDR1 | (ECC_END_ADDR1 << 16),
-		     base + KS2_DDR3_ECC_ADDR_RANGE1_OFFSET);
+	val1 = readl(addr);
+	printf("\tECC test: addr 0x%x, read data 0x%x\n", addr, val1);
 
-	puts("Enabling DDR ECC ...\n");
-	ddr3_enable_ecc(base, 1);
+	ddr_check_ecc_status();
 
-	value1 = __raw_readl(address);
-	printf("ECC err test, addr 0x%x, read data 0x%x\n", address, value1);
+	debug("Enabling D-cache back after ECC test\n");
+	enable_caches();
+#endif
 
-	ddr3_check_ecc_int(base);
 	return 0;
 }
 
+static int is_addr_valid(u32 addr)
+{
+#ifndef CONFIG_ARCH_KEYSTONE
+	struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
+	u32 start_addr, end_addr, range, ecc_ctrl;
+
+	ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg);
+
+	printf("%s: emif1_base = 0x%x,  Ecc ctrl = 0x%x \n", __func__, EMIF1_BASE, ecc_ctrl);
+
+	/* Check in ecc address range 1 */
+	if (ecc_ctrl & EMIF_ECC_REG_ECC_ADDR_RGN_1_EN_MASK) {
+		range = readl(&emif->emif_ecc_address_range_1);
+		start_addr = ((range & EMIF_ECC_REG_ECC_START_ADDR_MASK) << 16)
+				+ CONFIG_SYS_SDRAM_BASE;
+		end_addr = start_addr + (range & EMIF_ECC_REG_ECC_END_ADDR_MASK)
+				+ 0xFFFF;
+		if ((addr >= start_addr) && (addr <= end_addr))
+			/* addr within ecc address range 1 */
+			return 1;
+	}
+
+	/* Check in ecc address range 2 */
+	if (ecc_ctrl & EMIF_ECC_REG_ECC_ADDR_RGN_2_EN_MASK) {
+		range = readl(&emif->emif_ecc_address_range_2);
+		start_addr = ((range & EMIF_ECC_REG_ECC_START_ADDR_MASK) << 16)
+				+ CONFIG_SYS_SDRAM_BASE;
+		end_addr = start_addr + (range & EMIF_ECC_REG_ECC_END_ADDR_MASK)
+				+ 0xFFFF;
+		if ((addr >= start_addr) && (addr <= end_addr))
+			/* addr within ecc address range 2 */
+			return 1;
+	}
+
+	return 0;
+#else
+	if ((addr < CONFIG_SYS_SDRAM_BASE) ||
+	    (addr > (CONFIG_SYS_SDRAM_BASE + CONFIG_MAX_RAM_BANK_SIZE - 1))) {
+		puts("Invalid address!\n");
+		return 1;
+	}
+
+	return 1;
+#endif
+}
+
+static int is_ecc_enabled(void)
+{
+	struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
+	u32 ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg);
+
+	return (ecc_ctrl & EMIF_ECC_CTRL_REG_ECC_EN_MASK) &&
+		(ecc_ctrl & EMIF_ECC_REG_RMW_EN_MASK);
+}
+
 static int do_ddr_test(cmd_tbl_t *cmdtp,
 		       int flag, int argc, char * const argv[])
 {
 	u32 start_addr, end_addr, size, ecc_err;
 
 	if ((argc == 4) && (strncmp(argv[1], "ecc_err", 8) == 0)) {
-		if (!ddr3_ecc_support_rmw(KS2_DDR3A_EMIF_CTRL_BASE)) {
-			puts("ECC RMW isn't supported for this SOC\n");
-			return 1;
+		if (!is_ecc_enabled()) {
+			puts("ECC not enabled. Please Enable ECC any try again\n");
+			return CMD_RET_FAILURE;
 		}
 
 		start_addr = simple_strtoul(argv[2], NULL, 16);
 		ecc_err = simple_strtoul(argv[3], NULL, 16);
 
-		if ((start_addr < CONFIG_SYS_SDRAM_BASE) ||
-		    (start_addr > (CONFIG_SYS_SDRAM_BASE +
-		     CONFIG_MAX_RAM_BANK_SIZE - 1))) {
-			puts("Invalid address!\n");
-			return cmd_usage(cmdtp);
+		if (!is_addr_valid(start_addr)) {
+			puts("Invalid address. Please enter ECC supported address!\n");
+			return CMD_RET_FAILURE;
 		}
 
-		ddr_memory_ecc_err(KS2_DDR3A_EMIF_CTRL_BASE,
-				   start_addr, ecc_err);
+		ddr_memory_ecc_err(start_addr, ecc_err);
 		return 0;
 	}
 
@@ -216,10 +318,10 @@  static int do_ddr_test(cmd_tbl_t *cmdtp,
 
 	if ((start_addr < CONFIG_SYS_SDRAM_BASE) ||
 	    (start_addr > (CONFIG_SYS_SDRAM_BASE +
-	     CONFIG_MAX_RAM_BANK_SIZE - 1)) ||
+	     get_effective_memsize() - 1)) ||
 	    (end_addr < CONFIG_SYS_SDRAM_BASE) ||
 	    (end_addr > (CONFIG_SYS_SDRAM_BASE +
-	     CONFIG_MAX_RAM_BANK_SIZE - 1)) || (start_addr >= end_addr)) {
+	     get_effective_memsize() - 1)) || (start_addr >= end_addr)) {
 		puts("Invalid start or end address!\n");
 		return cmd_usage(cmdtp);
 	}