[U-Boot] [PATCH 2/2] mtd/nand : workaround for Freescale FCM to supportlarge-page Nand chip

Mike Hench mhench at elutions.com
Fri Jul 8 21:10:03 CEST 2011


Ok, so to port Liu Shuo's huge page nand to fake 2k page patch to uboot
We either need to introduce a callback after mtd initialization
(Which would have to be outside the driver) or lie about the ID info
coming from the driver.
I choose the second.
Does this look reasonable to you guys?
The IPL boot loader part is NOT included here.
The new stuff is fix_id_info()


diff -purN orig/drivers/mtd/nand/fsl_elbc_nand.c
u-boot-2011.06/drivers/mtd/nand/fsl_elbc_nand.c
--- orig/drivers/mtd/nand/fsl_elbc_nand.c	2011-07-08
14:18:18.634544056 -0500
+++ u-boot-2011.06/drivers/mtd/nand/fsl_elbc_nand.c	2011-07-08
14:17:58.592570060 -0500
@@ -86,6 +86,10 @@ struct fsl_elbc_ctrl {
 	unsigned int use_mdr;    /* Non zero if the MDR is to be set
*/
 	unsigned int oob;        /* Non zero if operating on OOB data
*/
 	uint8_t *oob_poi;        /* Place to write ECC after read back
*/
+
+	int subpage_shift;       /* If writesize > 2048, these two
members*/
+	int subpage_mask;        /* are used to calculate the real page
*/
+                            /* address and real column address       */
 };
 
 /* These map to the positions used by the FCM hardware ECC generator */
@@ -173,10 +177,20 @@ static void set_addr(struct mtd_info *mt
 	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
 	fsl_lbc_t *lbc = ctrl->regs;
 	int buf_num;
+	u32 real_ca = column;
+
+	if (priv->page_size && ctrl->subpage_shift) {
+		real_ca = (page_addr & ctrl->subpage_mask) * 2112;
+		page_addr >>= ctrl->subpage_shift;
+	}
 
 	ctrl->page = page_addr;
 
 	if (priv->page_size) {
+		real_ca += (oob ? 2048 : 0);
+		ctrl->use_mdr = 1;
+		ctrl->mdr = real_ca;
+
 		out_be32(&lbc->fbar, page_addr >> 6);
 		out_be32(&lbc->fpar,
 			 ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI)
|
@@ -265,11 +279,12 @@ static void fsl_elbc_do_read(struct nand
 
 	if (priv->page_size) {
 		out_be32(&lbc->fir,
-			 (FIR_OP_CW0 << FIR_OP0_SHIFT) |
-			 (FIR_OP_CA  << FIR_OP1_SHIFT) |
-			 (FIR_OP_PA  << FIR_OP2_SHIFT) |
-			 (FIR_OP_CW1 << FIR_OP3_SHIFT) |
-			 (FIR_OP_RBW << FIR_OP4_SHIFT));
+			(FIR_OP_CW0 << FIR_OP0_SHIFT) |
+			(FIR_OP_UA  << FIR_OP1_SHIFT) |
+			(FIR_OP_UA  << FIR_OP2_SHIFT) |
+			(FIR_OP_PA  << FIR_OP3_SHIFT) |
+			(FIR_OP_CW1 << FIR_OP4_SHIFT) |
+			(FIR_OP_RBW << FIR_OP5_SHIFT));
 
 		out_be32(&lbc->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) |
 				    (NAND_CMD_READSTART <<
FCR_CMD1_SHIFT));
@@ -288,6 +303,28 @@ static void fsl_elbc_do_read(struct nand
 	}
 }
 
+#ifdef CONFIG_NAND_FSL_ELBC_HUGE_PAGE_WORKAROUND
+void fix_id_info(struct fsl_elbc_ctrl *ctrl)
+{
+	int ext = in_8(&ctrl->addr[ctrl->index+3]);
+
+	/* Hack for supporting the flash chip whose writesize is
+	 * larger than 2K bytes. if the page size is 4k or greater
+	 * say it is 2k.
+	 */
+	if(ext == 0xff)
+		return;
+	if((ext & 0x3) >= 2) {
+		ctrl->subpage_shift = (ext & 0x3) - 1;
+		ctrl->subpage_mask = (1 << ctrl->subpage_shift) - 1;
+		ext &= ~0x3;
+		ext |= 1;
+		out_8(&ctrl->addr[ctrl->index+3], ext);
+		ext = in_8(&ctrl->addr[ctrl->index+3]);
+	}
+}
+#endif
+
 /* cmdfunc send commands to the FCM */
 static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int
command,
 			     int column, int page_addr)
@@ -355,6 +392,9 @@ static void fsl_elbc_cmdfunc(struct mtd_
 
 		set_addr(mtd, 0, 0, 0);
 		fsl_elbc_run_command(mtd);
+#ifdef CONFIG_NAND_FSL_ELBC_HUGE_PAGE_WORKAROUND
+		fix_id_info(ctrl);
+#endif
 		return;
 
 	/* ERASE1 stores the block and page address */
@@ -399,10 +439,11 @@ static void fsl_elbc_cmdfunc(struct mtd_
 
 			out_be32(&lbc->fir,
 				 (FIR_OP_CW0 << FIR_OP0_SHIFT) |
-				 (FIR_OP_CA  << FIR_OP1_SHIFT) |
-				 (FIR_OP_PA  << FIR_OP2_SHIFT) |
-				 (FIR_OP_WB  << FIR_OP3_SHIFT) |
-				 (FIR_OP_CW1 << FIR_OP4_SHIFT));
+				 (FIR_OP_UA  << FIR_OP1_SHIFT) |
+				 (FIR_OP_UA  << FIR_OP2_SHIFT) |
+				 (FIR_OP_PA  << FIR_OP3_SHIFT) |
+				 (FIR_OP_WB  << FIR_OP4_SHIFT) |
+				 (FIR_OP_CW1 << FIR_OP5_SHIFT));
 		} else {
 			fcr = (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT) |
 			      (NAND_CMD_SEQIN << FCR_CMD2_SHIFT);
@@ -453,6 +494,10 @@ static void fsl_elbc_cmdfunc(struct mtd_
 			full_page = 1;
 		}
 
+		if (priv->page_size)
+			ctrl->use_mdr = 1;
+
+
 		fsl_elbc_run_command(mtd);
 
 		ctrl->oob_poi = NULL;





More information about the U-Boot mailing list