From 86e38b0af2fb97aa322560328c48a682bff4f754 Mon Sep 17 00:00:00 2001
From: Keerthy <j-keerthy@ti.com>
Date: Tue, 12 Oct 2021 22:46:55 +0530
Subject: [PATCH] Enable ECC for 3 GB

---
 board/ti/j721e/evm.c                  |   4 +-
 drivers/ram/k3-j721e/k3-j721e-ddrss.c | 271 ++++++++++++++++++++++++++
 2 files changed, 273 insertions(+), 2 deletions(-)

diff --git a/board/ti/j721e/evm.c b/board/ti/j721e/evm.c
index 3950aa68ab..70dd3e4194 100644
--- a/board/ti/j721e/evm.c
+++ b/board/ti/j721e/evm.c
@@ -74,8 +74,8 @@ int dram_init_banksize(void)
 #ifdef CONFIG_PHYS_64BIT
 	/* Bank 1 declares the memory available in the DDR high region */
 	gd->bd->bi_dram[1].start = CONFIG_SYS_SDRAM_BASE1;
-	gd->bd->bi_dram[1].size = 0x80000000;
-	gd->ram_size = 0x100000000;
+	gd->bd->bi_dram[1].size = 0x40000000;
+	gd->ram_size = 0xC0000000;
 #endif
 
 	return 0;
diff --git a/drivers/ram/k3-j721e/k3-j721e-ddrss.c b/drivers/ram/k3-j721e/k3-j721e-ddrss.c
index 63bf56528b..22ae8766ea 100644
--- a/drivers/ram/k3-j721e/k3-j721e-ddrss.c
+++ b/drivers/ram/k3-j721e/k3-j721e-ddrss.c
@@ -340,6 +340,275 @@ void j721e_lpddr4_priority_map(void)
     writel(DDRSS_V2A_LPT_HPT_PRI_MAP_VAL, (uintptr_t)DDRSS_V2A_HPT_DEF_PRI_MAP_REG);
 }
 
+#define KB (1024)
+#define MB (1024 * KB)
+#define GB (1024 * MB)
+
+#define DDR_BASE (0x80000000)
+
+/* Update this value based on number of routeIDs programmed */
+#define J721E_NUM_ROUTE_ID (29)
+#define J721E_NUM_ECC_CACHE_LINES (128)
+
+#define J721E_DMPAC_DATA0_ROUTE_ID             (2568)
+#define J721E_DMPAC_DATA1_ROUTE_ID             (2569)
+#define J721E_DECODER0_RD_ROUTE_ID             (2584)
+#define J721E_DECODER0_WR_ROUTE_ID             (2585)
+#define J721E_ENCODER0_RD_ROUTE_ID             (2576)
+#define J721E_ENCODER0_WR_ROUTE_ID             (2577)
+#define J721E_VPAC_MST0_0_ROUTE_ID             (2562)
+#define J721E_VPAC_MST0_1_ROUTE_ID             (2563)
+#define J721E_VPAC_MST1_0_ROUTE_ID             (2564)
+#define J721E_VPAC_MST1_1_ROUTE_ID             (2565)
+#define J721E_VPAC_LDC_ROUTE_ID                (2560)
+#define J721E_DSS_DMA_ROUTE_ID                 (2592)
+#define J721E_DSS_FDBC_ROUTE_ID                (2593)
+#define J721E_GPU_M0_RD_ROUTE_ID               (2601)
+#define J721E_GPU_M0_WR_ROUTE_ID               (2602)
+#define J721E_GPU_M1_RD_ROUTE_ID               (2600)
+#define J721E_GPU_M1_WR_ROUTE_ID               (2603)
+#define J721E_C66X_0_ROUTE_ID                  (576)
+#define J721E_C66X_1_ROUTE_ID                  (578)
+#define J721E_R5FSS0_CORE0_MEM_RD_ROUTE_ID     (520)
+#define J721E_R5FSS0_CORE1_MEM_RD_ROUTE_ID     (528)
+#define J721E_R5FSS0_CORE0_MEM_WR_ROUTE_ID     (521)
+#define J721E_R5FSS0_CORE1_MEM_WR_ROUTE_ID     (529)
+#define J721E_R5FSS1_CORE0_MEM_RD_ROUTE_ID     (536)
+#define J721E_R5FSS1_CORE1_MEM_RD_ROUTE_ID     (544)
+#define J721E_R5FSS1_CORE0_MEM_WR_ROUTE_ID     (537)
+#define J721E_R5FSS1_CORE1_MEM_WR_ROUTE_ID     (545)
+#define J721E_COMPUTE_CLUSTER0_RD_ROUTE_ID     (302)
+#define J721E_COMPUTE_CLUSTER0_WR_ROUTE_ID     (303)
+
+static unsigned int j7es_soc_route_id[] =
+{
+    J721E_DMPAC_DATA0_ROUTE_ID,
+    J721E_DMPAC_DATA1_ROUTE_ID,
+    J721E_DECODER0_RD_ROUTE_ID,
+    J721E_DECODER0_WR_ROUTE_ID,
+    J721E_ENCODER0_RD_ROUTE_ID,
+    J721E_ENCODER0_WR_ROUTE_ID,
+    J721E_VPAC_MST0_0_ROUTE_ID,
+    J721E_VPAC_MST0_1_ROUTE_ID,
+    J721E_VPAC_MST1_0_ROUTE_ID,
+    J721E_VPAC_MST1_1_ROUTE_ID,
+    J721E_VPAC_LDC_ROUTE_ID,
+    J721E_DSS_DMA_ROUTE_ID,
+    J721E_DSS_FDBC_ROUTE_ID,
+    J721E_GPU_M0_RD_ROUTE_ID,
+    J721E_GPU_M0_WR_ROUTE_ID,
+    J721E_GPU_M1_RD_ROUTE_ID,
+    J721E_GPU_M1_WR_ROUTE_ID,
+    J721E_C66X_0_ROUTE_ID,
+    J721E_C66X_1_ROUTE_ID,
+    J721E_R5FSS0_CORE0_MEM_RD_ROUTE_ID,
+    J721E_R5FSS0_CORE1_MEM_RD_ROUTE_ID,
+    J721E_R5FSS0_CORE0_MEM_WR_ROUTE_ID,
+    J721E_R5FSS0_CORE1_MEM_WR_ROUTE_ID,
+    J721E_R5FSS1_CORE0_MEM_RD_ROUTE_ID,
+    J721E_R5FSS1_CORE1_MEM_RD_ROUTE_ID,
+    J721E_R5FSS1_CORE0_MEM_WR_ROUTE_ID,
+    J721E_R5FSS1_CORE1_MEM_WR_ROUTE_ID,
+    J721E_COMPUTE_CLUSTER0_RD_ROUTE_ID,
+    J721E_COMPUTE_CLUSTER0_WR_ROUTE_ID
+};
+
+static unsigned char j7es_ecc_cache_lines[] =
+{
+    0, /* J721E_DMPAC_DATA0_ROUTE_ID  */
+    0, /* J721E_DMPAC_DATA1_ROUTE_ID  */
+    0, /* J721E_DECODER0_RD_ROUTE_ID  */
+    0, /* J721E_DECODER0_WR_ROUTE_ID  */
+    4, /* J721E_ENCODER0_RD_ROUTE_ID  */
+    4, /* J721E_ENCODER0_WR_ROUTE_ID  */
+    4, /* J721E_VPAC_MST0_0_ROUTE_ID  */
+    4, /* J721E_VPAC_MST0_1_ROUTE_ID  */
+    4, /* J721E_VPAC_MST1_0_ROUTE_ID  */
+    4, /* J721E_VPAC_MST1_1_ROUTE_ID  */
+    8, /* J721E_VPAC_LDC_ROUTE_ID  */
+    4, /* J721E_DSS_DMA_ROUTE_ID  */
+    0, /* J721E_DSS_FDBC_ROUTE_ID  */
+    8, /* J721E_GPU_M0_RD_ROUTE_ID  */
+    8, /* J721E_GPU_M0_WR_ROUTE_ID  */
+    8, /* J721E_GPU_M1_RD_ROUTE_ID  */
+    8, /* J721E_GPU_M1_WR_ROUTE_ID  */
+    4, /* J721E_C66X_0_ROUTE_ID  */
+    4, /* J721E_C66X_1_ROUTE_ID  */
+    8, /* J721E_R5FSS0_CORE0_MEM_RD_ROUTE_ID */
+    8, /* J721E_R5FSS0_CORE1_MEM_RD_ROUTE_ID */
+    0, /* J721E_R5FSS0_CORE0_MEM_WR_ROUTE_ID */
+    0, /* J721E_R5FSS0_CORE1_MEM_WR_ROUTE_ID */
+    0, /* J721E_R5FSS1_CORE0_MEM_RD_ROUTE_ID */
+    0, /* J721E_R5FSS1_CORE1_MEM_RD_ROUTE_ID */
+    0, /* J721E_R5FSS1_CORE0_MEM_WR_ROUTE_ID */
+    0, /* J721E_R5FSS1_CORE1_MEM_WR_ROUTE_ID */
+    4, /* J721E_COMPUTE_CLUSTER0_RD_ROUTE_ID */
+    4  /* J721E_COMPUTE_CLUSTER0_WR_ROUTE_ID */
+};
+
+static int clear_mem_sect(unsigned int *pAddr, unsigned int size, unsigned int word)
+{
+	int i;
+
+	for(i = 0; i < (size / 4); i++)
+	{
+		pAddr[i] = word;
+	}
+	
+	return 0;
+}
+
+static int set_ecc_range_r1(unsigned int start_address, unsigned int size)
+{
+	*((unsigned int *)0x02980130) = (start_address) >> 16;
+	*((unsigned int *)0x02980134) = (start_address + size - 1) >> 16;
+
+	return 0;
+}
+
+static int set_ecc_range_r2(unsigned int start_address, unsigned int size)
+{
+	*((unsigned int *)0x02980138) = (start_address) >> 16;
+	*((unsigned int *)0x0298013C) = (start_address + size - 1) >> 16;
+
+	return 0;
+}
+
+static int set_ecc_range_r3(unsigned int start_address, unsigned int size)
+{
+	*((unsigned int *)0x02980140) = (start_address) >> 16;
+	*((unsigned int *)0x02980144) = (start_address + size - 1) >> 16;
+
+	return 0;
+}
+
+static int clr_ecc_1bit_cnt()
+{
+	//Writing a 1 clears the register
+	*((unsigned int *)0x02980150) = 1;
+
+	return 0;
+}
+
+#define DDRSS_ECC_RID_INDX_REG (0x02980124)
+#define DDRSS_ECC_RID_VAL_REG  (0x02980128)
+
+static int set_ecc_cache_lines()
+{
+    int i, j, k;
+    unsigned char line_count;
+
+    /* Map route-id's to ECC cache lines by writing into DDRSS_ECC_RID_INDX_REG and DDRSS_ECC_RID_VAL_REG */
+    line_count = 0;
+    k = 0;
+    for(i = 0; i < J721E_NUM_ROUTE_ID; i++)
+    {
+        for(j = 0; j < j7es_ecc_cache_lines[i]; j++)
+        {
+            if( k < J721E_NUM_ECC_CACHE_LINES)
+            {
+                *((unsigned int *)DDRSS_ECC_RID_INDX_REG) = k++;
+                *((unsigned int *)DDRSS_ECC_RID_VAL_REG) = j7es_soc_route_id[i] | (1 << 15);
+
+                //printf("[Linux-R5F SPL] Setting ECC cache line = %d, Route ID = %d \n", k, j7es_soc_route_id[i]);
+            }
+        }
+    }
+
+    /* Read the values back to check if the route-id to cache line map is done as expected */
+    for(i = 0; i < J721E_NUM_ECC_CACHE_LINES; i++)
+    {
+        *((unsigned int *)DDRSS_ECC_RID_INDX_REG) = i;
+        unsigned int route_id = *((unsigned int *)DDRSS_ECC_RID_VAL_REG);
+
+        printf("[Linux-R5F SPL] ECC cache line = %d, Route ID = %d \n", i, (route_id & 0x7FFF));
+    }
+}
+
+static int enable_ecc()
+{
+	//bit0 - ECC_EN - 1
+	//bit1 - RMW_EN - 1
+	//bit2 - ECC_CK - 0
+	//bit4 - WR_ALLOC - 1
+	*((unsigned int *)0x02980120) = 0x00000003;
+
+	return 0;
+}
+
+static int enable_ecc_check()
+{
+	//bit0 - ECC_EN - 1
+	//bit1 - RMW_EN - 1
+	//bit2 - ECC_CK - 1
+	//bit4 - WR_ALLOC - 1
+	*((unsigned int *)0x02980120) = 0x00000017;
+
+	return 0;
+}
+
+static void configure_rat()
+{
+	// In Address 0x80000000
+	*((volatile unsigned int *)0x40f90044) = 0x80000000;
+	// Lower 32 bits of the out address 0x80000000
+	*((volatile unsigned int *)0x40f90048) = 0x80000000;
+	// Higher bits of the out address 0x8 so > 32 bit address = 0x880000000
+	*((volatile unsigned int *)0x40f9004C) = 0x00000008;
+	// Enable the region bit31 & size = 0x1e = decimal 30 so 2 ^ 30 = 1GB region
+	*((volatile unsigned int *)0x40f90040) = 0x8000001e;
+}
+
+static void disable_rat()
+{
+	*((volatile unsigned int *)0x40f90040) = 0x00000000;
+}
+
+static int j721e_lpddr4_ecc_init()
+{
+	unsigned int init_word = 0;
+	unsigned int ecc_range = (1024 + 1024)*MB; //0xDFE0000; //(1024 + 1024)*MB;
+	unsigned int ecc_start = 0x80000000;
+
+	printf("[Linux-R5F SPL] DDR Init Done! \n");
+
+	printf("[Linux-R5F SPL] Setting R1 range from 0x%08x of size %u bytes ...\n", ecc_start, ecc_range);
+	set_ecc_range_r1((unsigned int)ecc_start - (unsigned int)DDR_BASE, ecc_range);
+	printf("[Linux-R5F SPL] R1 range setting Done!\n");
+
+	printf("[Linux-R5F SPL] Setting R2 range from 0x%08x of size %u bytes ...\n", 0x80000000, 0x80000000);
+	set_ecc_range_r2((unsigned int)0x80000000, 0xC0000000);
+	printf("[Linux-R5F SPL] R2 range setting Done!\n");
+
+	printf("[Linux-R5F SPL] Enabling ECC...\n");
+	enable_ecc();
+	printf("[Linux-R5F SPL] ECC check enabled! \n");
+
+	printf("[Linux-R5F SPL] Setting ECC cache lines...\n");
+        set_ecc_cache_lines();
+	printf("[Linux-R5F SPL] ECC cache lines set! \n");	
+
+	configure_rat();
+	printf("Clearing higher memroy addresses\n");
+	clear_mem_sect((volatile unsigned int *)0x80000000, 1024 * MB, init_word);
+        printf("Clearing memroy done\n");
+	disable_rat();
+
+	printf("[Linux-R5F SPL] Memory initialization with known pattern 0x%08x ...\n", init_word);
+	clear_mem_sect((unsigned int *)ecc_start, ecc_range, init_word);
+	printf("[Linux-R5F SPL] Memory initialization Done!\n");
+
+	printf("[Linux-R5F SPL] Clearing 1bit count register...\n");
+	clr_ecc_1bit_cnt();
+	printf("[Linux-R5F SPL] 1bit count register cleared! \n");
+
+	printf("[Linux-R5F SPL] Enabling ECC check...\n");
+	enable_ecc_check();
+	printf("[Linux-R5F SPL] ECC check enabled! \n");
+
+	return 0;
+}
+
 static int j721e_ddrss_probe(struct udevice *dev)
 {
 	int ret;
@@ -363,6 +632,8 @@ static int j721e_ddrss_probe(struct udevice *dev)
 	j721e_lpddr4_priority_map();
 	j721e_lpddr4_start();
 
+	j721e_lpddr4_ecc_init();
+
 	return ret;
 }
 
-- 
2.17.1

