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

Roy Spliet
2015-06-05T11:52:39Z

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@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>