]>
Commit | Line | Data |
---|---|---|
36fab997 | 1 | /* |
cfcbf8c4 | 2 | * Copyright 2004-2007 Freescale Semiconductor, Inc. |
36fab997 IY |
3 | * Copyright 2008 Sascha Hauer, kernel@pengutronix.de |
4 | * Copyright 2009 Ilya Yanok, <yanok@emcraft.com> | |
5 | * | |
1a459660 | 6 | * SPDX-License-Identifier: GPL-2.0+ |
36fab997 IY |
7 | */ |
8 | ||
9 | #include <common.h> | |
10 | #include <nand.h> | |
11 | #include <linux/err.h> | |
12 | #include <asm/io.h> | |
35537bc7 BT |
13 | #if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX35) || \ |
14 | defined(CONFIG_MX51) || defined(CONFIG_MX53) | |
36fab997 IY |
15 | #include <asm/arch/imx-regs.h> |
16 | #endif | |
da962b71 | 17 | #include "mxc_nand.h" |
36fab997 IY |
18 | |
19 | #define DRIVER_NAME "mxc_nand" | |
20 | ||
36fab997 | 21 | struct mxc_nand_host { |
80c8ab7b BT |
22 | struct mtd_info mtd; |
23 | struct nand_chip *nand; | |
24 | ||
da962b71 | 25 | struct mxc_nand_regs __iomem *regs; |
35537bc7 | 26 | #ifdef MXC_NFC_V3_2 |
da962b71 | 27 | struct mxc_nand_ip_regs __iomem *ip_regs; |
35537bc7 | 28 | #endif |
80c8ab7b BT |
29 | int spare_only; |
30 | int status_request; | |
31 | int pagesize_2k; | |
32 | int clk_act; | |
33 | uint16_t col_addr; | |
34 | unsigned int page_addr; | |
36fab997 IY |
35 | }; |
36 | ||
37 | static struct mxc_nand_host mxc_host; | |
38 | static struct mxc_nand_host *host = &mxc_host; | |
39 | ||
40 | /* Define delays in microsec for NAND device operations */ | |
41 | #define TROP_US_DELAY 2000 | |
42 | /* Macros to get byte and bit positions of ECC */ | |
43 | #define COLPOS(x) ((x) >> 3) | |
44 | #define BITPOS(x) ((x) & 0xf) | |
45 | ||
46 | /* Define single bit Error positions in Main & Spare area */ | |
47 | #define MAIN_SINGLEBIT_ERROR 0x4 | |
48 | #define SPARE_SINGLEBIT_ERROR 0x1 | |
49 | ||
50 | /* OOB placement block for use with hardware ecc generation */ | |
b081c2e9 JR |
51 | #if defined(MXC_NFC_V1) |
52 | #ifndef CONFIG_SYS_NAND_LARGEPAGE | |
36fab997 IY |
53 | static struct nand_ecclayout nand_hw_eccoob = { |
54 | .eccbytes = 5, | |
55 | .eccpos = {6, 7, 8, 9, 10}, | |
b081c2e9 | 56 | .oobfree = { {0, 5}, {11, 5}, } |
36fab997 IY |
57 | }; |
58 | #else | |
b081c2e9 JR |
59 | static struct nand_ecclayout nand_hw_eccoob2k = { |
60 | .eccbytes = 20, | |
61 | .eccpos = { | |
62 | 6, 7, 8, 9, 10, | |
63 | 22, 23, 24, 25, 26, | |
64 | 38, 39, 40, 41, 42, | |
65 | 54, 55, 56, 57, 58, | |
66 | }, | |
67 | .oobfree = { {2, 4}, {11, 11}, {27, 11}, {43, 11}, {59, 5} }, | |
36fab997 IY |
68 | }; |
69 | #endif | |
35537bc7 | 70 | #elif defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2) |
b081c2e9 JR |
71 | #ifndef CONFIG_SYS_NAND_LARGEPAGE |
72 | static struct nand_ecclayout nand_hw_eccoob = { | |
73 | .eccbytes = 9, | |
74 | .eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15}, | |
75 | .oobfree = { {2, 5} } | |
c4832dff | 76 | }; |
b081c2e9 JR |
77 | #else |
78 | static struct nand_ecclayout nand_hw_eccoob2k = { | |
79 | .eccbytes = 36, | |
80 | .eccpos = { | |
81 | 7, 8, 9, 10, 11, 12, 13, 14, 15, | |
82 | 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
83 | 39, 40, 41, 42, 43, 44, 45, 46, 47, | |
84 | 55, 56, 57, 58, 59, 60, 61, 62, 63, | |
85 | }, | |
86 | .oobfree = { {2, 5}, {16, 7}, {32, 7}, {48, 7} }, | |
87 | }; | |
88 | #endif | |
89 | #endif | |
c4832dff | 90 | |
f6a9748e ML |
91 | static int is_16bit_nand(void) |
92 | { | |
a430e916 FE |
93 | #if defined(CONFIG_SYS_NAND_BUSWIDTH_16BIT) |
94 | return 1; | |
f6a9748e | 95 | #else |
f6a9748e | 96 | return 0; |
f6a9748e | 97 | #endif |
a430e916 | 98 | } |
f6a9748e | 99 | |
36fab997 IY |
100 | static uint32_t *mxc_nand_memcpy32(uint32_t *dest, uint32_t *source, size_t size) |
101 | { | |
102 | uint32_t *d = dest; | |
103 | ||
104 | size >>= 2; | |
105 | while (size--) | |
106 | __raw_writel(__raw_readl(source++), d++); | |
107 | return dest; | |
108 | } | |
109 | ||
110 | /* | |
111 | * This function polls the NANDFC to wait for the basic operation to | |
2dc0aa02 | 112 | * complete by checking the INT bit. |
36fab997 IY |
113 | */ |
114 | static void wait_op_done(struct mxc_nand_host *host, int max_retries, | |
115 | uint16_t param) | |
116 | { | |
117 | uint32_t tmp; | |
118 | ||
119 | while (max_retries-- > 0) { | |
35537bc7 | 120 | #if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) |
2dc0aa02 BT |
121 | tmp = readnfc(&host->regs->config2); |
122 | if (tmp & NFC_V1_V2_CONFIG2_INT) { | |
123 | tmp &= ~NFC_V1_V2_CONFIG2_INT; | |
124 | writenfc(tmp, &host->regs->config2); | |
35537bc7 BT |
125 | #elif defined(MXC_NFC_V3_2) |
126 | tmp = readnfc(&host->ip_regs->ipc); | |
127 | if (tmp & NFC_V3_IPC_INT) { | |
128 | tmp &= ~NFC_V3_IPC_INT; | |
129 | writenfc(tmp, &host->ip_regs->ipc); | |
130 | #endif | |
36fab997 IY |
131 | break; |
132 | } | |
133 | udelay(1); | |
134 | } | |
135 | if (max_retries < 0) { | |
136 | MTDDEBUG(MTD_DEBUG_LEVEL0, "%s(%d): INT not set\n", | |
137 | __func__, param); | |
138 | } | |
139 | } | |
140 | ||
141 | /* | |
142 | * This function issues the specified command to the NAND device and | |
143 | * waits for completion. | |
144 | */ | |
145 | static void send_cmd(struct mxc_nand_host *host, uint16_t cmd) | |
146 | { | |
147 | MTDDEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x)\n", cmd); | |
148 | ||
2dc0aa02 BT |
149 | writenfc(cmd, &host->regs->flash_cmd); |
150 | writenfc(NFC_CMD, &host->regs->operation); | |
36fab997 IY |
151 | |
152 | /* Wait for operation to complete */ | |
153 | wait_op_done(host, TROP_US_DELAY, cmd); | |
154 | } | |
155 | ||
156 | /* | |
157 | * This function sends an address (or partial address) to the | |
158 | * NAND device. The address is used to select the source/destination for | |
159 | * a NAND command. | |
160 | */ | |
161 | static void send_addr(struct mxc_nand_host *host, uint16_t addr) | |
162 | { | |
163 | MTDDEBUG(MTD_DEBUG_LEVEL3, "send_addr(host, 0x%x)\n", addr); | |
164 | ||
2dc0aa02 BT |
165 | writenfc(addr, &host->regs->flash_addr); |
166 | writenfc(NFC_ADDR, &host->regs->operation); | |
36fab997 IY |
167 | |
168 | /* Wait for operation to complete */ | |
169 | wait_op_done(host, TROP_US_DELAY, addr); | |
170 | } | |
171 | ||
172 | /* | |
780f30b6 | 173 | * This function requests the NANDFC to initiate the transfer |
36fab997 IY |
174 | * of data currently in the NANDFC RAM buffer to the NAND device. |
175 | */ | |
176 | static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id, | |
177 | int spare_only) | |
178 | { | |
b081c2e9 JR |
179 | if (spare_only) |
180 | MTDDEBUG(MTD_DEBUG_LEVEL1, "send_prog_page (%d)\n", spare_only); | |
181 | ||
35537bc7 | 182 | if (is_mxc_nfc_21() || is_mxc_nfc_32()) { |
b081c2e9 JR |
183 | int i; |
184 | /* | |
185 | * The controller copies the 64 bytes of spare data from | |
186 | * the first 16 bytes of each of the 4 64 byte spare buffers. | |
187 | * Copy the contiguous data starting in spare_area[0] to | |
188 | * the four spare area buffers. | |
189 | */ | |
190 | for (i = 1; i < 4; i++) { | |
191 | void __iomem *src = &host->regs->spare_area[0][i * 16]; | |
192 | void __iomem *dst = &host->regs->spare_area[i][0]; | |
193 | ||
194 | mxc_nand_memcpy32(dst, src, 16); | |
195 | } | |
196 | } | |
36fab997 | 197 | |
35537bc7 | 198 | #if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) |
2dc0aa02 | 199 | writenfc(buf_id, &host->regs->buf_addr); |
35537bc7 BT |
200 | #elif defined(MXC_NFC_V3_2) |
201 | uint32_t tmp = readnfc(&host->regs->config1); | |
202 | tmp &= ~NFC_V3_CONFIG1_RBA_MASK; | |
203 | tmp |= NFC_V3_CONFIG1_RBA(buf_id); | |
204 | writenfc(tmp, &host->regs->config1); | |
205 | #endif | |
36fab997 IY |
206 | |
207 | /* Configure spare or page+spare access */ | |
208 | if (!host->pagesize_2k) { | |
35537bc7 | 209 | uint32_t config1 = readnfc(&host->regs->config1); |
36fab997 | 210 | if (spare_only) |
2dc0aa02 | 211 | config1 |= NFC_CONFIG1_SP_EN; |
36fab997 | 212 | else |
2dc0aa02 BT |
213 | config1 &= ~NFC_CONFIG1_SP_EN; |
214 | writenfc(config1, &host->regs->config1); | |
36fab997 IY |
215 | } |
216 | ||
2dc0aa02 | 217 | writenfc(NFC_INPUT, &host->regs->operation); |
36fab997 IY |
218 | |
219 | /* Wait for operation to complete */ | |
220 | wait_op_done(host, TROP_US_DELAY, spare_only); | |
221 | } | |
222 | ||
223 | /* | |
780f30b6 | 224 | * Requests NANDFC to initiate the transfer of data from the |
36fab997 IY |
225 | * NAND device into in the NANDFC ram buffer. |
226 | */ | |
227 | static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id, | |
228 | int spare_only) | |
229 | { | |
230 | MTDDEBUG(MTD_DEBUG_LEVEL3, "send_read_page (%d)\n", spare_only); | |
231 | ||
35537bc7 | 232 | #if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) |
2dc0aa02 | 233 | writenfc(buf_id, &host->regs->buf_addr); |
35537bc7 BT |
234 | #elif defined(MXC_NFC_V3_2) |
235 | uint32_t tmp = readnfc(&host->regs->config1); | |
236 | tmp &= ~NFC_V3_CONFIG1_RBA_MASK; | |
237 | tmp |= NFC_V3_CONFIG1_RBA(buf_id); | |
238 | writenfc(tmp, &host->regs->config1); | |
239 | #endif | |
36fab997 IY |
240 | |
241 | /* Configure spare or page+spare access */ | |
242 | if (!host->pagesize_2k) { | |
2dc0aa02 | 243 | uint32_t config1 = readnfc(&host->regs->config1); |
36fab997 | 244 | if (spare_only) |
2dc0aa02 | 245 | config1 |= NFC_CONFIG1_SP_EN; |
36fab997 | 246 | else |
2dc0aa02 BT |
247 | config1 &= ~NFC_CONFIG1_SP_EN; |
248 | writenfc(config1, &host->regs->config1); | |
36fab997 IY |
249 | } |
250 | ||
2dc0aa02 | 251 | writenfc(NFC_OUTPUT, &host->regs->operation); |
36fab997 IY |
252 | |
253 | /* Wait for operation to complete */ | |
254 | wait_op_done(host, TROP_US_DELAY, spare_only); | |
b081c2e9 | 255 | |
35537bc7 | 256 | if (is_mxc_nfc_21() || is_mxc_nfc_32()) { |
b081c2e9 JR |
257 | int i; |
258 | ||
259 | /* | |
260 | * The controller copies the 64 bytes of spare data to | |
261 | * the first 16 bytes of each of the 4 spare buffers. | |
262 | * Make the data contiguous starting in spare_area[0]. | |
263 | */ | |
264 | for (i = 1; i < 4; i++) { | |
265 | void __iomem *src = &host->regs->spare_area[i][0]; | |
266 | void __iomem *dst = &host->regs->spare_area[0][i * 16]; | |
267 | ||
268 | mxc_nand_memcpy32(dst, src, 16); | |
269 | } | |
270 | } | |
36fab997 IY |
271 | } |
272 | ||
273 | /* Request the NANDFC to perform a read of the NAND device ID. */ | |
274 | static void send_read_id(struct mxc_nand_host *host) | |
275 | { | |
35537bc7 | 276 | uint32_t tmp; |
36fab997 | 277 | |
35537bc7 | 278 | #if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) |
36fab997 | 279 | /* NANDFC buffer 0 is used for device ID output */ |
2dc0aa02 | 280 | writenfc(0x0, &host->regs->buf_addr); |
35537bc7 BT |
281 | #elif defined(MXC_NFC_V3_2) |
282 | tmp = readnfc(&host->regs->config1); | |
283 | tmp &= ~NFC_V3_CONFIG1_RBA_MASK; | |
284 | writenfc(tmp, &host->regs->config1); | |
285 | #endif | |
36fab997 IY |
286 | |
287 | /* Read ID into main buffer */ | |
2dc0aa02 BT |
288 | tmp = readnfc(&host->regs->config1); |
289 | tmp &= ~NFC_CONFIG1_SP_EN; | |
290 | writenfc(tmp, &host->regs->config1); | |
36fab997 | 291 | |
2dc0aa02 | 292 | writenfc(NFC_ID, &host->regs->operation); |
36fab997 IY |
293 | |
294 | /* Wait for operation to complete */ | |
295 | wait_op_done(host, TROP_US_DELAY, 0); | |
296 | } | |
297 | ||
298 | /* | |
299 | * This function requests the NANDFC to perform a read of the | |
300 | * NAND device status and returns the current status. | |
301 | */ | |
302 | static uint16_t get_dev_status(struct mxc_nand_host *host) | |
303 | { | |
35537bc7 | 304 | #if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) |
b081c2e9 | 305 | void __iomem *main_buf = host->regs->main_area[1]; |
36fab997 | 306 | uint32_t store; |
35537bc7 BT |
307 | #endif |
308 | uint32_t ret, tmp; | |
36fab997 IY |
309 | /* Issue status request to NAND device */ |
310 | ||
35537bc7 | 311 | #if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) |
36fab997 IY |
312 | /* store the main area1 first word, later do recovery */ |
313 | store = readl(main_buf); | |
314 | /* NANDFC buffer 1 is used for device status */ | |
2dc0aa02 | 315 | writenfc(1, &host->regs->buf_addr); |
35537bc7 | 316 | #endif |
36fab997 IY |
317 | |
318 | /* Read status into main buffer */ | |
2dc0aa02 BT |
319 | tmp = readnfc(&host->regs->config1); |
320 | tmp &= ~NFC_CONFIG1_SP_EN; | |
321 | writenfc(tmp, &host->regs->config1); | |
36fab997 | 322 | |
2dc0aa02 | 323 | writenfc(NFC_STATUS, &host->regs->operation); |
36fab997 IY |
324 | |
325 | /* Wait for operation to complete */ | |
326 | wait_op_done(host, TROP_US_DELAY, 0); | |
327 | ||
35537bc7 | 328 | #if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) |
36fab997 IY |
329 | /* |
330 | * Status is placed in first word of main buffer | |
331 | * get status, then recovery area 1 data | |
332 | */ | |
333 | ret = readw(main_buf); | |
334 | writel(store, main_buf); | |
35537bc7 BT |
335 | #elif defined(MXC_NFC_V3_2) |
336 | ret = readnfc(&host->regs->config1) >> 16; | |
337 | #endif | |
36fab997 IY |
338 | |
339 | return ret; | |
340 | } | |
341 | ||
342 | /* This function is used by upper layer to checks if device is ready */ | |
343 | static int mxc_nand_dev_ready(struct mtd_info *mtd) | |
344 | { | |
345 | /* | |
346 | * NFC handles R/B internally. Therefore, this function | |
347 | * always returns status as ready. | |
348 | */ | |
349 | return 1; | |
350 | } | |
351 | ||
b081c2e9 JR |
352 | static void _mxc_nand_enable_hwecc(struct mtd_info *mtd, int on) |
353 | { | |
17cb4b8f SW |
354 | struct nand_chip *nand_chip = mtd_to_nand(mtd); |
355 | struct mxc_nand_host *host = nand_get_controller_data(nand_chip); | |
35537bc7 | 356 | #if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) |
2dc0aa02 | 357 | uint16_t tmp = readnfc(&host->regs->config1); |
b081c2e9 JR |
358 | |
359 | if (on) | |
2dc0aa02 | 360 | tmp |= NFC_V1_V2_CONFIG1_ECC_EN; |
b081c2e9 | 361 | else |
2dc0aa02 BT |
362 | tmp &= ~NFC_V1_V2_CONFIG1_ECC_EN; |
363 | writenfc(tmp, &host->regs->config1); | |
35537bc7 BT |
364 | #elif defined(MXC_NFC_V3_2) |
365 | uint32_t tmp = readnfc(&host->ip_regs->config2); | |
366 | ||
367 | if (on) | |
368 | tmp |= NFC_V3_CONFIG2_ECC_EN; | |
369 | else | |
370 | tmp &= ~NFC_V3_CONFIG2_ECC_EN; | |
371 | writenfc(tmp, &host->ip_regs->config2); | |
372 | #endif | |
b081c2e9 JR |
373 | } |
374 | ||
0e499b07 BT |
375 | #ifdef CONFIG_MXC_NAND_HWECC |
376 | static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode) | |
377 | { | |
378 | /* | |
379 | * If HW ECC is enabled, we turn it on during init. There is | |
380 | * no need to enable again here. | |
381 | */ | |
382 | } | |
383 | ||
35537bc7 | 384 | #if defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2) |
b081c2e9 JR |
385 | static int mxc_nand_read_oob_syndrome(struct mtd_info *mtd, |
386 | struct nand_chip *chip, | |
dfe64e2c | 387 | int page) |
b081c2e9 | 388 | { |
17cb4b8f | 389 | struct mxc_nand_host *host = nand_get_controller_data(chip); |
b081c2e9 JR |
390 | uint8_t *buf = chip->oob_poi; |
391 | int length = mtd->oobsize; | |
392 | int eccpitch = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; | |
393 | uint8_t *bufpoi = buf; | |
394 | int i, toread; | |
395 | ||
396 | MTDDEBUG(MTD_DEBUG_LEVEL0, | |
397 | "%s: Reading OOB area of page %u to oob %p\n", | |
78ee7b17 | 398 | __func__, page, buf); |
b081c2e9 JR |
399 | |
400 | chip->cmdfunc(mtd, NAND_CMD_READOOB, mtd->writesize, page); | |
401 | for (i = 0; i < chip->ecc.steps; i++) { | |
402 | toread = min_t(int, length, chip->ecc.prepad); | |
403 | if (toread) { | |
404 | chip->read_buf(mtd, bufpoi, toread); | |
405 | bufpoi += toread; | |
406 | length -= toread; | |
407 | } | |
408 | bufpoi += chip->ecc.bytes; | |
409 | host->col_addr += chip->ecc.bytes; | |
410 | length -= chip->ecc.bytes; | |
411 | ||
412 | toread = min_t(int, length, chip->ecc.postpad); | |
413 | if (toread) { | |
414 | chip->read_buf(mtd, bufpoi, toread); | |
415 | bufpoi += toread; | |
416 | length -= toread; | |
417 | } | |
418 | } | |
419 | if (length > 0) | |
420 | chip->read_buf(mtd, bufpoi, length); | |
421 | ||
422 | _mxc_nand_enable_hwecc(mtd, 0); | |
423 | chip->cmdfunc(mtd, NAND_CMD_READOOB, | |
424 | mtd->writesize + chip->ecc.prepad, page); | |
425 | bufpoi = buf + chip->ecc.prepad; | |
426 | length = mtd->oobsize - chip->ecc.prepad; | |
427 | for (i = 0; i < chip->ecc.steps; i++) { | |
428 | toread = min_t(int, length, chip->ecc.bytes); | |
429 | chip->read_buf(mtd, bufpoi, toread); | |
430 | bufpoi += eccpitch; | |
431 | length -= eccpitch; | |
432 | host->col_addr += chip->ecc.postpad + chip->ecc.prepad; | |
433 | } | |
434 | _mxc_nand_enable_hwecc(mtd, 1); | |
435 | return 1; | |
436 | } | |
437 | ||
438 | static int mxc_nand_read_page_raw_syndrome(struct mtd_info *mtd, | |
439 | struct nand_chip *chip, | |
440 | uint8_t *buf, | |
dfe64e2c | 441 | int oob_required, |
b081c2e9 JR |
442 | int page) |
443 | { | |
17cb4b8f | 444 | struct mxc_nand_host *host = nand_get_controller_data(chip); |
b081c2e9 JR |
445 | int eccsize = chip->ecc.size; |
446 | int eccbytes = chip->ecc.bytes; | |
447 | int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; | |
448 | uint8_t *oob = chip->oob_poi; | |
449 | int steps, size; | |
450 | int n; | |
451 | ||
452 | _mxc_nand_enable_hwecc(mtd, 0); | |
3ec9d6eb | 453 | chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); |
b081c2e9 JR |
454 | |
455 | for (n = 0, steps = chip->ecc.steps; steps > 0; n++, steps--) { | |
456 | host->col_addr = n * eccsize; | |
457 | chip->read_buf(mtd, buf, eccsize); | |
458 | buf += eccsize; | |
459 | ||
460 | host->col_addr = mtd->writesize + n * eccpitch; | |
461 | if (chip->ecc.prepad) { | |
462 | chip->read_buf(mtd, oob, chip->ecc.prepad); | |
463 | oob += chip->ecc.prepad; | |
464 | } | |
465 | ||
466 | chip->read_buf(mtd, oob, eccbytes); | |
467 | oob += eccbytes; | |
468 | ||
469 | if (chip->ecc.postpad) { | |
470 | chip->read_buf(mtd, oob, chip->ecc.postpad); | |
471 | oob += chip->ecc.postpad; | |
472 | } | |
473 | } | |
474 | ||
475 | size = mtd->oobsize - (oob - chip->oob_poi); | |
476 | if (size) | |
477 | chip->read_buf(mtd, oob, size); | |
7c28a1cf | 478 | _mxc_nand_enable_hwecc(mtd, 1); |
b081c2e9 JR |
479 | |
480 | return 0; | |
481 | } | |
482 | ||
483 | static int mxc_nand_read_page_syndrome(struct mtd_info *mtd, | |
484 | struct nand_chip *chip, | |
485 | uint8_t *buf, | |
dfe64e2c | 486 | int oob_required, |
b081c2e9 JR |
487 | int page) |
488 | { | |
17cb4b8f | 489 | struct mxc_nand_host *host = nand_get_controller_data(chip); |
b081c2e9 JR |
490 | int n, eccsize = chip->ecc.size; |
491 | int eccbytes = chip->ecc.bytes; | |
492 | int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; | |
493 | int eccsteps = chip->ecc.steps; | |
494 | uint8_t *p = buf; | |
495 | uint8_t *oob = chip->oob_poi; | |
496 | ||
497 | MTDDEBUG(MTD_DEBUG_LEVEL1, "Reading page %u to buf %p oob %p\n", | |
3ec9d6eb | 498 | page, buf, oob); |
b081c2e9 | 499 | |
780f30b6 | 500 | /* first read the data area and the available portion of OOB */ |
b081c2e9 JR |
501 | for (n = 0; eccsteps; n++, eccsteps--, p += eccsize) { |
502 | int stat; | |
503 | ||
504 | host->col_addr = n * eccsize; | |
505 | ||
506 | chip->read_buf(mtd, p, eccsize); | |
507 | ||
508 | host->col_addr = mtd->writesize + n * eccpitch; | |
509 | ||
510 | if (chip->ecc.prepad) { | |
511 | chip->read_buf(mtd, oob, chip->ecc.prepad); | |
512 | oob += chip->ecc.prepad; | |
513 | } | |
514 | ||
515 | stat = chip->ecc.correct(mtd, p, oob, NULL); | |
516 | ||
517 | if (stat < 0) | |
518 | mtd->ecc_stats.failed++; | |
519 | else | |
520 | mtd->ecc_stats.corrected += stat; | |
521 | oob += eccbytes; | |
522 | ||
523 | if (chip->ecc.postpad) { | |
524 | chip->read_buf(mtd, oob, chip->ecc.postpad); | |
525 | oob += chip->ecc.postpad; | |
526 | } | |
527 | } | |
528 | ||
529 | /* Calculate remaining oob bytes */ | |
530 | n = mtd->oobsize - (oob - chip->oob_poi); | |
531 | if (n) | |
532 | chip->read_buf(mtd, oob, n); | |
533 | ||
534 | /* Then switch ECC off and read the OOB area to get the ECC code */ | |
535 | _mxc_nand_enable_hwecc(mtd, 0); | |
3ec9d6eb | 536 | chip->cmdfunc(mtd, NAND_CMD_READOOB, mtd->writesize, page); |
b081c2e9 JR |
537 | eccsteps = chip->ecc.steps; |
538 | oob = chip->oob_poi + chip->ecc.prepad; | |
539 | for (n = 0; eccsteps; n++, eccsteps--, p += eccsize) { | |
540 | host->col_addr = mtd->writesize + | |
541 | n * eccpitch + | |
542 | chip->ecc.prepad; | |
543 | chip->read_buf(mtd, oob, eccbytes); | |
544 | oob += eccbytes + chip->ecc.postpad; | |
545 | } | |
546 | _mxc_nand_enable_hwecc(mtd, 1); | |
547 | return 0; | |
548 | } | |
549 | ||
550 | static int mxc_nand_write_oob_syndrome(struct mtd_info *mtd, | |
551 | struct nand_chip *chip, int page) | |
552 | { | |
17cb4b8f | 553 | struct mxc_nand_host *host = nand_get_controller_data(chip); |
b081c2e9 JR |
554 | int eccpitch = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; |
555 | int length = mtd->oobsize; | |
556 | int i, len, status, steps = chip->ecc.steps; | |
557 | const uint8_t *bufpoi = chip->oob_poi; | |
558 | ||
559 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); | |
560 | for (i = 0; i < steps; i++) { | |
561 | len = min_t(int, length, eccpitch); | |
562 | ||
563 | chip->write_buf(mtd, bufpoi, len); | |
564 | bufpoi += len; | |
565 | length -= len; | |
566 | host->col_addr += chip->ecc.prepad + chip->ecc.postpad; | |
567 | } | |
568 | if (length > 0) | |
569 | chip->write_buf(mtd, bufpoi, length); | |
570 | ||
571 | chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); | |
572 | status = chip->waitfunc(mtd, chip); | |
573 | return status & NAND_STATUS_FAIL ? -EIO : 0; | |
574 | } | |
575 | ||
dfe64e2c | 576 | static int mxc_nand_write_page_raw_syndrome(struct mtd_info *mtd, |
b081c2e9 | 577 | struct nand_chip *chip, |
dfe64e2c | 578 | const uint8_t *buf, |
81c77252 | 579 | int oob_required, int page) |
b081c2e9 | 580 | { |
17cb4b8f | 581 | struct mxc_nand_host *host = nand_get_controller_data(chip); |
b081c2e9 JR |
582 | int eccsize = chip->ecc.size; |
583 | int eccbytes = chip->ecc.bytes; | |
584 | int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; | |
585 | uint8_t *oob = chip->oob_poi; | |
586 | int steps, size; | |
587 | int n; | |
588 | ||
589 | for (n = 0, steps = chip->ecc.steps; steps > 0; n++, steps--) { | |
590 | host->col_addr = n * eccsize; | |
591 | chip->write_buf(mtd, buf, eccsize); | |
592 | buf += eccsize; | |
593 | ||
594 | host->col_addr = mtd->writesize + n * eccpitch; | |
595 | ||
596 | if (chip->ecc.prepad) { | |
597 | chip->write_buf(mtd, oob, chip->ecc.prepad); | |
598 | oob += chip->ecc.prepad; | |
599 | } | |
600 | ||
601 | host->col_addr += eccbytes; | |
602 | oob += eccbytes; | |
603 | ||
604 | if (chip->ecc.postpad) { | |
605 | chip->write_buf(mtd, oob, chip->ecc.postpad); | |
606 | oob += chip->ecc.postpad; | |
607 | } | |
608 | } | |
609 | ||
610 | size = mtd->oobsize - (oob - chip->oob_poi); | |
611 | if (size) | |
612 | chip->write_buf(mtd, oob, size); | |
dfe64e2c | 613 | return 0; |
b081c2e9 JR |
614 | } |
615 | ||
dfe64e2c | 616 | static int mxc_nand_write_page_syndrome(struct mtd_info *mtd, |
b081c2e9 | 617 | struct nand_chip *chip, |
dfe64e2c | 618 | const uint8_t *buf, |
81c77252 | 619 | int oob_required, int page) |
b081c2e9 | 620 | { |
17cb4b8f | 621 | struct mxc_nand_host *host = nand_get_controller_data(chip); |
b081c2e9 JR |
622 | int i, n, eccsize = chip->ecc.size; |
623 | int eccbytes = chip->ecc.bytes; | |
624 | int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; | |
625 | int eccsteps = chip->ecc.steps; | |
626 | const uint8_t *p = buf; | |
627 | uint8_t *oob = chip->oob_poi; | |
628 | ||
629 | chip->ecc.hwctl(mtd, NAND_ECC_WRITE); | |
630 | ||
631 | for (i = n = 0; | |
632 | eccsteps; | |
633 | n++, eccsteps--, i += eccbytes, p += eccsize) { | |
634 | host->col_addr = n * eccsize; | |
635 | ||
636 | chip->write_buf(mtd, p, eccsize); | |
637 | ||
638 | host->col_addr = mtd->writesize + n * eccpitch; | |
639 | ||
640 | if (chip->ecc.prepad) { | |
641 | chip->write_buf(mtd, oob, chip->ecc.prepad); | |
642 | oob += chip->ecc.prepad; | |
643 | } | |
644 | ||
645 | chip->write_buf(mtd, oob, eccbytes); | |
646 | oob += eccbytes; | |
647 | ||
648 | if (chip->ecc.postpad) { | |
649 | chip->write_buf(mtd, oob, chip->ecc.postpad); | |
650 | oob += chip->ecc.postpad; | |
651 | } | |
652 | } | |
653 | ||
654 | /* Calculate remaining oob bytes */ | |
655 | i = mtd->oobsize - (oob - chip->oob_poi); | |
656 | if (i) | |
657 | chip->write_buf(mtd, oob, i); | |
dfe64e2c | 658 | return 0; |
b081c2e9 JR |
659 | } |
660 | ||
661 | static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, | |
662 | u_char *read_ecc, u_char *calc_ecc) | |
663 | { | |
17cb4b8f SW |
664 | struct nand_chip *nand_chip = mtd_to_nand(mtd); |
665 | struct mxc_nand_host *host = nand_get_controller_data(nand_chip); | |
c1db8dd6 | 666 | uint32_t ecc_status = readl(&host->regs->ecc_status_result); |
b081c2e9 JR |
667 | int subpages = mtd->writesize / nand_chip->subpagesize; |
668 | int pg2blk_shift = nand_chip->phys_erase_shift - | |
669 | nand_chip->page_shift; | |
670 | ||
671 | do { | |
672 | if ((ecc_status & 0xf) > 4) { | |
673 | static int last_bad = -1; | |
674 | ||
675 | if (last_bad != host->page_addr >> pg2blk_shift) { | |
676 | last_bad = host->page_addr >> pg2blk_shift; | |
677 | printk(KERN_DEBUG | |
678 | "MXC_NAND: HWECC uncorrectable ECC error" | |
679 | " in block %u page %u subpage %d\n", | |
680 | last_bad, host->page_addr, | |
681 | mtd->writesize / nand_chip->subpagesize | |
682 | - subpages); | |
683 | } | |
684 | return -1; | |
685 | } | |
686 | ecc_status >>= 4; | |
687 | subpages--; | |
688 | } while (subpages > 0); | |
689 | ||
690 | return 0; | |
691 | } | |
692 | #else | |
693 | #define mxc_nand_read_page_syndrome NULL | |
694 | #define mxc_nand_read_page_raw_syndrome NULL | |
695 | #define mxc_nand_read_oob_syndrome NULL | |
696 | #define mxc_nand_write_page_syndrome NULL | |
697 | #define mxc_nand_write_page_raw_syndrome NULL | |
698 | #define mxc_nand_write_oob_syndrome NULL | |
b081c2e9 | 699 | |
36fab997 IY |
700 | static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, |
701 | u_char *read_ecc, u_char *calc_ecc) | |
702 | { | |
17cb4b8f SW |
703 | struct nand_chip *nand_chip = mtd_to_nand(mtd); |
704 | struct mxc_nand_host *host = nand_get_controller_data(nand_chip); | |
36fab997 IY |
705 | |
706 | /* | |
707 | * 1-Bit errors are automatically corrected in HW. No need for | |
708 | * additional correction. 2-Bit errors cannot be corrected by | |
709 | * HW ECC, so we need to return failure | |
710 | */ | |
2dc0aa02 | 711 | uint16_t ecc_status = readnfc(&host->regs->ecc_status_result); |
36fab997 IY |
712 | |
713 | if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { | |
714 | MTDDEBUG(MTD_DEBUG_LEVEL0, | |
715 | "MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); | |
716 | return -1; | |
717 | } | |
718 | ||
719 | return 0; | |
720 | } | |
b081c2e9 JR |
721 | #endif |
722 | ||
36fab997 IY |
723 | static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, |
724 | u_char *ecc_code) | |
725 | { | |
726 | return 0; | |
727 | } | |
728 | #endif | |
729 | ||
730 | static u_char mxc_nand_read_byte(struct mtd_info *mtd) | |
731 | { | |
17cb4b8f SW |
732 | struct nand_chip *nand_chip = mtd_to_nand(mtd); |
733 | struct mxc_nand_host *host = nand_get_controller_data(nand_chip); | |
36fab997 IY |
734 | uint8_t ret = 0; |
735 | uint16_t col; | |
736 | uint16_t __iomem *main_buf = | |
b081c2e9 | 737 | (uint16_t __iomem *)host->regs->main_area[0]; |
36fab997 | 738 | uint16_t __iomem *spare_buf = |
b081c2e9 | 739 | (uint16_t __iomem *)host->regs->spare_area[0]; |
36fab997 IY |
740 | union { |
741 | uint16_t word; | |
742 | uint8_t bytes[2]; | |
743 | } nfc_word; | |
744 | ||
745 | /* Check for status request */ | |
746 | if (host->status_request) | |
747 | return get_dev_status(host) & 0xFF; | |
748 | ||
749 | /* Get column for 16-bit access */ | |
750 | col = host->col_addr >> 1; | |
751 | ||
752 | /* If we are accessing the spare region */ | |
753 | if (host->spare_only) | |
754 | nfc_word.word = readw(&spare_buf[col]); | |
755 | else | |
756 | nfc_word.word = readw(&main_buf[col]); | |
757 | ||
758 | /* Pick upper/lower byte of word from RAM buffer */ | |
759 | ret = nfc_word.bytes[host->col_addr & 0x1]; | |
760 | ||
761 | /* Update saved column address */ | |
762 | if (nand_chip->options & NAND_BUSWIDTH_16) | |
763 | host->col_addr += 2; | |
764 | else | |
765 | host->col_addr++; | |
766 | ||
767 | return ret; | |
768 | } | |
769 | ||
770 | static uint16_t mxc_nand_read_word(struct mtd_info *mtd) | |
771 | { | |
17cb4b8f SW |
772 | struct nand_chip *nand_chip = mtd_to_nand(mtd); |
773 | struct mxc_nand_host *host = nand_get_controller_data(nand_chip); | |
36fab997 IY |
774 | uint16_t col, ret; |
775 | uint16_t __iomem *p; | |
776 | ||
777 | MTDDEBUG(MTD_DEBUG_LEVEL3, | |
778 | "mxc_nand_read_word(col = %d)\n", host->col_addr); | |
779 | ||
780 | col = host->col_addr; | |
781 | /* Adjust saved column address */ | |
782 | if (col < mtd->writesize && host->spare_only) | |
783 | col += mtd->writesize; | |
784 | ||
785 | if (col < mtd->writesize) { | |
b081c2e9 JR |
786 | p = (uint16_t __iomem *)(host->regs->main_area[0] + |
787 | (col >> 1)); | |
36fab997 | 788 | } else { |
b081c2e9 | 789 | p = (uint16_t __iomem *)(host->regs->spare_area[0] + |
36fab997 IY |
790 | ((col - mtd->writesize) >> 1)); |
791 | } | |
792 | ||
793 | if (col & 1) { | |
794 | union { | |
795 | uint16_t word; | |
796 | uint8_t bytes[2]; | |
797 | } nfc_word[3]; | |
798 | ||
799 | nfc_word[0].word = readw(p); | |
800 | nfc_word[1].word = readw(p + 1); | |
801 | ||
802 | nfc_word[2].bytes[0] = nfc_word[0].bytes[1]; | |
803 | nfc_word[2].bytes[1] = nfc_word[1].bytes[0]; | |
804 | ||
805 | ret = nfc_word[2].word; | |
806 | } else { | |
807 | ret = readw(p); | |
808 | } | |
809 | ||
810 | /* Update saved column address */ | |
811 | host->col_addr = col + 2; | |
812 | ||
813 | return ret; | |
814 | } | |
815 | ||
816 | /* | |
817 | * Write data of length len to buffer buf. The data to be | |
818 | * written on NAND Flash is first copied to RAMbuffer. After the Data Input | |
819 | * Operation by the NFC, the data is written to NAND Flash | |
820 | */ | |
821 | static void mxc_nand_write_buf(struct mtd_info *mtd, | |
822 | const u_char *buf, int len) | |
823 | { | |
17cb4b8f SW |
824 | struct nand_chip *nand_chip = mtd_to_nand(mtd); |
825 | struct mxc_nand_host *host = nand_get_controller_data(nand_chip); | |
36fab997 IY |
826 | int n, col, i = 0; |
827 | ||
828 | MTDDEBUG(MTD_DEBUG_LEVEL3, | |
829 | "mxc_nand_write_buf(col = %d, len = %d)\n", host->col_addr, | |
830 | len); | |
831 | ||
832 | col = host->col_addr; | |
833 | ||
834 | /* Adjust saved column address */ | |
835 | if (col < mtd->writesize && host->spare_only) | |
836 | col += mtd->writesize; | |
837 | ||
838 | n = mtd->writesize + mtd->oobsize - col; | |
839 | n = min(len, n); | |
840 | ||
841 | MTDDEBUG(MTD_DEBUG_LEVEL3, | |
842 | "%s:%d: col = %d, n = %d\n", __func__, __LINE__, col, n); | |
843 | ||
844 | while (n > 0) { | |
845 | void __iomem *p; | |
846 | ||
847 | if (col < mtd->writesize) { | |
b081c2e9 | 848 | p = host->regs->main_area[0] + (col & ~3); |
36fab997 | 849 | } else { |
b081c2e9 | 850 | p = host->regs->spare_area[0] - |
36fab997 IY |
851 | mtd->writesize + (col & ~3); |
852 | } | |
853 | ||
854 | MTDDEBUG(MTD_DEBUG_LEVEL3, "%s:%d: p = %p\n", __func__, | |
855 | __LINE__, p); | |
856 | ||
857 | if (((col | (unsigned long)&buf[i]) & 3) || n < 4) { | |
858 | union { | |
859 | uint32_t word; | |
860 | uint8_t bytes[4]; | |
861 | } nfc_word; | |
862 | ||
863 | nfc_word.word = readl(p); | |
864 | nfc_word.bytes[col & 3] = buf[i++]; | |
865 | n--; | |
866 | col++; | |
867 | ||
868 | writel(nfc_word.word, p); | |
869 | } else { | |
870 | int m = mtd->writesize - col; | |
871 | ||
872 | if (col >= mtd->writesize) | |
873 | m += mtd->oobsize; | |
874 | ||
875 | m = min(n, m) & ~3; | |
876 | ||
877 | MTDDEBUG(MTD_DEBUG_LEVEL3, | |
878 | "%s:%d: n = %d, m = %d, i = %d, col = %d\n", | |
879 | __func__, __LINE__, n, m, i, col); | |
880 | ||
881 | mxc_nand_memcpy32(p, (uint32_t *)&buf[i], m); | |
882 | col += m; | |
883 | i += m; | |
884 | n -= m; | |
885 | } | |
886 | } | |
887 | /* Update saved column address */ | |
888 | host->col_addr = col; | |
889 | } | |
890 | ||
891 | /* | |
892 | * Read the data buffer from the NAND Flash. To read the data from NAND | |
893 | * Flash first the data output cycle is initiated by the NFC, which copies | |
894 | * the data to RAMbuffer. This data of length len is then copied to buffer buf. | |
895 | */ | |
896 | static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) | |
897 | { | |
17cb4b8f SW |
898 | struct nand_chip *nand_chip = mtd_to_nand(mtd); |
899 | struct mxc_nand_host *host = nand_get_controller_data(nand_chip); | |
36fab997 IY |
900 | int n, col, i = 0; |
901 | ||
902 | MTDDEBUG(MTD_DEBUG_LEVEL3, | |
903 | "mxc_nand_read_buf(col = %d, len = %d)\n", host->col_addr, len); | |
904 | ||
905 | col = host->col_addr; | |
906 | ||
907 | /* Adjust saved column address */ | |
908 | if (col < mtd->writesize && host->spare_only) | |
909 | col += mtd->writesize; | |
910 | ||
911 | n = mtd->writesize + mtd->oobsize - col; | |
912 | n = min(len, n); | |
913 | ||
914 | while (n > 0) { | |
915 | void __iomem *p; | |
916 | ||
917 | if (col < mtd->writesize) { | |
b081c2e9 | 918 | p = host->regs->main_area[0] + (col & ~3); |
36fab997 | 919 | } else { |
b081c2e9 | 920 | p = host->regs->spare_area[0] - |
36fab997 IY |
921 | mtd->writesize + (col & ~3); |
922 | } | |
923 | ||
924 | if (((col | (int)&buf[i]) & 3) || n < 4) { | |
925 | union { | |
926 | uint32_t word; | |
927 | uint8_t bytes[4]; | |
928 | } nfc_word; | |
929 | ||
930 | nfc_word.word = readl(p); | |
931 | buf[i++] = nfc_word.bytes[col & 3]; | |
932 | n--; | |
933 | col++; | |
934 | } else { | |
935 | int m = mtd->writesize - col; | |
936 | ||
937 | if (col >= mtd->writesize) | |
938 | m += mtd->oobsize; | |
939 | ||
940 | m = min(n, m) & ~3; | |
941 | mxc_nand_memcpy32((uint32_t *)&buf[i], p, m); | |
942 | ||
943 | col += m; | |
944 | i += m; | |
945 | n -= m; | |
946 | } | |
947 | } | |
948 | /* Update saved column address */ | |
949 | host->col_addr = col; | |
950 | } | |
951 | ||
36fab997 IY |
952 | /* |
953 | * This function is used by upper layer for select and | |
954 | * deselect of the NAND chip | |
955 | */ | |
956 | static void mxc_nand_select_chip(struct mtd_info *mtd, int chip) | |
957 | { | |
17cb4b8f SW |
958 | struct nand_chip *nand_chip = mtd_to_nand(mtd); |
959 | struct mxc_nand_host *host = nand_get_controller_data(nand_chip); | |
36fab997 IY |
960 | |
961 | switch (chip) { | |
962 | case -1: | |
963 | /* TODO: Disable the NFC clock */ | |
964 | if (host->clk_act) | |
965 | host->clk_act = 0; | |
966 | break; | |
967 | case 0: | |
968 | /* TODO: Enable the NFC clock */ | |
969 | if (!host->clk_act) | |
970 | host->clk_act = 1; | |
971 | break; | |
972 | ||
973 | default: | |
974 | break; | |
975 | } | |
976 | } | |
977 | ||
978 | /* | |
979 | * Used by the upper layer to write command to NAND Flash for | |
980 | * different operations to be carried out on NAND Flash | |
981 | */ | |
b081c2e9 | 982 | void mxc_nand_command(struct mtd_info *mtd, unsigned command, |
36fab997 IY |
983 | int column, int page_addr) |
984 | { | |
17cb4b8f SW |
985 | struct nand_chip *nand_chip = mtd_to_nand(mtd); |
986 | struct mxc_nand_host *host = nand_get_controller_data(nand_chip); | |
36fab997 IY |
987 | |
988 | MTDDEBUG(MTD_DEBUG_LEVEL3, | |
989 | "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", | |
990 | command, column, page_addr); | |
991 | ||
992 | /* Reset command state information */ | |
993 | host->status_request = false; | |
994 | ||
995 | /* Command pre-processing step */ | |
996 | switch (command) { | |
997 | ||
998 | case NAND_CMD_STATUS: | |
999 | host->col_addr = 0; | |
1000 | host->status_request = true; | |
1001 | break; | |
1002 | ||
1003 | case NAND_CMD_READ0: | |
b081c2e9 | 1004 | host->page_addr = page_addr; |
36fab997 IY |
1005 | host->col_addr = column; |
1006 | host->spare_only = false; | |
1007 | break; | |
1008 | ||
1009 | case NAND_CMD_READOOB: | |
1010 | host->col_addr = column; | |
1011 | host->spare_only = true; | |
1012 | if (host->pagesize_2k) | |
1013 | command = NAND_CMD_READ0; /* only READ0 is valid */ | |
1014 | break; | |
1015 | ||
1016 | case NAND_CMD_SEQIN: | |
1017 | if (column >= mtd->writesize) { | |
1018 | /* | |
1019 | * before sending SEQIN command for partial write, | |
1020 | * we need read one page out. FSL NFC does not support | |
780f30b6 | 1021 | * partial write. It always sends out 512+ecc+512+ecc |
36fab997 IY |
1022 | * for large page nand flash. But for small page nand |
1023 | * flash, it does support SPARE ONLY operation. | |
1024 | */ | |
1025 | if (host->pagesize_2k) { | |
1026 | /* call ourself to read a page */ | |
1027 | mxc_nand_command(mtd, NAND_CMD_READ0, 0, | |
1028 | page_addr); | |
1029 | } | |
1030 | ||
1031 | host->col_addr = column - mtd->writesize; | |
1032 | host->spare_only = true; | |
1033 | ||
1034 | /* Set program pointer to spare region */ | |
1035 | if (!host->pagesize_2k) | |
1036 | send_cmd(host, NAND_CMD_READOOB); | |
1037 | } else { | |
1038 | host->spare_only = false; | |
1039 | host->col_addr = column; | |
1040 | ||
1041 | /* Set program pointer to page start */ | |
1042 | if (!host->pagesize_2k) | |
1043 | send_cmd(host, NAND_CMD_READ0); | |
1044 | } | |
1045 | break; | |
1046 | ||
1047 | case NAND_CMD_PAGEPROG: | |
1048 | send_prog_page(host, 0, host->spare_only); | |
1049 | ||
9c60e75e | 1050 | if (host->pagesize_2k && is_mxc_nfc_1()) { |
780f30b6 | 1051 | /* data in 4 areas */ |
36fab997 IY |
1052 | send_prog_page(host, 1, host->spare_only); |
1053 | send_prog_page(host, 2, host->spare_only); | |
1054 | send_prog_page(host, 3, host->spare_only); | |
1055 | } | |
1056 | ||
1057 | break; | |
1058 | } | |
1059 | ||
1060 | /* Write out the command to the device. */ | |
1061 | send_cmd(host, command); | |
1062 | ||
1063 | /* Write out column address, if necessary */ | |
1064 | if (column != -1) { | |
1065 | /* | |
1066 | * MXC NANDFC can only perform full page+spare or | |
780f30b6 HR |
1067 | * spare-only read/write. When the upper layers perform |
1068 | * a read/write buffer operation, we will use the saved | |
1069 | * column address to index into the full page. | |
36fab997 IY |
1070 | */ |
1071 | send_addr(host, 0); | |
1072 | if (host->pagesize_2k) | |
1073 | /* another col addr cycle for 2k page */ | |
1074 | send_addr(host, 0); | |
1075 | } | |
1076 | ||
1077 | /* Write out page address, if necessary */ | |
1078 | if (page_addr != -1) { | |
b081c2e9 JR |
1079 | u32 page_mask = nand_chip->pagemask; |
1080 | do { | |
1081 | send_addr(host, page_addr & 0xFF); | |
1082 | page_addr >>= 8; | |
1083 | page_mask >>= 8; | |
1084 | } while (page_mask); | |
36fab997 IY |
1085 | } |
1086 | ||
1087 | /* Command post-processing step */ | |
1088 | switch (command) { | |
1089 | ||
1090 | case NAND_CMD_RESET: | |
1091 | break; | |
1092 | ||
1093 | case NAND_CMD_READOOB: | |
1094 | case NAND_CMD_READ0: | |
1095 | if (host->pagesize_2k) { | |
1096 | /* send read confirm command */ | |
1097 | send_cmd(host, NAND_CMD_READSTART); | |
1098 | /* read for each AREA */ | |
1099 | send_read_page(host, 0, host->spare_only); | |
9c60e75e | 1100 | if (is_mxc_nfc_1()) { |
b081c2e9 JR |
1101 | send_read_page(host, 1, host->spare_only); |
1102 | send_read_page(host, 2, host->spare_only); | |
1103 | send_read_page(host, 3, host->spare_only); | |
1104 | } | |
36fab997 IY |
1105 | } else { |
1106 | send_read_page(host, 0, host->spare_only); | |
1107 | } | |
1108 | break; | |
1109 | ||
1110 | case NAND_CMD_READID: | |
1111 | host->col_addr = 0; | |
1112 | send_read_id(host); | |
1113 | break; | |
1114 | ||
1115 | case NAND_CMD_PAGEPROG: | |
1116 | break; | |
1117 | ||
1118 | case NAND_CMD_STATUS: | |
1119 | break; | |
1120 | ||
1121 | case NAND_CMD_ERASE2: | |
1122 | break; | |
1123 | } | |
1124 | } | |
1125 | ||
a1028730 TK |
1126 | #ifdef CONFIG_SYS_NAND_USE_FLASH_BBT |
1127 | ||
1128 | static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; | |
1129 | static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; | |
1130 | ||
1131 | static struct nand_bbt_descr bbt_main_descr = { | |
1132 | .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | | |
1133 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, | |
1134 | .offs = 0, | |
1135 | .len = 4, | |
1136 | .veroffs = 4, | |
1137 | .maxblocks = 4, | |
1138 | .pattern = bbt_pattern, | |
1139 | }; | |
1140 | ||
1141 | static struct nand_bbt_descr bbt_mirror_descr = { | |
1142 | .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | | |
1143 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, | |
1144 | .offs = 0, | |
1145 | .len = 4, | |
1146 | .veroffs = 4, | |
1147 | .maxblocks = 4, | |
1148 | .pattern = mirror_pattern, | |
1149 | }; | |
1150 | ||
1151 | #endif | |
1152 | ||
36fab997 IY |
1153 | int board_nand_init(struct nand_chip *this) |
1154 | { | |
36fab997 | 1155 | struct mtd_info *mtd; |
35537bc7 BT |
1156 | #if defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2) |
1157 | uint32_t tmp; | |
efa1f43b | 1158 | #endif |
36fab997 | 1159 | |
a1028730 | 1160 | #ifdef CONFIG_SYS_NAND_USE_FLASH_BBT |
dfe64e2c | 1161 | this->bbt_options |= NAND_BBT_USE_FLASH; |
a1028730 TK |
1162 | this->bbt_td = &bbt_main_descr; |
1163 | this->bbt_md = &bbt_mirror_descr; | |
1164 | #endif | |
1165 | ||
36fab997 | 1166 | /* structures must be linked */ |
b616d9b0 | 1167 | mtd = &this->mtd; |
36fab997 IY |
1168 | host->nand = this; |
1169 | ||
1170 | /* 5 us command delay time */ | |
1171 | this->chip_delay = 5; | |
1172 | ||
17cb4b8f | 1173 | nand_set_controller_data(this, host); |
36fab997 IY |
1174 | this->dev_ready = mxc_nand_dev_ready; |
1175 | this->cmdfunc = mxc_nand_command; | |
1176 | this->select_chip = mxc_nand_select_chip; | |
1177 | this->read_byte = mxc_nand_read_byte; | |
1178 | this->read_word = mxc_nand_read_word; | |
1179 | this->write_buf = mxc_nand_write_buf; | |
1180 | this->read_buf = mxc_nand_read_buf; | |
36fab997 | 1181 | |
da962b71 | 1182 | host->regs = (struct mxc_nand_regs __iomem *)CONFIG_MXC_NAND_REGS_BASE; |
35537bc7 BT |
1183 | #ifdef MXC_NFC_V3_2 |
1184 | host->ip_regs = | |
da962b71 | 1185 | (struct mxc_nand_ip_regs __iomem *)CONFIG_MXC_NAND_IP_REGS_BASE; |
35537bc7 | 1186 | #endif |
36fab997 IY |
1187 | host->clk_act = 1; |
1188 | ||
1189 | #ifdef CONFIG_MXC_NAND_HWECC | |
1190 | this->ecc.calculate = mxc_nand_calculate_ecc; | |
1191 | this->ecc.hwctl = mxc_nand_enable_hwecc; | |
1192 | this->ecc.correct = mxc_nand_correct_data; | |
35537bc7 | 1193 | if (is_mxc_nfc_21() || is_mxc_nfc_32()) { |
b081c2e9 JR |
1194 | this->ecc.mode = NAND_ECC_HW_SYNDROME; |
1195 | this->ecc.read_page = mxc_nand_read_page_syndrome; | |
1196 | this->ecc.read_page_raw = mxc_nand_read_page_raw_syndrome; | |
1197 | this->ecc.read_oob = mxc_nand_read_oob_syndrome; | |
1198 | this->ecc.write_page = mxc_nand_write_page_syndrome; | |
1199 | this->ecc.write_page_raw = mxc_nand_write_page_raw_syndrome; | |
1200 | this->ecc.write_oob = mxc_nand_write_oob_syndrome; | |
1201 | this->ecc.bytes = 9; | |
1202 | this->ecc.prepad = 7; | |
1203 | } else { | |
1204 | this->ecc.mode = NAND_ECC_HW; | |
1205 | } | |
1206 | ||
1c903694 MV |
1207 | if (is_mxc_nfc_1()) |
1208 | this->ecc.strength = 1; | |
1209 | else | |
1210 | this->ecc.strength = 4; | |
dfe64e2c | 1211 | |
b081c2e9 JR |
1212 | host->pagesize_2k = 0; |
1213 | ||
36fab997 | 1214 | this->ecc.size = 512; |
0e499b07 | 1215 | _mxc_nand_enable_hwecc(mtd, 1); |
36fab997 IY |
1216 | #else |
1217 | this->ecc.layout = &nand_soft_eccoob; | |
1218 | this->ecc.mode = NAND_ECC_SOFT; | |
0e499b07 | 1219 | _mxc_nand_enable_hwecc(mtd, 0); |
36fab997 | 1220 | #endif |
36fab997 IY |
1221 | /* Reset NAND */ |
1222 | this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); | |
1223 | ||
13927f07 BT |
1224 | /* NAND bus width determines access functions used by upper layer */ |
1225 | if (is_16bit_nand()) | |
1226 | this->options |= NAND_BUSWIDTH_16; | |
1227 | ||
1228 | #ifdef CONFIG_SYS_NAND_LARGEPAGE | |
1229 | host->pagesize_2k = 1; | |
1230 | this->ecc.layout = &nand_hw_eccoob2k; | |
1231 | #else | |
1232 | host->pagesize_2k = 0; | |
1233 | this->ecc.layout = &nand_hw_eccoob; | |
1234 | #endif | |
1235 | ||
35537bc7 | 1236 | #if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) |
9c60e75e | 1237 | #ifdef MXC_NFC_V2_1 |
2dc0aa02 BT |
1238 | tmp = readnfc(&host->regs->config1); |
1239 | tmp |= NFC_V2_CONFIG1_ONE_CYCLE; | |
1240 | tmp |= NFC_V2_CONFIG1_ECC_MODE_4; | |
1241 | writenfc(tmp, &host->regs->config1); | |
13927f07 | 1242 | if (host->pagesize_2k) |
2dc0aa02 | 1243 | writenfc(64/2, &host->regs->spare_area_size); |
13927f07 | 1244 | else |
2dc0aa02 | 1245 | writenfc(16/2, &host->regs->spare_area_size); |
13927f07 BT |
1246 | #endif |
1247 | ||
36fab997 IY |
1248 | /* |
1249 | * preset operation | |
1250 | * Unlock the internal RAM Buffer | |
1251 | */ | |
2dc0aa02 | 1252 | writenfc(0x2, &host->regs->config); |
36fab997 IY |
1253 | |
1254 | /* Blocks to be unlocked */ | |
2dc0aa02 | 1255 | writenfc(0x0, &host->regs->unlockstart_blkaddr); |
b4b1e769 HR |
1256 | /* Originally (Freescale LTIB 2.6.21) 0x4000 was written to the |
1257 | * unlockend_blkaddr, but the magic 0x4000 does not always work | |
1258 | * when writing more than some 32 megabytes (on 2k page nands) | |
1259 | * However 0xFFFF doesn't seem to have this kind | |
1260 | * of limitation (tried it back and forth several times). | |
1261 | * The linux kernel driver sets this to 0xFFFF for the v2 controller | |
1262 | * only, but probably this was not tested there for v1. | |
1263 | * The very same limitation seems to apply to this kernel driver. | |
1264 | * This might be NAND chip specific and the i.MX31 datasheet is | |
1265 | * extremely vague about the semantics of this register. | |
1266 | */ | |
2dc0aa02 | 1267 | writenfc(0xFFFF, &host->regs->unlockend_blkaddr); |
36fab997 IY |
1268 | |
1269 | /* Unlock Block Command for given address range */ | |
2dc0aa02 | 1270 | writenfc(0x4, &host->regs->wrprot); |
35537bc7 BT |
1271 | #elif defined(MXC_NFC_V3_2) |
1272 | writenfc(NFC_V3_CONFIG1_RBA(0), &host->regs->config1); | |
1273 | writenfc(NFC_V3_IPC_CREQ, &host->ip_regs->ipc); | |
1274 | ||
1275 | /* Unlock the internal RAM Buffer */ | |
1276 | writenfc(NFC_V3_WRPROT_BLS_UNLOCK | NFC_V3_WRPROT_UNLOCK, | |
1277 | &host->ip_regs->wrprot); | |
1278 | ||
1279 | /* Blocks to be unlocked */ | |
1280 | for (tmp = 0; tmp < CONFIG_SYS_NAND_MAX_CHIPS; tmp++) | |
1281 | writenfc(0x0 | 0xFFFF << 16, | |
1282 | &host->ip_regs->wrprot_unlock_blkaddr[tmp]); | |
1283 | ||
1284 | writenfc(0, &host->ip_regs->ipc); | |
1285 | ||
1286 | tmp = readnfc(&host->ip_regs->config2); | |
1287 | tmp &= ~(NFC_V3_CONFIG2_SPAS_MASK | NFC_V3_CONFIG2_EDC_MASK | | |
1288 | NFC_V3_CONFIG2_ECC_MODE_8 | NFC_V3_CONFIG2_PS_MASK); | |
1289 | tmp |= NFC_V3_CONFIG2_ONE_CYCLE; | |
1290 | ||
1291 | if (host->pagesize_2k) { | |
1292 | tmp |= NFC_V3_CONFIG2_SPAS(64/2); | |
1293 | tmp |= NFC_V3_CONFIG2_PS_2048; | |
1294 | } else { | |
1295 | tmp |= NFC_V3_CONFIG2_SPAS(16/2); | |
1296 | tmp |= NFC_V3_CONFIG2_PS_512; | |
1297 | } | |
1298 | ||
1299 | writenfc(tmp, &host->ip_regs->config2); | |
1300 | ||
1301 | tmp = NFC_V3_CONFIG3_NUM_OF_DEVS(0) | | |
1302 | NFC_V3_CONFIG3_NO_SDMA | | |
1303 | NFC_V3_CONFIG3_RBB_MODE | | |
1304 | NFC_V3_CONFIG3_SBB(6) | /* Reset default */ | |
1305 | NFC_V3_CONFIG3_ADD_OP(0); | |
1306 | ||
1307 | if (!(this->options & NAND_BUSWIDTH_16)) | |
1308 | tmp |= NFC_V3_CONFIG3_FW8; | |
1309 | ||
1310 | writenfc(tmp, &host->ip_regs->config3); | |
1311 | ||
1312 | writenfc(0, &host->ip_regs->delay_line); | |
1313 | #endif | |
36fab997 | 1314 | |
365b2c07 | 1315 | return 0; |
36fab997 | 1316 | } |