]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
sh: se722: Move FPGA IRQs to irqdomain and generic irq chip.
authorPaul Mundt <lethal@linux-sh.org>
Thu, 24 May 2012 09:24:32 +0000 (18:24 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Thu, 24 May 2012 09:24:32 +0000 (18:24 +0900)
This implements a total rewrite of the rather buggy SE7722 FPGA IRQ code,
utilizing a linear irq domain as well as the generic irq chip type.

While the interaction between the two APIs is a bit clunky (ie, revmap
lookup for gc irq_base), they work well enough together that it's easy
enough to work with going forward.

While we're at it, deal with irq_mask_ack/unmask of the chained IRQ in
the demux handler to prevent smc91x screaming about spurious interrupts.

There's also some more improvement that can be made to the irqdomain code
to create backing irqdescs for the entire linear range in one bang
instead of iterating over the number of hwirqs and doing it
irq-at-a-time. This is easily dealt with at a later point, though.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
arch/sh/boards/Kconfig
arch/sh/boards/mach-se/7722/irq.c
arch/sh/boards/mach-se/7722/setup.c
arch/sh/include/mach-se/mach/se7722.h

index f2024a91319fe5937f0637620ead4e52af63d27c..525b9e32cd14660a822cd3ae63ad04f75de5c4d5 100644 (file)
@@ -44,6 +44,8 @@ config SH_7721_SOLUTION_ENGINE
 config SH_7722_SOLUTION_ENGINE
        bool "SolutionEngine7722"
        select SOLUTION_ENGINE
+       select GENERIC_IRQ_CHIP
+       select IRQ_DOMAIN
        depends on CPU_SUBTYPE_SH7722
        help
          Select 7722 SolutionEngine if configuring for a Hitachi SH772
index aac92f21ebd23e945b680550eb90274ec622ca0d..f5e2af1bf040ff93dc415362e7ef3f2ac4e75753 100644 (file)
@@ -1,79 +1,96 @@
 /*
- * linux/arch/sh/boards/se/7722/irq.c
+ * Hitachi UL SolutionEngine 7722 FPGA IRQ Support.
  *
  * Copyright (C) 2007  Nobuhiro Iwamatsu
- *
- * Hitachi UL SolutionEngine 7722 Support.
+ * Copyright (C) 2012  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  */
+#define DRV_NAME "SE7722-FPGA"
+#define pr_fmt(fmt) DRV_NAME ": " fmt
+
+#define irq_reg_readl  ioread16
+#define irq_reg_writel iowrite16
+
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <asm/irq.h>
-#include <asm/io.h>
+#include <linux/irqdomain.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <asm/sizes.h>
 #include <mach-se/mach/se7722.h>
 
-unsigned int se7722_fpga_irq[SE7722_FPGA_IRQ_NR] = { 0, };
+#define IRQ01_BASE_ADDR        0x11800000
+#define IRQ01_MODE_REG 0
+#define IRQ01_STS_REG  4
+#define IRQ01_MASK_REG 8
 
-static void disable_se7722_irq(struct irq_data *data)
-{
-       unsigned int bit = (unsigned int)irq_data_get_irq_chip_data(data);
-       __raw_writew(__raw_readw(IRQ01_MASK) | 1 << bit, IRQ01_MASK);
-}
+static void __iomem *se7722_irq_regs;
+struct irq_domain *se7722_irq_domain;
 
-static void enable_se7722_irq(struct irq_data *data)
+static void se7722_irq_demux(unsigned int irq, struct irq_desc *desc)
 {
-       unsigned int bit = (unsigned int)irq_data_get_irq_chip_data(data);
-       __raw_writew(__raw_readw(IRQ01_MASK) & ~(1 << bit), IRQ01_MASK);
-}
+       struct irq_data *data = irq_get_irq_data(irq);
+       struct irq_chip *chip = irq_data_get_irq_chip(data);
+       unsigned long mask;
+       int bit;
 
-static struct irq_chip se7722_irq_chip __read_mostly = {
-       .name           = "SE7722-FPGA",
-       .irq_mask       = disable_se7722_irq,
-       .irq_unmask     = enable_se7722_irq,
-};
+       chip->irq_mask_ack(data);
 
-static void se7722_irq_demux(unsigned int irq, struct irq_desc *desc)
+       mask = ioread16(se7722_irq_regs + IRQ01_STS_REG);
+
+       for_each_set_bit(bit, &mask, SE7722_FPGA_IRQ_NR)
+               generic_handle_irq(irq_linear_revmap(se7722_irq_domain, bit));
+
+       chip->irq_unmask(data);
+}
+
+static void __init se7722_domain_init(void)
 {
-       unsigned short intv = __raw_readw(IRQ01_STS);
-       unsigned int ext_irq = 0;
+       int i;
 
-       intv &= (1 << SE7722_FPGA_IRQ_NR) - 1;
+       se7722_irq_domain = irq_domain_add_linear(NULL, SE7722_FPGA_IRQ_NR,
+                                                 &irq_domain_simple_ops, NULL);
+       if (unlikely(!se7722_irq_domain)) {
+               printk("Failed to get IRQ domain\n");
+               return;
+       }
 
-       for (; intv; intv >>= 1, ext_irq++) {
-               if (!(intv & 1))
-                       continue;
+       for (i = 0; i < SE7722_FPGA_IRQ_NR; i++) {
+               int irq = irq_create_mapping(se7722_irq_domain, i);
 
-               generic_handle_irq(se7722_fpga_irq[ext_irq]);
+               if (unlikely(irq == 0)) {
+                       printk("Failed to allocate IRQ %d\n", i);
+                       return;
+               }
        }
 }
 
-/*
- * Initialize IRQ setting
- */
-void __init init_se7722_IRQ(void)
+static void __init se7722_gc_init(void)
 {
-       int i, irq;
+       struct irq_chip_generic *gc;
+       struct irq_chip_type *ct;
+       unsigned int irq_base;
 
-       __raw_writew(0, IRQ01_MASK);       /* disable all irqs */
-       __raw_writew(0x2000, 0xb03fffec);  /* mrshpc irq enable */
+       irq_base = irq_linear_revmap(se7722_irq_domain, 0);
 
-       for (i = 0; i < SE7722_FPGA_IRQ_NR; i++) {
-               irq = create_irq();
-               if (irq < 0)
-                       return;
-               se7722_fpga_irq[i] = irq;
+       gc = irq_alloc_generic_chip(DRV_NAME, 1, irq_base, se7722_irq_regs,
+                                   handle_level_irq);
+       if (unlikely(!gc))
+               return;
 
-               irq_set_chip_and_handler_name(se7722_fpga_irq[i],
-                                             &se7722_irq_chip,
-                                             handle_level_irq,
-                                             "level");
+       ct = gc->chip_types;
+       ct->chip.irq_mask = irq_gc_mask_set_bit;
+       ct->chip.irq_unmask = irq_gc_mask_clr_bit;
 
-               irq_set_chip_data(se7722_fpga_irq[i], (void *)i);
-       }
+       ct->regs.mask = IRQ01_MASK_REG;
+
+       irq_setup_generic_chip(gc, IRQ_MSK(SE7722_FPGA_IRQ_NR),
+                              IRQ_GC_INIT_MASK_CACHE,
+                              IRQ_NOREQUEST | IRQ_NOPROBE, 0);
 
        irq_set_chained_handler(IRQ0_IRQ, se7722_irq_demux);
        irq_set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW);
@@ -81,3 +98,25 @@ void __init init_se7722_IRQ(void)
        irq_set_chained_handler(IRQ1_IRQ, se7722_irq_demux);
        irq_set_irq_type(IRQ1_IRQ, IRQ_TYPE_LEVEL_LOW);
 }
+
+/*
+ * Initialize FPGA IRQs
+ */
+void __init init_se7722_IRQ(void)
+{
+       se7722_irq_regs = ioremap(IRQ01_BASE_ADDR, SZ_16);
+       if (unlikely(!se7722_irq_regs)) {
+               printk("Failed to remap IRQ01 regs\n");
+               return;
+       }
+
+       /*
+        * All FPGA IRQs disabled by default
+        */
+       iowrite16(0, se7722_irq_regs + IRQ01_MASK_REG);
+
+       __raw_writew(0x2000, 0xb03fffec);  /* mrshpc irq enable */
+
+       se7722_domain_init();
+       se7722_gc_init();
+}
index e1963fecd761ace85df196720c2c68c4f4d7a738..2ec0111fdf9b5854a13dbb12860d36a6f4d99806 100644 (file)
@@ -2,6 +2,7 @@
  * linux/arch/sh/boards/se/7722/setup.c
  *
  * Copyright (C) 2007 Nobuhiro Iwamatsu
+ * Copyright (C) 2012 Paul Mundt
  *
  * Hitachi UL SolutionEngine 7722 Support.
  *
@@ -15,6 +16,7 @@
 #include <linux/ata_platform.h>
 #include <linux/input.h>
 #include <linux/input/sh_keysc.h>
+#include <linux/irqdomain.h>
 #include <linux/smc91x.h>
 #include <mach-se/mach/se7722.h>
 #include <mach-se/mach/mrshpc.h>
@@ -142,10 +144,10 @@ static int __init se7722_devices_setup(void)
 
        /* Wire-up dynamic vectors */
        cf_ide_resources[2].start = cf_ide_resources[2].end =
-               se7722_fpga_irq[SE7722_FPGA_IRQ_MRSHPC0];
+               irq_find_mapping(se7722_irq_domain, SE7722_FPGA_IRQ_MRSHPC0);
 
        smc91x_eth_resources[1].start = smc91x_eth_resources[1].end =
-               se7722_fpga_irq[SE7722_FPGA_IRQ_SMC];
+               irq_find_mapping(se7722_irq_domain, SE7722_FPGA_IRQ_SMC);
 
        return platform_add_devices(se7722_devices, ARRAY_SIZE(se7722_devices));
 }
index 16505bfb8a9e5443ccc5b6102565f444d671dc47..5508dc42e4d29f4816839cc96a77fc7e2872cb64 100644 (file)
 #define IRQ0_IRQ        32
 #define IRQ1_IRQ        33
 
-#define IRQ01_MODE      0xb1800000
-#define IRQ01_STS       0xb1800004
-#define IRQ01_MASK      0xb1800008
-
-/* Bits in IRQ01_* registers */
-
 #define SE7722_FPGA_IRQ_USB    0 /* IRQ0 */
 #define SE7722_FPGA_IRQ_SMC    1 /* IRQ0 */
 #define SE7722_FPGA_IRQ_MRSHPC0        2 /* IRQ1 */
 #define SE7722_FPGA_IRQ_MRSHPC3        5 /* IRQ1 */
 #define SE7722_FPGA_IRQ_NR     6
 
+struct irq_domain;
+
 /* arch/sh/boards/se/7722/irq.c */
-extern unsigned int se7722_fpga_irq[];
+extern struct irq_domain *se7722_irq_domain;
 
 void init_se7722_IRQ(void);