Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Kevin Cernekee and committed by
Ralf Baechle
7b7230e7 ca40f1b2

+92 -4
+41
Documentation/devicetree/bindings/interrupt-controller/brcm,bcm3380-l2-intc.txt
··· 1 + Broadcom BCM3380-style Level 1 / Level 2 interrupt controller 2 + 3 + This interrupt controller shows up in various forms on many BCM338x/BCM63xx 4 + chipsets. It has the following properties: 5 + 6 + - outputs a single interrupt signal to its interrupt controller parent 7 + 8 + - contains one or more enable/status word pairs, which often appear at 9 + different offsets in different blocks 10 + 11 + - no atomic set/clear operations 12 + 13 + Required properties: 14 + 15 + - compatible: should be "brcm,bcm3380-l2-intc" 16 + - reg: specifies one or more enable/status pairs, in the following format: 17 + <enable_reg 0x4 status_reg 0x4>... 18 + - interrupt-controller: identifies the node as an interrupt controller 19 + - #interrupt-cells: specifies the number of cells needed to encode an interrupt 20 + source, should be 1. 21 + - interrupt-parent: specifies the phandle to the parent interrupt controller 22 + this one is cascaded from 23 + - interrupts: specifies the interrupt line in the interrupt-parent controller 24 + node, valid values depend on the type of parent interrupt controller 25 + 26 + Optional properties: 27 + 28 + - brcm,irq-can-wake: if present, this means the L2 controller can be used as a 29 + wakeup source for system suspend/resume. 30 + 31 + Example: 32 + 33 + irq0_intc: interrupt-controller@10000020 { 34 + compatible = "brcm,bcm3380-l2-intc"; 35 + reg = <0x10000024 0x4 0x1000002c 0x4>, 36 + <0x10000020 0x4 0x10000028 0x4>; 37 + interrupt-controller; 38 + #interrupt-cells = <1>; 39 + interrupt-parent = <&cpu_intc>; 40 + interrupts = <2>; 41 + };
+51 -4
drivers/irqchip/irq-bcm7120-l2.c
··· 14 14 #include <linux/slab.h> 15 15 #include <linux/module.h> 16 16 #include <linux/kconfig.h> 17 + #include <linux/kernel.h> 17 18 #include <linux/platform_device.h> 18 19 #include <linux/of.h> 19 20 #include <linux/of_irq.h> ··· 121 120 /* For multiple parent IRQs with multiple words, this looks like: 122 121 * <irq0_w0 irq0_w1 irq1_w0 irq1_w1 ...> 123 122 */ 124 - for (idx = 0; idx < data->n_words; idx++) 125 - data->irq_map_mask[idx] |= 126 - be32_to_cpup(data->map_mask_prop + 127 - irq * data->n_words + idx); 123 + for (idx = 0; idx < data->n_words; idx++) { 124 + if (data->map_mask_prop) { 125 + data->irq_map_mask[idx] |= 126 + be32_to_cpup(data->map_mask_prop + 127 + irq * data->n_words + idx); 128 + } else { 129 + data->irq_map_mask[idx] = 0xffffffff; 130 + } 131 + } 128 132 129 133 irq_set_handler_data(parent_irq, data); 130 134 irq_set_chained_handler(parent_irq, bcm7120_l2_intc_irq_handle); ··· 168 162 return -EINVAL; 169 163 } 170 164 165 + return 0; 166 + } 167 + 168 + static int __init bcm7120_l2_intc_iomap_3380(struct device_node *dn, 169 + struct bcm7120_l2_intc_data *data) 170 + { 171 + unsigned int gc_idx; 172 + 173 + for (gc_idx = 0; gc_idx < MAX_WORDS; gc_idx++) { 174 + unsigned int map_idx = gc_idx * 2; 175 + void __iomem *en = of_iomap(dn, map_idx + 0); 176 + void __iomem *stat = of_iomap(dn, map_idx + 1); 177 + void __iomem *base = min(en, stat); 178 + 179 + data->map_base[map_idx + 0] = en; 180 + data->map_base[map_idx + 1] = stat; 181 + 182 + if (!base) 183 + break; 184 + 185 + data->pair_base[gc_idx] = base; 186 + data->en_offset[gc_idx] = en - base; 187 + data->stat_offset[gc_idx] = stat - base; 188 + } 189 + 190 + if (!gc_idx) { 191 + pr_err("unable to map registers\n"); 192 + return -EINVAL; 193 + } 194 + 195 + data->n_words = gc_idx; 171 196 return 0; 172 197 } 173 198 ··· 316 279 "BCM7120 L2"); 317 280 } 318 281 282 + int __init bcm7120_l2_intc_probe_3380(struct device_node *dn, 283 + struct device_node *parent) 284 + { 285 + return bcm7120_l2_intc_probe(dn, parent, bcm7120_l2_intc_iomap_3380, 286 + "BCM3380 L2"); 287 + } 288 + 319 289 IRQCHIP_DECLARE(bcm7120_l2_intc, "brcm,bcm7120-l2-intc", 320 290 bcm7120_l2_intc_probe_7120); 291 + 292 + IRQCHIP_DECLARE(bcm3380_l2_intc, "brcm,bcm3380-l2-intc", 293 + bcm7120_l2_intc_probe_3380);