Commit 42be56f53c8b107868e6125c8524ae84293e95a7

Authored by Stefan Roese
1 parent a471db07fb

NAND: Add ECC support to NAND booting support in nand_spl/nand_boot.c

The U-Boot NAND booting support is now extended to support ECC
upon loading of the NAND U-Boot image.

Tested on AMCC Sequoia (440EPx) and Bamboo (440EP).

Signed-off-by: Stefan Roese <sr@denx.de>

Showing 1 changed file with 56 additions and 39 deletions Side-by-side Diff

nand_spl/nand_boot.c
1 1 /*
2   - * (C) Copyright 2006
  2 + * (C) Copyright 2006-2007
3 3 * Stefan Roese, DENX Software Engineering, sr@denx.de.
4 4 *
5 5 * This program is free software; you can redistribute it and/or
6 6  
7 7  
8 8  
9 9  
10 10  
11 11  
... ... @@ -24,27 +24,28 @@
24 24 #define CFG_NAND_READ_DELAY \
25 25 { volatile int dummy; int i; for (i=0; i<10000; i++) dummy = i; }
26 26  
  27 +static int nand_ecc_pos[] = CFG_NAND_ECCPOS;
  28 +
27 29 extern void board_nand_init(struct nand_chip *nand);
28   -extern void ndfc_hwcontrol(struct mtd_info *mtdinfo, int cmd);
29   -extern void ndfc_write_byte(struct mtd_info *mtdinfo, u_char byte);
30   -extern u_char ndfc_read_byte(struct mtd_info *mtdinfo);
31   -extern int ndfc_dev_ready(struct mtd_info *mtdinfo);
32   -extern int jump_to_ram(ulong delta);
33   -extern int jump_to_uboot(ulong addr);
34 30  
35   -static int nand_is_bad_block(struct mtd_info *mtd, int block)
  31 +static int nand_command(struct mtd_info *mtd, int block, int page, int offs, u8 cmd)
36 32 {
37 33 struct nand_chip *this = mtd->priv;
38   - int page_addr = block * CFG_NAND_PAGE_COUNT;
  34 + int page_addr = page + block * CFG_NAND_PAGE_COUNT;
39 35  
  36 + if (this->dev_ready)
  37 + this->dev_ready(mtd);
  38 + else
  39 + CFG_NAND_READ_DELAY;
  40 +
40 41 /* Begin command latch cycle */
41 42 this->hwcontrol(mtd, NAND_CTL_SETCLE);
42   - this->write_byte(mtd, NAND_CMD_READOOB);
  43 + this->write_byte(mtd, cmd);
43 44 /* Set ALE and clear CLE to start address cycle */
44 45 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
45 46 this->hwcontrol(mtd, NAND_CTL_SETALE);
46 47 /* Column address */
47   - this->write_byte(mtd, CFG_NAND_BAD_BLOCK_POS); /* A[7:0] */
  48 + this->write_byte(mtd, offs); /* A[7:0] */
48 49 this->write_byte(mtd, (uchar)(page_addr & 0xff)); /* A[16:9] */
49 50 this->write_byte(mtd, (uchar)((page_addr >> 8) & 0xff)); /* A[24:17] */
50 51 #ifdef CFG_NAND_4_ADDR_CYCLE
... ... @@ -62,6 +63,15 @@
62 63 else
63 64 CFG_NAND_READ_DELAY;
64 65  
  66 + return 0;
  67 +}
  68 +
  69 +static int nand_is_bad_block(struct mtd_info *mtd, int block)
  70 +{
  71 + struct nand_chip *this = mtd->priv;
  72 +
  73 + nand_command(mtd, block, 0, CFG_NAND_BAD_BLOCK_POS, NAND_CMD_READOOB);
  74 +
65 75 /*
66 76 * Read on byte
67 77 */
68 78  
69 79  
70 80  
71 81  
72 82  
... ... @@ -74,39 +84,46 @@
74 84 static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst)
75 85 {
76 86 struct nand_chip *this = mtd->priv;
77   - int page_addr = page + block * CFG_NAND_PAGE_COUNT;
  87 + u_char *ecc_calc;
  88 + u_char *ecc_code;
  89 + u_char *oob_data;
78 90 int i;
  91 + int eccsize = CFG_NAND_ECCSIZE;
  92 + int eccbytes = CFG_NAND_ECCBYTES;
  93 + int eccsteps = CFG_NAND_ECCSTEPS;
  94 + uint8_t *p = dst;
  95 + int stat;
79 96  
80   - /* Begin command latch cycle */
81   - this->hwcontrol(mtd, NAND_CTL_SETCLE);
82   - this->write_byte(mtd, NAND_CMD_READ0);
83   - /* Set ALE and clear CLE to start address cycle */
84   - this->hwcontrol(mtd, NAND_CTL_CLRCLE);
85   - this->hwcontrol(mtd, NAND_CTL_SETALE);
86   - /* Column address */
87   - this->write_byte(mtd, 0); /* A[7:0] */
88   - this->write_byte(mtd, (uchar)(page_addr & 0xff)); /* A[16:9] */
89   - this->write_byte(mtd, (uchar)((page_addr >> 8) & 0xff)); /* A[24:17] */
90   -#ifdef CFG_NAND_4_ADDR_CYCLE
91   - /* One more address cycle for devices > 32MiB */
92   - this->write_byte(mtd, (uchar)((page_addr >> 16) & 0x0f)); /* A[xx:25] */
93   -#endif
94   - /* Latch in address */
95   - this->hwcontrol(mtd, NAND_CTL_CLRALE);
  97 + nand_command(mtd, block, page, 0, NAND_CMD_READ0);
96 98  
97   - /*
98   - * Wait a while for the data to be ready
  99 + /* No malloc available for now, just use some temporary locations
  100 + * in SDRAM
99 101 */
100   - if (this->dev_ready)
101   - this->dev_ready(mtd);
102   - else
103   - CFG_NAND_READ_DELAY;
  102 + ecc_calc = (u_char *)(CFG_SDRAM_BASE + 0x10000);
  103 + ecc_code = ecc_calc + 0x100;
  104 + oob_data = ecc_calc + 0x200;
104 105  
105   - /*
106   - * Read page into buffer
107   - */
108   - for (i=0; i<CFG_NAND_PAGE_SIZE; i++)
109   - *dst++ = this->read_byte(mtd);
  106 + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
  107 + this->enable_hwecc(mtd, NAND_ECC_READ);
  108 + this->read_buf(mtd, p, eccsize);
  109 + this->calculate_ecc(mtd, p, &ecc_calc[i]);
  110 + }
  111 + this->read_buf(mtd, oob_data, CFG_NAND_OOBSIZE);
  112 +
  113 + /* Pick the ECC bytes out of the oob data */
  114 + for (i = 0; i < CFG_NAND_ECCTOTAL; i++)
  115 + ecc_code[i] = oob_data[nand_ecc_pos[i]];
  116 +
  117 + eccsteps = CFG_NAND_ECCSTEPS;
  118 + p = dst;
  119 +
  120 + for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
  121 + /* No chance to do something with the possible error message
  122 + * from correct_data(). We just hope that all possible errors
  123 + * are corrected by this routine.
  124 + */
  125 + stat = this->correct_data(mtd, p, &ecc_code[i], &ecc_calc[i]);
  126 + }
110 127  
111 128 return 0;
112 129 }