aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEzequiel Garcia <ezequiel.garcia@free-electrons.com>2014-02-10 15:00:02 -0500
committerJason Cooper <jason@lakedaemon.net>2014-02-22 01:12:29 -0500
commitbc69b8adfe221def02ea10f7b9ab32e80195334c (patch)
tree55ac7cb070259dee0c49555062fab25334fc91e9
parent9b8cf779f93bc48c0f12ef71e5bc90fd92322656 (diff)
irqchip: armada-370-xp: Setup a chained handler for the MPIC
The new Armada 375 and Armada 38x Marvell SoCs are based on Cortex-A9 CPU cores and use the ARM GIC as their main interrupt controller. However, for various purposes (wake-up from suspend, MSI interrupts), they have kept a separate MPIC interrupt controller, acting as a slave to the GIC. This MPIC was already used as the primary controller on previous Marvell SoCs, so this commit extends the existing driver to allow the MPIC to be used as a GIC slave. Reviewed-by: Gregory CLEMENT <gregory.clement@free-electrons.com> Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> Signed-off-by: Jason Cooper <jason@lakedaemon.net>
-rw-r--r--Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt8
-rw-r--r--drivers/irqchip/irq-armada-370-xp.c50
2 files changed, 50 insertions, 8 deletions
diff --git a/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt b/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt
index d74091a8a3bf..5fc03134a999 100644
--- a/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt
+++ b/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt
@@ -1,4 +1,4 @@
1Marvell Armada 370 and Armada XP Interrupt Controller 1Marvell Armada 370, 375, 38x, XP Interrupt Controller
2----------------------------------------------------- 2-----------------------------------------------------
3 3
4Required properties: 4Required properties:
@@ -16,7 +16,13 @@ Required properties:
16 automatically map to the interrupt controller registers of the 16 automatically map to the interrupt controller registers of the
17 current CPU) 17 current CPU)
18 18
19Optional properties:
19 20
21- interrupts: If defined, then it indicates that this MPIC is
22 connected as a slave to another interrupt controller. This is
23 typically the case on Armada 375 and Armada 38x, where the MPIC is
24 connected as a slave to the Cortex-A9 GIC. The provided interrupt
25 indicate to which GIC interrupt the MPIC output is connected.
20 26
21Example: 27Example:
22 28
diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c
index 2ba5761a638e..cd79503abea9 100644
--- a/drivers/irqchip/irq-armada-370-xp.c
+++ b/drivers/irqchip/irq-armada-370-xp.c
@@ -18,6 +18,7 @@
18#include <linux/init.h> 18#include <linux/init.h>
19#include <linux/irq.h> 19#include <linux/irq.h>
20#include <linux/interrupt.h> 20#include <linux/interrupt.h>
21#include <linux/irqchip/chained_irq.h>
21#include <linux/io.h> 22#include <linux/io.h>
22#include <linux/of_address.h> 23#include <linux/of_address.h>
23#include <linux/of_irq.h> 24#include <linux/of_irq.h>
@@ -42,6 +43,7 @@
42#define ARMADA_370_XP_INT_SOURCE_CTL(irq) (0x100 + irq*4) 43#define ARMADA_370_XP_INT_SOURCE_CTL(irq) (0x100 + irq*4)
43 44
44#define ARMADA_370_XP_CPU_INTACK_OFFS (0x44) 45#define ARMADA_370_XP_CPU_INTACK_OFFS (0x44)
46#define ARMADA_375_PPI_CAUSE (0x10)
45 47
46#define ARMADA_370_XP_SW_TRIG_INT_OFFS (0x4) 48#define ARMADA_370_XP_SW_TRIG_INT_OFFS (0x4)
47#define ARMADA_370_XP_IN_DRBEL_MSK_OFFS (0xc) 49#define ARMADA_370_XP_IN_DRBEL_MSK_OFFS (0xc)
@@ -353,7 +355,7 @@ static struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
353}; 355};
354 356
355#ifdef CONFIG_PCI_MSI 357#ifdef CONFIG_PCI_MSI
356static void armada_370_xp_handle_msi_irq(struct pt_regs *regs) 358static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained)
357{ 359{
358 u32 msimask, msinr; 360 u32 msimask, msinr;
359 361
@@ -373,13 +375,41 @@ static void armada_370_xp_handle_msi_irq(struct pt_regs *regs)
373 375
374 irq = irq_find_mapping(armada_370_xp_msi_domain, 376 irq = irq_find_mapping(armada_370_xp_msi_domain,
375 msinr - 16); 377 msinr - 16);
376 handle_IRQ(irq, regs); 378
379 if (is_chained)
380 generic_handle_irq(irq);
381 else
382 handle_IRQ(irq, regs);
377 } 383 }
378} 384}
379#else 385#else
380static void armada_370_xp_handle_msi_irq(struct pt_regs *r) {} 386static void armada_370_xp_handle_msi_irq(struct pt_regs *r, bool b) {}
381#endif 387#endif
382 388
389static void armada_370_xp_mpic_handle_cascade_irq(unsigned int irq,
390 struct irq_desc *desc)
391{
392 struct irq_chip *chip = irq_get_chip(irq);
393 unsigned long irqmap, irqn;
394 unsigned int cascade_irq;
395
396 chained_irq_enter(chip, desc);
397
398 irqmap = readl_relaxed(per_cpu_int_base + ARMADA_375_PPI_CAUSE);
399
400 if (irqmap & BIT(0)) {
401 armada_370_xp_handle_msi_irq(NULL, true);
402 irqmap &= ~BIT(0);
403 }
404
405 for_each_set_bit(irqn, &irqmap, BITS_PER_LONG) {
406 cascade_irq = irq_find_mapping(armada_370_xp_mpic_domain, irqn);
407 generic_handle_irq(cascade_irq);
408 }
409
410 chained_irq_exit(chip, desc);
411}
412
383static asmlinkage void __exception_irq_entry 413static asmlinkage void __exception_irq_entry
384armada_370_xp_handle_irq(struct pt_regs *regs) 414armada_370_xp_handle_irq(struct pt_regs *regs)
385{ 415{
@@ -402,7 +432,7 @@ armada_370_xp_handle_irq(struct pt_regs *regs)
402 432
403 /* MSI handling */ 433 /* MSI handling */
404 if (irqnr == 1) 434 if (irqnr == 1)
405 armada_370_xp_handle_msi_irq(regs); 435 armada_370_xp_handle_msi_irq(regs, false);
406 436
407#ifdef CONFIG_SMP 437#ifdef CONFIG_SMP
408 /* IPI Handling */ 438 /* IPI Handling */
@@ -433,6 +463,7 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
433 struct device_node *parent) 463 struct device_node *parent)
434{ 464{
435 struct resource main_int_res, per_cpu_int_res; 465 struct resource main_int_res, per_cpu_int_res;
466 int parent_irq;
436 u32 control; 467 u32 control;
437 468
438 BUG_ON(of_address_to_resource(node, 0, &main_int_res)); 469 BUG_ON(of_address_to_resource(node, 0, &main_int_res));
@@ -461,8 +492,6 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
461 492
462 BUG_ON(!armada_370_xp_mpic_domain); 493 BUG_ON(!armada_370_xp_mpic_domain);
463 494
464 irq_set_default_host(armada_370_xp_mpic_domain);
465
466#ifdef CONFIG_SMP 495#ifdef CONFIG_SMP
467 armada_xp_mpic_smp_cpu_init(); 496 armada_xp_mpic_smp_cpu_init();
468 497
@@ -478,7 +507,14 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
478 507
479 armada_370_xp_msi_init(node, main_int_res.start); 508 armada_370_xp_msi_init(node, main_int_res.start);
480 509
481 set_handle_irq(armada_370_xp_handle_irq); 510 parent_irq = irq_of_parse_and_map(node, 0);
511 if (parent_irq <= 0) {
512 irq_set_default_host(armada_370_xp_mpic_domain);
513 set_handle_irq(armada_370_xp_handle_irq);
514 } else {
515 irq_set_chained_handler(parent_irq,
516 armada_370_xp_mpic_handle_cascade_irq);
517 }
482 518
483 return 0; 519 return 0;
484} 520}