aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/brcm,l2-intc.txt29
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/marvell,armada-370-xp-mpic.txt (renamed from Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt)0
-rw-r--r--drivers/irqchip/Kconfig6
-rw-r--r--drivers/irqchip/Makefile1
-rw-r--r--drivers/irqchip/irq-brcmstb-l2.c202
-rw-r--r--drivers/irqchip/irq-gic.c2
-rw-r--r--include/linux/irqchip/arm-gic.h2
7 files changed, 241 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/brcm,l2-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/brcm,l2-intc.txt
new file mode 100644
index 000000000000..448273a30a11
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,l2-intc.txt
@@ -0,0 +1,29 @@
1Broadcom Generic Level 2 Interrupt Controller
2
3Required properties:
4
5- compatible: should be "brcm,l2-intc"
6- reg: specifies the base physical address and size of the registers
7- interrupt-controller: identifies the node as an interrupt controller
8- #interrupt-cells: specifies the number of cells needed to encode an
9 interrupt source. Should be 1.
10- interrupt-parent: specifies the phandle to the parent interrupt controller
11 this controller is cacaded from
12- interrupts: specifies the interrupt line in the interrupt-parent irq space
13 to be used for cascading
14
15Optional properties:
16
17- brcm,irq-can-wake: If present, this means the L2 controller can be used as a
18 wakeup source for system suspend/resume.
19
20Example:
21
22hif_intr2_intc: interrupt-controller@f0441000 {
23 compatible = "brcm,l2-intc";
24 reg = <0xf0441000 0x30>;
25 interrupt-controller;
26 #interrupt-cells = <1>;
27 interrupt-parent = <&intc>;
28 interrupts = <0x0 0x20 0x0>;
29};
diff --git a/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,armada-370-xp-mpic.txt
index 5fc03134a999..5fc03134a999 100644
--- a/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,armada-370-xp-mpic.txt
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index d770f7406631..bbb746e35500 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -30,6 +30,12 @@ config ARM_VIC_NR
30 The maximum number of VICs available in the system, for 30 The maximum number of VICs available in the system, for
31 power management. 31 power management.
32 32
33config BRCMSTB_L2_IRQ
34 bool
35 depends on ARM
36 select GENERIC_IRQ_CHIP
37 select IRQ_DOMAIN
38
33config DW_APB_ICTL 39config DW_APB_ICTL
34 bool 40 bool
35 select IRQ_DOMAIN 41 select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index f180f8d5fb7b..62a13e5ef98f 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -29,3 +29,4 @@ obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o
29obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o 29obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o
30obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o 30obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o
31obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o 31obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o
32obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o
diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c
new file mode 100644
index 000000000000..8ee2a36d5840
--- /dev/null
+++ b/drivers/irqchip/irq-brcmstb-l2.c
@@ -0,0 +1,202 @@
1/*
2 * Generic Broadcom Set Top Box Level 2 Interrupt controller driver
3 *
4 * Copyright (C) 2014 Broadcom Corporation
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17
18#include <linux/init.h>
19#include <linux/slab.h>
20#include <linux/module.h>
21#include <linux/platform_device.h>
22#include <linux/of.h>
23#include <linux/of_irq.h>
24#include <linux/of_address.h>
25#include <linux/of_platform.h>
26#include <linux/interrupt.h>
27#include <linux/irq.h>
28#include <linux/io.h>
29#include <linux/irqdomain.h>
30#include <linux/irqchip.h>
31#include <linux/irqchip/chained_irq.h>
32
33#include <asm/mach/irq.h>
34
35#include "irqchip.h"
36
37/* Register offsets in the L2 interrupt controller */
38#define CPU_STATUS 0x00
39#define CPU_SET 0x04
40#define CPU_CLEAR 0x08
41#define CPU_MASK_STATUS 0x0c
42#define CPU_MASK_SET 0x10
43#define CPU_MASK_CLEAR 0x14
44
45/* L2 intc private data structure */
46struct brcmstb_l2_intc_data {
47 int parent_irq;
48 void __iomem *base;
49 struct irq_domain *domain;
50 bool can_wake;
51 u32 saved_mask; /* for suspend/resume */
52};
53
54static void brcmstb_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc)
55{
56 struct brcmstb_l2_intc_data *b = irq_desc_get_handler_data(desc);
57 struct irq_chip *chip = irq_desc_get_chip(desc);
58 u32 status;
59
60 chained_irq_enter(chip, desc);
61
62 status = __raw_readl(b->base + CPU_STATUS) &
63 ~(__raw_readl(b->base + CPU_MASK_STATUS));
64
65 if (status == 0) {
66 do_bad_IRQ(irq, desc);
67 goto out;
68 }
69
70 do {
71 irq = ffs(status) - 1;
72 /* ack at our level */
73 __raw_writel(1 << irq, b->base + CPU_CLEAR);
74 status &= ~(1 << irq);
75 generic_handle_irq(irq_find_mapping(b->domain, irq));
76 } while (status);
77out:
78 chained_irq_exit(chip, desc);
79}
80
81static void brcmstb_l2_intc_suspend(struct irq_data *d)
82{
83 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
84 struct brcmstb_l2_intc_data *b = gc->private;
85
86 irq_gc_lock(gc);
87 /* Save the current mask */
88 b->saved_mask = __raw_readl(b->base + CPU_MASK_STATUS);
89
90 if (b->can_wake) {
91 /* Program the wakeup mask */
92 __raw_writel(~gc->wake_active, b->base + CPU_MASK_SET);
93 __raw_writel(gc->wake_active, b->base + CPU_MASK_CLEAR);
94 }
95 irq_gc_unlock(gc);
96}
97
98static void brcmstb_l2_intc_resume(struct irq_data *d)
99{
100 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
101 struct brcmstb_l2_intc_data *b = gc->private;
102
103 irq_gc_lock(gc);
104 /* Clear unmasked non-wakeup interrupts */
105 __raw_writel(~b->saved_mask & ~gc->wake_active, b->base + CPU_CLEAR);
106
107 /* Restore the saved mask */
108 __raw_writel(b->saved_mask, b->base + CPU_MASK_SET);
109 __raw_writel(~b->saved_mask, b->base + CPU_MASK_CLEAR);
110 irq_gc_unlock(gc);
111}
112
113int __init brcmstb_l2_intc_of_init(struct device_node *np,
114 struct device_node *parent)
115{
116 unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
117 struct brcmstb_l2_intc_data *data;
118 struct irq_chip_generic *gc;
119 struct irq_chip_type *ct;
120 int ret;
121
122 data = kzalloc(sizeof(*data), GFP_KERNEL);
123 if (!data)
124 return -ENOMEM;
125
126 data->base = of_iomap(np, 0);
127 if (!data->base) {
128 pr_err("failed to remap intc L2 registers\n");
129 ret = -ENOMEM;
130 goto out_free;
131 }
132
133 /* Disable all interrupts by default */
134 __raw_writel(0xffffffff, data->base + CPU_MASK_SET);
135 __raw_writel(0xffffffff, data->base + CPU_CLEAR);
136
137 data->parent_irq = irq_of_parse_and_map(np, 0);
138 if (data->parent_irq < 0) {
139 pr_err("failed to find parent interrupt\n");
140 ret = data->parent_irq;
141 goto out_unmap;
142 }
143
144 data->domain = irq_domain_add_linear(np, 32,
145 &irq_generic_chip_ops, NULL);
146 if (!data->domain) {
147 ret = -ENOMEM;
148 goto out_unmap;
149 }
150
151 /* Allocate a single Generic IRQ chip for this node */
152 ret = irq_alloc_domain_generic_chips(data->domain, 32, 1,
153 np->full_name, handle_level_irq, clr, 0, 0);
154 if (ret) {
155 pr_err("failed to allocate generic irq chip\n");
156 goto out_free_domain;
157 }
158
159 /* Set the IRQ chaining logic */
160 irq_set_handler_data(data->parent_irq, data);
161 irq_set_chained_handler(data->parent_irq, brcmstb_l2_intc_irq_handle);
162
163 gc = irq_get_domain_generic_chip(data->domain, 0);
164 gc->reg_base = data->base;
165 gc->private = data;
166 ct = gc->chip_types;
167
168 ct->chip.irq_ack = irq_gc_ack_set_bit;
169 ct->regs.ack = CPU_CLEAR;
170
171 ct->chip.irq_mask = irq_gc_mask_disable_reg;
172 ct->regs.disable = CPU_MASK_SET;
173
174 ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
175 ct->regs.enable = CPU_MASK_CLEAR;
176
177 ct->chip.irq_suspend = brcmstb_l2_intc_suspend;
178 ct->chip.irq_resume = brcmstb_l2_intc_resume;
179
180 if (of_property_read_bool(np, "brcm,irq-can-wake")) {
181 data->can_wake = true;
182 /* This IRQ chip can wake the system, set all child interrupts
183 * in wake_enabled mask
184 */
185 gc->wake_enabled = 0xffffffff;
186 ct->chip.irq_set_wake = irq_gc_set_wake;
187 }
188
189 pr_info("registered L2 intc (mem: 0x%p, parent irq: %d)\n",
190 data->base, data->parent_irq);
191
192 return 0;
193
194out_free_domain:
195 irq_domain_remove(data->domain);
196out_unmap:
197 iounmap(data->base);
198out_free:
199 kfree(data);
200 return ret;
201}
202IRQCHIP_DECLARE(brcmstb_l2_intc, "brcm,l2-intc", brcmstb_l2_intc_of_init);
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 57d165e026f4..7e11c9d6ae8c 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -291,7 +291,7 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
291 291
292 do { 292 do {
293 irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK); 293 irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
294 irqnr = irqstat & ~0x1c00; 294 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
295 295
296 if (likely(irqnr > 15 && irqnr < 1021)) { 296 if (likely(irqnr > 15 && irqnr < 1021)) {
297 irqnr = irq_find_mapping(gic->domain, irqnr); 297 irqnr = irq_find_mapping(gic->domain, irqnr);
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 7ed92d0560d5..45e2d8c15bd2 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -21,6 +21,8 @@
21#define GIC_CPU_ACTIVEPRIO 0xd0 21#define GIC_CPU_ACTIVEPRIO 0xd0
22#define GIC_CPU_IDENT 0xfc 22#define GIC_CPU_IDENT 0xfc
23 23
24#define GICC_IAR_INT_ID_MASK 0x3ff
25
24#define GIC_DIST_CTRL 0x000 26#define GIC_DIST_CTRL 0x000
25#define GIC_DIST_CTR 0x004 27#define GIC_DIST_CTR 0x004
26#define GIC_DIST_IGROUP 0x080 28#define GIC_DIST_IGROUP 0x080