diff options
author | Kevin Cernekee <cernekee@gmail.com> | 2014-12-25 09:49:05 -0800 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2015-04-01 17:21:37 +0200 |
commit | 7b7230e70e9eda75356cf15c450b65b77924486f (patch) | |
tree | 240e5446a54d0de5e3caf8566ac39cc01cf7459b | |
parent | ca40f1b23df70c6f31b14a5743a6f3b60e862ce1 (diff) | |
download | op-kernel-dev-7b7230e70e9eda75356cf15c450b65b77924486f.zip op-kernel-dev-7b7230e70e9eda75356cf15c450b65b77924486f.tar.gz |
IRQCHIP: bcm7120-l2: Add support for BCM3380-style controllers
These controllers support multiple enable/status pairs (64+ IRQs),
can put the enable/status words at different offsets, and do not
support multiple parent IRQs.
Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
Cc: f.fainelli@gmail.com
Cc: jaedon.shin@gmail.com
Cc: abrestic@chromium.org
Cc: tglx@linutronix.de
Cc: jason@lakedaemon.net
Cc: jogo@openwrt.org
Cc: arnd@arndb.de
Cc: computersforpeace@gmail.com
Cc: linux-mips@linux-mips.org
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/8843/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r-- | Documentation/devicetree/bindings/interrupt-controller/brcm,bcm3380-l2-intc.txt | 41 | ||||
-rw-r--r-- | drivers/irqchip/irq-bcm7120-l2.c | 55 |
2 files changed, 92 insertions, 4 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm3380-l2-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm3380-l2-intc.txt new file mode 100644 index 0000000..8f48aad --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm3380-l2-intc.txt @@ -0,0 +1,41 @@ +Broadcom BCM3380-style Level 1 / Level 2 interrupt controller + +This interrupt controller shows up in various forms on many BCM338x/BCM63xx +chipsets. It has the following properties: + +- outputs a single interrupt signal to its interrupt controller parent + +- contains one or more enable/status word pairs, which often appear at + different offsets in different blocks + +- no atomic set/clear operations + +Required properties: + +- compatible: should be "brcm,bcm3380-l2-intc" +- reg: specifies one or more enable/status pairs, in the following format: + <enable_reg 0x4 status_reg 0x4>... +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: specifies the number of cells needed to encode an interrupt + source, should be 1. +- interrupt-parent: specifies the phandle to the parent interrupt controller + this one is cascaded from +- interrupts: specifies the interrupt line in the interrupt-parent controller + node, valid values depend on the type of parent interrupt controller + +Optional properties: + +- brcm,irq-can-wake: if present, this means the L2 controller can be used as a + wakeup source for system suspend/resume. + +Example: + +irq0_intc: interrupt-controller@10000020 { + compatible = "brcm,bcm3380-l2-intc"; + reg = <0x10000024 0x4 0x1000002c 0x4>, + <0x10000020 0x4 0x10000028 0x4>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&cpu_intc>; + interrupts = <2>; +}; diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index 6a62858..3ba5cc7 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -14,6 +14,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/kconfig.h> +#include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/of.h> #include <linux/of_irq.h> @@ -120,10 +121,15 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn, /* For multiple parent IRQs with multiple words, this looks like: * <irq0_w0 irq0_w1 irq1_w0 irq1_w1 ...> */ - for (idx = 0; idx < data->n_words; idx++) - data->irq_map_mask[idx] |= - be32_to_cpup(data->map_mask_prop + - irq * data->n_words + idx); + for (idx = 0; idx < data->n_words; idx++) { + if (data->map_mask_prop) { + data->irq_map_mask[idx] |= + be32_to_cpup(data->map_mask_prop + + irq * data->n_words + idx); + } else { + data->irq_map_mask[idx] = 0xffffffff; + } + } irq_set_handler_data(parent_irq, data); irq_set_chained_handler(parent_irq, bcm7120_l2_intc_irq_handle); @@ -165,6 +171,37 @@ static int __init bcm7120_l2_intc_iomap_7120(struct device_node *dn, return 0; } +static int __init bcm7120_l2_intc_iomap_3380(struct device_node *dn, + struct bcm7120_l2_intc_data *data) +{ + unsigned int gc_idx; + + for (gc_idx = 0; gc_idx < MAX_WORDS; gc_idx++) { + unsigned int map_idx = gc_idx * 2; + void __iomem *en = of_iomap(dn, map_idx + 0); + void __iomem *stat = of_iomap(dn, map_idx + 1); + void __iomem *base = min(en, stat); + + data->map_base[map_idx + 0] = en; + data->map_base[map_idx + 1] = stat; + + if (!base) + break; + + data->pair_base[gc_idx] = base; + data->en_offset[gc_idx] = en - base; + data->stat_offset[gc_idx] = stat - base; + } + + if (!gc_idx) { + pr_err("unable to map registers\n"); + return -EINVAL; + } + + data->n_words = gc_idx; + return 0; +} + int __init bcm7120_l2_intc_probe(struct device_node *dn, struct device_node *parent, int (*iomap_regs_fn)(struct device_node *, @@ -279,5 +316,15 @@ int __init bcm7120_l2_intc_probe_7120(struct device_node *dn, "BCM7120 L2"); } +int __init bcm7120_l2_intc_probe_3380(struct device_node *dn, + struct device_node *parent) +{ + return bcm7120_l2_intc_probe(dn, parent, bcm7120_l2_intc_iomap_3380, + "BCM3380 L2"); +} + IRQCHIP_DECLARE(bcm7120_l2_intc, "brcm,bcm7120-l2-intc", bcm7120_l2_intc_probe_7120); + +IRQCHIP_DECLARE(bcm3380_l2_intc, "brcm,bcm3380-l2-intc", + bcm7120_l2_intc_probe_3380); |