aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGrant Likely <grant.likely@linaro.org>2013-09-19 17:47:37 -0400
committerShawn Guo <shawn.guo@freescale.com>2014-05-16 04:19:12 -0400
commitbb976a3070d8f947dddbf738cfe36487ec17ab2a (patch)
tree257567050176403424697a9e05e2b933648fc532
parent0a911f537055e872691f8ac057eb74e9a90877b2 (diff)
ENGR00313685-9 of/irq: create interrupts-extended property
commit 79d9701559a9f3e9b2021fbd292f5e70ad75f686 upstream. 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> Signed-off-by: Shawn Guo <shawn.guo@freescale.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 1f4ffeb4aaec..7f51e266888b 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;