]>
Commit | Line | Data |
---|---|---|
932394ac WD |
1 | /* |
2 | * This file contains an ECC algorithm from Toshiba that detects and | |
3 | * corrects 1 bit errors in a 256 byte block of data. | |
4 | * | |
5 | * drivers/mtd/nand/nand_ecc.c | |
6 | * | |
7 | * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com) | |
8 | * Toshiba America Electronics Components, Inc. | |
9 | * | |
10 | * $Id: nand_ecc.c,v 1.14 2004/06/16 15:34:37 gleixner Exp $ | |
11 | * | |
12 | * This file is free software; you can redistribute it and/or modify it | |
13 | * under the terms of the GNU General Public License as published by the | |
14 | * Free Software Foundation; either version 2 or (at your option) any | |
15 | * later version. | |
ac7eb8a3 | 16 | * |
932394ac WD |
17 | * This file is distributed in the hope that it will be useful, but WITHOUT |
18 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
19 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
20 | * for more details. | |
ac7eb8a3 | 21 | * |
932394ac WD |
22 | * You should have received a copy of the GNU General Public License along |
23 | * with this file; if not, write to the Free Software Foundation, Inc., | |
24 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | |
ac7eb8a3 | 25 | * |
932394ac WD |
26 | * As a special exception, if other files instantiate templates or use |
27 | * macros or inline functions from these files, or you compile these | |
28 | * files and link them with other works to produce a work based on these | |
29 | * files, these files do not by themselves cause the resulting work to be | |
30 | * covered by the GNU General Public License. However the source code for | |
31 | * these files must still be made available in accordance with section (3) | |
32 | * of the GNU General Public License. | |
ac7eb8a3 | 33 | * |
932394ac WD |
34 | * This exception does not invalidate any other reasons why a work based on |
35 | * this file might be covered by the GNU General Public License. | |
36 | */ | |
37 | ||
38 | #include <common.h> | |
39 | ||
6db39708 | 40 | #if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY) |
932394ac | 41 | |
038ccac5 | 42 | #include<linux/mtd/mtd.h> |
932394ac WD |
43 | /* |
44 | * Pre-calculated 256-way 1 byte column parity | |
45 | */ | |
46 | static const u_char nand_ecc_precalc_table[] = { | |
47 | 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, | |
48 | 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, | |
49 | 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, | |
50 | 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, | |
51 | 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, | |
52 | 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, | |
53 | 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, | |
54 | 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, | |
55 | 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, | |
56 | 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, | |
57 | 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, | |
58 | 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, | |
59 | 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, | |
60 | 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, | |
61 | 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, | |
62 | 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 | |
63 | }; | |
64 | ||
65 | ||
66 | /** | |
67 | * nand_trans_result - [GENERIC] create non-inverted ECC | |
68 | * @reg2: line parity reg 2 | |
69 | * @reg3: line parity reg 3 | |
ac7eb8a3 | 70 | * @ecc_code: ecc |
932394ac WD |
71 | * |
72 | * Creates non-inverted ECC code from line parity | |
73 | */ | |
74 | static void nand_trans_result(u_char reg2, u_char reg3, | |
75 | u_char *ecc_code) | |
76 | { | |
77 | u_char a, b, i, tmp1, tmp2; | |
ac7eb8a3 | 78 | |
932394ac WD |
79 | /* Initialize variables */ |
80 | a = b = 0x80; | |
81 | tmp1 = tmp2 = 0; | |
ac7eb8a3 | 82 | |
932394ac WD |
83 | /* Calculate first ECC byte */ |
84 | for (i = 0; i < 4; i++) { | |
85 | if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ | |
86 | tmp1 |= b; | |
87 | b >>= 1; | |
88 | if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */ | |
89 | tmp1 |= b; | |
90 | b >>= 1; | |
91 | a >>= 1; | |
92 | } | |
ac7eb8a3 | 93 | |
932394ac WD |
94 | /* Calculate second ECC byte */ |
95 | b = 0x80; | |
96 | for (i = 0; i < 4; i++) { | |
97 | if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */ | |
98 | tmp2 |= b; | |
99 | b >>= 1; | |
100 | if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */ | |
101 | tmp2 |= b; | |
102 | b >>= 1; | |
103 | a >>= 1; | |
104 | } | |
ac7eb8a3 | 105 | |
932394ac WD |
106 | /* Store two of the ECC bytes */ |
107 | ecc_code[0] = tmp1; | |
108 | ecc_code[1] = tmp2; | |
109 | } | |
110 | ||
111 | /** | |
112 | * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code for 256 byte block | |
113 | * @mtd: MTD block structure | |
114 | * @dat: raw data | |
115 | * @ecc_code: buffer for ECC | |
116 | */ | |
117 | int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) | |
118 | { | |
119 | u_char idx, reg1, reg2, reg3; | |
120 | int j; | |
ac7eb8a3 | 121 | |
932394ac WD |
122 | /* Initialize variables */ |
123 | reg1 = reg2 = reg3 = 0; | |
124 | ecc_code[0] = ecc_code[1] = ecc_code[2] = 0; | |
ac7eb8a3 WD |
125 | |
126 | /* Build up column parity */ | |
932394ac | 127 | for(j = 0; j < 256; j++) { |
ac7eb8a3 | 128 | |
932394ac WD |
129 | /* Get CP0 - CP5 from table */ |
130 | idx = nand_ecc_precalc_table[dat[j]]; | |
131 | reg1 ^= (idx & 0x3f); | |
ac7eb8a3 | 132 | |
932394ac WD |
133 | /* All bit XOR = 1 ? */ |
134 | if (idx & 0x40) { | |
135 | reg3 ^= (u_char) j; | |
136 | reg2 ^= ~((u_char) j); | |
137 | } | |
138 | } | |
ac7eb8a3 | 139 | |
932394ac WD |
140 | /* Create non-inverted ECC code from line parity */ |
141 | nand_trans_result(reg2, reg3, ecc_code); | |
ac7eb8a3 | 142 | |
932394ac WD |
143 | /* Calculate final ECC code */ |
144 | ecc_code[0] = ~ecc_code[0]; | |
145 | ecc_code[1] = ~ecc_code[1]; | |
146 | ecc_code[2] = ((~reg1) << 2) | 0x03; | |
147 | return 0; | |
148 | } | |
149 | ||
150 | /** | |
151 | * nand_correct_data - [NAND Interface] Detect and correct bit error(s) | |
152 | * @mtd: MTD block structure | |
153 | * @dat: raw data read from the chip | |
154 | * @read_ecc: ECC from the chip | |
155 | * @calc_ecc: the ECC calculated from raw data | |
156 | * | |
157 | * Detect and correct a 1 bit error for 256 byte block | |
158 | */ | |
159 | int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) | |
160 | { | |
161 | u_char a, b, c, d1, d2, d3, add, bit, i; | |
ac7eb8a3 WD |
162 | |
163 | /* Do error detection */ | |
932394ac WD |
164 | d1 = calc_ecc[0] ^ read_ecc[0]; |
165 | d2 = calc_ecc[1] ^ read_ecc[1]; | |
166 | d3 = calc_ecc[2] ^ read_ecc[2]; | |
ac7eb8a3 | 167 | |
932394ac WD |
168 | if ((d1 | d2 | d3) == 0) { |
169 | /* No errors */ | |
170 | return 0; | |
171 | } | |
172 | else { | |
173 | a = (d1 ^ (d1 >> 1)) & 0x55; | |
174 | b = (d2 ^ (d2 >> 1)) & 0x55; | |
175 | c = (d3 ^ (d3 >> 1)) & 0x54; | |
ac7eb8a3 | 176 | |
932394ac WD |
177 | /* Found and will correct single bit error in the data */ |
178 | if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { | |
179 | c = 0x80; | |
180 | add = 0; | |
181 | a = 0x80; | |
182 | for (i=0; i<4; i++) { | |
183 | if (d1 & c) | |
184 | add |= a; | |
185 | c >>= 2; | |
186 | a >>= 1; | |
187 | } | |
188 | c = 0x80; | |
189 | for (i=0; i<4; i++) { | |
190 | if (d2 & c) | |
191 | add |= a; | |
192 | c >>= 2; | |
193 | a >>= 1; | |
194 | } | |
195 | bit = 0; | |
196 | b = 0x04; | |
197 | c = 0x80; | |
198 | for (i=0; i<3; i++) { | |
199 | if (d3 & c) | |
200 | bit |= b; | |
201 | c >>= 2; | |
202 | b >>= 1; | |
203 | } | |
204 | b = 0x01; | |
205 | a = dat[add]; | |
206 | a ^= (b << bit); | |
207 | dat[add] = a; | |
208 | return 1; | |
ac7eb8a3 | 209 | } else { |
932394ac WD |
210 | i = 0; |
211 | while (d1) { | |
212 | if (d1 & 0x01) | |
213 | ++i; | |
214 | d1 >>= 1; | |
215 | } | |
216 | while (d2) { | |
217 | if (d2 & 0x01) | |
218 | ++i; | |
219 | d2 >>= 1; | |
220 | } | |
221 | while (d3) { | |
222 | if (d3 & 0x01) | |
223 | ++i; | |
224 | d3 >>= 1; | |
225 | } | |
226 | if (i == 1) { | |
227 | /* ECC Code Error Correction */ | |
228 | read_ecc[0] = calc_ecc[0]; | |
229 | read_ecc[1] = calc_ecc[1]; | |
230 | read_ecc[2] = calc_ecc[2]; | |
231 | return 2; | |
232 | } | |
233 | else { | |
234 | /* Uncorrectable Error */ | |
235 | return -1; | |
236 | } | |
237 | } | |
238 | } | |
ac7eb8a3 | 239 | |
932394ac WD |
240 | /* Should never happen */ |
241 | return -1; | |
242 | } | |
243 | ||
244 | #endif /* CONFIG_COMMANDS & CFG_CMD_NAND */ |