aboutsummaryrefslogtreecommitdiffstats
path: root/uart-monitor/lib/ecc_256.c
diff options
context:
space:
mode:
Diffstat (limited to 'uart-monitor/lib/ecc_256.c')
m---------uart-monitor0
-rw-r--r--uart-monitor/lib/ecc_256.c329
2 files changed, 329 insertions, 0 deletions
diff --git a/uart-monitor b/uart-monitor
deleted file mode 160000
-Subproject eb8b047c29a2027fbdd841cd1289fa27ddb22d7
diff --git a/uart-monitor/lib/ecc_256.c b/uart-monitor/lib/ecc_256.c
new file mode 100644
index 0000000..92c310f
--- /dev/null
+++ b/uart-monitor/lib/ecc_256.c
@@ -0,0 +1,329 @@
+/*
+ * (C) Copyright 2000 Texas Instruments
+ *
+ * This file os based on the following u-boot file:
+ * common/cmd_nand.c
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#ifndef CFG_SW_ECC_512
+
+/*
+ * Pre-calculated 256-way 1 byte column parity
+ */
+static const u_char nand_ecc_precalc_table[] = {
+ 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
+ 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+ 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+ 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+ 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+ 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+ 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+ 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+ 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+ 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+ 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+ 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+ 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+ 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+ 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+ 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
+};
+
+
+#ifdef NAND_LEGACY
+/*
+ * Creates non-inverted ECC code from line parity
+ */
+static void nand_trans_result(u_char reg2, u_char reg3,
+ u_char *ecc_code)
+{
+ u_char a, b, i, tmp1, tmp2;
+
+ /* Initialize variables */
+ a = b = 0x80;
+ tmp1 = tmp2 = 0;
+
+ /* Calculate first ECC byte */
+ for (i = 0; i < 4; i++) {
+ if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */
+ tmp1 |= b;
+ b >>= 1;
+ if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */
+ tmp1 |= b;
+ b >>= 1;
+ a >>= 1;
+ }
+
+ /* Calculate second ECC byte */
+ b = 0x80;
+ for (i = 0; i < 4; i++) {
+ if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */
+ tmp2 |= b;
+ b >>= 1;
+ if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */
+ tmp2 |= b;
+ b >>= 1;
+ a >>= 1;
+ }
+
+ /* Store two of the ECC bytes */
+ ecc_code[0] = tmp1;
+ ecc_code[1] = tmp2;
+}
+
+/*
+ * Calculate 3 byte ECC code for 256 byte block
+ */
+/* ECC Calculation is different between NAND and NAND Legacy code
+ * in U-Boot. If NAND_LEGACY is enabled in u-boot it should be
+ * enabled in the config file in x-loader also
+ */
+void nand_calculate_ecc (const u_char *dat, u_char *ecc_code)
+{
+ u_char idx, reg1, reg3;
+ int j;
+
+ /* Initialize variables */
+ reg1 = reg3 = 0;
+ ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
+
+ /* Build up column parity */
+ for(j = 0; j < 256; j++) {
+
+ /* Get CP0 - CP5 from table */
+ idx = nand_ecc_precalc_table[dat[j]];
+ reg1 ^= idx;
+
+ /* All bit XOR = 1 ? */
+ if (idx & 0x40) {
+ reg3 ^= (u_char) j;
+
+ }
+ }
+
+ /* Create non-inverted ECC code from line parity */
+ nand_trans_result((reg1 & 0x40) ? ~reg3 : reg3, reg3, ecc_code);
+
+ /* Calculate final ECC code */
+ ecc_code[0] = ~ecc_code[0];
+ ecc_code[1] = ~ecc_code[1];
+ ecc_code[2] = ((~reg1) << 2) | 0x03;
+}
+
+/*
+ * Detect and correct a 1 bit error for 256 byte block
+ */
+int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc)
+{
+ u_char a, b, c, d1, d2, d3, add, bit, i;
+
+ /* Do error detection */
+ d1 = calc_ecc[0] ^ read_ecc[0];
+ d2 = calc_ecc[1] ^ read_ecc[1];
+ d3 = calc_ecc[2] ^ read_ecc[2];
+
+ if ((d1 | d2 | d3) == 0) {
+ /* No errors */
+ return 0;
+ }
+ else {
+ a = (d1 ^ (d1 >> 1)) & 0x55;
+ b = (d2 ^ (d2 >> 1)) & 0x55;
+ c = (d3 ^ (d3 >> 1)) & 0x54;
+
+ /* Found and will correct single bit error in the data */
+ if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
+ c = 0x80;
+ add = 0;
+ a = 0x80;
+ for (i=0; i<4; i++) {
+ if (d1 & c)
+ add |= a;
+ c >>= 2;
+ a >>= 1;
+ }
+ c = 0x80;
+ for (i=0; i<4; i++) {
+ if (d2 & c)
+ add |= a;
+ c >>= 2;
+ a >>= 1;
+ }
+ bit = 0;
+ b = 0x04;
+ c = 0x80;
+ for (i=0; i<3; i++) {
+ if (d3 & c)
+ bit |= b;
+ c >>= 2;
+ b >>= 1;
+ }
+ b = 0x01;
+ a = dat[add];
+ a ^= (b << bit);
+ dat[add] = a;
+ return 1;
+ }
+ else {
+ i = 0;
+ while (d1) {
+ if (d1 & 0x01)
+ ++i;
+ d1 >>= 1;
+ }
+ while (d2) {
+ if (d2 & 0x01)
+ ++i;
+ d2 >>= 1;
+ }
+ while (d3) {
+ if (d3 & 0x01)
+ ++i;
+ d3 >>= 1;
+ }
+ if (i == 1) {
+ /* ECC Code Error Correction */
+ read_ecc[0] = calc_ecc[0];
+ read_ecc[1] = calc_ecc[1];
+ read_ecc[2] = calc_ecc[2];
+ return 2;
+ }
+ else {
+ /* Uncorrectable Error */
+ return -1;
+ }
+ }
+ }
+
+ /* Should never happen */
+ return -1;
+}
+#else /* not NAND_LEGACY */
+void nand_calculate_ecc(const u_char *dat, u_char *ecc_code)
+{
+ uint8_t idx, reg1, reg2, reg3, tmp1, tmp2;
+ int i;
+
+ /* Initialize variables */
+ reg1 = reg2 = reg3 = 0;
+
+ /* Build up column parity */
+ for(i = 0; i < 256; i++) {
+ /* Get CP0 - CP5 from table */
+ idx = nand_ecc_precalc_table[*dat++];
+ reg1 ^= (idx & 0x3f);
+
+ /* All bit XOR = 1 ? */
+ if (idx & 0x40) {
+ reg3 ^= (uint8_t) i;
+ reg2 ^= ~((uint8_t) i);
+ }
+ }
+
+ /* Create non-inverted ECC code from line parity */
+ tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */
+ tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */
+ tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */
+ tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */
+ tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */
+ tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */
+ tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */
+ tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */
+
+ tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */
+ tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */
+ tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */
+ tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */
+ tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */
+ tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */
+ tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */
+ tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */
+
+ /* Calculate final ECC code */
+ ecc_code[0] = ~tmp1;
+ ecc_code[1] = ~tmp2;
+ ecc_code[2] = ((~reg1) << 2) | 0x03;
+}
+
+static inline int countbits(uint32_t byte)
+{
+ int res = 0;
+
+ for (;byte; byte >>= 1)
+ res += byte & 0x01;
+ return res;
+}
+
+/*
+ * nand_correct_data - [NAND Interface] Detect and correct bit error(s)
+ * @mtd: MTD block structure
+ * @dat: raw data read from the chip
+ * @read_ecc: ECC from the chip
+ * @calc_ecc: the ECC calculated from raw data
+ *
+ * Detect and correct a 1 bit error for 256 byte block
+ */
+int nand_correct_data(u_char *dat, u_char *read_ecc, u_char *calc_ecc)
+{
+ uint8_t s0, s1, s2;
+
+ s0 = calc_ecc[0] ^ read_ecc[0];
+ s1 = calc_ecc[1] ^ read_ecc[1];
+ s2 = calc_ecc[2] ^ read_ecc[2];
+
+ if ((s0 | s1 | s2) == 0)
+ return 0;
+
+/* 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;
+}
+#endif /* NAND_LEGACY */
+#endif /* ! CFG_SW_ECC_512 */