ramips: fix for kernel 4.0 napi repoll need return budgets number
[lede.git] / target / linux / sunxi / patches-4.1 / 123-mtd-nand-sunxi-add-hw-randomizer-support.patch
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
5
6 Add support for the HW randomizer available on the sunxi nand controller.
7
8 Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
9 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
10 ---
11  drivers/mtd/nand/sunxi_nand.c | 603 ++++++++++++++++++++++++++++++++++++++++--
12  1 file changed, 585 insertions(+), 18 deletions(-)
13
14 --- a/drivers/mtd/nand/sunxi_nand.c
15 +++ b/drivers/mtd/nand/sunxi_nand.c
16 @@ -210,10 +210,12 @@ struct sunxi_nand_hw_ecc {
17   *
18   * @part: base paritition structure
19   * @ecc: per-partition ECC info
20 + * @rnd: per-partition randomizer info
21   */
22  struct sunxi_nand_part {
23         struct nand_part part;
24         struct nand_ecc_ctrl ecc;
25 +       struct nand_rnd_ctrl rnd;
26  };
27  
28  static inline struct sunxi_nand_part *
29 @@ -223,6 +225,29 @@ to_sunxi_nand_part(struct nand_part *par
30  }
31  
32  /*
33 + * sunxi NAND randomizer structure: stores NAND randomizer information
34 + *
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
43 + */
44 +struct sunxi_nand_hw_rnd {
45 +       int page;
46 +       int column;
47 +       int nseeds;
48 +       u16 *seeds;
49 +       u16 *subseeds;
50 +       u16 (*step)(struct mtd_info *mtd, u16 state, int column, int *left);
51 +       int left;
52 +       u16 state;
53 +};
54 +
55 +/*
56   * NAND chip structure: stores NAND chip device related information
57   *
58   * @node:              used to store NAND chips into a list
59 @@ -237,6 +262,7 @@ struct sunxi_nand_chip {
60         struct list_head node;
61         struct nand_chip nand;
62         struct mtd_info mtd;
63 +       void *buffer;
64         unsigned long clk_rate;
65         int selected;
66         int nsels;
67 @@ -493,6 +519,185 @@ static void sunxi_nfc_write_buf(struct m
68         }
69  }
70  
71 +static u16 sunxi_nfc_hwrnd_step(struct sunxi_nand_hw_rnd *rnd, u16 state, int count)
72 +{
73 +       state &= 0x7fff;
74 +       count *= 8;
75 +       while (count--)
76 +               state = ((state >> 1) |
77 +                        ((((state >> 0) ^ (state >> 1)) & 1) << 14)) & 0x7fff;
78 +
79 +       return state;
80 +}
81 +
82 +static u16 sunxi_nfc_hwrnd_single_step(u16 state, int count)
83 +{
84 +       state &= 0x7fff;
85 +       while (count--)
86 +               state = ((state >> 1) |
87 +                        ((((state >> 0) ^ (state >> 1)) & 1) << 14)) & 0x7fff;
88 +
89 +       return state;
90 +}
91 +
92 +static int sunxi_nfc_hwrnd_config(struct mtd_info *mtd, int page, int column,
93 +                                 enum nand_rnd_action action)
94 +{
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;
98 +       u16 state;
99 +
100 +       if (page < 0 && column < 0) {
101 +               rnd->page = -1;
102 +               rnd->column = -1;
103 +               return 0;
104 +       }
105 +
106 +       if (column < 0)
107 +               column = 0;
108 +       if (page < 0)
109 +               page = rnd->page;
110 +
111 +       if (page < 0)
112 +               return -EINVAL;
113 +
114 +       if (page != rnd->page && action == NAND_RND_READ) {
115 +               int status;
116 +
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);
122 +
123 +                       if (nand_page_is_empty(mtd, sunxi_nand->buffer,
124 +                                              sunxi_nand->buffer +
125 +                                              mtd->writesize))
126 +                               status = NAND_PAGE_EMPTY;
127 +                       else
128 +                               status = NAND_PAGE_FILLED;
129 +
130 +                       nand_page_set_status(mtd, page, status);
131 +                       nand->cmdfunc(mtd, NAND_CMD_RNDOUT, column, -1);
132 +               }
133 +       }
134 +
135 +       state = rnd->seeds[page % rnd->nseeds];
136 +       rnd->page = page;
137 +       rnd->column = column;
138 +
139 +       if (rnd->step) {
140 +               rnd->state = rnd->step(mtd, state, column, &rnd->left);
141 +       } else {
142 +               rnd->state = sunxi_nfc_hwrnd_step(rnd, state, column % 4096);
143 +               rnd->left = mtd->oobsize + mtd->writesize - column;
144 +       }
145 +
146 +       return 0;
147 +}
148 +
149 +static void sunxi_nfc_hwrnd_write_buf(struct mtd_info *mtd, const uint8_t *buf,
150 +                                     int len)
151 +{
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);
156 +       int cnt;
157 +       int offs = 0;
158 +       int rndactiv;
159 +
160 +       tmp &= ~(NFC_RANDOM_DIRECTION | NFC_RANDOM_SEED | NFC_RANDOM_EN);
161 +       writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
162 +
163 +       if (rnd->page < 0) {
164 +               sunxi_nfc_write_buf(mtd, buf, len);
165 +               return;
166 +       }
167 +
168 +       while (len > offs) {
169 +               cnt = len - offs;
170 +               if (cnt > 1024)
171 +                       cnt = 1024;
172 +
173 +               rndactiv = nand_rnd_is_activ(mtd, rnd->page, rnd->column,
174 +                                            &cnt);
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)
179 +                               cnt = rnd->left;
180 +               }
181 +
182 +               sunxi_nfc_write_buf(mtd, buf + offs, cnt);
183 +
184 +               if (rndactiv > 0)
185 +                       writel(tmp & ~NFC_RANDOM_EN,
186 +                              nfc->regs + NFC_REG_ECC_CTL);
187 +
188 +               offs += cnt;
189 +               if (len <= offs)
190 +                       break;
191 +
192 +               sunxi_nfc_hwrnd_config(mtd, -1, rnd->column + cnt, NAND_RND_WRITE);
193 +       }
194 +}
195 +
196 +static void sunxi_nfc_hwrnd_read_buf(struct mtd_info *mtd, uint8_t *buf,
197 +                                    int len)
198 +{
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);
203 +       int cnt;
204 +       int offs = 0;
205 +       int rndactiv;
206 +
207 +       tmp &= ~(NFC_RANDOM_DIRECTION | NFC_RANDOM_SEED | NFC_RANDOM_EN);
208 +       writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
209 +
210 +       if (rnd->page < 0) {
211 +               sunxi_nfc_read_buf(mtd, buf, len);
212 +               return;
213 +       }
214 +
215 +       while (len > offs) {
216 +               cnt = len - offs;
217 +               if (cnt > 1024)
218 +                       cnt = 1024;
219 +
220 +               if (nand_page_get_status(mtd, rnd->page) != NAND_PAGE_EMPTY &&
221 +                   nand_rnd_is_activ(mtd, rnd->page, rnd->column, &cnt) > 0)
222 +                       rndactiv = 1;
223 +               else
224 +                       rndactiv = 0;
225 +
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)
230 +                               cnt = rnd->left;
231 +               }
232 +
233 +               if (buf)
234 +                       sunxi_nfc_read_buf(mtd, buf + offs, cnt);
235 +               else
236 +                       sunxi_nfc_read_buf(mtd, NULL, cnt);
237 +
238 +               if (rndactiv > 0)
239 +                       writel(tmp & ~NFC_RANDOM_EN,
240 +                              nfc->regs + NFC_REG_ECC_CTL);
241 +
242 +               offs += cnt;
243 +               if (len <= offs)
244 +                       break;
245 +
246 +               sunxi_nfc_hwrnd_config(mtd, -1, rnd->column + cnt, NAND_RND_READ);
247 +       }
248 +}
249 +
250  static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd)
251  {
252         uint8_t ret;
253 @@ -542,16 +747,43 @@ static int sunxi_nfc_hw_ecc_read_page(st
254                                       int oob_required, int page)
255  {
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;
262 +       int status;
263         int offset;
264         int ret;
265         u32 tmp;
266         int i;
267         int cnt;
268  
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);
274 +
275 +               if (nand_page_is_empty(mtd, sunxi_nand->buffer,
276 +                                      sunxi_nand->buffer +
277 +                                      mtd->writesize)) {
278 +                       status = NAND_PAGE_EMPTY;
279 +               } else {
280 +                       status = NAND_PAGE_FILLED;
281 +                       chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
282 +               }
283 +
284 +               nand_page_set_status(mtd, page, status);
285 +       }
286 +
287 +       if (status == NAND_PAGE_EMPTY) {
288 +               memset(buf, 0xff, mtd->writesize);
289 +               if (oob_required)
290 +                       memset(chip->oob_poi, 0xff, mtd->oobsize);
291 +               return 0;
292 +       }
293 +
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 @@ -560,12 +792,15 @@ static int sunxi_nfc_hw_ecc_read_page(st
298         writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
299  
300         for (i = 0; i < ecc->steps; i++) {
301 +               bool rndactiv = false;
302 +
303                 if (i)
304                         chip->cmdfunc(mtd, NAND_CMD_RNDOUT, i * ecc->size, -1);
305  
306                 offset = mtd->writesize + layout->eccpos[i * ecc->bytes] - 4;
307  
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);
311  
312                 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
313  
314 @@ -573,6 +808,25 @@ static int sunxi_nfc_hw_ecc_read_page(st
315                 if (ret)
316                         return ret;
317  
318 +               if (i) {
319 +                       cnt = ecc->bytes + 4;
320 +                       if (nand_rnd_is_activ(mtd, page, offset, &cnt) > 0 &&
321 +                           cnt == ecc->bytes + 4)
322 +                               rndactiv = true;
323 +               } else {
324 +                       cnt = ecc->bytes + 2;
325 +                       if (nand_rnd_is_activ(mtd, page, offset + 2, &cnt) > 0 &&
326 +                           cnt == ecc->bytes + 2)
327 +                               rndactiv = true;
328 +               }
329 +
330 +               if (rndactiv) {
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);
335 +               }
336 +
337                 tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30);
338                 writel(tmp, nfc->regs + NFC_REG_CMD);
339  
340 @@ -583,6 +837,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);
343  
344 +               writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
345 +                      nfc->regs + NFC_REG_ECC_CTL);
346 +
347                 if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) {
348                         mtd->ecc_stats.failed++;
349                 } else {
350 @@ -598,9 +855,10 @@ static int sunxi_nfc_hw_ecc_read_page(st
351                         if (ret)
352                                 return ret;
353  
354 +                       nand_rnd_config(mtd, -1, offset, NAND_RND_READ);
355                         offset -= mtd->writesize;
356 -                       chip->read_buf(mtd, chip->oob_poi + offset,
357 -                                     ecc->bytes + 4);
358 +                       nand_rnd_read_buf(mtd, chip->oob_poi + offset,
359 +                                         ecc->bytes + 4);
360                 }
361         }
362  
363 @@ -610,11 +868,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);
371                 }
372         }
373  
374 +       nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
375 +
376         tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
377         tmp &= ~NFC_ECC_EN;
378  
379 @@ -631,6 +892,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;
384         int offset;
385         int ret;
386         u32 tmp;
387 @@ -645,17 +907,57 @@ static int sunxi_nfc_hw_ecc_write_page(s
388         writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
389  
390         for (i = 0; i < ecc->steps; i++) {
391 +               bool rndactiv = false;
392 +               u8 oob_buf[4];
393 +
394                 if (i)
395                         chip->cmdfunc(mtd, NAND_CMD_RNDIN, i * ecc->size, -1);
396  
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);
400  
401                 offset = layout->eccpos[i * ecc->bytes] - 4 + mtd->writesize;
402  
403                 /* Fill OOB data in */
404 -               writel(NFC_BUF_TO_USER_DATA(chip->oob_poi +
405 -                                           layout->oobfree[i].offset),
406 -                      nfc->regs + NFC_REG_USER_DATA_BASE);
407 +               if (!oob_required)
408 +                       memset(oob_buf, 0xff, 4);
409 +               else
410 +                       memcpy(oob_buf,
411 +                              chip->oob_poi + layout->oobfree[i].offset,
412 +                              4);
413 +
414 +
415 +               memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, oob_buf, 4);
416 +
417 +               if (i) {
418 +                       cnt = ecc->bytes + 4;
419 +                       if (rnd &&
420 +                           nand_rnd_is_activ(mtd, -1, offset, &cnt) > 0 &&
421 +                           cnt == ecc->bytes + 4)
422 +                               rndactiv = true;
423 +               } else {
424 +                       cnt = ecc->bytes + 2;
425 +                       if (rnd &&
426 +                           nand_rnd_is_activ(mtd, -1, offset + 2, &cnt) > 0 &&
427 +                           cnt == ecc->bytes + 2)
428 +                               rndactiv = true;
429 +               }
430 +
431 +               if (rndactiv) {
432 +                       /* pre randomize to generate FF patterns on the NAND */
433 +                       if (!i) {
434 +                               u16 state = rnd->subseeds[rnd->page % rnd->nseeds];
435 +                               state = sunxi_nfc_hwrnd_single_step(state, 15);
436 +                               oob_buf[0] ^= state;
437 +                               state = sunxi_nfc_hwrnd_step(rnd, state, 1);
438 +                               oob_buf[1] ^= state;
439 +                               memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, oob_buf, 4);
440 +                       }
441 +                       tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
442 +                       tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION);
443 +                       tmp |= NFC_RANDOM_EN;
444 +                       writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
445 +               }
446  
447                 chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1);
448  
449 @@ -669,6 +971,9 @@ static int sunxi_nfc_hw_ecc_write_page(s
450                 ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
451                 if (ret)
452                         return ret;
453 +
454 +               writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
455 +                      nfc->regs + NFC_REG_ECC_CTL);
456         }
457  
458         if (oob_required) {
459 @@ -677,11 +982,14 @@ static int sunxi_nfc_hw_ecc_write_page(s
460                         offset = mtd->writesize +
461                                  ecc->layout->oobfree[i].offset;
462                         chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1);
463 +                       nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE);
464                         offset -= mtd->writesize;
465 -                       chip->write_buf(mtd, chip->oob_poi + offset, cnt);
466 +                       nand_rnd_write_buf(mtd, chip->oob_poi + offset, cnt);
467                 }
468         }
469  
470 +       nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE);
471 +
472         tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
473         tmp &= ~NFC_ECC_EN;
474  
475 @@ -690,22 +998,76 @@ static int sunxi_nfc_hw_ecc_write_page(s
476         return 0;
477  }
478  
479 +static u16 sunxi_nfc_hw_ecc_rnd_steps(struct mtd_info *mtd, u16 state,
480 +                                     int column, int *left)
481 +{
482 +       struct nand_chip *chip = mtd->priv;
483 +       struct nand_ecc_ctrl *ecc = chip->cur_ecc;
484 +       struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv;
485 +       int nblks = mtd->writesize / ecc->size;
486 +       int modsize = ecc->size;
487 +       int steps;
488 +
489 +       if (column < mtd->writesize) {
490 +               steps = column % modsize;
491 +               *left = modsize - steps;
492 +       } else if (column < mtd->writesize +
493 +                           (nblks * (ecc->bytes + 4))) {
494 +               column -= mtd->writesize;
495 +               steps = column % (ecc->bytes + 4);
496 +               *left = ecc->bytes + 4 - steps;
497 +               state = rnd->subseeds[rnd->page % rnd->nseeds];
498 +       } else {
499 +               steps = column % 4096;
500 +               *left = mtd->writesize + mtd->oobsize - column;
501 +       }
502 +
503 +       return sunxi_nfc_hwrnd_step(rnd, state, steps);
504 +}
505 +
506  static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
507                                                struct nand_chip *chip,
508                                                uint8_t *buf, int oob_required,
509                                                int page)
510  {
511         struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller);
512 +       struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(chip);
513         struct nand_ecc_ctrl *ecc = chip->cur_ecc;
514         struct sunxi_nand_hw_ecc *data = ecc->priv;
515         unsigned int max_bitflips = 0;
516         uint8_t *oob = chip->oob_poi;
517         int offset = 0;
518         int ret;
519 +       int status;
520         int cnt;
521         u32 tmp;
522         int i;
523  
524 +       status = nand_page_get_status(mtd, page);
525 +       if (status == NAND_PAGE_STATUS_UNKNOWN) {
526 +               chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
527 +               sunxi_nfc_read_buf(mtd, sunxi_nand->buffer,
528 +                                  mtd->writesize + mtd->oobsize);
529 +
530 +               if (nand_page_is_empty(mtd, sunxi_nand->buffer,
531 +                                      sunxi_nand->buffer +
532 +                                      mtd->writesize)) {
533 +                       status = NAND_PAGE_EMPTY;
534 +               } else {
535 +                       status = NAND_PAGE_FILLED;
536 +                       chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
537 +               }
538 +
539 +               nand_page_set_status(mtd, page, status);
540 +       }
541 +
542 +       if (status == NAND_PAGE_EMPTY) {
543 +               memset(buf, 0xff, mtd->writesize);
544 +               if (oob_required)
545 +                       memset(chip->oob_poi, 0xff, mtd->oobsize);
546 +               return 0;
547 +       }
548 +
549         tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
550         tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE);
551         tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) |
552 @@ -714,7 +1076,17 @@ static int sunxi_nfc_hw_syndrome_ecc_rea
553         writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
554  
555         for (i = 0; i < ecc->steps; i++) {
556 -               chip->read_buf(mtd, NULL, ecc->size);
557 +               nand_rnd_config(mtd, page, offset, NAND_RND_READ);
558 +               nand_rnd_read_buf(mtd, NULL, ecc->size);
559 +
560 +               cnt = ecc->bytes + 4;
561 +               if (nand_rnd_is_activ(mtd, page, offset, &cnt) > 0 &&
562 +                   cnt == ecc->bytes + 4) {
563 +                       tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
564 +                       tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION);
565 +                       tmp |= NFC_RANDOM_EN;
566 +                       writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
567 +               }
568  
569                 tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30);
570                 writel(tmp, nfc->regs + NFC_REG_CMD);
571 @@ -727,6 +1099,9 @@ static int sunxi_nfc_hw_syndrome_ecc_rea
572                 buf += ecc->size;
573                 offset += ecc->size;
574  
575 +               writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
576 +                      nfc->regs + NFC_REG_ECC_CTL);
577 +
578                 if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) {
579                         mtd->ecc_stats.failed++;
580                 } else {
581 @@ -737,7 +1112,8 @@ static int sunxi_nfc_hw_syndrome_ecc_rea
582  
583                 if (oob_required) {
584                         chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
585 -                       chip->read_buf(mtd, oob, ecc->bytes + ecc->prepad);
586 +                       nand_rnd_config(mtd, -1, offset, NAND_RND_READ);
587 +                       nand_rnd_read_buf(mtd, oob, ecc->bytes + ecc->prepad);
588                         oob += ecc->bytes + ecc->prepad;
589                 }
590  
591 @@ -748,10 +1124,13 @@ static int sunxi_nfc_hw_syndrome_ecc_rea
592                 cnt = mtd->oobsize - (oob - chip->oob_poi);
593                 if (cnt > 0) {
594                         chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
595 -                       chip->read_buf(mtd, oob, cnt);
596 +                       nand_rnd_config(mtd, page, offset, NAND_RND_READ);
597 +                       nand_rnd_read_buf(mtd, oob, cnt);
598                 }
599         }
600  
601 +       nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
602 +
603         writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN,
604                nfc->regs + NFC_REG_ECC_CTL);
605  
606 @@ -766,6 +1145,7 @@ static int sunxi_nfc_hw_syndrome_ecc_wri
607         struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller);
608         struct nand_ecc_ctrl *ecc = chip->cur_ecc;
609         struct sunxi_nand_hw_ecc *data = ecc->priv;
610 +       struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv;
611         uint8_t *oob = chip->oob_poi;
612         int offset = 0;
613         int ret;
614 @@ -781,13 +1161,24 @@ static int sunxi_nfc_hw_syndrome_ecc_wri
615         writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
616  
617         for (i = 0; i < ecc->steps; i++) {
618 -               chip->write_buf(mtd, buf + (i * ecc->size), ecc->size);
619 +               nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE);
620 +               nand_rnd_write_buf(mtd, buf + (i * ecc->size), ecc->size);
621                 offset += ecc->size;
622  
623                 /* Fill OOB data in */
624                 writel(NFC_BUF_TO_USER_DATA(oob),
625                        nfc->regs + NFC_REG_USER_DATA_BASE);
626  
627 +               cnt = ecc->bytes + 4;
628 +               if (rnd &&
629 +                   nand_rnd_is_activ(mtd, rnd->page, offset, &cnt) > 0 &&
630 +                   cnt == ecc->bytes + 4) {
631 +                       tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
632 +                       tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION);
633 +                       tmp |= NFC_RANDOM_EN;
634 +                       writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
635 +               }
636 +
637                 tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ACCESS_DIR |
638                       (1 << 30);
639                 writel(tmp, nfc->regs + NFC_REG_CMD);
640 @@ -796,6 +1187,9 @@ static int sunxi_nfc_hw_syndrome_ecc_wri
641                 if (ret)
642                         return ret;
643  
644 +               writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
645 +                      nfc->regs + NFC_REG_ECC_CTL);
646 +
647                 offset += ecc->bytes + ecc->prepad;
648                 oob += ecc->bytes + ecc->prepad;
649         }
650 @@ -804,9 +1198,11 @@ static int sunxi_nfc_hw_syndrome_ecc_wri
651                 cnt = mtd->oobsize - (oob - chip->oob_poi);
652                 if (cnt > 0) {
653                         chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1);
654 -                       chip->write_buf(mtd, oob, cnt);
655 +                       nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE);
656 +                       nand_rnd_write_buf(mtd, oob, cnt);
657                 }
658         }
659 +       nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE);
660  
661         tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
662         tmp &= ~NFC_ECC_EN;
663 @@ -816,6 +1212,128 @@ static int sunxi_nfc_hw_syndrome_ecc_wri
664         return 0;
665  }
666  
667 +static u16 sunxi_nfc_hw_syndrome_ecc_rnd_steps(struct mtd_info *mtd, u16 state,
668 +                                              int column, int *left)
669 +{
670 +       struct nand_chip *chip = mtd->priv;
671 +       struct nand_ecc_ctrl *ecc = chip->cur_ecc;
672 +       struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv;
673 +       int eccsteps = mtd->writesize / ecc->size;
674 +       int modsize = ecc->size + ecc->prepad + ecc->bytes;
675 +       int steps;
676 +
677 +       if (column < (eccsteps * modsize)) {
678 +               steps = column % modsize;
679 +               *left = modsize - steps;
680 +               if (steps >= ecc->size) {
681 +                       steps -= ecc->size;
682 +                       state = rnd->subseeds[rnd->page % rnd->nseeds];
683 +               }
684 +       } else {
685 +               steps = column % 4096;
686 +               *left = mtd->writesize + mtd->oobsize - column;
687 +       }
688 +
689 +       return sunxi_nfc_hwrnd_step(rnd, state, steps);
690 +}
691 +
692 +static u16 default_seeds[] = {0x4a80};
693 +
694 +static void sunxi_nand_rnd_ctrl_cleanup(struct nand_rnd_ctrl *rnd)
695 +{
696 +       struct sunxi_nand_hw_rnd *hwrnd = rnd->priv;
697 +
698 +       if (hwrnd->seeds != default_seeds)
699 +               kfree(hwrnd->seeds);
700 +       kfree(hwrnd->subseeds);
701 +       kfree(rnd->layout);
702 +       kfree(hwrnd);
703 +}
704 +
705 +static int sunxi_nand_rnd_ctrl_init(struct mtd_info *mtd,
706 +                                   struct nand_rnd_ctrl *rnd,
707 +                                   struct nand_ecc_ctrl *ecc,
708 +                                   struct device_node *np)
709 +{
710 +       struct sunxi_nand_hw_rnd *hwrnd;
711 +       struct nand_rnd_layout *layout = NULL;
712 +       int ret;
713 +
714 +       hwrnd = kzalloc(sizeof(*hwrnd), GFP_KERNEL);
715 +       if (!hwrnd)
716 +               return -ENOMEM;
717 +
718 +       hwrnd->seeds = default_seeds;
719 +       hwrnd->nseeds = ARRAY_SIZE(default_seeds);
720 +
721 +       if (of_get_property(np, "nand-randomizer-seeds", &ret)) {
722 +               hwrnd->nseeds = ret / sizeof(*hwrnd->seeds);
723 +               hwrnd->seeds = kzalloc(hwrnd->nseeds * sizeof(*hwrnd->seeds),
724 +                                      GFP_KERNEL);
725 +               if (!hwrnd->seeds) {
726 +                       ret = -ENOMEM;
727 +                       goto err;
728 +               }
729 +
730 +               ret = of_property_read_u16_array(np, "nand-randomizer-seeds",
731 +                                                hwrnd->seeds, hwrnd->nseeds);
732 +               if (ret)
733 +                       goto err;
734 +       }
735 +
736 +       switch (ecc->mode) {
737 +       case NAND_ECC_HW_SYNDROME:
738 +               hwrnd->step = sunxi_nfc_hw_syndrome_ecc_rnd_steps;
739 +               break;
740 +
741 +       case NAND_ECC_HW:
742 +               hwrnd->step = sunxi_nfc_hw_ecc_rnd_steps;
743 +
744 +       default:
745 +               layout = kzalloc(sizeof(*layout) + sizeof(struct nand_rndfree),
746 +                                GFP_KERNEL);
747 +               if (!layout) {
748 +                       ret = -ENOMEM;
749 +                       goto err;
750 +               }
751 +               layout->nranges = 1;
752 +               layout->ranges[0].offset = mtd->writesize;
753 +               layout->ranges[0].length = 2;
754 +               rnd->layout = layout;
755 +               break;
756 +       }
757 +
758 +       if (ecc->mode == NAND_ECC_HW_SYNDROME || ecc->mode == NAND_ECC_HW) {
759 +               int i;
760 +
761 +               hwrnd->subseeds = kzalloc(hwrnd->nseeds *
762 +                                         sizeof(*hwrnd->subseeds),
763 +                                         GFP_KERNEL);
764 +               if (!hwrnd->subseeds) {
765 +                       ret = -ENOMEM;
766 +                       goto err;
767 +               }
768 +
769 +               for (i = 0; i < hwrnd->nseeds; i++)
770 +                       hwrnd->subseeds[i] = sunxi_nfc_hwrnd_step(hwrnd,
771 +                                                       hwrnd->seeds[i],
772 +                                                       ecc->size);
773 +       }
774 +
775 +       rnd->config = sunxi_nfc_hwrnd_config;
776 +       rnd->read_buf = sunxi_nfc_hwrnd_read_buf;
777 +       rnd->write_buf = sunxi_nfc_hwrnd_write_buf;
778 +       rnd->priv = hwrnd;
779 +
780 +       return 0;
781 +
782 +err:
783 +       kfree(hwrnd);
784 +       kfree(layout);
785 +
786 +       return ret;
787 +}
788 +
789  static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
790                                        const struct nand_sdr_timings *timings)
791  {
792 @@ -1076,6 +1594,40 @@ static int sunxi_nand_hw_syndrome_ecc_ct
793         return 0;
794  }
795  
796 +static void sunxi_nand_rnd_cleanup(struct nand_rnd_ctrl *rnd)
797 +{
798 +       switch (rnd->mode) {
799 +       case NAND_RND_HW:
800 +               sunxi_nand_rnd_ctrl_cleanup(rnd);
801 +               break;
802 +       default:
803 +               break;
804 +       }
805 +}
806 +
807 +static int sunxi_nand_rnd_init(struct mtd_info *mtd,
808 +                              struct nand_rnd_ctrl *rnd,
809 +                              struct nand_ecc_ctrl *ecc,
810 +                              struct device_node *np)
811 +{
812 +       int ret;
813 +
814 +       rnd->mode = NAND_RND_NONE;
815 +
816 +       ret = of_get_nand_rnd_mode(np);
817 +       if (ret >= 0)
818 +               rnd->mode = ret;
819 +
820 +       switch (rnd->mode) {
821 +       case NAND_RND_HW:
822 +               return sunxi_nand_rnd_ctrl_init(mtd, rnd, ecc, np);
823 +       default:
824 +               break;
825 +       }
826 +
827 +       return 0;
828 +}
829 +
830  static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
831  {
832         switch (ecc->mode) {
833 @@ -1167,7 +1719,14 @@ struct nand_part *sunxi_ofnandpart_parse
834         if (ret)
835                 goto err;
836  
837 +       ret = sunxi_nand_rnd_init(master, &part->rnd, &part->ecc, pp);
838 +       if (ret) {
839 +               sunxi_nand_ecc_cleanup(&part->ecc);
840 +               goto err;
841 +       }
842 +
843         part->part.ecc = &part->ecc;
844 +       part->part.rnd = &part->rnd;
845  
846         return &part->part;
847  
848 @@ -1292,18 +1851,30 @@ static int sunxi_nand_chip_init(struct d
849         if (ret)
850                 return ret;
851  
852 +       chip->buffer = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
853 +       if (!chip->buffer)
854 +               return -ENOMEM;
855 +
856         ret = sunxi_nand_chip_init_timings(chip, np);
857         if (ret) {
858                 dev_err(dev, "could not configure chip timings: %d\n", ret);
859                 return ret;
860         }
861  
862 +       ret = nand_pst_create(mtd);
863 +       if (ret)
864 +               return ret;
865 +
866         ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np);
867         if (ret) {
868                 dev_err(dev, "ECC init failed: %d\n", ret);
869                 return ret;
870         }
871  
872 +       ret = sunxi_nand_rnd_init(mtd, &nand->rnd, &nand->ecc, np);
873 +       if (ret)
874 +               return ret;
875 +
876         ret = nand_scan_tail(mtd);
877         if (ret) {
878                 dev_err(dev, "nand_scan_tail failed: %d\n", ret);
879 @@ -1360,6 +1931,8 @@ static void sunxi_nand_chips_cleanup(str
880                 nand_release(&chip->mtd);
881                 sunxi_nand_ecc_cleanup(&chip->nand.ecc);
882                 list_del(&chip->node);
883 +               sunxi_nand_rnd_cleanup(&chip->nand.rnd);
884 +               kfree(chip->buffer);
885         }
886  }
887