Commit 42be56f53c8b107868e6125c8524ae84293e95a7
1 parent
a471db07fb
Exists in
master
and in
54 other branches
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 | } |