os/nandboot-R2_0_4/mtd/nand_ecc.c

Go to the documentation of this file.
00001 /*
00002  * Taken from  drivers/mtd/nand/nand_ecc.c, from Linux 2.6.16 (IR2_6_16-9)
00003  * Modified to run outside Linux.
00004  * #if 0'd to remove non-essential functionality
00005  *
00006  * This file contains an ECC algorithm from Toshiba that detects and
00007  * corrects 1 bit errors in a 256 byte block of data.
00008  *
00009  * drivers/mtd/nand/nand_ecc.c
00010  *
00011  * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com)
00012  *                         Toshiba America Electronics Components, Inc.
00013  *
00014  * $Id: nand_ecc.c,v 1.1.1.1 2008/11/27 20:04:00 elphel Exp $
00015  *
00016  * This file is free software; you can redistribute it and/or modify it
00017  * under the terms of the GNU General Public License as published by the
00018  * Free Software Foundation; either version 2 or (at your option) any
00019  * later version.
00020  *
00021  * This file is distributed in the hope that it will be useful, but WITHOUT
00022  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00023  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00024  * for more details.
00025  *
00026  * You should have received a copy of the GNU General Public License along
00027  * with this file; if not, write to the Free Software Foundation, Inc.,
00028  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00029  *
00030  * As a special exception, if other files instantiate templates or use
00031  * macros or inline functions from these files, or you compile these
00032  * files and link them with other works to produce a work based on these
00033  * files, these files do not by themselves cause the resulting work to be
00034  * covered by the GNU General Public License. However the source code for
00035  * these files must still be made available in accordance with section (3)
00036  * of the GNU General Public License.
00037  *
00038  * This exception does not invalidate any other reasons why a work based on
00039  * this file might be covered by the GNU General Public License.
00040  */
00041 
00042 #include <linux/types.h>
00043 #if 0
00044 #include <linux/kernel.h>
00045 #include <linux/module.h>
00046 #include <linux/mtd/nand_ecc.h>
00047 #endif
00048 
00049 #include "nand_ecc.h"
00050 
00051 /*
00052  * Pre-calculated 256-way 1 byte column parity
00053  */
00054 static const u_char nand_ecc_precalc_table[] = {
00055         0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
00056         0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
00057         0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
00058         0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
00059         0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
00060         0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
00061         0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
00062         0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
00063         0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
00064         0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
00065         0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
00066         0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
00067         0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
00068         0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
00069         0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
00070         0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
00071 };
00072 
00073 
00082 static void nand_trans_result(u_char reg2, u_char reg3,
00083         u_char *ecc_code)
00084 {
00085         u_char a, b, i, tmp1, tmp2;
00086 
00087         /* Initialize variables */
00088         a = b = 0x80;
00089         tmp1 = tmp2 = 0;
00090 
00091         /* Calculate first ECC byte */
00092         for (i = 0; i < 4; i++) {
00093                 if (reg3 & a)           /* LP15,13,11,9 --> ecc_code[0] */
00094                         tmp1 |= b;
00095                 b >>= 1;
00096                 if (reg2 & a)           /* LP14,12,10,8 --> ecc_code[0] */
00097                         tmp1 |= b;
00098                 b >>= 1;
00099                 a >>= 1;
00100         }
00101 
00102         /* Calculate second ECC byte */
00103         b = 0x80;
00104         for (i = 0; i < 4; i++) {
00105                 if (reg3 & a)           /* LP7,5,3,1 --> ecc_code[1] */
00106                         tmp2 |= b;
00107                 b >>= 1;
00108                 if (reg2 & a)           /* LP6,4,2,0 --> ecc_code[1] */
00109                         tmp2 |= b;
00110                 b >>= 1;
00111                 a >>= 1;
00112         }
00113 
00114         /* Store two of the ECC bytes */
00115         ecc_code[0] = tmp1;
00116         ecc_code[1] = tmp2;
00117 }
00118 
00125 int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
00126 {
00127         u_char idx, reg1, reg2, reg3;
00128         int j;
00129 
00130         /* Initialize variables */
00131         reg1 = reg2 = reg3 = 0;
00132         ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
00133 
00134         /* Build up column parity */
00135         for(j = 0; j < 256; j++) {
00136 
00137                 /* Get CP0 - CP5 from table */
00138                 idx = nand_ecc_precalc_table[dat[j]];
00139                 reg1 ^= (idx & 0x3f);
00140 
00141                 /* All bit XOR = 1 ? */
00142                 if (idx & 0x40) {
00143                         reg3 ^= (u_char) j;
00144                         reg2 ^= ~((u_char) j);
00145                 }
00146         }
00147 
00148         /* Create non-inverted ECC code from line parity */
00149         nand_trans_result(reg2, reg3, ecc_code);
00150 
00151         /* Calculate final ECC code */
00152         ecc_code[0] = ~ecc_code[0];
00153         ecc_code[1] = ~ecc_code[1];
00154         ecc_code[2] = ((~reg1) << 2) | 0x03;
00155         return 0;
00156 }
00157 
00167 int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
00168 {
00169         u_char a, b, c, d1, d2, d3, add, bit, i;
00170 
00171         /* Do error detection */
00172         d1 = calc_ecc[0] ^ read_ecc[0];
00173         d2 = calc_ecc[1] ^ read_ecc[1];
00174         d3 = calc_ecc[2] ^ read_ecc[2];
00175 
00176         if ((d1 | d2 | d3) == 0) {
00177                 /* No errors */
00178                 return 0;
00179         }
00180         else {
00181                 a = (d1 ^ (d1 >> 1)) & 0x55;
00182                 b = (d2 ^ (d2 >> 1)) & 0x55;
00183                 c = (d3 ^ (d3 >> 1)) & 0x54;
00184 
00185                 /* Found and will correct single bit error in the data */
00186                 if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
00187                         c = 0x80;
00188                         add = 0;
00189                         a = 0x80;
00190                         for (i=0; i<4; i++) {
00191                                 if (d1 & c)
00192                                         add |= a;
00193                                 c >>= 2;
00194                                 a >>= 1;
00195                         }
00196                         c = 0x80;
00197                         for (i=0; i<4; i++) {
00198                                 if (d2 & c)
00199                                         add |= a;
00200                                 c >>= 2;
00201                                 a >>= 1;
00202                         }
00203                         bit = 0;
00204                         b = 0x04;
00205                         c = 0x80;
00206                         for (i=0; i<3; i++) {
00207                                 if (d3 & c)
00208                                         bit |= b;
00209                                 c >>= 2;
00210                                 b >>= 1;
00211                         }
00212                         b = 0x01;
00213                         a = dat[add];
00214                         a ^= (b << bit);
00215                         dat[add] = a;
00216                         return 1;
00217                 }
00218                 else {
00219                         i = 0;
00220                         while (d1) {
00221                                 if (d1 & 0x01)
00222                                         ++i;
00223                                 d1 >>= 1;
00224                         }
00225                         while (d2) {
00226                                 if (d2 & 0x01)
00227                                         ++i;
00228                                 d2 >>= 1;
00229                         }
00230                         while (d3) {
00231                                 if (d3 & 0x01)
00232                                         ++i;
00233                                 d3 >>= 1;
00234                         }
00235                         if (i == 1) {
00236                                 /* ECC Code Error Correction */
00237                                 read_ecc[0] = calc_ecc[0];
00238                                 read_ecc[1] = calc_ecc[1];
00239                                 read_ecc[2] = calc_ecc[2];
00240                                 return 2;
00241                         }
00242                         else {
00243                                 /* Uncorrectable Error */
00244                                 return -1;
00245                         }
00246                 }
00247         }
00248 
00249         /* Should never happen */
00250         return -1;
00251 }
00252 
00253 EXPORT_SYMBOL(nand_calculate_ecc);
00254 EXPORT_SYMBOL(nand_correct_data);
00255 
00256 MODULE_LICENSE("GPL");
00257 MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>");
00258 MODULE_DESCRIPTION("Generic NAND ECC support");

Generated on Fri Nov 28 00:06:24 2008 for elphel by  doxygen 1.5.1