aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/onenand/samsung.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/onenand/samsung.c')
-rw-r--r--drivers/mtd/onenand/samsung.c133
1 files changed, 115 insertions, 18 deletions
diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c
index a460f1b748c2..0de7a05e6de0 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>
@@ -58,7 +59,7 @@ enum soc_type {
58#define MAP_11 (0x3) 59#define MAP_11 (0x3)
59 60
60#define S3C64XX_CMD_MAP_SHIFT 24 61#define S3C64XX_CMD_MAP_SHIFT 24
61#define S5PC1XX_CMD_MAP_SHIFT 26 62#define S5PC100_CMD_MAP_SHIFT 26
62 63
63#define S3C6400_FBA_SHIFT 10 64#define S3C6400_FBA_SHIFT 10
64#define S3C6400_FPA_SHIFT 4 65#define S3C6400_FPA_SHIFT 4
@@ -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
@@ -191,7 +204,7 @@ static unsigned int s3c64xx_cmd_map(unsigned type, unsigned val)
191 204
192static unsigned int s5pc1xx_cmd_map(unsigned type, unsigned val) 205static unsigned int s5pc1xx_cmd_map(unsigned type, unsigned val)
193{ 206{
194 return (type << S5PC1XX_CMD_MAP_SHIFT) | val; 207 return (type << S5PC100_CMD_MAP_SHIFT) | val;
195} 208}
196 209
197static unsigned int s3c6400_mem_addr(int fba, int fpa, int fsa) 210static unsigned int s3c6400_mem_addr(int fba, int fpa, int fsa)
@@ -531,10 +544,13 @@ 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;
553 unsigned long timeout;
538 554
539 writel(src, base + S5PC110_DMA_SRC_ADDR); 555 writel(src, base + S5PC110_DMA_SRC_ADDR);
540 writel(dst, base + S5PC110_DMA_DST_ADDR); 556 writel(dst, base + S5PC110_DMA_DST_ADDR);
@@ -552,6 +568,13 @@ static int s5pc110_dma_ops(void *dst, void *src, size_t count, int direction)
552 568
553 writel(S5PC110_DMA_TRANS_CMD_TR, base + S5PC110_DMA_TRANS_CMD); 569 writel(S5PC110_DMA_TRANS_CMD_TR, base + S5PC110_DMA_TRANS_CMD);
554 570
571 /*
572 * There's no exact timeout values at Spec.
573 * In real case it takes under 1 msec.
574 * So 20 msecs are enough.
575 */
576 timeout = jiffies + msecs_to_jiffies(20);
577
555 do { 578 do {
556 status = readl(base + S5PC110_DMA_TRANS_STATUS); 579 status = readl(base + S5PC110_DMA_TRANS_STATUS);
557 if (status & S5PC110_DMA_TRANS_STATUS_TE) { 580 if (status & S5PC110_DMA_TRANS_STATUS_TE) {
@@ -559,13 +582,68 @@ static int s5pc110_dma_ops(void *dst, void *src, size_t count, int direction)
559 base + S5PC110_DMA_TRANS_CMD); 582 base + S5PC110_DMA_TRANS_CMD);
560 return -EIO; 583 return -EIO;
561 } 584 }
562 } while (!(status & S5PC110_DMA_TRANS_STATUS_TD)); 585 } while (!(status & S5PC110_DMA_TRANS_STATUS_TD) &&
586 time_before(jiffies, timeout));
563 587
564 writel(S5PC110_DMA_TRANS_CMD_TDC, base + S5PC110_DMA_TRANS_CMD); 588 writel(S5PC110_DMA_TRANS_CMD_TDC, base + S5PC110_DMA_TRANS_CMD);
565 589
566 return 0; 590 return 0;
567} 591}
568 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
569static int s5pc110_read_bufferram(struct mtd_info *mtd, int area, 647static int s5pc110_read_bufferram(struct mtd_info *mtd, int area,
570 unsigned char *buffer, int offset, size_t count) 648 unsigned char *buffer, int offset, size_t count)
571{ 649{
@@ -573,7 +651,8 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area,
573 void __iomem *p; 651 void __iomem *p;
574 void *buf = (void *) buffer; 652 void *buf = (void *) buffer;
575 dma_addr_t dma_src, dma_dst; 653 dma_addr_t dma_src, dma_dst;
576 int err; 654 int err, page_dma = 0;
655 struct device *dev = &onenand->pdev->dev;
577 656
578 p = this->base + area; 657 p = this->base + area;
579 if (ONENAND_CURRENT_BUFFERRAM(this)) { 658 if (ONENAND_CURRENT_BUFFERRAM(this)) {
@@ -597,21 +676,27 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area,
597 page = vmalloc_to_page(buf); 676 page = vmalloc_to_page(buf);
598 if (!page) 677 if (!page)
599 goto normal; 678 goto normal;
600 buf = page_address(page) + ((size_t) buf & ~PAGE_MASK);
601 }
602 679
603 /* DMA routine */ 680 page_dma = 1;
604 dma_src = onenand->phys_base + (p - this->base); 681 /* DMA routine */
605 dma_dst = dma_map_single(&onenand->pdev->dev, 682 dma_src = onenand->phys_base + (p - this->base);
606 buf, count, DMA_FROM_DEVICE); 683 dma_dst = dma_map_page(dev, page, 0, count, DMA_FROM_DEVICE);
607 if (dma_mapping_error(&onenand->pdev->dev, dma_dst)) { 684 } else {
608 dev_err(&onenand->pdev->dev, 685 /* DMA routine */
609 "Couldn't map a %d byte buffer for DMA\n", count); 686 dma_src = onenand->phys_base + (p - this->base);
687 dma_dst = dma_map_single(dev, buf, count, DMA_FROM_DEVICE);
688 }
689 if (dma_mapping_error(dev, dma_dst)) {
690 dev_err(dev, "Couldn't map a %d byte buffer for DMA\n", count);
610 goto normal; 691 goto normal;
611 } 692 }
612 err = s5pc110_dma_ops((void *) dma_dst, (void *) dma_src, 693 err = s5pc110_dma_ops((void *) dma_dst, (void *) dma_src,
613 count, S5PC110_DMA_DIR_READ); 694 count, S5PC110_DMA_DIR_READ);
614 dma_unmap_single(&onenand->pdev->dev, dma_dst, count, DMA_FROM_DEVICE); 695
696 if (page_dma)
697 dma_unmap_page(dev, dma_dst, count, DMA_FROM_DEVICE);
698 else
699 dma_unmap_single(dev, dma_dst, count, DMA_FROM_DEVICE);
615 700
616 if (!err) 701 if (!err)
617 return 0; 702 return 0;
@@ -759,7 +844,6 @@ static void s3c_onenand_setup(struct mtd_info *mtd)
759 onenand->cmd_map = s5pc1xx_cmd_map; 844 onenand->cmd_map = s5pc1xx_cmd_map;
760 } else if (onenand->type == TYPE_S5PC110) { 845 } else if (onenand->type == TYPE_S5PC110) {
761 /* Use generic onenand functions */ 846 /* Use generic onenand functions */
762 onenand->cmd_map = s5pc1xx_cmd_map;
763 this->read_bufferram = s5pc110_read_bufferram; 847 this->read_bufferram = s5pc110_read_bufferram;
764 this->chip_probe = s5pc110_chip_probe; 848 this->chip_probe = s5pc110_chip_probe;
765 return; 849 return;
@@ -904,6 +988,20 @@ static int s3c_onenand_probe(struct platform_device *pdev)
904 } 988 }
905 989
906 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 }
907 } 1005 }
908 1006
909 if (onenand_scan(mtd, 1)) { 1007 if (onenand_scan(mtd, 1)) {
@@ -1000,7 +1098,7 @@ static int s3c_pm_ops_suspend(struct device *dev)
1000 struct onenand_chip *this = mtd->priv; 1098 struct onenand_chip *this = mtd->priv;
1001 1099
1002 this->wait(mtd, FL_PM_SUSPENDED); 1100 this->wait(mtd, FL_PM_SUSPENDED);
1003 return mtd->suspend(mtd); 1101 return 0;
1004} 1102}
1005 1103
1006static int s3c_pm_ops_resume(struct device *dev) 1104static int s3c_pm_ops_resume(struct device *dev)
@@ -1009,7 +1107,6 @@ static int s3c_pm_ops_resume(struct device *dev)
1009 struct mtd_info *mtd = platform_get_drvdata(pdev); 1107 struct mtd_info *mtd = platform_get_drvdata(pdev);
1010 struct onenand_chip *this = mtd->priv; 1108 struct onenand_chip *this = mtd->priv;
1011 1109
1012 mtd->resume(mtd);
1013 this->unlock_all(mtd); 1110 this->unlock_all(mtd);
1014 return 0; 1111 return 0;
1015} 1112}