diff options
Diffstat (limited to 'arch/arm/mach-omap2/gpmc.c')
-rw-r--r-- | arch/arm/mach-omap2/gpmc.c | 167 |
1 files changed, 147 insertions, 20 deletions
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index b2b5759ab0fe..055ae8bd943f 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c | |||
@@ -28,8 +28,13 @@ | |||
28 | #include <asm/mach-types.h> | 28 | #include <asm/mach-types.h> |
29 | #include <plat/gpmc.h> | 29 | #include <plat/gpmc.h> |
30 | 30 | ||
31 | #include <plat/cpu.h> | ||
32 | #include <plat/gpmc.h> | ||
31 | #include <plat/sdrc.h> | 33 | #include <plat/sdrc.h> |
32 | 34 | ||
35 | #include "soc.h" | ||
36 | #include "common.h" | ||
37 | |||
33 | /* GPMC register offsets */ | 38 | /* GPMC register offsets */ |
34 | #define GPMC_REVISION 0x00 | 39 | #define GPMC_REVISION 0x00 |
35 | #define GPMC_SYSCONFIG 0x10 | 40 | #define GPMC_SYSCONFIG 0x10 |
@@ -78,6 +83,15 @@ | |||
78 | #define ENABLE_PREFETCH (0x1 << 7) | 83 | #define ENABLE_PREFETCH (0x1 << 7) |
79 | #define DMA_MPU_MODE 2 | 84 | #define DMA_MPU_MODE 2 |
80 | 85 | ||
86 | /* XXX: Only NAND irq has been considered,currently these are the only ones used | ||
87 | */ | ||
88 | #define GPMC_NR_IRQ 2 | ||
89 | |||
90 | struct gpmc_client_irq { | ||
91 | unsigned irq; | ||
92 | u32 bitmask; | ||
93 | }; | ||
94 | |||
81 | /* Structure to save gpmc cs context */ | 95 | /* Structure to save gpmc cs context */ |
82 | struct gpmc_cs_config { | 96 | struct gpmc_cs_config { |
83 | u32 config1; | 97 | u32 config1; |
@@ -105,6 +119,10 @@ struct omap3_gpmc_regs { | |||
105 | struct gpmc_cs_config cs_context[GPMC_CS_NUM]; | 119 | struct gpmc_cs_config cs_context[GPMC_CS_NUM]; |
106 | }; | 120 | }; |
107 | 121 | ||
122 | static struct gpmc_client_irq gpmc_client_irq[GPMC_NR_IRQ]; | ||
123 | static struct irq_chip gpmc_irq_chip; | ||
124 | static unsigned gpmc_irq_start; | ||
125 | |||
108 | static struct resource gpmc_mem_root; | 126 | static struct resource gpmc_mem_root; |
109 | static struct resource gpmc_cs_mem[GPMC_CS_NUM]; | 127 | static struct resource gpmc_cs_mem[GPMC_CS_NUM]; |
110 | static DEFINE_SPINLOCK(gpmc_mem_lock); | 128 | static DEFINE_SPINLOCK(gpmc_mem_lock); |
@@ -682,6 +700,117 @@ int gpmc_prefetch_reset(int cs) | |||
682 | } | 700 | } |
683 | EXPORT_SYMBOL(gpmc_prefetch_reset); | 701 | EXPORT_SYMBOL(gpmc_prefetch_reset); |
684 | 702 | ||
703 | void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs) | ||
704 | { | ||
705 | reg->gpmc_status = gpmc_base + GPMC_STATUS; | ||
706 | reg->gpmc_nand_command = gpmc_base + GPMC_CS0_OFFSET + | ||
707 | GPMC_CS_NAND_COMMAND + GPMC_CS_SIZE * cs; | ||
708 | reg->gpmc_nand_address = gpmc_base + GPMC_CS0_OFFSET + | ||
709 | GPMC_CS_NAND_ADDRESS + GPMC_CS_SIZE * cs; | ||
710 | reg->gpmc_nand_data = gpmc_base + GPMC_CS0_OFFSET + | ||
711 | GPMC_CS_NAND_DATA + GPMC_CS_SIZE * cs; | ||
712 | reg->gpmc_prefetch_config1 = gpmc_base + GPMC_PREFETCH_CONFIG1; | ||
713 | reg->gpmc_prefetch_config2 = gpmc_base + GPMC_PREFETCH_CONFIG2; | ||
714 | reg->gpmc_prefetch_control = gpmc_base + GPMC_PREFETCH_CONTROL; | ||
715 | reg->gpmc_prefetch_status = gpmc_base + GPMC_PREFETCH_STATUS; | ||
716 | reg->gpmc_ecc_config = gpmc_base + GPMC_ECC_CONFIG; | ||
717 | reg->gpmc_ecc_control = gpmc_base + GPMC_ECC_CONTROL; | ||
718 | reg->gpmc_ecc_size_config = gpmc_base + GPMC_ECC_SIZE_CONFIG; | ||
719 | reg->gpmc_ecc1_result = gpmc_base + GPMC_ECC1_RESULT; | ||
720 | reg->gpmc_bch_result0 = gpmc_base + GPMC_ECC_BCH_RESULT_0; | ||
721 | } | ||
722 | |||
723 | int gpmc_get_client_irq(unsigned irq_config) | ||
724 | { | ||
725 | int i; | ||
726 | |||
727 | if (hweight32(irq_config) > 1) | ||
728 | return 0; | ||
729 | |||
730 | for (i = 0; i < GPMC_NR_IRQ; i++) | ||
731 | if (gpmc_client_irq[i].bitmask & irq_config) | ||
732 | return gpmc_client_irq[i].irq; | ||
733 | |||
734 | return 0; | ||
735 | } | ||
736 | |||
737 | static int gpmc_irq_endis(unsigned irq, bool endis) | ||
738 | { | ||
739 | int i; | ||
740 | u32 regval; | ||
741 | |||
742 | for (i = 0; i < GPMC_NR_IRQ; i++) | ||
743 | if (irq == gpmc_client_irq[i].irq) { | ||
744 | regval = gpmc_read_reg(GPMC_IRQENABLE); | ||
745 | if (endis) | ||
746 | regval |= gpmc_client_irq[i].bitmask; | ||
747 | else | ||
748 | regval &= ~gpmc_client_irq[i].bitmask; | ||
749 | gpmc_write_reg(GPMC_IRQENABLE, regval); | ||
750 | break; | ||
751 | } | ||
752 | |||
753 | return 0; | ||
754 | } | ||
755 | |||
756 | static void gpmc_irq_disable(struct irq_data *p) | ||
757 | { | ||
758 | gpmc_irq_endis(p->irq, false); | ||
759 | } | ||
760 | |||
761 | static void gpmc_irq_enable(struct irq_data *p) | ||
762 | { | ||
763 | gpmc_irq_endis(p->irq, true); | ||
764 | } | ||
765 | |||
766 | static void gpmc_irq_noop(struct irq_data *data) { } | ||
767 | |||
768 | static unsigned int gpmc_irq_noop_ret(struct irq_data *data) { return 0; } | ||
769 | |||
770 | static int gpmc_setup_irq(int gpmc_irq) | ||
771 | { | ||
772 | int i; | ||
773 | u32 regval; | ||
774 | |||
775 | if (!gpmc_irq) | ||
776 | return -EINVAL; | ||
777 | |||
778 | gpmc_irq_start = irq_alloc_descs(-1, 0, GPMC_NR_IRQ, 0); | ||
779 | if (IS_ERR_VALUE(gpmc_irq_start)) { | ||
780 | pr_err("irq_alloc_descs failed\n"); | ||
781 | return gpmc_irq_start; | ||
782 | } | ||
783 | |||
784 | gpmc_irq_chip.name = "gpmc"; | ||
785 | gpmc_irq_chip.irq_startup = gpmc_irq_noop_ret; | ||
786 | gpmc_irq_chip.irq_enable = gpmc_irq_enable; | ||
787 | gpmc_irq_chip.irq_disable = gpmc_irq_disable; | ||
788 | gpmc_irq_chip.irq_shutdown = gpmc_irq_noop; | ||
789 | gpmc_irq_chip.irq_ack = gpmc_irq_noop; | ||
790 | gpmc_irq_chip.irq_mask = gpmc_irq_noop; | ||
791 | gpmc_irq_chip.irq_unmask = gpmc_irq_noop; | ||
792 | |||
793 | gpmc_client_irq[0].bitmask = GPMC_IRQ_FIFOEVENTENABLE; | ||
794 | gpmc_client_irq[1].bitmask = GPMC_IRQ_COUNT_EVENT; | ||
795 | |||
796 | for (i = 0; i < GPMC_NR_IRQ; i++) { | ||
797 | gpmc_client_irq[i].irq = gpmc_irq_start + i; | ||
798 | irq_set_chip_and_handler(gpmc_client_irq[i].irq, | ||
799 | &gpmc_irq_chip, handle_simple_irq); | ||
800 | set_irq_flags(gpmc_client_irq[i].irq, | ||
801 | IRQF_VALID | IRQF_NOAUTOEN); | ||
802 | } | ||
803 | |||
804 | /* Disable interrupts */ | ||
805 | gpmc_write_reg(GPMC_IRQENABLE, 0); | ||
806 | |||
807 | /* clear interrupts */ | ||
808 | regval = gpmc_read_reg(GPMC_IRQSTATUS); | ||
809 | gpmc_write_reg(GPMC_IRQSTATUS, regval); | ||
810 | |||
811 | return request_irq(gpmc_irq, gpmc_handle_irq, 0, "gpmc", NULL); | ||
812 | } | ||
813 | |||
685 | static void __init gpmc_mem_init(void) | 814 | static void __init gpmc_mem_init(void) |
686 | { | 815 | { |
687 | int cs; | 816 | int cs; |
@@ -711,8 +840,8 @@ static void __init gpmc_mem_init(void) | |||
711 | 840 | ||
712 | static int __init gpmc_init(void) | 841 | static int __init gpmc_init(void) |
713 | { | 842 | { |
714 | u32 l, irq; | 843 | u32 l; |
715 | int cs, ret = -EINVAL; | 844 | int ret = -EINVAL; |
716 | int gpmc_irq; | 845 | int gpmc_irq; |
717 | char *ck = NULL; | 846 | char *ck = NULL; |
718 | 847 | ||
@@ -722,16 +851,16 @@ static int __init gpmc_init(void) | |||
722 | l = OMAP2420_GPMC_BASE; | 851 | l = OMAP2420_GPMC_BASE; |
723 | else | 852 | else |
724 | l = OMAP34XX_GPMC_BASE; | 853 | l = OMAP34XX_GPMC_BASE; |
725 | gpmc_irq = INT_34XX_GPMC_IRQ; | 854 | gpmc_irq = 20 + OMAP_INTC_START; |
726 | } else if (cpu_is_omap34xx()) { | 855 | } else if (cpu_is_omap34xx()) { |
727 | ck = "gpmc_fck"; | 856 | ck = "gpmc_fck"; |
728 | l = OMAP34XX_GPMC_BASE; | 857 | l = OMAP34XX_GPMC_BASE; |
729 | gpmc_irq = INT_34XX_GPMC_IRQ; | 858 | gpmc_irq = 20 + OMAP_INTC_START; |
730 | } else if (cpu_is_omap44xx() || soc_is_omap54xx()) { | 859 | } else if (cpu_is_omap44xx() || soc_is_omap54xx()) { |
731 | /* Base address and irq number are same for OMAP4/5 */ | 860 | /* Base address and irq number are same for OMAP4/5 */ |
732 | ck = "gpmc_ck"; | 861 | ck = "gpmc_ck"; |
733 | l = OMAP44XX_GPMC_BASE; | 862 | l = OMAP44XX_GPMC_BASE; |
734 | gpmc_irq = OMAP44XX_IRQ_GPMC; | 863 | gpmc_irq = 20 + OMAP44XX_IRQ_GIC_START; |
735 | } | 864 | } |
736 | 865 | ||
737 | if (WARN_ON(!ck)) | 866 | if (WARN_ON(!ck)) |
@@ -761,16 +890,7 @@ static int __init gpmc_init(void) | |||
761 | gpmc_write_reg(GPMC_SYSCONFIG, l); | 890 | gpmc_write_reg(GPMC_SYSCONFIG, l); |
762 | gpmc_mem_init(); | 891 | gpmc_mem_init(); |
763 | 892 | ||
764 | /* initalize the irq_chained */ | 893 | ret = gpmc_setup_irq(gpmc_irq); |
765 | irq = OMAP_GPMC_IRQ_BASE; | ||
766 | for (cs = 0; cs < GPMC_CS_NUM; cs++) { | ||
767 | irq_set_chip_and_handler(irq, &dummy_irq_chip, | ||
768 | handle_simple_irq); | ||
769 | set_irq_flags(irq, IRQF_VALID); | ||
770 | irq++; | ||
771 | } | ||
772 | |||
773 | ret = request_irq(gpmc_irq, gpmc_handle_irq, IRQF_SHARED, "gpmc", NULL); | ||
774 | if (ret) | 894 | if (ret) |
775 | pr_err("gpmc: irq-%d could not claim: err %d\n", | 895 | pr_err("gpmc: irq-%d could not claim: err %d\n", |
776 | gpmc_irq, ret); | 896 | gpmc_irq, ret); |
@@ -780,12 +900,19 @@ postcore_initcall(gpmc_init); | |||
780 | 900 | ||
781 | static irqreturn_t gpmc_handle_irq(int irq, void *dev) | 901 | static irqreturn_t gpmc_handle_irq(int irq, void *dev) |
782 | { | 902 | { |
783 | u8 cs; | 903 | int i; |
904 | u32 regval; | ||
905 | |||
906 | regval = gpmc_read_reg(GPMC_IRQSTATUS); | ||
907 | |||
908 | if (!regval) | ||
909 | return IRQ_NONE; | ||
910 | |||
911 | for (i = 0; i < GPMC_NR_IRQ; i++) | ||
912 | if (regval & gpmc_client_irq[i].bitmask) | ||
913 | generic_handle_irq(gpmc_client_irq[i].irq); | ||
784 | 914 | ||
785 | /* check cs to invoke the irq */ | 915 | gpmc_write_reg(GPMC_IRQSTATUS, regval); |
786 | cs = ((gpmc_read_reg(GPMC_PREFETCH_CONFIG1)) >> CS_NUM_SHIFT) & 0x7; | ||
787 | if (OMAP_GPMC_IRQ_BASE+cs <= OMAP_GPMC_IRQ_END) | ||
788 | generic_handle_irq(OMAP_GPMC_IRQ_BASE+cs); | ||
789 | 916 | ||
790 | return IRQ_HANDLED; | 917 | return IRQ_HANDLED; |
791 | } | 918 | } |