]> git.sur5r.net Git - openocd/blob - src/flash/nand_ecc.c
Nicolas Pitre nico at cam.org software ECC computation for NAND flash
[openocd] / src / flash / nand_ecc.c
1 /*\r
2  * This file contains an ECC algorithm from Toshiba that allows for detection\r
3  * and correction of 1-bit errors in a 256 byte block of data.\r
4  *\r
5  * [ Extracted from the initial code found in some early Linux versions.\r
6  *   The current Linux code is bigger while being faster, but this is of\r
7  *   no real benefit when the bottleneck largely remains the JTAG link.  ]\r
8  *\r
9  * Copyright (C) 2000-2004 Steven J. Hill (sjhill at realitydiluted.com)\r
10  *                         Toshiba America Electronics Components, Inc.\r
11  *\r
12  * Copyright (C) 2006 Thomas Gleixner <tglx at linutronix.de>\r
13  *\r
14  * This file is free software; you can redistribute it and/or modify it\r
15  * under the terms of the GNU General Public License as published by the\r
16  * Free Software Foundation; either version 2 or (at your option) any\r
17  * later version.\r
18  *\r
19  * This file is distributed in the hope that it will be useful, but WITHOUT\r
20  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
21  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\r
22  * for more details.\r
23  *\r
24  * You should have received a copy of the GNU General Public License along\r
25  * with this file; if not, write to the Free Software Foundation, Inc.,\r
26  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.\r
27  *\r
28  * As a special exception, if other files instantiate templates or use\r
29  * macros or inline functions from these files, or you compile these\r
30  * files and link them with other works to produce a work based on these\r
31  * files, these files do not by themselves cause the resulting work to be\r
32  * covered by the GNU General Public License. However the source code for\r
33  * these files must still be made available in accordance with section (3)\r
34  * of the GNU General Public License.\r
35  *\r
36  * This exception does not invalidate any other reasons why a work based on\r
37  * this file might be covered by the GNU General Public License.\r
38  */\r
39 \r
40 #ifdef HAVE_CONFIG_H\r
41 #include "config.h"\r
42 #endif\r
43 \r
44 #include "replacements.h"\r
45 \r
46 #include <inttypes.h>\r
47 \r
48 #include "nand.h"\r
49 \r
50 /*\r
51  * Pre-calculated 256-way 1 byte column parity\r
52  */\r
53 static const u8 nand_ecc_precalc_table[] = {\r
54         0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,\r
55         0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,\r
56         0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,\r
57         0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,\r
58         0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,\r
59         0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,\r
60         0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,\r
61         0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,\r
62         0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,\r
63         0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,\r
64         0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,\r
65         0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,\r
66         0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,\r
67         0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,\r
68         0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,\r
69         0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00\r
70 };\r
71 \r
72 /*\r
73  * nand_calculate_ecc - Calculate 3-byte ECC for 256-byte block\r
74  */\r
75 int nand_calculate_ecc(struct nand_device_s *device, const u8 *dat, u8 *ecc_code)\r
76 {\r
77         u8 idx, reg1, reg2, reg3, tmp1, tmp2;\r
78         int i;\r
79 \r
80         /* Initialize variables */\r
81         reg1 = reg2 = reg3 = 0;\r
82 \r
83         /* Build up column parity */\r
84         for(i = 0; i < 256; i++) {\r
85                 /* Get CP0 - CP5 from table */\r
86                 idx = nand_ecc_precalc_table[*dat++];\r
87                 reg1 ^= (idx & 0x3f);\r
88 \r
89                 /* All bit XOR = 1 ? */\r
90                 if (idx & 0x40) {\r
91                         reg3 ^= (u8) i;\r
92                         reg2 ^= ~((u8) i);\r
93                 }\r
94         }\r
95 \r
96         /* Create non-inverted ECC code from line parity */\r
97         tmp1  = (reg3 & 0x80) >> 0; /* B7 -> B7 */\r
98         tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */\r
99         tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */\r
100         tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */\r
101         tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */\r
102         tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */\r
103         tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */\r
104         tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */\r
105 \r
106         tmp2  = (reg3 & 0x08) << 4; /* B3 -> B7 */\r
107         tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */\r
108         tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */\r
109         tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */\r
110         tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */\r
111         tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */\r
112         tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */\r
113         tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */\r
114 \r
115         /* Calculate final ECC code */\r
116 #ifdef NAND_ECC_SMC\r
117         ecc_code[0] = ~tmp2;\r
118         ecc_code[1] = ~tmp1;\r
119 #else\r
120         ecc_code[0] = ~tmp1;\r
121         ecc_code[1] = ~tmp2;\r
122 #endif\r
123         ecc_code[2] = ((~reg1) << 2) | 0x03;\r
124 \r
125         return 0;\r
126 }\r