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 ****************************************************************************/
nand_bcm_umi_bch_ecc_flip_bit(uint8_t * datap,int errorLocation)45 static 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 ****************************************************************************/
nand_bcm_umi_bch_correct_page(uint8_t * datap,uint8_t * readEccData,int numEccBytes)95 int 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