aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-exynos/common.c
diff options
context:
space:
mode:
authorThomas Abraham <thomas.abraham@linaro.org>2012-05-15 03:18:35 -0400
committerKukjin Kim <kgene.kim@samsung.com>2012-05-15 18:03:44 -0400
commit1e60bc0b5f488c8acde22adeb62118ccfdb49062 (patch)
treea84b04ae45b848ae00fa8283728f678ce78d07fc /arch/arm/mach-exynos/common.c
parent9ee6af9c3fad48cddc0684d0c77d3ea1329e10a1 (diff)
ARM: EXYNOS: Add irq_domain support for interrupt combiner
Add irq_domain support for hardware interrupts of the interrupt combiner. The hardware interrupts of all the instances of the combiner are grouped in a single irq_domain. Cc: Grant Likely <grant.likely@secretlab.ca> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org> Acked-by: Rob Herring <rob.herring@calxeda.com> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
Diffstat (limited to 'arch/arm/mach-exynos/common.c')
-rw-r--r--arch/arm/mach-exynos/common.c88
1 files changed, 50 insertions, 38 deletions
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c
index 3302a8dca4e0..a688c17bc869 100644
--- a/arch/arm/mach-exynos/common.c
+++ b/arch/arm/mach-exynos/common.c
@@ -19,6 +19,8 @@
19#include <linux/serial_core.h> 19#include <linux/serial_core.h>
20#include <linux/of.h> 20#include <linux/of.h>
21#include <linux/of_irq.h> 21#include <linux/of_irq.h>
22#include <linux/export.h>
23#include <linux/irqdomain.h>
22 24
23#include <asm/proc-fns.h> 25#include <asm/proc-fns.h>
24#include <asm/exception.h> 26#include <asm/exception.h>
@@ -399,6 +401,7 @@ struct combiner_chip_data {
399 void __iomem *base; 401 void __iomem *base;
400}; 402};
401 403
404static struct irq_domain *combiner_irq_domain;
402static struct combiner_chip_data combiner_data[MAX_COMBINER_NR]; 405static struct combiner_chip_data combiner_data[MAX_COMBINER_NR];
403 406
404static inline void __iomem *combiner_base(struct irq_data *data) 407static inline void __iomem *combiner_base(struct irq_data *data)
@@ -411,14 +414,14 @@ static inline void __iomem *combiner_base(struct irq_data *data)
411 414
412static void combiner_mask_irq(struct irq_data *data) 415static void combiner_mask_irq(struct irq_data *data)
413{ 416{
414 u32 mask = 1 << (data->irq % 32); 417 u32 mask = 1 << (data->hwirq % 32);
415 418
416 __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR); 419 __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR);
417} 420}
418 421
419static void combiner_unmask_irq(struct irq_data *data) 422static void combiner_unmask_irq(struct irq_data *data)
420{ 423{
421 u32 mask = 1 << (data->irq % 32); 424 u32 mask = 1 << (data->hwirq % 32);
422 425
423 __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET); 426 __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET);
424} 427}
@@ -474,36 +477,58 @@ static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int i
474 irq_set_chained_handler(irq, combiner_handle_cascade_irq); 477 irq_set_chained_handler(irq, combiner_handle_cascade_irq);
475} 478}
476 479
477static void __init combiner_init(unsigned int combiner_nr, void __iomem *base, 480static void __init combiner_init_one(unsigned int combiner_nr,
478 unsigned int irq_start) 481 void __iomem *base)
479{ 482{
480 unsigned int i;
481 unsigned int max_nr;
482
483 if (soc_is_exynos5250())
484 max_nr = EXYNOS5_MAX_COMBINER_NR;
485 else
486 max_nr = EXYNOS4_MAX_COMBINER_NR;
487
488 if (combiner_nr >= max_nr)
489 BUG();
490
491 combiner_data[combiner_nr].base = base; 483 combiner_data[combiner_nr].base = base;
492 combiner_data[combiner_nr].irq_offset = irq_start; 484 combiner_data[combiner_nr].irq_offset = irq_find_mapping(
485 combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER);
493 combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3); 486 combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);
494 487
495 /* Disable all interrupts */ 488 /* Disable all interrupts */
496
497 __raw_writel(combiner_data[combiner_nr].irq_mask, 489 __raw_writel(combiner_data[combiner_nr].irq_mask,
498 base + COMBINER_ENABLE_CLEAR); 490 base + COMBINER_ENABLE_CLEAR);
491}
492
493static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq,
494 irq_hw_number_t hw)
495{
496 irq_set_chip_and_handler(irq, &combiner_chip, handle_level_irq);
497 irq_set_chip_data(irq, &combiner_data[hw >> 3]);
498 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
499
500 return 0;
501}
502
503static struct irq_domain_ops combiner_irq_domain_ops = {
504 .map = combiner_irq_domain_map,
505};
506
507void __init combiner_init(void __iomem *combiner_base, struct device_node *np)
508{
509 int i, irq_base;
510 unsigned int max_nr, nr_irq;
511
512 max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR :
513 EXYNOS4_MAX_COMBINER_NR;
514 nr_irq = max_nr * MAX_IRQ_IN_COMBINER;
515
516 irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0);
517 if (IS_ERR_VALUE(irq_base)) {
518 irq_base = COMBINER_IRQ(0, 0);
519 pr_warning("%s: irq desc alloc failed. Continuing with %d as linux irq base\n", __func__, irq_base);
520 }
499 521
500 /* Setup the Linux IRQ subsystem */ 522 combiner_irq_domain = irq_domain_add_legacy(np, nr_irq, irq_base, 0,
523 &combiner_irq_domain_ops, &combiner_data);
524 if (WARN_ON(!combiner_irq_domain)) {
525 pr_warning("%s: irq domain init failed\n", __func__);
526 return;
527 }
501 528
502 for (i = irq_start; i < combiner_data[combiner_nr].irq_offset 529 for (i = 0; i < max_nr; i++) {
503 + MAX_IRQ_IN_COMBINER; i++) { 530 combiner_init_one(i, combiner_base + (i >> 2) * 0x10);
504 irq_set_chip_and_handler(i, &combiner_chip, handle_level_irq); 531 combiner_cascade_irq(i, IRQ_SPI(i));
505 irq_set_chip_data(i, &combiner_data[combiner_nr]);
506 set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
507 } 532 }
508} 533}
509 534
@@ -516,7 +541,6 @@ static const struct of_device_id exynos4_dt_irq_match[] = {
516 541
517void __init exynos4_init_irq(void) 542void __init exynos4_init_irq(void)
518{ 543{
519 int irq;
520 unsigned int gic_bank_offset; 544 unsigned int gic_bank_offset;
521 545
522 gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000; 546 gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000;
@@ -528,12 +552,7 @@ void __init exynos4_init_irq(void)
528 of_irq_init(exynos4_dt_irq_match); 552 of_irq_init(exynos4_dt_irq_match);
529#endif 553#endif
530 554
531 for (irq = 0; irq < EXYNOS4_MAX_COMBINER_NR; irq++) { 555 combiner_init(S5P_VA_COMBINER_BASE, NULL);
532
533 combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
534 COMBINER_IRQ(irq, 0));
535 combiner_cascade_irq(irq, IRQ_SPI(irq));
536 }
537 556
538 /* 557 /*
539 * The parameters of s5p_init_irq() are for VIC init. 558 * The parameters of s5p_init_irq() are for VIC init.
@@ -545,17 +564,10 @@ void __init exynos4_init_irq(void)
545 564
546void __init exynos5_init_irq(void) 565void __init exynos5_init_irq(void)
547{ 566{
548 int irq;
549
550#ifdef CONFIG_OF 567#ifdef CONFIG_OF
551 of_irq_init(exynos4_dt_irq_match); 568 of_irq_init(exynos4_dt_irq_match);
552#endif 569#endif
553 570 combiner_init(S5P_VA_COMBINER_BASE, NULL);
554 for (irq = 0; irq < EXYNOS5_MAX_COMBINER_NR; irq++) {
555 combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
556 COMBINER_IRQ(irq, 0));
557 combiner_cascade_irq(irq, IRQ_SPI(irq));
558 }
559 571
560 /* 572 /*
561 * The parameters of s5p_init_irq() are for VIC init. 573 * The parameters of s5p_init_irq() are for VIC init.