linux/drivers/mtd/nand/nand_bcm_umi.c
<<
>>
Prefs
   1/*****************************************************************************
   2* Copyright 2004 - 2009 Broadcom Corporation.  All rights reserved.
   3*
   4* Unless you and Broadcom execute a separate written software license
   5* agreement governing use of this software, this software is licensed to you
   6* under the terms of the GNU General Public License version 2, available at
   7* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
   8*
   9* Notwithstanding the above, under no circumstances may you combine this
  10* software in any way with any other Broadcom software provided under a
  11* license other than the GPL, without Broadcom's express prior written
  12* consent.
  13*****************************************************************************/
  14
  15/* ---- Include Files ---------------------------------------------------- */
  16#include <mach/reg_umi.h>
  17#include "nand_bcm_umi.h"
  18#ifdef BOOT0_BUILD
  19#include <uart.h>
  20#endif
  21
  22/* ---- External Variable Declarations ----------------------------------- */
  23/* ---- External Function Prototypes ------------------------------------- */
  24/* ---- Public Variables ------------------------------------------------- */
  25/* ---- Private Constants and Types -------------------------------------- */
  26/* ---- Private Function Prototypes -------------------------------------- */
  27/* ---- Private Variables ------------------------------------------------ */
  28/* ---- Private Functions ------------------------------------------------ */
  29
  30#if NAND_ECC_BCH
  31/****************************************************************************
  32*  nand_bch_ecc_flip_bit - Routine to flip an errored bit
  33*
  34*  PURPOSE:
  35*     This is a helper routine that flips the bit (0 -> 1 or 1 -> 0) of the
  36*     errored bit specified
  37*
  38*  PARAMETERS:
  39*     datap - Container that holds the 512 byte data
  40*     errorLocation - Location of the bit that needs to be flipped
  41*
  42*  RETURNS:
  43*     None
  44****************************************************************************/
  45static void nand_bcm_umi_bch_ecc_flip_bit(uint8_t *datap, int errorLocation)
  46{
  47        int locWithinAByte = (errorLocation & REG_UMI_BCH_ERR_LOC_BYTE) >> 0;
  48        int locWithinAWord = (errorLocation & REG_UMI_BCH_ERR_LOC_WORD) >> 3;
  49        int locWithinAPage = (errorLocation & REG_UMI_BCH_ERR_LOC_PAGE) >> 5;
  50
  51        uint8_t errorByte = 0;
  52        uint8_t byteMask = 1 << locWithinAByte;
  53
  54        /* BCH uses big endian, need to change the location
  55         * bits to little endian */
  56        locWithinAWord = 3 - locWithinAWord;
  57
  58        errorByte = datap[locWithinAPage * sizeof(uint32_t) + locWithinAWord];
  59
  60#ifdef BOOT0_BUILD
  61        puthexs("\nECC Correct Offset: ",
  62                locWithinAPage * sizeof(uint32_t) + locWithinAWord);
  63        puthexs(" errorByte:", errorByte);
  64        puthex8(" Bit: ", locWithinAByte);
  65#endif
  66
  67        if (errorByte & byteMask) {
  68                /* bit needs to be cleared */
  69                errorByte &= ~byteMask;
  70        } else {
  71                /* bit needs to be set */
  72                errorByte |= byteMask;
  73        }
  74
  75        /* write back the value with the fixed bit */
  76        datap[locWithinAPage * sizeof(uint32_t) + locWithinAWord] = errorByte;
  77}
  78
  79/****************************************************************************
  80*  nand_correct_page_bch - Routine to correct bit errors when reading NAND
  81*
  82*  PURPOSE:
  83*     This routine reads the BCH registers to determine if there are any bit
  84*     errors during the read of the last 512 bytes of data + ECC bytes.  If
  85*     errors exists, the routine fixes it.
  86*
  87*  PARAMETERS:
  88*     datap - Container that holds the 512 byte data
  89*
  90*  RETURNS:
  91*     0 or greater = Number of errors corrected
  92*                    (No errors are found or errors have been fixed)
  93*    -1 = Error(s) cannot be fixed
  94****************************************************************************/
  95int nand_bcm_umi_bch_correct_page(uint8_t *datap, uint8_t *readEccData,
  96                                  int numEccBytes)
  97{
  98        int numErrors;
  99        int errorLocation;
 100        int idx;
 101        uint32_t regValue;
 102
 103        /* wait for read ECC to be valid */
 104        regValue = nand_bcm_umi_bch_poll_read_ecc_calc();
 105
 106        /*
 107         * read the control status register to determine if there
 108         * are error'ed bits
 109         * see if errors are correctible
 110         */
 111        if ((regValue & REG_UMI_BCH_CTRL_STATUS_UNCORR_ERR) > 0) {
 112                int i;
 113
 114                for (i = 0; i < numEccBytes; i++) {
 115                        if (readEccData[i] != 0xff) {
 116                                /* errors cannot be fixed, return -1 */
 117                                return -1;
 118                        }
 119                }
 120                /* If ECC is unprogrammed then we can't correct,
 121                 * assume everything OK */
 122                return 0;
 123        }
 124
 125        if ((regValue & REG_UMI_BCH_CTRL_STATUS_CORR_ERR) == 0) {
 126                /* no errors */
 127                return 0;
 128        }
 129
 130        /*
 131         * Fix errored bits by doing the following:
 132         * 1. Read the number of errors in the control and status register
 133         * 2. Read the error location registers that corresponds to the number
 134         *    of errors reported
 135         * 3. Invert the bit in the data
 136         */
 137        numErrors = (regValue & REG_UMI_BCH_CTRL_STATUS_NB_CORR_ERROR) >> 20;
 138
 139        for (idx = 0; idx < numErrors; idx++) {
 140                errorLocation =
 141                    REG_UMI_BCH_ERR_LOC_ADDR(idx) & REG_UMI_BCH_ERR_LOC_MASK;
 142
 143                /* Flip bit */
 144                nand_bcm_umi_bch_ecc_flip_bit(datap, errorLocation);
 145        }
 146        /* Errors corrected */
 147        return numErrors;
 148}
 149#endif
 150