]> git.sur5r.net Git - openocd/commitdiff
Nicolas Pitre nico at cam.org software ECC computation for NAND flash
authoroharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Thu, 2 Apr 2009 21:23:16 +0000 (21:23 +0000)
committeroharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Thu, 2 Apr 2009 21:23:16 +0000 (21:23 +0000)
git-svn-id: svn://svn.berlios.de/openocd/trunk@1445 b42882b7-edfa-0310-969c-e2dbd0fdcd60

src/flash/nand_ecc.c [new file with mode: 0644]

diff --git a/src/flash/nand_ecc.c b/src/flash/nand_ecc.c
new file mode 100644 (file)
index 0000000..27777c3
--- /dev/null
@@ -0,0 +1,126 @@
+/*\r
+ * This file contains an ECC algorithm from Toshiba that allows for detection\r
+ * and correction of 1-bit errors in a 256 byte block of data.\r
+ *\r
+ * [ Extracted from the initial code found in some early Linux versions.\r
+ *   The current Linux code is bigger while being faster, but this is of\r
+ *   no real benefit when the bottleneck largely remains the JTAG link.  ]\r
+ *\r
+ * Copyright (C) 2000-2004 Steven J. Hill (sjhill at realitydiluted.com)\r
+ *                         Toshiba America Electronics Components, Inc.\r
+ *\r
+ * Copyright (C) 2006 Thomas Gleixner <tglx at linutronix.de>\r
+ *\r
+ * This file is free software; you can redistribute it and/or modify it\r
+ * under the terms of the GNU General Public License as published by the\r
+ * Free Software Foundation; either version 2 or (at your option) any\r
+ * later version.\r
+ *\r
+ * This file is distributed in the hope that it will be useful, but WITHOUT\r
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\r
+ * for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this file; if not, write to the Free Software Foundation, Inc.,\r
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.\r
+ *\r
+ * As a special exception, if other files instantiate templates or use\r
+ * macros or inline functions from these files, or you compile these\r
+ * files and link them with other works to produce a work based on these\r
+ * files, these files do not by themselves cause the resulting work to be\r
+ * covered by the GNU General Public License. However the source code for\r
+ * these files must still be made available in accordance with section (3)\r
+ * of the GNU General Public License.\r
+ *\r
+ * This exception does not invalidate any other reasons why a work based on\r
+ * this file might be covered by the GNU General Public License.\r
+ */\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#include "replacements.h"\r
+\r
+#include <inttypes.h>\r
+\r
+#include "nand.h"\r
+\r
+/*\r
+ * Pre-calculated 256-way 1 byte column parity\r
+ */\r
+static const u8 nand_ecc_precalc_table[] = {\r
+       0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,\r
+       0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,\r
+       0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,\r
+       0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,\r
+       0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,\r
+       0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,\r
+       0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,\r
+       0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,\r
+       0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,\r
+       0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,\r
+       0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,\r
+       0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,\r
+       0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,\r
+       0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,\r
+       0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,\r
+       0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00\r
+};\r
+\r
+/*\r
+ * nand_calculate_ecc - Calculate 3-byte ECC for 256-byte block\r
+ */\r
+int nand_calculate_ecc(struct nand_device_s *device, const u8 *dat, u8 *ecc_code)\r
+{\r
+       u8 idx, reg1, reg2, reg3, tmp1, tmp2;\r
+       int i;\r
+\r
+       /* Initialize variables */\r
+       reg1 = reg2 = reg3 = 0;\r
+\r
+       /* Build up column parity */\r
+       for(i = 0; i < 256; i++) {\r
+               /* Get CP0 - CP5 from table */\r
+               idx = nand_ecc_precalc_table[*dat++];\r
+               reg1 ^= (idx & 0x3f);\r
+\r
+               /* All bit XOR = 1 ? */\r
+               if (idx & 0x40) {\r
+                       reg3 ^= (u8) i;\r
+                       reg2 ^= ~((u8) i);\r
+               }\r
+       }\r
+\r
+       /* Create non-inverted ECC code from line parity */\r
+       tmp1  = (reg3 & 0x80) >> 0; /* B7 -> B7 */\r
+       tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */\r
+       tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */\r
+       tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */\r
+       tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */\r
+       tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */\r
+       tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */\r
+       tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */\r
+\r
+       tmp2  = (reg3 & 0x08) << 4; /* B3 -> B7 */\r
+       tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */\r
+       tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */\r
+       tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */\r
+       tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */\r
+       tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */\r
+       tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */\r
+       tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */\r
+\r
+       /* Calculate final ECC code */\r
+#ifdef NAND_ECC_SMC\r
+       ecc_code[0] = ~tmp2;\r
+       ecc_code[1] = ~tmp1;\r
+#else\r
+       ecc_code[0] = ~tmp1;\r
+       ecc_code[1] = ~tmp2;\r
+#endif\r
+       ecc_code[2] = ((~reg1) << 2) | 0x03;\r
+\r
+       return 0;\r
+}\r