aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2013-11-21 17:11:29 -0500
committerLinus Walleij <linus.walleij@linaro.org>2014-02-13 05:21:21 -0500
commite641b987c20832dfaaa51d7792ed928c2b2d2dbf (patch)
tree1831772b115d772d3fd63ab53858866bc8b8f911
parent3b4df9dbd9bf27a35d5c7d36684d245518e5a939 (diff)
irqchip: support cascaded VICs
This adds support for a VIC to be cascaded off another IRQ. On the Integrator/AP logical module IM-PD1 there is a VIC cascaded off the central FPGA IRQ controller so this is needed for that to work out. In order for the plug-in board to be able to register all the devices with their IRQs relative to the offset of the base obtained for the cascaded VIC, the base IRQ number is passed back to the caller. Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r--arch/arm/mach-versatile/core.c2
-rw-r--r--drivers/irqchip/irq-vic.c53
-rw-r--r--include/linux/irqchip/arm-vic.h6
3 files changed, 52 insertions, 9 deletions
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index a335126ae18f..f2c89fb8fca9 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -108,7 +108,7 @@ void __init versatile_init_irq(void)
108 108
109 np = of_find_matching_node_by_address(NULL, vic_of_match, 109 np = of_find_matching_node_by_address(NULL, vic_of_match,
110 VERSATILE_VIC_BASE); 110 VERSATILE_VIC_BASE);
111 __vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0, 0, np); 111 __vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np);
112 112
113 writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); 113 writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
114 114
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 70108c1491bc..6002942a231c 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -57,6 +57,7 @@
57 57
58/** 58/**
59 * struct vic_device - VIC PM device 59 * struct vic_device - VIC PM device
60 * @parent_irq: The parent IRQ number of the VIC if cascaded, or 0.
60 * @irq: The IRQ number for the base of the VIC. 61 * @irq: The IRQ number for the base of the VIC.
61 * @base: The register base for the VIC. 62 * @base: The register base for the VIC.
62 * @valid_sources: A bitmask of valid interrupts 63 * @valid_sources: A bitmask of valid interrupts
@@ -224,6 +225,17 @@ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs)
224 return handled; 225 return handled;
225} 226}
226 227
228static void vic_handle_irq_cascaded(unsigned int irq, struct irq_desc *desc)
229{
230 u32 stat, hwirq;
231 struct vic_device *vic = irq_desc_get_handler_data(desc);
232
233 while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) {
234 hwirq = ffs(stat) - 1;
235 generic_handle_irq(irq_find_mapping(vic->domain, hwirq));
236 }
237}
238
227/* 239/*
228 * Keep iterating over all registered VIC's until there are no pending 240 * Keep iterating over all registered VIC's until there are no pending
229 * interrupts. 241 * interrupts.
@@ -246,6 +258,7 @@ static struct irq_domain_ops vic_irqdomain_ops = {
246/** 258/**
247 * vic_register() - Register a VIC. 259 * vic_register() - Register a VIC.
248 * @base: The base address of the VIC. 260 * @base: The base address of the VIC.
261 * @parent_irq: The parent IRQ if cascaded, else 0.
249 * @irq: The base IRQ for the VIC. 262 * @irq: The base IRQ for the VIC.
250 * @valid_sources: bitmask of valid interrupts 263 * @valid_sources: bitmask of valid interrupts
251 * @resume_sources: bitmask of interrupts allowed for resume sources. 264 * @resume_sources: bitmask of interrupts allowed for resume sources.
@@ -257,7 +270,8 @@ static struct irq_domain_ops vic_irqdomain_ops = {
257 * 270 *
258 * This also configures the IRQ domain for the VIC. 271 * This also configures the IRQ domain for the VIC.
259 */ 272 */
260static void __init vic_register(void __iomem *base, unsigned int irq, 273static void __init vic_register(void __iomem *base, unsigned int parent_irq,
274 unsigned int irq,
261 u32 valid_sources, u32 resume_sources, 275 u32 valid_sources, u32 resume_sources,
262 struct device_node *node) 276 struct device_node *node)
263{ 277{
@@ -275,6 +289,12 @@ static void __init vic_register(void __iomem *base, unsigned int irq,
275 v->resume_sources = resume_sources; 289 v->resume_sources = resume_sources;
276 set_handle_irq(vic_handle_irq); 290 set_handle_irq(vic_handle_irq);
277 vic_id++; 291 vic_id++;
292
293 if (parent_irq) {
294 irq_set_handler_data(parent_irq, v);
295 irq_set_chained_handler(parent_irq, vic_handle_irq_cascaded);
296 }
297
278 v->domain = irq_domain_add_simple(node, fls(valid_sources), irq, 298 v->domain = irq_domain_add_simple(node, fls(valid_sources), irq,
279 &vic_irqdomain_ops, v); 299 &vic_irqdomain_ops, v);
280 /* create an IRQ mapping for each valid IRQ */ 300 /* create an IRQ mapping for each valid IRQ */
@@ -413,10 +433,10 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
413 writel(32, base + VIC_PL190_DEF_VECT_ADDR); 433 writel(32, base + VIC_PL190_DEF_VECT_ADDR);
414 } 434 }
415 435
416 vic_register(base, irq_start, vic_sources, 0, node); 436 vic_register(base, 0, irq_start, vic_sources, 0, node);
417} 437}
418 438
419void __init __vic_init(void __iomem *base, int irq_start, 439void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
420 u32 vic_sources, u32 resume_sources, 440 u32 vic_sources, u32 resume_sources,
421 struct device_node *node) 441 struct device_node *node)
422{ 442{
@@ -453,7 +473,7 @@ void __init __vic_init(void __iomem *base, int irq_start,
453 473
454 vic_init2(base); 474 vic_init2(base);
455 475
456 vic_register(base, irq_start, vic_sources, resume_sources, node); 476 vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node);
457} 477}
458 478
459/** 479/**
@@ -466,7 +486,28 @@ void __init __vic_init(void __iomem *base, int irq_start,
466void __init vic_init(void __iomem *base, unsigned int irq_start, 486void __init vic_init(void __iomem *base, unsigned int irq_start,
467 u32 vic_sources, u32 resume_sources) 487 u32 vic_sources, u32 resume_sources)
468{ 488{
469 __vic_init(base, irq_start, vic_sources, resume_sources, NULL); 489 __vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL);
490}
491
492/**
493 * vic_init_cascaded() - initialise a cascaded vectored interrupt controller
494 * @base: iomem base address
495 * @parent_irq: the parent IRQ we're cascaded off
496 * @irq_start: starting interrupt number, must be muliple of 32
497 * @vic_sources: bitmask of interrupt sources to allow
498 * @resume_sources: bitmask of interrupt sources to allow for resume
499 *
500 * This returns the base for the new interrupts or negative on error.
501 */
502int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
503 u32 vic_sources, u32 resume_sources)
504{
505 struct vic_device *v;
506
507 v = &vic_devices[vic_id];
508 __vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL);
509 /* Return out acquired base */
510 return v->irq;
470} 511}
471 512
472#ifdef CONFIG_OF 513#ifdef CONFIG_OF
@@ -489,7 +530,7 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
489 /* 530 /*
490 * Passing 0 as first IRQ makes the simple domain allocate descriptors 531 * Passing 0 as first IRQ makes the simple domain allocate descriptors
491 */ 532 */
492 __vic_init(regs, 0, interrupt_mask, wakeup_mask, node); 533 __vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node);
493 534
494 return 0; 535 return 0;
495} 536}
diff --git a/include/linux/irqchip/arm-vic.h b/include/linux/irqchip/arm-vic.h
index e3c82dc95756..ba46c794b4e5 100644
--- a/include/linux/irqchip/arm-vic.h
+++ b/include/linux/irqchip/arm-vic.h
@@ -29,8 +29,10 @@
29struct device_node; 29struct device_node;
30struct pt_regs; 30struct pt_regs;
31 31
32void __vic_init(void __iomem *base, int irq_start, u32 vic_sources, 32void __vic_init(void __iomem *base, int parent_irq, int irq_start,
33 u32 resume_sources, struct device_node *node); 33 u32 vic_sources, u32 resume_sources, struct device_node *node);
34void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources); 34void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
35int vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
36 u32 vic_sources, u32 resume_sources);
35 37
36#endif 38#endif