]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/nand/nand_ecc.c
* Add hook to NAND erase and implement nand_wait function.
[karo-tx-uboot.git] / drivers / nand / nand_ecc.c
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.
16  *
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.
21  *
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.
25  *
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.
33  *
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
40 #if (CONFIG_COMMANDS & CFG_CMD_NAND)
41
42 /*
43  * Pre-calculated 256-way 1 byte column parity
44  */
45 static const u_char nand_ecc_precalc_table[] = {
46         0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
47         0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
48         0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
49         0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
50         0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
51         0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
52         0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
53         0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
54         0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
55         0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
56         0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
57         0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
58         0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
59         0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
60         0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
61         0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
62 };
63
64
65 /**
66  * nand_trans_result - [GENERIC] create non-inverted ECC
67  * @reg2:       line parity reg 2
68  * @reg3:       line parity reg 3
69  * @ecc_code:   ecc
70  *
71  * Creates non-inverted ECC code from line parity
72  */
73 static void nand_trans_result(u_char reg2, u_char reg3,
74         u_char *ecc_code)
75 {
76         u_char a, b, i, tmp1, tmp2;
77
78         /* Initialize variables */
79         a = b = 0x80;
80         tmp1 = tmp2 = 0;
81
82         /* Calculate first ECC byte */
83         for (i = 0; i < 4; i++) {
84                 if (reg3 & a)           /* LP15,13,11,9 --> ecc_code[0] */
85                         tmp1 |= b;
86                 b >>= 1;
87                 if (reg2 & a)           /* LP14,12,10,8 --> ecc_code[0] */
88                         tmp1 |= b;
89                 b >>= 1;
90                 a >>= 1;
91         }
92
93         /* Calculate second ECC byte */
94         b = 0x80;
95         for (i = 0; i < 4; i++) {
96                 if (reg3 & a)           /* LP7,5,3,1 --> ecc_code[1] */
97                         tmp2 |= b;
98                 b >>= 1;
99                 if (reg2 & a)           /* LP6,4,2,0 --> ecc_code[1] */
100                         tmp2 |= b;
101                 b >>= 1;
102                 a >>= 1;
103         }
104
105         /* Store two of the ECC bytes */
106         ecc_code[0] = tmp1;
107         ecc_code[1] = tmp2;
108 }
109
110 /**
111  * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code for 256 byte block
112  * @mtd:        MTD block structure
113  * @dat:        raw data
114  * @ecc_code:   buffer for ECC
115  */
116 int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
117 {
118         u_char idx, reg1, reg2, reg3;
119         int j;
120
121         /* Initialize variables */
122         reg1 = reg2 = reg3 = 0;
123         ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
124
125         /* Build up column parity */
126         for(j = 0; j < 256; j++) {
127
128                 /* Get CP0 - CP5 from table */
129                 idx = nand_ecc_precalc_table[dat[j]];
130                 reg1 ^= (idx & 0x3f);
131
132                 /* All bit XOR = 1 ? */
133                 if (idx & 0x40) {
134                         reg3 ^= (u_char) j;
135                         reg2 ^= ~((u_char) j);
136                 }
137         }
138
139         /* Create non-inverted ECC code from line parity */
140         nand_trans_result(reg2, reg3, ecc_code);
141
142         /* Calculate final ECC code */
143         ecc_code[0] = ~ecc_code[0];
144         ecc_code[1] = ~ecc_code[1];
145         ecc_code[2] = ((~reg1) << 2) | 0x03;
146         return 0;
147 }
148
149 /**
150  * nand_correct_data - [NAND Interface] Detect and correct bit error(s)
151  * @mtd:        MTD block structure
152  * @dat:        raw data read from the chip
153  * @read_ecc:   ECC from the chip
154  * @calc_ecc:   the ECC calculated from raw data
155  *
156  * Detect and correct a 1 bit error for 256 byte block
157  */
158 int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
159 {
160         u_char a, b, c, d1, d2, d3, add, bit, i;
161
162         /* Do error detection */
163         d1 = calc_ecc[0] ^ read_ecc[0];
164         d2 = calc_ecc[1] ^ read_ecc[1];
165         d3 = calc_ecc[2] ^ read_ecc[2];
166
167         if ((d1 | d2 | d3) == 0) {
168                 /* No errors */
169                 return 0;
170         }
171         else {
172                 a = (d1 ^ (d1 >> 1)) & 0x55;
173                 b = (d2 ^ (d2 >> 1)) & 0x55;
174                 c = (d3 ^ (d3 >> 1)) & 0x54;
175
176                 /* Found and will correct single bit error in the data */
177                 if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
178                         c = 0x80;
179                         add = 0;
180                         a = 0x80;
181                         for (i=0; i<4; i++) {
182                                 if (d1 & c)
183                                         add |= a;
184                                 c >>= 2;
185                                 a >>= 1;
186                         }
187                         c = 0x80;
188                         for (i=0; i<4; i++) {
189                                 if (d2 & c)
190                                         add |= a;
191                                 c >>= 2;
192                                 a >>= 1;
193                         }
194                         bit = 0;
195                         b = 0x04;
196                         c = 0x80;
197                         for (i=0; i<3; i++) {
198                                 if (d3 & c)
199                                         bit |= b;
200                                 c >>= 2;
201                                 b >>= 1;
202                         }
203                         b = 0x01;
204                         a = dat[add];
205                         a ^= (b << bit);
206                         dat[add] = a;
207                         return 1;
208                 } else {
209                         i = 0;
210                         while (d1) {
211                                 if (d1 & 0x01)
212                                         ++i;
213                                 d1 >>= 1;
214                         }
215                         while (d2) {
216                                 if (d2 & 0x01)
217                                         ++i;
218                                 d2 >>= 1;
219                         }
220                         while (d3) {
221                                 if (d3 & 0x01)
222                                         ++i;
223                                 d3 >>= 1;
224                         }
225                         if (i == 1) {
226                                 /* ECC Code Error Correction */
227                                 read_ecc[0] = calc_ecc[0];
228                                 read_ecc[1] = calc_ecc[1];
229                                 read_ecc[2] = calc_ecc[2];
230                                 return 2;
231                         }
232                         else {
233                                 /* Uncorrectable Error */
234                                 return -1;
235                         }
236                 }
237         }
238
239         /* Should never happen */
240         return -1;
241 }
242
243 #endif  /* CONFIG_COMMANDS & CFG_CMD_NAND */