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