]>
Commit | Line | Data |
---|---|---|
42cb1403 | 1 | /* |
42cb1403 AV |
2 | * Copyright (C) 2003 Rick Bronson |
3 | * | |
4 | * Derived from drivers/mtd/nand/autcpu12.c | |
5 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) | |
6 | * | |
7 | * Derived from drivers/mtd/spia.c | |
8 | * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) | |
9 | * | |
77f5492c RG |
10 | * |
11 | * Add Hardware ECC support for AT91SAM9260 / AT91SAM9263 | |
12 | * Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright (C) 2007 | |
13 | * | |
14 | * Derived from Das U-Boot source code | |
15 | * (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c) | |
16 | * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas | |
17 | * | |
18 | * | |
42cb1403 AV |
19 | * This program is free software; you can redistribute it and/or modify |
20 | * it under the terms of the GNU General Public License version 2 as | |
21 | * published by the Free Software Foundation. | |
22 | * | |
23 | */ | |
24 | ||
b7f080cf | 25 | #include <linux/dma-mapping.h> |
42cb1403 AV |
26 | #include <linux/slab.h> |
27 | #include <linux/module.h> | |
f4fa697c | 28 | #include <linux/moduleparam.h> |
42cb1403 | 29 | #include <linux/platform_device.h> |
d6a01661 JCPV |
30 | #include <linux/of.h> |
31 | #include <linux/of_device.h> | |
32 | #include <linux/of_gpio.h> | |
33 | #include <linux/of_mtd.h> | |
42cb1403 AV |
34 | #include <linux/mtd/mtd.h> |
35 | #include <linux/mtd/nand.h> | |
36 | #include <linux/mtd/partitions.h> | |
37 | ||
5c39c4c5 | 38 | #include <linux/dmaengine.h> |
90574d0a DW |
39 | #include <linux/gpio.h> |
40 | #include <linux/io.h> | |
bf4289cb | 41 | #include <linux/platform_data/atmel.h> |
42cb1403 | 42 | |
a09e64fb | 43 | #include <mach/cpu.h> |
42cb1403 | 44 | |
cbc6c5e7 HX |
45 | static int use_dma = 1; |
46 | module_param(use_dma, int, 0); | |
47 | ||
f4fa697c SP |
48 | static int on_flash_bbt = 0; |
49 | module_param(on_flash_bbt, int, 0); | |
50 | ||
77f5492c RG |
51 | /* Register access macros */ |
52 | #define ecc_readl(add, reg) \ | |
3c3796cc | 53 | __raw_readl(add + ATMEL_ECC_##reg) |
77f5492c | 54 | #define ecc_writel(add, reg, value) \ |
3c3796cc | 55 | __raw_writel((value), add + ATMEL_ECC_##reg) |
77f5492c | 56 | |
d4f4c0aa | 57 | #include "atmel_nand_ecc.h" /* Hardware ECC registers */ |
77f5492c RG |
58 | |
59 | /* oob layout for large page size | |
60 | * bad block info is on bytes 0 and 1 | |
61 | * the bytes have to be consecutives to avoid | |
62 | * several NAND_CMD_RNDOUT during read | |
63 | */ | |
3c3796cc | 64 | static struct nand_ecclayout atmel_oobinfo_large = { |
77f5492c RG |
65 | .eccbytes = 4, |
66 | .eccpos = {60, 61, 62, 63}, | |
67 | .oobfree = { | |
68 | {2, 58} | |
69 | }, | |
70 | }; | |
71 | ||
72 | /* oob layout for small page size | |
73 | * bad block info is on bytes 4 and 5 | |
74 | * the bytes have to be consecutives to avoid | |
75 | * several NAND_CMD_RNDOUT during read | |
76 | */ | |
3c3796cc | 77 | static struct nand_ecclayout atmel_oobinfo_small = { |
77f5492c RG |
78 | .eccbytes = 4, |
79 | .eccpos = {0, 1, 2, 3}, | |
80 | .oobfree = { | |
81 | {6, 10} | |
82 | }, | |
83 | }; | |
84 | ||
3c3796cc | 85 | struct atmel_nand_host { |
42cb1403 AV |
86 | struct nand_chip nand_chip; |
87 | struct mtd_info mtd; | |
88 | void __iomem *io_base; | |
cbc6c5e7 | 89 | dma_addr_t io_phys; |
d6a01661 | 90 | struct atmel_nand_data board; |
77f5492c RG |
91 | struct device *dev; |
92 | void __iomem *ecc; | |
cbc6c5e7 HX |
93 | |
94 | struct completion comp; | |
95 | struct dma_chan *dma_chan; | |
a41b51a1 JW |
96 | |
97 | bool has_pmecc; | |
98 | u8 pmecc_corr_cap; | |
99 | u16 pmecc_sector_size; | |
100 | u32 pmecc_lookup_table_offset; | |
42cb1403 AV |
101 | }; |
102 | ||
cbc6c5e7 HX |
103 | static int cpu_has_dma(void) |
104 | { | |
105 | return cpu_is_at91sam9rl() || cpu_is_at91sam9g45(); | |
106 | } | |
107 | ||
8136508c AN |
108 | /* |
109 | * Enable NAND. | |
110 | */ | |
3c3796cc | 111 | static void atmel_nand_enable(struct atmel_nand_host *host) |
8136508c | 112 | { |
d6a01661 JCPV |
113 | if (gpio_is_valid(host->board.enable_pin)) |
114 | gpio_set_value(host->board.enable_pin, 0); | |
8136508c AN |
115 | } |
116 | ||
117 | /* | |
118 | * Disable NAND. | |
119 | */ | |
3c3796cc | 120 | static void atmel_nand_disable(struct atmel_nand_host *host) |
8136508c | 121 | { |
d6a01661 JCPV |
122 | if (gpio_is_valid(host->board.enable_pin)) |
123 | gpio_set_value(host->board.enable_pin, 1); | |
8136508c AN |
124 | } |
125 | ||
42cb1403 AV |
126 | /* |
127 | * Hardware specific access to control-lines | |
128 | */ | |
3c3796cc | 129 | static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) |
42cb1403 AV |
130 | { |
131 | struct nand_chip *nand_chip = mtd->priv; | |
3c3796cc | 132 | struct atmel_nand_host *host = nand_chip->priv; |
42cb1403 | 133 | |
8136508c | 134 | if (ctrl & NAND_CTRL_CHANGE) { |
2314488e | 135 | if (ctrl & NAND_NCE) |
3c3796cc | 136 | atmel_nand_enable(host); |
2314488e | 137 | else |
3c3796cc | 138 | atmel_nand_disable(host); |
2314488e | 139 | } |
42cb1403 AV |
140 | if (cmd == NAND_CMD_NONE) |
141 | return; | |
142 | ||
143 | if (ctrl & NAND_CLE) | |
d6a01661 | 144 | writeb(cmd, host->io_base + (1 << host->board.cle)); |
42cb1403 | 145 | else |
d6a01661 | 146 | writeb(cmd, host->io_base + (1 << host->board.ale)); |
42cb1403 AV |
147 | } |
148 | ||
149 | /* | |
150 | * Read the Device Ready pin. | |
151 | */ | |
3c3796cc | 152 | static int atmel_nand_device_ready(struct mtd_info *mtd) |
42cb1403 AV |
153 | { |
154 | struct nand_chip *nand_chip = mtd->priv; | |
3c3796cc | 155 | struct atmel_nand_host *host = nand_chip->priv; |
42cb1403 | 156 | |
d6a01661 JCPV |
157 | return gpio_get_value(host->board.rdy_pin) ^ |
158 | !!host->board.rdy_pin_active_low; | |
42cb1403 AV |
159 | } |
160 | ||
50082319 AB |
161 | /* |
162 | * Minimal-overhead PIO for data access. | |
163 | */ | |
164 | static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len) | |
165 | { | |
166 | struct nand_chip *nand_chip = mtd->priv; | |
167 | ||
168 | __raw_readsb(nand_chip->IO_ADDR_R, buf, len); | |
169 | } | |
170 | ||
171 | static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len) | |
172 | { | |
173 | struct nand_chip *nand_chip = mtd->priv; | |
174 | ||
175 | __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2); | |
176 | } | |
177 | ||
178 | static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len) | |
179 | { | |
180 | struct nand_chip *nand_chip = mtd->priv; | |
181 | ||
182 | __raw_writesb(nand_chip->IO_ADDR_W, buf, len); | |
183 | } | |
184 | ||
185 | static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) | |
186 | { | |
187 | struct nand_chip *nand_chip = mtd->priv; | |
188 | ||
189 | __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2); | |
190 | } | |
191 | ||
cbc6c5e7 HX |
192 | static void dma_complete_func(void *completion) |
193 | { | |
194 | complete(completion); | |
195 | } | |
196 | ||
197 | static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len, | |
198 | int is_read) | |
199 | { | |
200 | struct dma_device *dma_dev; | |
201 | enum dma_ctrl_flags flags; | |
202 | dma_addr_t dma_src_addr, dma_dst_addr, phys_addr; | |
203 | struct dma_async_tx_descriptor *tx = NULL; | |
204 | dma_cookie_t cookie; | |
205 | struct nand_chip *chip = mtd->priv; | |
206 | struct atmel_nand_host *host = chip->priv; | |
207 | void *p = buf; | |
208 | int err = -EIO; | |
209 | enum dma_data_direction dir = is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE; | |
210 | ||
80b4f81a HX |
211 | if (buf >= high_memory) |
212 | goto err_buf; | |
cbc6c5e7 HX |
213 | |
214 | dma_dev = host->dma_chan->device; | |
215 | ||
216 | flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP | | |
217 | DMA_COMPL_SKIP_DEST_UNMAP; | |
218 | ||
219 | phys_addr = dma_map_single(dma_dev->dev, p, len, dir); | |
220 | if (dma_mapping_error(dma_dev->dev, phys_addr)) { | |
221 | dev_err(host->dev, "Failed to dma_map_single\n"); | |
222 | goto err_buf; | |
223 | } | |
224 | ||
225 | if (is_read) { | |
226 | dma_src_addr = host->io_phys; | |
227 | dma_dst_addr = phys_addr; | |
228 | } else { | |
229 | dma_src_addr = phys_addr; | |
230 | dma_dst_addr = host->io_phys; | |
231 | } | |
232 | ||
233 | tx = dma_dev->device_prep_dma_memcpy(host->dma_chan, dma_dst_addr, | |
234 | dma_src_addr, len, flags); | |
235 | if (!tx) { | |
236 | dev_err(host->dev, "Failed to prepare DMA memcpy\n"); | |
237 | goto err_dma; | |
238 | } | |
239 | ||
240 | init_completion(&host->comp); | |
241 | tx->callback = dma_complete_func; | |
242 | tx->callback_param = &host->comp; | |
243 | ||
244 | cookie = tx->tx_submit(tx); | |
245 | if (dma_submit_error(cookie)) { | |
246 | dev_err(host->dev, "Failed to do DMA tx_submit\n"); | |
247 | goto err_dma; | |
248 | } | |
249 | ||
250 | dma_async_issue_pending(host->dma_chan); | |
251 | wait_for_completion(&host->comp); | |
252 | ||
253 | err = 0; | |
254 | ||
255 | err_dma: | |
256 | dma_unmap_single(dma_dev->dev, phys_addr, len, dir); | |
257 | err_buf: | |
258 | if (err != 0) | |
259 | dev_warn(host->dev, "Fall back to CPU I/O\n"); | |
260 | return err; | |
261 | } | |
262 | ||
263 | static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) | |
264 | { | |
265 | struct nand_chip *chip = mtd->priv; | |
50082319 | 266 | struct atmel_nand_host *host = chip->priv; |
cbc6c5e7 | 267 | |
9d51567e NF |
268 | if (use_dma && len > mtd->oobsize) |
269 | /* only use DMA for bigger than oob size: better performances */ | |
cbc6c5e7 HX |
270 | if (atmel_nand_dma_op(mtd, buf, len, 1) == 0) |
271 | return; | |
272 | ||
d6a01661 | 273 | if (host->board.bus_width_16) |
50082319 AB |
274 | atmel_read_buf16(mtd, buf, len); |
275 | else | |
276 | atmel_read_buf8(mtd, buf, len); | |
cbc6c5e7 HX |
277 | } |
278 | ||
279 | static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) | |
280 | { | |
281 | struct nand_chip *chip = mtd->priv; | |
50082319 | 282 | struct atmel_nand_host *host = chip->priv; |
cbc6c5e7 | 283 | |
9d51567e NF |
284 | if (use_dma && len > mtd->oobsize) |
285 | /* only use DMA for bigger than oob size: better performances */ | |
cbc6c5e7 HX |
286 | if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) == 0) |
287 | return; | |
288 | ||
d6a01661 | 289 | if (host->board.bus_width_16) |
50082319 AB |
290 | atmel_write_buf16(mtd, buf, len); |
291 | else | |
292 | atmel_write_buf8(mtd, buf, len); | |
cbc6c5e7 HX |
293 | } |
294 | ||
77f5492c RG |
295 | /* |
296 | * Calculate HW ECC | |
297 | * | |
298 | * function called after a write | |
299 | * | |
300 | * mtd: MTD block structure | |
301 | * dat: raw data (unused) | |
302 | * ecc_code: buffer for ECC | |
303 | */ | |
3c3796cc | 304 | static int atmel_nand_calculate(struct mtd_info *mtd, |
77f5492c RG |
305 | const u_char *dat, unsigned char *ecc_code) |
306 | { | |
307 | struct nand_chip *nand_chip = mtd->priv; | |
3c3796cc | 308 | struct atmel_nand_host *host = nand_chip->priv; |
77f5492c RG |
309 | unsigned int ecc_value; |
310 | ||
311 | /* get the first 2 ECC bytes */ | |
d43fa149 | 312 | ecc_value = ecc_readl(host->ecc, PR); |
77f5492c | 313 | |
3fc23898 RG |
314 | ecc_code[0] = ecc_value & 0xFF; |
315 | ecc_code[1] = (ecc_value >> 8) & 0xFF; | |
77f5492c RG |
316 | |
317 | /* get the last 2 ECC bytes */ | |
3c3796cc | 318 | ecc_value = ecc_readl(host->ecc, NPR) & ATMEL_ECC_NPARITY; |
77f5492c | 319 | |
3fc23898 RG |
320 | ecc_code[2] = ecc_value & 0xFF; |
321 | ecc_code[3] = (ecc_value >> 8) & 0xFF; | |
77f5492c RG |
322 | |
323 | return 0; | |
324 | } | |
325 | ||
326 | /* | |
327 | * HW ECC read page function | |
328 | * | |
329 | * mtd: mtd info structure | |
330 | * chip: nand chip info structure | |
331 | * buf: buffer to store read data | |
1fbb938d | 332 | * oob_required: caller expects OOB data read to chip->oob_poi |
77f5492c | 333 | */ |
1fbb938d BN |
334 | static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, |
335 | uint8_t *buf, int oob_required, int page) | |
77f5492c RG |
336 | { |
337 | int eccsize = chip->ecc.size; | |
338 | int eccbytes = chip->ecc.bytes; | |
339 | uint32_t *eccpos = chip->ecc.layout->eccpos; | |
340 | uint8_t *p = buf; | |
341 | uint8_t *oob = chip->oob_poi; | |
342 | uint8_t *ecc_pos; | |
343 | int stat; | |
3f91e94f | 344 | unsigned int max_bitflips = 0; |
77f5492c | 345 | |
d6248fdd HS |
346 | /* |
347 | * Errata: ALE is incorrectly wired up to the ECC controller | |
348 | * on the AP7000, so it will include the address cycles in the | |
349 | * ECC calculation. | |
350 | * | |
351 | * Workaround: Reset the parity registers before reading the | |
352 | * actual data. | |
353 | */ | |
354 | if (cpu_is_at32ap7000()) { | |
355 | struct atmel_nand_host *host = chip->priv; | |
356 | ecc_writel(host->ecc, CR, ATMEL_ECC_RST); | |
357 | } | |
358 | ||
77f5492c RG |
359 | /* read the page */ |
360 | chip->read_buf(mtd, p, eccsize); | |
361 | ||
362 | /* move to ECC position if needed */ | |
363 | if (eccpos[0] != 0) { | |
364 | /* This only works on large pages | |
365 | * because the ECC controller waits for | |
366 | * NAND_CMD_RNDOUTSTART after the | |
367 | * NAND_CMD_RNDOUT. | |
368 | * anyway, for small pages, the eccpos[0] == 0 | |
369 | */ | |
370 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, | |
371 | mtd->writesize + eccpos[0], -1); | |
372 | } | |
373 | ||
374 | /* the ECC controller needs to read the ECC just after the data */ | |
375 | ecc_pos = oob + eccpos[0]; | |
376 | chip->read_buf(mtd, ecc_pos, eccbytes); | |
377 | ||
378 | /* check if there's an error */ | |
379 | stat = chip->ecc.correct(mtd, p, oob, NULL); | |
380 | ||
3f91e94f | 381 | if (stat < 0) { |
77f5492c | 382 | mtd->ecc_stats.failed++; |
3f91e94f | 383 | } else { |
77f5492c | 384 | mtd->ecc_stats.corrected += stat; |
3f91e94f MD |
385 | max_bitflips = max_t(unsigned int, max_bitflips, stat); |
386 | } | |
77f5492c RG |
387 | |
388 | /* get back to oob start (end of page) */ | |
389 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); | |
390 | ||
391 | /* read the oob */ | |
392 | chip->read_buf(mtd, oob, mtd->oobsize); | |
393 | ||
3f91e94f | 394 | return max_bitflips; |
77f5492c RG |
395 | } |
396 | ||
397 | /* | |
398 | * HW ECC Correction | |
399 | * | |
400 | * function called after a read | |
401 | * | |
402 | * mtd: MTD block structure | |
403 | * dat: raw data read from the chip | |
404 | * read_ecc: ECC from the chip (unused) | |
405 | * isnull: unused | |
406 | * | |
407 | * Detect and correct a 1 bit error for a page | |
408 | */ | |
3c3796cc | 409 | static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, |
77f5492c RG |
410 | u_char *read_ecc, u_char *isnull) |
411 | { | |
412 | struct nand_chip *nand_chip = mtd->priv; | |
3c3796cc | 413 | struct atmel_nand_host *host = nand_chip->priv; |
77f5492c RG |
414 | unsigned int ecc_status; |
415 | unsigned int ecc_word, ecc_bit; | |
416 | ||
417 | /* get the status from the Status Register */ | |
418 | ecc_status = ecc_readl(host->ecc, SR); | |
419 | ||
420 | /* if there's no error */ | |
3c3796cc | 421 | if (likely(!(ecc_status & ATMEL_ECC_RECERR))) |
77f5492c RG |
422 | return 0; |
423 | ||
424 | /* get error bit offset (4 bits) */ | |
3c3796cc | 425 | ecc_bit = ecc_readl(host->ecc, PR) & ATMEL_ECC_BITADDR; |
77f5492c | 426 | /* get word address (12 bits) */ |
3c3796cc | 427 | ecc_word = ecc_readl(host->ecc, PR) & ATMEL_ECC_WORDADDR; |
77f5492c RG |
428 | ecc_word >>= 4; |
429 | ||
430 | /* if there are multiple errors */ | |
3c3796cc | 431 | if (ecc_status & ATMEL_ECC_MULERR) { |
77f5492c RG |
432 | /* check if it is a freshly erased block |
433 | * (filled with 0xff) */ | |
3c3796cc HS |
434 | if ((ecc_bit == ATMEL_ECC_BITADDR) |
435 | && (ecc_word == (ATMEL_ECC_WORDADDR >> 4))) { | |
77f5492c RG |
436 | /* the block has just been erased, return OK */ |
437 | return 0; | |
438 | } | |
439 | /* it doesn't seems to be a freshly | |
440 | * erased block. | |
441 | * We can't correct so many errors */ | |
3c3796cc | 442 | dev_dbg(host->dev, "atmel_nand : multiple errors detected." |
77f5492c RG |
443 | " Unable to correct.\n"); |
444 | return -EIO; | |
445 | } | |
446 | ||
447 | /* if there's a single bit error : we can correct it */ | |
3c3796cc | 448 | if (ecc_status & ATMEL_ECC_ECCERR) { |
77f5492c RG |
449 | /* there's nothing much to do here. |
450 | * the bit error is on the ECC itself. | |
451 | */ | |
3c3796cc | 452 | dev_dbg(host->dev, "atmel_nand : one bit error on ECC code." |
77f5492c RG |
453 | " Nothing to correct\n"); |
454 | return 0; | |
455 | } | |
456 | ||
3c3796cc | 457 | dev_dbg(host->dev, "atmel_nand : one bit error on data." |
77f5492c RG |
458 | " (word offset in the page :" |
459 | " 0x%x bit offset : 0x%x)\n", | |
460 | ecc_word, ecc_bit); | |
461 | /* correct the error */ | |
462 | if (nand_chip->options & NAND_BUSWIDTH_16) { | |
463 | /* 16 bits words */ | |
464 | ((unsigned short *) dat)[ecc_word] ^= (1 << ecc_bit); | |
465 | } else { | |
466 | /* 8 bits words */ | |
467 | dat[ecc_word] ^= (1 << ecc_bit); | |
468 | } | |
3c3796cc | 469 | dev_dbg(host->dev, "atmel_nand : error corrected\n"); |
77f5492c RG |
470 | return 1; |
471 | } | |
472 | ||
473 | /* | |
d6248fdd | 474 | * Enable HW ECC : unused on most chips |
77f5492c | 475 | */ |
d6248fdd HS |
476 | static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) |
477 | { | |
478 | if (cpu_is_at32ap7000()) { | |
479 | struct nand_chip *nand_chip = mtd->priv; | |
480 | struct atmel_nand_host *host = nand_chip->priv; | |
481 | ecc_writel(host->ecc, CR, ATMEL_ECC_RST); | |
482 | } | |
483 | } | |
77f5492c | 484 | |
d6a01661 JCPV |
485 | #if defined(CONFIG_OF) |
486 | static int __devinit atmel_of_init_port(struct atmel_nand_host *host, | |
487 | struct device_node *np) | |
488 | { | |
a41b51a1 JW |
489 | u32 val, table_offset; |
490 | u32 offset[2]; | |
d6a01661 JCPV |
491 | int ecc_mode; |
492 | struct atmel_nand_data *board = &host->board; | |
493 | enum of_gpio_flags flags; | |
494 | ||
495 | if (of_property_read_u32(np, "atmel,nand-addr-offset", &val) == 0) { | |
496 | if (val >= 32) { | |
497 | dev_err(host->dev, "invalid addr-offset %u\n", val); | |
498 | return -EINVAL; | |
499 | } | |
500 | board->ale = val; | |
501 | } | |
502 | ||
503 | if (of_property_read_u32(np, "atmel,nand-cmd-offset", &val) == 0) { | |
504 | if (val >= 32) { | |
505 | dev_err(host->dev, "invalid cmd-offset %u\n", val); | |
506 | return -EINVAL; | |
507 | } | |
508 | board->cle = val; | |
509 | } | |
510 | ||
511 | ecc_mode = of_get_nand_ecc_mode(np); | |
512 | ||
513 | board->ecc_mode = ecc_mode < 0 ? NAND_ECC_SOFT : ecc_mode; | |
514 | ||
515 | board->on_flash_bbt = of_get_nand_on_flash_bbt(np); | |
516 | ||
517 | if (of_get_nand_bus_width(np) == 16) | |
518 | board->bus_width_16 = 1; | |
519 | ||
520 | board->rdy_pin = of_get_gpio_flags(np, 0, &flags); | |
521 | board->rdy_pin_active_low = (flags == OF_GPIO_ACTIVE_LOW); | |
522 | ||
523 | board->enable_pin = of_get_gpio(np, 1); | |
524 | board->det_pin = of_get_gpio(np, 2); | |
525 | ||
a41b51a1 JW |
526 | host->has_pmecc = of_property_read_bool(np, "atmel,has-pmecc"); |
527 | ||
528 | if (!(board->ecc_mode == NAND_ECC_HW) || !host->has_pmecc) | |
529 | return 0; /* Not using PMECC */ | |
530 | ||
531 | /* use PMECC, get correction capability, sector size and lookup | |
532 | * table offset. | |
533 | */ | |
534 | if (of_property_read_u32(np, "atmel,pmecc-cap", &val) != 0) { | |
535 | dev_err(host->dev, "Cannot decide PMECC Capability\n"); | |
536 | return -EINVAL; | |
537 | } else if ((val != 2) && (val != 4) && (val != 8) && (val != 12) && | |
538 | (val != 24)) { | |
539 | dev_err(host->dev, | |
540 | "Unsupported PMECC correction capability: %d; should be 2, 4, 8, 12 or 24\n", | |
541 | val); | |
542 | return -EINVAL; | |
543 | } | |
544 | host->pmecc_corr_cap = (u8)val; | |
545 | ||
546 | if (of_property_read_u32(np, "atmel,pmecc-sector-size", &val) != 0) { | |
547 | dev_err(host->dev, "Cannot decide PMECC Sector Size\n"); | |
548 | return -EINVAL; | |
549 | } else if ((val != 512) && (val != 1024)) { | |
550 | dev_err(host->dev, | |
551 | "Unsupported PMECC sector size: %d; should be 512 or 1024 bytes\n", | |
552 | val); | |
553 | return -EINVAL; | |
554 | } | |
555 | host->pmecc_sector_size = (u16)val; | |
556 | ||
557 | if (of_property_read_u32_array(np, "atmel,pmecc-lookup-table-offset", | |
558 | offset, 2) != 0) { | |
559 | dev_err(host->dev, "Cannot get PMECC lookup table offset\n"); | |
560 | return -EINVAL; | |
561 | } | |
562 | table_offset = host->pmecc_sector_size == 512 ? offset[0] : offset[1]; | |
563 | ||
564 | if (!table_offset) { | |
565 | dev_err(host->dev, "Invalid PMECC lookup table offset\n"); | |
566 | return -EINVAL; | |
567 | } | |
568 | host->pmecc_lookup_table_offset = table_offset; | |
569 | ||
d6a01661 JCPV |
570 | return 0; |
571 | } | |
572 | #else | |
573 | static int __devinit atmel_of_init_port(struct atmel_nand_host *host, | |
574 | struct device_node *np) | |
575 | { | |
576 | return -EINVAL; | |
577 | } | |
578 | #endif | |
579 | ||
3dfe41a4 JW |
580 | static int __init atmel_hw_nand_init_params(struct platform_device *pdev, |
581 | struct atmel_nand_host *host) | |
582 | { | |
583 | struct mtd_info *mtd = &host->mtd; | |
584 | struct nand_chip *nand_chip = &host->nand_chip; | |
585 | struct resource *regs; | |
586 | ||
587 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); | |
588 | if (!regs) { | |
589 | dev_err(host->dev, | |
590 | "Can't get I/O resource regs, use software ECC\n"); | |
591 | nand_chip->ecc.mode = NAND_ECC_SOFT; | |
592 | return 0; | |
593 | } | |
594 | ||
595 | host->ecc = ioremap(regs->start, resource_size(regs)); | |
596 | if (host->ecc == NULL) { | |
597 | dev_err(host->dev, "ioremap failed\n"); | |
598 | return -EIO; | |
599 | } | |
600 | ||
601 | /* ECC is calculated for the whole page (1 step) */ | |
602 | nand_chip->ecc.size = mtd->writesize; | |
603 | ||
604 | /* set ECC page size and oob layout */ | |
605 | switch (mtd->writesize) { | |
606 | case 512: | |
607 | nand_chip->ecc.layout = &atmel_oobinfo_small; | |
608 | ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); | |
609 | break; | |
610 | case 1024: | |
611 | nand_chip->ecc.layout = &atmel_oobinfo_large; | |
612 | ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056); | |
613 | break; | |
614 | case 2048: | |
615 | nand_chip->ecc.layout = &atmel_oobinfo_large; | |
616 | ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112); | |
617 | break; | |
618 | case 4096: | |
619 | nand_chip->ecc.layout = &atmel_oobinfo_large; | |
620 | ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224); | |
621 | break; | |
622 | default: | |
623 | /* page size not handled by HW ECC */ | |
624 | /* switching back to soft ECC */ | |
625 | nand_chip->ecc.mode = NAND_ECC_SOFT; | |
626 | return 0; | |
627 | } | |
628 | ||
629 | /* set up for HW ECC */ | |
630 | nand_chip->ecc.calculate = atmel_nand_calculate; | |
631 | nand_chip->ecc.correct = atmel_nand_correct; | |
632 | nand_chip->ecc.hwctl = atmel_nand_hwctl; | |
633 | nand_chip->ecc.read_page = atmel_nand_read_page; | |
634 | nand_chip->ecc.bytes = 4; | |
635 | nand_chip->ecc.strength = 1; | |
636 | ||
637 | return 0; | |
638 | } | |
639 | ||
42cb1403 AV |
640 | /* |
641 | * Probe for the NAND device. | |
642 | */ | |
3c3796cc | 643 | static int __init atmel_nand_probe(struct platform_device *pdev) |
42cb1403 | 644 | { |
3c3796cc | 645 | struct atmel_nand_host *host; |
42cb1403 AV |
646 | struct mtd_info *mtd; |
647 | struct nand_chip *nand_chip; | |
77f5492c | 648 | struct resource *mem; |
d6a01661 | 649 | struct mtd_part_parser_data ppdata = {}; |
42cb1403 | 650 | int res; |
42cb1403 | 651 | |
cc0c72e1 HS |
652 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
653 | if (!mem) { | |
654 | printk(KERN_ERR "atmel_nand: can't get I/O resource mem\n"); | |
655 | return -ENXIO; | |
656 | } | |
657 | ||
42cb1403 | 658 | /* Allocate memory for the device structure (and zero it) */ |
3c3796cc | 659 | host = kzalloc(sizeof(struct atmel_nand_host), GFP_KERNEL); |
42cb1403 | 660 | if (!host) { |
3c3796cc | 661 | printk(KERN_ERR "atmel_nand: failed to allocate device structure.\n"); |
42cb1403 AV |
662 | return -ENOMEM; |
663 | } | |
664 | ||
cbc6c5e7 HX |
665 | host->io_phys = (dma_addr_t)mem->start; |
666 | ||
28f65c11 | 667 | host->io_base = ioremap(mem->start, resource_size(mem)); |
42cb1403 | 668 | if (host->io_base == NULL) { |
3c3796cc | 669 | printk(KERN_ERR "atmel_nand: ioremap failed\n"); |
cc0c72e1 HS |
670 | res = -EIO; |
671 | goto err_nand_ioremap; | |
42cb1403 AV |
672 | } |
673 | ||
674 | mtd = &host->mtd; | |
675 | nand_chip = &host->nand_chip; | |
77f5492c | 676 | host->dev = &pdev->dev; |
d6a01661 JCPV |
677 | if (pdev->dev.of_node) { |
678 | res = atmel_of_init_port(host, pdev->dev.of_node); | |
679 | if (res) | |
680 | goto err_nand_ioremap; | |
681 | } else { | |
682 | memcpy(&host->board, pdev->dev.platform_data, | |
683 | sizeof(struct atmel_nand_data)); | |
684 | } | |
42cb1403 AV |
685 | |
686 | nand_chip->priv = host; /* link the private data structures */ | |
687 | mtd->priv = nand_chip; | |
688 | mtd->owner = THIS_MODULE; | |
689 | ||
690 | /* Set address of NAND IO lines */ | |
691 | nand_chip->IO_ADDR_R = host->io_base; | |
692 | nand_chip->IO_ADDR_W = host->io_base; | |
3c3796cc | 693 | nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl; |
a4265f8d | 694 | |
d6a01661 | 695 | if (gpio_is_valid(host->board.rdy_pin)) |
3c3796cc | 696 | nand_chip->dev_ready = atmel_nand_device_ready; |
a4265f8d | 697 | |
d6a01661 | 698 | nand_chip->ecc.mode = host->board.ecc_mode; |
42cb1403 AV |
699 | nand_chip->chip_delay = 20; /* 20us command delay time */ |
700 | ||
d6a01661 | 701 | if (host->board.bus_width_16) /* 16-bit bus width */ |
dd11b8cd | 702 | nand_chip->options |= NAND_BUSWIDTH_16; |
cbc6c5e7 HX |
703 | |
704 | nand_chip->read_buf = atmel_read_buf; | |
705 | nand_chip->write_buf = atmel_write_buf; | |
dd11b8cd | 706 | |
42cb1403 | 707 | platform_set_drvdata(pdev, host); |
3c3796cc | 708 | atmel_nand_enable(host); |
42cb1403 | 709 | |
d6a01661 JCPV |
710 | if (gpio_is_valid(host->board.det_pin)) { |
711 | if (gpio_get_value(host->board.det_pin)) { | |
f4fa697c | 712 | printk(KERN_INFO "No SmartMedia card inserted.\n"); |
895fb494 | 713 | res = -ENXIO; |
cc0c72e1 | 714 | goto err_no_card; |
42cb1403 AV |
715 | } |
716 | } | |
717 | ||
d6a01661 | 718 | if (host->board.on_flash_bbt || on_flash_bbt) { |
f4fa697c | 719 | printk(KERN_INFO "atmel_nand: Use On Flash BBT\n"); |
bb9ebd4e | 720 | nand_chip->bbt_options |= NAND_BBT_USE_FLASH; |
f4fa697c SP |
721 | } |
722 | ||
cb457a4d HX |
723 | if (!cpu_has_dma()) |
724 | use_dma = 0; | |
725 | ||
726 | if (use_dma) { | |
cbc6c5e7 HX |
727 | dma_cap_mask_t mask; |
728 | ||
729 | dma_cap_zero(mask); | |
730 | dma_cap_set(DMA_MEMCPY, mask); | |
201ab536 | 731 | host->dma_chan = dma_request_channel(mask, NULL, NULL); |
cbc6c5e7 HX |
732 | if (!host->dma_chan) { |
733 | dev_err(host->dev, "Failed to request DMA channel\n"); | |
734 | use_dma = 0; | |
735 | } | |
736 | } | |
737 | if (use_dma) | |
042bc9c0 NF |
738 | dev_info(host->dev, "Using %s for DMA transfers.\n", |
739 | dma_chan_name(host->dma_chan)); | |
cbc6c5e7 HX |
740 | else |
741 | dev_info(host->dev, "No DMA support for NAND access.\n"); | |
742 | ||
77f5492c | 743 | /* first scan to find the device and get the page size */ |
5e81e88a | 744 | if (nand_scan_ident(mtd, 1, NULL)) { |
77f5492c | 745 | res = -ENXIO; |
cc0c72e1 | 746 | goto err_scan_ident; |
77f5492c RG |
747 | } |
748 | ||
3fc23898 | 749 | if (nand_chip->ecc.mode == NAND_ECC_HW) { |
3dfe41a4 JW |
750 | res = atmel_hw_nand_init_params(pdev, host); |
751 | if (res != 0) | |
752 | goto err_hw_ecc; | |
77f5492c RG |
753 | } |
754 | ||
755 | /* second phase scan */ | |
756 | if (nand_scan_tail(mtd)) { | |
42cb1403 | 757 | res = -ENXIO; |
cc0c72e1 | 758 | goto err_scan_tail; |
42cb1403 AV |
759 | } |
760 | ||
3c3796cc | 761 | mtd->name = "atmel_nand"; |
d6a01661 JCPV |
762 | ppdata.of_node = pdev->dev.of_node; |
763 | res = mtd_device_parse_register(mtd, NULL, &ppdata, | |
764 | host->board.parts, host->board.num_parts); | |
42cb1403 AV |
765 | if (!res) |
766 | return res; | |
767 | ||
cc0c72e1 | 768 | err_scan_tail: |
3dfe41a4 JW |
769 | if (host->ecc) |
770 | iounmap(host->ecc); | |
771 | err_hw_ecc: | |
cc0c72e1 HS |
772 | err_scan_ident: |
773 | err_no_card: | |
3c3796cc | 774 | atmel_nand_disable(host); |
42cb1403 | 775 | platform_set_drvdata(pdev, NULL); |
cbc6c5e7 HX |
776 | if (host->dma_chan) |
777 | dma_release_channel(host->dma_chan); | |
42cb1403 | 778 | iounmap(host->io_base); |
cc0c72e1 | 779 | err_nand_ioremap: |
42cb1403 AV |
780 | kfree(host); |
781 | return res; | |
782 | } | |
783 | ||
784 | /* | |
785 | * Remove a NAND device. | |
786 | */ | |
23a346ca | 787 | static int __exit atmel_nand_remove(struct platform_device *pdev) |
42cb1403 | 788 | { |
3c3796cc | 789 | struct atmel_nand_host *host = platform_get_drvdata(pdev); |
42cb1403 AV |
790 | struct mtd_info *mtd = &host->mtd; |
791 | ||
792 | nand_release(mtd); | |
793 | ||
3c3796cc | 794 | atmel_nand_disable(host); |
42cb1403 | 795 | |
cc0c72e1 HS |
796 | if (host->ecc) |
797 | iounmap(host->ecc); | |
cbc6c5e7 HX |
798 | |
799 | if (host->dma_chan) | |
800 | dma_release_channel(host->dma_chan); | |
801 | ||
42cb1403 AV |
802 | iounmap(host->io_base); |
803 | kfree(host); | |
804 | ||
805 | return 0; | |
806 | } | |
807 | ||
d6a01661 JCPV |
808 | #if defined(CONFIG_OF) |
809 | static const struct of_device_id atmel_nand_dt_ids[] = { | |
810 | { .compatible = "atmel,at91rm9200-nand" }, | |
811 | { /* sentinel */ } | |
812 | }; | |
813 | ||
814 | MODULE_DEVICE_TABLE(of, atmel_nand_dt_ids); | |
815 | #endif | |
816 | ||
3c3796cc | 817 | static struct platform_driver atmel_nand_driver = { |
23a346ca | 818 | .remove = __exit_p(atmel_nand_remove), |
42cb1403 | 819 | .driver = { |
3c3796cc | 820 | .name = "atmel_nand", |
42cb1403 | 821 | .owner = THIS_MODULE, |
d6a01661 | 822 | .of_match_table = of_match_ptr(atmel_nand_dt_ids), |
42cb1403 AV |
823 | }, |
824 | }; | |
825 | ||
3c3796cc | 826 | static int __init atmel_nand_init(void) |
42cb1403 | 827 | { |
23a346ca | 828 | return platform_driver_probe(&atmel_nand_driver, atmel_nand_probe); |
42cb1403 AV |
829 | } |
830 | ||
831 | ||
3c3796cc | 832 | static void __exit atmel_nand_exit(void) |
42cb1403 | 833 | { |
3c3796cc | 834 | platform_driver_unregister(&atmel_nand_driver); |
42cb1403 AV |
835 | } |
836 | ||
837 | ||
3c3796cc HS |
838 | module_init(atmel_nand_init); |
839 | module_exit(atmel_nand_exit); | |
42cb1403 AV |
840 | |
841 | MODULE_LICENSE("GPL"); | |
842 | MODULE_AUTHOR("Rick Bronson"); | |
d4f4c0aa | 843 | MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91 / AVR32"); |
3c3796cc | 844 | MODULE_ALIAS("platform:atmel_nand"); |