OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [mtd/] [nand/] [nand_ecc.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  drivers/mtd/nand_ecc.c
3
 *
4
 *  Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
5
 *                     Toshiba America Electronics Components, Inc.
6
 *
7
 * $Id: nand_ecc.c,v 1.1.1.1 2004-04-15 01:51:59 phoenix Exp $
8
 *
9
 * This program is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public License
11
 * version 2.1 as published by the Free Software Foundation.
12
 *
13
 * This file contains an ECC algorithm from Toshiba that detects and
14
 * corrects 1 bit errors in a 256 byte block of data.
15
 */
16
 
17
#include <linux/types.h>
18
#include <linux/kernel.h>
19
#include <linux/module.h>
20
 
21
/*
22
 * Pre-calculated 256-way 1 byte column parity
23
 */
24
static const u_char nand_ecc_precalc_table[] = {
25
        0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
26
        0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
27
        0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
28
        0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
29
        0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
30
        0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
31
        0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
32
        0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
33
        0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
34
        0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
35
        0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
36
        0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
37
        0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
38
        0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
39
        0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
40
        0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
41
};
42
 
43
 
44
/*
45
 * Creates non-inverted ECC code from line parity
46
 */
47
static void nand_trans_result(u_char reg2, u_char reg3,
48
        u_char *ecc_code)
49
{
50
        u_char a, b, i, tmp1, tmp2;
51
 
52
        /* Initialize variables */
53
        a = b = 0x80;
54
        tmp1 = tmp2 = 0;
55
 
56
        /* Calculate first ECC byte */
57
        for (i = 0; i < 4; i++) {
58
                if (reg3 & a)           /* LP15,13,11,9 --> ecc_code[0] */
59
                        tmp1 |= b;
60
                b >>= 1;
61
                if (reg2 & a)           /* LP14,12,10,8 --> ecc_code[0] */
62
                        tmp1 |= b;
63
                b >>= 1;
64
                a >>= 1;
65
        }
66
 
67
        /* Calculate second ECC byte */
68
        b = 0x80;
69
        for (i = 0; i < 4; i++) {
70
                if (reg3 & a)           /* LP7,5,3,1 --> ecc_code[1] */
71
                        tmp2 |= b;
72
                b >>= 1;
73
                if (reg2 & a)           /* LP6,4,2,0 --> ecc_code[1] */
74
                        tmp2 |= b;
75
                b >>= 1;
76
                a >>= 1;
77
        }
78
 
79
        /* Store two of the ECC bytes */
80
        ecc_code[0] = tmp1;
81
        ecc_code[1] = tmp2;
82
}
83
 
84
/*
85
 * Calculate 3 byte ECC code for 256 byte block
86
 */
87
void nand_calculate_ecc (const u_char *dat, u_char *ecc_code)
88
{
89
        u_char idx, reg1, reg2, reg3;
90
        int j;
91
 
92
        /* Initialize variables */
93
        reg1 = reg2 = reg3 = 0;
94
        ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
95
 
96
        /* Build up column parity */
97
        for(j = 0; j < 256; j++) {
98
 
99
                /* Get CP0 - CP5 from table */
100
                idx = nand_ecc_precalc_table[dat[j]];
101
                reg1 ^= (idx & 0x3f);
102
 
103
                /* All bit XOR = 1 ? */
104
                if (idx & 0x40) {
105
                        reg3 ^= (u_char) j;
106
                        reg2 ^= ~((u_char) j);
107
                }
108
        }
109
 
110
        /* Create non-inverted ECC code from line parity */
111
        nand_trans_result(reg2, reg3, ecc_code);
112
 
113
        /* Calculate final ECC code */
114
        ecc_code[0] = ~ecc_code[0];
115
        ecc_code[1] = ~ecc_code[1];
116
        ecc_code[2] = ((~reg1) << 2) | 0x03;
117
}
118
 
119
/*
120
 * Detect and correct a 1 bit error for 256 byte block
121
 */
122
int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc)
123
{
124
        u_char a, b, c, d1, d2, d3, add, bit, i;
125
 
126
        /* Do error detection */
127
        d1 = calc_ecc[0] ^ read_ecc[0];
128
        d2 = calc_ecc[1] ^ read_ecc[1];
129
        d3 = calc_ecc[2] ^ read_ecc[2];
130
 
131
        if ((d1 | d2 | d3) == 0) {
132
                /* No errors */
133
                return 0;
134
        }
135
        else {
136
                a = (d1 ^ (d1 >> 1)) & 0x55;
137
                b = (d2 ^ (d2 >> 1)) & 0x55;
138
                c = (d3 ^ (d3 >> 1)) & 0x54;
139
 
140
                /* Found and will correct single bit error in the data */
141
                if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
142
                        c = 0x80;
143
                        add = 0;
144
                        a = 0x80;
145
                        for (i=0; i<4; i++) {
146
                                if (d1 & c)
147
                                        add |= a;
148
                                c >>= 2;
149
                                a >>= 1;
150
                        }
151
                        c = 0x80;
152
                        for (i=0; i<4; i++) {
153
                                if (d2 & c)
154
                                        add |= a;
155
                                c >>= 2;
156
                                a >>= 1;
157
                        }
158
                        bit = 0;
159
                        b = 0x04;
160
                        c = 0x80;
161
                        for (i=0; i<3; i++) {
162
                                if (d3 & c)
163
                                        bit |= b;
164
                                c >>= 2;
165
                                b >>= 1;
166
                        }
167
                        b = 0x01;
168
                        a = dat[add];
169
                        a ^= (b << bit);
170
                        dat[add] = a;
171
                        return 1;
172
                }
173
                else {
174
                        i = 0;
175
                        while (d1) {
176
                                if (d1 & 0x01)
177
                                        ++i;
178
                                d1 >>= 1;
179
                        }
180
                        while (d2) {
181
                                if (d2 & 0x01)
182
                                        ++i;
183
                                d2 >>= 1;
184
                        }
185
                        while (d3) {
186
                                if (d3 & 0x01)
187
                                        ++i;
188
                                d3 >>= 1;
189
                        }
190
                        if (i == 1) {
191
                                /* ECC Code Error Correction */
192
                                read_ecc[0] = calc_ecc[0];
193
                                read_ecc[1] = calc_ecc[1];
194
                                read_ecc[2] = calc_ecc[2];
195
                                return 2;
196
                        }
197
                        else {
198
                                /* Uncorrectable Error */
199
                                return -1;
200
                        }
201
                }
202
        }
203
 
204
        /* Should never happen */
205
        return -1;
206
}
207
 
208
EXPORT_SYMBOL(nand_calculate_ecc);
209
EXPORT_SYMBOL(nand_correct_data);
210
 
211
MODULE_LICENSE("GPL");
212
MODULE_AUTHOR("Steven J. Hill <sjhill@cotw.com>");
213
MODULE_DESCRIPTION("Generic NAND ECC support");

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.