Logo Search packages:      
Sourcecode: x-loader version File versions  Download package

ecc.c

/*
 * (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>

/*
 * 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
};


/*
 * 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 
 */
#ifdef NAND_LEGACY
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;
}
#else
void nand_calculate_ecc (const u_char *dat, u_char *ecc_code)
{
      u_char idx, reg1, reg2, reg3;
      int j;

      /* Initialize variables */
      reg1 = reg2 = 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 & 0x3f);

            /* All bit XOR = 1 ? */
            if (idx & 0x40) {
                  reg3 ^= (u_char) j;
                  reg2 ^= ~((u_char) j);
            }
      }

      /* Create non-inverted ECC code from line parity */
      nand_trans_result(reg2, 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;
}
#endif
/*
 * 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;
}


Generated by  Doxygen 1.6.0   Back to index