more verbose logging
[pandora-x-loader.git] / lib / ecc.c
1 /*
2  * (C) Copyright 2000 Texas Instruments
3  * 
4  * This file os based on the following u-boot file:
5  *      common/cmd_nand.c
6  *
7  * See file CREDITS for list of people who contributed to this
8  * project.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation; either version 2 of
13  * the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23  * MA 02111-1307 USA
24  */
25
26 #include <common.h>
27 \r
28 /*
29  * Pre-calculated 256-way 1 byte column parity
30  */
31 static const u_char nand_ecc_precalc_table[] = {
32         0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
33         0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
34         0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
35         0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
36         0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
37         0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
38         0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
39         0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
40         0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
41         0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
42         0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
43         0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
44         0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
45         0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
46         0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
47         0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
48 };
49
50
51 /*
52  * Creates non-inverted ECC code from line parity
53  */
54 static void nand_trans_result(u_char reg2, u_char reg3,
55         u_char *ecc_code)
56 {
57         u_char a, b, i, tmp1, tmp2;
58
59         /* Initialize variables */
60         a = b = 0x80;
61         tmp1 = tmp2 = 0;
62
63         /* Calculate first ECC byte */
64         for (i = 0; i < 4; i++) {
65                 if (reg3 & a)           /* LP15,13,11,9 --> ecc_code[0] */
66                         tmp1 |= b;
67                 b >>= 1;
68                 if (reg2 & a)           /* LP14,12,10,8 --> ecc_code[0] */
69                         tmp1 |= b;
70                 b >>= 1;
71                 a >>= 1;
72         }
73
74         /* Calculate second ECC byte */
75         b = 0x80;
76         for (i = 0; i < 4; i++) {
77                 if (reg3 & a)           /* LP7,5,3,1 --> ecc_code[1] */
78                         tmp2 |= b;
79                 b >>= 1;
80                 if (reg2 & a)           /* LP6,4,2,0 --> ecc_code[1] */
81                         tmp2 |= b;
82                 b >>= 1;
83                 a >>= 1;
84         }
85
86         /* Store two of the ECC bytes */
87         ecc_code[0] = tmp1;
88         ecc_code[1] = tmp2;
89 }
90
91 /*
92  * Calculate 3 byte ECC code for 256 byte block
93  */
94 /* ECC Calculation is different between NAND and NAND Legacy code
95  * in U-Boot. If NAND_LEGACY is enabled in u-boot it should be 
96  * enabled in the config file in x-loader also 
97  */
98 #ifdef NAND_LEGACY
99 void nand_calculate_ecc (const u_char *dat, u_char *ecc_code)
100 {
101         u_char idx, reg1, reg3;
102         int j;
103
104         /* Initialize variables */
105         reg1 = reg3 = 0;
106         ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
107
108         /* Build up column parity */
109         for(j = 0; j < 256; j++) {
110
111                 /* Get CP0 - CP5 from table */
112                 idx = nand_ecc_precalc_table[dat[j]];
113                 reg1 ^= idx;
114
115                 /* All bit XOR = 1 ? */
116                 if (idx & 0x40) {
117                         reg3 ^= (u_char) j;
118                 }
119         }
120
121         /* Create non-inverted ECC code from line parity */
122         nand_trans_result((reg1 & 0x40) ? ~reg3 : reg3, reg3, ecc_code);
123
124         /* Calculate final ECC code */
125         ecc_code[0] = ~ecc_code[0];
126         ecc_code[1] = ~ecc_code[1];
127         ecc_code[2] = ((~reg1) << 2) | 0x03;
128 }
129 #else
130 void nand_calculate_ecc (const u_char *dat, u_char *ecc_code)
131 {
132         u_char idx, reg1, reg2, reg3;
133         int j;
134
135         /* Initialize variables */
136         reg1 = reg2 = reg3 = 0;
137         ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
138
139         /* Build up column parity */
140         for(j = 0; j < 256; j++) {
141
142                 /* Get CP0 - CP5 from table */
143                 idx = nand_ecc_precalc_table[dat[j]];
144                 reg1 ^= (idx & 0x3f);
145
146                 /* All bit XOR = 1 ? */
147                 if (idx & 0x40) {
148                         reg3 ^= (u_char) j;
149                         reg2 ^= ~((u_char) j);
150                 }
151         }
152
153         /* Create non-inverted ECC code from line parity */
154         nand_trans_result(reg2, reg3, ecc_code);
155
156         /* Calculate final ECC code */
157         ecc_code[0] = ~ecc_code[0];
158         ecc_code[1] = ~ecc_code[1];
159         ecc_code[2] = ((~reg1) << 2) | 0x03;
160 }
161 #endif
162 /*
163  * Detect and correct a 1 bit error for 256 byte block
164  */
165 int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc)
166 {
167         u_char a, b, c, d1, d2, d3, add, bit, i;
168
169         /* Do error detection */
170         d1 = calc_ecc[0] ^ read_ecc[0];
171         d2 = calc_ecc[1] ^ read_ecc[1];
172         d3 = calc_ecc[2] ^ read_ecc[2];
173
174         if ((d1 | d2 | d3) == 0) {
175                 /* No errors */
176                 return 0;
177         }
178         else {
179                 a = (d1 ^ (d1 >> 1)) & 0x55;
180                 b = (d2 ^ (d2 >> 1)) & 0x55;
181                 c = (d3 ^ (d3 >> 1)) & 0x54;
182
183                 /* Found and will correct single bit error in the data */
184                 if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
185                         c = 0x80;
186                         add = 0;
187                         a = 0x80;
188                         for (i=0; i<4; i++) {
189                                 if (d1 & c)
190                                         add |= a;
191                                 c >>= 2;
192                                 a >>= 1;
193                         }
194                         c = 0x80;
195                         for (i=0; i<4; i++) {
196                                 if (d2 & c)
197                                         add |= a;
198                                 c >>= 2;
199                                 a >>= 1;
200                         }
201                         bit = 0;
202                         b = 0x04;
203                         c = 0x80;
204                         for (i=0; i<3; i++) {
205                                 if (d3 & c)
206                                         bit |= b;
207                                 c >>= 2;
208                                 b >>= 1;
209                         }
210                         b = 0x01;
211                         a = dat[add];
212                         a ^= (b << bit);
213                         dat[add] = a;
214                         return 1;
215                 }
216                 else {
217                         i = 0;
218                         while (d1) {
219                                 if (d1 & 0x01)
220                                         ++i;
221                                 d1 >>= 1;
222                         }
223                         while (d2) {
224                                 if (d2 & 0x01)
225                                         ++i;
226                                 d2 >>= 1;
227                         }
228                         while (d3) {
229                                 if (d3 & 0x01)
230                                         ++i;
231                                 d3 >>= 1;
232                         }
233                         if (i == 1) {
234                                 /* ECC Code Error Correction */
235                                 read_ecc[0] = calc_ecc[0];
236                                 read_ecc[1] = calc_ecc[1];
237                                 read_ecc[2] = calc_ecc[2];
238                                 return 2;
239                         }
240                         else {
241                                 /* Uncorrectable Error */
242                                 return -1;
243                         }
244                 }
245         }
246
247         /* Should never happen */
248         return -1;
249 }
250