sunxi: add support for 4.1
[openwrt.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 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 {
19   *
20   * @part: base paritition structure
21   * @ecc: per-partition ECC info
22 + * @rnd: per-partition randomizer info
23   */
24  struct sunxi_nand_part {
25         struct nand_part part;
26         struct nand_ecc_ctrl ecc;
27 +       struct nand_rnd_ctrl rnd;
28  };
29  
30  static inline struct sunxi_nand_part *
31 @@ -219,6 +221,29 @@ to_sunxi_nand_part(struct nand_part *part)
32  }
33  
34  /*
35 + * sunxi NAND randomizer structure: stores NAND randomizer information
36 + *
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
45 + */
46 +struct sunxi_nand_hw_rnd {
47 +       int page;
48 +       int column;
49 +       int nseeds;
50 +       u16 *seeds;
51 +       u16 *subseeds;
52 +       u16 (*step)(struct mtd_info *mtd, u16 state, int column, int *left);
53 +       int left;
54 +       u16 state;
55 +};
56 +
57 +/*
58   * NAND chip structure: stores NAND chip device related information
59   *
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;
64         struct mtd_info mtd;
65 +       void *buffer;
66         unsigned long clk_rate;
67         int selected;
68         int nsels;
69 @@ -489,6 +515,185 @@ static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
70         }
71  }
72  
73 +static u16 sunxi_nfc_hwrnd_step(struct sunxi_nand_hw_rnd *rnd, u16 state, int count)
74 +{
75 +       state &= 0x7fff;
76 +       count *= 8;
77 +       while (count--)
78 +               state = ((state >> 1) |
79 +                        ((((state >> 0) ^ (state >> 1)) & 1) << 14)) & 0x7fff;
80 +
81 +       return state;
82 +}
83 +
84 +static u16 sunxi_nfc_hwrnd_single_step(u16 state, int count)
85 +{
86 +       state &= 0x7fff;
87 +       while (count--)
88 +               state = ((state >> 1) |
89 +                        ((((state >> 0) ^ (state >> 1)) & 1) << 14)) & 0x7fff;
90 +
91 +       return state;
92 +}
93 +
94 +static int sunxi_nfc_hwrnd_config(struct mtd_info *mtd, int page, int column,
95 +                                 enum nand_rnd_action action)
96 +{
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;
100 +       u16 state;
101 +
102 +       if (page < 0 && column < 0) {
103 +               rnd->page = -1;
104 +               rnd->column = -1;
105 +               return 0;
106 +       }
107 +
108 +       if (column < 0)
109 +               column = 0;
110 +       if (page < 0)
111 +               page = rnd->page;
112 +
113 +       if (page < 0)
114 +               return -EINVAL;
115 +
116 +       if (page != rnd->page && action == NAND_RND_READ) {
117 +               int status;
118 +
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);
124 +
125 +                       if (nand_page_is_empty(mtd, sunxi_nand->buffer,
126 +                                              sunxi_nand->buffer +
127 +                                              mtd->writesize))
128 +                               status = NAND_PAGE_EMPTY;
129 +                       else
130 +                               status = NAND_PAGE_FILLED;
131 +
132 +                       nand_page_set_status(mtd, page, status);
133 +                       nand->cmdfunc(mtd, NAND_CMD_RNDOUT, column, -1);
134 +               }
135 +       }
136 +
137 +       state = rnd->seeds[page % rnd->nseeds];
138 +       rnd->page = page;
139 +       rnd->column = column;
140 +
141 +       if (rnd->step) {
142 +               rnd->state = rnd->step(mtd, state, column, &rnd->left);
143 +       } else {
144 +               rnd->state = sunxi_nfc_hwrnd_step(rnd, state, column % 4096);
145 +               rnd->left = mtd->oobsize + mtd->writesize - column;
146 +       }
147 +
148 +       return 0;
149 +}
150 +
151 +static void sunxi_nfc_hwrnd_write_buf(struct mtd_info *mtd, const uint8_t *buf,
152 +                                     int len)
153 +{
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);
158 +       int cnt;
159 +       int offs = 0;
160 +       int rndactiv;
161 +
162 +       tmp &= ~(NFC_RANDOM_DIRECTION | NFC_RANDOM_SEED | NFC_RANDOM_EN);
163 +       writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
164 +
165 +       if (rnd->page < 0) {
166 +               sunxi_nfc_write_buf(mtd, buf, len);
167 +               return;
168 +       }
169 +
170 +       while (len > offs) {
171 +               cnt = len - offs;
172 +               if (cnt > 1024)
173 +                       cnt = 1024;
174 +
175 +               rndactiv = nand_rnd_is_activ(mtd, rnd->page, rnd->column,
176 +                                            &cnt);
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)
181 +                               cnt = rnd->left;
182 +               }
183 +
184 +               sunxi_nfc_write_buf(mtd, buf + offs, cnt);
185 +
186 +               if (rndactiv > 0)
187 +                       writel(tmp & ~NFC_RANDOM_EN,
188 +                              nfc->regs + NFC_REG_ECC_CTL);
189 +
190 +               offs += cnt;
191 +               if (len <= offs)
192 +                       break;
193 +
194 +               sunxi_nfc_hwrnd_config(mtd, -1, rnd->column + cnt, NAND_RND_WRITE);
195 +       }
196 +}
197 +
198 +static void sunxi_nfc_hwrnd_read_buf(struct mtd_info *mtd, uint8_t *buf,
199 +                                    int len)
200 +{
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);
205 +       int cnt;
206 +       int offs = 0;
207 +       int rndactiv;
208 +
209 +       tmp &= ~(NFC_RANDOM_DIRECTION | NFC_RANDOM_SEED | NFC_RANDOM_EN);
210 +       writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
211 +
212 +       if (rnd->page < 0) {
213 +               sunxi_nfc_read_buf(mtd, buf, len);
214 +               return;
215 +       }
216 +
217 +       while (len > offs) {
218 +               cnt = len - offs;
219 +               if (cnt > 1024)
220 +                       cnt = 1024;
221 +
222 +               if (nand_page_get_status(mtd, rnd->page) != NAND_PAGE_EMPTY &&
223 +                   nand_rnd_is_activ(mtd, rnd->page, rnd->column, &cnt) > 0)
224 +                       rndactiv = 1;
225 +               else
226 +                       rndactiv = 0;
227 +
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)
232 +                               cnt = rnd->left;
233 +               }
234 +
235 +               if (buf)
236 +                       sunxi_nfc_read_buf(mtd, buf + offs, cnt);
237 +               else
238 +                       sunxi_nfc_read_buf(mtd, NULL, cnt);
239 +
240 +               if (rndactiv > 0)
241 +                       writel(tmp & ~NFC_RANDOM_EN,
242 +                              nfc->regs + NFC_REG_ECC_CTL);
243 +
244 +               offs += cnt;
245 +               if (len <= offs)
246 +                       break;
247 +
248 +               sunxi_nfc_hwrnd_config(mtd, -1, rnd->column + cnt, NAND_RND_READ);
249 +       }
250 +}
251 +
252  static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd)
253  {
254         uint8_t ret;
255 @@ -538,16 +743,43 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
256                                       int oob_required, int page)
257  {
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;
264 +       int status;
265         int offset;
266         int ret;
267         u32 tmp;
268         int i;
269         int cnt;
270  
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);
276 +
277 +               if (nand_page_is_empty(mtd, sunxi_nand->buffer,
278 +                                      sunxi_nand->buffer +
279 +                                      mtd->writesize)) {
280 +                       status = NAND_PAGE_EMPTY;
281 +               } else {
282 +                       status = NAND_PAGE_FILLED;
283 +                       chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
284 +               }
285 +
286 +               nand_page_set_status(mtd, page, status);
287 +       }
288 +
289 +       if (status == NAND_PAGE_EMPTY) {
290 +               memset(buf, 0xff, mtd->writesize);
291 +               if (oob_required)
292 +                       memset(chip->oob_poi, 0xff, mtd->oobsize);
293 +               return 0;
294 +       }
295 +
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);
301  
302         for (i = 0; i < ecc->steps; i++) {
303 +               bool rndactiv = false;
304 +
305                 if (i)
306                         chip->cmdfunc(mtd, NAND_CMD_RNDOUT, i * ecc->size, -1);
307  
308                 offset = mtd->writesize + layout->eccpos[i * ecc->bytes] - 4;
309  
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);
313  
314                 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
315  
316 @@ -569,6 +804,25 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
317                 if (ret)
318                         return ret;
319  
320 +               if (i) {
321 +                       cnt = ecc->bytes + 4;
322 +                       if (nand_rnd_is_activ(mtd, page, offset, &cnt) > 0 &&
323 +                           cnt == ecc->bytes + 4)
324 +                               rndactiv = true;
325 +               } else {
326 +                       cnt = ecc->bytes + 2;
327 +                       if (nand_rnd_is_activ(mtd, page, offset + 2, &cnt) > 0 &&
328 +                           cnt == ecc->bytes + 2)
329 +                               rndactiv = true;
330 +               }
331 +
332 +               if (rndactiv) {
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);
337 +               }
338 +
339                 tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30);
340                 writel(tmp, nfc->regs + NFC_REG_CMD);
341  
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);
345  
346 +               writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
347 +                      nfc->regs + NFC_REG_ECC_CTL);
348 +
349                 if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) {
350                         mtd->ecc_stats.failed++;
351                 } else {
352 @@ -594,9 +851,10 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
353                         if (ret)
354                                 return ret;
355  
356 +                       nand_rnd_config(mtd, -1, offset, NAND_RND_READ);
357                         offset -= mtd->writesize;
358 -                       chip->read_buf(mtd, chip->oob_poi + offset,
359 -                                     ecc->bytes + 4);
360 +                       nand_rnd_read_buf(mtd, chip->oob_poi + offset,
361 +                                         ecc->bytes + 4);
362                 }
363         }
364  
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);
373                 }
374         }
375  
376 +       nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
377 +
378         tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
379         tmp &= ~NFC_ECC_EN;
380  
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;
386         int offset;
387         int ret;
388         u32 tmp;
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);
391  
392         for (i = 0; i < ecc->steps; i++) {
393 +               bool rndactiv = false;
394 +               u8 oob_buf[4];
395 +
396                 if (i)
397                         chip->cmdfunc(mtd, NAND_CMD_RNDIN, i * ecc->size, -1);
398  
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);
402  
403                 offset = layout->eccpos[i * ecc->bytes] - 4 + mtd->writesize;
404  
405                 /* Fill OOB data in */
406 -               if (oob_required) {
407 -                       tmp = 0xffffffff;
408 -                       memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, &tmp,
409 -                                   4);
410 +               if (!oob_required)
411 +                       memset(oob_buf, 0xff, 4);
412 +               else
413 +                       memcpy(oob_buf,
414 +                              chip->oob_poi + layout->oobfree[i].offset,
415 +                              4);
416 +
417 +
418 +               memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, oob_buf, 4);
419 +
420 +               if (i) {
421 +                       cnt = ecc->bytes + 4;
422 +                       if (rnd &&
423 +                           nand_rnd_is_activ(mtd, -1, offset, &cnt) > 0 &&
424 +                           cnt == ecc->bytes + 4)
425 +                               rndactiv = true;
426                 } else {
427 -                       memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE,
428 -                                   chip->oob_poi + offset - mtd->writesize,
429 -                                   4);
430 +                       cnt = ecc->bytes + 2;
431 +                       if (rnd &&
432 +                           nand_rnd_is_activ(mtd, -1, offset + 2, &cnt) > 0 &&
433 +                           cnt == ecc->bytes + 2)
434 +                               rndactiv = true;
435 +               }
436 +
437 +               if (rndactiv) {
438 +                       /* pre randomize to generate FF patterns on the NAND */
439 +                       if (!i) {
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);
446 +                       }
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);
451                 }
452  
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);
456                 if (ret)
457                         return ret;
458 +
459 +               writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
460 +                      nfc->regs + NFC_REG_ECC_CTL);
461         }
462  
463         if (oob_required) {
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);
472                 }
473         }
474  
475 +       nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE);
476 +
477         tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
478         tmp &= ~NFC_ECC_EN;
479  
480 @@ -692,22 +994,76 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
481         return 0;
482  }
483  
484 +static u16 sunxi_nfc_hw_ecc_rnd_steps(struct mtd_info *mtd, u16 state,
485 +                                     int column, int *left)
486 +{
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;
492 +       int steps;
493 +
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];
503 +       } else {
504 +               steps = column % 4096;
505 +               *left = mtd->writesize + mtd->oobsize - column;
506 +       }
507 +
508 +       return sunxi_nfc_hwrnd_step(rnd, state, steps);
509 +}
510 +
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,
514                                                int page)
515  {
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;
522         int offset = 0;
523         int ret;
524 +       int status;
525         int cnt;
526         u32 tmp;
527         int i;
528  
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);
534 +
535 +               if (nand_page_is_empty(mtd, sunxi_nand->buffer,
536 +                                      sunxi_nand->buffer +
537 +                                      mtd->writesize)) {
538 +                       status = NAND_PAGE_EMPTY;
539 +               } else {
540 +                       status = NAND_PAGE_FILLED;
541 +                       chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
542 +               }
543 +
544 +               nand_page_set_status(mtd, page, status);
545 +       }
546 +
547 +       if (status == NAND_PAGE_EMPTY) {
548 +               memset(buf, 0xff, mtd->writesize);
549 +               if (oob_required)
550 +                       memset(chip->oob_poi, 0xff, mtd->oobsize);
551 +               return 0;
552 +       }
553 +
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);
559  
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);
564 +
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);
572 +               }
573  
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,
577                 buf += ecc->size;
578                 offset += ecc->size;
579  
580 +               writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
581 +                      nfc->regs + NFC_REG_ECC_CTL);
582 +
583                 if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) {
584                         mtd->ecc_stats.failed++;
585                 } else {
586 @@ -739,7 +1108,8 @@ static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
587  
588                 if (oob_required) {
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;
594                 }
595  
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);
598                 if (cnt > 0) {
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);
603                 }
604         }
605  
606 +       nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
607 +
608         writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN,
609                nfc->regs + NFC_REG_ECC_CTL);
610  
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;
617         int offset = 0;
618         int ret;
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);
621  
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);
626                 offset += ecc->size;
627  
628                 /* Fill OOB data in */
629 @@ -796,6 +1171,16 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd,
630                                     4);
631                 }
632  
633 +               cnt = ecc->bytes + 4;
634 +               if (rnd &&
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);
641 +               }
642 +
643                 tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ACCESS_DIR |
644                       (1 << 30);
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,
647                 if (ret)
648                         return ret;
649  
650 +               writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
651 +                      nfc->regs + NFC_REG_ECC_CTL);
652 +
653                 offset += ecc->bytes + ecc->prepad;
654                 oob += ecc->bytes + ecc->prepad;
655         }
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);
658                 if (cnt > 0) {
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);
663                 }
664         }
665 +       nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE);
666  
667         tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
668         tmp &= ~NFC_ECC_EN;
669 @@ -824,6 +1214,128 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd,
670         return 0;
671  }
672  
673 +static u16 sunxi_nfc_hw_syndrome_ecc_rnd_steps(struct mtd_info *mtd, u16 state,
674 +                                              int column, int *left)
675 +{
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;
681 +       int steps;
682 +
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];
689 +               }
690 +       } else {
691 +               steps = column % 4096;
692 +               *left = mtd->writesize + mtd->oobsize - column;
693 +       }
694 +
695 +       return sunxi_nfc_hwrnd_step(rnd, state, steps);
696 +}
697 +
698 +static u16 default_seeds[] = {0x4a80};
699 +
700 +static void sunxi_nand_rnd_ctrl_cleanup(struct nand_rnd_ctrl *rnd)
701 +{
702 +       struct sunxi_nand_hw_rnd *hwrnd = rnd->priv;
703 +
704 +       if (hwrnd->seeds != default_seeds)
705 +               kfree(hwrnd->seeds);
706 +       kfree(hwrnd->subseeds);
707 +       kfree(rnd->layout);
708 +       kfree(hwrnd);
709 +}
710 +
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)
715 +{
716 +       struct sunxi_nand_hw_rnd *hwrnd;
717 +       struct nand_rnd_layout *layout = NULL;
718 +       int ret;
719 +
720 +       hwrnd = kzalloc(sizeof(*hwrnd), GFP_KERNEL);
721 +       if (!hwrnd)
722 +               return -ENOMEM;
723 +
724 +       hwrnd->seeds = default_seeds;
725 +       hwrnd->nseeds = ARRAY_SIZE(default_seeds);
726 +
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),
730 +                                      GFP_KERNEL);
731 +               if (!hwrnd->seeds) {
732 +                       ret = -ENOMEM;
733 +                       goto err;
734 +               }
735 +
736 +               ret = of_property_read_u16_array(np, "nand-randomizer-seeds",
737 +                                                hwrnd->seeds, hwrnd->nseeds);
738 +               if (ret)
739 +                       goto err;
740 +       }
741 +
742 +       switch (ecc->mode) {
743 +       case NAND_ECC_HW_SYNDROME:
744 +               hwrnd->step = sunxi_nfc_hw_syndrome_ecc_rnd_steps;
745 +               break;
746 +
747 +       case NAND_ECC_HW:
748 +               hwrnd->step = sunxi_nfc_hw_ecc_rnd_steps;
749 +
750 +       default:
751 +               layout = kzalloc(sizeof(*layout) + sizeof(struct nand_rndfree),
752 +                                GFP_KERNEL);
753 +               if (!layout) {
754 +                       ret = -ENOMEM;
755 +                       goto err;
756 +               }
757 +               layout->nranges = 1;
758 +               layout->ranges[0].offset = mtd->writesize;
759 +               layout->ranges[0].length = 2;
760 +               rnd->layout = layout;
761 +               break;
762 +       }
763 +
764 +       if (ecc->mode == NAND_ECC_HW_SYNDROME || ecc->mode == NAND_ECC_HW) {
765 +               int i;
766 +
767 +               hwrnd->subseeds = kzalloc(hwrnd->nseeds *
768 +                                         sizeof(*hwrnd->subseeds),
769 +                                         GFP_KERNEL);
770 +               if (!hwrnd->subseeds) {
771 +                       ret = -ENOMEM;
772 +                       goto err;
773 +               }
774 +
775 +               for (i = 0; i < hwrnd->nseeds; i++)
776 +                       hwrnd->subseeds[i] = sunxi_nfc_hwrnd_step(hwrnd,
777 +                                                       hwrnd->seeds[i],
778 +                                                       ecc->size);
779 +       }
780 +
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;
784 +       rnd->priv = hwrnd;
785 +
786 +       return 0;
787 +
788 +err:
789 +       kfree(hwrnd);
790 +       kfree(layout);
791 +
792 +       return ret;
793 +}
794 +
795  static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
796                                        const struct nand_sdr_timings *timings)
797  {
798 @@ -1084,6 +1596,40 @@ static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd,
799         return 0;
800  }
801  
802 +static void sunxi_nand_rnd_cleanup(struct nand_rnd_ctrl *rnd)
803 +{
804 +       switch (rnd->mode) {
805 +       case NAND_RND_HW:
806 +               sunxi_nand_rnd_ctrl_cleanup(rnd);
807 +               break;
808 +       default:
809 +               break;
810 +       }
811 +}
812 +
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)
817 +{
818 +       int ret;
819 +
820 +       rnd->mode = NAND_RND_NONE;
821 +
822 +       ret = of_get_nand_rnd_mode(np);
823 +       if (ret >= 0)
824 +               rnd->mode = ret;
825 +
826 +       switch (rnd->mode) {
827 +       case NAND_RND_HW:
828 +               return sunxi_nand_rnd_ctrl_init(mtd, rnd, ecc, np);
829 +       default:
830 +               break;
831 +       }
832 +
833 +       return 0;
834 +}
835 +
836  static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
837  {
838         switch (ecc->mode) {
839 @@ -1175,7 +1721,14 @@ struct nand_part *sunxi_ofnandpart_parse(void *priv, struct mtd_info *master,
840         if (ret)
841                 goto err;
842  
843 +       ret = sunxi_nand_rnd_init(master, &part->rnd, &part->ecc, pp);
844 +       if (ret) {
845 +               sunxi_nand_ecc_cleanup(&part->ecc);
846 +               goto err;
847 +       }
848 +
849         part->part.ecc = &part->ecc;
850 +       part->part.rnd = &part->rnd;
851  
852         return &part->part;
853  
854 @@ -1300,18 +1853,30 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
855         if (ret)
856                 return ret;
857  
858 +       chip->buffer = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
859 +       if (!chip->buffer)
860 +               return -ENOMEM;
861 +
862         ret = sunxi_nand_chip_init_timings(chip, np);
863         if (ret) {
864                 dev_err(dev, "could not configure chip timings: %d\n", ret);
865                 return ret;
866         }
867  
868 +       ret = nand_pst_create(mtd);
869 +       if (ret)
870 +               return ret;
871 +
872         ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np);
873         if (ret) {
874                 dev_err(dev, "ECC init failed: %d\n", ret);
875                 return ret;
876         }
877  
878 +       ret = sunxi_nand_rnd_init(mtd, &nand->rnd, &nand->ecc, np);
879 +       if (ret)
880 +               return ret;
881 +
882         ret = nand_scan_tail(mtd);
883         if (ret) {
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)
886                                         node);
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);
891         }
892  }
893