aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-exynos/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-exynos/common.c')
-rw-r--r--arch/arm/mach-exynos/common.c223
1 files changed, 5 insertions, 218 deletions
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c
index 0c7e3ad7ba93..d63d399c7bae 100644
--- a/arch/arm/mach-exynos/common.c
+++ b/arch/arm/mach-exynos/common.c
@@ -12,6 +12,7 @@
12#include <linux/kernel.h> 12#include <linux/kernel.h>
13#include <linux/interrupt.h> 13#include <linux/interrupt.h>
14#include <linux/irq.h> 14#include <linux/irq.h>
15#include <linux/irqchip.h>
15#include <linux/io.h> 16#include <linux/io.h>
16#include <linux/device.h> 17#include <linux/device.h>
17#include <linux/gpio.h> 18#include <linux/gpio.h>
@@ -22,12 +23,13 @@
22#include <linux/of_irq.h> 23#include <linux/of_irq.h>
23#include <linux/export.h> 24#include <linux/export.h>
24#include <linux/irqdomain.h> 25#include <linux/irqdomain.h>
26#include <linux/irqchip.h>
25#include <linux/of_address.h> 27#include <linux/of_address.h>
28#include <linux/irqchip/arm-gic.h>
26 29
27#include <asm/proc-fns.h> 30#include <asm/proc-fns.h>
28#include <asm/exception.h> 31#include <asm/exception.h>
29#include <asm/hardware/cache-l2x0.h> 32#include <asm/hardware/cache-l2x0.h>
30#include <asm/hardware/gic.h>
31#include <asm/mach/map.h> 33#include <asm/mach/map.h>
32#include <asm/mach/irq.h> 34#include <asm/mach/irq.h>
33#include <asm/cacheflush.h> 35#include <asm/cacheflush.h>
@@ -35,7 +37,6 @@
35#include <mach/regs-irq.h> 37#include <mach/regs-irq.h>
36#include <mach/regs-pmu.h> 38#include <mach/regs-pmu.h>
37#include <mach/regs-gpio.h> 39#include <mach/regs-gpio.h>
38#include <mach/pmu.h>
39 40
40#include <plat/cpu.h> 41#include <plat/cpu.h>
41#include <plat/clock.h> 42#include <plat/clock.h>
@@ -440,220 +441,6 @@ static void __init exynos5_init_clocks(int xtal)
440#endif 441#endif
441} 442}
442 443
443#define COMBINER_ENABLE_SET 0x0
444#define COMBINER_ENABLE_CLEAR 0x4
445#define COMBINER_INT_STATUS 0xC
446
447static DEFINE_SPINLOCK(irq_controller_lock);
448
449struct combiner_chip_data {
450 unsigned int irq_offset;
451 unsigned int irq_mask;
452 void __iomem *base;
453};
454
455static struct irq_domain *combiner_irq_domain;
456static struct combiner_chip_data combiner_data[MAX_COMBINER_NR];
457
458static inline void __iomem *combiner_base(struct irq_data *data)
459{
460 struct combiner_chip_data *combiner_data =
461 irq_data_get_irq_chip_data(data);
462
463 return combiner_data->base;
464}
465
466static void combiner_mask_irq(struct irq_data *data)
467{
468 u32 mask = 1 << (data->hwirq % 32);
469
470 __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR);
471}
472
473static void combiner_unmask_irq(struct irq_data *data)
474{
475 u32 mask = 1 << (data->hwirq % 32);
476
477 __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET);
478}
479
480static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
481{
482 struct combiner_chip_data *chip_data = irq_get_handler_data(irq);
483 struct irq_chip *chip = irq_get_chip(irq);
484 unsigned int cascade_irq, combiner_irq;
485 unsigned long status;
486
487 chained_irq_enter(chip, desc);
488
489 spin_lock(&irq_controller_lock);
490 status = __raw_readl(chip_data->base + COMBINER_INT_STATUS);
491 spin_unlock(&irq_controller_lock);
492 status &= chip_data->irq_mask;
493
494 if (status == 0)
495 goto out;
496
497 combiner_irq = __ffs(status);
498
499 cascade_irq = combiner_irq + (chip_data->irq_offset & ~31);
500 if (unlikely(cascade_irq >= NR_IRQS))
501 do_bad_IRQ(cascade_irq, desc);
502 else
503 generic_handle_irq(cascade_irq);
504
505 out:
506 chained_irq_exit(chip, desc);
507}
508
509static struct irq_chip combiner_chip = {
510 .name = "COMBINER",
511 .irq_mask = combiner_mask_irq,
512 .irq_unmask = combiner_unmask_irq,
513};
514
515static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq)
516{
517 unsigned int max_nr;
518
519 if (soc_is_exynos5250())
520 max_nr = EXYNOS5_MAX_COMBINER_NR;
521 else
522 max_nr = EXYNOS4_MAX_COMBINER_NR;
523
524 if (combiner_nr >= max_nr)
525 BUG();
526 if (irq_set_handler_data(irq, &combiner_data[combiner_nr]) != 0)
527 BUG();
528 irq_set_chained_handler(irq, combiner_handle_cascade_irq);
529}
530
531static void __init combiner_init_one(unsigned int combiner_nr,
532 void __iomem *base)
533{
534 combiner_data[combiner_nr].base = base;
535 combiner_data[combiner_nr].irq_offset = irq_find_mapping(
536 combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER);
537 combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);
538
539 /* Disable all interrupts */
540 __raw_writel(combiner_data[combiner_nr].irq_mask,
541 base + COMBINER_ENABLE_CLEAR);
542}
543
544#ifdef CONFIG_OF
545static int combiner_irq_domain_xlate(struct irq_domain *d,
546 struct device_node *controller,
547 const u32 *intspec, unsigned int intsize,
548 unsigned long *out_hwirq,
549 unsigned int *out_type)
550{
551 if (d->of_node != controller)
552 return -EINVAL;
553
554 if (intsize < 2)
555 return -EINVAL;
556
557 *out_hwirq = intspec[0] * MAX_IRQ_IN_COMBINER + intspec[1];
558 *out_type = 0;
559
560 return 0;
561}
562#else
563static int combiner_irq_domain_xlate(struct irq_domain *d,
564 struct device_node *controller,
565 const u32 *intspec, unsigned int intsize,
566 unsigned long *out_hwirq,
567 unsigned int *out_type)
568{
569 return -EINVAL;
570}
571#endif
572
573static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq,
574 irq_hw_number_t hw)
575{
576 irq_set_chip_and_handler(irq, &combiner_chip, handle_level_irq);
577 irq_set_chip_data(irq, &combiner_data[hw >> 3]);
578 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
579
580 return 0;
581}
582
583static struct irq_domain_ops combiner_irq_domain_ops = {
584 .xlate = combiner_irq_domain_xlate,
585 .map = combiner_irq_domain_map,
586};
587
588static void __init combiner_init(void __iomem *combiner_base,
589 struct device_node *np)
590{
591 int i, irq, irq_base;
592 unsigned int max_nr, nr_irq;
593
594 if (np) {
595 if (of_property_read_u32(np, "samsung,combiner-nr", &max_nr)) {
596 pr_warning("%s: number of combiners not specified, "
597 "setting default as %d.\n",
598 __func__, EXYNOS4_MAX_COMBINER_NR);
599 max_nr = EXYNOS4_MAX_COMBINER_NR;
600 }
601 } else {
602 max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR :
603 EXYNOS4_MAX_COMBINER_NR;
604 }
605 nr_irq = max_nr * MAX_IRQ_IN_COMBINER;
606
607 irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0);
608 if (IS_ERR_VALUE(irq_base)) {
609 irq_base = COMBINER_IRQ(0, 0);
610 pr_warning("%s: irq desc alloc failed. Continuing with %d as linux irq base\n", __func__, irq_base);
611 }
612
613 combiner_irq_domain = irq_domain_add_legacy(np, nr_irq, irq_base, 0,
614 &combiner_irq_domain_ops, &combiner_data);
615 if (WARN_ON(!combiner_irq_domain)) {
616 pr_warning("%s: irq domain init failed\n", __func__);
617 return;
618 }
619
620 for (i = 0; i < max_nr; i++) {
621 combiner_init_one(i, combiner_base + (i >> 2) * 0x10);
622 irq = IRQ_SPI(i);
623#ifdef CONFIG_OF
624 if (np)
625 irq = irq_of_parse_and_map(np, i);
626#endif
627 combiner_cascade_irq(i, irq);
628 }
629}
630
631#ifdef CONFIG_OF
632static int __init combiner_of_init(struct device_node *np,
633 struct device_node *parent)
634{
635 void __iomem *combiner_base;
636
637 combiner_base = of_iomap(np, 0);
638 if (!combiner_base) {
639 pr_err("%s: failed to map combiner registers\n", __func__);
640 return -ENXIO;
641 }
642
643 combiner_init(combiner_base, np);
644
645 return 0;
646}
647
648static const struct of_device_id exynos_dt_irq_match[] = {
649 { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
650 { .compatible = "arm,cortex-a15-gic", .data = gic_of_init, },
651 { .compatible = "samsung,exynos4210-combiner",
652 .data = combiner_of_init, },
653 {},
654};
655#endif
656
657void __init exynos4_init_irq(void) 444void __init exynos4_init_irq(void)
658{ 445{
659 unsigned int gic_bank_offset; 446 unsigned int gic_bank_offset;
@@ -664,7 +451,7 @@ void __init exynos4_init_irq(void)
664 gic_init_bases(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU, gic_bank_offset, NULL); 451 gic_init_bases(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU, gic_bank_offset, NULL);
665#ifdef CONFIG_OF 452#ifdef CONFIG_OF
666 else 453 else
667 of_irq_init(exynos_dt_irq_match); 454 irqchip_init();
668#endif 455#endif
669 456
670 if (!of_have_populated_dt()) 457 if (!of_have_populated_dt())
@@ -681,7 +468,7 @@ void __init exynos4_init_irq(void)
681void __init exynos5_init_irq(void) 468void __init exynos5_init_irq(void)
682{ 469{
683#ifdef CONFIG_OF 470#ifdef CONFIG_OF
684 of_irq_init(exynos_dt_irq_match); 471 irqchip_init();
685#endif 472#endif
686 /* 473 /*
687 * The parameters of s5p_init_irq() are for VIC init. 474 * The parameters of s5p_init_irq() are for VIC init.