aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorKyungmin Park <kyungmin.park@samsung.com>2010-09-28 06:27:15 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2010-10-24 19:52:26 -0400
commite23abf4b774322cbeb3f15cb95756544a64dda5e (patch)
tree2fd435efec17a4879275d32eafb0bbba830c07c0 /drivers/mtd
parentdcf08227e964a53a2cb39130b74842c7dcb6adde (diff)
mtd: OneNAND: S5PC110: Implement DMA interrupt method
Implement DMA interrupt method. previous time it polls the DMA status. It can reduce the CPU power but decrease the performance a little. Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/onenand/samsung.c85
1 files changed, 84 insertions, 1 deletions
diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c
index afdb4c544132..214ed1e763b6 100644
--- a/drivers/mtd/onenand/samsung.c
+++ b/drivers/mtd/onenand/samsung.c
@@ -22,6 +22,7 @@
22#include <linux/mtd/onenand.h> 22#include <linux/mtd/onenand.h>
23#include <linux/mtd/partitions.h> 23#include <linux/mtd/partitions.h>
24#include <linux/dma-mapping.h> 24#include <linux/dma-mapping.h>
25#include <linux/interrupt.h>
25 26
26#include <asm/mach/flash.h> 27#include <asm/mach/flash.h>
27#include <plat/regs-onenand.h> 28#include <plat/regs-onenand.h>
@@ -81,6 +82,17 @@ enum soc_type {
81#define S5PC110_DMA_TRANS_CMD 0x418 82#define S5PC110_DMA_TRANS_CMD 0x418
82#define S5PC110_DMA_TRANS_STATUS 0x41C 83#define S5PC110_DMA_TRANS_STATUS 0x41C
83#define S5PC110_DMA_TRANS_DIR 0x420 84#define S5PC110_DMA_TRANS_DIR 0x420
85#define S5PC110_INTC_DMA_CLR 0x1004
86#define S5PC110_INTC_ONENAND_CLR 0x1008
87#define S5PC110_INTC_DMA_MASK 0x1024
88#define S5PC110_INTC_ONENAND_MASK 0x1028
89#define S5PC110_INTC_DMA_PEND 0x1044
90#define S5PC110_INTC_ONENAND_PEND 0x1048
91#define S5PC110_INTC_DMA_STATUS 0x1064
92#define S5PC110_INTC_ONENAND_STATUS 0x1068
93
94#define S5PC110_INTC_DMA_TD (1 << 24)
95#define S5PC110_INTC_DMA_TE (1 << 16)
84 96
85#define S5PC110_DMA_CFG_SINGLE (0x0 << 16) 97#define S5PC110_DMA_CFG_SINGLE (0x0 << 16)
86#define S5PC110_DMA_CFG_4BURST (0x2 << 16) 98#define S5PC110_DMA_CFG_4BURST (0x2 << 16)
@@ -134,6 +146,7 @@ struct s3c_onenand {
134 void __iomem *dma_addr; 146 void __iomem *dma_addr;
135 struct resource *dma_res; 147 struct resource *dma_res;
136 unsigned long phys_base; 148 unsigned long phys_base;
149 struct completion complete;
137#ifdef CONFIG_MTD_PARTITIONS 150#ifdef CONFIG_MTD_PARTITIONS
138 struct mtd_partition *parts; 151 struct mtd_partition *parts;
139#endif 152#endif
@@ -531,7 +544,9 @@ static int onenand_write_bufferram(struct mtd_info *mtd, int area,
531 return 0; 544 return 0;
532} 545}
533 546
534static int s5pc110_dma_ops(void *dst, void *src, size_t count, int direction) 547static int (*s5pc110_dma_ops)(void *dst, void *src, size_t count, int direction);
548
549static int s5pc110_dma_poll(void *dst, void *src, size_t count, int direction)
535{ 550{
536 void __iomem *base = onenand->dma_addr; 551 void __iomem *base = onenand->dma_addr;
537 int status; 552 int status;
@@ -575,6 +590,60 @@ static int s5pc110_dma_ops(void *dst, void *src, size_t count, int direction)
575 return 0; 590 return 0;
576} 591}
577 592
593static irqreturn_t s5pc110_onenand_irq(int irq, void *data)
594{
595 void __iomem *base = onenand->dma_addr;
596 int status, cmd = 0;
597
598 status = readl(base + S5PC110_INTC_DMA_STATUS);
599
600 if (likely(status & S5PC110_INTC_DMA_TD))
601 cmd = S5PC110_DMA_TRANS_CMD_TDC;
602
603 if (unlikely(status & S5PC110_INTC_DMA_TE))
604 cmd = S5PC110_DMA_TRANS_CMD_TEC;
605
606 writel(cmd, base + S5PC110_DMA_TRANS_CMD);
607 writel(status, base + S5PC110_INTC_DMA_CLR);
608
609 if (!onenand->complete.done)
610 complete(&onenand->complete);
611
612 return IRQ_HANDLED;
613}
614
615static int s5pc110_dma_irq(void *dst, void *src, size_t count, int direction)
616{
617 void __iomem *base = onenand->dma_addr;
618 int status;
619
620 status = readl(base + S5PC110_INTC_DMA_MASK);
621 if (status) {
622 status &= ~(S5PC110_INTC_DMA_TD | S5PC110_INTC_DMA_TE);
623 writel(status, base + S5PC110_INTC_DMA_MASK);
624 }
625
626 writel(src, base + S5PC110_DMA_SRC_ADDR);
627 writel(dst, base + S5PC110_DMA_DST_ADDR);
628
629 if (direction == S5PC110_DMA_DIR_READ) {
630 writel(S5PC110_DMA_SRC_CFG_READ, base + S5PC110_DMA_SRC_CFG);
631 writel(S5PC110_DMA_DST_CFG_READ, base + S5PC110_DMA_DST_CFG);
632 } else {
633 writel(S5PC110_DMA_SRC_CFG_WRITE, base + S5PC110_DMA_SRC_CFG);
634 writel(S5PC110_DMA_DST_CFG_WRITE, base + S5PC110_DMA_DST_CFG);
635 }
636
637 writel(count, base + S5PC110_DMA_TRANS_SIZE);
638 writel(direction, base + S5PC110_DMA_TRANS_DIR);
639
640 writel(S5PC110_DMA_TRANS_CMD_TR, base + S5PC110_DMA_TRANS_CMD);
641
642 wait_for_completion_timeout(&onenand->complete, msecs_to_jiffies(20));
643
644 return 0;
645}
646
578static int s5pc110_read_bufferram(struct mtd_info *mtd, int area, 647static int s5pc110_read_bufferram(struct mtd_info *mtd, int area,
579 unsigned char *buffer, int offset, size_t count) 648 unsigned char *buffer, int offset, size_t count)
580{ 649{
@@ -919,6 +988,20 @@ static int s3c_onenand_probe(struct platform_device *pdev)
919 } 988 }
920 989
921 onenand->phys_base = onenand->base_res->start; 990 onenand->phys_base = onenand->base_res->start;
991
992 s5pc110_dma_ops = s5pc110_dma_poll;
993 /* Interrupt support */
994 r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
995 if (r) {
996 init_completion(&onenand->complete);
997 s5pc110_dma_ops = s5pc110_dma_irq;
998 err = request_irq(r->start, s5pc110_onenand_irq,
999 IRQF_SHARED, "onenand", &onenand);
1000 if (err) {
1001 dev_err(&pdev->dev, "failed to get irq\n");
1002 goto scan_failed;
1003 }
1004 }
922 } 1005 }
923 1006
924 if (onenand_scan(mtd, 1)) { 1007 if (onenand_scan(mtd, 1)) {