From 5263a02e8b5034dfe962ed2ce9892a617bac8583 Mon Sep 17 00:00:00 2001 From: Luca Ellero Date: Tue, 16 Dec 2014 15:36:14 +0100 Subject: mtd: nand: mxs: fix PIO_WORDs in mxs_nand_read_buf() There is only one pio_word in this DMA transaction so data field must be 1. Signed-off-by: Luca Ellero --- drivers/mtd/nand/mxs_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/mxs_nand.c b/drivers/mtd/nand/mxs_nand.c index 7a064ab..8c6954b 100644 --- a/drivers/mtd/nand/mxs_nand.c +++ b/drivers/mtd/nand/mxs_nand.c @@ -453,7 +453,7 @@ static void mxs_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int length) d->cmd.data = MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_IRQ | MXS_DMA_DESC_NAND_WAIT_4_READY | MXS_DMA_DESC_DEC_SEM | - MXS_DMA_DESC_WAIT4END | (4 << MXS_DMA_DESC_PIO_WORDS_OFFSET); + MXS_DMA_DESC_WAIT4END | (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET); d->cmd.address = 0; -- cgit v1.1 From 88a2cbb2aeb34c7c91f7cd30b59066368063bd07 Mon Sep 17 00:00:00 2001 From: Luca Ellero Date: Tue, 16 Dec 2014 15:36:15 +0100 Subject: mtd: nand: mxs: fix PIO_WORDs in mxs_nand_write_buf() There is only one pio_word in this DMA transaction so data field must be 1. Signed-off-by: Luca Ellero --- drivers/mtd/nand/mxs_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/mxs_nand.c b/drivers/mtd/nand/mxs_nand.c index 8c6954b..2d2b938 100644 --- a/drivers/mtd/nand/mxs_nand.c +++ b/drivers/mtd/nand/mxs_nand.c @@ -510,7 +510,7 @@ static void mxs_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, d->cmd.data = MXS_DMA_DESC_COMMAND_DMA_READ | MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM | MXS_DMA_DESC_WAIT4END | - (4 << MXS_DMA_DESC_PIO_WORDS_OFFSET) | + (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET) | (length << MXS_DMA_DESC_BYTES_OFFSET); d->cmd.address = (dma_addr_t)nand_info->data_buf; -- cgit v1.1 From 59b5a2ad83dfefae75011a839e94d4880ff02933 Mon Sep 17 00:00:00 2001 From: Peter Tyser Date: Tue, 3 Feb 2015 11:58:12 -0600 Subject: nand: Add verification functions Add nand_verify() and nand_verify_page_oob(). nand_verify() verifies NAND contents against an arbitrarily sized buffer using ECC while nand_verify_page_oob() verifies a NAND page's contents and OOB. Signed-off-by: Peter Tyser Tested-by: Heiko Schocher Acked-by: Heiko Schocher --- drivers/mtd/nand/nand_util.c | 97 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index afdd160..f487756 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -464,6 +464,87 @@ static size_t drop_ffs(const nand_info_t *nand, const u_char *buf, #endif /** + * nand_verify_page_oob: + * + * Verify a page of NAND flash, including the OOB. + * Reads page of NAND and verifies the contents and OOB against the + * values in ops. + * + * @param nand NAND device + * @param ops MTD operations, including data to verify + * @param ofs offset in flash + * @return 0 in case of success + */ +int nand_verify_page_oob(nand_info_t *nand, struct mtd_oob_ops *ops, loff_t ofs) +{ + int rval; + struct mtd_oob_ops vops; + size_t verlen = nand->writesize + nand->oobsize; + + memcpy(&vops, ops, sizeof(vops)); + + vops.datbuf = malloc(verlen); + + if (!vops.datbuf) + return -ENOMEM; + + vops.oobbuf = vops.datbuf + nand->writesize; + + rval = mtd_read_oob(nand, ofs, &vops); + if (!rval) + rval = memcmp(ops->datbuf, vops.datbuf, vops.len); + if (!rval) + rval = memcmp(ops->oobbuf, vops.oobbuf, vops.ooblen); + + free(vops.datbuf); + + return rval ? -EIO : 0; +} + +/** + * nand_verify: + * + * Verify a region of NAND flash. + * Reads NAND in page-sized chunks and verifies the contents against + * the contents of a buffer. The offset into the NAND must be + * page-aligned, and the function doesn't handle skipping bad blocks. + * + * @param nand NAND device + * @param ofs offset in flash + * @param len buffer length + * @param buf buffer to read from + * @return 0 in case of success + */ +int nand_verify(nand_info_t *nand, loff_t ofs, size_t len, u_char *buf) +{ + int rval = 0; + size_t verofs; + size_t verlen = nand->writesize; + uint8_t *verbuf = malloc(verlen); + + if (!verbuf) + return -ENOMEM; + + /* Read the NAND back in page-size groups to limit malloc size */ + for (verofs = ofs; verofs < ofs + len; + verofs += verlen, buf += verlen) { + verlen = min(nand->writesize, (uint32_t)(ofs + len - verofs)); + rval = nand_read(nand, verofs, &verlen, verbuf); + if (!rval || (rval == -EUCLEAN)) + rval = memcmp(buf, verbuf, verlen); + + if (rval) + break; + } + + free(verbuf); + + return rval ? -EIO : 0; +} + + + +/** * nand_write_skip_bad: * * Write image to NAND flash. @@ -501,7 +582,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, #ifdef CONFIG_CMD_NAND_YAFFS if (flags & WITH_YAFFS_OOB) { - if (flags & ~WITH_YAFFS_OOB) + if (flags & (~WITH_YAFFS_OOB & ~WITH_WR_VERIFY)) return -EINVAL; int pages; @@ -554,6 +635,10 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, if (!need_skip && !(flags & WITH_DROP_FFS)) { rval = nand_write(nand, offset, length, buffer); + + if ((flags & WITH_WR_VERIFY) && !rval) + rval = nand_verify(nand, offset, *length, buffer); + if (rval == 0) return 0; @@ -601,6 +686,11 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, ops.oobbuf = ops.datbuf + pagesize; rval = mtd_write_oob(nand, offset, &ops); + + if ((flags & WITH_WR_VERIFY) && !rval) + rval = nand_verify_page_oob(nand, + &ops, offset); + if (rval != 0) break; @@ -620,6 +710,11 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, rval = nand_write(nand, offset, &truncated_write_size, p_buffer); + + if ((flags & WITH_WR_VERIFY) && !rval) + rval = nand_verify(nand, offset, + truncated_write_size, p_buffer); + offset += write_size; p_buffer += write_size; } -- cgit v1.1 From 9ac71f112eb3cffc42e012fcdf5009e5b3b01a1d Mon Sep 17 00:00:00 2001 From: Peter Tyser Date: Tue, 3 Feb 2015 11:58:14 -0600 Subject: dfu: nand: Verify writes Previously NAND writes were not verified and could fail silently. Add a verification step after all writes to NAND. Signed-off-by: Peter Tyser Reviewed-by: Lukasz Majewski Tested-by: Heiko Schocher Acked-by: Heiko Schocher --- drivers/dfu/dfu_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dfu/dfu_nand.c b/drivers/dfu/dfu_nand.c index f9ee189..a975492 100644 --- a/drivers/dfu/dfu_nand.c +++ b/drivers/dfu/dfu_nand.c @@ -64,7 +64,7 @@ static int nand_block_op(enum dfu_op op, struct dfu_entity *dfu, return ret; /* then write */ ret = nand_write_skip_bad(nand, start, &count, &actual, - lim, buf, 0); + lim, buf, WITH_WR_VERIFY); } if (ret != 0) { -- cgit v1.1 From 073adf987e8251ad934fcac4fd1bf20d4f34f96e Mon Sep 17 00:00:00 2001 From: Peter Tyser Date: Tue, 3 Feb 2015 11:58:15 -0600 Subject: nand: Remove CONFIG_MTD_NAND_VERIFY_WRITE The CONFIG_MTD_NAND_VERIFY_WRITE has been removed from Linux for some time and a more generic method of NAND verification now exists in U-Boot. Signed-off-by: Peter Tyser Tested-by: Heiko Schocher Acked-by: Heiko Schocher --- drivers/mtd/nand/davinci_nand.c | 12 -------- drivers/mtd/nand/fsl_elbc_nand.c | 38 ----------------------- drivers/mtd/nand/fsl_ifc_nand.c | 38 ----------------------- drivers/mtd/nand/fsl_upm.c | 18 ----------- drivers/mtd/nand/mpc5121_nfc.c | 26 ---------------- drivers/mtd/nand/mxc_nand.c | 33 -------------------- drivers/mtd/nand/nand_base.c | 65 ---------------------------------------- drivers/mtd/nand/ndfc.c | 18 ----------- 8 files changed, 248 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 41689b5..a397074 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -405,18 +405,6 @@ static int nand_davinci_write_page(struct mtd_info *mtd, struct nand_chip *chip, goto err; } -#ifdef CONFIG_MTD_NAND_VERIFY_WRITE - /* Send command to read back the data */ - chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); - - if (chip->verify_buf(mtd, buf, mtd->writesize)) { - ret = -EIO; - goto err; - } - - /* Make sure the next page prog is preceded by a status read */ - chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); -#endif err: /* restore ECC layout */ if (page < CONFIG_KEYSTONE_NAND_MAX_RBL_PAGE) { diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 3372b64..e85832d 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -561,41 +561,6 @@ static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len) len, avail); } -#if defined(CONFIG_MTD_NAND_VERIFY_WRITE) -/* - * Verify buffer against the FCM Controller Data Buffer - */ -static int fsl_elbc_verify_buf(struct mtd_info *mtd, - const u_char *buf, int len) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; - int i; - - if (len < 0) { - printf("write_buf of %d bytes", len); - return -EINVAL; - } - - if ((unsigned int)len > ctrl->read_bytes - ctrl->index) { - printf("verify_buf beyond end of buffer " - "(%d requested, %u available)\n", - len, ctrl->read_bytes - ctrl->index); - - ctrl->index = ctrl->read_bytes; - return -EINVAL; - } - - for (i = 0; i < len; i++) - if (in_8(&ctrl->addr[ctrl->index + i]) != buf[i]) - break; - - ctrl->index += len; - return i == len && ctrl->status == LTESR_CC ? 0 : -EIO; -} -#endif - /* This function is called after Program and Erase Operations to * check for success or failure. */ @@ -727,9 +692,6 @@ static int fsl_elbc_chip_init(int devnum, u8 *addr) nand->read_byte = fsl_elbc_read_byte; nand->write_buf = fsl_elbc_write_buf; nand->read_buf = fsl_elbc_read_buf; -#if defined(CONFIG_MTD_NAND_VERIFY_WRITE) - nand->verify_buf = fsl_elbc_verify_buf; -#endif nand->select_chip = fsl_elbc_select_chip; nand->cmdfunc = fsl_elbc_cmdfunc; nand->waitfunc = fsl_elbc_wait; diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index b283eae..7903eeb 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -683,41 +683,6 @@ static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len) __func__, len, avail); } -#if defined(CONFIG_MTD_NAND_VERIFY_WRITE) -/* - * Verify buffer against the IFC Controller Data Buffer - */ -static int fsl_ifc_verify_buf(struct mtd_info *mtd, - const u_char *buf, int len) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_ifc_mtd *priv = chip->priv; - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - int i; - - if (len < 0) { - printf("%s of %d bytes", __func__, len); - return -EINVAL; - } - - if ((unsigned int)len > ctrl->read_bytes - ctrl->index) { - printf("%s beyond end of buffer " - "(%d requested, %u available)\n", - __func__, len, ctrl->read_bytes - ctrl->index); - - ctrl->index = ctrl->read_bytes; - return -EINVAL; - } - - for (i = 0; i < len; i++) - if (in_8(&ctrl->addr[ctrl->index + i]) != buf[i]) - break; - - ctrl->index += len; - return i == len && ctrl->status == IFC_NAND_EVTER_STAT_OPC ? 0 : -EIO; -} -#endif - /* This function is called after Program and Erase Operations to * check for success or failure. */ @@ -940,9 +905,6 @@ static int fsl_ifc_chip_init(int devnum, u8 *addr) nand->write_buf = fsl_ifc_write_buf; nand->read_buf = fsl_ifc_read_buf; -#if defined(CONFIG_MTD_NAND_VERIFY_WRITE) - nand->verify_buf = fsl_ifc_verify_buf; -#endif nand->select_chip = fsl_ifc_select_chip; nand->cmdfunc = fsl_ifc_cmdfunc; nand->waitfunc = fsl_ifc_wait; diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index 65ce98a..5426c32 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -153,21 +153,6 @@ static void upm_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) buf[i] = in_8(chip->IO_ADDR_R); } -#if defined(CONFIG_MTD_NAND_VERIFY_WRITE) -static int upm_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) -{ - int i; - struct nand_chip *chip = mtd->priv; - - for (i = 0; i < len; i++) { - if (buf[i] != in_8(chip->IO_ADDR_R)) - return -EFAULT; - } - - return 0; -} -#endif - static int nand_dev_ready(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; @@ -193,9 +178,6 @@ int fsl_upm_nand_init(struct nand_chip *chip, struct fsl_upm_nand *fun) chip->read_byte = upm_nand_read_byte; chip->read_buf = upm_nand_read_buf; chip->write_buf = upm_nand_write_buf; -#if defined(CONFIG_MTD_NAND_VERIFY_WRITE) - chip->verify_buf = upm_nand_verify_buf; -#endif if (fun->dev_ready) chip->dev_ready = nand_dev_ready; diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index 7233bfc..e621c36 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -459,29 +459,6 @@ static void mpc5121_nfc_write_buf(struct mtd_info *mtd, mpc5121_nfc_buf_copy(mtd, (u_char *) buf, len, 1); } -#if defined(CONFIG_MTD_NAND_VERIFY_WRITE) -/* Compare buffer with NAND flash */ -static int mpc5121_nfc_verify_buf(struct mtd_info *mtd, - const u_char * buf, int len) -{ - u_char tmp[256]; - uint bsize; - - while (len) { - bsize = min(len, 256); - mpc5121_nfc_read_buf(mtd, tmp, bsize); - - if (memcmp(buf, tmp, bsize)) - return 1; - - buf += bsize; - len -= bsize; - } - - return 0; -} -#endif - /* Read byte from NFC buffers */ static u8 mpc5121_nfc_read_byte(struct mtd_info *mtd) { @@ -609,9 +586,6 @@ int board_nand_init(struct nand_chip *chip) chip->read_word = mpc5121_nfc_read_word; chip->read_buf = mpc5121_nfc_read_buf; chip->write_buf = mpc5121_nfc_write_buf; -#if defined(CONFIG_MTD_NAND_VERIFY_WRITE) - chip->verify_buf = mpc5121_nfc_verify_buf; -#endif chip->select_chip = mpc5121_nfc_select_chip; chip->bbt_options = NAND_BBT_USE_FLASH; chip->ecc.mode = NAND_ECC_SOFT; diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 2e5b5b9..f12b07e 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -949,34 +949,6 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) host->col_addr = col; } -#ifdef __UBOOT__ -#if defined(CONFIG_MTD_NAND_VERIFY_WRITE) -/* - * Used by the upper layer to verify the data in NAND Flash - * with the data in the buf. - */ -static int mxc_nand_verify_buf(struct mtd_info *mtd, - const u_char *buf, int len) -{ - u_char tmp[256]; - uint bsize; - - while (len) { - bsize = min(len, 256); - mxc_nand_read_buf(mtd, tmp, bsize); - - if (memcmp(buf, tmp, bsize)) - return 1; - - buf += bsize; - len -= bsize; - } - - return 0; -} -#endif -#endif - /* * This function is used by upper layer for select and * deselect of the NAND chip @@ -1207,11 +1179,6 @@ int board_nand_init(struct nand_chip *this) this->read_word = mxc_nand_read_word; this->write_buf = mxc_nand_write_buf; this->read_buf = mxc_nand_read_buf; -#ifdef __UBOOT__ -#if defined(CONFIG_MTD_NAND_VERIFY_WRITE) - this->verify_buf = mxc_nand_verify_buf; -#endif -#endif host->regs = (struct mxc_nand_regs __iomem *)CONFIG_MXC_NAND_REGS_BASE; #ifdef MXC_NFC_V3_2 diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 6db6566..c0e381a 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -361,51 +361,6 @@ void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) ioread8_rep(chip->IO_ADDR_R, buf, len); } -#ifdef __UBOOT__ -#if defined(CONFIG_MTD_NAND_VERIFY_WRITE) -/** - * nand_verify_buf - [DEFAULT] Verify chip data against buffer - * @mtd: MTD device structure - * @buf: buffer containing the data to compare - * @len: number of bytes to compare - * - * Default verify function for 8bit buswidth. - */ -static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) -{ - int i; - struct nand_chip *chip = mtd->priv; - - for (i = 0; i < len; i++) - if (buf[i] != readb(chip->IO_ADDR_R)) - return -EFAULT; - return 0; -} - -/** - * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer - * @mtd: MTD device structure - * @buf: buffer containing the data to compare - * @len: number of bytes to compare - * - * Default verify function for 16bit buswidth. - */ -static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) -{ - int i; - struct nand_chip *chip = mtd->priv; - u16 *p = (u16 *) buf; - len >>= 1; - - for (i = 0; i < len; i++) - if (p[i] != readw(chip->IO_ADDR_R)) - return -EFAULT; - - return 0; -} -#endif -#endif - /** * nand_write_buf16 - [DEFAULT] write buffer to chip * @mtd: MTD device structure @@ -2435,20 +2390,6 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, status = chip->waitfunc(mtd, chip); } - -#ifdef __UBOOT__ -#if defined(CONFIG_MTD_NAND_VERIFY_WRITE) - /* Send command to read back the data */ - chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); - - if (chip->verify_buf(mtd, buf, mtd->writesize)) - return -EIO; - - /* Make sure the next page prog is preceded by a status read */ - chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); -#endif -#endif - return 0; } @@ -3139,12 +3080,6 @@ static void nand_set_defaults(struct nand_chip *chip, int busw) chip->read_buf = busw ? nand_read_buf16 : nand_read_buf; if (!chip->scan_bbt) chip->scan_bbt = nand_default_bbt; -#ifdef __UBOOT__ -#if defined(CONFIG_MTD_NAND_VERIFY_WRITE) - if (!chip->verify_buf) - chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf; -#endif -#endif if (!chip->controller) { chip->controller = &chip->hwcontrol; diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 2659595..8a68cb0 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -118,21 +118,6 @@ static void ndfc_write_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len out_be32((u32 *)(base + NDFC_DATA), *p++); } -#if defined(CONFIG_MTD_NAND_VERIFY_WRITE) -static int ndfc_verify_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len) -{ - struct nand_chip *this = mtdinfo->priv; - ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; - uint32_t *p = (uint32_t *) buf; - - for (; len > 0; len -= 4) - if (*p++ != in_be32((u32 *)(base + NDFC_DATA))) - return -1; - - return 0; -} -#endif - /* * Read a byte from the NDFC. */ @@ -207,9 +192,6 @@ int board_nand_init(struct nand_chip *nand) #endif nand->write_buf = ndfc_write_buf; -#if defined(CONFIG_MTD_NAND_VERIFY_WRITE) - nand->verify_buf = ndfc_verify_buf; -#endif nand->read_byte = ndfc_read_byte; chip++; -- cgit v1.1 From 004a1fdb45fb06ee2faf6e50945ceb79d43a2f41 Mon Sep 17 00:00:00 2001 From: Peter Tyser Date: Tue, 3 Feb 2015 11:58:16 -0600 Subject: nand: yaffs: Remove the "nand write.yaffs" command This command is only enabled by one board, complicates the NAND code, and doesn't appear to have been functioning properly for several years. If there are no bad blocks in the NAND region being written nand_write_skip_bad() will take the shortcut of calling nand_write() which bypasses the special yaffs handling. This causes invalid YAFFS data to be written. See http://lists.denx.de/pipermail/u-boot/2011-September/102830.html for an example and a potential workaround. U-Boot still retains the ability to mount and access YAFFS partitions via CONFIG_YAFFS2. Signed-off-by: Peter Tyser --- drivers/mtd/nand/nand_util.c | 77 +++++++------------------------------------- 1 file changed, 12 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index f487756..12dd26a 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -580,24 +580,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, if (actual) *actual = 0; -#ifdef CONFIG_CMD_NAND_YAFFS - if (flags & WITH_YAFFS_OOB) { - if (flags & (~WITH_YAFFS_OOB & ~WITH_WR_VERIFY)) - return -EINVAL; - - int pages; - pages = nand->erasesize / nand->writesize; - blocksize = (pages * nand->oobsize) + nand->erasesize; - if (*length % (nand->writesize + nand->oobsize)) { - printf("Attempt to write incomplete page" - " in yaffs mode\n"); - return -EINVAL; - } - } else -#endif - { - blocksize = nand->erasesize; - } + blocksize = nand->erasesize; /* * nand_write() handles unaligned, partial page writes. @@ -666,58 +649,22 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, else write_size = blocksize - block_offset; -#ifdef CONFIG_CMD_NAND_YAFFS - if (flags & WITH_YAFFS_OOB) { - int page, pages; - size_t pagesize = nand->writesize; - size_t pagesize_oob = pagesize + nand->oobsize; - struct mtd_oob_ops ops; - - ops.len = pagesize; - ops.ooblen = nand->oobsize; - ops.mode = MTD_OPS_AUTO_OOB; - ops.ooboffs = 0; - - pages = write_size / pagesize_oob; - for (page = 0; page < pages; page++) { - WATCHDOG_RESET(); - - ops.datbuf = p_buffer; - ops.oobbuf = ops.datbuf + pagesize; - - rval = mtd_write_oob(nand, offset, &ops); - - if ((flags & WITH_WR_VERIFY) && !rval) - rval = nand_verify_page_oob(nand, - &ops, offset); - - if (rval != 0) - break; - - offset += pagesize; - p_buffer += pagesize_oob; - } - } - else -#endif - { - truncated_write_size = write_size; + truncated_write_size = write_size; #ifdef CONFIG_CMD_NAND_TRIMFFS - if (flags & WITH_DROP_FFS) - truncated_write_size = drop_ffs(nand, p_buffer, - &write_size); + if (flags & WITH_DROP_FFS) + truncated_write_size = drop_ffs(nand, p_buffer, + &write_size); #endif - rval = nand_write(nand, offset, &truncated_write_size, - p_buffer); + rval = nand_write(nand, offset, &truncated_write_size, + p_buffer); - if ((flags & WITH_WR_VERIFY) && !rval) - rval = nand_verify(nand, offset, - truncated_write_size, p_buffer); + if ((flags & WITH_WR_VERIFY) && !rval) + rval = nand_verify(nand, offset, + truncated_write_size, p_buffer); - offset += write_size; - p_buffer += write_size; - } + offset += write_size; + p_buffer += write_size; if (rval != 0) { printf("NAND write to offset %llx failed %d\n", -- cgit v1.1 From 7653fc288a964ce5bb0cff9176444260731d0f90 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Tue, 24 Mar 2015 17:54:19 +0100 Subject: mtd: vf610_nfc: mark page as dirty on block erase The driver tries to re-use the page buffer by storing the page number of the current page in the buffer. The page is only read if the requested page number is not currently in the buffer. When a block is erased, the page number is marked as invalid if the erased page equals the one currently in the cache. However, since a erase block consists of multiple pages, also other page numbers could be affected. The commands to reproduce this issue (on a written page): > nand dump 0x800 > nand erase 0x0 0x20000 > nand dump 0x800 The second nand dump command returns the data from the buffer, while in fact the page is erased (0xff). Avoid the hassle to calculate whether the page is affected or not, but set the page buffer unconditionally to invalid instead. Signed-off-by: Stefan Agner --- drivers/mtd/nand/vf610_nfc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c index 928d58b..9de971c 100644 --- a/drivers/mtd/nand/vf610_nfc.c +++ b/drivers/mtd/nand/vf610_nfc.c @@ -369,8 +369,7 @@ static void vf610_nfc_command(struct mtd_info *mtd, unsigned command, break; case NAND_CMD_ERASE1: - if (nfc->page == page) - nfc->page = -1; + nfc->page = -1; vf610_nfc_send_commands(nfc->regs, command, NAND_CMD_ERASE2, ERASE_CMD_CODE); vf610_nfc_addr_cycle(mtd, column, page); -- cgit v1.1 From 55765b1842e7dcf22efa8d973c7d1b7498dd99fa Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Tue, 24 Mar 2015 17:54:20 +0100 Subject: mtd: vf610_nfc: specify transfer size before each transfer Testing showed, that commands like STATUS made the buffer dirty when executed with NFC_SECSZ set to the page size. It looks like the controller transfers bogus data when this register is configured. When setting it to 0, the buffer does not get altered while the status command still seems to work flawless. Signed-off-by: Stefan Agner --- drivers/mtd/nand/vf610_nfc.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c index 9de971c..d98dd28 100644 --- a/drivers/mtd/nand/vf610_nfc.c +++ b/drivers/mtd/nand/vf610_nfc.c @@ -146,6 +146,7 @@ struct vf610_nfc { void __iomem *regs; uint column; int spareonly; + int page_sz; int page; /* Status and ID are in alternate locations. */ int alt_buf; @@ -329,6 +330,11 @@ static void vf610_nfc_addr_cycle(struct mtd_info *mtd, int column, int page) ROW_ADDR_SHIFT, page); } +static inline void vf610_nfc_transfer_size(void __iomem *regbase, int size) +{ + __raw_writel(size, regbase + NFC_SECTOR_SIZE); +} + /* Send command to NAND chip */ static void vf610_nfc_command(struct mtd_info *mtd, unsigned command, int column, int page) @@ -342,12 +348,14 @@ static void vf610_nfc_command(struct mtd_info *mtd, unsigned command, switch (command) { case NAND_CMD_PAGEPROG: nfc->page = -1; + vf610_nfc_transfer_size(nfc->regs, nfc->page_sz); vf610_nfc_send_commands(nfc->regs, NAND_CMD_SEQIN, command, PROGRAM_PAGE_CMD_CODE); vf610_nfc_addr_cycle(mtd, column, page); break; case NAND_CMD_RESET: + vf610_nfc_transfer_size(nfc->regs, 0); vf610_nfc_send_command(nfc->regs, command, RESET_CMD_CODE); break; /* @@ -363,6 +371,7 @@ static void vf610_nfc_command(struct mtd_info *mtd, unsigned command, if (nfc->page == page) return; nfc->page = page; + vf610_nfc_transfer_size(nfc->regs, nfc->page_sz); vf610_nfc_send_commands(nfc->regs, NAND_CMD_READ0, NAND_CMD_READSTART, READ_PAGE_CMD_CODE); vf610_nfc_addr_cycle(mtd, column, page); @@ -370,6 +379,7 @@ static void vf610_nfc_command(struct mtd_info *mtd, unsigned command, case NAND_CMD_ERASE1: nfc->page = -1; + vf610_nfc_transfer_size(nfc->regs, 0); vf610_nfc_send_commands(nfc->regs, command, NAND_CMD_ERASE2, ERASE_CMD_CODE); vf610_nfc_addr_cycle(mtd, column, page); @@ -377,11 +387,13 @@ static void vf610_nfc_command(struct mtd_info *mtd, unsigned command, case NAND_CMD_READID: nfc->alt_buf = ALT_BUF_ID; + vf610_nfc_transfer_size(nfc->regs, 0); vf610_nfc_send_command(nfc->regs, command, READ_ID_CMD_CODE); break; case NAND_CMD_STATUS: nfc->alt_buf = ALT_BUF_STAT; + vf610_nfc_transfer_size(nfc->regs, 0); vf610_nfc_send_command(nfc->regs, command, STATUS_READ_CMD_CODE); break; @@ -579,7 +591,6 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr) struct nand_chip *chip; struct vf610_nfc *nfc; int err = 0; - int page_sz; struct vf610_nfc_config cfg = { .hardware_ecc = 1, #ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT @@ -633,9 +644,8 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr) chip->bbt_td = &bbt_main_descr; chip->bbt_md = &bbt_mirror_descr; - page_sz = PAGE_2K + OOB_64; - page_sz += cfg.width == 16 ? 1 : 0; - vf610_nfc_write(mtd, NFC_SECTOR_SIZE, page_sz); + nfc->page_sz = PAGE_2K + OOB_64; + nfc->page_sz += cfg.width == 16 ? 1 : 0; /* Set configuration register. */ vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_ADDR_AUTO_INCR_BIT); @@ -664,16 +674,15 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr) chip->ecc.mode = NAND_ECC_SOFT; /* default */ - page_sz = mtd->writesize + mtd->oobsize; + nfc->page_sz = mtd->writesize + mtd->oobsize; /* Single buffer only, max 256 OOB minus ECC status */ - if (page_sz > PAGE_2K + 256 - 8) { + if (nfc->page_sz > PAGE_2K + 256 - 8) { dev_err(nfc->dev, "Unsupported flash size\n"); err = -ENXIO; goto error; } - page_sz += cfg.width == 16 ? 1 : 0; - vf610_nfc_write(mtd, NFC_SECTOR_SIZE, page_sz); + nfc->page_sz += cfg.width == 16 ? 1 : 0; if (cfg.hardware_ecc) { if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) { -- cgit v1.1