aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/sunxi/patches-4.1/114-mtd-randomizer-into-nand-framework.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/sunxi/patches-4.1/114-mtd-randomizer-into-nand-framework.patch')
-rw-r--r--target/linux/sunxi/patches-4.1/114-mtd-randomizer-into-nand-framework.patch847
1 files changed, 847 insertions, 0 deletions
diff --git a/target/linux/sunxi/patches-4.1/114-mtd-randomizer-into-nand-framework.patch b/target/linux/sunxi/patches-4.1/114-mtd-randomizer-into-nand-framework.patch
new file mode 100644
index 0000000..173bd1e
--- /dev/null
+++ b/target/linux/sunxi/patches-4.1/114-mtd-randomizer-into-nand-framework.patch
@@ -0,0 +1,847 @@
+From 293984c7f167a08285596ef2166d8ab9cb571778 Mon Sep 17 00:00:00 2001
+From: Boris BREZILLON <boris.brezillon@free-electrons.com>
+Date: Mon, 28 Jul 2014 14:46:26 +0200
+Subject: [PATCH] mtd: nand: Introduce a randomizer layer in the NAND framework
+
+This patch introduce a new layer in the NAND framework to support both HW
+and SW randomizers.
+
+This randomization is required on some MLC/TLC NAND chips which do not
+support large islands of same patterns.
+
+The randomizer layer defines a nand_rnd_ctrl struct which is intended to
+be used by NAND core functions or NAND drivers to randomize/derandomize
+data stored on NAND chips.
+
+The implementation can implement any of these functions:
+- config: prepare a random transfer to/from the NAND chip
+- write_buf: randomize and write data to the NAND chip
+- read_buf: read and derandomize data from the NAND chip
+
+read/write_buf functions are always called after a config call.
+The config call specify the page, the column within the page and the action
+that will take place after the config (either read or write).
+If column is set to -1, the randomizer is disabled.
+If page is set to -1, we keep working on the same page.
+
+The randomizer layer provides helper functions that choose wether the
+randomizer or the chip read/write_buf should be used.
+
+Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/mtd/nand/nand_base.c | 278 ++++++++++++++++++++++++++++++++++---------
+ include/linux/mtd/nand.h | 98 +++++++++++++++
+ 2 files changed, 321 insertions(+), 55 deletions(-)
+
+--- a/drivers/mtd/nand/nand_base.c
++++ b/drivers/mtd/nand/nand_base.c
+@@ -1102,6 +1102,62 @@ out:
+ EXPORT_SYMBOL(nand_lock);
+
+ /**
++ * 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->cur_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
+@@ -1246,9 +1302,14 @@ 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;
+ }
+
+@@ -1270,28 +1331,40 @@ static int nand_read_page_raw_syndrome(s
+ int eccbytes = chip->cur_ecc->bytes;
+ uint8_t *oob = chip->oob_poi;
+ int steps, size;
++ int column = 0;
+
+ for (steps = chip->cur_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->cur_ecc->prepad) {
+- chip->read_buf(mtd, oob, chip->cur_ecc->prepad);
++ nand_rnd_config(mtd, page, column, NAND_RND_READ);
++ nand_rnd_read_buf(mtd, oob, chip->cur_ecc->prepad);
+ oob += chip->cur_ecc->prepad;
++ column += chip->cur_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->cur_ecc->postpad) {
+- chip->read_buf(mtd, oob, chip->cur_ecc->postpad);
++ nand_rnd_config(mtd, page, column, NAND_RND_READ);
++ nand_rnd_read_buf(mtd, oob, chip->cur_ecc->postpad);
+ oob += chip->cur_ecc->postpad;
++ column += chip->cur_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;
+ }
+@@ -1380,7 +1453,8 @@ static int nand_read_subpage(struct mtd_
+ 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;
+@@ -1399,7 +1473,8 @@ static int nand_read_subpage(struct mtd_
+ }
+ 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
+@@ -1415,7 +1490,8 @@ static int nand_read_subpage(struct mtd_
+
+ 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++)
+@@ -1436,6 +1512,7 @@ static int nand_read_subpage(struct mtd_
+ max_bitflips = max_t(unsigned int, max_bitflips, stat);
+ }
+ }
++ nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
+ return max_bitflips;
+ }
+
+@@ -1460,13 +1537,17 @@ static int nand_read_page_hwecc(struct m
+ uint8_t *ecc_code = chip->buffers->ecccode;
+ uint32_t *eccpos = chip->cur_ecc->layout->eccpos;
+ unsigned int max_bitflips = 0;
++ int column = 0;
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ chip->cur_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->cur_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->cur_ecc->total; i++)
+ ecc_code[i] = chip->oob_poi[eccpos[i]];
+@@ -1486,6 +1567,7 @@ static int nand_read_page_hwecc(struct m
+ max_bitflips = max_t(unsigned int, max_bitflips, stat);
+ }
+ }
++ nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
+ return max_bitflips;
+ }
+
+@@ -1514,11 +1596,14 @@ static int nand_read_page_hwecc_oob_firs
+ uint32_t *eccpos = chip->cur_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->cur_ecc->total; i++)
+ ecc_code[i] = chip->oob_poi[eccpos[i]];
+@@ -1527,7 +1612,8 @@ static int nand_read_page_hwecc_oob_firs
+ int stat;
+
+ chip->cur_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->cur_ecc->calculate(mtd, p, &ecc_calc[i]);
+
+ stat = chip->cur_ecc->correct(mtd, p, &ecc_code[i], NULL);
+@@ -1538,6 +1624,7 @@ static int nand_read_page_hwecc_oob_firs
+ max_bitflips = max_t(unsigned int, max_bitflips, stat);
+ }
+ }
++ nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
+ return max_bitflips;
+ }
+
+@@ -1561,20 +1648,27 @@ static int nand_read_page_syndrome(struc
+ 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->cur_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->cur_ecc->prepad) {
+- chip->read_buf(mtd, oob, chip->cur_ecc->prepad);
++ nand_rnd_config(mtd, page, column, NAND_RND_READ);
++ nand_rnd_read_buf(mtd, oob, chip->cur_ecc->prepad);
+ oob += chip->cur_ecc->prepad;
+ }
+
+ chip->cur_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->cur_ecc->correct(mtd, p, oob, NULL);
+
+ if (stat < 0) {
+@@ -1587,29 +1681,36 @@ static int nand_read_page_syndrome(struc
+ oob += eccbytes;
+
+ if (chip->cur_ecc->postpad) {
+- chip->read_buf(mtd, oob, chip->cur_ecc->postpad);
++ nand_rnd_config(mtd, page, column, NAND_RND_READ);
++ nand_rnd_read_buf(mtd, oob, chip->cur_ecc->postpad);
++ column += chip->cur_ecc->postpad;
+ oob += chip->cur_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;
+ }
+
+ /**
+ * nand_transfer_oob - [INTERN] Transfer oob to client buffer
+- * @chip: nand chip structure
++ * @mtd: mtd structure
+ * @oob: oob destination address
+ * @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:
+@@ -1737,6 +1838,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->cur_ecc->read_page_raw(mtd, chip,
+ bufpoi,
+@@ -1753,6 +1855,8 @@ read_retry:
+ bufpoi,
+ oob_required,
+ page);
++ nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
++
+ if (ret < 0) {
+ if (use_bufpoi)
+ /* Invalidate page cache */
+@@ -1780,8 +1884,8 @@ read_retry:
+ int toread = min(oobreadlen, max_oobsize);
+
+ if (toread) {
+- oob = nand_transfer_oob(chip,
+- oob, ops, toread);
++ oob = nand_transfer_oob(mtd, oob, ops,
++ toread);
+ oobreadlen -= toread;
+ }
+ }
+@@ -1909,12 +2013,15 @@ static int nand_part_read(struct mtd_inf
+ nand_get_device(part->master, FL_READING);
+ if (part->ecc)
+ chip->cur_ecc = part->ecc;
++ if (part->rnd)
++ chip->cur_rnd = part->rnd;
+ ops.len = len;
+ ops.datbuf = buf;
+ ops.oobbuf = NULL;
+ ops.mode = MTD_OPS_PLACE_OOB;
+ ret = nand_do_read_ops(part->master, from, &ops);
+ *retlen = ops.retlen;
++ chip->cur_rnd = &chip->rnd;
+ chip->cur_ecc = &chip->ecc;
+ nand_release_device(part->master);
+ return ret;
+@@ -1930,7 +2037,9 @@ static int nand_read_oob_std(struct mtd_
+ 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;
+ }
+
+@@ -1949,7 +2058,7 @@ static int nand_read_oob_syndrome(struct
+ chip->cur_ecc->postpad;
+ int eccsize = chip->cur_ecc->size;
+ uint8_t *bufpoi = chip->oob_poi;
+- int i, toread, sndrnd = 0, pos;
++ int i, toread, sndrnd = 0, pos = eccsize;
+
+ chip->cmdfunc(mtd, NAND_CMD_READ0, chip->cur_ecc->size, page);
+ for (i = 0; i < chip->cur_ecc->steps; i++) {
+@@ -1962,12 +2071,17 @@ static int nand_read_oob_syndrome(struct
+ } 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;
+ }
+@@ -1986,7 +2100,9 @@ static int nand_write_oob_std(struct mtd
+ 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);
+
+@@ -2042,12 +2158,18 @@ static int nand_write_oob_syndrome(struc
+ } 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);
+@@ -2116,7 +2238,7 @@ static int nand_do_read_oob(struct mtd_i
+ 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 */
+@@ -2226,6 +2348,8 @@ static int nand_part_read_oob(struct mtd
+ nand_get_device(part->master, FL_READING);
+ if (part->ecc)
+ chip->cur_ecc = part->ecc;
++ if (part->rnd)
++ chip->cur_rnd = part->rnd;
+
+ switch (ops->mode) {
+ case MTD_OPS_PLACE_OOB:
+@@ -2243,6 +2367,7 @@ static int nand_part_read_oob(struct mtd
+ ret = nand_do_read_ops(part->master, from, ops);
+
+ out:
++ chip->cur_rnd = &chip->rnd;
+ chip->cur_ecc = &chip->ecc;
+ nand_release_device(part->master);
+ return ret;
+@@ -2261,9 +2386,11 @@ out:
+ static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf, int oob_required)
+ {
+- chip->write_buf(mtd, buf, mtd->writesize);
+- if (oob_required)
+- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
++ nand_rnd_write_buf(mtd, buf, mtd->writesize);
++ if (oob_required) {
++ nand_rnd_config(mtd, -1, mtd->writesize, NAND_RND_WRITE);
++ nand_rnd_write_buf(mtd, chip->oob_poi, mtd->oobsize);
++ }
+
+ return 0;
+ }
+@@ -2285,28 +2412,39 @@ static int nand_write_page_raw_syndrome(
+ int eccbytes = chip->cur_ecc->bytes;
+ uint8_t *oob = chip->oob_poi;
+ int steps, size;
++ int column = 0;
+
+ for (steps = chip->cur_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->cur_ecc->prepad) {
+- chip->write_buf(mtd, oob, chip->cur_ecc->prepad);
++ nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
++ nand_rnd_write_buf(mtd, oob, chip->cur_ecc->prepad);
+ oob += chip->cur_ecc->prepad;
++ column += chip->cur_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->cur_ecc->postpad) {
+- chip->write_buf(mtd, oob, chip->cur_ecc->postpad);
++ nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
++ nand_rnd_write_buf(mtd, oob, chip->cur_ecc->postpad);
+ oob += chip->cur_ecc->postpad;
++ column += chip->cur_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;
+ }
+@@ -2353,17 +2491,21 @@ static int nand_write_page_hwecc(struct
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ const uint8_t *p = buf;
+ uint32_t *eccpos = chip->cur_ecc->layout->eccpos;
++ int column = 0;
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ chip->cur_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->cur_ecc->calculate(mtd, p, &ecc_calc[i]);
++ column += eccsize;
+ }
+
+ for (i = 0; i < chip->cur_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;
+ }
+@@ -2399,7 +2541,9 @@ static int nand_write_subpage_hwecc(stru
+ chip->cur_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))
+@@ -2424,7 +2568,8 @@ static int nand_write_subpage_hwecc(stru
+ 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;
+ }
+@@ -2449,31 +2594,42 @@ static int nand_write_page_syndrome(stru
+ int eccsteps = chip->cur_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->cur_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->cur_ecc->prepad) {
+- chip->write_buf(mtd, oob, chip->cur_ecc->prepad);
++ nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
++ nand_rnd_write_buf(mtd, oob, chip->cur_ecc->prepad);
+ oob += chip->cur_ecc->prepad;
++ column += chip->cur_ecc->prepad;
+ }
+
+ chip->cur_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->cur_ecc->postpad) {
+- chip->write_buf(mtd, oob, chip->cur_ecc->postpad);
++ nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
++ nand_rnd_write_buf(mtd, oob, chip->cur_ecc->postpad);
+ oob += chip->cur_ecc->postpad;
++ column += chip->cur_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;
+ }
+@@ -2504,6 +2660,7 @@ static int nand_write_page(struct mtd_in
+
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+
++ nand_rnd_config(mtd, page, 0, NAND_RND_WRITE);
+ if (unlikely(raw))
+ status = chip->cur_ecc->write_page_raw(mtd, chip, buf,
+ oob_required);
+@@ -2514,6 +2671,7 @@ static int nand_write_page(struct mtd_in
+ else
+ status = chip->cur_ecc->write_page(mtd, chip, buf,
+ oob_required);
++ nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE);
+
+ if (status < 0)
+ return status;
+@@ -2803,6 +2961,8 @@ static int panic_nand_part_write(struct
+ panic_nand_get_device(chip, part->master, FL_WRITING);
+ if (part->ecc)
+ chip->cur_ecc = part->ecc;
++ if (part->rnd)
++ chip->cur_rnd = part->rnd;
+
+ ops.len = len;
+ ops.datbuf = (uint8_t *)buf;
+@@ -2811,6 +2971,7 @@ static int panic_nand_part_write(struct
+
+ ret = nand_do_write_ops(part->master, to, &ops);
+
++ chip->cur_rnd = &chip->rnd;
+ chip->cur_ecc = &chip->ecc;
+ *retlen = ops.retlen;
+ return ret;
+@@ -2865,12 +3026,15 @@ static int nand_part_write(struct mtd_in
+ nand_get_device(part->master, FL_WRITING);
+ if (part->ecc)
+ chip->cur_ecc = part->ecc;
++ if (part->rnd)
++ chip->cur_rnd = part->rnd;
+ ops.len = len;
+ ops.datbuf = (uint8_t *)buf;
+ ops.oobbuf = NULL;
+ ops.mode = MTD_OPS_PLACE_OOB;
+ ret = nand_do_write_ops(part->master, to, &ops);
+ *retlen = ops.retlen;
++ chip->cur_rnd = &chip->rnd;
+ chip->cur_ecc = &chip->ecc;
+ nand_release_device(part->master);
+ return ret;
+@@ -3032,6 +3196,8 @@ static int nand_part_write_oob(struct mt
+ nand_get_device(part->master, FL_WRITING);
+ if (part->ecc)
+ chip->cur_ecc = part->ecc;
++ if (part->rnd)
++ chip->cur_rnd = part->rnd;
+
+ switch (ops->mode) {
+ case MTD_OPS_PLACE_OOB:
+@@ -3049,6 +3215,7 @@ static int nand_part_write_oob(struct mt
+ ret = nand_do_write_ops(part->master, to, ops);
+
+ out:
++ chip->cur_rnd = &chip->rnd;
+ chip->cur_ecc = &chip->ecc;
+ nand_release_device(part->master);
+ return ret;
+@@ -4749,6 +4916,7 @@ int nand_scan_tail(struct mtd_info *mtd)
+ mutex_init(&chip->part_lock);
+
+ chip->cur_ecc = &chip->ecc;
++ chip->cur_rnd = &chip->rnd;
+
+ /* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
+ if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
+--- a/include/linux/mtd/nand.h
++++ b/include/linux/mtd/nand.h
+@@ -539,6 +539,64 @@ void nand_page_set_status(struct mtd_inf
+
+ 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.
+@@ -731,6 +789,9 @@ struct nand_chip {
+ struct nand_buffers *buffers;
+ struct nand_hw_control hwcontrol;
+
++ struct nand_rnd_ctrl rnd;
++ struct nand_rnd_ctrl *cur_rnd;
++
+ uint8_t *bbt;
+ struct nand_bbt_descr *bbt_td;
+ struct nand_bbt_descr *bbt_md;
+@@ -752,6 +813,7 @@ struct nand_chip {
+ * @master: MTD device representing the NAND chip
+ * @offset: partition offset
+ * @ecc: partition specific ECC struct
++ * @rnd: partition specific randomizer struct
+ * @release: function used to release this nand_part struct
+ *
+ * NAND partitions work as standard MTD partitions except it can override
+@@ -765,6 +827,7 @@ struct nand_part {
+ struct mtd_info *master;
+ uint64_t offset;
+ struct nand_ecc_ctrl *ecc;
++ struct nand_rnd_ctrl *rnd;
+ void (*release)(struct nand_part *part);
+ };
+
+@@ -902,6 +965,41 @@ extern int nand_erase_nand(struct mtd_in
+ 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->cur_rnd && chip->cur_rnd->config)
++ return chip->cur_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->cur_rnd && chip->cur_rnd->read_buf)
++ chip->cur_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->cur_rnd && chip->cur_rnd->read_buf)
++ chip->cur_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);
++
+ /**
+ * struct platform_nand_chip - chip level device structure
+ * @nr_chips: max. number of chips to scan for