irqchip/mxs: Prepare driver for hardware with different offsets
authorOleksij Rempel <linux@rempel-privat.de>
Mon, 12 Oct 2015 19:15:33 +0000 (21:15 +0200)
committerThomas Gleixner <tglx@linutronix.de>
Wed, 14 Oct 2015 07:37:47 +0000 (09:37 +0200)
Alphascale asm9260 has similar functionality but different register
offsets. To support asm9260 in the mxs driver we need to rework the
hardcoded access mechanisms.

- Define SET_REG and CLR_REG. These controllers support seperate CLR and
  SET offsets for each register.

- Reimplement HW_ICOLL_INTERRUPT with SET_REG and CLR_REG to make it
  usable for both cases.

- Instead of using icoll_base and adding the offsets at runtime,
  create a new data structure which contains base pointers to all
  required regitsters and use it.

- Split out functionality, which is required for the init code of mxs
  and asm9260, into helper functions

[ tglx: Massaged changelog and moved the return value change to the
   previous patch ]

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
Tested-by: Shawn Guo <shawnguo@kernel.org>
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: marc.zyngier@arm.com
Cc: jason@lakedaemon.net
Link: http://lkml.kernel.org/r/1444677334-12242-5-git-send-email-linux@rempel-privat.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
drivers/irqchip/irq-mxs.c

index 96148a7beba129ff84d557c437058dd06ec7395a..eaab5a67e536682ef46ea2972911701fb94c8681 100644 (file)
 #include <linux/stmp_device.h>
 #include <asm/exception.h>
 
+/*
+ * this device provide 4 offsets for each register:
+ * 0x0 - plain read write mode
+ * 0x4 - set mode, OR logic.
+ * 0x8 - clr mode, XOR logic.
+ * 0xc - togle mode.
+ */
+#define SET_REG 4
+#define CLR_REG 8
+
 #define HW_ICOLL_VECTOR                                0x0000
 #define HW_ICOLL_LEVELACK                      0x0010
 #define HW_ICOLL_CTRL                          0x0020
 #define HW_ICOLL_STAT_OFFSET                   0x0070
-#define HW_ICOLL_INTERRUPTn_SET(n)             (0x0124 + (n) * 0x10)
-#define HW_ICOLL_INTERRUPTn_CLR(n)             (0x0128 + (n) * 0x10)
-#define BM_ICOLL_INTERRUPTn_ENABLE             0x00000004
+#define HW_ICOLL_INTERRUPT0                    0x0120
+#define HW_ICOLL_INTERRUPTn(n)                 ((n) * 0x10)
+#define BM_ICOLL_INTR_ENABLE                   BIT(2)
 #define BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0  0x1
 
 #define ICOLL_NUM_IRQS         128
 
-static void __iomem *icoll_base;
+struct icoll_priv {
+       void __iomem *vector;
+       void __iomem *levelack;
+       void __iomem *ctrl;
+       void __iomem *stat;
+       void __iomem *intr;
+};
+
+static struct icoll_priv icoll_priv;
 static struct irq_domain *icoll_domain;
 
 static void icoll_ack_irq(struct irq_data *d)
@@ -50,19 +68,19 @@ static void icoll_ack_irq(struct irq_data *d)
         * BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 unconditionally.
         */
        __raw_writel(BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0,
-                       icoll_base + HW_ICOLL_LEVELACK);
+                       icoll_priv.levelack);
 }
 
 static void icoll_mask_irq(struct irq_data *d)
 {
-       __raw_writel(BM_ICOLL_INTERRUPTn_ENABLE,
-                       icoll_base + HW_ICOLL_INTERRUPTn_CLR(d->hwirq));
+       __raw_writel(BM_ICOLL_INTR_ENABLE,
+                       icoll_priv.intr + CLR_REG + HW_ICOLL_INTERRUPTn(d->hwirq));
 }
 
 static void icoll_unmask_irq(struct irq_data *d)
 {
-       __raw_writel(BM_ICOLL_INTERRUPTn_ENABLE,
-                       icoll_base + HW_ICOLL_INTERRUPTn_SET(d->hwirq));
+       __raw_writel(BM_ICOLL_INTR_ENABLE,
+                       icoll_priv.intr + SET_REG + HW_ICOLL_INTERRUPTn(d->hwirq));
 }
 
 static struct irq_chip mxs_icoll_chip = {
@@ -75,8 +93,8 @@ asmlinkage void __exception_irq_entry icoll_handle_irq(struct pt_regs *regs)
 {
        u32 irqnr;
 
-       irqnr = __raw_readl(icoll_base + HW_ICOLL_STAT_OFFSET);
-       __raw_writel(irqnr, icoll_base + HW_ICOLL_VECTOR);
+       irqnr = __raw_readl(icoll_priv.stat);
+       __raw_writel(irqnr, icoll_priv.vector);
        handle_domain_irq(icoll_domain, irqnr, regs);
 }
 
@@ -93,23 +111,45 @@ static const struct irq_domain_ops icoll_irq_domain_ops = {
        .xlate = irq_domain_xlate_onecell,
 };
 
-static int __init icoll_of_init(struct device_node *np,
-                         struct device_node *interrupt_parent)
+static void __init icoll_add_domain(struct device_node *np,
+                         int num)
+{
+       icoll_domain = irq_domain_add_linear(np, num,
+                                            &icoll_irq_domain_ops, NULL);
+
+       if (!icoll_domain)
+               panic("%s: unable to create irq domain", np->full_name);
+}
+
+static void __iomem * __init icoll_init_iobase(struct device_node *np)
 {
-       icoll_base = of_iomap(np, 0);
+       void __iomem *icoll_base;
+
+       icoll_base = of_io_request_and_map(np, 0, np->name);
        if (!icoll_base)
                panic("%s: unable to map resource", np->full_name);
+       return icoll_base;
+}
+
+static int __init icoll_of_init(struct device_node *np,
+                         struct device_node *interrupt_parent)
+{
+       void __iomem *icoll_base;
+
+       icoll_base              = icoll_init_iobase(np);
+       icoll_priv.vector       = icoll_base + HW_ICOLL_VECTOR;
+       icoll_priv.levelack     = icoll_base + HW_ICOLL_LEVELACK;
+       icoll_priv.ctrl         = icoll_base + HW_ICOLL_CTRL;
+       icoll_priv.stat         = icoll_base + HW_ICOLL_STAT_OFFSET;
+       icoll_priv.intr         = icoll_base + HW_ICOLL_INTERRUPT0;
 
        /*
         * Interrupt Collector reset, which initializes the priority
         * for each irq to level 0.
         */
-       stmp_reset_block(icoll_base + HW_ICOLL_CTRL);
+       stmp_reset_block(icoll_priv.ctrl);
 
-       icoll_domain = irq_domain_add_linear(np, ICOLL_NUM_IRQS,
-                                            &icoll_irq_domain_ops, NULL);
-       if (!icoll_domain)
-               panic("%s: unable to create irqdomain", np->full_name);
+       icoll_add_domain(np, ICOLL_NUM_IRQS);
 
        return 0;
 }