diff mbox series

[U-Boot,RFC,v1,3/5] imx: nandbcb: add support for i.MX7

Message ID 20190911090535.21905-4-igor.opaniuk@gmail.com
State RFC
Delegated to: Stefano Babic
Headers show
Series imx: nandbcb: support for i.MX7 and bcb only updates | expand

Commit Message

Igor Opaniuk Sept. 11, 2019, 9:05 a.m. UTC
From: Igor Opaniuk <igor.opaniuk@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@toradex.com>
---

 arch/arm/include/asm/mach-imx/imx-nandbcb.h |  12 ++
 arch/arm/mach-imx/Kconfig                   |   2 +-
 arch/arm/mach-imx/Makefile                  |   1 +
 arch/arm/mach-imx/cmd_nandbcb.c             | 129 +++++++++++++-------
 4 files changed, 101 insertions(+), 43 deletions(-)
diff mbox series

Patch

diff --git a/arch/arm/include/asm/mach-imx/imx-nandbcb.h b/arch/arm/include/asm/mach-imx/imx-nandbcb.h
index 033659a038..37ebd03a42 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;
+#if CONFIG_IS_ENABLED(MX7)
+	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
 };
 
 #endif	/* _IMX_NAND_BCB_H_ */
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index d44f74e474..ee01494e97 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -81,7 +81,7 @@  config CMD_HDMIDETECT
 config CMD_NANDBCB
 	bool "i.MX6 NAND Boot Control Block(BCB) command"
 	depends on NAND && CMD_MTDPARTS
-	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/Makefile b/arch/arm/mach-imx/Makefile
index 08ee52edbf..2c53f76ff8 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -208,3 +208,4 @@  obj-$(CONFIG_MX7) += mx7/
 obj-$(CONFIG_ARCH_MX7ULP) += mx7ulp/
 obj-$(CONFIG_IMX8M) += imx8m/
 obj-$(CONFIG_ARCH_IMX8) += imx8/
+obj-$(CONFIG_CMD_WRITEBCB_MX7) += cmd_writebcb_mx7.o
diff --git a/arch/arm/mach-imx/cmd_nandbcb.c b/arch/arm/mach-imx/cmd_nandbcb.c
index 065b814b2e..b7f651568f 100644
--- a/arch/arm/mach-imx/cmd_nandbcb.c
+++ b/arch/arm/mach-imx/cmd_nandbcb.c
@@ -16,6 +16,7 @@ 
 #include <jffs2/jffs2.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>
@@ -67,26 +68,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;
@@ -98,6 +109,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);
 }
 
@@ -133,6 +147,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;
@@ -223,45 +238,74 @@  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;
-	}
-
-	memcpy(fcb_raw_page + 12, fcb, sizeof(struct fcb_block));
-	encode_hamming_13_8(fcb_raw_page + 12, fcb_raw_page + 12 + 512, 512);
 	/*
-	 * 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.
+	 * We prepare raw page only for i.MX6, for i.MX7 we
+	 * leverage BCH hw module instead
 	 */
-	memset(fcb_raw_page + mtd->writesize, 0xFF, 2);
+	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;
+		}
 
+		memcpy(fcb_raw_page + 12, fcb, sizeof(struct fcb_block));
+		encode_hamming_13_8(fcb_raw_page + 12, fcb_raw_page +
+				    12 + 512, 512);
+		/*
+		 * 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);
@@ -283,7 +327,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: