aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand
diff options
context:
space:
mode:
authorHong Xu <hong.xu@atmel.com>2011-01-18 01:36:05 -0500
committerDavid Woodhouse <David.Woodhouse@intel.com>2011-03-11 09:22:42 -0500
commitcbc6c5e73dfa598b1fa5e67cef28096186e2a7cd (patch)
tree77e0933fcba5181c21e3ec9226ebe4356f98f5e7 /drivers/mtd/nand
parent7f53f12f02b0b60af373a07fcac62b578381308e (diff)
mtd: atmel_nand: Add DMA support to access Nandflash
Some SAM9 chips have the ability to perform DMA between CPU and SMC controller. This patch adds DMA support for SAM9RL, SAM9G45, SSAM9G46,AM9M10, SAM9M11. Signed-off-by: Hong Xu <hong.xu@atmel.com> Tested-by: Ryan Mallon <ryan@bluewatersys.com> Acked-by: Ryan Mallon <ryan@bluewatersys.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r--drivers/mtd/nand/atmel_nand.c166
1 files changed, 157 insertions, 9 deletions
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index ccce0f03b5dc..6fae04b3fc6d 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -48,6 +48,9 @@
48#define no_ecc 0 48#define no_ecc 0
49#endif 49#endif
50 50
51static int use_dma = 1;
52module_param(use_dma, int, 0);
53
51static int on_flash_bbt = 0; 54static int on_flash_bbt = 0;
52module_param(on_flash_bbt, int, 0); 55module_param(on_flash_bbt, int, 0);
53 56
@@ -89,11 +92,20 @@ struct atmel_nand_host {
89 struct nand_chip nand_chip; 92 struct nand_chip nand_chip;
90 struct mtd_info mtd; 93 struct mtd_info mtd;
91 void __iomem *io_base; 94 void __iomem *io_base;
95 dma_addr_t io_phys;
92 struct atmel_nand_data *board; 96 struct atmel_nand_data *board;
93 struct device *dev; 97 struct device *dev;
94 void __iomem *ecc; 98 void __iomem *ecc;
99
100 struct completion comp;
101 struct dma_chan *dma_chan;
95}; 102};
96 103
104static int cpu_has_dma(void)
105{
106 return cpu_is_at91sam9rl() || cpu_is_at91sam9g45();
107}
108
97/* 109/*
98 * Enable NAND. 110 * Enable NAND.
99 */ 111 */
@@ -150,7 +162,7 @@ static int atmel_nand_device_ready(struct mtd_info *mtd)
150/* 162/*
151 * Minimal-overhead PIO for data access. 163 * Minimal-overhead PIO for data access.
152 */ 164 */
153static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) 165static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len)
154{ 166{
155 struct nand_chip *nand_chip = mtd->priv; 167 struct nand_chip *nand_chip = mtd->priv;
156 168
@@ -164,7 +176,7 @@ static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len)
164 __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2); 176 __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2);
165} 177}
166 178
167static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) 179static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len)
168{ 180{
169 struct nand_chip *nand_chip = mtd->priv; 181 struct nand_chip *nand_chip = mtd->priv;
170 182
@@ -178,6 +190,121 @@ static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len)
178 __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2); 190 __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2);
179} 191}
180 192
193static void dma_complete_func(void *completion)
194{
195 complete(completion);
196}
197
198static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
199 int is_read)
200{
201 struct dma_device *dma_dev;
202 enum dma_ctrl_flags flags;
203 dma_addr_t dma_src_addr, dma_dst_addr, phys_addr;
204 struct dma_async_tx_descriptor *tx = NULL;
205 dma_cookie_t cookie;
206 struct nand_chip *chip = mtd->priv;
207 struct atmel_nand_host *host = chip->priv;
208 void *p = buf;
209 int err = -EIO;
210 enum dma_data_direction dir = is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
211
212 if (buf >= high_memory) {
213 struct page *pg;
214
215 if (((size_t)buf & PAGE_MASK) !=
216 ((size_t)(buf + len - 1) & PAGE_MASK)) {
217 dev_warn(host->dev, "Buffer not fit in one page\n");
218 goto err_buf;
219 }
220
221 pg = vmalloc_to_page(buf);
222 if (pg == 0) {
223 dev_err(host->dev, "Failed to vmalloc_to_page\n");
224 goto err_buf;
225 }
226 p = page_address(pg) + ((size_t)buf & ~PAGE_MASK);
227 }
228
229 dma_dev = host->dma_chan->device;
230
231 flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP |
232 DMA_COMPL_SKIP_DEST_UNMAP;
233
234 phys_addr = dma_map_single(dma_dev->dev, p, len, dir);
235 if (dma_mapping_error(dma_dev->dev, phys_addr)) {
236 dev_err(host->dev, "Failed to dma_map_single\n");
237 goto err_buf;
238 }
239
240 if (is_read) {
241 dma_src_addr = host->io_phys;
242 dma_dst_addr = phys_addr;
243 } else {
244 dma_src_addr = phys_addr;
245 dma_dst_addr = host->io_phys;
246 }
247
248 tx = dma_dev->device_prep_dma_memcpy(host->dma_chan, dma_dst_addr,
249 dma_src_addr, len, flags);
250 if (!tx) {
251 dev_err(host->dev, "Failed to prepare DMA memcpy\n");
252 goto err_dma;
253 }
254
255 init_completion(&host->comp);
256 tx->callback = dma_complete_func;
257 tx->callback_param = &host->comp;
258
259 cookie = tx->tx_submit(tx);
260 if (dma_submit_error(cookie)) {
261 dev_err(host->dev, "Failed to do DMA tx_submit\n");
262 goto err_dma;
263 }
264
265 dma_async_issue_pending(host->dma_chan);
266 wait_for_completion(&host->comp);
267
268 err = 0;
269
270err_dma:
271 dma_unmap_single(dma_dev->dev, phys_addr, len, dir);
272err_buf:
273 if (err != 0)
274 dev_warn(host->dev, "Fall back to CPU I/O\n");
275 return err;
276}
277
278static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len)
279{
280 struct nand_chip *chip = mtd->priv;
281 struct atmel_nand_host *host = chip->priv;
282
283 if (use_dma && len >= mtd->oobsize)
284 if (atmel_nand_dma_op(mtd, buf, len, 1) == 0)
285 return;
286
287 if (host->board->bus_width_16)
288 atmel_read_buf16(mtd, buf, len);
289 else
290 atmel_read_buf8(mtd, buf, len);
291}
292
293static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
294{
295 struct nand_chip *chip = mtd->priv;
296 struct atmel_nand_host *host = chip->priv;
297
298 if (use_dma && len >= mtd->oobsize)
299 if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) == 0)
300 return;
301
302 if (host->board->bus_width_16)
303 atmel_write_buf16(mtd, buf, len);
304 else
305 atmel_write_buf8(mtd, buf, len);
306}
307
181/* 308/*
182 * Calculate HW ECC 309 * Calculate HW ECC
183 * 310 *
@@ -398,6 +525,8 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
398 return -ENOMEM; 525 return -ENOMEM;
399 } 526 }
400 527
528 host->io_phys = (dma_addr_t)mem->start;
529
401 host->io_base = ioremap(mem->start, mem->end - mem->start + 1); 530 host->io_base = ioremap(mem->start, mem->end - mem->start + 1);
402 if (host->io_base == NULL) { 531 if (host->io_base == NULL) {
403 printk(KERN_ERR "atmel_nand: ioremap failed\n"); 532 printk(KERN_ERR "atmel_nand: ioremap failed\n");
@@ -448,14 +577,11 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
448 577
449 nand_chip->chip_delay = 20; /* 20us command delay time */ 578 nand_chip->chip_delay = 20; /* 20us command delay time */
450 579
451 if (host->board->bus_width_16) { /* 16-bit bus width */ 580 if (host->board->bus_width_16) /* 16-bit bus width */
452 nand_chip->options |= NAND_BUSWIDTH_16; 581 nand_chip->options |= NAND_BUSWIDTH_16;
453 nand_chip->read_buf = atmel_read_buf16; 582
454 nand_chip->write_buf = atmel_write_buf16; 583 nand_chip->read_buf = atmel_read_buf;
455 } else { 584 nand_chip->write_buf = atmel_write_buf;
456 nand_chip->read_buf = atmel_read_buf;
457 nand_chip->write_buf = atmel_write_buf;
458 }
459 585
460 platform_set_drvdata(pdev, host); 586 platform_set_drvdata(pdev, host);
461 atmel_nand_enable(host); 587 atmel_nand_enable(host);
@@ -473,6 +599,22 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
473 nand_chip->options |= NAND_USE_FLASH_BBT; 599 nand_chip->options |= NAND_USE_FLASH_BBT;
474 } 600 }
475 601
602 if (cpu_has_dma() && use_dma) {
603 dma_cap_mask_t mask;
604
605 dma_cap_zero(mask);
606 dma_cap_set(DMA_MEMCPY, mask);
607 host->dma_chan = dma_request_channel(mask, 0, NULL);
608 if (!host->dma_chan) {
609 dev_err(host->dev, "Failed to request DMA channel\n");
610 use_dma = 0;
611 }
612 }
613 if (use_dma)
614 dev_info(host->dev, "Using DMA for NAND access.\n");
615 else
616 dev_info(host->dev, "No DMA support for NAND access.\n");
617
476 /* first scan to find the device and get the page size */ 618 /* first scan to find the device and get the page size */
477 if (nand_scan_ident(mtd, 1, NULL)) { 619 if (nand_scan_ident(mtd, 1, NULL)) {
478 res = -ENXIO; 620 res = -ENXIO;
@@ -555,6 +697,8 @@ err_scan_ident:
555err_no_card: 697err_no_card:
556 atmel_nand_disable(host); 698 atmel_nand_disable(host);
557 platform_set_drvdata(pdev, NULL); 699 platform_set_drvdata(pdev, NULL);
700 if (host->dma_chan)
701 dma_release_channel(host->dma_chan);
558 if (host->ecc) 702 if (host->ecc)
559 iounmap(host->ecc); 703 iounmap(host->ecc);
560err_ecc_ioremap: 704err_ecc_ioremap:
@@ -578,6 +722,10 @@ static int __exit atmel_nand_remove(struct platform_device *pdev)
578 722
579 if (host->ecc) 723 if (host->ecc)
580 iounmap(host->ecc); 724 iounmap(host->ecc);
725
726 if (host->dma_chan)
727 dma_release_channel(host->dma_chan);
728
581 iounmap(host->io_base); 729 iounmap(host->io_base);
582 kfree(host); 730 kfree(host);
583 731