summaryrefslogtreecommitdiff
path: root/ubi-utils/src/nandcorr.c
diff options
context:
space:
mode:
Diffstat (limited to 'ubi-utils/src/nandcorr.c')
-rw-r--r--ubi-utils/src/nandcorr.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/ubi-utils/src/nandcorr.c b/ubi-utils/src/nandcorr.c
new file mode 100644
index 0000000..7f1a547
--- /dev/null
+++ b/ubi-utils/src/nandcorr.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * ECC algorithm for NAND FLASH. Detects and corrects 1 bit errors in
+ * a 256 bytes of data.
+ *
+ * Reimplement by Thomas Gleixner after staring long enough at the
+ * mess in drivers/mtd/nand/nandecc.c
+ *
+ */
+
+#include "nandecc.h"
+
+static int countbits(uint32_t byte)
+{
+ int res = 0;
+
+ for (;byte; byte >>= 1)
+ res += byte & 0x01;
+ return res;
+}
+
+int nand_correct_data(uint8_t *dat, const uint8_t *fail_ecc)
+
+{
+ uint8_t s0, s1, s2;
+
+ /*
+ * Do error detection
+ *
+ * Be careful, the index magic is due to a pointer to a
+ * uint32_t.
+ */
+ s0 = fail_ecc[1];
+ s1 = fail_ecc[2];
+ s2 = fail_ecc[3];
+
+ /* Check for a single bit error */
+ if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 &&
+ ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 &&
+ ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) {
+
+ uint32_t byteoffs, bitnum;
+
+ byteoffs = (s1 << 0) & 0x80;
+ byteoffs |= (s1 << 1) & 0x40;
+ byteoffs |= (s1 << 2) & 0x20;
+ byteoffs |= (s1 << 3) & 0x10;
+
+ byteoffs |= (s0 >> 4) & 0x08;
+ byteoffs |= (s0 >> 3) & 0x04;
+ byteoffs |= (s0 >> 2) & 0x02;
+ byteoffs |= (s0 >> 1) & 0x01;
+
+ bitnum = (s2 >> 5) & 0x04;
+ bitnum |= (s2 >> 4) & 0x02;
+ bitnum |= (s2 >> 3) & 0x01;
+
+ dat[byteoffs] ^= (1 << bitnum);
+
+ return 1;
+ }
+
+ if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1)
+ return 1;
+
+ return -1;
+}
+