aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand
diff options
context:
space:
mode:
authorvimal singh <vimalsingh@ti.com>2009-07-13 06:59:16 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-09-19 16:21:05 -0400
commitdfe32893cbe3e599a39770199b9982a6ad5daa7b (patch)
tree44f019729831fcda3bcec71dcf31827861f77219 /drivers/mtd/nand
parent59e9c5ae17179fe561103fbe0808fac5976ca1bd (diff)
mtd: omap: adding DMA mode support in nand prefetch/post-write
This patch adds DMA mode support for nand prefetch/post-write engine. Signed-off-by: Vimal Singh <vimalsingh@ti.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r--drivers/mtd/nand/Kconfig9
-rw-r--r--drivers/mtd/nand/omap2.c186
2 files changed, 193 insertions, 2 deletions
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 7dab79caed44..2c9a0ed4aed8 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -88,6 +88,15 @@ config MTD_NAND_OMAP_PREFETCH
88 The NAND device can be accessed for Read/Write using GPMC PREFETCH engine 88 The NAND device can be accessed for Read/Write using GPMC PREFETCH engine
89 to improve the performance. 89 to improve the performance.
90 90
91config MTD_NAND_OMAP_PREFETCH_DMA
92 depends on MTD_NAND_OMAP_PREFETCH
93 bool "DMA mode"
94 default n
95 help
96 The GPMC PREFETCH engine can be configured eigther in MPU interrupt mode
97 or in DMA interrupt mode.
98 Say y for DMA mode or MPU mode will be used
99
91config MTD_NAND_TS7250 100config MTD_NAND_TS7250
92 tristate "NAND Flash device on TS-7250 board" 101 tristate "NAND Flash device on TS-7250 board"
93 depends on MACH_TS72XX 102 depends on MACH_TS72XX
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 6736822c4751..090ab87086b5 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -18,8 +18,7 @@
18#include <linux/mtd/partitions.h> 18#include <linux/mtd/partitions.h>
19#include <linux/io.h> 19#include <linux/io.h>
20 20
21#include <asm/dma.h> 21#include <mach/dma.h>
22
23#include <mach/gpmc.h> 22#include <mach/gpmc.h>
24#include <mach/nand.h> 23#include <mach/nand.h>
25 24
@@ -118,8 +117,19 @@ static int use_prefetch = 1;
118/* "modprobe ... use_prefetch=0" etc */ 117/* "modprobe ... use_prefetch=0" etc */
119module_param(use_prefetch, bool, 0); 118module_param(use_prefetch, bool, 0);
120MODULE_PARM_DESC(use_prefetch, "enable/disable use of PREFETCH"); 119MODULE_PARM_DESC(use_prefetch, "enable/disable use of PREFETCH");
120
121#ifdef CONFIG_MTD_NAND_OMAP_PREFETCH_DMA
122static int use_dma = 1;
123
124/* "modprobe ... use_dma=0" etc */
125module_param(use_dma, bool, 0);
126MODULE_PARM_DESC(use_dma, "enable/disable use of DMA");
127#else
128const int use_dma;
129#endif
121#else 130#else
122const int use_prefetch; 131const int use_prefetch;
132const int use_dma;
123#endif 133#endif
124 134
125struct omap_nand_info { 135struct omap_nand_info {
@@ -135,6 +145,8 @@ struct omap_nand_info {
135 void __iomem *gpmc_cs_baseaddr; 145 void __iomem *gpmc_cs_baseaddr;
136 void __iomem *gpmc_baseaddr; 146 void __iomem *gpmc_baseaddr;
137 void __iomem *nand_pref_fifo_add; 147 void __iomem *nand_pref_fifo_add;
148 struct completion comp;
149 int dma_ch;
138}; 150};
139 151
140/** 152/**
@@ -355,6 +367,147 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
355 } 367 }
356} 368}
357 369
370#ifdef CONFIG_MTD_NAND_OMAP_PREFETCH_DMA
371/*
372 * omap_nand_dma_cb: callback on the completion of dma transfer
373 * @lch: logical channel
374 * @ch_satuts: channel status
375 * @data: pointer to completion data structure
376 */
377static void omap_nand_dma_cb(int lch, u16 ch_status, void *data)
378{
379 complete((struct completion *) data);
380}
381
382/*
383 * omap_nand_dma_transfer: configer and start dma transfer
384 * @mtd: MTD device structure
385 * @addr: virtual address in RAM of source/destination
386 * @len: number of data bytes to be transferred
387 * @is_write: flag for read/write operation
388 */
389static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
390 unsigned int len, int is_write)
391{
392 struct omap_nand_info *info = container_of(mtd,
393 struct omap_nand_info, mtd);
394 uint32_t prefetch_status = 0;
395 enum dma_data_direction dir = is_write ? DMA_TO_DEVICE :
396 DMA_FROM_DEVICE;
397 dma_addr_t dma_addr;
398 int ret;
399
400 /* The fifo depth is 64 bytes. We have a sync at each frame and frame
401 * length is 64 bytes.
402 */
403 int buf_len = len >> 6;
404
405 if (addr >= high_memory) {
406 struct page *p1;
407
408 if (((size_t)addr & PAGE_MASK) !=
409 ((size_t)(addr + len - 1) & PAGE_MASK))
410 goto out_copy;
411 p1 = vmalloc_to_page(addr);
412 if (!p1)
413 goto out_copy;
414 addr = page_address(p1) + ((size_t)addr & ~PAGE_MASK);
415 }
416
417 dma_addr = dma_map_single(&info->pdev->dev, addr, len, dir);
418 if (dma_mapping_error(&info->pdev->dev, dma_addr)) {
419 dev_err(&info->pdev->dev,
420 "Couldn't DMA map a %d byte buffer\n", len);
421 goto out_copy;
422 }
423
424 if (is_write) {
425 omap_set_dma_dest_params(info->dma_ch, 0, OMAP_DMA_AMODE_CONSTANT,
426 info->phys_base, 0, 0);
427 omap_set_dma_src_params(info->dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
428 dma_addr, 0, 0);
429 omap_set_dma_transfer_params(info->dma_ch, OMAP_DMA_DATA_TYPE_S32,
430 0x10, buf_len, OMAP_DMA_SYNC_FRAME,
431 OMAP24XX_DMA_GPMC, OMAP_DMA_DST_SYNC);
432 } else {
433 omap_set_dma_src_params(info->dma_ch, 0, OMAP_DMA_AMODE_CONSTANT,
434 info->phys_base, 0, 0);
435 omap_set_dma_dest_params(info->dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
436 dma_addr, 0, 0);
437 omap_set_dma_transfer_params(info->dma_ch, OMAP_DMA_DATA_TYPE_S32,
438 0x10, buf_len, OMAP_DMA_SYNC_FRAME,
439 OMAP24XX_DMA_GPMC, OMAP_DMA_SRC_SYNC);
440 }
441 /* configure and start prefetch transfer */
442 ret = gpmc_prefetch_enable(info->gpmc_cs, 0x1, len, is_write);
443 if (ret)
444 /* PFPW engine is busy, use cpu copy methode */
445 goto out_copy;
446
447 init_completion(&info->comp);
448
449 omap_start_dma(info->dma_ch);
450
451 /* setup and start DMA using dma_addr */
452 wait_for_completion(&info->comp);
453
454 while (0x3fff & (prefetch_status = gpmc_prefetch_status()))
455 ;
456 /* disable and stop the PFPW engine */
457 gpmc_prefetch_reset();
458
459 dma_unmap_single(&info->pdev->dev, dma_addr, len, dir);
460 return 0;
461
462out_copy:
463 if (info->nand.options & NAND_BUSWIDTH_16)
464 is_write == 0 ? omap_read_buf16(mtd, (u_char *) addr, len)
465 : omap_write_buf16(mtd, (u_char *) addr, len);
466 else
467 is_write == 0 ? omap_read_buf8(mtd, (u_char *) addr, len)
468 : omap_write_buf8(mtd, (u_char *) addr, len);
469 return 0;
470}
471#else
472static void omap_nand_dma_cb(int lch, u16 ch_status, void *data) {}
473static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
474 unsigned int len, int is_write)
475{
476 return 0;
477}
478#endif
479
480/**
481 * omap_read_buf_dma_pref - read data from NAND controller into buffer
482 * @mtd: MTD device structure
483 * @buf: buffer to store date
484 * @len: number of bytes to read
485 */
486static void omap_read_buf_dma_pref(struct mtd_info *mtd, u_char *buf, int len)
487{
488 if (len <= mtd->oobsize)
489 omap_read_buf_pref(mtd, buf, len);
490 else
491 /* start transfer in DMA mode */
492 omap_nand_dma_transfer(mtd, buf, len, 0x0);
493}
494
495/**
496 * omap_write_buf_dma_pref - write buffer to NAND controller
497 * @mtd: MTD device structure
498 * @buf: data buffer
499 * @len: number of bytes to write
500 */
501static void omap_write_buf_dma_pref(struct mtd_info *mtd,
502 const u_char *buf, int len)
503{
504 if (len <= mtd->oobsize)
505 omap_write_buf_pref(mtd, buf, len);
506 else
507 /* start transfer in DMA mode */
508 omap_nand_dma_transfer(mtd, buf, len, 0x1);
509}
510
358/** 511/**
359 * omap_verify_buf - Verify chip data against buffer 512 * omap_verify_buf - Verify chip data against buffer
360 * @mtd: MTD device structure 513 * @mtd: MTD device structure
@@ -821,6 +974,23 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
821 974
822 info->nand.read_buf = omap_read_buf_pref; 975 info->nand.read_buf = omap_read_buf_pref;
823 info->nand.write_buf = omap_write_buf_pref; 976 info->nand.write_buf = omap_write_buf_pref;
977 if (use_dma) {
978 err = omap_request_dma(OMAP24XX_DMA_GPMC, "NAND",
979 omap_nand_dma_cb, &info->comp, &info->dma_ch);
980 if (err < 0) {
981 info->dma_ch = -1;
982 printk(KERN_WARNING "DMA request failed."
983 " Non-dma data transfer mode\n");
984 } else {
985 omap_set_dma_dest_burst_mode(info->dma_ch,
986 OMAP_DMA_DATA_BURST_16);
987 omap_set_dma_src_burst_mode(info->dma_ch,
988 OMAP_DMA_DATA_BURST_16);
989
990 info->nand.read_buf = omap_read_buf_dma_pref;
991 info->nand.write_buf = omap_write_buf_dma_pref;
992 }
993 }
824 } else { 994 } else {
825 if (info->nand.options & NAND_BUSWIDTH_16) { 995 if (info->nand.options & NAND_BUSWIDTH_16) {
826 info->nand.read_buf = omap_read_buf16; 996 info->nand.read_buf = omap_read_buf16;
@@ -887,6 +1057,9 @@ static int omap_nand_remove(struct platform_device *pdev)
887 struct omap_nand_info *info = mtd->priv; 1057 struct omap_nand_info *info = mtd->priv;
888 1058
889 platform_set_drvdata(pdev, NULL); 1059 platform_set_drvdata(pdev, NULL);
1060 if (use_dma)
1061 omap_free_dma(info->dma_ch);
1062
890 /* Release NAND device, its internal structures and partitions */ 1063 /* Release NAND device, its internal structures and partitions */
891 nand_release(&info->mtd); 1064 nand_release(&info->mtd);
892 iounmap(info->nand_pref_fifo_add); 1065 iounmap(info->nand_pref_fifo_add);
@@ -906,6 +1079,15 @@ static struct platform_driver omap_nand_driver = {
906static int __init omap_nand_init(void) 1079static int __init omap_nand_init(void)
907{ 1080{
908 printk(KERN_INFO "%s driver initializing\n", DRIVER_NAME); 1081 printk(KERN_INFO "%s driver initializing\n", DRIVER_NAME);
1082
1083 /* This check is required if driver is being
1084 * loaded run time as a module
1085 */
1086 if ((1 == use_dma) && (0 == use_prefetch)) {
1087 printk(KERN_INFO"Wrong parameters: 'use_dma' can not be 1 "
1088 "without use_prefetch'. Prefetch will not be"
1089 " used in either mode (mpu or dma)\n");
1090 }
909 return platform_driver_register(&omap_nand_driver); 1091 return platform_driver_register(&omap_nand_driver);
910} 1092}
911 1093