Commit | Line | Data |
---|---|---|
266dead2 LHC |
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 | ****************************************************************************/ | |
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 | ****************************************************************************/ | |
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 |