uboot/drivers/mtd/nand/nand_ecc.c
<<
>>
Prefs
   1/*
   2 * This file contains an ECC algorithm from Toshiba that detects and
   3 * corrects 1 bit errors in a 256 byte block of data.
   4 *
   5 * drivers/mtd/nand/nand_ecc.c
   6 *
   7 * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com)
   8 *                         Toshiba America Electronics Components, Inc.
   9 *
  10 * Copyright (C) 2006 Thomas Gleixner <tglx@linutronix.de>
  11 *
  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
  15 * later version.
  16 *
  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
  20 * for more details.
  21 *
  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.
  25 *
  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.
  33 *
  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.
  36 */
  37
  38#include <common.h>
  39
  40#include <asm/errno.h>
  41#include <linux/mtd/mtd.h>
  42
  43/* The PPC4xx NDFC uses Smart Media (SMC) bytes order */
  44#ifdef CONFIG_NAND_NDFC
  45#define CONFIG_MTD_NAND_ECC_SMC
  46#endif
  47
  48/*
  49 * NAND-SPL has no sofware ECC for now, so don't include nand_calculate_ecc(),
  50 * only nand_correct_data() is needed
  51 */
  52
  53#if !defined(CONFIG_NAND_SPL) || defined(CONFIG_SPL_NAND_SOFTECC)
  54/*
  55 * Pre-calculated 256-way 1 byte column parity
  56 */
  57static const u_char nand_ecc_precalc_table[] = {
  58        0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
  59        0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
  60        0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
  61        0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
  62        0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
  63        0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
  64        0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
  65        0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
  66        0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
  67        0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
  68        0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
  69        0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
  70        0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
  71        0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
  72        0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
  73        0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
  74};
  75
  76/**
  77 * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block
  78 * @mtd:        MTD block structure
  79 * @dat:        raw data
  80 * @ecc_code:   buffer for ECC
  81 */
  82int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
  83                       u_char *ecc_code)
  84{
  85        uint8_t idx, reg1, reg2, reg3, tmp1, tmp2;
  86        int i;
  87
  88        /* Initialize variables */
  89        reg1 = reg2 = reg3 = 0;
  90
  91        /* Build up column parity */
  92        for(i = 0; i < 256; i++) {
  93                /* Get CP0 - CP5 from table */
  94                idx = nand_ecc_precalc_table[*dat++];
  95                reg1 ^= (idx & 0x3f);
  96
  97                /* All bit XOR = 1 ? */
  98                if (idx & 0x40) {
  99                        reg3 ^= (uint8_t) i;
 100                        reg2 ^= ~((uint8_t) i);
 101                }
 102        }
 103
 104        /* Create non-inverted ECC code from line parity */
 105        tmp1  = (reg3 & 0x80) >> 0; /* B7 -> B7 */
 106        tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */
 107        tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */
 108        tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */
 109        tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */
 110        tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */
 111        tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */
 112        tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */
 113
 114        tmp2  = (reg3 & 0x08) << 4; /* B3 -> B7 */
 115        tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */
 116        tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */
 117        tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */
 118        tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */
 119        tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */
 120        tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */
 121        tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */
 122
 123        /* Calculate final ECC code */
 124#ifdef CONFIG_MTD_NAND_ECC_SMC
 125        ecc_code[0] = ~tmp2;
 126        ecc_code[1] = ~tmp1;
 127#else
 128        ecc_code[0] = ~tmp1;
 129        ecc_code[1] = ~tmp2;
 130#endif
 131        ecc_code[2] = ((~reg1) << 2) | 0x03;
 132
 133        return 0;
 134}
 135#endif /* CONFIG_NAND_SPL */
 136
 137static inline int countbits(uint32_t byte)
 138{
 139        int res = 0;
 140
 141        for (;byte; byte >>= 1)
 142                res += byte & 0x01;
 143        return res;
 144}
 145
 146/**
 147 * nand_correct_data - [NAND Interface] Detect and correct bit error(s)
 148 * @mtd:        MTD block structure
 149 * @dat:        raw data read from the chip
 150 * @read_ecc:   ECC from the chip
 151 * @calc_ecc:   the ECC calculated from raw data
 152 *
 153 * Detect and correct a 1 bit error for 256 byte block
 154 */
 155int nand_correct_data(struct mtd_info *mtd, u_char *dat,
 156                      u_char *read_ecc, u_char *calc_ecc)
 157{
 158        uint8_t s0, s1, s2;
 159
 160#ifdef CONFIG_MTD_NAND_ECC_SMC
 161        s0 = calc_ecc[0] ^ read_ecc[0];
 162        s1 = calc_ecc[1] ^ read_ecc[1];
 163        s2 = calc_ecc[2] ^ read_ecc[2];
 164#else
 165        s1 = calc_ecc[0] ^ read_ecc[0];
 166        s0 = calc_ecc[1] ^ read_ecc[1];
 167        s2 = calc_ecc[2] ^ read_ecc[2];
 168#endif
 169        if ((s0 | s1 | s2) == 0)
 170                return 0;
 171
 172        /* Check for a single bit error */
 173        if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 &&
 174            ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 &&
 175            ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) {
 176
 177                uint32_t byteoffs, bitnum;
 178
 179                byteoffs = (s1 << 0) & 0x80;
 180                byteoffs |= (s1 << 1) & 0x40;
 181                byteoffs |= (s1 << 2) & 0x20;
 182                byteoffs |= (s1 << 3) & 0x10;
 183
 184                byteoffs |= (s0 >> 4) & 0x08;
 185                byteoffs |= (s0 >> 3) & 0x04;
 186                byteoffs |= (s0 >> 2) & 0x02;
 187                byteoffs |= (s0 >> 1) & 0x01;
 188
 189                bitnum = (s2 >> 5) & 0x04;
 190                bitnum |= (s2 >> 4) & 0x02;
 191                bitnum |= (s2 >> 3) & 0x01;
 192
 193                dat[byteoffs] ^= (1 << bitnum);
 194
 195                return 1;
 196        }
 197
 198        if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1)
 199                return 1;
 200
 201        return -EBADMSG;
 202}
 203