diff options
author | Thomas Abraham <thomas.abraham@linaro.org> | 2012-05-15 03:18:35 -0400 |
---|---|---|
committer | Kukjin Kim <kgene.kim@samsung.com> | 2012-05-15 18:03:44 -0400 |
commit | 1e60bc0b5f488c8acde22adeb62118ccfdb49062 (patch) | |
tree | a84b04ae45b848ae00fa8283728f678ce78d07fc /arch/arm | |
parent | 9ee6af9c3fad48cddc0684d0c77d3ea1329e10a1 (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')
-rw-r--r-- | arch/arm/mach-exynos/common.c | 88 |
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 | ||
404 | static struct irq_domain *combiner_irq_domain; | ||
402 | static struct combiner_chip_data combiner_data[MAX_COMBINER_NR]; | 405 | static struct combiner_chip_data combiner_data[MAX_COMBINER_NR]; |
403 | 406 | ||
404 | static inline void __iomem *combiner_base(struct irq_data *data) | 407 | static 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 | ||
412 | static void combiner_mask_irq(struct irq_data *data) | 415 | static 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 | ||
419 | static void combiner_unmask_irq(struct irq_data *data) | 422 | static 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 | ||
477 | static void __init combiner_init(unsigned int combiner_nr, void __iomem *base, | 480 | static 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 | |||
493 | static 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 | |||
503 | static struct irq_domain_ops combiner_irq_domain_ops = { | ||
504 | .map = combiner_irq_domain_map, | ||
505 | }; | ||
506 | |||
507 | void __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 | ||
517 | void __init exynos4_init_irq(void) | 542 | void __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 | ||
546 | void __init exynos5_init_irq(void) | 565 | void __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. |