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 * SPDX-License-Identifier:     GPL-2.0+
  13 *
  14 * As a special exception, if other files instantiate templates or use
  15 * macros or inline functions from these files, or you compile these
  16 * files and link them with other works to produce a work based on these
  17 * files, these files do not by themselves cause the resulting work to be
  18 * covered by the GNU General Public License. However the source code for
  19 * these files must still be made available in accordance with section (3)
  20 * of the GNU General Public License.
  21 *
  22 * This exception does not invalidate any other reasons why a work based on
  23 * this file might be covered by the GNU General Public License.
  24 */
  25
  26#include <common.h>
  27
  28#include <asm/errno.h>
  29#include <linux/mtd/mtd.h>
  30#include <linux/mtd/nand_ecc.h>
  31
  32/* The PPC4xx NDFC uses Smart Media (SMC) bytes order */
  33#ifdef CONFIG_NAND_NDFC
  34#define CONFIG_MTD_NAND_ECC_SMC
  35#endif
  36
  37/*
  38 * NAND-SPL has no sofware ECC for now, so don't include nand_calculate_ecc(),
  39 * only nand_correct_data() is needed
  40 */
  41
  42#if !defined(CONFIG_NAND_SPL) || defined(CONFIG_SPL_NAND_SOFTECC)
  43/*
  44 * Pre-calculated 256-way 1 byte column parity
  45 */
  46static 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
  63};
  64
  65/**
  66 * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block
  67 * @mtd:        MTD block structure
  68 * @dat:        raw data
  69 * @ecc_code:   buffer for ECC
  70 */
  71int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
  72                       u_char *ecc_code)
  73{
  74        uint8_t idx, reg1, reg2, reg3, tmp1, tmp2;
  75        int i;
  76
  77        /* Initialize variables */
  78        reg1 = reg2 = reg3 = 0;
  79
  80        /* Build up column parity */
  81        for(i = 0; i < 256; i++) {
  82                /* Get CP0 - CP5 from table */
  83                idx = nand_ecc_precalc_table[*dat++];
  84                reg1 ^= (idx & 0x3f);
  85
  86                /* All bit XOR = 1 ? */
  87                if (idx & 0x40) {
  88                        reg3 ^= (uint8_t) i;
  89                        reg2 ^= ~((uint8_t) i);
  90                }
  91        }
  92
  93        /* Create non-inverted ECC code from line parity */
  94        tmp1  = (reg3 & 0x80) >> 0; /* B7 -> B7 */
  95        tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */
  96        tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */
  97        tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */
  98        tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */
  99        tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */
 100        tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */
 101        tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */
 102
 103        tmp2  = (reg3 & 0x08) << 4; /* B3 -> B7 */
 104        tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */
 105        tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */
 106        tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */
 107        tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */
 108        tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */
 109        tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */
 110        tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */
 111
 112        /* Calculate final ECC code */
 113#ifdef CONFIG_MTD_NAND_ECC_SMC
 114        ecc_code[0] = ~tmp2;
 115        ecc_code[1] = ~tmp1;
 116#else
 117        ecc_code[0] = ~tmp1;
 118        ecc_code[1] = ~tmp2;
 119#endif
 120        ecc_code[2] = ((~reg1) << 2) | 0x03;
 121
 122        return 0;
 123}
 124#endif /* CONFIG_NAND_SPL */
 125
 126static inline int countbits(uint32_t byte)
 127{
 128        int res = 0;
 129
 130        for (;byte; byte >>= 1)
 131                res += byte & 0x01;
 132        return res;
 133}
 134
 135/**
 136 * nand_correct_data - [NAND Interface] Detect and correct bit error(s)
 137 * @mtd:        MTD block structure
 138 * @dat:        raw data read from the chip
 139 * @read_ecc:   ECC from the chip
 140 * @calc_ecc:   the ECC calculated from raw data
 141 *
 142 * Detect and correct a 1 bit error for 256 byte block
 143 */
 144int nand_correct_data(struct mtd_info *mtd, u_char *dat,
 145                      u_char *read_ecc, u_char *calc_ecc)
 146{
 147        uint8_t s0, s1, s2;
 148
 149#ifdef CONFIG_MTD_NAND_ECC_SMC
 150        s0 = calc_ecc[0] ^ read_ecc[0];
 151        s1 = calc_ecc[1] ^ read_ecc[1];
 152        s2 = calc_ecc[2] ^ read_ecc[2];
 153#else
 154        s1 = calc_ecc[0] ^ read_ecc[0];
 155        s0 = calc_ecc[1] ^ read_ecc[1];
 156        s2 = calc_ecc[2] ^ read_ecc[2];
 157#endif
 158        if ((s0 | s1 | s2) == 0)
 159                return 0;
 160
 161        /* Check for a single bit error */
 162        if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 &&
 163            ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 &&
 164            ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) {
 165
 166                uint32_t byteoffs, bitnum;
 167
 168                byteoffs = (s1 << 0) & 0x80;
 169                byteoffs |= (s1 << 1) & 0x40;
 170                byteoffs |= (s1 << 2) & 0x20;
 171                byteoffs |= (s1 << 3) & 0x10;
 172
 173                byteoffs |= (s0 >> 4) & 0x08;
 174                byteoffs |= (s0 >> 3) & 0x04;
 175                byteoffs |= (s0 >> 2) & 0x02;
 176                byteoffs |= (s0 >> 1) & 0x01;
 177
 178                bitnum = (s2 >> 5) & 0x04;
 179                bitnum |= (s2 >> 4) & 0x02;
 180                bitnum |= (s2 >> 3) & 0x01;
 181
 182                dat[byteoffs] ^= (1 << bitnum);
 183
 184                return 1;
 185        }
 186
 187        if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1)
 188                return 1;
 189
 190        return -EBADMSG;
 191}
 192