Message ID | 20191021133859.23824-4-igor.opaniuk@gmail.com |
---|---|
State | Changes Requested |
Delegated to: | Stefano Babic |
Headers | show |
Series | imx: nandbcb: support for i.MX7 and bcb only updates | expand |
On Mon, Oct 21, 2019 at 4:40 PM Igor Opaniuk <igor.opaniuk@gmail.com> wrote: > > 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> Reviewed-by: Oleksandr Suvorov <oleksandr.suvorov@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 | 129 +++++++++++++------- > 3 files changed, 100 insertions(+), 43 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 b0b9d2c070..c22e8f51b4 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/cmd_nandbcb.c b/arch/arm/mach-imx/cmd_nandbcb.c > index 7811c61d22..aae2cc82f3 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: > -- > 2.17.1 > > _______________________________________________ > U-Boot mailing list > U-Boot@lists.denx.de > https://lists.denx.de/listinfo/u-boot
On Mon, 2019-10-21 at 16:38 +0300, Igor Opaniuk wrote: > 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/cmd_nandbcb.c | 129 +++++++++++++------- > 3 files changed, 100 insertions(+), 43 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 b0b9d2c070..c22e8f51b4 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/cmd_nandbcb.c b/arch/arm/mach-imx/cmd_nandbcb.c > index 7811c61d22..aae2cc82f3 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; The user space tool imx-kobs aligns this to the beginning of the NAND block immediately following the last fcb instance. If we want to hardcode I propose to set it to the page number of the first page of the block immediately following the fcb. I.e. to 2 * (mtd->erasesize / mtd->writesize) Note that the code which does write the dbbt also assumes a hardcoded '1' here, so any change here requires a change also further below. I added a comment. On a Colibri iMX6ULL/iMX7 we actually use page 1 for device information which then conflicts with the dbbt. > @@ -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, This assumes a hardcoded 'fcb->dbbt_start = 1;' but it should be start at 'mtd->erasesize * i + mtd->writesize * fcb->dbbt_start' With the hardcoded dbbt_start fixed: Tested-by: Max Krummenacher <max.krummenacher@toradex.com> Regards Max > 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:
Hi Igor, On 21/10/19 15:38, Igor Opaniuk wrote: > 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> > --- > Patch conflicts with the one for i.MX6UL, that I have currently applied (you see it on -next branch). Could you please rebase on it and resend ? Thanks ! Regards, Stefano > arch/arm/include/asm/mach-imx/imx-nandbcb.h | 12 ++ > arch/arm/mach-imx/Kconfig | 2 +- > arch/arm/mach-imx/cmd_nandbcb.c | 129 +++++++++++++------- > 3 files changed, 100 insertions(+), 43 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 b0b9d2c070..c22e8f51b4 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/cmd_nandbcb.c b/arch/arm/mach-imx/cmd_nandbcb.c > index 7811c61d22..aae2cc82f3 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: >
HI Stefano, On Sun, Nov 3, 2019 at 2:55 PM Stefano Babic <sbabic@denx.de> wrote: > > Hi Igor, > > On 21/10/19 15:38, Igor Opaniuk wrote: > > 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> > > --- > > > > Patch conflicts with the one for i.MX6UL, that I have currently applied > (you see it on -next branch). Could you please rebase on it and resend ? > Thanks ! Done, please check v3 here [1] Thanks [1] https://patchwork.ozlabs.org/project/uboot/list/?series=140330 > > Regards, > Stefano > > > arch/arm/include/asm/mach-imx/imx-nandbcb.h | 12 ++ > > arch/arm/mach-imx/Kconfig | 2 +- > > arch/arm/mach-imx/cmd_nandbcb.c | 129 +++++++++++++------- > > 3 files changed, 100 insertions(+), 43 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 b0b9d2c070..c22e8f51b4 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/cmd_nandbcb.c b/arch/arm/mach-imx/cmd_nandbcb.c > > index 7811c61d22..aae2cc82f3 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: > > > > > -- > ===================================================================== > DENX Software Engineering GmbH, Managing Director: Wolfgang Denk > HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany > Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sbabic@denx.de > =====================================================================
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 b0b9d2c070..c22e8f51b4 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/cmd_nandbcb.c b/arch/arm/mach-imx/cmd_nandbcb.c index 7811c61d22..aae2cc82f3 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: