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 --- a/drivers/mtd/nand/sunxi_nand.c
15 +++ b/drivers/mtd/nand/sunxi_nand.c
16 @@ -206,10 +206,12 @@ struct sunxi_nand_hw_ecc {
18 * @part: base paritition structure
19 * @ecc: per-partition ECC info
20 + * @rnd: per-partition randomizer info
22 struct sunxi_nand_part {
23 struct nand_part part;
24 struct nand_ecc_ctrl ecc;
25 + struct nand_rnd_ctrl rnd;
28 static inline struct sunxi_nand_part *
29 @@ -219,6 +221,29 @@ to_sunxi_nand_part(struct nand_part *par
33 + * sunxi NAND randomizer structure: stores NAND randomizer information
35 + * @page: current page
36 + * @column: current column
37 + * @nseeds: seed table size
38 + * @seeds: seed table
39 + * @subseeds: pre computed sub seeds
40 + * @step: step function
41 + * @left: number of remaining bytes in the page
42 + * @state: current randomizer state
44 +struct sunxi_nand_hw_rnd {
50 + u16 (*step)(struct mtd_info *mtd, u16 state, int column, int *left);
56 * NAND chip structure: stores NAND chip device related information
58 * @node: used to store NAND chips into a list
59 @@ -233,6 +258,7 @@ struct sunxi_nand_chip {
60 struct list_head node;
61 struct nand_chip nand;
64 unsigned long clk_rate;
67 @@ -489,6 +515,185 @@ static void sunxi_nfc_write_buf(struct m
71 +static u16 sunxi_nfc_hwrnd_step(struct sunxi_nand_hw_rnd *rnd, u16 state, int count)
76 + state = ((state >> 1) |
77 + ((((state >> 0) ^ (state >> 1)) & 1) << 14)) & 0x7fff;
82 +static u16 sunxi_nfc_hwrnd_single_step(u16 state, int count)
86 + state = ((state >> 1) |
87 + ((((state >> 0) ^ (state >> 1)) & 1) << 14)) & 0x7fff;
92 +static int sunxi_nfc_hwrnd_config(struct mtd_info *mtd, int page, int column,
93 + enum nand_rnd_action action)
95 + struct nand_chip *nand = mtd->priv;
96 + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
97 + struct sunxi_nand_hw_rnd *rnd = nand->cur_rnd->priv;
100 + if (page < 0 && column < 0) {
114 + if (page != rnd->page && action == NAND_RND_READ) {
117 + status = nand_page_get_status(mtd, page);
118 + if (status == NAND_PAGE_STATUS_UNKNOWN) {
119 + nand->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
120 + sunxi_nfc_read_buf(mtd, sunxi_nand->buffer,
121 + mtd->writesize + mtd->oobsize);
123 + if (nand_page_is_empty(mtd, sunxi_nand->buffer,
124 + sunxi_nand->buffer +
126 + status = NAND_PAGE_EMPTY;
128 + status = NAND_PAGE_FILLED;
130 + nand_page_set_status(mtd, page, status);
131 + nand->cmdfunc(mtd, NAND_CMD_RNDOUT, column, -1);
135 + state = rnd->seeds[page % rnd->nseeds];
137 + rnd->column = column;
140 + rnd->state = rnd->step(mtd, state, column, &rnd->left);
142 + rnd->state = sunxi_nfc_hwrnd_step(rnd, state, column % 4096);
143 + rnd->left = mtd->oobsize + mtd->writesize - column;
149 +static void sunxi_nfc_hwrnd_write_buf(struct mtd_info *mtd, const uint8_t *buf,
152 + struct nand_chip *nand = mtd->priv;
153 + struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
154 + struct sunxi_nand_hw_rnd *rnd = nand->cur_rnd->priv;
155 + u32 tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
160 + tmp &= ~(NFC_RANDOM_DIRECTION | NFC_RANDOM_SEED | NFC_RANDOM_EN);
161 + writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
163 + if (rnd->page < 0) {
164 + sunxi_nfc_write_buf(mtd, buf, len);
168 + while (len > offs) {
173 + rndactiv = nand_rnd_is_activ(mtd, rnd->page, rnd->column,
175 + if (rndactiv > 0) {
176 + writel(tmp | NFC_RANDOM_EN | (rnd->state << 16),
177 + nfc->regs + NFC_REG_ECC_CTL);
178 + if (rnd->left < cnt)
182 + sunxi_nfc_write_buf(mtd, buf + offs, cnt);
185 + writel(tmp & ~NFC_RANDOM_EN,
186 + nfc->regs + NFC_REG_ECC_CTL);
192 + sunxi_nfc_hwrnd_config(mtd, -1, rnd->column + cnt, NAND_RND_WRITE);
196 +static void sunxi_nfc_hwrnd_read_buf(struct mtd_info *mtd, uint8_t *buf,
199 + struct nand_chip *nand = mtd->priv;
200 + struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
201 + struct sunxi_nand_hw_rnd *rnd = nand->cur_rnd->priv;
202 + u32 tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
207 + tmp &= ~(NFC_RANDOM_DIRECTION | NFC_RANDOM_SEED | NFC_RANDOM_EN);
208 + writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
210 + if (rnd->page < 0) {
211 + sunxi_nfc_read_buf(mtd, buf, len);
215 + while (len > offs) {
220 + if (nand_page_get_status(mtd, rnd->page) != NAND_PAGE_EMPTY &&
221 + nand_rnd_is_activ(mtd, rnd->page, rnd->column, &cnt) > 0)
226 + if (rndactiv > 0) {
227 + writel(tmp | NFC_RANDOM_EN | (rnd->state << 16),
228 + nfc->regs + NFC_REG_ECC_CTL);
229 + if (rnd->left < cnt)
234 + sunxi_nfc_read_buf(mtd, buf + offs, cnt);
236 + sunxi_nfc_read_buf(mtd, NULL, cnt);
239 + writel(tmp & ~NFC_RANDOM_EN,
240 + nfc->regs + NFC_REG_ECC_CTL);
246 + sunxi_nfc_hwrnd_config(mtd, -1, rnd->column + cnt, NAND_RND_READ);
250 static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd)
253 @@ -538,16 +743,43 @@ static int sunxi_nfc_hw_ecc_read_page(st
254 int oob_required, int page)
256 struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller);
257 + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(chip);
258 struct nand_ecc_ctrl *ecc = chip->cur_ecc;
259 struct nand_ecclayout *layout = ecc->layout;
260 struct sunxi_nand_hw_ecc *data = ecc->priv;
261 unsigned int max_bitflips = 0;
269 + status = nand_page_get_status(mtd, page);
270 + if (status == NAND_PAGE_STATUS_UNKNOWN) {
271 + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
272 + sunxi_nfc_read_buf(mtd, sunxi_nand->buffer,
273 + mtd->writesize + mtd->oobsize);
275 + if (nand_page_is_empty(mtd, sunxi_nand->buffer,
276 + sunxi_nand->buffer +
278 + status = NAND_PAGE_EMPTY;
280 + status = NAND_PAGE_FILLED;
281 + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
284 + nand_page_set_status(mtd, page, status);
287 + if (status == NAND_PAGE_EMPTY) {
288 + memset(buf, 0xff, mtd->writesize);
290 + memset(chip->oob_poi, 0xff, mtd->oobsize);
294 tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
295 tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE);
296 tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) |
297 @@ -556,12 +788,15 @@ static int sunxi_nfc_hw_ecc_read_page(st
298 writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
300 for (i = 0; i < ecc->steps; i++) {
301 + bool rndactiv = false;
304 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, i * ecc->size, -1);
306 offset = mtd->writesize + layout->eccpos[i * ecc->bytes] - 4;
308 - chip->read_buf(mtd, NULL, ecc->size);
309 + nand_rnd_config(mtd, page, i * ecc->size, NAND_RND_READ);
310 + nand_rnd_read_buf(mtd, NULL, ecc->size);
312 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
314 @@ -569,6 +804,25 @@ static int sunxi_nfc_hw_ecc_read_page(st
319 + cnt = ecc->bytes + 4;
320 + if (nand_rnd_is_activ(mtd, page, offset, &cnt) > 0 &&
321 + cnt == ecc->bytes + 4)
324 + cnt = ecc->bytes + 2;
325 + if (nand_rnd_is_activ(mtd, page, offset + 2, &cnt) > 0 &&
326 + cnt == ecc->bytes + 2)
331 + tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
332 + tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION);
333 + tmp |= NFC_RANDOM_EN;
334 + writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
337 tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30);
338 writel(tmp, nfc->regs + NFC_REG_CMD);
340 @@ -579,6 +833,9 @@ static int sunxi_nfc_hw_ecc_read_page(st
341 memcpy_fromio(buf + (i * ecc->size),
342 nfc->regs + NFC_RAM0_BASE, ecc->size);
344 + writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
345 + nfc->regs + NFC_REG_ECC_CTL);
347 if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) {
348 mtd->ecc_stats.failed++;
350 @@ -594,9 +851,10 @@ static int sunxi_nfc_hw_ecc_read_page(st
354 + nand_rnd_config(mtd, -1, offset, NAND_RND_READ);
355 offset -= mtd->writesize;
356 - chip->read_buf(mtd, chip->oob_poi + offset,
358 + nand_rnd_read_buf(mtd, chip->oob_poi + offset,
363 @@ -606,11 +864,14 @@ static int sunxi_nfc_hw_ecc_read_page(st
364 offset = mtd->writesize +
365 ecc->layout->oobfree[ecc->steps].offset;
366 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
367 + nand_rnd_config(mtd, -1, offset, NAND_RND_READ);
368 offset -= mtd->writesize;
369 - chip->read_buf(mtd, chip->oob_poi + offset, cnt);
370 + nand_rnd_read_buf(mtd, chip->oob_poi + offset, cnt);
374 + nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
376 tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
379 @@ -627,6 +888,7 @@ static int sunxi_nfc_hw_ecc_write_page(s
380 struct nand_ecc_ctrl *ecc = chip->cur_ecc;
381 struct nand_ecclayout *layout = ecc->layout;
382 struct sunxi_nand_hw_ecc *data = ecc->priv;
383 + struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv;
387 @@ -641,22 +903,56 @@ static int sunxi_nfc_hw_ecc_write_page(s
388 writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
390 for (i = 0; i < ecc->steps; i++) {
391 + bool rndactiv = false;
395 chip->cmdfunc(mtd, NAND_CMD_RNDIN, i * ecc->size, -1);
397 - chip->write_buf(mtd, buf + (i * ecc->size), ecc->size);
398 + nand_rnd_config(mtd, -1, i * ecc->size, NAND_RND_WRITE);
399 + nand_rnd_write_buf(mtd, buf + (i * ecc->size), ecc->size);
401 offset = layout->eccpos[i * ecc->bytes] - 4 + mtd->writesize;
403 /* Fill OOB data in */
404 - if (oob_required) {
406 - memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, &tmp,
409 + memset(oob_buf, 0xff, 4);
412 + chip->oob_poi + layout->oobfree[i].offset,
416 + memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, oob_buf, 4);
419 + cnt = ecc->bytes + 4;
421 + nand_rnd_is_activ(mtd, -1, offset, &cnt) > 0 &&
422 + cnt == ecc->bytes + 4)
425 - memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE,
426 - chip->oob_poi + offset - mtd->writesize,
428 + cnt = ecc->bytes + 2;
430 + nand_rnd_is_activ(mtd, -1, offset + 2, &cnt) > 0 &&
431 + cnt == ecc->bytes + 2)
436 + /* pre randomize to generate FF patterns on the NAND */
438 + u16 state = rnd->subseeds[rnd->page % rnd->nseeds];
439 + state = sunxi_nfc_hwrnd_single_step(state, 15);
440 + oob_buf[0] ^= state;
441 + state = sunxi_nfc_hwrnd_step(rnd, state, 1);
442 + oob_buf[1] ^= state;
443 + memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, oob_buf, 4);
445 + tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
446 + tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION);
447 + tmp |= NFC_RANDOM_EN;
448 + writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
451 chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1);
452 @@ -671,6 +967,9 @@ static int sunxi_nfc_hw_ecc_write_page(s
453 ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
457 + writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
458 + nfc->regs + NFC_REG_ECC_CTL);
462 @@ -679,11 +978,14 @@ static int sunxi_nfc_hw_ecc_write_page(s
463 offset = mtd->writesize +
464 ecc->layout->oobfree[i].offset;
465 chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1);
466 + nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE);
467 offset -= mtd->writesize;
468 - chip->write_buf(mtd, chip->oob_poi + offset, cnt);
469 + nand_rnd_write_buf(mtd, chip->oob_poi + offset, cnt);
473 + nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE);
475 tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
478 @@ -692,22 +994,76 @@ static int sunxi_nfc_hw_ecc_write_page(s
482 +static u16 sunxi_nfc_hw_ecc_rnd_steps(struct mtd_info *mtd, u16 state,
483 + int column, int *left)
485 + struct nand_chip *chip = mtd->priv;
486 + struct nand_ecc_ctrl *ecc = chip->cur_ecc;
487 + struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv;
488 + int nblks = mtd->writesize / ecc->size;
489 + int modsize = ecc->size;
492 + if (column < mtd->writesize) {
493 + steps = column % modsize;
494 + *left = modsize - steps;
495 + } else if (column < mtd->writesize +
496 + (nblks * (ecc->bytes + 4))) {
497 + column -= mtd->writesize;
498 + steps = column % (ecc->bytes + 4);
499 + *left = ecc->bytes + 4 - steps;
500 + state = rnd->subseeds[rnd->page % rnd->nseeds];
502 + steps = column % 4096;
503 + *left = mtd->writesize + mtd->oobsize - column;
506 + return sunxi_nfc_hwrnd_step(rnd, state, steps);
509 static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
510 struct nand_chip *chip,
511 uint8_t *buf, int oob_required,
514 struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller);
515 + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(chip);
516 struct nand_ecc_ctrl *ecc = chip->cur_ecc;
517 struct sunxi_nand_hw_ecc *data = ecc->priv;
518 unsigned int max_bitflips = 0;
519 uint8_t *oob = chip->oob_poi;
527 + status = nand_page_get_status(mtd, page);
528 + if (status == NAND_PAGE_STATUS_UNKNOWN) {
529 + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
530 + sunxi_nfc_read_buf(mtd, sunxi_nand->buffer,
531 + mtd->writesize + mtd->oobsize);
533 + if (nand_page_is_empty(mtd, sunxi_nand->buffer,
534 + sunxi_nand->buffer +
536 + status = NAND_PAGE_EMPTY;
538 + status = NAND_PAGE_FILLED;
539 + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
542 + nand_page_set_status(mtd, page, status);
545 + if (status == NAND_PAGE_EMPTY) {
546 + memset(buf, 0xff, mtd->writesize);
548 + memset(chip->oob_poi, 0xff, mtd->oobsize);
552 tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
553 tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE);
554 tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) |
555 @@ -716,7 +1072,17 @@ static int sunxi_nfc_hw_syndrome_ecc_rea
556 writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
558 for (i = 0; i < ecc->steps; i++) {
559 - chip->read_buf(mtd, NULL, ecc->size);
560 + nand_rnd_config(mtd, page, offset, NAND_RND_READ);
561 + nand_rnd_read_buf(mtd, NULL, ecc->size);
563 + cnt = ecc->bytes + 4;
564 + if (nand_rnd_is_activ(mtd, page, offset, &cnt) > 0 &&
565 + cnt == ecc->bytes + 4) {
566 + tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
567 + tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION);
568 + tmp |= NFC_RANDOM_EN;
569 + writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
572 tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30);
573 writel(tmp, nfc->regs + NFC_REG_CMD);
574 @@ -729,6 +1095,9 @@ static int sunxi_nfc_hw_syndrome_ecc_rea
578 + writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
579 + nfc->regs + NFC_REG_ECC_CTL);
581 if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) {
582 mtd->ecc_stats.failed++;
584 @@ -739,7 +1108,8 @@ static int sunxi_nfc_hw_syndrome_ecc_rea
587 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
588 - chip->read_buf(mtd, oob, ecc->bytes + ecc->prepad);
589 + nand_rnd_config(mtd, -1, offset, NAND_RND_READ);
590 + nand_rnd_read_buf(mtd, oob, ecc->bytes + ecc->prepad);
591 oob += ecc->bytes + ecc->prepad;
594 @@ -750,10 +1120,13 @@ static int sunxi_nfc_hw_syndrome_ecc_rea
595 cnt = mtd->oobsize - (oob - chip->oob_poi);
597 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
598 - chip->read_buf(mtd, oob, cnt);
599 + nand_rnd_config(mtd, page, offset, NAND_RND_READ);
600 + nand_rnd_read_buf(mtd, oob, cnt);
604 + nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
606 writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN,
607 nfc->regs + NFC_REG_ECC_CTL);
609 @@ -768,6 +1141,7 @@ static int sunxi_nfc_hw_syndrome_ecc_wri
610 struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller);
611 struct nand_ecc_ctrl *ecc = chip->cur_ecc;
612 struct sunxi_nand_hw_ecc *data = ecc->priv;
613 + struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv;
614 uint8_t *oob = chip->oob_poi;
617 @@ -783,7 +1157,8 @@ static int sunxi_nfc_hw_syndrome_ecc_wri
618 writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
620 for (i = 0; i < ecc->steps; i++) {
621 - chip->write_buf(mtd, buf + (i * ecc->size), ecc->size);
622 + nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE);
623 + nand_rnd_write_buf(mtd, buf + (i * ecc->size), ecc->size);
626 /* Fill OOB data in */
627 @@ -796,6 +1171,16 @@ static int sunxi_nfc_hw_syndrome_ecc_wri
631 + cnt = ecc->bytes + 4;
633 + nand_rnd_is_activ(mtd, rnd->page, offset, &cnt) > 0 &&
634 + cnt == ecc->bytes + 4) {
635 + tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
636 + tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION);
637 + tmp |= NFC_RANDOM_EN;
638 + writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
641 tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ACCESS_DIR |
643 writel(tmp, nfc->regs + NFC_REG_CMD);
644 @@ -804,6 +1189,9 @@ static int sunxi_nfc_hw_syndrome_ecc_wri
648 + writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
649 + nfc->regs + NFC_REG_ECC_CTL);
651 offset += ecc->bytes + ecc->prepad;
652 oob += ecc->bytes + ecc->prepad;
654 @@ -812,9 +1200,11 @@ static int sunxi_nfc_hw_syndrome_ecc_wri
655 cnt = mtd->oobsize - (oob - chip->oob_poi);
657 chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1);
658 - chip->write_buf(mtd, oob, cnt);
659 + nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE);
660 + nand_rnd_write_buf(mtd, oob, cnt);
663 + nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE);
665 tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
667 @@ -824,6 +1214,128 @@ static int sunxi_nfc_hw_syndrome_ecc_wri
671 +static u16 sunxi_nfc_hw_syndrome_ecc_rnd_steps(struct mtd_info *mtd, u16 state,
672 + int column, int *left)
674 + struct nand_chip *chip = mtd->priv;
675 + struct nand_ecc_ctrl *ecc = chip->cur_ecc;
676 + struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv;
677 + int eccsteps = mtd->writesize / ecc->size;
678 + int modsize = ecc->size + ecc->prepad + ecc->bytes;
681 + if (column < (eccsteps * modsize)) {
682 + steps = column % modsize;
683 + *left = modsize - steps;
684 + if (steps >= ecc->size) {
685 + steps -= ecc->size;
686 + state = rnd->subseeds[rnd->page % rnd->nseeds];
689 + steps = column % 4096;
690 + *left = mtd->writesize + mtd->oobsize - column;
693 + return sunxi_nfc_hwrnd_step(rnd, state, steps);
696 +static u16 default_seeds[] = {0x4a80};
698 +static void sunxi_nand_rnd_ctrl_cleanup(struct nand_rnd_ctrl *rnd)
700 + struct sunxi_nand_hw_rnd *hwrnd = rnd->priv;
702 + if (hwrnd->seeds != default_seeds)
703 + kfree(hwrnd->seeds);
704 + kfree(hwrnd->subseeds);
705 + kfree(rnd->layout);
709 +static int sunxi_nand_rnd_ctrl_init(struct mtd_info *mtd,
710 + struct nand_rnd_ctrl *rnd,
711 + struct nand_ecc_ctrl *ecc,
712 + struct device_node *np)
714 + struct sunxi_nand_hw_rnd *hwrnd;
715 + struct nand_rnd_layout *layout = NULL;
718 + hwrnd = kzalloc(sizeof(*hwrnd), GFP_KERNEL);
722 + hwrnd->seeds = default_seeds;
723 + hwrnd->nseeds = ARRAY_SIZE(default_seeds);
725 + if (of_get_property(np, "nand-randomizer-seeds", &ret)) {
726 + hwrnd->nseeds = ret / sizeof(*hwrnd->seeds);
727 + hwrnd->seeds = kzalloc(hwrnd->nseeds * sizeof(*hwrnd->seeds),
729 + if (!hwrnd->seeds) {
734 + ret = of_property_read_u16_array(np, "nand-randomizer-seeds",
735 + hwrnd->seeds, hwrnd->nseeds);
740 + switch (ecc->mode) {
741 + case NAND_ECC_HW_SYNDROME:
742 + hwrnd->step = sunxi_nfc_hw_syndrome_ecc_rnd_steps;
746 + hwrnd->step = sunxi_nfc_hw_ecc_rnd_steps;
749 + layout = kzalloc(sizeof(*layout) + sizeof(struct nand_rndfree),
755 + layout->nranges = 1;
756 + layout->ranges[0].offset = mtd->writesize;
757 + layout->ranges[0].length = 2;
758 + rnd->layout = layout;
762 + if (ecc->mode == NAND_ECC_HW_SYNDROME || ecc->mode == NAND_ECC_HW) {
765 + hwrnd->subseeds = kzalloc(hwrnd->nseeds *
766 + sizeof(*hwrnd->subseeds),
768 + if (!hwrnd->subseeds) {
773 + for (i = 0; i < hwrnd->nseeds; i++)
774 + hwrnd->subseeds[i] = sunxi_nfc_hwrnd_step(hwrnd,
779 + rnd->config = sunxi_nfc_hwrnd_config;
780 + rnd->read_buf = sunxi_nfc_hwrnd_read_buf;
781 + rnd->write_buf = sunxi_nfc_hwrnd_write_buf;
793 static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
794 const struct nand_sdr_timings *timings)
796 @@ -1084,6 +1596,40 @@ static int sunxi_nand_hw_syndrome_ecc_ct
800 +static void sunxi_nand_rnd_cleanup(struct nand_rnd_ctrl *rnd)
802 + switch (rnd->mode) {
804 + sunxi_nand_rnd_ctrl_cleanup(rnd);
811 +static int sunxi_nand_rnd_init(struct mtd_info *mtd,
812 + struct nand_rnd_ctrl *rnd,
813 + struct nand_ecc_ctrl *ecc,
814 + struct device_node *np)
818 + rnd->mode = NAND_RND_NONE;
820 + ret = of_get_nand_rnd_mode(np);
824 + switch (rnd->mode) {
826 + return sunxi_nand_rnd_ctrl_init(mtd, rnd, ecc, np);
834 static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
837 @@ -1175,7 +1721,14 @@ struct nand_part *sunxi_ofnandpart_parse
841 + ret = sunxi_nand_rnd_init(master, &part->rnd, &part->ecc, pp);
843 + sunxi_nand_ecc_cleanup(&part->ecc);
847 part->part.ecc = &part->ecc;
848 + part->part.rnd = &part->rnd;
852 @@ -1300,18 +1853,30 @@ static int sunxi_nand_chip_init(struct d
856 + chip->buffer = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
860 ret = sunxi_nand_chip_init_timings(chip, np);
862 dev_err(dev, "could not configure chip timings: %d\n", ret);
866 + ret = nand_pst_create(mtd);
870 ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np);
872 dev_err(dev, "ECC init failed: %d\n", ret);
876 + ret = sunxi_nand_rnd_init(mtd, &nand->rnd, &nand->ecc, np);
880 ret = nand_scan_tail(mtd);
882 dev_err(dev, "nand_scan_tail failed: %d\n", ret);
883 @@ -1367,6 +1932,8 @@ static void sunxi_nand_chips_cleanup(str
885 nand_release(&chip->mtd);
886 sunxi_nand_ecc_cleanup(&chip->nand.ecc);
887 + sunxi_nand_rnd_cleanup(&chip->nand.rnd);
888 + kfree(chip->buffer);