1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include <common.h>
25#include <asm/io.h>
26#include <asm/errno.h>
27#include <asm/arch/mem.h>
28#include <asm/arch/omap_gpmc.h>
29#include <linux/mtd/nand_ecc.h>
30#include <linux/compiler.h>
31#include <nand.h>
32#ifdef CONFIG_AM33XX
33#include <asm/arch/elm.h>
34#endif
35
36static uint8_t cs;
37static __maybe_unused struct nand_ecclayout hw_nand_oob =
38 GPMC_NAND_HW_ECC_LAYOUT;
39
40
41
42
43
44static void omap_nand_hwcontrol(struct mtd_info *mtd, int32_t cmd,
45 uint32_t ctrl)
46{
47 register struct nand_chip *this = mtd->priv;
48
49
50
51
52
53 switch (ctrl) {
54 case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
55 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
56 break;
57 case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
58 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_adr;
59 break;
60 case NAND_CTRL_CHANGE | NAND_NCE:
61 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
62 break;
63 }
64
65 if (cmd != NAND_CMD_NONE)
66 writeb(cmd, this->IO_ADDR_W);
67}
68
69#ifdef CONFIG_SPL_BUILD
70
71int omap_spl_dev_ready(struct mtd_info *mtd)
72{
73 return gpmc_cfg->status & (1 << 8);
74}
75#endif
76
77
78
79
80
81
82
83static void __maybe_unused omap_hwecc_init(struct nand_chip *chip)
84{
85
86
87
88
89 writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
90 writel(ECCSIZE1 | ECCSIZE0 | ECCSIZE0SEL, &gpmc_cfg->ecc_size_config);
91}
92
93
94
95
96
97
98
99
100
101static uint32_t gen_true_ecc(uint8_t *ecc_buf)
102{
103 return ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xF0) << 20) |
104 ((ecc_buf[2] & 0x0F) << 8);
105}
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
122 uint8_t *read_ecc, uint8_t *calc_ecc)
123{
124 uint32_t orig_ecc, new_ecc, res, hm;
125 uint16_t parity_bits, byte;
126 uint8_t bit;
127
128
129 orig_ecc = gen_true_ecc(read_ecc);
130 new_ecc = gen_true_ecc(calc_ecc);
131
132 res = orig_ecc ^ new_ecc;
133 if (res) {
134
135 hm = hweight32(res);
136
137 if (hm == 12) {
138
139 parity_bits = res >> 16;
140 bit = (parity_bits & 0x7);
141 byte = (parity_bits >> 3) & 0x1FF;
142
143 dat[byte] ^= (0x1 << bit);
144 } else if (hm == 1) {
145 printf("Error: Ecc is wrong\n");
146
147 return 2;
148 } else {
149
150
151
152
153
154
155
156
157
158
159
160
161
162 if ((orig_ecc == 0x0FFF0FFF) && (new_ecc == 0x00000000))
163 return 0;
164 printf("Error: Bad compare! failed\n");
165
166 return -1;
167 }
168 }
169 return 0;
170}
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187static int __maybe_unused omap_calculate_ecc(struct mtd_info *mtd,
188 const uint8_t *dat, uint8_t *ecc_code)
189{
190 u_int32_t val;
191
192
193 val = readl(&gpmc_cfg->ecc1_result);
194
195 ecc_code[0] = val & 0xFF;
196 ecc_code[1] = (val >> 16) & 0xFF;
197 ecc_code[2] = ((val >> 8) & 0x0F) | ((val >> 20) & 0xF0);
198
199
200
201
202
203 writel(0x000, &gpmc_cfg->ecc_config);
204
205 return 0;
206}
207
208
209
210
211
212
213static void __maybe_unused omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
214{
215 struct nand_chip *chip = mtd->priv;
216 uint32_t val, dev_width = (chip->options & NAND_BUSWIDTH_16) >> 1;
217
218 switch (mode) {
219 case NAND_ECC_READ:
220 case NAND_ECC_WRITE:
221
222 writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
223
224
225
226
227
228
229 writel(ECCSIZE1 | ECCSIZE0 | ECCSIZE0SEL,
230 &gpmc_cfg->ecc_size_config);
231 val = (dev_width << 7) | (cs << 1) | (0x1);
232 writel(val, &gpmc_cfg->ecc_config);
233 break;
234 default:
235 printf("Error: Unrecognized Mode[%d]!\n", mode);
236 break;
237 }
238}
239
240
241
242
243#ifdef CONFIG_AM33XX
244struct nand_bch_priv {
245 uint8_t mode;
246 uint8_t type;
247 uint8_t nibbles;
248};
249
250
251#define ECC_BCH4 0
252#define ECC_BCH8 1
253#define ECC_BCH16 2
254
255
256#define NAND_ECC_HW_BCH ((uint8_t)(NAND_ECC_HW_OOB_FIRST) + 1)
257#define ECC_BCH4_NIBBLES 13
258#define ECC_BCH8_NIBBLES 26
259#define ECC_BCH16_NIBBLES 52
260
261static struct nand_ecclayout hw_bch8_nand_oob = GPMC_NAND_HW_BCH8_ECC_LAYOUT;
262
263static struct nand_bch_priv bch_priv = {
264 .mode = NAND_ECC_HW_BCH,
265 .type = ECC_BCH8,
266 .nibbles = ECC_BCH8_NIBBLES
267};
268
269
270
271
272
273
274
275
276static void omap_read_bch8_result(struct mtd_info *mtd, uint8_t big_endian,
277 uint8_t *ecc_code)
278{
279 uint32_t *ptr;
280 int8_t i = 0, j;
281
282 if (big_endian) {
283 ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[3];
284 ecc_code[i++] = readl(ptr) & 0xFF;
285 ptr--;
286 for (j = 0; j < 3; j++) {
287 ecc_code[i++] = (readl(ptr) >> 24) & 0xFF;
288 ecc_code[i++] = (readl(ptr) >> 16) & 0xFF;
289 ecc_code[i++] = (readl(ptr) >> 8) & 0xFF;
290 ecc_code[i++] = readl(ptr) & 0xFF;
291 ptr--;
292 }
293 } else {
294 ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[0];
295 for (j = 0; j < 3; j++) {
296 ecc_code[i++] = readl(ptr) & 0xFF;
297 ecc_code[i++] = (readl(ptr) >> 8) & 0xFF;
298 ecc_code[i++] = (readl(ptr) >> 16) & 0xFF;
299 ecc_code[i++] = (readl(ptr) >> 24) & 0xFF;
300 ptr++;
301 }
302 ecc_code[i++] = readl(ptr) & 0xFF;
303 ecc_code[i++] = 0;
304 }
305}
306
307
308
309
310
311
312
313static void omap_ecc_disable(struct mtd_info *mtd)
314{
315 writel((readl(&gpmc_cfg->ecc_config) & ~0x1),
316 &gpmc_cfg->ecc_config);
317}
318
319
320
321
322
323
324
325
326
327static void omap_rotate_ecc_bch(struct mtd_info *mtd, uint8_t *calc_ecc,
328 uint8_t *syndrome)
329{
330 struct nand_chip *chip = mtd->priv;
331 struct nand_bch_priv *bch = chip->priv;
332 uint8_t n_bytes = 0;
333 int8_t i, j;
334
335 switch (bch->type) {
336 case ECC_BCH4:
337 n_bytes = 8;
338 break;
339
340 case ECC_BCH16:
341 n_bytes = 28;
342 break;
343
344 case ECC_BCH8:
345 default:
346 n_bytes = 13;
347 break;
348 }
349
350 for (i = 0, j = (n_bytes-1); i < n_bytes; i++, j--)
351 syndrome[i] = calc_ecc[j];
352}
353
354
355
356
357
358
359
360
361static int omap_calculate_ecc_bch(struct mtd_info *mtd, const uint8_t *dat,
362 uint8_t *ecc_code)
363{
364 struct nand_chip *chip = mtd->priv;
365 struct nand_bch_priv *bch = chip->priv;
366 uint8_t big_endian = 1;
367 int8_t ret = 0;
368
369 if (bch->type == ECC_BCH8)
370 omap_read_bch8_result(mtd, big_endian, ecc_code);
371 else
372 ret = -1;
373
374
375
376
377
378 omap_ecc_disable(mtd);
379
380 return ret;
381}
382
383
384
385
386
387
388
389
390
391
392static void omap_fix_errors_bch(struct mtd_info *mtd, uint8_t *data,
393 uint32_t error_count, uint32_t *error_loc)
394{
395 struct nand_chip *chip = mtd->priv;
396 struct nand_bch_priv *bch = chip->priv;
397 uint8_t count = 0;
398 uint32_t error_byte_pos;
399 uint32_t error_bit_mask;
400 uint32_t last_bit = (bch->nibbles * 4) - 1;
401
402
403
404 for (count = 0; count < error_count; count++) {
405 if (error_loc[count] > last_bit) {
406
407 error_loc[count] -= (last_bit + 1);
408
409 error_byte_pos = ((512 * 8) -
410 (error_loc[count]) - 1) / 8;
411
412 error_bit_mask = 0x1 << (error_loc[count] % 8);
413
414 data[error_byte_pos] ^= error_bit_mask;
415 }
416 }
417}
418
419
420
421
422
423
424
425
426
427
428
429
430static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
431 uint8_t *read_ecc, uint8_t *calc_ecc)
432{
433 struct nand_chip *chip = mtd->priv;
434 struct nand_bch_priv *bch = chip->priv;
435 uint8_t syndrome[28];
436 uint32_t error_count = 0;
437 uint32_t error_loc[8];
438 uint32_t i, ecc_flag;
439
440 ecc_flag = 0;
441 for (i = 0; i < chip->ecc.bytes; i++)
442 if (read_ecc[i] != 0xff)
443 ecc_flag = 1;
444
445 if (!ecc_flag)
446 return 0;
447
448 elm_reset();
449 elm_config((enum bch_level)(bch->type));
450
451
452
453
454
455 omap_rotate_ecc_bch(mtd, calc_ecc, syndrome);
456
457
458 if (elm_check_error(syndrome, bch->nibbles, &error_count,
459 error_loc) != 0) {
460 printf("ECC: uncorrectable.\n");
461 return -1;
462 }
463
464
465 if (error_count > 0)
466 omap_fix_errors_bch(mtd, dat, error_count, error_loc);
467
468 return 0;
469}
470
471
472
473
474
475
476static void omap_hwecc_init_bch(struct nand_chip *chip, int32_t mode)
477{
478 uint32_t val, dev_width = (chip->options & NAND_BUSWIDTH_16) >> 1;
479 uint32_t unused_length = 0;
480 struct nand_bch_priv *bch = chip->priv;
481
482 switch (bch->nibbles) {
483 case ECC_BCH4_NIBBLES:
484 unused_length = 3;
485 break;
486 case ECC_BCH8_NIBBLES:
487 unused_length = 2;
488 break;
489 case ECC_BCH16_NIBBLES:
490 unused_length = 0;
491 break;
492 }
493
494
495 writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
496
497 switch (mode) {
498 case NAND_ECC_WRITE:
499
500 val = ((unused_length + bch->nibbles) << 22);
501 break;
502
503 case NAND_ECC_READ:
504 default:
505
506
507 val = (bch->nibbles << 12);
508
509 val |= (unused_length << 22);
510 break;
511 }
512
513 writel(val, &gpmc_cfg->ecc_size_config);
514
515
516 val = (1 << 16);
517
518 val |= (bch->type << 12);
519
520 val |= (1 << 8);
521 val |= (dev_width << 7);
522 val |= (cs << 1);
523 writel(val, &gpmc_cfg->ecc_config);
524}
525
526
527
528
529
530
531
532static void omap_enable_ecc_bch(struct mtd_info *mtd, int32_t mode)
533{
534 struct nand_chip *chip = mtd->priv;
535
536 omap_hwecc_init_bch(chip, mode);
537
538 writel((readl(&gpmc_cfg->ecc_config) | 0x1), &gpmc_cfg->ecc_config);
539}
540
541
542
543
544
545
546
547
548
549static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
550 uint8_t *buf, int page)
551{
552 int i, eccsize = chip->ecc.size;
553 int eccbytes = chip->ecc.bytes;
554 int eccsteps = chip->ecc.steps;
555 uint8_t *p = buf;
556 uint8_t *ecc_calc = chip->buffers->ecccalc;
557 uint8_t *ecc_code = chip->buffers->ecccode;
558 uint32_t *eccpos = chip->ecc.layout->eccpos;
559 uint8_t *oob = chip->oob_poi;
560 uint32_t data_pos;
561 uint32_t oob_pos;
562
563 data_pos = 0;
564
565 oob_pos = (eccsize * eccsteps) + chip->ecc.layout->eccpos[0];
566 oob += chip->ecc.layout->eccpos[0];
567
568 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize,
569 oob += eccbytes) {
570 chip->ecc.hwctl(mtd, NAND_ECC_READ);
571
572 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_pos, page);
573 chip->read_buf(mtd, p, eccsize);
574
575
576 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, page);
577 chip->read_buf(mtd, oob, eccbytes);
578
579 chip->ecc.calculate(mtd, p, &ecc_calc[i]);
580
581 data_pos += eccsize;
582 oob_pos += eccbytes;
583 }
584
585 for (i = 0; i < chip->ecc.total; i++)
586 ecc_code[i] = chip->oob_poi[eccpos[i]];
587
588 eccsteps = chip->ecc.steps;
589 p = buf;
590
591 for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
592 int stat;
593
594 stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
595 if (stat < 0)
596 mtd->ecc_stats.failed++;
597 else
598 mtd->ecc_stats.corrected += stat;
599 }
600 return 0;
601}
602#endif
603
604#ifndef CONFIG_SPL_BUILD
605
606
607
608
609
610
611
612void omap_nand_switch_ecc(int32_t hardware)
613{
614 struct nand_chip *nand;
615 struct mtd_info *mtd;
616
617 if (nand_curr_device < 0 ||
618 nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
619 !nand_info[nand_curr_device].name) {
620 printf("Error: Can't switch ecc, no devices available\n");
621 return;
622 }
623
624 mtd = &nand_info[nand_curr_device];
625 nand = mtd->priv;
626
627 nand->options |= NAND_OWN_BUFFERS;
628
629
630 nand->ecc.read_page = NULL;
631 nand->ecc.write_page = NULL;
632 nand->ecc.read_oob = NULL;
633 nand->ecc.write_oob = NULL;
634 nand->ecc.hwctl = NULL;
635 nand->ecc.correct = NULL;
636 nand->ecc.calculate = NULL;
637
638
639 if (hardware == 1) {
640 nand->ecc.mode = NAND_ECC_HW;
641 nand->ecc.layout = &hw_nand_oob;
642 nand->ecc.size = 512;
643 nand->ecc.bytes = 3;
644 nand->ecc.hwctl = omap_enable_hwecc;
645 nand->ecc.correct = omap_correct_data;
646 nand->ecc.calculate = omap_calculate_ecc;
647 omap_hwecc_init(nand);
648 printf("HW ECC selected\n");
649#ifdef CONFIG_AM33XX
650 } else if (hardware == 2) {
651 nand->ecc.mode = NAND_ECC_HW;
652 nand->ecc.layout = &hw_bch8_nand_oob;
653 nand->ecc.size = 512;
654 nand->ecc.bytes = 14;
655 nand->ecc.read_page = omap_read_page_bch;
656 nand->ecc.hwctl = omap_enable_ecc_bch;
657 nand->ecc.correct = omap_correct_data_bch;
658 nand->ecc.calculate = omap_calculate_ecc_bch;
659 omap_hwecc_init_bch(nand, NAND_ECC_READ);
660 printf("HW BCH8 selected\n");
661#endif
662 } else {
663 nand->ecc.mode = NAND_ECC_SOFT;
664
665 nand->ecc.layout = NULL;
666 nand->ecc.size = 0;
667 printf("SW ECC selected\n");
668 }
669
670
671 nand_scan_tail(mtd);
672
673 nand->options &= ~NAND_OWN_BUFFERS;
674}
675#endif
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692int board_nand_init(struct nand_chip *nand)
693{
694 int32_t gpmc_config = 0;
695 cs = 0;
696
697
698
699
700
701
702
703
704 while (cs < GPMC_MAX_CS) {
705
706 if ((readl(&gpmc_cfg->cs[cs].config1) & 0xC00) == 0x800) {
707
708 break;
709 }
710 cs++;
711 }
712 if (cs >= GPMC_MAX_CS) {
713 printf("NAND: Unable to find NAND settings in "
714 "GPMC Configuration - quitting\n");
715 return -ENODEV;
716 }
717
718 gpmc_config = readl(&gpmc_cfg->config);
719
720 gpmc_config |= 0x10;
721 writel(gpmc_config, &gpmc_cfg->config);
722
723 nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
724 nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
725
726 nand->cmd_ctrl = omap_nand_hwcontrol;
727 nand->options = NAND_NO_PADDING | NAND_CACHEPRG | NAND_NO_AUTOINCR;
728
729 if ((readl(&gpmc_cfg->cs[cs].config1) & 0x3000) == 0x1000)
730 nand->options |= NAND_BUSWIDTH_16;
731
732 nand->chip_delay = 100;
733
734#ifdef CONFIG_AM33XX
735
736 elm_init();
737
738
739 nand->priv = &bch_priv;
740#endif
741
742
743#ifdef CONFIG_AM33XX
744 nand->ecc.mode = NAND_ECC_HW;
745 nand->ecc.layout = &hw_bch8_nand_oob;
746 nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
747 nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
748 nand->ecc.hwctl = omap_enable_ecc_bch;
749 nand->ecc.correct = omap_correct_data_bch;
750 nand->ecc.calculate = omap_calculate_ecc_bch;
751 nand->ecc.read_page = omap_read_page_bch;
752 omap_hwecc_init_bch(nand, NAND_ECC_READ);
753#else
754#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_NAND_SOFTECC)
755 nand->ecc.mode = NAND_ECC_SOFT;
756#else
757 nand->ecc.mode = NAND_ECC_HW;
758 nand->ecc.layout = &hw_nand_oob;
759 nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
760 nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
761 nand->ecc.hwctl = omap_enable_hwecc;
762 nand->ecc.correct = omap_correct_data;
763 nand->ecc.calculate = omap_calculate_ecc;
764 omap_hwecc_init(nand);
765#endif
766#endif
767
768#ifdef CONFIG_SPL_BUILD
769 if (nand->options & NAND_BUSWIDTH_16)
770 nand->read_buf = nand_read_buf16;
771 else
772 nand->read_buf = nand_read_buf;
773 nand->dev_ready = omap_spl_dev_ready;
774#endif
775
776 return 0;
777}
778