aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/irqchip/irq-vic.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-04-05 18:37:40 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-04-05 18:37:40 -0400
commitcbda94e039c3862326a65d1d0506447af8330c3c (patch)
tree1147da54ec6eb7e1081977f07e62d514b981d9a3 /drivers/irqchip/irq-vic.c
parentf83ccb93585d1f472c30fa2bbb8b56c23dbdb506 (diff)
parentf1d7d8c86bc8ca41c88acf10ce383c5104cf4920 (diff)
Merge tag 'drivers-3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC driver changes from Arnd Bergmann: "These changes are mostly for ARM specific device drivers that either don't have an upstream maintainer, or that had the maintainer ask us to pick up the changes to avoid conflicts. A large chunk of this are clock drivers (bcm281xx, exynos, versatile, shmobile), aside from that, reset controllers for STi as well as a large rework of the Marvell Orion/EBU watchdog driver are notable" * tag 'drivers-3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (99 commits) Revert "dts: socfpga: Add DTS entry for adding the stmmac glue layer for stmmac." Revert "net: stmmac: Add SOCFPGA glue driver" ARM: shmobile: r8a7791: Fix SCIFA3-5 clocks ARM: STi: Add reset controller support to mach-sti Kconfig drivers: reset: stih416: add softreset controller drivers: reset: stih415: add softreset controller drivers: reset: Reset controller driver for STiH416 drivers: reset: Reset controller driver for STiH415 drivers: reset: STi SoC system configuration reset controller support dts: socfpga: Add sysmgr node so the gmac can use to reference dts: socfpga: Add support for SD/MMC on the SOCFPGA platform reset: Add optional resets and stubs ARM: shmobile: r7s72100: fix bus clock calculation Power: Reset: Generalize qnap-poweroff to work on Synology devices. dts: socfpga: Update clock entry to support multiple parents ARM: socfpga: Update socfpga_defconfig dts: socfpga: Add DTS entry for adding the stmmac glue layer for stmmac. net: stmmac: Add SOCFPGA glue driver watchdog: orion_wdt: Use %pa to print 'phys_addr_t' drivers: cci: Export CCI PMU revision ...
Diffstat (limited to 'drivers/irqchip/irq-vic.c')
-rw-r--r--drivers/irqchip/irq-vic.c60
1 files changed, 53 insertions, 7 deletions
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 473f09a74d4d..37dab0b472cd 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{
@@ -273,15 +287,25 @@ static void __init vic_register(void __iomem *base, unsigned int irq,
273 v->base = base; 287 v->base = base;
274 v->valid_sources = valid_sources; 288 v->valid_sources = valid_sources;
275 v->resume_sources = resume_sources; 289 v->resume_sources = resume_sources;
276 v->irq = irq;
277 set_handle_irq(vic_handle_irq); 290 set_handle_irq(vic_handle_irq);
278 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
279 v->domain = irq_domain_add_simple(node, fls(valid_sources), irq, 298 v->domain = irq_domain_add_simple(node, fls(valid_sources), irq,
280 &vic_irqdomain_ops, v); 299 &vic_irqdomain_ops, v);
281 /* create an IRQ mapping for each valid IRQ */ 300 /* create an IRQ mapping for each valid IRQ */
282 for (i = 0; i < fls(valid_sources); i++) 301 for (i = 0; i < fls(valid_sources); i++)
283 if (valid_sources & (1 << i)) 302 if (valid_sources & (1 << i))
284 irq_create_mapping(v->domain, i); 303 irq_create_mapping(v->domain, i);
304 /* If no base IRQ was passed, figure out our allocated base */
305 if (irq)
306 v->irq = irq;
307 else
308 v->irq = irq_find_mapping(v->domain, 0);
285} 309}
286 310
287static void vic_ack_irq(struct irq_data *d) 311static void vic_ack_irq(struct irq_data *d)
@@ -409,10 +433,10 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
409 writel(32, base + VIC_PL190_DEF_VECT_ADDR); 433 writel(32, base + VIC_PL190_DEF_VECT_ADDR);
410 } 434 }
411 435
412 vic_register(base, irq_start, vic_sources, 0, node); 436 vic_register(base, 0, irq_start, vic_sources, 0, node);
413} 437}
414 438
415void __init __vic_init(void __iomem *base, int irq_start, 439void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
416 u32 vic_sources, u32 resume_sources, 440 u32 vic_sources, u32 resume_sources,
417 struct device_node *node) 441 struct device_node *node)
418{ 442{
@@ -449,7 +473,7 @@ void __init __vic_init(void __iomem *base, int irq_start,
449 473
450 vic_init2(base); 474 vic_init2(base);
451 475
452 vic_register(base, irq_start, vic_sources, resume_sources, node); 476 vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node);
453} 477}
454 478
455/** 479/**
@@ -462,8 +486,30 @@ void __init __vic_init(void __iomem *base, int irq_start,
462void __init vic_init(void __iomem *base, unsigned int irq_start, 486void __init vic_init(void __iomem *base, unsigned int irq_start,
463 u32 vic_sources, u32 resume_sources) 487 u32 vic_sources, u32 resume_sources)
464{ 488{
465 __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;
466} 511}
512EXPORT_SYMBOL_GPL(vic_init_cascaded);
467 513
468#ifdef CONFIG_OF 514#ifdef CONFIG_OF
469int __init vic_of_init(struct device_node *node, struct device_node *parent) 515int __init vic_of_init(struct device_node *node, struct device_node *parent)
@@ -485,7 +531,7 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
485 /* 531 /*
486 * Passing 0 as first IRQ makes the simple domain allocate descriptors 532 * Passing 0 as first IRQ makes the simple domain allocate descriptors
487 */ 533 */
488 __vic_init(regs, 0, interrupt_mask, wakeup_mask, node); 534 __vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node);
489 535
490 return 0; 536 return 0;
491} 537}