1 From ef4bc8ab68979e5c1c30f061c5af1a7d6ec8eb52 Mon Sep 17 00:00:00 2001
2 From: Boris Brezillon <boris.brezillon@free-electrons.com>
3 Date: Tue, 21 Oct 2014 14:40:42 +0200
4 Subject: [PATCH] mtd: nand: sunxi: Add HW randomizer support
6 Add support for the HW randomizer available on the sunxi nand controller.
8 Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
9 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
11 drivers/mtd/nand/sunxi_nand.c | 603 ++++++++++++++++++++++++++++++++++++++++--
12 1 file changed, 585 insertions(+), 18 deletions(-)
14 diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
15 index c3e0473..2f6ab39 100644
16 --- a/drivers/mtd/nand/sunxi_nand.c
17 +++ b/drivers/mtd/nand/sunxi_nand.c
18 @@ -206,10 +206,12 @@ struct sunxi_nand_hw_ecc {
20 * @part: base paritition structure
21 * @ecc: per-partition ECC info
22 + * @rnd: per-partition randomizer info
24 struct sunxi_nand_part {
25 struct nand_part part;
26 struct nand_ecc_ctrl ecc;
27 + struct nand_rnd_ctrl rnd;
30 static inline struct sunxi_nand_part *
31 @@ -219,6 +221,29 @@ to_sunxi_nand_part(struct nand_part *part)
35 + * sunxi NAND randomizer structure: stores NAND randomizer information
37 + * @page: current page
38 + * @column: current column
39 + * @nseeds: seed table size
40 + * @seeds: seed table
41 + * @subseeds: pre computed sub seeds
42 + * @step: step function
43 + * @left: number of remaining bytes in the page
44 + * @state: current randomizer state
46 +struct sunxi_nand_hw_rnd {
52 + u16 (*step)(struct mtd_info *mtd, u16 state, int column, int *left);
58 * NAND chip structure: stores NAND chip device related information
60 * @node: used to store NAND chips into a list
61 @@ -233,6 +258,7 @@ struct sunxi_nand_chip {
62 struct list_head node;
63 struct nand_chip nand;
66 unsigned long clk_rate;
69 @@ -489,6 +515,185 @@ static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
73 +static u16 sunxi_nfc_hwrnd_step(struct sunxi_nand_hw_rnd *rnd, u16 state, int count)
78 + state = ((state >> 1) |
79 + ((((state >> 0) ^ (state >> 1)) & 1) << 14)) & 0x7fff;
84 +static u16 sunxi_nfc_hwrnd_single_step(u16 state, int count)
88 + state = ((state >> 1) |
89 + ((((state >> 0) ^ (state >> 1)) & 1) << 14)) & 0x7fff;
94 +static int sunxi_nfc_hwrnd_config(struct mtd_info *mtd, int page, int column,
95 + enum nand_rnd_action action)
97 + struct nand_chip *nand = mtd->priv;
98 + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
99 + struct sunxi_nand_hw_rnd *rnd = nand->cur_rnd->priv;
102 + if (page < 0 && column < 0) {
116 + if (page != rnd->page && action == NAND_RND_READ) {
119 + status = nand_page_get_status(mtd, page);
120 + if (status == NAND_PAGE_STATUS_UNKNOWN) {
121 + nand->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
122 + sunxi_nfc_read_buf(mtd, sunxi_nand->buffer,
123 + mtd->writesize + mtd->oobsize);
125 + if (nand_page_is_empty(mtd, sunxi_nand->buffer,
126 + sunxi_nand->buffer +
128 + status = NAND_PAGE_EMPTY;
130 + status = NAND_PAGE_FILLED;
132 + nand_page_set_status(mtd, page, status);
133 + nand->cmdfunc(mtd, NAND_CMD_RNDOUT, column, -1);
137 + state = rnd->seeds[page % rnd->nseeds];
139 + rnd->column = column;
142 + rnd->state = rnd->step(mtd, state, column, &rnd->left);
144 + rnd->state = sunxi_nfc_hwrnd_step(rnd, state, column % 4096);
145 + rnd->left = mtd->oobsize + mtd->writesize - column;
151 +static void sunxi_nfc_hwrnd_write_buf(struct mtd_info *mtd, const uint8_t *buf,
154 + struct nand_chip *nand = mtd->priv;
155 + struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
156 + struct sunxi_nand_hw_rnd *rnd = nand->cur_rnd->priv;
157 + u32 tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
162 + tmp &= ~(NFC_RANDOM_DIRECTION | NFC_RANDOM_SEED | NFC_RANDOM_EN);
163 + writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
165 + if (rnd->page < 0) {
166 + sunxi_nfc_write_buf(mtd, buf, len);
170 + while (len > offs) {
175 + rndactiv = nand_rnd_is_activ(mtd, rnd->page, rnd->column,
177 + if (rndactiv > 0) {
178 + writel(tmp | NFC_RANDOM_EN | (rnd->state << 16),
179 + nfc->regs + NFC_REG_ECC_CTL);
180 + if (rnd->left < cnt)
184 + sunxi_nfc_write_buf(mtd, buf + offs, cnt);
187 + writel(tmp & ~NFC_RANDOM_EN,
188 + nfc->regs + NFC_REG_ECC_CTL);
194 + sunxi_nfc_hwrnd_config(mtd, -1, rnd->column + cnt, NAND_RND_WRITE);
198 +static void sunxi_nfc_hwrnd_read_buf(struct mtd_info *mtd, uint8_t *buf,
201 + struct nand_chip *nand = mtd->priv;
202 + struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
203 + struct sunxi_nand_hw_rnd *rnd = nand->cur_rnd->priv;
204 + u32 tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
209 + tmp &= ~(NFC_RANDOM_DIRECTION | NFC_RANDOM_SEED | NFC_RANDOM_EN);
210 + writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
212 + if (rnd->page < 0) {
213 + sunxi_nfc_read_buf(mtd, buf, len);
217 + while (len > offs) {
222 + if (nand_page_get_status(mtd, rnd->page) != NAND_PAGE_EMPTY &&
223 + nand_rnd_is_activ(mtd, rnd->page, rnd->column, &cnt) > 0)
228 + if (rndactiv > 0) {
229 + writel(tmp | NFC_RANDOM_EN | (rnd->state << 16),
230 + nfc->regs + NFC_REG_ECC_CTL);
231 + if (rnd->left < cnt)
236 + sunxi_nfc_read_buf(mtd, buf + offs, cnt);
238 + sunxi_nfc_read_buf(mtd, NULL, cnt);
241 + writel(tmp & ~NFC_RANDOM_EN,
242 + nfc->regs + NFC_REG_ECC_CTL);
248 + sunxi_nfc_hwrnd_config(mtd, -1, rnd->column + cnt, NAND_RND_READ);
252 static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd)
255 @@ -538,16 +743,43 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
256 int oob_required, int page)
258 struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller);
259 + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(chip);
260 struct nand_ecc_ctrl *ecc = chip->cur_ecc;
261 struct nand_ecclayout *layout = ecc->layout;
262 struct sunxi_nand_hw_ecc *data = ecc->priv;
263 unsigned int max_bitflips = 0;
271 + status = nand_page_get_status(mtd, page);
272 + if (status == NAND_PAGE_STATUS_UNKNOWN) {
273 + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
274 + sunxi_nfc_read_buf(mtd, sunxi_nand->buffer,
275 + mtd->writesize + mtd->oobsize);
277 + if (nand_page_is_empty(mtd, sunxi_nand->buffer,
278 + sunxi_nand->buffer +
280 + status = NAND_PAGE_EMPTY;
282 + status = NAND_PAGE_FILLED;
283 + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
286 + nand_page_set_status(mtd, page, status);
289 + if (status == NAND_PAGE_EMPTY) {
290 + memset(buf, 0xff, mtd->writesize);
292 + memset(chip->oob_poi, 0xff, mtd->oobsize);
296 tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
297 tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE);
298 tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) |
299 @@ -556,12 +788,15 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
300 writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
302 for (i = 0; i < ecc->steps; i++) {
303 + bool rndactiv = false;
306 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, i * ecc->size, -1);
308 offset = mtd->writesize + layout->eccpos[i * ecc->bytes] - 4;
310 - chip->read_buf(mtd, NULL, ecc->size);
311 + nand_rnd_config(mtd, page, i * ecc->size, NAND_RND_READ);
312 + nand_rnd_read_buf(mtd, NULL, ecc->size);
314 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
316 @@ -569,6 +804,25 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
321 + cnt = ecc->bytes + 4;
322 + if (nand_rnd_is_activ(mtd, page, offset, &cnt) > 0 &&
323 + cnt == ecc->bytes + 4)
326 + cnt = ecc->bytes + 2;
327 + if (nand_rnd_is_activ(mtd, page, offset + 2, &cnt) > 0 &&
328 + cnt == ecc->bytes + 2)
333 + tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
334 + tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION);
335 + tmp |= NFC_RANDOM_EN;
336 + writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
339 tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30);
340 writel(tmp, nfc->regs + NFC_REG_CMD);
342 @@ -579,6 +833,9 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
343 memcpy_fromio(buf + (i * ecc->size),
344 nfc->regs + NFC_RAM0_BASE, ecc->size);
346 + writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
347 + nfc->regs + NFC_REG_ECC_CTL);
349 if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) {
350 mtd->ecc_stats.failed++;
352 @@ -594,9 +851,10 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
356 + nand_rnd_config(mtd, -1, offset, NAND_RND_READ);
357 offset -= mtd->writesize;
358 - chip->read_buf(mtd, chip->oob_poi + offset,
360 + nand_rnd_read_buf(mtd, chip->oob_poi + offset,
365 @@ -606,11 +864,14 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
366 offset = mtd->writesize +
367 ecc->layout->oobfree[ecc->steps].offset;
368 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
369 + nand_rnd_config(mtd, -1, offset, NAND_RND_READ);
370 offset -= mtd->writesize;
371 - chip->read_buf(mtd, chip->oob_poi + offset, cnt);
372 + nand_rnd_read_buf(mtd, chip->oob_poi + offset, cnt);
376 + nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
378 tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
381 @@ -627,6 +888,7 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
382 struct nand_ecc_ctrl *ecc = chip->cur_ecc;
383 struct nand_ecclayout *layout = ecc->layout;
384 struct sunxi_nand_hw_ecc *data = ecc->priv;
385 + struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv;
389 @@ -641,22 +903,56 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
390 writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
392 for (i = 0; i < ecc->steps; i++) {
393 + bool rndactiv = false;
397 chip->cmdfunc(mtd, NAND_CMD_RNDIN, i * ecc->size, -1);
399 - chip->write_buf(mtd, buf + (i * ecc->size), ecc->size);
400 + nand_rnd_config(mtd, -1, i * ecc->size, NAND_RND_WRITE);
401 + nand_rnd_write_buf(mtd, buf + (i * ecc->size), ecc->size);
403 offset = layout->eccpos[i * ecc->bytes] - 4 + mtd->writesize;
405 /* Fill OOB data in */
406 - if (oob_required) {
408 - memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, &tmp,
411 + memset(oob_buf, 0xff, 4);
414 + chip->oob_poi + layout->oobfree[i].offset,
418 + memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, oob_buf, 4);
421 + cnt = ecc->bytes + 4;
423 + nand_rnd_is_activ(mtd, -1, offset, &cnt) > 0 &&
424 + cnt == ecc->bytes + 4)
427 - memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE,
428 - chip->oob_poi + offset - mtd->writesize,
430 + cnt = ecc->bytes + 2;
432 + nand_rnd_is_activ(mtd, -1, offset + 2, &cnt) > 0 &&
433 + cnt == ecc->bytes + 2)
438 + /* pre randomize to generate FF patterns on the NAND */
440 + u16 state = rnd->subseeds[rnd->page % rnd->nseeds];
441 + state = sunxi_nfc_hwrnd_single_step(state, 15);
442 + oob_buf[0] ^= state;
443 + state = sunxi_nfc_hwrnd_step(rnd, state, 1);
444 + oob_buf[1] ^= state;
445 + memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, oob_buf, 4);
447 + tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
448 + tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION);
449 + tmp |= NFC_RANDOM_EN;
450 + writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
453 chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1);
454 @@ -671,6 +967,9 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
455 ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
459 + writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
460 + nfc->regs + NFC_REG_ECC_CTL);
464 @@ -679,11 +978,14 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
465 offset = mtd->writesize +
466 ecc->layout->oobfree[i].offset;
467 chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1);
468 + nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE);
469 offset -= mtd->writesize;
470 - chip->write_buf(mtd, chip->oob_poi + offset, cnt);
471 + nand_rnd_write_buf(mtd, chip->oob_poi + offset, cnt);
475 + nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE);
477 tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
480 @@ -692,22 +994,76 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
484 +static u16 sunxi_nfc_hw_ecc_rnd_steps(struct mtd_info *mtd, u16 state,
485 + int column, int *left)
487 + struct nand_chip *chip = mtd->priv;
488 + struct nand_ecc_ctrl *ecc = chip->cur_ecc;
489 + struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv;
490 + int nblks = mtd->writesize / ecc->size;
491 + int modsize = ecc->size;
494 + if (column < mtd->writesize) {
495 + steps = column % modsize;
496 + *left = modsize - steps;
497 + } else if (column < mtd->writesize +
498 + (nblks * (ecc->bytes + 4))) {
499 + column -= mtd->writesize;
500 + steps = column % (ecc->bytes + 4);
501 + *left = ecc->bytes + 4 - steps;
502 + state = rnd->subseeds[rnd->page % rnd->nseeds];
504 + steps = column % 4096;
505 + *left = mtd->writesize + mtd->oobsize - column;
508 + return sunxi_nfc_hwrnd_step(rnd, state, steps);
511 static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
512 struct nand_chip *chip,
513 uint8_t *buf, int oob_required,
516 struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller);
517 + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(chip);
518 struct nand_ecc_ctrl *ecc = chip->cur_ecc;
519 struct sunxi_nand_hw_ecc *data = ecc->priv;
520 unsigned int max_bitflips = 0;
521 uint8_t *oob = chip->oob_poi;
529 + status = nand_page_get_status(mtd, page);
530 + if (status == NAND_PAGE_STATUS_UNKNOWN) {
531 + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
532 + sunxi_nfc_read_buf(mtd, sunxi_nand->buffer,
533 + mtd->writesize + mtd->oobsize);
535 + if (nand_page_is_empty(mtd, sunxi_nand->buffer,
536 + sunxi_nand->buffer +
538 + status = NAND_PAGE_EMPTY;
540 + status = NAND_PAGE_FILLED;
541 + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
544 + nand_page_set_status(mtd, page, status);
547 + if (status == NAND_PAGE_EMPTY) {
548 + memset(buf, 0xff, mtd->writesize);
550 + memset(chip->oob_poi, 0xff, mtd->oobsize);
554 tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
555 tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE);
556 tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) |
557 @@ -716,7 +1072,17 @@ static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
558 writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
560 for (i = 0; i < ecc->steps; i++) {
561 - chip->read_buf(mtd, NULL, ecc->size);
562 + nand_rnd_config(mtd, page, offset, NAND_RND_READ);
563 + nand_rnd_read_buf(mtd, NULL, ecc->size);
565 + cnt = ecc->bytes + 4;
566 + if (nand_rnd_is_activ(mtd, page, offset, &cnt) > 0 &&
567 + cnt == ecc->bytes + 4) {
568 + tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
569 + tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION);
570 + tmp |= NFC_RANDOM_EN;
571 + writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
574 tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30);
575 writel(tmp, nfc->regs + NFC_REG_CMD);
576 @@ -729,6 +1095,9 @@ static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
580 + writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
581 + nfc->regs + NFC_REG_ECC_CTL);
583 if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) {
584 mtd->ecc_stats.failed++;
586 @@ -739,7 +1108,8 @@ static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
589 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
590 - chip->read_buf(mtd, oob, ecc->bytes + ecc->prepad);
591 + nand_rnd_config(mtd, -1, offset, NAND_RND_READ);
592 + nand_rnd_read_buf(mtd, oob, ecc->bytes + ecc->prepad);
593 oob += ecc->bytes + ecc->prepad;
596 @@ -750,10 +1120,13 @@ static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
597 cnt = mtd->oobsize - (oob - chip->oob_poi);
599 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
600 - chip->read_buf(mtd, oob, cnt);
601 + nand_rnd_config(mtd, page, offset, NAND_RND_READ);
602 + nand_rnd_read_buf(mtd, oob, cnt);
606 + nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
608 writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN,
609 nfc->regs + NFC_REG_ECC_CTL);
611 @@ -768,6 +1141,7 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd,
612 struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller);
613 struct nand_ecc_ctrl *ecc = chip->cur_ecc;
614 struct sunxi_nand_hw_ecc *data = ecc->priv;
615 + struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv;
616 uint8_t *oob = chip->oob_poi;
619 @@ -783,7 +1157,8 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd,
620 writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
622 for (i = 0; i < ecc->steps; i++) {
623 - chip->write_buf(mtd, buf + (i * ecc->size), ecc->size);
624 + nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE);
625 + nand_rnd_write_buf(mtd, buf + (i * ecc->size), ecc->size);
628 /* Fill OOB data in */
629 @@ -796,6 +1171,16 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd,
633 + cnt = ecc->bytes + 4;
635 + nand_rnd_is_activ(mtd, rnd->page, offset, &cnt) > 0 &&
636 + cnt == ecc->bytes + 4) {
637 + tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
638 + tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION);
639 + tmp |= NFC_RANDOM_EN;
640 + writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
643 tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ACCESS_DIR |
645 writel(tmp, nfc->regs + NFC_REG_CMD);
646 @@ -804,6 +1189,9 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd,
650 + writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
651 + nfc->regs + NFC_REG_ECC_CTL);
653 offset += ecc->bytes + ecc->prepad;
654 oob += ecc->bytes + ecc->prepad;
656 @@ -812,9 +1200,11 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd,
657 cnt = mtd->oobsize - (oob - chip->oob_poi);
659 chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1);
660 - chip->write_buf(mtd, oob, cnt);
661 + nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE);
662 + nand_rnd_write_buf(mtd, oob, cnt);
665 + nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE);
667 tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
669 @@ -824,6 +1214,128 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd,
673 +static u16 sunxi_nfc_hw_syndrome_ecc_rnd_steps(struct mtd_info *mtd, u16 state,
674 + int column, int *left)
676 + struct nand_chip *chip = mtd->priv;
677 + struct nand_ecc_ctrl *ecc = chip->cur_ecc;
678 + struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv;
679 + int eccsteps = mtd->writesize / ecc->size;
680 + int modsize = ecc->size + ecc->prepad + ecc->bytes;
683 + if (column < (eccsteps * modsize)) {
684 + steps = column % modsize;
685 + *left = modsize - steps;
686 + if (steps >= ecc->size) {
687 + steps -= ecc->size;
688 + state = rnd->subseeds[rnd->page % rnd->nseeds];
691 + steps = column % 4096;
692 + *left = mtd->writesize + mtd->oobsize - column;
695 + return sunxi_nfc_hwrnd_step(rnd, state, steps);
698 +static u16 default_seeds[] = {0x4a80};
700 +static void sunxi_nand_rnd_ctrl_cleanup(struct nand_rnd_ctrl *rnd)
702 + struct sunxi_nand_hw_rnd *hwrnd = rnd->priv;
704 + if (hwrnd->seeds != default_seeds)
705 + kfree(hwrnd->seeds);
706 + kfree(hwrnd->subseeds);
707 + kfree(rnd->layout);
711 +static int sunxi_nand_rnd_ctrl_init(struct mtd_info *mtd,
712 + struct nand_rnd_ctrl *rnd,
713 + struct nand_ecc_ctrl *ecc,
714 + struct device_node *np)
716 + struct sunxi_nand_hw_rnd *hwrnd;
717 + struct nand_rnd_layout *layout = NULL;
720 + hwrnd = kzalloc(sizeof(*hwrnd), GFP_KERNEL);
724 + hwrnd->seeds = default_seeds;
725 + hwrnd->nseeds = ARRAY_SIZE(default_seeds);
727 + if (of_get_property(np, "nand-randomizer-seeds", &ret)) {
728 + hwrnd->nseeds = ret / sizeof(*hwrnd->seeds);
729 + hwrnd->seeds = kzalloc(hwrnd->nseeds * sizeof(*hwrnd->seeds),
731 + if (!hwrnd->seeds) {
736 + ret = of_property_read_u16_array(np, "nand-randomizer-seeds",
737 + hwrnd->seeds, hwrnd->nseeds);
742 + switch (ecc->mode) {
743 + case NAND_ECC_HW_SYNDROME:
744 + hwrnd->step = sunxi_nfc_hw_syndrome_ecc_rnd_steps;
748 + hwrnd->step = sunxi_nfc_hw_ecc_rnd_steps;
751 + layout = kzalloc(sizeof(*layout) + sizeof(struct nand_rndfree),
757 + layout->nranges = 1;
758 + layout->ranges[0].offset = mtd->writesize;
759 + layout->ranges[0].length = 2;
760 + rnd->layout = layout;
764 + if (ecc->mode == NAND_ECC_HW_SYNDROME || ecc->mode == NAND_ECC_HW) {
767 + hwrnd->subseeds = kzalloc(hwrnd->nseeds *
768 + sizeof(*hwrnd->subseeds),
770 + if (!hwrnd->subseeds) {
775 + for (i = 0; i < hwrnd->nseeds; i++)
776 + hwrnd->subseeds[i] = sunxi_nfc_hwrnd_step(hwrnd,
781 + rnd->config = sunxi_nfc_hwrnd_config;
782 + rnd->read_buf = sunxi_nfc_hwrnd_read_buf;
783 + rnd->write_buf = sunxi_nfc_hwrnd_write_buf;
795 static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
796 const struct nand_sdr_timings *timings)
798 @@ -1084,6 +1596,40 @@ static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd,
802 +static void sunxi_nand_rnd_cleanup(struct nand_rnd_ctrl *rnd)
804 + switch (rnd->mode) {
806 + sunxi_nand_rnd_ctrl_cleanup(rnd);
813 +static int sunxi_nand_rnd_init(struct mtd_info *mtd,
814 + struct nand_rnd_ctrl *rnd,
815 + struct nand_ecc_ctrl *ecc,
816 + struct device_node *np)
820 + rnd->mode = NAND_RND_NONE;
822 + ret = of_get_nand_rnd_mode(np);
826 + switch (rnd->mode) {
828 + return sunxi_nand_rnd_ctrl_init(mtd, rnd, ecc, np);
836 static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
839 @@ -1175,7 +1721,14 @@ struct nand_part *sunxi_ofnandpart_parse(void *priv, struct mtd_info *master,
843 + ret = sunxi_nand_rnd_init(master, &part->rnd, &part->ecc, pp);
845 + sunxi_nand_ecc_cleanup(&part->ecc);
849 part->part.ecc = &part->ecc;
850 + part->part.rnd = &part->rnd;
854 @@ -1300,18 +1853,30 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
858 + chip->buffer = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
862 ret = sunxi_nand_chip_init_timings(chip, np);
864 dev_err(dev, "could not configure chip timings: %d\n", ret);
868 + ret = nand_pst_create(mtd);
872 ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np);
874 dev_err(dev, "ECC init failed: %d\n", ret);
878 + ret = sunxi_nand_rnd_init(mtd, &nand->rnd, &nand->ecc, np);
882 ret = nand_scan_tail(mtd);
884 dev_err(dev, "nand_scan_tail failed: %d\n", ret);
885 @@ -1367,6 +1932,8 @@ static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc)
887 nand_release(&chip->mtd);
888 sunxi_nand_ecc_cleanup(&chip->nand.ecc);
889 + sunxi_nand_rnd_cleanup(&chip->nand.rnd);
890 + kfree(chip->buffer);