diff options
Diffstat (limited to 'drivers/mtd/nand/nand_bcm_umi.h')
-rw-r--r-- | drivers/mtd/nand/nand_bcm_umi.h | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/drivers/mtd/nand/nand_bcm_umi.h b/drivers/mtd/nand/nand_bcm_umi.h new file mode 100644 index 000000000000..7cec2cd97854 --- /dev/null +++ b/drivers/mtd/nand/nand_bcm_umi.h | |||
@@ -0,0 +1,358 @@ | |||
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> | ||
20 | #include <cfg_global.h> | ||
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 | { | ||
51 | return REG_UMI_NAND_RCSR & REG_UMI_NAND_RCSR_RDY; | ||
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 */ | ||
65 | REG_UMI_NAND_ECC_CSR &= ~(REG_UMI_NAND_ECC_CSR_ECC_ENABLE | | ||
66 | REG_UMI_NAND_ECC_CSR_256BYTE); | ||
67 | /* enable ECC */ | ||
68 | REG_UMI_NAND_ECC_CSR |= REG_UMI_NAND_ECC_CSR_ECC_ENABLE; | ||
69 | } | ||
70 | |||
71 | #if NAND_ECC_BCH | ||
72 | /* BCH ECC specifics */ | ||
73 | #define ECC_BITS_PER_CORRECTABLE_BIT 13 | ||
74 | |||
75 | /* Enable BCH Read ECC */ | ||
76 | static inline void nand_bcm_umi_bch_enable_read_hwecc(void) | ||
77 | { | ||
78 | /* disable and reset ECC */ | ||
79 | REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID; | ||
80 | /* Turn on ECC */ | ||
81 | REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN; | ||
82 | } | ||
83 | |||
84 | /* Enable BCH Write ECC */ | ||
85 | static inline void nand_bcm_umi_bch_enable_write_hwecc(void) | ||
86 | { | ||
87 | /* disable and reset ECC */ | ||
88 | REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID; | ||
89 | /* Turn on ECC */ | ||
90 | REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_ECC_WR_EN; | ||
91 | } | ||
92 | |||
93 | /* Config number of BCH ECC bytes */ | ||
94 | static inline void nand_bcm_umi_bch_config_ecc(uint8_t numEccBytes) | ||
95 | { | ||
96 | uint32_t nValue; | ||
97 | uint32_t tValue; | ||
98 | uint32_t kValue; | ||
99 | uint32_t numBits = numEccBytes * 8; | ||
100 | |||
101 | /* disable and reset ECC */ | ||
102 | REG_UMI_BCH_CTRL_STATUS = | ||
103 | REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID | | ||
104 | REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID; | ||
105 | |||
106 | /* Every correctible bit requires 13 ECC bits */ | ||
107 | tValue = (uint32_t) (numBits / ECC_BITS_PER_CORRECTABLE_BIT); | ||
108 | |||
109 | /* Total data in number of bits for generating and computing BCH ECC */ | ||
110 | nValue = (NAND_DATA_ACCESS_SIZE + numEccBytes) * 8; | ||
111 | |||
112 | /* K parameter is used internally. K = N - (T * 13) */ | ||
113 | kValue = nValue - (tValue * ECC_BITS_PER_CORRECTABLE_BIT); | ||
114 | |||
115 | /* Write the settings */ | ||
116 | REG_UMI_BCH_N = nValue; | ||
117 | REG_UMI_BCH_T = tValue; | ||
118 | REG_UMI_BCH_K = kValue; | ||
119 | } | ||
120 | |||
121 | /* Pause during ECC read calculation to skip bytes in OOB */ | ||
122 | static inline void nand_bcm_umi_bch_pause_read_ecc_calc(void) | ||
123 | { | ||
124 | REG_UMI_BCH_CTRL_STATUS = | ||
125 | REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN | | ||
126 | REG_UMI_BCH_CTRL_STATUS_PAUSE_ECC_DEC; | ||
127 | } | ||
128 | |||
129 | /* Resume during ECC read calculation after skipping bytes in OOB */ | ||
130 | static inline void nand_bcm_umi_bch_resume_read_ecc_calc(void) | ||
131 | { | ||
132 | REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN; | ||
133 | } | ||
134 | |||
135 | /* Poll read ECC calc to check when hardware completes */ | ||
136 | static inline uint32_t nand_bcm_umi_bch_poll_read_ecc_calc(void) | ||
137 | { | ||
138 | uint32_t regVal; | ||
139 | |||
140 | do { | ||
141 | /* wait for ECC to be valid */ | ||
142 | regVal = REG_UMI_BCH_CTRL_STATUS; | ||
143 | } while ((regVal & REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID) == 0); | ||
144 | |||
145 | return regVal; | ||
146 | } | ||
147 | |||
148 | /* Poll write ECC calc to check when hardware completes */ | ||
149 | static inline void nand_bcm_umi_bch_poll_write_ecc_calc(void) | ||
150 | { | ||
151 | /* wait for ECC to be valid */ | ||
152 | while ((REG_UMI_BCH_CTRL_STATUS & REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID) | ||
153 | == 0) | ||
154 | ; | ||
155 | } | ||
156 | |||
157 | /* Read the OOB and ECC, for kernel write OOB to a buffer */ | ||
158 | #if defined(__KERNEL__) && !defined(STANDALONE) | ||
159 | static inline void nand_bcm_umi_bch_read_oobEcc(uint32_t pageSize, | ||
160 | uint8_t *eccCalc, int numEccBytes, uint8_t *oobp) | ||
161 | #else | ||
162 | static inline void nand_bcm_umi_bch_read_oobEcc(uint32_t pageSize, | ||
163 | uint8_t *eccCalc, int numEccBytes) | ||
164 | #endif | ||
165 | { | ||
166 | int eccPos = 0; | ||
167 | int numToRead = 16; /* There are 16 bytes per sector in the OOB */ | ||
168 | |||
169 | /* ECC is already paused when this function is called */ | ||
170 | |||
171 | if (pageSize == NAND_DATA_ACCESS_SIZE) { | ||
172 | while (numToRead > numEccBytes) { | ||
173 | /* skip free oob region */ | ||
174 | #if defined(__KERNEL__) && !defined(STANDALONE) | ||
175 | *oobp++ = REG_NAND_DATA8; | ||
176 | #else | ||
177 | REG_NAND_DATA8; | ||
178 | #endif | ||
179 | numToRead--; | ||
180 | } | ||
181 | |||
182 | /* read ECC bytes before BI */ | ||
183 | nand_bcm_umi_bch_resume_read_ecc_calc(); | ||
184 | |||
185 | while (numToRead > 11) { | ||
186 | #if defined(__KERNEL__) && !defined(STANDALONE) | ||
187 | *oobp = REG_NAND_DATA8; | ||
188 | eccCalc[eccPos++] = *oobp; | ||
189 | oobp++; | ||
190 | #else | ||
191 | eccCalc[eccPos++] = REG_NAND_DATA8; | ||
192 | #endif | ||
193 | } | ||
194 | |||
195 | nand_bcm_umi_bch_pause_read_ecc_calc(); | ||
196 | |||
197 | if (numToRead == 11) { | ||
198 | /* read BI */ | ||
199 | #if defined(__KERNEL__) && !defined(STANDALONE) | ||
200 | *oobp++ = REG_NAND_DATA8; | ||
201 | #else | ||
202 | REG_NAND_DATA8; | ||
203 | #endif | ||
204 | numToRead--; | ||
205 | } | ||
206 | |||
207 | /* read ECC bytes */ | ||
208 | nand_bcm_umi_bch_resume_read_ecc_calc(); | ||
209 | while (numToRead) { | ||
210 | #if defined(__KERNEL__) && !defined(STANDALONE) | ||
211 | *oobp = REG_NAND_DATA8; | ||
212 | eccCalc[eccPos++] = *oobp; | ||
213 | oobp++; | ||
214 | #else | ||
215 | eccCalc[eccPos++] = REG_NAND_DATA8; | ||
216 | #endif | ||
217 | numToRead--; | ||
218 | } | ||
219 | } else { | ||
220 | /* skip BI */ | ||
221 | #if defined(__KERNEL__) && !defined(STANDALONE) | ||
222 | *oobp++ = REG_NAND_DATA8; | ||
223 | #else | ||
224 | REG_NAND_DATA8; | ||
225 | #endif | ||
226 | numToRead--; | ||
227 | |||
228 | while (numToRead > numEccBytes) { | ||
229 | /* skip free oob region */ | ||
230 | #if defined(__KERNEL__) && !defined(STANDALONE) | ||
231 | *oobp++ = REG_NAND_DATA8; | ||
232 | #else | ||
233 | REG_NAND_DATA8; | ||
234 | #endif | ||
235 | numToRead--; | ||
236 | } | ||
237 | |||
238 | /* read ECC bytes */ | ||
239 | nand_bcm_umi_bch_resume_read_ecc_calc(); | ||
240 | while (numToRead) { | ||
241 | #if defined(__KERNEL__) && !defined(STANDALONE) | ||
242 | *oobp = REG_NAND_DATA8; | ||
243 | eccCalc[eccPos++] = *oobp; | ||
244 | oobp++; | ||
245 | #else | ||
246 | eccCalc[eccPos++] = REG_NAND_DATA8; | ||
247 | #endif | ||
248 | numToRead--; | ||
249 | } | ||
250 | } | ||
251 | } | ||
252 | |||
253 | /* Helper function to write ECC */ | ||
254 | static inline void NAND_BCM_UMI_ECC_WRITE(int numEccBytes, int eccBytePos, | ||
255 | uint8_t *oobp, uint8_t eccVal) | ||
256 | { | ||
257 | if (eccBytePos <= numEccBytes) | ||
258 | *oobp = eccVal; | ||
259 | } | ||
260 | |||
261 | /* Write OOB with ECC */ | ||
262 | static inline void nand_bcm_umi_bch_write_oobEcc(uint32_t pageSize, | ||
263 | uint8_t *oobp, int numEccBytes) | ||
264 | { | ||
265 | uint32_t eccVal = 0xffffffff; | ||
266 | |||
267 | /* wait for write ECC to be valid */ | ||
268 | nand_bcm_umi_bch_poll_write_ecc_calc(); | ||
269 | |||
270 | /* | ||
271 | ** Get the hardware ecc from the 32-bit result registers. | ||
272 | ** Read after 512 byte accesses. Format B3B2B1B0 | ||
273 | ** where B3 = ecc3, etc. | ||
274 | */ | ||
275 | |||
276 | if (pageSize == NAND_DATA_ACCESS_SIZE) { | ||
277 | /* Now fill in the ECC bytes */ | ||
278 | if (numEccBytes >= 13) | ||
279 | eccVal = REG_UMI_BCH_WR_ECC_3; | ||
280 | |||
281 | /* Usually we skip CM in oob[0,1] */ | ||
282 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 15, &oobp[0], | ||
283 | (eccVal >> 16) & 0xff); | ||
284 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 14, &oobp[1], | ||
285 | (eccVal >> 8) & 0xff); | ||
286 | |||
287 | /* Write ECC in oob[2,3,4] */ | ||
288 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 13, &oobp[2], | ||
289 | eccVal & 0xff); /* ECC 12 */ | ||
290 | |||
291 | if (numEccBytes >= 9) | ||
292 | eccVal = REG_UMI_BCH_WR_ECC_2; | ||
293 | |||
294 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 12, &oobp[3], | ||
295 | (eccVal >> 24) & 0xff); /* ECC11 */ | ||
296 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 11, &oobp[4], | ||
297 | (eccVal >> 16) & 0xff); /* ECC10 */ | ||
298 | |||
299 | /* Always Skip BI in oob[5] */ | ||
300 | } else { | ||
301 | /* Always Skip BI in oob[0] */ | ||
302 | |||
303 | /* Now fill in the ECC bytes */ | ||
304 | if (numEccBytes >= 13) | ||
305 | eccVal = REG_UMI_BCH_WR_ECC_3; | ||
306 | |||
307 | /* Usually skip CM in oob[1,2] */ | ||
308 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 15, &oobp[1], | ||
309 | (eccVal >> 16) & 0xff); | ||
310 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 14, &oobp[2], | ||
311 | (eccVal >> 8) & 0xff); | ||
312 | |||
313 | /* Write ECC in oob[3-15] */ | ||
314 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 13, &oobp[3], | ||
315 | eccVal & 0xff); /* ECC12 */ | ||
316 | |||
317 | if (numEccBytes >= 9) | ||
318 | eccVal = REG_UMI_BCH_WR_ECC_2; | ||
319 | |||
320 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 12, &oobp[4], | ||
321 | (eccVal >> 24) & 0xff); /* ECC11 */ | ||
322 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 11, &oobp[5], | ||
323 | (eccVal >> 16) & 0xff); /* ECC10 */ | ||
324 | } | ||
325 | |||
326 | /* Fill in the remainder of ECC locations */ | ||
327 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 10, &oobp[6], | ||
328 | (eccVal >> 8) & 0xff); /* ECC9 */ | ||
329 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 9, &oobp[7], | ||
330 | eccVal & 0xff); /* ECC8 */ | ||
331 | |||
332 | if (numEccBytes >= 5) | ||
333 | eccVal = REG_UMI_BCH_WR_ECC_1; | ||
334 | |||
335 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 8, &oobp[8], | ||
336 | (eccVal >> 24) & 0xff); /* ECC7 */ | ||
337 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 7, &oobp[9], | ||
338 | (eccVal >> 16) & 0xff); /* ECC6 */ | ||
339 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 6, &oobp[10], | ||
340 | (eccVal >> 8) & 0xff); /* ECC5 */ | ||
341 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 5, &oobp[11], | ||
342 | eccVal & 0xff); /* ECC4 */ | ||
343 | |||
344 | if (numEccBytes >= 1) | ||
345 | eccVal = REG_UMI_BCH_WR_ECC_0; | ||
346 | |||
347 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 4, &oobp[12], | ||
348 | (eccVal >> 24) & 0xff); /* ECC3 */ | ||
349 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 3, &oobp[13], | ||
350 | (eccVal >> 16) & 0xff); /* ECC2 */ | ||
351 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 2, &oobp[14], | ||
352 | (eccVal >> 8) & 0xff); /* ECC1 */ | ||
353 | NAND_BCM_UMI_ECC_WRITE(numEccBytes, 1, &oobp[15], | ||
354 | eccVal & 0xff); /* ECC0 */ | ||
355 | } | ||
356 | #endif | ||
357 | |||
358 | #endif /* NAND_BCM_UMI_H */ | ||