Commit | Line | Data |
---|---|---|
266dead2 LHC |
1 | /***************************************************************************** |
2 | * Copyright 2003 - 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 | #ifndef NAND_BCM_UMI_H | |
15 | #define NAND_BCM_UMI_H | |
16 | ||
17 | /* ---- Include Files ---------------------------------------------------- */ | |
18 | #include <mach/reg_umi.h> | |
19 | #include <mach/reg_nand.h> | |
651ef18d | 20 | #include <mach/cfg_global.h> |
266dead2 LHC |
21 | |
22 | /* ---- Constants and Types ---------------------------------------------- */ | |
23 | #if (CFG_GLOBAL_CHIP_FAMILY == CFG_GLOBAL_CHIP_FAMILY_BCMRING) | |
24 | #define NAND_ECC_BCH (CFG_GLOBAL_CHIP_REV > 0xA0) | |
25 | #else | |
26 | #define NAND_ECC_BCH 0 | |
27 | #endif | |
28 | ||
29 | #define CFG_GLOBAL_NAND_ECC_BCH_NUM_BYTES 13 | |
30 | ||
31 | #if NAND_ECC_BCH | |
32 | #ifdef BOOT0_BUILD | |
33 | #define NAND_ECC_NUM_BYTES 13 | |
34 | #else | |
35 | #define NAND_ECC_NUM_BYTES CFG_GLOBAL_NAND_ECC_BCH_NUM_BYTES | |
36 | #endif | |
37 | #else | |
38 | #define NAND_ECC_NUM_BYTES 3 | |
39 | #endif | |
40 | ||
41 | #define NAND_DATA_ACCESS_SIZE 512 | |
42 | ||
43 | /* ---- Variable Externs ------------------------------------------ */ | |
44 | /* ---- Function Prototypes --------------------------------------- */ | |
45 | int nand_bcm_umi_bch_correct_page(uint8_t *datap, uint8_t *readEccData, | |
46 | int numEccBytes); | |
47 | ||
48 | /* Check in device is ready */ | |
49 | static inline int nand_bcm_umi_dev_ready(void) | |
50 | { | |
878040ef | 51 | return readl(®_UMI_NAND_RCSR) & REG_UMI_NAND_RCSR_RDY; |
266dead2 LHC |
52 | } |
53 | ||
54 | /* Wait until device is ready */ | |
55 | static inline void nand_bcm_umi_wait_till_ready(void) | |
56 | { | |
57 | while (nand_bcm_umi_dev_ready() == 0) | |
58 | ; | |
59 | } | |
60 | ||
61 | /* Enable Hamming ECC */ | |
62 | static inline void nand_bcm_umi_hamming_enable_hwecc(void) | |
63 | { | |
64 | /* disable and reset ECC, 512 byte page */ | |
878040ef AB |
65 | writel(readl(®_UMI_NAND_ECC_CSR) & ~(REG_UMI_NAND_ECC_CSR_ECC_ENABLE | |
66 | REG_UMI_NAND_ECC_CSR_256BYTE), ®_UMI_NAND_ECC_CSR); | |
266dead2 | 67 | /* enable ECC */ |
878040ef AB |
68 | writel(readl(®_UMI_NAND_ECC_CSR) | REG_UMI_NAND_ECC_CSR_ECC_ENABLE, |
69 | ®_UMI_NAND_ECC_CSR); | |
266dead2 LHC |
70 | } |
71 | ||
72 | #if NAND_ECC_BCH | |
73 | /* BCH ECC specifics */ | |
74 | #define ECC_BITS_PER_CORRECTABLE_BIT 13 | |
75 | ||
76 | /* Enable BCH Read ECC */ | |
77 | static inline void nand_bcm_umi_bch_enable_read_hwecc(void) | |
78 | { | |
79 | /* disable and reset ECC */ | |
878040ef | 80 | writel(REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID, ®_UMI_BCH_CTRL_STATUS); |
266dead2 | 81 | /* Turn on ECC */ |
878040ef | 82 | writel(REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN, ®_UMI_BCH_CTRL_STATUS); |
266dead2 LHC |
83 | } |
84 | ||
85 | /* Enable BCH Write ECC */ | |
86 | static inline void nand_bcm_umi_bch_enable_write_hwecc(void) | |
87 | { | |
88 | /* disable and reset ECC */ | |
878040ef | 89 | writel(REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID, ®_UMI_BCH_CTRL_STATUS); |
266dead2 | 90 | /* Turn on ECC */ |
878040ef | 91 | writel(REG_UMI_BCH_CTRL_STATUS_ECC_WR_EN, ®_UMI_BCH_CTRL_STATUS); |
266dead2 LHC |
92 | } |
93 | ||
94 | /* Config number of BCH ECC bytes */ | |
95 | static inline void nand_bcm_umi_bch_config_ecc(uint8_t numEccBytes) | |
96 | { | |
97 | uint32_t nValue; | |
98 | uint32_t tValue; | |
99 | uint32_t kValue; | |
100 | uint32_t numBits = numEccBytes * 8; | |
101 | ||
102 | /* disable and reset ECC */ | |
878040ef AB |
103 | writel(REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID | |
104 | REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID, | |
105 | ®_UMI_BCH_CTRL_STATUS); | |
266dead2 LHC |
106 | |
107 | /* Every correctible bit requires 13 ECC bits */ | |
108 | tValue = (uint32_t) (numBits / ECC_BITS_PER_CORRECTABLE_BIT); | |
109 | ||
110 | /* Total data in number of bits for generating and computing BCH ECC */ | |
111 | nValue = (NAND_DATA_ACCESS_SIZE + numEccBytes) * 8; | |
112 | ||
113 | /* K parameter is used internally. K = N - (T * 13) */ | |
114 | kValue = nValue - (tValue * ECC_BITS_PER_CORRECTABLE_BIT); | |
115 | ||
116 | /* Write the settings */ | |
878040ef AB |
117 | writel(nValue, ®_UMI_BCH_N); |
118 | writel(tValue, ®_UMI_BCH_T); | |
119 | writel(kValue, ®_UMI_BCH_K); | |
266dead2 LHC |
120 | } |
121 | ||
122 | /* Pause during ECC read calculation to skip bytes in OOB */ | |
123 | static inline void nand_bcm_umi_bch_pause_read_ecc_calc(void) | |
124 | { | |
878040ef | 125 | writel(REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN | REG_UMI_BCH_CTRL_STATUS_PAUSE_ECC_DEC, ®_UMI_BCH_CTRL_STATUS); |
266dead2 LHC |
126 | } |
127 | ||
128 | /* Resume during ECC read calculation after skipping bytes in OOB */ | |
129 | static inline void nand_bcm_umi_bch_resume_read_ecc_calc(void) | |
130 | { | |
878040ef | 131 | writel(REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN, ®_UMI_BCH_CTRL_STATUS); |
266dead2 LHC |
132 | } |
133 | ||
134 | /* Poll read ECC calc to check when hardware completes */ | |
135 | static inline uint32_t nand_bcm_umi_bch_poll_read_ecc_calc(void) | |
136 | { | |
137 | uint32_t regVal; | |
138 | ||
139 | do { | |
140 | /* wait for ECC to be valid */ | |
878040ef | 141 | regVal = readl(®_UMI_BCH_CTRL_STATUS); |
266dead2 LHC |
142 | } while ((regVal & REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID) == 0); |
143 | ||
144 | return regVal; | |
145 | } | |
146 | ||
147 | /* Poll write ECC calc to check when hardware completes */ | |
148 | static inline void nand_bcm_umi_bch_poll_write_ecc_calc(void) | |
149 | { | |
150 | /* wait for ECC to be valid */ | |
878040ef | 151 | while ((readl(®_UMI_BCH_CTRL_STATUS) & REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID) |
266dead2 LHC |
152 | == 0) |
153 | ; | |
154 | } | |
155 | ||
156 | /* Read the OOB and ECC, for kernel write OOB to a buffer */ | |
157 | #if defined(__KERNEL__) && !defined(STANDALONE) | |
158 | static inline void nand_bcm_umi_bch_read_oobEcc(uint32_t pageSize, | |
159 | uint8_t *eccCalc, int numEccBytes, uint8_t *oobp) | |
160 | #else | |
161 | static inline void nand_bcm_umi_bch_read_oobEcc(uint32_t pageSize, | |
162 | uint8_t *eccCalc, int numEccBytes) | |
163 | #endif | |
164 | { | |
165 | int eccPos = 0; | |
166 | int numToRead = 16; /* There are 16 bytes per sector in the OOB */ | |
167 | ||
168 | /* ECC is already paused when this function is called */ | |
1385858e RK |
169 | if (pageSize != NAND_DATA_ACCESS_SIZE) { |
170 | /* skip BI */ | |
171 | #if defined(__KERNEL__) && !defined(STANDALONE) | |
878040ef | 172 | *oobp++ = readb(®_NAND_DATA8); |
1385858e | 173 | #else |
878040ef | 174 | readb(®_NAND_DATA8); |
1385858e RK |
175 | #endif |
176 | numToRead--; | |
177 | } | |
266dead2 | 178 | |
1385858e RK |
179 | while (numToRead > numEccBytes) { |
180 | /* skip free oob region */ | |
266dead2 | 181 | #if defined(__KERNEL__) && !defined(STANDALONE) |
878040ef | 182 | *oobp++ = readb(®_NAND_DATA8); |
266dead2 | 183 | #else |
878040ef | 184 | readb(®_NAND_DATA8); |
266dead2 | 185 | #endif |
1385858e RK |
186 | numToRead--; |
187 | } | |
266dead2 | 188 | |
1385858e | 189 | if (pageSize == NAND_DATA_ACCESS_SIZE) { |
266dead2 LHC |
190 | /* read ECC bytes before BI */ |
191 | nand_bcm_umi_bch_resume_read_ecc_calc(); | |
192 | ||
193 | while (numToRead > 11) { | |
194 | #if defined(__KERNEL__) && !defined(STANDALONE) | |
878040ef | 195 | *oobp = readb(®_NAND_DATA8); |
266dead2 LHC |
196 | eccCalc[eccPos++] = *oobp; |
197 | oobp++; | |
198 | #else | |
878040ef | 199 | eccCalc[eccPos++] = readb(®_NAND_DATA8); |
266dead2 | 200 | #endif |
1385858e | 201 | numToRead--; |
266dead2 LHC |
202 | } |
203 | ||
204 | nand_bcm_umi_bch_pause_read_ecc_calc(); | |
205 | ||
206 | if (numToRead == 11) { | |
207 | /* read BI */ | |
208 | #if defined(__KERNEL__) && !defined(STANDALONE) | |
878040ef | 209 | *oobp++ = readb(®_NAND_DATA8); |
266dead2 | 210 | #else |
878040ef | 211 | readb(®_NAND_DATA8); |
266dead2 LHC |
212 | #endif |
213 | numToRead--; | |
214 | } | |
215 | ||
1385858e RK |
216 | } |
217 | /* read ECC bytes */ | |
218 | nand_bcm_umi_bch_resume_read_ecc_calc(); | |
219 | while (numToRead) { | |
266dead2 | 220 | #if defined(__KERNEL__) && !defined(STANDALONE) |
878040ef | 221 | *oobp = readb(®_NAND_DATA8); |
1385858e RK |
222 | eccCalc[eccPos++] = *oobp; |
223 | oobp++; | |
266dead2 | 224 | #else |
878040ef | 225 | eccCalc[eccPos++] = readb(®_NAND_DATA8); |
266dead2 LHC |
226 | #endif |
227 | numToRead--; | |
266dead2 LHC |
228 | } |
229 | } | |
230 | ||
231 | /* Helper function to write ECC */ | |
232 | static inline void NAND_BCM_UMI_ECC_WRITE(int numEccBytes, int eccBytePos, | |
233 | uint8_t *oobp, uint8_t eccVal) | |
234 | { | |
235 | if (eccBytePos <= numEccBytes) | |
236 | *oobp = eccVal; | |
237 | } | |
238 | ||
239 | /* Write OOB with ECC */ | |
240 | static inline void nand_bcm_umi_bch_write_oobEcc(uint32_t pageSize, | |
241 | uint8_t *oobp, int numEccBytes) | |
242 | { | |
243 | uint32_t eccVal = 0xffffffff; | |
244 | ||
245 | /* wait for write ECC to be valid */ | |
246 | nand_bcm_umi_bch_poll_write_ecc_calc(); | |
247 | ||
248 | /* | |
249 | ** Get the hardware ecc from the 32-bit result registers. | |
250 | ** Read after 512 byte accesses. Format B3B2B1B0 | |
251 | ** where B3 = ecc3, etc. | |
252 | */ | |
253 | ||
254 | if (pageSize == NAND_DATA_ACCESS_SIZE) { | |
255 | /* Now fill in the ECC bytes */ | |
256 | if (numEccBytes >= 13) | |
878040ef | 257 | eccVal = readl(®_UMI_BCH_WR_ECC_3); |
266dead2 LHC |
258 | |
259 | /* Usually we skip CM in oob[0,1] */ | |
260 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 15, &oobp[0], | |
261 | (eccVal >> 16) & 0xff); | |
262 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 14, &oobp[1], | |
263 | (eccVal >> 8) & 0xff); | |
264 | ||
265 | /* Write ECC in oob[2,3,4] */ | |
266 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 13, &oobp[2], | |
267 | eccVal & 0xff); /* ECC 12 */ | |
268 | ||
269 | if (numEccBytes >= 9) | |
878040ef | 270 | eccVal = readl(®_UMI_BCH_WR_ECC_2); |
266dead2 LHC |
271 | |
272 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 12, &oobp[3], | |
273 | (eccVal >> 24) & 0xff); /* ECC11 */ | |
274 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 11, &oobp[4], | |
275 | (eccVal >> 16) & 0xff); /* ECC10 */ | |
276 | ||
277 | /* Always Skip BI in oob[5] */ | |
278 | } else { | |
279 | /* Always Skip BI in oob[0] */ | |
280 | ||
281 | /* Now fill in the ECC bytes */ | |
282 | if (numEccBytes >= 13) | |
878040ef | 283 | eccVal = readl(®_UMI_BCH_WR_ECC_3); |
266dead2 LHC |
284 | |
285 | /* Usually skip CM in oob[1,2] */ | |
286 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 15, &oobp[1], | |
287 | (eccVal >> 16) & 0xff); | |
288 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 14, &oobp[2], | |
289 | (eccVal >> 8) & 0xff); | |
290 | ||
291 | /* Write ECC in oob[3-15] */ | |
292 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 13, &oobp[3], | |
293 | eccVal & 0xff); /* ECC12 */ | |
294 | ||
295 | if (numEccBytes >= 9) | |
878040ef | 296 | eccVal = readl(®_UMI_BCH_WR_ECC_2); |
266dead2 LHC |
297 | |
298 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 12, &oobp[4], | |
299 | (eccVal >> 24) & 0xff); /* ECC11 */ | |
300 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 11, &oobp[5], | |
301 | (eccVal >> 16) & 0xff); /* ECC10 */ | |
302 | } | |
303 | ||
304 | /* Fill in the remainder of ECC locations */ | |
305 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 10, &oobp[6], | |
306 | (eccVal >> 8) & 0xff); /* ECC9 */ | |
307 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 9, &oobp[7], | |
308 | eccVal & 0xff); /* ECC8 */ | |
309 | ||
310 | if (numEccBytes >= 5) | |
878040ef | 311 | eccVal = readl(®_UMI_BCH_WR_ECC_1); |
266dead2 LHC |
312 | |
313 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 8, &oobp[8], | |
314 | (eccVal >> 24) & 0xff); /* ECC7 */ | |
315 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 7, &oobp[9], | |
316 | (eccVal >> 16) & 0xff); /* ECC6 */ | |
317 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 6, &oobp[10], | |
318 | (eccVal >> 8) & 0xff); /* ECC5 */ | |
319 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 5, &oobp[11], | |
320 | eccVal & 0xff); /* ECC4 */ | |
321 | ||
322 | if (numEccBytes >= 1) | |
878040ef | 323 | eccVal = readl(®_UMI_BCH_WR_ECC_0); |
266dead2 LHC |
324 | |
325 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 4, &oobp[12], | |
326 | (eccVal >> 24) & 0xff); /* ECC3 */ | |
327 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 3, &oobp[13], | |
328 | (eccVal >> 16) & 0xff); /* ECC2 */ | |
329 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 2, &oobp[14], | |
330 | (eccVal >> 8) & 0xff); /* ECC1 */ | |
331 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 1, &oobp[15], | |
332 | eccVal & 0xff); /* ECC0 */ | |
333 | } | |
334 | #endif | |
335 | ||
336 | #endif /* NAND_BCM_UMI_H */ |