 266dead216
			
		
	
	
	266dead216
	
	
	
		
			
			Signed-off-by: Leo Hao Chen <leochen@broadcom.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
		
			
				
	
	
		
			149 lines
		
	
	
	
		
			4.9 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			149 lines
		
	
	
	
		
			4.9 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| /*****************************************************************************
 | |
| * Copyright 2004 - 2009 Broadcom Corporation.  All rights reserved.
 | |
| *
 | |
| * Unless you and Broadcom execute a separate written software license
 | |
| * agreement governing use of this software, this software is licensed to you
 | |
| * under the terms of the GNU General Public License version 2, available at
 | |
| * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
 | |
| *
 | |
| * Notwithstanding the above, under no circumstances may you combine this
 | |
| * software in any way with any other Broadcom software provided under a
 | |
| * license other than the GPL, without Broadcom's express prior written
 | |
| * consent.
 | |
| *****************************************************************************/
 | |
| 
 | |
| /* ---- Include Files ---------------------------------------------------- */
 | |
| #include <mach/reg_umi.h>
 | |
| #include "nand_bcm_umi.h"
 | |
| #ifdef BOOT0_BUILD
 | |
| #include <uart.h>
 | |
| #endif
 | |
| 
 | |
| /* ---- External Variable Declarations ----------------------------------- */
 | |
| /* ---- External Function Prototypes ------------------------------------- */
 | |
| /* ---- Public Variables ------------------------------------------------- */
 | |
| /* ---- Private Constants and Types -------------------------------------- */
 | |
| /* ---- Private Function Prototypes -------------------------------------- */
 | |
| /* ---- Private Variables ------------------------------------------------ */
 | |
| /* ---- Private Functions ------------------------------------------------ */
 | |
| 
 | |
| #if NAND_ECC_BCH
 | |
| /****************************************************************************
 | |
| *  nand_bch_ecc_flip_bit - Routine to flip an errored bit
 | |
| *
 | |
| *  PURPOSE:
 | |
| *     This is a helper routine that flips the bit (0 -> 1 or 1 -> 0) of the
 | |
| *     errored bit specified
 | |
| *
 | |
| *  PARAMETERS:
 | |
| *     datap - Container that holds the 512 byte data
 | |
| *     errorLocation - Location of the bit that needs to be flipped
 | |
| *
 | |
| *  RETURNS:
 | |
| *     None
 | |
| ****************************************************************************/
 | |
| static void nand_bcm_umi_bch_ecc_flip_bit(uint8_t *datap, int errorLocation)
 | |
| {
 | |
| 	int locWithinAByte = (errorLocation & REG_UMI_BCH_ERR_LOC_BYTE) >> 0;
 | |
| 	int locWithinAWord = (errorLocation & REG_UMI_BCH_ERR_LOC_WORD) >> 3;
 | |
| 	int locWithinAPage = (errorLocation & REG_UMI_BCH_ERR_LOC_PAGE) >> 5;
 | |
| 
 | |
| 	uint8_t errorByte = 0;
 | |
| 	uint8_t byteMask = 1 << locWithinAByte;
 | |
| 
 | |
| 	/* BCH uses big endian, need to change the location
 | |
| 	 * bits to little endian */
 | |
| 	locWithinAWord = 3 - locWithinAWord;
 | |
| 
 | |
| 	errorByte = datap[locWithinAPage * sizeof(uint32_t) + locWithinAWord];
 | |
| 
 | |
| #ifdef BOOT0_BUILD
 | |
| 	puthexs("\nECC Correct Offset: ",
 | |
| 		locWithinAPage * sizeof(uint32_t) + locWithinAWord);
 | |
| 	puthexs(" errorByte:", errorByte);
 | |
| 	puthex8(" Bit: ", locWithinAByte);
 | |
| #endif
 | |
| 
 | |
| 	if (errorByte & byteMask) {
 | |
| 		/* bit needs to be cleared */
 | |
| 		errorByte &= ~byteMask;
 | |
| 	} else {
 | |
| 		/* bit needs to be set */
 | |
| 		errorByte |= byteMask;
 | |
| 	}
 | |
| 
 | |
| 	/* write back the value with the fixed bit */
 | |
| 	datap[locWithinAPage * sizeof(uint32_t) + locWithinAWord] = errorByte;
 | |
| }
 | |
| 
 | |
| /****************************************************************************
 | |
| *  nand_correct_page_bch - Routine to correct bit errors when reading NAND
 | |
| *
 | |
| *  PURPOSE:
 | |
| *     This routine reads the BCH registers to determine if there are any bit
 | |
| *     errors during the read of the last 512 bytes of data + ECC bytes.  If
 | |
| *     errors exists, the routine fixes it.
 | |
| *
 | |
| *  PARAMETERS:
 | |
| *     datap - Container that holds the 512 byte data
 | |
| *
 | |
| *  RETURNS:
 | |
| *     0 or greater = Number of errors corrected
 | |
| *                    (No errors are found or errors have been fixed)
 | |
| *    -1 = Error(s) cannot be fixed
 | |
| ****************************************************************************/
 | |
| int nand_bcm_umi_bch_correct_page(uint8_t *datap, uint8_t *readEccData,
 | |
| 				  int numEccBytes)
 | |
| {
 | |
| 	int numErrors;
 | |
| 	int errorLocation;
 | |
| 	int idx;
 | |
| 	uint32_t regValue;
 | |
| 
 | |
| 	/* wait for read ECC to be valid */
 | |
| 	regValue = nand_bcm_umi_bch_poll_read_ecc_calc();
 | |
| 
 | |
| 	/*
 | |
| 	 * read the control status register to determine if there
 | |
| 	 * are error'ed bits
 | |
| 	 * see if errors are correctible
 | |
| 	 */
 | |
| 	if ((regValue & REG_UMI_BCH_CTRL_STATUS_UNCORR_ERR) > 0) {
 | |
| 		int i;
 | |
| 
 | |
| 		for (i = 0; i < numEccBytes; i++) {
 | |
| 			if (readEccData[i] != 0xff) {
 | |
| 				/* errors cannot be fixed, return -1 */
 | |
| 				return -1;
 | |
| 			}
 | |
| 		}
 | |
| 		/* If ECC is unprogrammed then we can't correct,
 | |
| 		 * assume everything OK */
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	if ((regValue & REG_UMI_BCH_CTRL_STATUS_CORR_ERR) == 0) {
 | |
| 		/* no errors */
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * Fix errored bits by doing the following:
 | |
| 	 * 1. Read the number of errors in the control and status register
 | |
| 	 * 2. Read the error location registers that corresponds to the number
 | |
| 	 *    of errors reported
 | |
| 	 * 3. Invert the bit in the data
 | |
| 	 */
 | |
| 	numErrors = (regValue & REG_UMI_BCH_CTRL_STATUS_NB_CORR_ERROR) >> 20;
 | |
| 
 | |
| 	for (idx = 0; idx < numErrors; idx++) {
 | |
| 		errorLocation =
 | |
| 		    REG_UMI_BCH_ERR_LOC_ADDR(idx) & REG_UMI_BCH_ERR_LOC_MASK;
 | |
| 
 | |
| 		/* Flip bit */
 | |
| 		nand_bcm_umi_bch_ecc_flip_bit(datap, errorLocation);
 | |
| 	}
 | |
| 	/* Errors corrected */
 | |
| 	return numErrors;
 | |
| }
 | |
| #endif
 |