diff options
Diffstat (limited to 'arch/arm/mach-omap2')
-rw-r--r-- | arch/arm/mach-omap2/gpmc-nand.c | 28 | ||||
-rw-r--r-- | arch/arm/mach-omap2/gpmc-onenand.c | 23 | ||||
-rw-r--r-- | arch/arm/mach-omap2/gpmc.c | 156 |
3 files changed, 184 insertions, 23 deletions
diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c index 386dec8d2351..045596a3e899 100644 --- a/arch/arm/mach-omap2/gpmc-nand.c +++ b/arch/arm/mach-omap2/gpmc-nand.c | |||
@@ -21,15 +21,23 @@ | |||
21 | #include <plat/board.h> | 21 | #include <plat/board.h> |
22 | #include <plat/gpmc.h> | 22 | #include <plat/gpmc.h> |
23 | 23 | ||
24 | static struct resource gpmc_nand_resource = { | 24 | static struct resource gpmc_nand_resource[] = { |
25 | .flags = IORESOURCE_MEM, | 25 | { |
26 | .flags = IORESOURCE_MEM, | ||
27 | }, | ||
28 | { | ||
29 | .flags = IORESOURCE_IRQ, | ||
30 | }, | ||
31 | { | ||
32 | .flags = IORESOURCE_IRQ, | ||
33 | }, | ||
26 | }; | 34 | }; |
27 | 35 | ||
28 | static struct platform_device gpmc_nand_device = { | 36 | static struct platform_device gpmc_nand_device = { |
29 | .name = "omap2-nand", | 37 | .name = "omap2-nand", |
30 | .id = 0, | 38 | .id = 0, |
31 | .num_resources = 1, | 39 | .num_resources = ARRAY_SIZE(gpmc_nand_resource), |
32 | .resource = &gpmc_nand_resource, | 40 | .resource = gpmc_nand_resource, |
33 | }; | 41 | }; |
34 | 42 | ||
35 | static int omap2_nand_gpmc_retime(struct omap_nand_platform_data *gpmc_nand_data) | 43 | static int omap2_nand_gpmc_retime(struct omap_nand_platform_data *gpmc_nand_data) |
@@ -75,6 +83,7 @@ static int omap2_nand_gpmc_retime(struct omap_nand_platform_data *gpmc_nand_data | |||
75 | gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_DEV_SIZE, 0); | 83 | gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_DEV_SIZE, 0); |
76 | gpmc_cs_configure(gpmc_nand_data->cs, | 84 | gpmc_cs_configure(gpmc_nand_data->cs, |
77 | GPMC_CONFIG_DEV_TYPE, GPMC_DEVICETYPE_NAND); | 85 | GPMC_CONFIG_DEV_TYPE, GPMC_DEVICETYPE_NAND); |
86 | gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_WP, 0); | ||
78 | err = gpmc_cs_set_timings(gpmc_nand_data->cs, &t); | 87 | err = gpmc_cs_set_timings(gpmc_nand_data->cs, &t); |
79 | if (err) | 88 | if (err) |
80 | return err; | 89 | return err; |
@@ -90,12 +99,19 @@ int __init gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data) | |||
90 | gpmc_nand_device.dev.platform_data = gpmc_nand_data; | 99 | gpmc_nand_device.dev.platform_data = gpmc_nand_data; |
91 | 100 | ||
92 | err = gpmc_cs_request(gpmc_nand_data->cs, NAND_IO_SIZE, | 101 | err = gpmc_cs_request(gpmc_nand_data->cs, NAND_IO_SIZE, |
93 | &gpmc_nand_data->phys_base); | 102 | (unsigned long *)&gpmc_nand_resource[0].start); |
94 | if (err < 0) { | 103 | if (err < 0) { |
95 | dev_err(dev, "Cannot request GPMC CS\n"); | 104 | dev_err(dev, "Cannot request GPMC CS\n"); |
96 | return err; | 105 | return err; |
97 | } | 106 | } |
98 | 107 | ||
108 | gpmc_nand_resource[0].end = gpmc_nand_resource[0].start + | ||
109 | NAND_IO_SIZE - 1; | ||
110 | |||
111 | gpmc_nand_resource[1].start = | ||
112 | gpmc_get_client_irq(GPMC_IRQ_FIFOEVENTENABLE); | ||
113 | gpmc_nand_resource[2].start = | ||
114 | gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT); | ||
99 | /* Set timings in GPMC */ | 115 | /* Set timings in GPMC */ |
100 | err = omap2_nand_gpmc_retime(gpmc_nand_data); | 116 | err = omap2_nand_gpmc_retime(gpmc_nand_data); |
101 | if (err < 0) { | 117 | if (err < 0) { |
@@ -108,6 +124,8 @@ int __init gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data) | |||
108 | gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_RDY_BSY, 1); | 124 | gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_RDY_BSY, 1); |
109 | } | 125 | } |
110 | 126 | ||
127 | gpmc_update_nand_reg(&gpmc_nand_data->reg, gpmc_nand_data->cs); | ||
128 | |||
111 | err = platform_device_register(&gpmc_nand_device); | 129 | err = platform_device_register(&gpmc_nand_device); |
112 | if (err < 0) { | 130 | if (err < 0) { |
113 | dev_err(dev, "Unable to register NAND device\n"); | 131 | dev_err(dev, "Unable to register NAND device\n"); |
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c index a0fa9bb2bda5..71d7c07dd350 100644 --- a/arch/arm/mach-omap2/gpmc-onenand.c +++ b/arch/arm/mach-omap2/gpmc-onenand.c | |||
@@ -23,11 +23,19 @@ | |||
23 | #include <plat/board.h> | 23 | #include <plat/board.h> |
24 | #include <plat/gpmc.h> | 24 | #include <plat/gpmc.h> |
25 | 25 | ||
26 | #define ONENAND_IO_SIZE SZ_128K | ||
27 | |||
26 | static struct omap_onenand_platform_data *gpmc_onenand_data; | 28 | static struct omap_onenand_platform_data *gpmc_onenand_data; |
27 | 29 | ||
30 | static struct resource gpmc_onenand_resource = { | ||
31 | .flags = IORESOURCE_MEM, | ||
32 | }; | ||
33 | |||
28 | static struct platform_device gpmc_onenand_device = { | 34 | static struct platform_device gpmc_onenand_device = { |
29 | .name = "omap2-onenand", | 35 | .name = "omap2-onenand", |
30 | .id = -1, | 36 | .id = -1, |
37 | .num_resources = 1, | ||
38 | .resource = &gpmc_onenand_resource, | ||
31 | }; | 39 | }; |
32 | 40 | ||
33 | static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base) | 41 | static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base) |
@@ -390,6 +398,8 @@ static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr) | |||
390 | 398 | ||
391 | void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) | 399 | void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) |
392 | { | 400 | { |
401 | int err; | ||
402 | |||
393 | gpmc_onenand_data = _onenand_data; | 403 | gpmc_onenand_data = _onenand_data; |
394 | gpmc_onenand_data->onenand_setup = gpmc_onenand_setup; | 404 | gpmc_onenand_data->onenand_setup = gpmc_onenand_setup; |
395 | gpmc_onenand_device.dev.platform_data = gpmc_onenand_data; | 405 | gpmc_onenand_device.dev.platform_data = gpmc_onenand_data; |
@@ -401,8 +411,19 @@ void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) | |||
401 | gpmc_onenand_data->flags |= ONENAND_SYNC_READ; | 411 | gpmc_onenand_data->flags |= ONENAND_SYNC_READ; |
402 | } | 412 | } |
403 | 413 | ||
414 | err = gpmc_cs_request(gpmc_onenand_data->cs, ONENAND_IO_SIZE, | ||
415 | (unsigned long *)&gpmc_onenand_resource.start); | ||
416 | if (err < 0) { | ||
417 | pr_err("%s: Cannot request GPMC CS\n", __func__); | ||
418 | return; | ||
419 | } | ||
420 | |||
421 | gpmc_onenand_resource.end = gpmc_onenand_resource.start + | ||
422 | ONENAND_IO_SIZE - 1; | ||
423 | |||
404 | if (platform_device_register(&gpmc_onenand_device) < 0) { | 424 | if (platform_device_register(&gpmc_onenand_device) < 0) { |
405 | printk(KERN_ERR "Unable to register OneNAND device\n"); | 425 | pr_err("%s: Unable to register OneNAND device\n", __func__); |
426 | gpmc_cs_free(gpmc_onenand_data->cs); | ||
406 | return; | 427 | return; |
407 | } | 428 | } |
408 | } | 429 | } |
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index b2b5759ab0fe..39c30d9bafd9 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c | |||
@@ -78,6 +78,15 @@ | |||
78 | #define ENABLE_PREFETCH (0x1 << 7) | 78 | #define ENABLE_PREFETCH (0x1 << 7) |
79 | #define DMA_MPU_MODE 2 | 79 | #define DMA_MPU_MODE 2 |
80 | 80 | ||
81 | /* XXX: Only NAND irq has been considered,currently these are the only ones used | ||
82 | */ | ||
83 | #define GPMC_NR_IRQ 2 | ||
84 | |||
85 | struct gpmc_client_irq { | ||
86 | unsigned irq; | ||
87 | u32 bitmask; | ||
88 | }; | ||
89 | |||
81 | /* Structure to save gpmc cs context */ | 90 | /* Structure to save gpmc cs context */ |
82 | struct gpmc_cs_config { | 91 | struct gpmc_cs_config { |
83 | u32 config1; | 92 | u32 config1; |
@@ -105,6 +114,10 @@ struct omap3_gpmc_regs { | |||
105 | struct gpmc_cs_config cs_context[GPMC_CS_NUM]; | 114 | struct gpmc_cs_config cs_context[GPMC_CS_NUM]; |
106 | }; | 115 | }; |
107 | 116 | ||
117 | static struct gpmc_client_irq gpmc_client_irq[GPMC_NR_IRQ]; | ||
118 | static struct irq_chip gpmc_irq_chip; | ||
119 | static unsigned gpmc_irq_start; | ||
120 | |||
108 | static struct resource gpmc_mem_root; | 121 | static struct resource gpmc_mem_root; |
109 | static struct resource gpmc_cs_mem[GPMC_CS_NUM]; | 122 | static struct resource gpmc_cs_mem[GPMC_CS_NUM]; |
110 | static DEFINE_SPINLOCK(gpmc_mem_lock); | 123 | static DEFINE_SPINLOCK(gpmc_mem_lock); |
@@ -682,6 +695,117 @@ int gpmc_prefetch_reset(int cs) | |||
682 | } | 695 | } |
683 | EXPORT_SYMBOL(gpmc_prefetch_reset); | 696 | EXPORT_SYMBOL(gpmc_prefetch_reset); |
684 | 697 | ||
698 | void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs) | ||
699 | { | ||
700 | reg->gpmc_status = gpmc_base + GPMC_STATUS; | ||
701 | reg->gpmc_nand_command = gpmc_base + GPMC_CS0_OFFSET + | ||
702 | GPMC_CS_NAND_COMMAND + GPMC_CS_SIZE * cs; | ||
703 | reg->gpmc_nand_address = gpmc_base + GPMC_CS0_OFFSET + | ||
704 | GPMC_CS_NAND_ADDRESS + GPMC_CS_SIZE * cs; | ||
705 | reg->gpmc_nand_data = gpmc_base + GPMC_CS0_OFFSET + | ||
706 | GPMC_CS_NAND_DATA + GPMC_CS_SIZE * cs; | ||
707 | reg->gpmc_prefetch_config1 = gpmc_base + GPMC_PREFETCH_CONFIG1; | ||
708 | reg->gpmc_prefetch_config2 = gpmc_base + GPMC_PREFETCH_CONFIG2; | ||
709 | reg->gpmc_prefetch_control = gpmc_base + GPMC_PREFETCH_CONTROL; | ||
710 | reg->gpmc_prefetch_status = gpmc_base + GPMC_PREFETCH_STATUS; | ||
711 | reg->gpmc_ecc_config = gpmc_base + GPMC_ECC_CONFIG; | ||
712 | reg->gpmc_ecc_control = gpmc_base + GPMC_ECC_CONTROL; | ||
713 | reg->gpmc_ecc_size_config = gpmc_base + GPMC_ECC_SIZE_CONFIG; | ||
714 | reg->gpmc_ecc1_result = gpmc_base + GPMC_ECC1_RESULT; | ||
715 | reg->gpmc_bch_result0 = gpmc_base + GPMC_ECC_BCH_RESULT_0; | ||
716 | } | ||
717 | |||
718 | int gpmc_get_client_irq(unsigned irq_config) | ||
719 | { | ||
720 | int i; | ||
721 | |||
722 | if (hweight32(irq_config) > 1) | ||
723 | return 0; | ||
724 | |||
725 | for (i = 0; i < GPMC_NR_IRQ; i++) | ||
726 | if (gpmc_client_irq[i].bitmask & irq_config) | ||
727 | return gpmc_client_irq[i].irq; | ||
728 | |||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | static int gpmc_irq_endis(unsigned irq, bool endis) | ||
733 | { | ||
734 | int i; | ||
735 | u32 regval; | ||
736 | |||
737 | for (i = 0; i < GPMC_NR_IRQ; i++) | ||
738 | if (irq == gpmc_client_irq[i].irq) { | ||
739 | regval = gpmc_read_reg(GPMC_IRQENABLE); | ||
740 | if (endis) | ||
741 | regval |= gpmc_client_irq[i].bitmask; | ||
742 | else | ||
743 | regval &= ~gpmc_client_irq[i].bitmask; | ||
744 | gpmc_write_reg(GPMC_IRQENABLE, regval); | ||
745 | break; | ||
746 | } | ||
747 | |||
748 | return 0; | ||
749 | } | ||
750 | |||
751 | static void gpmc_irq_disable(struct irq_data *p) | ||
752 | { | ||
753 | gpmc_irq_endis(p->irq, false); | ||
754 | } | ||
755 | |||
756 | static void gpmc_irq_enable(struct irq_data *p) | ||
757 | { | ||
758 | gpmc_irq_endis(p->irq, true); | ||
759 | } | ||
760 | |||
761 | static void gpmc_irq_noop(struct irq_data *data) { } | ||
762 | |||
763 | static unsigned int gpmc_irq_noop_ret(struct irq_data *data) { return 0; } | ||
764 | |||
765 | static int gpmc_setup_irq(int gpmc_irq) | ||
766 | { | ||
767 | int i; | ||
768 | u32 regval; | ||
769 | |||
770 | if (!gpmc_irq) | ||
771 | return -EINVAL; | ||
772 | |||
773 | gpmc_irq_start = irq_alloc_descs(-1, 0, GPMC_NR_IRQ, 0); | ||
774 | if (IS_ERR_VALUE(gpmc_irq_start)) { | ||
775 | pr_err("irq_alloc_descs failed\n"); | ||
776 | return gpmc_irq_start; | ||
777 | } | ||
778 | |||
779 | gpmc_irq_chip.name = "gpmc"; | ||
780 | gpmc_irq_chip.irq_startup = gpmc_irq_noop_ret; | ||
781 | gpmc_irq_chip.irq_enable = gpmc_irq_enable; | ||
782 | gpmc_irq_chip.irq_disable = gpmc_irq_disable; | ||
783 | gpmc_irq_chip.irq_shutdown = gpmc_irq_noop; | ||
784 | gpmc_irq_chip.irq_ack = gpmc_irq_noop; | ||
785 | gpmc_irq_chip.irq_mask = gpmc_irq_noop; | ||
786 | gpmc_irq_chip.irq_unmask = gpmc_irq_noop; | ||
787 | |||
788 | gpmc_client_irq[0].bitmask = GPMC_IRQ_FIFOEVENTENABLE; | ||
789 | gpmc_client_irq[1].bitmask = GPMC_IRQ_COUNT_EVENT; | ||
790 | |||
791 | for (i = 0; i < GPMC_NR_IRQ; i++) { | ||
792 | gpmc_client_irq[i].irq = gpmc_irq_start + i; | ||
793 | irq_set_chip_and_handler(gpmc_client_irq[i].irq, | ||
794 | &gpmc_irq_chip, handle_simple_irq); | ||
795 | set_irq_flags(gpmc_client_irq[i].irq, | ||
796 | IRQF_VALID | IRQF_NOAUTOEN); | ||
797 | } | ||
798 | |||
799 | /* Disable interrupts */ | ||
800 | gpmc_write_reg(GPMC_IRQENABLE, 0); | ||
801 | |||
802 | /* clear interrupts */ | ||
803 | regval = gpmc_read_reg(GPMC_IRQSTATUS); | ||
804 | gpmc_write_reg(GPMC_IRQSTATUS, regval); | ||
805 | |||
806 | return request_irq(gpmc_irq, gpmc_handle_irq, 0, "gpmc", NULL); | ||
807 | } | ||
808 | |||
685 | static void __init gpmc_mem_init(void) | 809 | static void __init gpmc_mem_init(void) |
686 | { | 810 | { |
687 | int cs; | 811 | int cs; |
@@ -711,8 +835,8 @@ static void __init gpmc_mem_init(void) | |||
711 | 835 | ||
712 | static int __init gpmc_init(void) | 836 | static int __init gpmc_init(void) |
713 | { | 837 | { |
714 | u32 l, irq; | 838 | u32 l; |
715 | int cs, ret = -EINVAL; | 839 | int ret = -EINVAL; |
716 | int gpmc_irq; | 840 | int gpmc_irq; |
717 | char *ck = NULL; | 841 | char *ck = NULL; |
718 | 842 | ||
@@ -761,16 +885,7 @@ static int __init gpmc_init(void) | |||
761 | gpmc_write_reg(GPMC_SYSCONFIG, l); | 885 | gpmc_write_reg(GPMC_SYSCONFIG, l); |
762 | gpmc_mem_init(); | 886 | gpmc_mem_init(); |
763 | 887 | ||
764 | /* initalize the irq_chained */ | 888 | 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) | 889 | if (ret) |
775 | pr_err("gpmc: irq-%d could not claim: err %d\n", | 890 | pr_err("gpmc: irq-%d could not claim: err %d\n", |
776 | gpmc_irq, ret); | 891 | gpmc_irq, ret); |
@@ -780,12 +895,19 @@ postcore_initcall(gpmc_init); | |||
780 | 895 | ||
781 | static irqreturn_t gpmc_handle_irq(int irq, void *dev) | 896 | static irqreturn_t gpmc_handle_irq(int irq, void *dev) |
782 | { | 897 | { |
783 | u8 cs; | 898 | int i; |
899 | u32 regval; | ||
900 | |||
901 | regval = gpmc_read_reg(GPMC_IRQSTATUS); | ||
902 | |||
903 | if (!regval) | ||
904 | return IRQ_NONE; | ||
905 | |||
906 | for (i = 0; i < GPMC_NR_IRQ; i++) | ||
907 | if (regval & gpmc_client_irq[i].bitmask) | ||
908 | generic_handle_irq(gpmc_client_irq[i].irq); | ||
784 | 909 | ||
785 | /* check cs to invoke the irq */ | 910 | 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 | 911 | ||
790 | return IRQ_HANDLED; | 912 | return IRQ_HANDLED; |
791 | } | 913 | } |