• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/mtd/nand/
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