1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38#include <common.h>
39
40#include <asm/errno.h>
41#include <linux/mtd/mtd.h>
42
43
44#ifdef CONFIG_NAND_NDFC
45#define CONFIG_MTD_NAND_ECC_SMC
46#endif
47
48
49
50
51
52
53#if !defined(CONFIG_NAND_SPL) || defined(CONFIG_SPL_NAND_SOFTECC)
54
55
56
57static const u_char nand_ecc_precalc_table[] = {
58 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
59 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
60 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
61 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
62 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
63 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
64 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
65 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
66 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
67 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
68 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
69 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
70 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
71 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
72 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
73 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
74};
75
76
77
78
79
80
81
82int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
83 u_char *ecc_code)
84{
85 uint8_t idx, reg1, reg2, reg3, tmp1, tmp2;
86 int i;
87
88
89 reg1 = reg2 = reg3 = 0;
90
91
92 for(i = 0; i < 256; i++) {
93
94 idx = nand_ecc_precalc_table[*dat++];
95 reg1 ^= (idx & 0x3f);
96
97
98 if (idx & 0x40) {
99 reg3 ^= (uint8_t) i;
100 reg2 ^= ~((uint8_t) i);
101 }
102 }
103
104
105 tmp1 = (reg3 & 0x80) >> 0;
106 tmp1 |= (reg2 & 0x80) >> 1;
107 tmp1 |= (reg3 & 0x40) >> 1;
108 tmp1 |= (reg2 & 0x40) >> 2;
109 tmp1 |= (reg3 & 0x20) >> 2;
110 tmp1 |= (reg2 & 0x20) >> 3;
111 tmp1 |= (reg3 & 0x10) >> 3;
112 tmp1 |= (reg2 & 0x10) >> 4;
113
114 tmp2 = (reg3 & 0x08) << 4;
115 tmp2 |= (reg2 & 0x08) << 3;
116 tmp2 |= (reg3 & 0x04) << 3;
117 tmp2 |= (reg2 & 0x04) << 2;
118 tmp2 |= (reg3 & 0x02) << 2;
119 tmp2 |= (reg2 & 0x02) << 1;
120 tmp2 |= (reg3 & 0x01) << 1;
121 tmp2 |= (reg2 & 0x01) << 0;
122
123
124#ifdef CONFIG_MTD_NAND_ECC_SMC
125 ecc_code[0] = ~tmp2;
126 ecc_code[1] = ~tmp1;
127#else
128 ecc_code[0] = ~tmp1;
129 ecc_code[1] = ~tmp2;
130#endif
131 ecc_code[2] = ((~reg1) << 2) | 0x03;
132
133 return 0;
134}
135#endif
136
137static inline int countbits(uint32_t byte)
138{
139 int res = 0;
140
141 for (;byte; byte >>= 1)
142 res += byte & 0x01;
143 return res;
144}
145
146
147
148
149
150
151
152
153
154
155int nand_correct_data(struct mtd_info *mtd, u_char *dat,
156 u_char *read_ecc, u_char *calc_ecc)
157{
158 uint8_t s0, s1, s2;
159
160#ifdef CONFIG_MTD_NAND_ECC_SMC
161 s0 = calc_ecc[0] ^ read_ecc[0];
162 s1 = calc_ecc[1] ^ read_ecc[1];
163 s2 = calc_ecc[2] ^ read_ecc[2];
164#else
165 s1 = calc_ecc[0] ^ read_ecc[0];
166 s0 = calc_ecc[1] ^ read_ecc[1];
167 s2 = calc_ecc[2] ^ read_ecc[2];
168#endif
169 if ((s0 | s1 | s2) == 0)
170 return 0;
171
172
173 if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 &&
174 ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 &&
175 ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) {
176
177 uint32_t byteoffs, bitnum;
178
179 byteoffs = (s1 << 0) & 0x80;
180 byteoffs |= (s1 << 1) & 0x40;
181 byteoffs |= (s1 << 2) & 0x20;
182 byteoffs |= (s1 << 3) & 0x10;
183
184 byteoffs |= (s0 >> 4) & 0x08;
185 byteoffs |= (s0 >> 3) & 0x04;
186 byteoffs |= (s0 >> 2) & 0x02;
187 byteoffs |= (s0 >> 1) & 0x01;
188
189 bitnum = (s2 >> 5) & 0x04;
190 bitnum |= (s2 >> 4) & 0x02;
191 bitnum |= (s2 >> 3) & 0x01;
192
193 dat[byteoffs] ^= (1 << bitnum);
194
195 return 1;
196 }
197
198 if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1)
199 return 1;
200
201 return -EBADMSG;
202}
203