2  * This file contains an ECC algorithm from Toshiba that detects and
 
   3  * corrects 1 bit errors in a 256 byte block of data.
 
   5  * drivers/mtd/nand/nand_ecc.c
 
   7  * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com)
 
   8  *                         Toshiba America Electronics Components, Inc.
 
  10  * $Id: nand_ecc.c,v 1.15 2005/11/07 11:14:30 gleixner Exp $
 
  12  * This file is free software; you can redistribute it and/or modify it
 
  13  * under the terms of the GNU General Public License as published by the
 
  14  * Free Software Foundation; either version 2 or (at your option) any
 
  17  * This file is distributed in the hope that it will be useful, but WITHOUT
 
  18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
  19  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 
  22  * You should have received a copy of the GNU General Public License along
 
  23  * with this file; if not, write to the Free Software Foundation, Inc.,
 
  24  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 
  26  * As a special exception, if other files instantiate templates or use
 
  27  * macros or inline functions from these files, or you compile these
 
  28  * files and link them with other works to produce a work based on these
 
  29  * files, these files do not by themselves cause the resulting work to be
 
  30  * covered by the GNU General Public License. However the source code for
 
  31  * these files must still be made available in accordance with section (3)
 
  32  * of the GNU General Public License.
 
  34  * This exception does not invalidate any other reasons why a work based on
 
  35  * this file might be covered by the GNU General Public License.
 
  38 #include <linux/types.h>
 
  39 #include <linux/kernel.h>
 
  40 #include <linux/module.h>
 
  41 #include <linux/mtd/nand_ecc.h>
 
  44  * Pre-calculated 256-way 1 byte column parity
 
  46 static const u_char nand_ecc_precalc_table[] = {
 
  47         0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
 
  48         0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
 
  49         0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
 
  50         0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
 
  51         0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
 
  52         0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
 
  53         0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
 
  54         0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
 
  55         0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
 
  56         0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
 
  57         0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
 
  58         0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
 
  59         0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
 
  60         0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
 
  61         0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
 
  62         0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
 
  67  * nand_trans_result - [GENERIC] create non-inverted ECC
 
  68  * @reg2:       line parity reg 2
 
  69  * @reg3:       line parity reg 3
 
  72  * Creates non-inverted ECC code from line parity
 
  74 static void nand_trans_result(u_char reg2, u_char reg3,
 
  77         u_char a, b, i, tmp1, tmp2;
 
  79         /* Initialize variables */
 
  83         /* Calculate first ECC byte */
 
  84         for (i = 0; i < 4; i++) {
 
  85                 if (reg3 & a)           /* LP15,13,11,9 --> ecc_code[0] */
 
  88                 if (reg2 & a)           /* LP14,12,10,8 --> ecc_code[0] */
 
  94         /* Calculate second ECC byte */
 
  96         for (i = 0; i < 4; i++) {
 
  97                 if (reg3 & a)           /* LP7,5,3,1 --> ecc_code[1] */
 
 100                 if (reg2 & a)           /* LP6,4,2,0 --> ecc_code[1] */
 
 106         /* Store two of the ECC bytes */
 
 112  * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code for 256 byte block
 
 113  * @mtd:        MTD block structure
 
 115  * @ecc_code:   buffer for ECC
 
 117 int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
 
 119         u_char idx, reg1, reg2, reg3;
 
 122         /* Initialize variables */
 
 123         reg1 = reg2 = reg3 = 0;
 
 124         ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
 
 126         /* Build up column parity */
 
 127         for(j = 0; j < 256; j++) {
 
 129                 /* Get CP0 - CP5 from table */
 
 130                 idx = nand_ecc_precalc_table[dat[j]];
 
 131                 reg1 ^= (idx & 0x3f);
 
 133                 /* All bit XOR = 1 ? */
 
 136                         reg2 ^= ~((u_char) j);
 
 140         /* Create non-inverted ECC code from line parity */
 
 141         nand_trans_result(reg2, reg3, ecc_code);
 
 143         /* Calculate final ECC code */
 
 144         ecc_code[0] = ~ecc_code[0];
 
 145         ecc_code[1] = ~ecc_code[1];
 
 146         ecc_code[2] = ((~reg1) << 2) | 0x03;
 
 151  * nand_correct_data - [NAND Interface] Detect and correct bit error(s)
 
 152  * @mtd:        MTD block structure
 
 153  * @dat:        raw data read from the chip
 
 154  * @read_ecc:   ECC from the chip
 
 155  * @calc_ecc:   the ECC calculated from raw data
 
 157  * Detect and correct a 1 bit error for 256 byte block
 
 159 int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
 
 161         u_char a, b, c, d1, d2, d3, add, bit, i;
 
 163         /* Do error detection */
 
 164         d1 = calc_ecc[0] ^ read_ecc[0];
 
 165         d2 = calc_ecc[1] ^ read_ecc[1];
 
 166         d3 = calc_ecc[2] ^ read_ecc[2];
 
 168         if ((d1 | d2 | d3) == 0) {
 
 173                 a = (d1 ^ (d1 >> 1)) & 0x55;
 
 174                 b = (d2 ^ (d2 >> 1)) & 0x55;
 
 175                 c = (d3 ^ (d3 >> 1)) & 0x54;
 
 177                 /* Found and will correct single bit error in the data */
 
 178                 if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
 
 182                         for (i=0; i<4; i++) {
 
 189                         for (i=0; i<4; i++) {
 
 198                         for (i=0; i<3; i++) {
 
 228                                 /* ECC Code Error Correction */
 
 229                                 read_ecc[0] = calc_ecc[0];
 
 230                                 read_ecc[1] = calc_ecc[1];
 
 231                                 read_ecc[2] = calc_ecc[2];
 
 235                                 /* Uncorrectable Error */
 
 241         /* Should never happen */
 
 245 EXPORT_SYMBOL(nand_calculate_ecc);
 
 246 EXPORT_SYMBOL(nand_correct_data);
 
 248 MODULE_LICENSE("GPL");
 
 249 MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>");
 
 250 MODULE_DESCRIPTION("Generic NAND ECC support");