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