aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2015-08-06 19:00:31 -0400
committerThomas Gleixner <tglx@linutronix.de>2015-08-20 16:38:41 -0400
commita493f339a88ddd20693460c1dcf8230aa3732b8b (patch)
tree1fecfe79a2633e2da69d3fd536ef3e72cd99c2ff
parentde58e52f207e3318cb1e1d43f951454e0c83827f (diff)
irqchip/bcm2835: Add support for being used as a second level controller
The BCM2836 (Raspberry Pi 2) uses two levels of interrupt handling with the CPU-local interrupts being the root, so we need to register ours as chained off of the CPU's local interrupt. Signed-off-by: Eric Anholt <eric@anholt.net> Acked-by: Stephen Warren <swarren@wwwdotorg.org> Cc: linux-rpi-kernel@lists.infradead.org Cc: Lee Jones <lee@kernel.org> Cc: Jason Cooper <jason@lakedaemon.net> Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1438902033-31477-3-git-send-email-eric@anholt.net Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt25
-rw-r--r--drivers/irqchip/irq-bcm2835.c43
2 files changed, 64 insertions, 4 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
index 7da578d72123..2d6c8bb4d827 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
@@ -5,9 +5,14 @@ The BCM2835 contains a custom top-level interrupt controller, which supports
5controller, or the HW block containing it, is referred to occasionally 5controller, or the HW block containing it, is referred to occasionally
6as "armctrl" in the SoC documentation, hence naming of this binding. 6as "armctrl" in the SoC documentation, hence naming of this binding.
7 7
8The BCM2836 contains the same interrupt controller with the same
9interrupts, but the per-CPU interrupt controller is the root, and an
10interrupt there indicates that the ARMCTRL has an interrupt to handle.
11
8Required properties: 12Required properties:
9 13
10- compatible : should be "brcm,bcm2835-armctrl-ic" 14- compatible : should be "brcm,bcm2835-armctrl-ic" or
15 "brcm,bcm2836-armctrl-ic"
11- reg : Specifies base physical address and size of the registers. 16- reg : Specifies base physical address and size of the registers.
12- interrupt-controller : Identifies the node as an interrupt controller 17- interrupt-controller : Identifies the node as an interrupt controller
13- #interrupt-cells : Specifies the number of cells needed to encode an 18- #interrupt-cells : Specifies the number of cells needed to encode an
@@ -20,6 +25,12 @@ Required properties:
20 The 2nd cell contains the interrupt number within the bank. Valid values 25 The 2nd cell contains the interrupt number within the bank. Valid values
21 are 0..7 for bank 0, and 0..31 for bank 1. 26 are 0..7 for bank 0, and 0..31 for bank 1.
22 27
28Additional required properties for brcm,bcm2836-armctrl-ic:
29- interrupt-parent : Specifies the parent interrupt controller when this
30 controller is the second level.
31- interrupts : Specifies the interrupt on the parent for this interrupt
32 controller to handle.
33
23The interrupt sources are as follows: 34The interrupt sources are as follows:
24 35
25Bank 0: 36Bank 0:
@@ -102,9 +113,21 @@ Bank 2:
102 113
103Example: 114Example:
104 115
116/* BCM2835, first level */
105intc: interrupt-controller { 117intc: interrupt-controller {
106 compatible = "brcm,bcm2835-armctrl-ic"; 118 compatible = "brcm,bcm2835-armctrl-ic";
107 reg = <0x7e00b200 0x200>; 119 reg = <0x7e00b200 0x200>;
108 interrupt-controller; 120 interrupt-controller;
109 #interrupt-cells = <2>; 121 #interrupt-cells = <2>;
110}; 122};
123
124/* BCM2836, second level */
125intc: interrupt-controller {
126 compatible = "brcm,bcm2836-armctrl-ic";
127 reg = <0x7e00b200 0x200>;
128 interrupt-controller;
129 #interrupt-cells = <2>;
130
131 interrupt-parent = <&local_intc>;
132 interrupts = <8>;
133};
diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c
index a40d97268b8a..ed4ca9deca70 100644
--- a/drivers/irqchip/irq-bcm2835.c
+++ b/drivers/irqchip/irq-bcm2835.c
@@ -96,6 +96,7 @@ struct armctrl_ic {
96static struct armctrl_ic intc __read_mostly; 96static struct armctrl_ic intc __read_mostly;
97static void __exception_irq_entry bcm2835_handle_irq( 97static void __exception_irq_entry bcm2835_handle_irq(
98 struct pt_regs *regs); 98 struct pt_regs *regs);
99static void bcm2836_chained_handle_irq(unsigned int irq, struct irq_desc *desc);
99 100
100static void armctrl_mask_irq(struct irq_data *d) 101static void armctrl_mask_irq(struct irq_data *d)
101{ 102{
@@ -139,7 +140,8 @@ static const struct irq_domain_ops armctrl_ops = {
139}; 140};
140 141
141static int __init armctrl_of_init(struct device_node *node, 142static int __init armctrl_of_init(struct device_node *node,
142 struct device_node *parent) 143 struct device_node *parent,
144 bool is_2836)
143{ 145{
144 void __iomem *base; 146 void __iomem *base;
145 int irq, b, i; 147 int irq, b, i;
@@ -168,10 +170,34 @@ static int __init armctrl_of_init(struct device_node *node,
168 } 170 }
169 } 171 }
170 172
171 set_handle_irq(bcm2835_handle_irq); 173 if (is_2836) {
174 int parent_irq = irq_of_parse_and_map(node, 0);
175
176 if (!parent_irq) {
177 panic("%s: unable to get parent interrupt.\n",
178 node->full_name);
179 }
180 irq_set_chained_handler(parent_irq, bcm2836_chained_handle_irq);
181 } else {
182 set_handle_irq(bcm2835_handle_irq);
183 }
184
172 return 0; 185 return 0;
173} 186}
174 187
188static int __init bcm2835_armctrl_of_init(struct device_node *node,
189 struct device_node *parent)
190{
191 return armctrl_of_init(node, parent, false);
192}
193
194static int __init bcm2836_armctrl_of_init(struct device_node *node,
195 struct device_node *parent)
196{
197 return armctrl_of_init(node, parent, true);
198}
199
200
175/* 201/*
176 * Handle each interrupt across the entire interrupt controller. This reads the 202 * Handle each interrupt across the entire interrupt controller. This reads the
177 * status register before handling each interrupt, which is necessary given that 203 * status register before handling each interrupt, which is necessary given that
@@ -219,4 +245,15 @@ static void __exception_irq_entry bcm2835_handle_irq(
219 handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs); 245 handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs);
220} 246}
221 247
222IRQCHIP_DECLARE(bcm2835_armctrl_ic, "brcm,bcm2835-armctrl-ic", armctrl_of_init); 248static void bcm2836_chained_handle_irq(unsigned int irq, struct irq_desc *desc)
249{
250 u32 hwirq;
251
252 while ((hwirq = get_next_armctrl_hwirq()) != ~0)
253 generic_handle_irq(irq_linear_revmap(intc.domain, hwirq));
254}
255
256IRQCHIP_DECLARE(bcm2835_armctrl_ic, "brcm,bcm2835-armctrl-ic",
257 bcm2835_armctrl_of_init);
258IRQCHIP_DECLARE(bcm2836_armctrl_ic, "brcm,bcm2836-armctrl-ic",
259 bcm2836_armctrl_of_init);