diff options
author | Grant Likely <grant.likely@linaro.org> | 2013-09-19 17:47:37 -0400 |
---|---|---|
committer | Shawn Guo <shawn.guo@freescale.com> | 2014-05-16 04:19:12 -0400 |
commit | bb976a3070d8f947dddbf738cfe36487ec17ab2a (patch) | |
tree | 257567050176403424697a9e05e2b933648fc532 | |
parent | 0a911f537055e872691f8ac057eb74e9a90877b2 (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.txt | 29 | ||||
-rw-r--r-- | arch/arm/boot/dts/testcases/tests-interrupts.dtsi | 16 | ||||
-rw-r--r-- | drivers/of/irq.c | 16 | ||||
-rw-r--r-- | drivers/of/selftest.c | 70 |
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 | |||
4 | 1) Interrupt client nodes | 4 | 1) Interrupt client nodes |
5 | ------------------------- | 5 | ------------------------- |
6 | 6 | ||
7 | Nodes that describe devices which generate interrupts must contain an | 7 | Nodes 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 |
9 | specifiers, one per output interrupt. The format of the interrupt specifier is | 9 | contain a list of interrupt specifiers, one per output interrupt. The format of |
10 | determined by the interrupt controller to which the interrupts are routed; see | 10 | the interrupt specifier is determined by the interrupt controller to which the |
11 | section 2 below for details. | 11 | interrupts are routed; see section 2 below for details. |
12 | |||
13 | Example: | ||
14 | interrupt-parent = <&intc1>; | ||
15 | interrupts = <5 0>, <6 0>; | ||
12 | 16 | ||
13 | The "interrupt-parent" property is used to specify the controller to which | 17 | The "interrupt-parent" property is used to specify the controller to which |
14 | interrupts are routed and contains a single phandle referring to the interrupt | 18 | interrupts are routed and contains a single phandle referring to the interrupt |
15 | controller node. This property is inherited, so it may be specified in an | 19 | controller node. This property is inherited, so it may be specified in an |
16 | interrupt client node or in any of its parent nodes. | 20 | interrupt 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 | |||
23 | The "interrupts-extended" property is a special form for use when a node needs | ||
24 | to reference multiple interrupt parents. Each entry in this property contains | ||
25 | both the parent phandle and the interrupt specifier. "interrupts-extended" | ||
26 | should only be used when a device has multiple interrupt parents. | ||
27 | |||
28 | Example: | ||
29 | interrupts-extended = <&intc1 5 1>, <&intc2 1 0>; | ||
30 | |||
31 | A device node may contain either "interrupts" or "interrupts-extended", but not | ||
32 | both. If both properties are present, then the operating system should log an | ||
33 | error and use only the data in "interrupts". | ||
17 | 34 | ||
18 | 2) Interrupt controller nodes | 35 | 2) 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 | ||
234 | static 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 | |||
234 | static int __init of_selftest(void) | 303 | static 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; |