summaryrefslogtreecommitdiff
path: root/drivers/mtd
diff options
context:
space:
mode:
authorPeter Tyser <ptyser@xes-inc.com>2015-02-03 11:58:12 -0600
committerScott Wood <scottwood@freescale.com>2015-03-30 23:24:38 -0500
commit59b5a2ad83dfefae75011a839e94d4880ff02933 (patch)
treef8e8795000de7c524b3e042a1d6318038bf3e6b7 /drivers/mtd
parent800772a1a6530c31509d65d8e9672fe209a35066 (diff)
downloadu-boot-imx-59b5a2ad83dfefae75011a839e94d4880ff02933.zip
u-boot-imx-59b5a2ad83dfefae75011a839e94d4880ff02933.tar.gz
u-boot-imx-59b5a2ad83dfefae75011a839e94d4880ff02933.tar.bz2
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 <ptyser@xes-inc.com> Tested-by: Heiko Schocher <hs@denx.de> Acked-by: Heiko Schocher <hs@denx.de>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/nand/nand_util.c97
1 files changed, 96 insertions, 1 deletions
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;
}