[U-Boot] [PATCH v3 3/5] imx: nandbcb: add support for i.MX7

Igor Opaniuk igor.opaniuk at gmail.com
Sun Nov 3 15:49:44 UTC 2019


From: Igor Opaniuk <igor.opaniuk at toradex.com>

Add support for updating FCB/DBBT on i.MX7:
- additional new fields in FCB structure
- Leverage hardware BCH/randomizer for writing FCB

Signed-off-by: Igor Opaniuk <igor.opaniuk at toradex.com>
Tested-by: Max Krummenacher <max.krummenacher at toradex.com>
Reviewed-by: Oleksandr Suvorov <oleksandr.suvorov at toradex.com>
---

 arch/arm/include/asm/mach-imx/imx-nandbcb.h |  12 ++
 arch/arm/mach-imx/Kconfig                   |   2 +-
 arch/arm/mach-imx/cmd_nandbcb.c             | 137 +++++++++++++-------
 3 files changed, 104 insertions(+), 47 deletions(-)

diff --git a/arch/arm/include/asm/mach-imx/imx-nandbcb.h b/arch/arm/include/asm/mach-imx/imx-nandbcb.h
index 033659a038..907e7ed8f9 100644
--- a/arch/arm/include/asm/mach-imx/imx-nandbcb.h
+++ b/arch/arm/include/asm/mach-imx/imx-nandbcb.h
@@ -106,6 +106,18 @@ struct fcb_block {
 
 	/* The swap position of main area in spare area */
 	u32 spare_offset;
+
+	/* Actual for iMX7 only */
+	u32 onfi_sync_enable;
+	u32 onfi_sync_speed;
+	u32 onfi_sync_nand_data;
+	u32 reserved2[6];
+	u32 disbbm_search;
+	u32 disbbm_search_limit;
+	u32 reserved3[15];
+	u32 read_retry_enable;
+	u32 reserved4[1];
+	u32 fill_to_1024[183];
 };
 
 #endif	/* _IMX_NAND_BCB_H_ */
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 4a2f39b110..3f93fe5174 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -82,7 +82,7 @@ config CMD_NANDBCB
 	bool "i.MX6 NAND Boot Control Block(BCB) command"
 	depends on NAND && CMD_MTDPARTS
 	select BCH if MX6UL || MX6ULL
-	default y if ARCH_MX6 && NAND_MXS
+	default y if (ARCH_MX6 && NAND_MXS) || (ARCH_MX7 && NAND_MXS)
 	help
 	  Unlike normal 'nand write/erase' commands, this command update
 	  Boot Control Block(BCB) for i.MX6 platform NAND IP's.
diff --git a/arch/arm/mach-imx/cmd_nandbcb.c b/arch/arm/mach-imx/cmd_nandbcb.c
index 1a2e017aaf..a3a44bc284 100644
--- a/arch/arm/mach-imx/cmd_nandbcb.c
+++ b/arch/arm/mach-imx/cmd_nandbcb.c
@@ -17,6 +17,7 @@
 #include <linux/bch.h>
 #include <linux/mtd/mtd.h>
 
+#include <asm/arch/sys_proto.h>
 #include <asm/mach-imx/imx-nandbcb.h>
 #include <asm/mach-imx/imximage.cfg>
 #include <mxs_nand.h>
@@ -131,26 +132,36 @@ static void fill_fcb(struct fcb_block *fcb, struct mtd_info *mtd)
 {
 	struct nand_chip *chip = mtd_to_nand(mtd);
 	struct mxs_nand_info *nand_info = nand_get_controller_data(chip);
+	struct mxs_nand_layout l;
+
+	mxs_nand_get_layout(mtd, &l);
 
 	fcb->fingerprint = FCB_FINGERPRINT;
 	fcb->version = FCB_VERSION_1;
+
 	fcb->pagesize = mtd->writesize;
 	fcb->oob_pagesize = mtd->writesize + mtd->oobsize;
 	fcb->sectors = mtd->erasesize / mtd->writesize;
 
-	/* Divide ECC strength by two and save the value into FCB structure. */
-	fcb->ecc_level = nand_info->bch_geometry.ecc_strength >> 1;
-
-	fcb->ecc_type = fcb->ecc_level;
+	fcb->meta_size = l.meta_size;
+	fcb->nr_blocks = l.nblocks;
+	fcb->ecc_nr = l.data0_size;
+	fcb->ecc_level = l.ecc0;
+	fcb->ecc_size = l.datan_size;
+	fcb->ecc_type = l.eccn;
 
 	/* Also hardcoded in kobs-ng */
-	fcb->ecc_nr = 0x00000200;
-	fcb->ecc_size = 0x00000200;
-	fcb->datasetup = 80;
-	fcb->datahold = 60;
-	fcb->addr_setup = 25;
-	fcb->dsample_time = 6;
-	fcb->meta_size = 10;
+	if (is_mx6()) {
+		fcb->datasetup = 80;
+		fcb->datahold = 60;
+		fcb->addr_setup = 25;
+		fcb->dsample_time = 6;
+	} else if (is_mx7()) {
+		fcb->datasetup = 10;
+		fcb->datahold = 7;
+		fcb->addr_setup = 15;
+		fcb->dsample_time = 6;
+	}
 
 	/* DBBT search area starts at second page on first block */
 	fcb->dbbt_start = 1;
@@ -162,6 +173,9 @@ static void fill_fcb(struct fcb_block *fcb, struct mtd_info *mtd)
 
 	fcb->nr_blocks = mtd->writesize / fcb->ecc_nr - 1;
 
+	fcb->disbbm = 0;
+	fcb->disbbm_search = 0;
+
 	fcb->checksum = calc_chksum((void *)fcb + 4, sizeof(*fcb) - 4);
 }
 
@@ -197,6 +211,7 @@ static int nandbcb_update(struct mtd_info *mtd, loff_t off, size_t size,
 	size_t fwsize, dummy;
 	int i, ret;
 
+	fcb_raw_page = 0;
 	/* erase */
 	memset(&opts, 0, sizeof(opts));
 	opts.offset = off;
@@ -287,50 +302,79 @@ static int nandbcb_update(struct mtd_info *mtd, loff_t off, size_t size,
 	else if (ret > 0)
 		dbbt->dbbtpages = 1;
 
-	/* write fcb/dbbt */
-	fcb_raw_page = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
-	if (!fcb_raw_page) {
-		debug("failed to allocate fcb_raw_page\n");
-		ret = -ENOMEM;
-		goto dbbt_data_page_err;
-	}
+	/*
+	 * We prepare raw page only for i.MX6, for i.MX7 we
+	 * leverage BCH hw module instead
+	 */
+	if (is_mx6()) {
+		/* write fcb/dbbt */
+		fcb_raw_page = kzalloc(mtd->writesize + mtd->oobsize,
+				       GFP_KERNEL);
+		if (!fcb_raw_page) {
+			debug("failed to allocate fcb_raw_page\n");
+			ret = -ENOMEM;
+			goto dbbt_data_page_err;
+		}
 
 #if defined(CONFIG_MX6UL) || defined(CONFIG_MX6ULL)
-	/* 40 bit BCH, for i.MX6UL(L) */
-	encode_bch_ecc(fcb_raw_page + 32, fcb, 40);
+		/* 40 bit BCH, for i.MX6UL(L) */
+		encode_bch_ecc(fcb_raw_page + 32, fcb, 40);
 #else
-	memcpy(fcb_raw_page + 12, fcb, sizeof(struct fcb_block));
-	encode_hamming_13_8(fcb_raw_page + 12, fcb_raw_page + 12 + 512, 512);
+		memcpy(fcb_raw_page + 12, fcb, sizeof(struct fcb_block));
+		encode_hamming_13_8(fcb_raw_page + 12,
+				    fcb_raw_page + 12 + 512, 512);
 #endif
-	/*
-	 * Set the first and second byte of OOB data to 0xFF, not 0x00. These
-	 * bytes are used as the Manufacturers Bad Block Marker (MBBM). Since
-	 * the FCB is mostly written to the first page in a block, a scan for
-	 * factory bad blocks will detect these blocks as bad, e.g. when
-	 * function nand_scan_bbt() is executed to build a new bad block table.
-	 */
-	memset(fcb_raw_page + mtd->writesize, 0xFF, 2);
-
+		/*
+		 * Set the first and second byte of OOB data to 0xFF,
+		 * not 0x00. These bytes are used as the Manufacturers Bad
+		 * Block Marker (MBBM). Since the FCB is mostly written to
+		 * the first page in a block, a scan for
+		 * factory bad blocks will detect these blocks as bad, e.g.
+		 * when function nand_scan_bbt() is executed to build a new
+		 * bad block table.
+		 */
+		memset(fcb_raw_page + mtd->writesize, 0xFF, 2);
+	}
 	for (i = 0; i < nr_blks_fcb; i++) {
 		if (mtd_block_isbad(mtd, off)) {
 			printf("Block %d is bad, skipped\n", i);
 			continue;
 		}
 
-		/* raw write */
-		mtd_oob_ops_t ops = {
-			.datbuf = (u8 *)fcb_raw_page,
-			.oobbuf = ((u8 *)fcb_raw_page) + mtd->writesize,
-			.len = mtd->writesize,
-			.ooblen = mtd->oobsize,
-			.mode = MTD_OPS_RAW
-		};
-
-		ret = mtd_write_oob(mtd, mtd->erasesize * i, &ops);
-		if (ret)
-			goto fcb_raw_page_err;
-		debug("NAND fcb write: 0x%x offset, 0x%x bytes written: %s\n",
-		      mtd->erasesize * i, ops.len, ret ? "ERROR" : "OK");
+		/*
+		 * User BCH ECC hardware module for i.MX7
+		 */
+		if (is_mx7()) {
+			u32 off = i * mtd->erasesize;
+			size_t rwsize = sizeof(*fcb);
+
+			printf("Writing %d bytes to 0x%x: ", rwsize, off);
+
+			/* switch nand BCH to FCB compatible settings */
+			mxs_nand_mode_fcb(mtd);
+			ret = nand_write(mtd, off, &rwsize,
+					 (unsigned char *)fcb);
+			mxs_nand_mode_normal(mtd);
+
+			printf("%s\n", ret ? "ERROR" : "OK");
+		} else if (is_mx6()) {
+			/* raw write */
+			mtd_oob_ops_t ops = {
+				.datbuf = (u8 *)fcb_raw_page,
+				.oobbuf = ((u8 *)fcb_raw_page) +
+					  mtd->writesize,
+				.len = mtd->writesize,
+				.ooblen = mtd->oobsize,
+				.mode = MTD_OPS_RAW
+			};
+
+			ret = mtd_write_oob(mtd, mtd->erasesize * i, &ops);
+			if (ret)
+				goto fcb_raw_page_err;
+			debug("NAND fcb write: 0x%x offset 0x%x written: %s\n",
+			      mtd->erasesize * i, ops.len, ret ?
+			      "ERROR" : "OK");
+		}
 
 		ret = mtd_write(mtd, mtd->erasesize * i + mtd->writesize,
 				mtd->writesize, &dummy, dbbt_page);
@@ -352,7 +396,8 @@ static int nandbcb_update(struct mtd_info *mtd, loff_t off, size_t size,
 	}
 
 fcb_raw_page_err:
-	kfree(fcb_raw_page);
+	if (is_mx6())
+		kfree(fcb_raw_page);
 dbbt_data_page_err:
 	kfree(dbbt_data_page);
 dbbt_page_err:
-- 
2.17.1



More information about the U-Boot mailing list