LK: Add 8bit BCH ECC Nand support.

Change-Id: I84277d6d3fd9021a3dcf1e5711827de05d4288d3
diff --git a/platform/msm_shared/nand.c b/platform/msm_shared/nand.c
index e69fa24..cae4834 100644
--- a/platform/msm_shared/nand.c
+++ b/platform/msm_shared/nand.c
@@ -66,12 +66,18 @@
 #define SRC_CRCI_NAND_DATA CMD_SRC_CRCI(DMOV_NAND_CRCI_DATA)
 #define DST_CRCI_NAND_DATA CMD_DST_CRCI(DMOV_NAND_CRCI_DATA)
 
-#define NAND_CFG0_RAW 0xA80420C0
-#define NAND_CFG1_RAW 0x5045D
+#define CFG0_RAW 0xA80420C0
+#define CFG1_RAW 0x5045D
+
+#define CFG0_RAW_BCHECC   0xA80428C0
 
 static unsigned CFG0, CFG1;
 static unsigned CFG0_M, CFG1_M;
 static unsigned CFG0_A, CFG1_A;
+static unsigned NAND_CFG0_RAW, NAND_CFG1_RAW;
+static unsigned ECC_BCH_CFG;
+
+static uint32_t enable_bch_ecc;
 
 #define CFG1_WIDE_FLASH (1U << 1)
 
@@ -143,6 +149,7 @@
 	{0x6600bcec, 0xFF00FFFF, (512<<20), 1, 4096, (4096<<6), 128, 0}, /*Sams*/
 	{0x5580ba2c, 0xFFFFFFFF, (256<<20), 1, 2048, (2048<<6), 64, 0}, /*Hynx*/
 	{0x6600b3ec, 0xFFFFFFFF, (512<<20), 1, 4096, (4096<<6), 128, 0}, /*Sams*/
+	{0x2600482c, 0xFF00FFFF, (2048<<20), 0, 4096, (4096<<7), 224 , 0}, /*8bit bch ecc*/
 	/* Note: Width flag is 0 for 8 bit Flash and 1 for 16 bit flash	  */
 	/* Note: Onenand flag is 0 for NAND Flash and 1 for OneNAND flash	*/
 	/* Note: The First row will be filled at runtime during ONFI probe	*/
@@ -256,17 +263,25 @@
 
 	/* addr0 */
 	if (CFG1 & CFG1_WIDE_FLASH)
-		data[1] = (page << 16) | ((528*(cwperpage-1)) >> 1);
+		data[1] = enable_bch_ecc ?
+			((page << 16) | ((532*(cwperpage-1)) >> 1)):
+			((page << 16) | ((528*(cwperpage-1)) >> 1));
+
 	else
-		data[1] = (page << 16) | (528*(cwperpage-1));
+		data[1] = enable_bch_ecc ?
+			((page << 16) | (532*(cwperpage-1))):
+			((page << 16) | (528*(cwperpage-1)));
 
 	data[2] = (page >> 16) & 0xff;						/* addr1	*/
 	data[3] = 0 | 4;									/* chipsel	*/
 	data[4] = NAND_CFG0_RAW & ~(7U << 6);				/* cfg0		*/
 	data[5] = NAND_CFG1_RAW | (CFG1 & CFG1_WIDE_FLASH);	/* cfg1		*/
-	data[6] = 1;
-	data[7] = CLEAN_DATA_32;	/* flash status */
-	data[8] = CLEAN_DATA_32;	/* buf status	*/
+	if (enable_bch_ecc) {
+		data[6] = ECC_BCH_CFG;				/* ECC CFG */
+	}
+	data[7] = 1;
+	data[8] = CLEAN_DATA_32;	/* flash status */
+	data[9] = CLEAN_DATA_32;	/* buf status	*/
 
 	cmd[0].cmd = DST_CRCI_NAND_CMD | CMD_OCB;
 	cmd[0].src = paddr(&data[0]);
@@ -276,20 +291,26 @@
 	cmd[1].cmd = 0;
 	cmd[1].src = paddr(&data[4]);
 	cmd[1].dst = NAND_DEV0_CFG0;
-	cmd[1].len = 8;
+	if (enable_bch_ecc) {
+		cmd[1].len = 12;
+	} else {
+		cmd[1].len = 8;
+	}
 
 	cmd[2].cmd = 0;
-	cmd[2].src = paddr(&data[6]);
+	cmd[2].src = paddr(&data[7]);
 	cmd[2].dst = NAND_EXEC_CMD;
 	cmd[2].len = 4;
 
 	cmd[3].cmd = SRC_CRCI_NAND_DATA;
 	cmd[3].src = NAND_FLASH_STATUS;
-	cmd[3].dst = paddr(&data[7]);
+	cmd[3].dst = paddr(&data[8]);
 	cmd[3].len = 8;
 
 	cmd[4].cmd = CMD_OCU | CMD_LC;
-	cmd[4].src = NAND_FLASH_BUFFER + (flash_pagesize - (528*(cwperpage-1)));
+	cmd[4].src = NAND_FLASH_BUFFER + (flash_pagesize - (enable_bch_ecc ?
+							(532*(cwperpage-1)):
+							(528*(cwperpage-1))));
 	cmd[4].dst = paddr(&buf);
 	cmd[4].len = 4;
 
@@ -298,13 +319,13 @@
 	dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
 
 #if VERBOSE
-	dprintf(INFO, "status: %x\n", data[7]);
+	dprintf(INFO, "status: %x\n", data[8]);
 #endif
 
 	/* we fail if there was an operation error, a mpu error, or the
 	** erase success bit was not set.
 	*/
-	if(data[7] & 0x110) return -1;
+	if(data[8] & 0x110) return -1;
 
 	/* Check for bad block marker byte */
 	if (CFG1 & CFG1_WIDE_FLASH) {
@@ -514,8 +535,9 @@
 	data[5] = 0xeeeeeeee;
 	data[6] = CFG0 & (~(7 << 6));  /* CW_PER_PAGE = 0 */
 	data[7] = CFG1;
-	data[8] = 0x00000020;
-	data[9] = 0x000000C0;
+	data[8] = ECC_BCH_CFG;
+	data[9] = 0x00000020;
+	data[10] = 0x000000C0;
 
 	cmd[0].cmd = DST_CRCI_NAND_CMD | CMD_OCB;
 	cmd[0].src = paddr(&data[0]);
@@ -525,7 +547,11 @@
 	cmd[1].cmd = 0;
 	cmd[1].src = paddr(&data[6]);
 	cmd[1].dst = NAND_DEV0_CFG0;
-	cmd[1].len = 8;
+	if (enable_bch_ecc) {
+		cmd[1].len = 12;
+	} else {
+		cmd[1].len = 8;
+	}
 
 	cmd[2].cmd = 0;
 	cmd[2].src = paddr(&data[4]);
@@ -538,12 +564,12 @@
 	cmd[3].len = 4;
 
 	cmd[4].cmd = 0;
-	cmd[4].src = paddr(&data[8]);
+	cmd[4].src = paddr(&data[9]);
 	cmd[4].dst = NAND_FLASH_STATUS;
 	cmd[4].len = 4;
 
 	cmd[5].cmd = CMD_OCU | CMD_LC;
-	cmd[5].src = paddr(&data[9]);
+	cmd[5].src = paddr(&data[10]);
 	cmd[5].dst = NAND_READ_STATUS;
 	cmd[5].len = 4;
 
@@ -717,6 +743,7 @@
 	unsigned chipsel;
 	unsigned cfg0;
 	unsigned cfg1;
+	unsigned ecc_bch_cfg;
 	unsigned exec;
 	unsigned ecc_cfg;
 	unsigned ecc_cfg_save;
@@ -780,6 +807,9 @@
 	data->cfg0 = CFG0;
 	data->cfg1 = CFG1;
 
+	if (enable_bch_ecc) {
+		data->ecc_bch_cfg = ECC_BCH_CFG;
+	}
 	data->ecc_cfg = 0x203;
 
 	/* save existing ecc config */
@@ -802,7 +832,11 @@
 			cmd->cmd = 0;
 			cmd->src = paddr(&data->cfg0);
 			cmd->dst = NAND_DEV0_CFG0;
-			cmd->len = 8;
+			if (enable_bch_ecc) {
+				cmd->len = 12;
+			} else {
+				cmd->len = 8;
+			}
 			cmd++;
 
 			/* set our ecc config */
@@ -836,7 +870,7 @@
 
 	/* read extra data */
 	cmd->cmd = 0;
-	cmd->src = NAND_FLASH_BUFFER + 500;
+	cmd->src = NAND_FLASH_BUFFER + (512 - ((cwperpage - 1) << 2));
 	cmd->dst = spareaddr;
 	cmd->len = 16;
 	cmd++;
@@ -1267,6 +1301,9 @@
 	if (!raw_mode){
 		data->cfg0 = CFG0;
 		data->cfg1 = CFG1;
+		if (enable_bch_ecc) {
+			data->ecc_bch_cfg = ECC_BCH_CFG;
+		}
 	}else{
 		data->cfg0 = (NAND_CFG0_RAW & ~(7 << 6)) |((cwperpage-1) << 6);
 		data->cfg1 = NAND_CFG1_RAW | (CFG1 & CFG1_WIDE_FLASH);
@@ -1300,7 +1337,12 @@
 			cmd->cmd = 0;
 			cmd->src = paddr(&data->cfg0);
 			cmd->dst = NAND_DEV0_CFG0;
-			cmd->len = 8;
+			if (enable_bch_ecc) {
+				cmd->len = 12;
+			} else {
+				cmd->len = 8;
+			}
+
 			cmd++;
 
 			/* set our ecc config */
@@ -1737,15 +1779,31 @@
 		|	(0 << 30)  /* Do not read status before data */
 		|	(1 << 31)  /* Send read cmd */
 			/* 0 spare bytes for 16 bit nand or 1 spare bytes for 8 bit */
-		|	((nand_cfg1 & CFG1_WIDE_FLASH) ? (0 << 23) : (1 << 23));
+		|	((nand_cfg1 & CFG1_WIDE_FLASH) ? (0 << 23) :
+		(enable_bch_ecc ? (2 << 23) : (1 << 23))); /* 2 spare bytes for 8 bit bch ecc */
 	CFG1_A = (0 <<  0)  /* Enable ecc */
 		|	(7 <<  2)  /* 8 recovery cycles */
 		|	(0 <<  5)  /* Allow CS deassertion */
-	  	|	((flash_pagesize - (528 * ((flash_pagesize >> 9) - 1)) + 1) <<  6)	/* Bad block marker location */
+		|	((flash_pagesize - ((enable_bch_ecc ? 532 : 528) *
+		((flash_pagesize >> 9) - 1)) + 1) << 6) /* Bad block marker location */
 		|	(0 << 16)  /* Bad block in user data area */
 		|	(2 << 17)  /* 6 cycle tWB/tRB */
 		|	(nand_cfg1 & CFG1_WIDE_FLASH); /* preserve wide flash flag */
 
+	NAND_CFG0_RAW = CFG0_RAW;
+	NAND_CFG1_RAW = CFG1_RAW;
+
+	if (enable_bch_ecc) {
+		CFG1_A |= (1 << 27); /* Enable BCH engine */
+		ECC_BCH_CFG = (0 << 0) /* Enable ECC*/
+			|   (0 << 1) /* Enable/Disable SW reset of ECC engine */
+			|   (1 << 4) /* 8bit ecc*/
+			|   ((nand_cfg1 & CFG1_WIDE_FLASH) ? (14 << 8) : (13 << 8))/*parity bytes*/
+			|   (516 << 16) /* 516 user data bytes */
+			|   (1 << 30); /* Turn on ECC engine clocks always */
+		NAND_CFG0_RAW = CFG0_RAW_BCHECC; /* CW size is increased to 532B */
+        }
+
 	dprintf(INFO, "nandcfg(Apps): %x %x (used)\n", CFG0_A, CFG1_A);
 
 	CFG0_M = CFG0_TMP;
@@ -3119,6 +3177,34 @@
 }
 
 
+unsigned flash_ctrl_hwinfo(dmov_s *cmdlist, unsigned *ptrlist)
+{
+	dmov_s *cmd = cmdlist;
+	unsigned *ptr = ptrlist;
+	unsigned *data = ptrlist + 4;
+
+	unsigned rv;
+
+	data[0] = 0xeeeeeeee;
+	data[1] = 1;
+
+	cmd[0].cmd = CMD_OCB;
+	cmd[0].src = NAND_HW_INFO;
+	cmd[0].dst = paddr(&data[0]);
+	cmd[0].len = 4;
+
+	cmd[1].cmd = CMD_OCU | CMD_LC;
+	cmd[1].src = paddr(&data[1]);
+	cmd[1].dst = NAND_EXEC_CMD;
+	cmd[1].len = 4;
+
+	ptr[0] = (paddr(cmd) >> 3) | CMD_PTR_LP;
+	dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
+	rv = data[0];
+
+	return rv;
+}
+
 /* Wrapper functions */
 static void flash_read_id(dmov_s *cmdlist, unsigned *ptrlist)
 {
@@ -3181,6 +3267,10 @@
 		// Use this for getting the next/current blocks
 		num_pages_per_blk = flash_info.block_size / flash_pagesize;
 		num_pages_per_blk_mask = num_pages_per_blk - 1;
+                //Look for 8bit BCH ECC Nand, TODO: ECC Correctability >= 8
+		if((flash_ctrl_hwinfo(cmdlist,ptrlist) == 0x307) &&  flash_info.id == 0x2600482c) {
+			enable_bch_ecc = 1;
+		}
 		return;
 	}
 
@@ -3480,3 +3570,8 @@
   }
   return;
 }
+
+int flash_ecc_bch_enabled()
+{
+       return enable_bch_ecc;
+}