ARM: mach-shmobile: Use common INTC IRQ code on sh73a0
authorMagnus Damm <damm@opensource.se>
Wed, 12 Oct 2011 07:21:42 +0000 (16:21 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Fri, 4 Nov 2011 16:02:51 +0000 (01:02 +0900)
Improve IRQ triggering support by making use of the macro
INTC_IRQ_PINS_32() for INTCA on sh73a0. Unfortunately it
is not as easy as just using the macro as-is, we need to
do mask and unmaks in the GIC but configure other bits
and ack in INTCA. Update GPIO IRQ mappings while at it.

Signed-off-by: Magnus Damm <damm@opensource.se>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
arch/arm/mach-shmobile/intc-sh73a0.c
arch/arm/mach-shmobile/pfc-sh73a0.c

index a911a60e7719a1e0fa040f5798b0e7174b060fa1..836e8155798666f3adfd41a1dd1a3be5c1e386f2 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/sh_intc.h>
+#include <mach/intc.h>
 #include <asm/hardware/gic.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -255,20 +256,141 @@ static int sh73a0_set_wake(struct irq_data *data, unsigned int on)
        return 0; /* always allow wakeup */
 }
 
+#define RELOC_BASE 0x1000
+
+/* INTCA IRQ pins at INTCS + 0x1000 to make space for GIC+INTC handling */
+#define INTCS_VECT_RELOC(n, vect) INTCS_VECT((n), (vect) + RELOC_BASE)
+
+INTC_IRQ_PINS_32(intca_irq_pins, 0xe6900000,
+                INTCS_VECT_RELOC, "sh73a0-intca-irq-pins");
+
+static int to_gic_irq(struct irq_data *data)
+{
+       unsigned int vect = irq2evt(data->irq) - INTCS_VECT_BASE;
+
+       if (vect >= 0x3200)
+               vect -= 0x3000;
+       else
+               vect -= 0x0200;
+
+       return gic_spi((vect >> 5) + 1);
+}
+
+static int to_intca_reloc_irq(struct irq_data *data)
+{
+       return data->irq + (RELOC_BASE >> 5);
+}
+
+#define irq_cb(cb, irq) irq_get_chip(irq)->cb(irq_get_irq_data(irq))
+#define irq_cbp(cb, irq, p...) irq_get_chip(irq)->cb(irq_get_irq_data(irq), p)
+
+static void intca_gic_enable(struct irq_data *data)
+{
+       irq_cb(irq_unmask, to_intca_reloc_irq(data));
+       irq_cb(irq_unmask, to_gic_irq(data));
+}
+
+static void intca_gic_disable(struct irq_data *data)
+{
+       irq_cb(irq_mask, to_gic_irq(data));
+       irq_cb(irq_mask, to_intca_reloc_irq(data));
+}
+
+static void intca_gic_mask_ack(struct irq_data *data)
+{
+       irq_cb(irq_mask, to_gic_irq(data));
+       irq_cb(irq_mask_ack, to_intca_reloc_irq(data));
+}
+
+static void intca_gic_eoi(struct irq_data *data)
+{
+       irq_cb(irq_eoi, to_gic_irq(data));
+}
+
+static int intca_gic_set_type(struct irq_data *data, unsigned int type)
+{
+       return irq_cbp(irq_set_type, to_intca_reloc_irq(data), type);
+}
+
+static int intca_gic_set_wake(struct irq_data *data, unsigned int on)
+{
+       return irq_cbp(irq_set_wake, to_intca_reloc_irq(data), on);
+}
+
+#ifdef CONFIG_SMP
+static int intca_gic_set_affinity(struct irq_data *data,
+                                 const struct cpumask *cpumask,
+                                 bool force)
+{
+       return irq_cbp(irq_set_affinity, to_gic_irq(data), cpumask, force);
+}
+#endif
+
+struct irq_chip intca_gic_irq_chip = {
+       .name                   = "INTCA-GIC",
+       .irq_mask               = intca_gic_disable,
+       .irq_unmask             = intca_gic_enable,
+       .irq_mask_ack           = intca_gic_mask_ack,
+       .irq_eoi                = intca_gic_eoi,
+       .irq_enable             = intca_gic_enable,
+       .irq_disable            = intca_gic_disable,
+       .irq_shutdown           = intca_gic_disable,
+       .irq_set_type           = intca_gic_set_type,
+       .irq_set_wake           = intca_gic_set_wake,
+#ifdef CONFIG_SMP
+       .irq_set_affinity       = intca_gic_set_affinity,
+#endif
+};
+
+static int to_intc_vect(int irq)
+{
+       unsigned int irq_pin = irq - gic_spi(1);
+       unsigned int offs;
+
+       if (irq_pin < 16)
+               offs = 0x0200;
+       else
+               offs = 0x3000;
+
+       return offs + (irq_pin << 5);
+}
+
+static irqreturn_t sh73a0_irq_pin_demux(int irq, void *dev_id)
+{
+       generic_handle_irq(intcs_evt2irq(to_intc_vect(irq)));
+       return IRQ_HANDLED;
+}
+
+static struct irqaction sh73a0_irq_pin_cascade[32];
+
 void __init sh73a0_init_irq(void)
 {
        void __iomem *gic_dist_base = __io(0xf0001000);
        void __iomem *gic_cpu_base = __io(0xf0000100);
        void __iomem *intevtsa = ioremap_nocache(0xffd20100, PAGE_SIZE);
+       int k, n;
 
        gic_init(0, 29, gic_dist_base, gic_cpu_base);
        gic_arch_extn.irq_set_wake = sh73a0_set_wake;
 
        register_intc_controller(&intcs_desc);
+       register_intc_controller(&intca_irq_pins_desc);
 
        /* demux using INTEVTSA */
        sh73a0_intcs_cascade.name = "INTCS cascade";
        sh73a0_intcs_cascade.handler = sh73a0_intcs_demux;
        sh73a0_intcs_cascade.dev_id = intevtsa;
        setup_irq(gic_spi(50), &sh73a0_intcs_cascade);
+
+       /* IRQ pins require special handling through INTCA and GIC */
+       for (k = 0; k < 32; k++) {
+               sh73a0_irq_pin_cascade[k].name = "INTCA-GIC cascade";
+               sh73a0_irq_pin_cascade[k].handler = sh73a0_irq_pin_demux;
+               setup_irq(gic_spi(1 + k), &sh73a0_irq_pin_cascade[k]);
+
+               n = intcs_evt2irq(to_intc_vect(gic_spi(1 + k)));
+               irq_set_chip_and_handler_name(n, &intca_gic_irq_chip,
+                                             handle_level_irq, "level");
+               set_irq_flags(n, IRQF_VALID); /* yuck */
+       }
 }
index 57322c9fd9b6ab8279205af56bb09800f1c845b6..5abe02fbd6b99aa6ba09c7a377e9649d7e70b289 100644 (file)
@@ -2766,41 +2766,43 @@ static struct pinmux_data_reg pinmux_data_regs[] = {
        { },
 };
 
-#define EXT_IRQ(n) gic_spi((n) + 1) /* GIC SPI starting from 1 for IRQ0 */
+/* IRQ pins through INTCS with IRQ0->15 from 0x200 and IRQ16-31 from 0x3200 */
+#define EXT_IRQ16L(n) intcs_evt2irq(0x200 + ((n) << 5))
+#define EXT_IRQ16H(n) intcs_evt2irq(0x3200 + ((n - 16) << 5))
 
 static struct pinmux_irq pinmux_irqs[] = {
-       PINMUX_IRQ(EXT_IRQ(19), PORT9_FN0),
-       PINMUX_IRQ(EXT_IRQ(1), PORT10_FN0),
-       PINMUX_IRQ(EXT_IRQ(0), PORT11_FN0),
-       PINMUX_IRQ(EXT_IRQ(18), PORT13_FN0),
-       PINMUX_IRQ(EXT_IRQ(20), PORT14_FN0),
-       PINMUX_IRQ(EXT_IRQ(21), PORT15_FN0),
-       PINMUX_IRQ(EXT_IRQ(31), PORT26_FN0),
-       PINMUX_IRQ(EXT_IRQ(30), PORT27_FN0),
-       PINMUX_IRQ(EXT_IRQ(29), PORT28_FN0),
-       PINMUX_IRQ(EXT_IRQ(22), PORT40_FN0),
-       PINMUX_IRQ(EXT_IRQ(23), PORT53_FN0),
-       PINMUX_IRQ(EXT_IRQ(10), PORT54_FN0),
-       PINMUX_IRQ(EXT_IRQ(9), PORT56_FN0),
-       PINMUX_IRQ(EXT_IRQ(26), PORT115_FN0),
-       PINMUX_IRQ(EXT_IRQ(27), PORT116_FN0),
-       PINMUX_IRQ(EXT_IRQ(28), PORT117_FN0),
-       PINMUX_IRQ(EXT_IRQ(24), PORT118_FN0),
-       PINMUX_IRQ(EXT_IRQ(6), PORT147_FN0),
-       PINMUX_IRQ(EXT_IRQ(2), PORT149_FN0),
-       PINMUX_IRQ(EXT_IRQ(7), PORT150_FN0),
-       PINMUX_IRQ(EXT_IRQ(12), PORT156_FN0),
-       PINMUX_IRQ(EXT_IRQ(4), PORT159_FN0),
-       PINMUX_IRQ(EXT_IRQ(25), PORT164_FN0),
-       PINMUX_IRQ(EXT_IRQ(8), PORT223_FN0),
-       PINMUX_IRQ(EXT_IRQ(3), PORT224_FN0),
-       PINMUX_IRQ(EXT_IRQ(5), PORT227_FN0),
-       PINMUX_IRQ(EXT_IRQ(17), PORT234_FN0),
-       PINMUX_IRQ(EXT_IRQ(11), PORT238_FN0),
-       PINMUX_IRQ(EXT_IRQ(13), PORT239_FN0),
-       PINMUX_IRQ(EXT_IRQ(16), PORT249_FN0),
-       PINMUX_IRQ(EXT_IRQ(14), PORT251_FN0),
-       PINMUX_IRQ(EXT_IRQ(9), PORT308_FN0),
+       PINMUX_IRQ(EXT_IRQ16H(19), PORT9_FN0),
+       PINMUX_IRQ(EXT_IRQ16L(1), PORT10_FN0),
+       PINMUX_IRQ(EXT_IRQ16L(0), PORT11_FN0),
+       PINMUX_IRQ(EXT_IRQ16H(18), PORT13_FN0),
+       PINMUX_IRQ(EXT_IRQ16H(20), PORT14_FN0),
+       PINMUX_IRQ(EXT_IRQ16H(21), PORT15_FN0),
+       PINMUX_IRQ(EXT_IRQ16H(31), PORT26_FN0),
+       PINMUX_IRQ(EXT_IRQ16H(30), PORT27_FN0),
+       PINMUX_IRQ(EXT_IRQ16H(29), PORT28_FN0),
+       PINMUX_IRQ(EXT_IRQ16H(22), PORT40_FN0),
+       PINMUX_IRQ(EXT_IRQ16H(23), PORT53_FN0),
+       PINMUX_IRQ(EXT_IRQ16L(10), PORT54_FN0),
+       PINMUX_IRQ(EXT_IRQ16L(9), PORT56_FN0),
+       PINMUX_IRQ(EXT_IRQ16H(26), PORT115_FN0),
+       PINMUX_IRQ(EXT_IRQ16H(27), PORT116_FN0),
+       PINMUX_IRQ(EXT_IRQ16H(28), PORT117_FN0),
+       PINMUX_IRQ(EXT_IRQ16H(24), PORT118_FN0),
+       PINMUX_IRQ(EXT_IRQ16L(6), PORT147_FN0),
+       PINMUX_IRQ(EXT_IRQ16L(2), PORT149_FN0),
+       PINMUX_IRQ(EXT_IRQ16L(7), PORT150_FN0),
+       PINMUX_IRQ(EXT_IRQ16L(12), PORT156_FN0),
+       PINMUX_IRQ(EXT_IRQ16L(4), PORT159_FN0),
+       PINMUX_IRQ(EXT_IRQ16H(25), PORT164_FN0),
+       PINMUX_IRQ(EXT_IRQ16L(8), PORT223_FN0),
+       PINMUX_IRQ(EXT_IRQ16L(3), PORT224_FN0),
+       PINMUX_IRQ(EXT_IRQ16L(5), PORT227_FN0),
+       PINMUX_IRQ(EXT_IRQ16H(17), PORT234_FN0),
+       PINMUX_IRQ(EXT_IRQ16L(11), PORT238_FN0),
+       PINMUX_IRQ(EXT_IRQ16L(13), PORT239_FN0),
+       PINMUX_IRQ(EXT_IRQ16H(16), PORT249_FN0),
+       PINMUX_IRQ(EXT_IRQ16L(14), PORT251_FN0),
+       PINMUX_IRQ(EXT_IRQ16L(9), PORT308_FN0),
 };
 
 static struct pinmux_info sh73a0_pinmux_info = {