diff options
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.patch | 851 |
1 files changed, 851 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..7d1bdbd --- /dev/null +++ b/target/linux/sunxi/patches-4.1/114-mtd-randomizer-into-nand-framework.patch @@ -0,0 +1,851 @@ +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(-) + +diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c +index 8a5d12e..577cb9e 100644 +--- a/drivers/mtd/nand/nand_base.c ++++ b/drivers/mtd/nand/nand_base.c +@@ -1102,6 +1102,62 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) + 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(struct mtd_info *mtd, + 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_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; +@@ -1399,7 +1473,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 +@@ -1415,7 +1490,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++) +@@ -1436,6 +1512,7 @@ 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; + } + +@@ -1460,13 +1537,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->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 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; + } + +@@ -1514,11 +1596,14 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, + 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_first(struct mtd_info *mtd, + 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_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; + } + +@@ -1561,20 +1648,27 @@ 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->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(struct mtd_info *mtd, struct nand_chip *chip, + 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 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, + * 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 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, + 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 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, + 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_info *mtd, loff_t from, size_t len, + 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_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; + } + +@@ -1949,7 +2058,7 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, + 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 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; + } +@@ -1986,7 +2100,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); + +@@ -2042,12 +2158,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); +@@ -2116,7 +2238,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 */ +@@ -2226,6 +2348,8 @@ static int nand_part_read_oob(struct mtd_info *mtd, loff_t from, + 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_info *mtd, loff_t from, + 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 @@ static int nand_part_read_oob(struct mtd_info *mtd, loff_t from, + 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(struct mtd_info *mtd, + 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 mtd_info *mtd, struct nand_chip *chip, + 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(struct mtd_info *mtd, + 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(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; + } +@@ -2449,31 +2594,42 @@ static int nand_write_page_syndrome(struct mtd_info *mtd, + 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_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->cur_ecc->write_page_raw(mtd, chip, buf, + oob_required); +@@ -2514,6 +2671,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, + 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 mtd_info *mtd, loff_t to, size_t len, + 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 mtd_info *mtd, loff_t to, size_t len, + + 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_info *mtd, loff_t to, size_t len, + 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 mtd_info *mtd, loff_t to, + 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 mtd_info *mtd, loff_t to, + 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)) { +diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h +index 4f7ca8d..6cbd06a3 100644 +--- a/include/linux/mtd/nand.h ++++ b/include/linux/mtd/nand.h +@@ -539,6 +539,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. +@@ -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_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->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 |