aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGrant Likely <grant.likely@linaro.org>2013-09-19 17:47:37 -0400
committerGrant Likely <grant.likely@linaro.org>2013-10-28 19:48:14 -0400
commit79d9701559a9f3e9b2021fbd292f5e70ad75f686 (patch)
treebbbcc05e19c73ffe9f6a5b71c8c45c5e051c2747
parentf27446c3ad5b6d3b5b28ec0176e23d3ceca595d8 (diff)
of/irq: create interrupts-extended property
The standard interrupts property in device tree can only handle interrupts coming from a single interrupt parent. If a device is wired to multiple interrupt controllers, then it needs to be attached to a node with an interrupt-map property to demux the interrupt specifiers which is confusing. It would be a lot easier if there was a form of the interrupts property that allows for a separate interrupt phandle for each interrupt specifier. This patch does exactly that by creating a new interrupts-extended property which reuses the phandle+arguments pattern used by GPIOs and other core bindings. Signed-off-by: Grant Likely <grant.likely@linaro.org> Acked-by: Tony Lindgren <tony@atomide.com> Acked-by: Kumar Gala <galak@codeaurora.org> [grant.likely: removed versatile platform hunks into separate patch] Cc: Rob Herring <rob.herring@calxeda.com>
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/interrupts.txt29
-rw-r--r--arch/arm/boot/dts/testcases/tests-interrupts.dtsi16
-rw-r--r--drivers/of/irq.c16
-rw-r--r--drivers/of/selftest.c70
4 files changed, 120 insertions, 11 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt b/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
index 72a06c0ab1db..1486497a24c1 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
@@ -4,16 +4,33 @@ Specifying interrupt information for devices
41) Interrupt client nodes 41) Interrupt client nodes
5------------------------- 5-------------------------
6 6
7Nodes that describe devices which generate interrupts must contain an 7Nodes that describe devices which generate interrupts must contain an either an
8"interrupts" property. This property must contain a list of interrupt 8"interrupts" property or an "interrupts-extended" property. These properties
9specifiers, one per output interrupt. The format of the interrupt specifier is 9contain a list of interrupt specifiers, one per output interrupt. The format of
10determined by the interrupt controller to which the interrupts are routed; see 10the interrupt specifier is determined by the interrupt controller to which the
11section 2 below for details. 11interrupts are routed; see section 2 below for details.
12
13 Example:
14 interrupt-parent = <&intc1>;
15 interrupts = <5 0>, <6 0>;
12 16
13The "interrupt-parent" property is used to specify the controller to which 17The "interrupt-parent" property is used to specify the controller to which
14interrupts are routed and contains a single phandle referring to the interrupt 18interrupts are routed and contains a single phandle referring to the interrupt
15controller node. This property is inherited, so it may be specified in an 19controller node. This property is inherited, so it may be specified in an
16interrupt client node or in any of its parent nodes. 20interrupt client node or in any of its parent nodes. Interrupts listed in the
21"interrupts" property are always in reference to the node's interrupt parent.
22
23The "interrupts-extended" property is a special form for use when a node needs
24to reference multiple interrupt parents. Each entry in this property contains
25both the parent phandle and the interrupt specifier. "interrupts-extended"
26should only be used when a device has multiple interrupt parents.
27
28 Example:
29 interrupts-extended = <&intc1 5 1>, <&intc2 1 0>;
30
31A device node may contain either "interrupts" or "interrupts-extended", but not
32both. If both properties are present, then the operating system should log an
33error and use only the data in "interrupts".
17 34
182) Interrupt controller nodes 352) Interrupt controller nodes
19----------------------------- 36-----------------------------
diff --git a/arch/arm/boot/dts/testcases/tests-interrupts.dtsi b/arch/arm/boot/dts/testcases/tests-interrupts.dtsi
index 6ecda716e9d4..560d6bf680b6 100644
--- a/arch/arm/boot/dts/testcases/tests-interrupts.dtsi
+++ b/arch/arm/boot/dts/testcases/tests-interrupts.dtsi
@@ -27,6 +27,12 @@
27 <4 &test_intc2 15 16>; 27 <4 &test_intc2 15 16>;
28 }; 28 };
29 29
30 test_intmap1: intmap1 {
31 #interrupt-cells = <2>;
32 #address-cells = <0>;
33 interrupt-map = <1 2 &test_intc0 15>;
34 };
35
30 interrupts0 { 36 interrupts0 {
31 interrupt-parent = <&test_intc0>; 37 interrupt-parent = <&test_intc0>;
32 interrupts = <1>, <2>, <3>, <4>; 38 interrupts = <1>, <2>, <3>, <4>;
@@ -36,6 +42,16 @@
36 interrupt-parent = <&test_intmap0>; 42 interrupt-parent = <&test_intmap0>;
37 interrupts = <1>, <2>, <3>, <4>; 43 interrupts = <1>, <2>, <3>, <4>;
38 }; 44 };
45
46 interrupts-extended0 {
47 interrupts-extended = <&test_intc0 1>,
48 <&test_intc1 2 3 4>,
49 <&test_intc2 5 6>,
50 <&test_intmap0 1>,
51 <&test_intmap0 2>,
52 <&test_intmap0 3>,
53 <&test_intmap1 1 2>;
54 };
39 }; 55 };
40 }; 56 };
41}; 57};
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index 7c4ff122785f..8cc62b4a7988 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -292,17 +292,23 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar
292 if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC) 292 if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
293 return of_irq_parse_oldworld(device, index, out_irq); 293 return of_irq_parse_oldworld(device, index, out_irq);
294 294
295 /* Get the reg property (if any) */
296 addr = of_get_property(device, "reg", NULL);
297
295 /* Get the interrupts property */ 298 /* Get the interrupts property */
296 intspec = of_get_property(device, "interrupts", &intlen); 299 intspec = of_get_property(device, "interrupts", &intlen);
297 if (intspec == NULL) 300 if (intspec == NULL) {
298 return -EINVAL; 301 /* Try the new-style interrupts-extended */
302 res = of_parse_phandle_with_args(device, "interrupts-extended",
303 "#interrupt-cells", index, out_irq);
304 if (res)
305 return -EINVAL;
306 return of_irq_parse_raw(addr, out_irq);
307 }
299 intlen /= sizeof(*intspec); 308 intlen /= sizeof(*intspec);
300 309
301 pr_debug(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen); 310 pr_debug(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen);
302 311
303 /* Get the reg property (if any) */
304 addr = of_get_property(device, "reg", NULL);
305
306 /* Look for the interrupt parent. */ 312 /* Look for the interrupt parent. */
307 p = of_irq_find_parent(device); 313 p = of_irq_find_parent(device);
308 if (p == NULL) 314 if (p == NULL)
diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c
index 9c80f0b7556b..e21012bde639 100644
--- a/drivers/of/selftest.c
+++ b/drivers/of/selftest.c
@@ -231,6 +231,75 @@ static void __init of_selftest_parse_interrupts(void)
231 of_node_put(np); 231 of_node_put(np);
232} 232}
233 233
234static void __init of_selftest_parse_interrupts_extended(void)
235{
236 struct device_node *np;
237 struct of_phandle_args args;
238 int i, rc;
239
240 np = of_find_node_by_path("/testcase-data/interrupts/interrupts-extended0");
241 if (!np) {
242 pr_err("missing testcase data\n");
243 return;
244 }
245
246 for (i = 0; i < 7; i++) {
247 bool passed = true;
248 rc = of_irq_parse_one(np, i, &args);
249
250 /* Test the values from tests-phandle.dtsi */
251 switch (i) {
252 case 0:
253 passed &= !rc;
254 passed &= (args.args_count == 1);
255 passed &= (args.args[0] == 1);
256 break;
257 case 1:
258 passed &= !rc;
259 passed &= (args.args_count == 3);
260 passed &= (args.args[0] == 2);
261 passed &= (args.args[1] == 3);
262 passed &= (args.args[2] == 4);
263 break;
264 case 2:
265 passed &= !rc;
266 passed &= (args.args_count == 2);
267 passed &= (args.args[0] == 5);
268 passed &= (args.args[1] == 6);
269 break;
270 case 3:
271 passed &= !rc;
272 passed &= (args.args_count == 1);
273 passed &= (args.args[0] == 9);
274 break;
275 case 4:
276 passed &= !rc;
277 passed &= (args.args_count == 3);
278 passed &= (args.args[0] == 10);
279 passed &= (args.args[1] == 11);
280 passed &= (args.args[2] == 12);
281 break;
282 case 5:
283 passed &= !rc;
284 passed &= (args.args_count == 2);
285 passed &= (args.args[0] == 13);
286 passed &= (args.args[1] == 14);
287 break;
288 case 6:
289 passed &= !rc;
290 passed &= (args.args_count == 1);
291 passed &= (args.args[0] == 15);
292 break;
293 default:
294 passed = false;
295 }
296
297 selftest(passed, "index %i - data error on node %s rc=%i\n",
298 i, args.np->full_name, rc);
299 }
300 of_node_put(np);
301}
302
234static int __init of_selftest(void) 303static int __init of_selftest(void)
235{ 304{
236 struct device_node *np; 305 struct device_node *np;
@@ -246,6 +315,7 @@ static int __init of_selftest(void)
246 of_selftest_parse_phandle_with_args(); 315 of_selftest_parse_phandle_with_args();
247 of_selftest_property_match_string(); 316 of_selftest_property_match_string();
248 of_selftest_parse_interrupts(); 317 of_selftest_parse_interrupts();
318 of_selftest_parse_interrupts_extended();
249 pr_info("end of selftest - %i passed, %i failed\n", 319 pr_info("end of selftest - %i passed, %i failed\n",
250 selftest_results.passed, selftest_results.failed); 320 selftest_results.passed, selftest_results.failed);
251 return 0; 321 return 0;