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

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to