Version 0.4 from Mike Line
[keystone-rtos/ibl.git] / src / ecc / 3byte / 3byte_ecc.c
1 /******************************************************************************
2  * Copyright (c) 2010 Texas Instruments Incorporated - http://www.ti.com
3  * 
4  *  Redistribution and use in source and binary forms, with or without 
5  *  modification, are permitted provided that the following conditions 
6  *  are met:
7  *
8  *    Redistributions of source code must retain the above copyright 
9  *    notice, this list of conditions and the following disclaimer.
10  *
11  *    Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the 
13  *    documentation and/or other materials provided with the   
14  *    distribution.
15  *
16  *    Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
21  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
22  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
24  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
25  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
26  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
29  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
30  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  * 
32  *****************************************************************************/
33  
34 /******************************************************************************
35  *
36  * File Name:   ecc.c
37  *
38  * Description: This file implements ECC algorithm used on micron NAND flash
39  *                              
40  * History:             
41  *              SEP/4/2009, Amit Solanki,       Created the file
42  * 
43  *****************************************************************************/
44 /****************
45  * Include Files
46  ****************/
47 #include "types.h"
48 #include "ecc.h"
50 /*********************************
51  * Defines and Macros and globals
52  *********************************/
53 // Pre-calculated 256-way 1 byte column parity
54 static const Uint8 nand_ecc_precalc_table[] = {
55         0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
56         0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
57         0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
58         0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
59         0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
60         0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
61         0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
62         0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
63         0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
64         0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
65         0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
66         0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
67         0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
68         0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
69         0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
70         0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
71 };
73 /******************************************************************************
74  * 
75  * Function:    nandTransResult  
76  *
77  * Description: Creates non-inverted ECC code from line parity
78  *
79  * Parameters:  Uint8 uchReg2 - line parity reg 2
80  *                              Uint8 uchReg3 - line parity reg 3
81  *                              Uint8 *puchEccCode - ecc
82  *
83  * Return Value: void
84  ******************************************************************************/
85 static void nandTransResult(Uint8 uchReg2, Uint8 uchReg3, Uint8 *puchEccCode)
86 {
87         Uint8 a, b, i, tmp1, tmp2;
89         /* Initialize variables */
90         a = b = 0x80;
91         tmp1 = tmp2 = 0;
93         /* Calculate first ECC byte */
94         for (i = 0; i < 4; i++) {
95                 if (uchReg3 & a)                /* LP15,13,11,9 --> ecc_code[0] */
96                         tmp1 |= b;
97                 b >>= 1;
98                 if (uchReg2 & a)                /* LP14,12,10,8 --> ecc_code[0] */
99                         tmp1 |= b;
100                 b >>= 1;
101                 a >>= 1;
102         }
104         /* Calculate second ECC byte */
105         b = 0x80;
106         for (i = 0; i < 4; i++) {
107                 if (uchReg3 & a)                /* LP7,5,3,1 --> ecc_code[1] */
108                         tmp2 |= b;
109                 b >>= 1;
110                 if (uchReg2 & a)                /* LP6,4,2,0 --> ecc_code[1] */
111                         tmp2 |= b;
112                 b >>= 1;
113                 a >>= 1;
114         }
116         /* Store two of the ECC bytes */
117         puchEccCode[0] = tmp1;
118         puchEccCode[1] = tmp2;
120 /******************************************************************************
121  * 
122  * Function:    eccComputeECC  
123  *
124  * Description: Compute 3 byte ECC code for 256 byte block
125  *
126  * Parameters:  Uint8* puchData - pointer to raw data
127  *                              Uint8 *puchEccCode - pointer to ECC buffer
128  *
129  * Return Value: status
130  ******************************************************************************/
131 Int32 eccComputeECC(const Uint8 *puchData, Uint8 *puchEccCode)
133         Uint8 uchIndex, uchReg1, uchReg2, uchReg3;
134         int j;
135         if(puchData == NULL || puchEccCode == NULL)
136                 return ECC_FAIL;
137                 
138         /* Initialize variables */
139         uchReg1 = uchReg2 = uchReg3 = 0;
140         puchEccCode[0] = puchEccCode[1] = puchEccCode[2] = 0;
142         /* Build up column parity */
143         for(j = 0; j < 256; j++) {
145                 /* Get CP0 - CP5 from table */
146                 uchIndex = nand_ecc_precalc_table[puchData[j]];
147                 uchReg1 ^= (uchIndex & 0x3f);
149                 /* All bit XOR = 1 ? */
150                 if (uchIndex & 0x40) {
151                         uchReg3 ^= (Uint8) j;
152                         uchReg2 ^= ~((Uint8) j);
153                 }
154         }
156         /* Create non-inverted ECC code from line parity */
157         nandTransResult(uchReg2, uchReg3, puchEccCode);
159         /* Calculate final ECC code */
160         puchEccCode[0] = ~puchEccCode[0];
161         puchEccCode[1] = ~puchEccCode[1];
162         puchEccCode[2] = ((~uchReg1) << 2) | 0x03;
163         return ECC_SUCCESS;
167 /******************************************************************************
168  * 
169  * Function:    eccCorrectData  
170  *
171  * Description: Detect and correct a 1 bit error for 256 byte block
172  *
173  * Parameters:  Uint8* puchData - Raw data read from the chip
174  *                              Uint8 *puchEccRead - ECC from the chip
175  *                              Uint8 *puchEccCalc - ECC calculated from raw data
176  *                              
177  * Return Value: status
178  ******************************************************************************/
179 Int32 eccCorrectData(Uint8 *puchData, Uint8 *puchEccRead, Uint8 *puchEccCalc)
181         Uint8 a, b, c, d1, d2, d3, add, bit, i;
182         
183         if(puchData == NULL || puchEccRead == NULL || puchEccCalc == NULL)
184                 return ECC_FAIL;
185         
186         /* Do error detection */
187         d1 = puchEccCalc[0] ^ puchEccRead[0];
188         d2 = puchEccCalc[1] ^ puchEccRead[1];
189         d3 = puchEccCalc[2] ^ puchEccRead[2];
191         if ((d1 | d2 | d3) == 0) {
192                 /* No errors */
193                 return ECC_SUCCESS;
194         }
195         else {
196                 a = (d1 ^ (d1 >> 1)) & 0x55;
197                 b = (d2 ^ (d2 >> 1)) & 0x55;
198                 c = (d3 ^ (d3 >> 1)) & 0x54;
200                 /* Found and will correct single bit error in the data */
201                 if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
202                         c = 0x80;
203                         add = 0;
204                         a = 0x80;
205                         for (i=0; i<4; i++) {
206                                 if (d1 & c)
207                                         add |= a;
208                                 c >>= 2;
209                                 a >>= 1;
210                         }
211                         c = 0x80;
212                         for (i=0; i<4; i++) {
213                                 if (d2 & c)
214                                         add |= a;
215                                 c >>= 2;
216                                 a >>= 1;
217                         }
218                         bit = 0;
219                         b = 0x04;
220                         c = 0x80;
221                         for (i=0; i<3; i++) {
222                                 if (d3 & c)
223                                         bit |= b;
224                                 c >>= 2;
225                                 b >>= 1;
226                         }
227                         b = 0x01;
228                         a = puchData[add];
229                         a ^= (b << bit);
230                         puchData[add] = a;
231                         return ECC_SUCCESS;
232                 } else {
233                         i = 0;
234                         while (d1) {
235                                 if (d1 & 0x01)
236                                         ++i;
237                                 d1 >>= 1;
238                         }
239                         while (d2) {
240                                 if (d2 & 0x01)
241                                         ++i;
242                                 d2 >>= 1;
243                         }
244                         while (d3) {
245                                 if (d3 & 0x01)
246                                         ++i;
247                                 d3 >>= 1;
248                         }
249                         if (i == 1) {
250                                 /* ECC Code Error Correction */
251                                 puchEccRead[0] = puchEccCalc[0];
252                                 puchEccRead[1] = puchEccCalc[1];
253                                 puchEccRead[2] = puchEccCalc[2];
254                                 return ECC_SUCCESS;
255                         }
256                         else {
257                                 /* Uncorrectable Error */
258                                 return ECC_FAIL;
259                         }
260                 }
261         }