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