brcm63xx: fix external interrupts on BCM6318
authorJonas Gorski <jonas.gorski@gmail.com>
Mon, 19 Dec 2016 12:02:21 +0000 (13:02 +0100)
committerJonas Gorski <jonas.gorski@gmail.com>
Fri, 10 Feb 2017 09:51:09 +0000 (10:51 +0100)
Setting the clear bit for an interrupt seems to cause interrupts to be
deasserted again immediately. So unset the bit for BCM6318 to allow
subsequent interrupts to still work.

Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
target/linux/brcm63xx/dts/bcm6318.dtsi
target/linux/brcm63xx/patches-4.4/321-irqchip-add-support-for-bcm6345-style-external-inter.patch

index 115b15c..7766980 100644 (file)
@@ -36,7 +36,7 @@
                compatible = "simple-bus";
 
                ext_intc: interrupt-controller@10000018 {
-                       compatible = "brcm,bcm6345-ext-intc";
+                       compatible = "brcm,bcm6318-ext-intc";
                        reg = <0x10000018 0x4>;
 
                        interrupt-controller;
index 2526456..2271b66 100644 (file)
@@ -23,7 +23,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
 +
 +Required properties:
 +
-+- compatible: Should be "brcm,bcm6345-ext-intc".
++- compatible: Should be "brcm,bcm6345-ext-intc" or "brcm,bcm6318-ext-intc".
 +- reg: Specifies the base physical addresses and size of the registers.
 +- interrupt-controller: identifies the node as an interrupt controller.
 +- #interrupt-cells: Specifies the number of cells needed to encode an interrupt
@@ -73,7 +73,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
  obj-$(CONFIG_METAG)                   += irq-metag-ext.o
 --- /dev/null
 +++ b/drivers/irqchip/irq-bcm6345-ext.c
-@@ -0,0 +1,288 @@
+@@ -0,0 +1,301 @@
 +/*
 + * 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
@@ -119,6 +119,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
 +      int parent_irq[MAX_IRQS];
 +      void __iomem *reg;
 +      int shift;
++      unsigned int toggle_clear_on_ack:1;
 +};
 +
 +static void bcm6345_ext_intc_irq_handle(struct irq_desc *desc)
@@ -148,8 +149,10 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
 +
 +      raw_spin_lock(&priv->lock);
 +      reg = __raw_readl(priv->reg);
-+      reg |= 1 << (hwirq + EXTIRQ_CFG_CLEAR * priv->shift);
-+      __raw_writel(reg, priv->reg);
++      __raw_writel(reg | (1 << (hwirq + EXTIRQ_CFG_CLEAR * priv->shift)),
++                   priv->reg);
++      if (priv->toggle_clear_on_ack)
++              __raw_writel(reg, priv->reg);
 +      raw_spin_unlock(&priv->lock);
 +}
 +
@@ -263,7 +266,8 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
 +
 +static int __init __bcm6345_ext_intc_init(struct device_node *node,
 +                                        int num_irqs, int *irqs,
-+                                        void __iomem *reg, int shift)
++                                        void __iomem *reg, int shift,
++                                        bool toggle_clear_on_ack)
 +{
 +      struct intc_data *data;
 +      unsigned int i;
@@ -284,6 +288,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
 +
 +      data->reg = reg;
 +      data->shift = shift;
++      data->toggle_clear_on_ack = toggle_clear_on_ack;
 +
 +      data->chip.name = "bcm6345-ext-intc";
 +      data->chip.irq_ack = bcm6345_ext_intc_irq_ack;
@@ -314,7 +319,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
 +void __init bcm6345_ext_intc_init(int num_irqs, int *irqs, void __iomem *reg,
 +                                int shift)
 +{
-+      __bcm6345_ext_intc_init(NULL, num_irqs, irqs, reg, shift);
++      __bcm6345_ext_intc_init(NULL, num_irqs, irqs, reg, shift, false);
 +}
 +
 +#ifdef CONFIG_OF
@@ -326,6 +331,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
 +      void __iomem *base;
 +      int irqs[MAX_IRQS] = { 0 };
 +      u32 shift;
++      bool toggle_clear_on_ack = false;
 +
 +      num_irqs = of_irq_count(node);
 +
@@ -335,6 +341,10 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
 +      if (of_property_read_u32(node, "brcm,field-width", &shift))
 +              shift = 4;
 +
++      /* on BCM6318 setting CLEAR seems to continuously mask interrupts */
++      if (of_device_is_compatible(node, "brcm,bcm6318-ext-intc"))
++              toggle_clear_on_ack = true;
++
 +      for (i = 0; i < num_irqs; i++) {
 +              irqs[i] = irq_of_parse_and_map(node, i);
 +              if (!irqs[i]) {
@@ -347,7 +357,8 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
 +      if (!base)
 +              goto out_unmap;
 +
-+      ret = __bcm6345_ext_intc_init(node, num_irqs, irqs, base, shift);
++      ret = __bcm6345_ext_intc_init(node, num_irqs, irqs, base, shift,
++                                    toggle_clear_on_ack);
 +      if (!ret)
 +              return 0;
 +out_unmap:
@@ -359,6 +370,8 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
 +      return ret;
 +}
 +
++IRQCHIP_DECLARE(bcm6318_ext_intc, "brcm,bcm6318-ext-intc",
++              bcm6345_ext_intc_of_init);
 +IRQCHIP_DECLARE(bcm6345_ext_intc, "brcm,bcm6345-ext-intc",
 +              bcm6345_ext_intc_of_init);
 +#endif