diff options
Diffstat (limited to 'arch/arm/mach-omap2/gpmc.c')
-rw-r--r-- | arch/arm/mach-omap2/gpmc.c | 71 |
1 files changed, 63 insertions, 8 deletions
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index f46933bc9373..130034bf01d5 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c | |||
@@ -14,6 +14,7 @@ | |||
14 | */ | 14 | */ |
15 | #undef DEBUG | 15 | #undef DEBUG |
16 | 16 | ||
17 | #include <linux/irq.h> | ||
17 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
18 | #include <linux/init.h> | 19 | #include <linux/init.h> |
19 | #include <linux/err.h> | 20 | #include <linux/err.h> |
@@ -22,6 +23,7 @@ | |||
22 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
23 | #include <linux/io.h> | 24 | #include <linux/io.h> |
24 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/interrupt.h> | ||
25 | 27 | ||
26 | #include <asm/mach-types.h> | 28 | #include <asm/mach-types.h> |
27 | #include <plat/gpmc.h> | 29 | #include <plat/gpmc.h> |
@@ -58,7 +60,6 @@ | |||
58 | #define GPMC_CHUNK_SHIFT 24 /* 16 MB */ | 60 | #define GPMC_CHUNK_SHIFT 24 /* 16 MB */ |
59 | #define GPMC_SECTION_SHIFT 28 /* 128 MB */ | 61 | #define GPMC_SECTION_SHIFT 28 /* 128 MB */ |
60 | 62 | ||
61 | #define PREFETCH_FIFOTHRESHOLD (0x40 << 8) | ||
62 | #define CS_NUM_SHIFT 24 | 63 | #define CS_NUM_SHIFT 24 |
63 | #define ENABLE_PREFETCH (0x1 << 7) | 64 | #define ENABLE_PREFETCH (0x1 << 7) |
64 | #define DMA_MPU_MODE 2 | 65 | #define DMA_MPU_MODE 2 |
@@ -100,6 +101,8 @@ static void __iomem *gpmc_base; | |||
100 | 101 | ||
101 | static struct clk *gpmc_l3_clk; | 102 | static struct clk *gpmc_l3_clk; |
102 | 103 | ||
104 | static irqreturn_t gpmc_handle_irq(int irq, void *dev); | ||
105 | |||
103 | static void gpmc_write_reg(int idx, u32 val) | 106 | static void gpmc_write_reg(int idx, u32 val) |
104 | { | 107 | { |
105 | __raw_writel(val, gpmc_base + idx); | 108 | __raw_writel(val, gpmc_base + idx); |
@@ -168,6 +171,16 @@ unsigned int gpmc_ns_to_ticks(unsigned int time_ns) | |||
168 | return (time_ns * 1000 + tick_ps - 1) / tick_ps; | 171 | return (time_ns * 1000 + tick_ps - 1) / tick_ps; |
169 | } | 172 | } |
170 | 173 | ||
174 | unsigned int gpmc_ps_to_ticks(unsigned int time_ps) | ||
175 | { | ||
176 | unsigned long tick_ps; | ||
177 | |||
178 | /* Calculate in picosecs to yield more exact results */ | ||
179 | tick_ps = gpmc_get_fclk_period(); | ||
180 | |||
181 | return (time_ps + tick_ps - 1) / tick_ps; | ||
182 | } | ||
183 | |||
171 | unsigned int gpmc_ticks_to_ns(unsigned int ticks) | 184 | unsigned int gpmc_ticks_to_ns(unsigned int ticks) |
172 | { | 185 | { |
173 | return ticks * gpmc_get_fclk_period() / 1000; | 186 | return ticks * gpmc_get_fclk_period() / 1000; |
@@ -235,7 +248,7 @@ int gpmc_cs_calc_divider(int cs, unsigned int sync_clk) | |||
235 | int div; | 248 | int div; |
236 | u32 l; | 249 | u32 l; |
237 | 250 | ||
238 | l = sync_clk * 1000 + (gpmc_get_fclk_period() - 1); | 251 | l = sync_clk + (gpmc_get_fclk_period() - 1); |
239 | div = l / gpmc_get_fclk_period(); | 252 | div = l / gpmc_get_fclk_period(); |
240 | if (div > 4) | 253 | if (div > 4) |
241 | return -1; | 254 | return -1; |
@@ -487,6 +500,10 @@ int gpmc_cs_configure(int cs, int cmd, int wval) | |||
487 | u32 regval = 0; | 500 | u32 regval = 0; |
488 | 501 | ||
489 | switch (cmd) { | 502 | switch (cmd) { |
503 | case GPMC_ENABLE_IRQ: | ||
504 | gpmc_write_reg(GPMC_IRQENABLE, wval); | ||
505 | break; | ||
506 | |||
490 | case GPMC_SET_IRQ_STATUS: | 507 | case GPMC_SET_IRQ_STATUS: |
491 | gpmc_write_reg(GPMC_IRQSTATUS, wval); | 508 | gpmc_write_reg(GPMC_IRQSTATUS, wval); |
492 | break; | 509 | break; |
@@ -588,15 +605,19 @@ EXPORT_SYMBOL(gpmc_nand_write); | |||
588 | /** | 605 | /** |
589 | * gpmc_prefetch_enable - configures and starts prefetch transfer | 606 | * gpmc_prefetch_enable - configures and starts prefetch transfer |
590 | * @cs: cs (chip select) number | 607 | * @cs: cs (chip select) number |
608 | * @fifo_th: fifo threshold to be used for read/ write | ||
591 | * @dma_mode: dma mode enable (1) or disable (0) | 609 | * @dma_mode: dma mode enable (1) or disable (0) |
592 | * @u32_count: number of bytes to be transferred | 610 | * @u32_count: number of bytes to be transferred |
593 | * @is_write: prefetch read(0) or write post(1) mode | 611 | * @is_write: prefetch read(0) or write post(1) mode |
594 | */ | 612 | */ |
595 | int gpmc_prefetch_enable(int cs, int dma_mode, | 613 | int gpmc_prefetch_enable(int cs, int fifo_th, int dma_mode, |
596 | unsigned int u32_count, int is_write) | 614 | unsigned int u32_count, int is_write) |
597 | { | 615 | { |
598 | 616 | ||
599 | if (!(gpmc_read_reg(GPMC_PREFETCH_CONTROL))) { | 617 | if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX) { |
618 | pr_err("gpmc: fifo threshold is not supported\n"); | ||
619 | return -1; | ||
620 | } else if (!(gpmc_read_reg(GPMC_PREFETCH_CONTROL))) { | ||
600 | /* Set the amount of bytes to be prefetched */ | 621 | /* Set the amount of bytes to be prefetched */ |
601 | gpmc_write_reg(GPMC_PREFETCH_CONFIG2, u32_count); | 622 | gpmc_write_reg(GPMC_PREFETCH_CONFIG2, u32_count); |
602 | 623 | ||
@@ -604,7 +625,7 @@ int gpmc_prefetch_enable(int cs, int dma_mode, | |||
604 | * enable the engine. Set which cs is has requested for. | 625 | * enable the engine. Set which cs is has requested for. |
605 | */ | 626 | */ |
606 | gpmc_write_reg(GPMC_PREFETCH_CONFIG1, ((cs << CS_NUM_SHIFT) | | 627 | gpmc_write_reg(GPMC_PREFETCH_CONFIG1, ((cs << CS_NUM_SHIFT) | |
607 | PREFETCH_FIFOTHRESHOLD | | 628 | PREFETCH_FIFOTHRESHOLD(fifo_th) | |
608 | ENABLE_PREFETCH | | 629 | ENABLE_PREFETCH | |
609 | (dma_mode << DMA_MPU_MODE) | | 630 | (dma_mode << DMA_MPU_MODE) | |
610 | (0x1 & is_write))); | 631 | (0x1 & is_write))); |
@@ -668,9 +689,11 @@ static void __init gpmc_mem_init(void) | |||
668 | } | 689 | } |
669 | } | 690 | } |
670 | 691 | ||
671 | void __init gpmc_init(void) | 692 | static int __init gpmc_init(void) |
672 | { | 693 | { |
673 | u32 l; | 694 | u32 l, irq; |
695 | int cs, ret = -EINVAL; | ||
696 | int gpmc_irq; | ||
674 | char *ck = NULL; | 697 | char *ck = NULL; |
675 | 698 | ||
676 | if (cpu_is_omap24xx()) { | 699 | if (cpu_is_omap24xx()) { |
@@ -679,16 +702,19 @@ void __init gpmc_init(void) | |||
679 | l = OMAP2420_GPMC_BASE; | 702 | l = OMAP2420_GPMC_BASE; |
680 | else | 703 | else |
681 | l = OMAP34XX_GPMC_BASE; | 704 | l = OMAP34XX_GPMC_BASE; |
705 | gpmc_irq = INT_34XX_GPMC_IRQ; | ||
682 | } else if (cpu_is_omap34xx()) { | 706 | } else if (cpu_is_omap34xx()) { |
683 | ck = "gpmc_fck"; | 707 | ck = "gpmc_fck"; |
684 | l = OMAP34XX_GPMC_BASE; | 708 | l = OMAP34XX_GPMC_BASE; |
709 | gpmc_irq = INT_34XX_GPMC_IRQ; | ||
685 | } else if (cpu_is_omap44xx()) { | 710 | } else if (cpu_is_omap44xx()) { |
686 | ck = "gpmc_ck"; | 711 | ck = "gpmc_ck"; |
687 | l = OMAP44XX_GPMC_BASE; | 712 | l = OMAP44XX_GPMC_BASE; |
713 | gpmc_irq = OMAP44XX_IRQ_GPMC; | ||
688 | } | 714 | } |
689 | 715 | ||
690 | if (WARN_ON(!ck)) | 716 | if (WARN_ON(!ck)) |
691 | return; | 717 | return ret; |
692 | 718 | ||
693 | gpmc_l3_clk = clk_get(NULL, ck); | 719 | gpmc_l3_clk = clk_get(NULL, ck); |
694 | if (IS_ERR(gpmc_l3_clk)) { | 720 | if (IS_ERR(gpmc_l3_clk)) { |
@@ -713,6 +739,35 @@ void __init gpmc_init(void) | |||
713 | l |= (0x02 << 3) | (1 << 0); | 739 | l |= (0x02 << 3) | (1 << 0); |
714 | gpmc_write_reg(GPMC_SYSCONFIG, l); | 740 | gpmc_write_reg(GPMC_SYSCONFIG, l); |
715 | gpmc_mem_init(); | 741 | gpmc_mem_init(); |
742 | |||
743 | /* initalize the irq_chained */ | ||
744 | irq = OMAP_GPMC_IRQ_BASE; | ||
745 | for (cs = 0; cs < GPMC_CS_NUM; cs++) { | ||
746 | irq_set_chip_and_handler(irq, &dummy_irq_chip, | ||
747 | handle_simple_irq); | ||
748 | set_irq_flags(irq, IRQF_VALID); | ||
749 | irq++; | ||
750 | } | ||
751 | |||
752 | ret = request_irq(gpmc_irq, | ||
753 | gpmc_handle_irq, IRQF_SHARED, "gpmc", gpmc_base); | ||
754 | if (ret) | ||
755 | pr_err("gpmc: irq-%d could not claim: err %d\n", | ||
756 | gpmc_irq, ret); | ||
757 | return ret; | ||
758 | } | ||
759 | postcore_initcall(gpmc_init); | ||
760 | |||
761 | static irqreturn_t gpmc_handle_irq(int irq, void *dev) | ||
762 | { | ||
763 | u8 cs; | ||
764 | |||
765 | /* check cs to invoke the irq */ | ||
766 | cs = ((gpmc_read_reg(GPMC_PREFETCH_CONFIG1)) >> CS_NUM_SHIFT) & 0x7; | ||
767 | if (OMAP_GPMC_IRQ_BASE+cs <= OMAP_GPMC_IRQ_END) | ||
768 | generic_handle_irq(OMAP_GPMC_IRQ_BASE+cs); | ||
769 | |||
770 | return IRQ_HANDLED; | ||
716 | } | 771 | } |
717 | 772 | ||
718 | #ifdef CONFIG_ARCH_OMAP3 | 773 | #ifdef CONFIG_ARCH_OMAP3 |