OMAP3: X-Loader: Make MMC register macros volatile
[x-load.git] / lib / ecc.c
blob28fc40de35626b07a40663fc616fc91088c8b8f4
1 /*
2 * (C) Copyright 2000 Texas Instruments
3 *
4 * This file os based on the following u-boot file:
5 * common/cmd_nand.c
7 * See file CREDITS for list of people who contributed to this
8 * project.
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.
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.
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
26 #include <common.h>
29 * Pre-calculated 256-way 1 byte column parity
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
52 * Creates non-inverted ECC code from line parity
54 static void nand_trans_result(u_char reg2, u_char reg3,
55 u_char *ecc_code)
57 u_char a, b, i, tmp1, tmp2;
59 /* Initialize variables */
60 a = b = 0x80;
61 tmp1 = tmp2 = 0;
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;
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;
86 /* Store two of the ECC bytes */
87 ecc_code[0] = tmp1;
88 ecc_code[1] = tmp2;
92 * Calculate 3 byte ECC code for 256 byte block
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
98 #ifdef NAND_LEGACY
99 void nand_calculate_ecc (const u_char *dat, u_char *ecc_code)
101 u_char idx, reg1, reg3;
102 int j;
104 /* Initialize variables */
105 reg1 = reg3 = 0;
106 ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
108 /* Build up column parity */
109 for(j = 0; j < 256; j++) {
111 /* Get CP0 - CP5 from table */
112 idx = nand_ecc_precalc_table[dat[j]];
113 reg1 ^= idx;
115 /* All bit XOR = 1 ? */
116 if (idx & 0x40) {
117 reg3 ^= (u_char) j;
121 /* Create non-inverted ECC code from line parity */
122 nand_trans_result((reg1 & 0x40) ? ~reg3 : reg3, reg3, ecc_code);
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;
129 #else
130 void nand_calculate_ecc (const u_char *dat, u_char *ecc_code)
132 u_char idx, reg1, reg2, reg3;
133 int j;
135 /* Initialize variables */
136 reg1 = reg2 = reg3 = 0;
137 ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
139 /* Build up column parity */
140 for(j = 0; j < 256; j++) {
142 /* Get CP0 - CP5 from table */
143 idx = nand_ecc_precalc_table[dat[j]];
144 reg1 ^= (idx & 0x3f);
146 /* All bit XOR = 1 ? */
147 if (idx & 0x40) {
148 reg3 ^= (u_char) j;
149 reg2 ^= ~((u_char) j);
153 /* Create non-inverted ECC code from line parity */
154 nand_trans_result(reg2, reg3, ecc_code);
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;
161 #endif
163 * Detect and correct a 1 bit error for 256 byte block
165 int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc)
167 u_char a, b, c, d1, d2, d3, add, bit, i;
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];
174 if ((d1 | d2 | d3) == 0) {
175 /* No errors */
176 return 0;
178 else {
179 a = (d1 ^ (d1 >> 1)) & 0x55;
180 b = (d2 ^ (d2 >> 1)) & 0x55;
181 c = (d3 ^ (d3 >> 1)) & 0x54;
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;
194 c = 0x80;
195 for (i=0; i<4; i++) {
196 if (d2 & c)
197 add |= a;
198 c >>= 2;
199 a >>= 1;
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;
210 b = 0x01;
211 a = dat[add];
212 a ^= (b << bit);
213 dat[add] = a;
214 return 1;
216 else {
217 i = 0;
218 while (d1) {
219 if (d1 & 0x01)
220 ++i;
221 d1 >>= 1;
223 while (d2) {
224 if (d2 & 0x01)
225 ++i;
226 d2 >>= 1;
228 while (d3) {
229 if (d3 & 0x01)
230 ++i;
231 d3 >>= 1;
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;
240 else {
241 /* Uncorrectable Error */
242 return -1;
247 /* Should never happen */
248 return -1;