kernel: update kernel 4.1 to version 4.1.11
[openwrt/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 --- 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