Blame view

fs/yaffs2/yaffs_ecc.c 6.98 KB
0e8cc8bd9   William Juul   YAFFS2 import
1
2
3
  /*
   * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
   *
753ac6108   Charles Manning   u-boot: Update ya...
4
   * Copyright (C) 2002-2011 Aleph One Ltd.
0e8cc8bd9   William Juul   YAFFS2 import
5
6
7
8
9
10
11
12
13
14
15
16
   *   for Toby Churchill Ltd and Brightstar Engineering
   *
   * Created by Charles Manning <charles@aleph1.co.uk>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
  
  /*
   * This code implements the ECC algorithm used in SmartMedia.
   *
4b0708093   Wolfgang Denk   Coding Style clea...
17
   * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
0e8cc8bd9   William Juul   YAFFS2 import
18
   * The two unused bit are set to 1.
753ac6108   Charles Manning   u-boot: Update ya...
19
20
   * The ECC can correct single bit errors in a 256-byte page of data. Thus, two
   * such ECC blocks are used on a 512-byte NAND page.
0e8cc8bd9   William Juul   YAFFS2 import
21
22
   *
   */
753ac6108   Charles Manning   u-boot: Update ya...
23
24
25
  #include "yportenv.h"
  
  #include "yaffs_ecc.h"
0e8cc8bd9   William Juul   YAFFS2 import
26
27
28
  /* Table generated by gen-ecc.c
   * Using a table means we do not have to calculate p1..p4 and p1'..p4'
   * for each byte of data. These are instead provided in a table in bits7..2.
753ac6108   Charles Manning   u-boot: Update ya...
29
30
   * Bit 0 of each entry indicates whether the entry has an odd or even parity,
   * and therefore this bytes influence on the line parity.
0e8cc8bd9   William Juul   YAFFS2 import
31
   */
0e8cc8bd9   William Juul   YAFFS2 import
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
  static const unsigned char column_parity_table[] = {
  	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
  	0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
  	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
  	0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
  	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
  	0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
  	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
  	0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
  	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
  	0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
  	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
  	0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
  	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
  	0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
  	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
  	0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
  	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
  	0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
  	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
  	0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
  	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
  	0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
  	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
  	0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
  	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
  	0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
  	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
  	0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
  	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
  	0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
  	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
  	0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
  };
0e8cc8bd9   William Juul   YAFFS2 import
66
67
  
  /* Calculate the ECC for a 256-byte block of data */
753ac6108   Charles Manning   u-boot: Update ya...
68
  void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc)
0e8cc8bd9   William Juul   YAFFS2 import
69
70
  {
  	unsigned int i;
0e8cc8bd9   William Juul   YAFFS2 import
71
72
73
74
75
76
77
78
79
  	unsigned char col_parity = 0;
  	unsigned char line_parity = 0;
  	unsigned char line_parity_prime = 0;
  	unsigned char t;
  	unsigned char b;
  
  	for (i = 0; i < 256; i++) {
  		b = column_parity_table[*data++];
  		col_parity ^= b;
753ac6108   Charles Manning   u-boot: Update ya...
80
  		if (b & 0x01) {	/* odd number of bits in the byte */
0e8cc8bd9   William Juul   YAFFS2 import
81
82
83
  			line_parity ^= i;
  			line_parity_prime ^= ~i;
  		}
0e8cc8bd9   William Juul   YAFFS2 import
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
  	}
  
  	ecc[2] = (~col_parity) | 0x03;
  
  	t = 0;
  	if (line_parity & 0x80)
  		t |= 0x80;
  	if (line_parity_prime & 0x80)
  		t |= 0x40;
  	if (line_parity & 0x40)
  		t |= 0x20;
  	if (line_parity_prime & 0x40)
  		t |= 0x10;
  	if (line_parity & 0x20)
  		t |= 0x08;
  	if (line_parity_prime & 0x20)
  		t |= 0x04;
  	if (line_parity & 0x10)
  		t |= 0x02;
  	if (line_parity_prime & 0x10)
  		t |= 0x01;
  	ecc[1] = ~t;
  
  	t = 0;
  	if (line_parity & 0x08)
  		t |= 0x80;
  	if (line_parity_prime & 0x08)
  		t |= 0x40;
  	if (line_parity & 0x04)
  		t |= 0x20;
  	if (line_parity_prime & 0x04)
  		t |= 0x10;
  	if (line_parity & 0x02)
  		t |= 0x08;
  	if (line_parity_prime & 0x02)
  		t |= 0x04;
  	if (line_parity & 0x01)
  		t |= 0x02;
  	if (line_parity_prime & 0x01)
  		t |= 0x01;
  	ecc[0] = ~t;
0e8cc8bd9   William Juul   YAFFS2 import
125
  }
0e8cc8bd9   William Juul   YAFFS2 import
126
  /* Correct the ECC on a 256 byte block of data */
753ac6108   Charles Manning   u-boot: Update ya...
127
128
  int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
  		      const unsigned char *test_ecc)
0e8cc8bd9   William Juul   YAFFS2 import
129
130
131
132
133
134
135
136
  {
  	unsigned char d0, d1, d2;	/* deltas */
  
  	d0 = read_ecc[0] ^ test_ecc[0];
  	d1 = read_ecc[1] ^ test_ecc[1];
  	d2 = read_ecc[2] ^ test_ecc[2];
  
  	if ((d0 | d1 | d2) == 0)
753ac6108   Charles Manning   u-boot: Update ya...
137
  		return 0;	/* no error */
0e8cc8bd9   William Juul   YAFFS2 import
138
139
140
141
142
143
144
145
  
  	if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
  	    ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
  	    ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
  		/* Single bit (recoverable) error in data */
  
  		unsigned byte;
  		unsigned bit;
0e8cc8bd9   William Juul   YAFFS2 import
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  		bit = byte = 0;
  
  		if (d1 & 0x80)
  			byte |= 0x80;
  		if (d1 & 0x20)
  			byte |= 0x40;
  		if (d1 & 0x08)
  			byte |= 0x20;
  		if (d1 & 0x02)
  			byte |= 0x10;
  		if (d0 & 0x80)
  			byte |= 0x08;
  		if (d0 & 0x20)
  			byte |= 0x04;
  		if (d0 & 0x08)
  			byte |= 0x02;
  		if (d0 & 0x02)
  			byte |= 0x01;
  
  		if (d2 & 0x80)
  			bit |= 0x04;
  		if (d2 & 0x20)
  			bit |= 0x02;
  		if (d2 & 0x08)
  			bit |= 0x01;
  
  		data[byte] ^= (1 << bit);
753ac6108   Charles Manning   u-boot: Update ya...
173
  		return 1;	/* Corrected the error */
0e8cc8bd9   William Juul   YAFFS2 import
174
  	}
753ac6108   Charles Manning   u-boot: Update ya...
175
  	if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) {
0e8cc8bd9   William Juul   YAFFS2 import
176
177
178
179
180
  		/* Reccoverable error in ecc */
  
  		read_ecc[0] = test_ecc[0];
  		read_ecc[1] = test_ecc[1];
  		read_ecc[2] = test_ecc[2];
753ac6108   Charles Manning   u-boot: Update ya...
181
  		return 1;	/* Corrected the error */
0e8cc8bd9   William Juul   YAFFS2 import
182
  	}
4b0708093   Wolfgang Denk   Coding Style clea...
183

0e8cc8bd9   William Juul   YAFFS2 import
184
185
186
187
188
  	/* Unrecoverable error */
  
  	return -1;
  
  }
0e8cc8bd9   William Juul   YAFFS2 import
189
190
191
  /*
   * ECCxxxOther does ECC calcs on arbitrary n bytes of data
   */
753ac6108   Charles Manning   u-boot: Update ya...
192
193
  void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
  			  struct yaffs_ecc_other *ecc_other)
0e8cc8bd9   William Juul   YAFFS2 import
194
195
  {
  	unsigned int i;
0e8cc8bd9   William Juul   YAFFS2 import
196
197
198
199
  	unsigned char col_parity = 0;
  	unsigned line_parity = 0;
  	unsigned line_parity_prime = 0;
  	unsigned char b;
753ac6108   Charles Manning   u-boot: Update ya...
200
  	for (i = 0; i < n_bytes; i++) {
0e8cc8bd9   William Juul   YAFFS2 import
201
202
  		b = column_parity_table[*data++];
  		col_parity ^= b;
753ac6108   Charles Manning   u-boot: Update ya...
203
  		if (b & 0x01) {
0e8cc8bd9   William Juul   YAFFS2 import
204
205
206
207
208
209
  			/* odd number of bits in the byte */
  			line_parity ^= i;
  			line_parity_prime ^= ~i;
  		}
  
  	}
753ac6108   Charles Manning   u-boot: Update ya...
210
211
212
  	ecc_other->col_parity = (col_parity >> 2) & 0x3f;
  	ecc_other->line_parity = line_parity;
  	ecc_other->line_parity_prime = line_parity_prime;
0e8cc8bd9   William Juul   YAFFS2 import
213
  }
753ac6108   Charles Manning   u-boot: Update ya...
214
215
216
  int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
  			    struct yaffs_ecc_other *read_ecc,
  			    const struct yaffs_ecc_other *test_ecc)
0e8cc8bd9   William Juul   YAFFS2 import
217
  {
753ac6108   Charles Manning   u-boot: Update ya...
218
219
220
  	unsigned char delta_col;	/* column parity delta */
  	unsigned delta_line;	/* line parity delta */
  	unsigned delta_line_prime;	/* line parity delta */
0e8cc8bd9   William Juul   YAFFS2 import
221
  	unsigned bit;
753ac6108   Charles Manning   u-boot: Update ya...
222
223
224
225
  	delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
  	delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
  	delta_line_prime =
  	    read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
0e8cc8bd9   William Juul   YAFFS2 import
226

753ac6108   Charles Manning   u-boot: Update ya...
227
228
  	if ((delta_col | delta_line | delta_line_prime) == 0)
  		return 0;	/* no error */
0e8cc8bd9   William Juul   YAFFS2 import
229

753ac6108   Charles Manning   u-boot: Update ya...
230
231
  	if (delta_line == ~delta_line_prime &&
  	    (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
0e8cc8bd9   William Juul   YAFFS2 import
232
233
234
  		/* Single bit (recoverable) error in data */
  
  		bit = 0;
753ac6108   Charles Manning   u-boot: Update ya...
235
  		if (delta_col & 0x20)
0e8cc8bd9   William Juul   YAFFS2 import
236
  			bit |= 0x04;
753ac6108   Charles Manning   u-boot: Update ya...
237
  		if (delta_col & 0x08)
0e8cc8bd9   William Juul   YAFFS2 import
238
  			bit |= 0x02;
753ac6108   Charles Manning   u-boot: Update ya...
239
  		if (delta_col & 0x02)
0e8cc8bd9   William Juul   YAFFS2 import
240
  			bit |= 0x01;
753ac6108   Charles Manning   u-boot: Update ya...
241
  		if (delta_line >= n_bytes)
0e8cc8bd9   William Juul   YAFFS2 import
242
  			return -1;
4b0708093   Wolfgang Denk   Coding Style clea...
243

753ac6108   Charles Manning   u-boot: Update ya...
244
  		data[delta_line] ^= (1 << bit);
0e8cc8bd9   William Juul   YAFFS2 import
245

753ac6108   Charles Manning   u-boot: Update ya...
246
  		return 1;	/* corrected */
0e8cc8bd9   William Juul   YAFFS2 import
247
  	}
753ac6108   Charles Manning   u-boot: Update ya...
248
249
250
  	if ((hweight32(delta_line) +
  	     hweight32(delta_line_prime) +
  	     hweight8(delta_col)) == 1) {
0e8cc8bd9   William Juul   YAFFS2 import
251
252
253
  		/* Reccoverable error in ecc */
  
  		*read_ecc = *test_ecc;
753ac6108   Charles Manning   u-boot: Update ya...
254
  		return 1;	/* corrected */
0e8cc8bd9   William Juul   YAFFS2 import
255
256
257
258
259
  	}
  
  	/* Unrecoverable error */
  
  	return -1;
0e8cc8bd9   William Juul   YAFFS2 import
260
  }