[U-Boot] [RFC 06/11] mtd/nand: Add randomisation layer

Roy Spliet r.spliet at ultimaker.com
Fri Jun 5 13:52:39 CEST 2015


Based on BBrezillons work, minus per-partition support. Changes to support
that would be quite invasive while it hasn't been solved yet for Linux.

Signed-off-by: Roy Spliet <r.spliet at ultimaker.com>
---
 drivers/mtd/nand/nand_base.c | 255 ++++++++++++++++++++++++++++++++++---------
 include/linux/mtd/nand.h     |  96 ++++++++++++++++
 2 files changed, 299 insertions(+), 52 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 83586cc..5196c0c 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1185,6 +1185,62 @@ EXPORT_SYMBOL(nand_lock);
 #endif
 
 /**
+ * nand_rnd_is_activ - check wether a region of a NAND page requires NAND
+ *		       randomizer to be disabled
+ * @mtd:	mtd info
+ * @page:	NAND page
+ * @column:	offset within the page
+ * @len:	len of the region
+ *
+ * Returns 1 if the randomizer should be enabled, 0 if not, or -ERR in case of
+ * error.
+ *
+ * In case of success len will contain the size of the region:
+ *  - if the requested region fits in a NAND random region len will not change
+ *  - else len will be replaced by the available length within the NAND random
+ *    region
+ */
+int nand_rnd_is_activ(struct mtd_info *mtd, int page, int column, int *len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct nand_rnd_layout *layout = chip->rnd.layout;
+	struct nand_rndfree *range;
+	int ret = 1;
+	int tmp;
+	int i;
+
+	if (!len || *len < 0 || column < 0 ||
+	    column + *len > mtd->writesize + mtd->oobsize)
+		return -EINVAL;
+
+	if (layout) {
+		for (i = 0; i < layout->nranges; i++) {
+			range = &layout->ranges[i];
+			if (column + *len <= range->offset) {
+				break;
+			} else if (column >= range->offset + range->length) {
+				continue;
+			} else if (column < range->offset) {
+				tmp = range->offset - column;
+				if (*len > tmp)
+					*len = tmp;
+				break;
+			} else {
+				tmp = range->offset + range->length - column;
+				if (*len > tmp)
+					*len = tmp;
+				ret = 0;
+				break;
+			}
+
+		}
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(nand_rnd_is_activ);
+
+/**
  * nand_page_is_empty - check wether a NAND page contains only FFs
  * @mtd:	mtd info
  * @data:	data buffer
@@ -1329,9 +1385,13 @@ EXPORT_SYMBOL(nand_pst_create);
 static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
 			      uint8_t *buf, int oob_required, int page)
 {
-	chip->read_buf(mtd, buf, mtd->writesize);
-	if (oob_required)
-		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+	nand_rnd_config(mtd, page, 0, NAND_RND_READ);
+	nand_rnd_read_buf(mtd, buf, mtd->writesize);
+	if (oob_required){
+		nand_rnd_config(mtd, page, mtd->writesize, NAND_RND_READ);
+		nand_rnd_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+	}
+	nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
 	return 0;
 }
 
@@ -1352,29 +1412,40 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
 	int eccsize = chip->ecc.size;
 	int eccbytes = chip->ecc.bytes;
 	uint8_t *oob = chip->oob_poi;
-	int steps, size;
+	int steps, size, column = 0;
 
 	for (steps = chip->ecc.steps; steps > 0; steps--) {
-		chip->read_buf(mtd, buf, eccsize);
+		nand_rnd_config(mtd, page, column, NAND_RND_READ);
+		nand_rnd_read_buf(mtd, buf, eccsize);
 		buf += eccsize;
+		column += eccsize;
 
 		if (chip->ecc.prepad) {
-			chip->read_buf(mtd, oob, chip->ecc.prepad);
+			nand_rnd_config(mtd, page, column, NAND_RND_READ);
+			nand_rnd_read_buf(mtd, oob, chip->ecc.prepad);
 			oob += chip->ecc.prepad;
+			column += chip->ecc.prepad;
 		}
 
-		chip->read_buf(mtd, oob, eccbytes);
+		nand_rnd_config(mtd, page, column, NAND_RND_READ);
+		nand_rnd_read_buf(mtd, oob, eccbytes);
 		oob += eccbytes;
+		column += eccbytes;
 
 		if (chip->ecc.postpad) {
-			chip->read_buf(mtd, oob, chip->ecc.postpad);
+			nand_rnd_config(mtd, page, column, NAND_RND_READ);
+			nand_rnd_read_buf(mtd, oob, chip->ecc.postpad);
 			oob += chip->ecc.postpad;
+			column += chip->ecc.postpad;
 		}
 	}
 
 	size = mtd->oobsize - (oob - chip->oob_poi);
-	if (size)
-		chip->read_buf(mtd, oob, size);
+	if (size) {
+		nand_rnd_config(mtd, page, column, NAND_RND_READ);
+		nand_rnd_read_buf(mtd, oob, size);
+	}
+	nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
 
 	return 0;
 }
@@ -1462,7 +1533,8 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
 		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1);
 
 	p = bufpoi + data_col_addr;
-	chip->read_buf(mtd, p, datafrag_len);
+	nand_rnd_config(mtd, -1, data_col_addr, NAND_RND_READ);
+	nand_rnd_read_buf(mtd, p, datafrag_len);
 
 	/* Calculate ECC */
 	for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size)
@@ -1481,7 +1553,8 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
 	}
 	if (gaps) {
 		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
-		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+		nand_rnd_config(mtd, -1, mtd->writesize, NAND_RND_READ);
+		nand_rnd_read_buf(mtd, chip->oob_poi, mtd->oobsize);
 	} else {
 		/*
 		 * Send the command to read the particular ECC bytes take care
@@ -1496,7 +1569,8 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
 
 		chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
 					mtd->writesize + aligned_pos, -1);
-		chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len);
+		nand_rnd_config(mtd, -1, mtd->writesize + aligned_pos, NAND_RND_READ);
+		nand_rnd_read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len);
 	}
 
 	for (i = 0; i < eccfrag_len; i++)
@@ -1515,6 +1589,8 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
 			max_bitflips = max_t(unsigned int, max_bitflips, stat);
 		}
 	}
+	nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
+
 	return max_bitflips;
 }
 
@@ -1539,13 +1615,17 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 	uint8_t *ecc_code = chip->buffers->ecccode;
 	uint32_t *eccpos = chip->ecc.layout->eccpos;
 	unsigned int max_bitflips = 0;
+	int column = 0;
 
 	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
 		chip->ecc.hwctl(mtd, NAND_ECC_READ);
-		chip->read_buf(mtd, p, eccsize);
+		nand_rnd_config(mtd, page, column, NAND_RND_READ);
+		nand_rnd_read_buf(mtd, p, eccsize);
 		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+		column += eccsize;
 	}
-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+	nand_rnd_config(mtd, page, column, NAND_RND_READ);
+	nand_rnd_read_buf(mtd, chip->oob_poi, mtd->oobsize);
 
 	for (i = 0; i < chip->ecc.total; i++)
 		ecc_code[i] = chip->oob_poi[eccpos[i]];
@@ -1564,6 +1644,8 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 			max_bitflips = max_t(unsigned int, max_bitflips, stat);
 		}
 	}
+	nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
+
 	return max_bitflips;
 }
 
@@ -1592,11 +1674,14 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
 	uint32_t *eccpos = chip->ecc.layout->eccpos;
 	uint8_t *ecc_calc = chip->buffers->ecccalc;
 	unsigned int max_bitflips = 0;
+	int column = 0;
 
 	/* Read the OOB area first */
 	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+	nand_rnd_config(mtd, page, mtd->writesize, NAND_RND_READ);
+	nand_rnd_read_buf(mtd, chip->oob_poi, mtd->oobsize);
 	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+	column = 0;
 
 	for (i = 0; i < chip->ecc.total; i++)
 		ecc_code[i] = chip->oob_poi[eccpos[i]];
@@ -1605,7 +1690,8 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
 		int stat;
 
 		chip->ecc.hwctl(mtd, NAND_ECC_READ);
-		chip->read_buf(mtd, p, eccsize);
+		nand_rnd_config(mtd, page, column, NAND_RND_READ);
+		nand_rnd_read_buf(mtd, p, eccsize);
 		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
 
 		stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
@@ -1616,6 +1702,8 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
 			max_bitflips = max_t(unsigned int, max_bitflips, stat);
 		}
 	}
+	nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
+
 	return max_bitflips;
 }
 
@@ -1639,20 +1727,26 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
 	uint8_t *p = buf;
 	uint8_t *oob = chip->oob_poi;
 	unsigned int max_bitflips = 0;
+	int column = 0;
 
 	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
 		int stat;
 
 		chip->ecc.hwctl(mtd, NAND_ECC_READ);
-		chip->read_buf(mtd, p, eccsize);
+		nand_rnd_config(mtd, page, column, NAND_RND_READ);
+		nand_rnd_read_buf(mtd, p, eccsize);
+		column += eccsize;
 
 		if (chip->ecc.prepad) {
-			chip->read_buf(mtd, oob, chip->ecc.prepad);
+			nand_rnd_config(mtd, page, column, NAND_RND_READ);
+			nand_rnd_read_buf(mtd, oob, chip->ecc.prepad);
 			oob += chip->ecc.prepad;
 		}
 
 		chip->ecc.hwctl(mtd, NAND_ECC_READSYN);
-		chip->read_buf(mtd, oob, eccbytes);
+		nand_rnd_config(mtd, page, column, NAND_RND_READ);
+		nand_rnd_read_buf(mtd, oob, eccbytes);
+		column += eccbytes;
 		stat = chip->ecc.correct(mtd, p, oob, NULL);
 
 		if (stat < 0) {
@@ -1665,15 +1759,20 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
 		oob += eccbytes;
 
 		if (chip->ecc.postpad) {
-			chip->read_buf(mtd, oob, chip->ecc.postpad);
+			nand_rnd_config(mtd, page, column, NAND_RND_READ);
+			nand_rnd_read_buf(mtd, oob, chip->ecc.postpad);
+			column += chip->ecc.postpad;
 			oob += chip->ecc.postpad;
 		}
 	}
 
 	/* Calculate remaining oob bytes */
 	i = mtd->oobsize - (oob - chip->oob_poi);
-	if (i)
-		chip->read_buf(mtd, oob, i);
+	if (i) {
+		nand_rnd_config(mtd, page, column, NAND_RND_READ);
+		nand_rnd_read_buf(mtd, oob, i);
+	}
+	nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
 
 	return max_bitflips;
 }
@@ -1685,9 +1784,11 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
  * @ops: oob ops structure
  * @len: size of oob to transfer
  */
-static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
+static uint8_t *nand_transfer_oob(struct mtd_info *mtd, uint8_t *oob,
 				  struct mtd_oob_ops *ops, size_t len)
 {
+	struct nand_chip *chip = mtd->priv;
+
 	switch (ops->mode) {
 
 	case MTD_OPS_PLACE_OOB:
@@ -1804,6 +1905,7 @@ read_retry:
 			 * Now read the page into the buffer.  Absent an error,
 			 * the read methods return max bitflips per ecc step.
 			 */
+			nand_rnd_config(mtd, page, -1, NAND_RND_READ);
 			if (unlikely(ops->mode == MTD_OPS_RAW))
 				ret = chip->ecc.read_page_raw(mtd, chip, bufpoi,
 							      oob_required,
@@ -1816,6 +1918,8 @@ read_retry:
 			else
 				ret = chip->ecc.read_page(mtd, chip, bufpoi,
 							  oob_required, page);
+			nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
+
 			if (ret < 0) {
 				if (!aligned)
 					/* Invalidate page cache */
@@ -1843,7 +1947,7 @@ read_retry:
 				int toread = min(oobreadlen, max_oobsize);
 
 				if (toread) {
-					oob = nand_transfer_oob(chip,
+					oob = nand_transfer_oob(mtd,
 						oob, ops, toread);
 					oobreadlen -= toread;
 				}
@@ -1960,7 +2064,9 @@ static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
 			     int page)
 {
 	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+	nand_rnd_config(mtd, page, mtd->writesize, NAND_RND_READ);
+	nand_rnd_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+	nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
 	return 0;
 }
 
@@ -1979,7 +2085,7 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
 	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
 	int eccsize = chip->ecc.size;
 	uint8_t *bufpoi = buf;
-	int i, toread, sndrnd = 0, pos;
+	int i, toread, sndrnd = 0, pos = eccsize;
 
 	chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page);
 	for (i = 0; i < chip->ecc.steps; i++) {
@@ -1992,12 +2098,17 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
 		} else
 			sndrnd = 1;
 		toread = min_t(int, length, chunk);
-		chip->read_buf(mtd, bufpoi, toread);
+		nand_rnd_config(mtd, page, pos, NAND_RND_READ);
+		nand_rnd_read_buf(mtd, bufpoi, toread);
 		bufpoi += toread;
 		length -= toread;
 	}
-	if (length > 0)
-		chip->read_buf(mtd, bufpoi, length);
+	if (length > 0){
+		pos = mtd->writesize + mtd->oobsize - length;
+		nand_rnd_config(mtd, page, pos, NAND_RND_READ);
+		nand_rnd_read_buf(mtd, bufpoi, length);
+	}
+	nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
 
 	return 0;
 }
@@ -2016,7 +2127,9 @@ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
 	int length = mtd->oobsize;
 
 	chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
-	chip->write_buf(mtd, buf, length);
+	nand_rnd_config(mtd, page, mtd->writesize, NAND_RND_WRITE);
+	nand_rnd_write_buf(mtd, buf, length);
+	nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE);
 	/* Send command to program the OOB data */
 	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
 
@@ -2071,12 +2184,18 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd,
 		} else
 			sndcmd = 1;
 		len = min_t(int, length, chunk);
-		chip->write_buf(mtd, bufpoi, len);
+		nand_rnd_config(mtd, page, pos, NAND_RND_WRITE);
+		nand_rnd_write_buf(mtd, bufpoi, len);
 		bufpoi += len;
 		length -= len;
 	}
-	if (length > 0)
-		chip->write_buf(mtd, bufpoi, length);
+
+	if (length > 0){
+		pos = mtd->writesize + mtd->oobsize - length;
+		nand_rnd_config(mtd, page, pos, NAND_RND_WRITE);
+		nand_rnd_write_buf(mtd, bufpoi, length);
+	}
+	nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE);
 
 	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
 	status = chip->waitfunc(mtd, chip);
@@ -2147,7 +2266,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
 			break;
 
 		len = min(len, readlen);
-		buf = nand_transfer_oob(chip, buf, ops, len);
+		buf = nand_transfer_oob(mtd, buf, ops, len);
 
 		if (chip->options & NAND_NEED_READRDY) {
 			/* Apply delay or wait for ready/busy pin */
@@ -2265,29 +2384,39 @@ static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
 	int eccsize = chip->ecc.size;
 	int eccbytes = chip->ecc.bytes;
 	uint8_t *oob = chip->oob_poi;
-	int steps, size;
+	int steps, size, column = 0;
 
 	for (steps = chip->ecc.steps; steps > 0; steps--) {
-		chip->write_buf(mtd, buf, eccsize);
+		nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+		nand_rnd_write_buf(mtd, buf, eccsize);
 		buf += eccsize;
+		column += eccsize;
 
 		if (chip->ecc.prepad) {
-			chip->write_buf(mtd, oob, chip->ecc.prepad);
+			nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+			nand_rnd_write_buf(mtd, oob, chip->ecc.prepad);
 			oob += chip->ecc.prepad;
+			column += chip->ecc.prepad;
 		}
 
-		chip->write_buf(mtd, oob, eccbytes);
+		nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+		nand_rnd_write_buf(mtd, oob, eccbytes);
 		oob += eccbytes;
+		column += eccbytes;
 
 		if (chip->ecc.postpad) {
-			chip->write_buf(mtd, oob, chip->ecc.postpad);
+			nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+			nand_rnd_write_buf(mtd, oob, chip->ecc.postpad);
 			oob += chip->ecc.postpad;
+			column += chip->ecc.postpad;
 		}
 	}
 
 	size = mtd->oobsize - (oob - chip->oob_poi);
-	if (size)
-		chip->write_buf(mtd, oob, size);
+	if (size) {
+		nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+		nand_rnd_write_buf(mtd, oob, size);
+	}
 
 	return 0;
 }
@@ -2334,17 +2463,21 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 	uint8_t *ecc_calc = chip->buffers->ecccalc;
 	const uint8_t *p = buf;
 	uint32_t *eccpos = chip->ecc.layout->eccpos;
+	int column = 0;
 
 	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
 		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
-		chip->write_buf(mtd, p, eccsize);
+		nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+		nand_rnd_write_buf(mtd, p, eccsize);
 		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+		column += eccsize;
 	}
 
 	for (i = 0; i < chip->ecc.total; i++)
 		chip->oob_poi[eccpos[i]] = ecc_calc[i];
 
-	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+	nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+	nand_rnd_write_buf(mtd, chip->oob_poi, mtd->oobsize);
 
 	return 0;
 }
@@ -2380,7 +2513,10 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
 		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
 
 		/* write data (untouched subpages already masked by 0xFF) */
-		chip->write_buf(mtd, buf, ecc_size);
+		nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE);
+		nand_rnd_write_buf(mtd, buf, ecc_size);
+		offset += ecc_size;
+
 
 		/* mask ECC of un-touched subpages by padding 0xFF */
 		if ((step < start_step) || (step > end_step))
@@ -2405,7 +2541,8 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
 		chip->oob_poi[eccpos[i]] = ecc_calc[i];
 
 	/* write OOB buffer to NAND device */
-	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+	nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE);
+	nand_rnd_write_buf(mtd, chip->oob_poi, mtd->oobsize);
 
 	return 0;
 }
@@ -2430,31 +2567,42 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
 	int eccsteps = chip->ecc.steps;
 	const uint8_t *p = buf;
 	uint8_t *oob = chip->oob_poi;
+	int column = 0;
 
 	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
 
 		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
-		chip->write_buf(mtd, p, eccsize);
+		nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+		nand_rnd_write_buf(mtd, p, eccsize);
+		column += eccsize;
 
 		if (chip->ecc.prepad) {
-			chip->write_buf(mtd, oob, chip->ecc.prepad);
+			nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+			nand_rnd_write_buf(mtd, oob, chip->ecc.prepad);
 			oob += chip->ecc.prepad;
+			column += chip->ecc.prepad;
 		}
 
 		chip->ecc.calculate(mtd, p, oob);
-		chip->write_buf(mtd, oob, eccbytes);
+		nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+		nand_rnd_write_buf(mtd, oob, eccbytes);
 		oob += eccbytes;
+		column += eccbytes;
 
 		if (chip->ecc.postpad) {
-			chip->write_buf(mtd, oob, chip->ecc.postpad);
+			nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+			nand_rnd_write_buf(mtd, oob, chip->ecc.postpad);
 			oob += chip->ecc.postpad;
+			column += chip->ecc.postpad;
 		}
 	}
 
 	/* Calculate remaining oob bytes */
 	i = mtd->oobsize - (oob - chip->oob_poi);
-	if (i)
-		chip->write_buf(mtd, oob, i);
+	if (i) {
+		nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+		nand_rnd_write_buf(mtd, oob, i);
+	}
 
 	return 0;
 }
@@ -2485,6 +2633,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 
 	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
 
+	nand_rnd_config(mtd, page, 0, NAND_RND_WRITE);
 	if (unlikely(raw))
 		status = chip->ecc.write_page_raw(mtd, chip, buf,
 							oob_required);
@@ -2494,6 +2643,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 	else
 		status = chip->ecc.write_page(mtd, chip, buf, oob_required);
 
+	nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE);
+
 	if (status < 0)
 		return status;
 
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index ef6a783..6465a52 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -565,6 +565,64 @@ void nand_page_set_status(struct mtd_info *mtd, int page,
 
 int nand_pst_create(struct mtd_info *mtd);
 
+/*
+ * Constants for randomizer modes
+ */
+typedef enum {
+	NAND_RND_NONE,
+	NAND_RND_SOFT,
+	NAND_RND_HW,
+} nand_rnd_modes_t;
+
+/*
+ * Constants for randomizer actions
+ */
+enum nand_rnd_action {
+	NAND_RND_NO_ACTION,
+	NAND_RND_READ,
+	NAND_RND_WRITE,
+};
+
+/**
+ * struct nand_rndfree - Structure defining a NAND page region where the
+ *			 randomizer should be disabled
+ * @offset:	range offset
+ * @length:	range length
+ */
+struct nand_rndfree {
+	u32 offset;
+	u32 length;
+};
+
+/**
+ * struct nand_rnd_layout - Structure defining rndfree regions
+ * @nranges:	number of ranges
+ * @ranges:	array defining the rndfree regions
+ */
+struct nand_rnd_layout {
+	int nranges;
+	struct nand_rndfree ranges[0];
+};
+
+/**
+ * struct nand_rnd_ctrl - Randomizer Control structure
+ * @mode:	Randomizer mode
+ * @config:	function to prepare the randomizer (i.e.: set the appropriate
+ *		seed/init value).
+ * @read_buf:	function that read from the NAND and descramble the retrieved
+ *		data.
+ * @write_buf:	function that scramble data before writing it to the NAND.
+ */
+struct nand_rnd_ctrl {
+	nand_rnd_modes_t mode;
+	struct nand_rnd_layout *layout;
+	void *priv;
+	int (*config)(struct mtd_info *mtd, int page, int column,
+		      enum nand_rnd_action action);
+	void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
+	void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
+};
+
 /**
  * struct nand_buffers - buffer structure for read/write
  * @ecccalc:	buffer pointer for calculated ECC, size is oobsize.
@@ -763,6 +821,8 @@ struct nand_chip {
 	struct nand_buffers *buffers;
 	struct nand_hw_control hwcontrol;
 
+	struct nand_rnd_ctrl rnd;
+
 	uint8_t *bbt;
 	struct nand_bbt_descr *bbt_td;
 	struct nand_bbt_descr *bbt_md;
@@ -894,6 +954,42 @@ extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
 			size_t *retlen, uint8_t *buf);
 
+static inline int nand_rnd_config(struct mtd_info *mtd, int page, int column,
+				  enum nand_rnd_action action)
+{
+	struct nand_chip *chip = mtd->priv;
+
+	if (chip->rnd.config)
+		return chip->rnd.config(mtd, page, column, action);
+
+	return 0;
+}
+
+static inline void nand_rnd_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+				     int len)
+{
+	struct nand_chip *chip = mtd->priv;
+
+	if (chip->rnd.write_buf)
+		chip->rnd.write_buf(mtd, buf, len);
+	else
+		chip->write_buf(mtd, buf, len);
+}
+
+static inline void nand_rnd_read_buf(struct mtd_info *mtd, uint8_t *buf,
+				    int len)
+{
+	struct nand_chip *chip = mtd->priv;
+
+	if (chip->rnd.read_buf)
+		chip->rnd.read_buf(mtd, buf, len);
+	else
+		chip->read_buf(mtd, buf, len);
+}
+
+int nand_rnd_is_activ(struct mtd_info *mtd, int page, int column, int *len);
+
+
 #ifdef __UBOOT__
 /*
 * Constants for oob configuration
-- 
2.4.2


-- 


IMAGINE IT >> MAKE IT

Meet us online at Twitter <http://twitter.com/ultimaker>, Facebook 
<http://facebook.com/ultimaker>, Google+ <http://google.com/+Ultimaker>

www.ultimaker.com


More information about the U-Boot mailing list