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.c233
1 files changed, 11 insertions, 222 deletions
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c
index 1a89824a5f78..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>
@@ -299,6 +300,7 @@ void exynos4_restart(char mode, const char *cmd)
299 300
300void exynos5_restart(char mode, const char *cmd) 301void exynos5_restart(char mode, const char *cmd)
301{ 302{
303 struct device_node *np;
302 u32 val; 304 u32 val;
303 void __iomem *addr; 305 void __iomem *addr;
304 306
@@ -306,8 +308,9 @@ void exynos5_restart(char mode, const char *cmd)
306 val = 0x1; 308 val = 0x1;
307 addr = EXYNOS_SWRESET; 309 addr = EXYNOS_SWRESET;
308 } else if (of_machine_is_compatible("samsung,exynos5440")) { 310 } else if (of_machine_is_compatible("samsung,exynos5440")) {
309 val = (0x10 << 20) | (0x1 << 16); 311 np = of_find_compatible_node(NULL, NULL, "samsung,exynos5440-clock");
310 addr = EXYNOS5440_SWRESET; 312 addr = of_iomap(np, 0) + 0xcc;
313 val = (0xfff << 20) | (0x1 << 16);
311 } else { 314 } else {
312 pr_err("%s: cannot support non-DT\n", __func__); 315 pr_err("%s: cannot support non-DT\n", __func__);
313 return; 316 return;
@@ -438,220 +441,6 @@ static void __init exynos5_init_clocks(int xtal)
438#endif 441#endif
439} 442}
440 443
441#define COMBINER_ENABLE_SET 0x0
442#define COMBINER_ENABLE_CLEAR 0x4
443#define COMBINER_INT_STATUS 0xC
444
445static DEFINE_SPINLOCK(irq_controller_lock);
446
447struct combiner_chip_data {
448 unsigned int irq_offset;
449 unsigned int irq_mask;
450 void __iomem *base;
451};
452
453static struct irq_domain *combiner_irq_domain;
454static struct combiner_chip_data combiner_data[MAX_COMBINER_NR];
455
456static inline void __iomem *combiner_base(struct irq_data *data)
457{
458 struct combiner_chip_data *combiner_data =
459 irq_data_get_irq_chip_data(data);
460
461 return combiner_data->base;
462}
463
464static void combiner_mask_irq(struct irq_data *data)
465{
466 u32 mask = 1 << (data->hwirq % 32);
467
468 __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR);
469}
470
471static void combiner_unmask_irq(struct irq_data *data)
472{
473 u32 mask = 1 << (data->hwirq % 32);
474
475 __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET);
476}
477
478static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
479{
480 struct combiner_chip_data *chip_data = irq_get_handler_data(irq);
481 struct irq_chip *chip = irq_get_chip(irq);
482 unsigned int cascade_irq, combiner_irq;
483 unsigned long status;
484
485 chained_irq_enter(chip, desc);
486
487 spin_lock(&irq_controller_lock);
488 status = __raw_readl(chip_data->base + COMBINER_INT_STATUS);
489 spin_unlock(&irq_controller_lock);
490 status &= chip_data->irq_mask;
491
492 if (status == 0)
493 goto out;
494
495 combiner_irq = __ffs(status);
496
497 cascade_irq = combiner_irq + (chip_data->irq_offset & ~31);
498 if (unlikely(cascade_irq >= NR_IRQS))
499 do_bad_IRQ(cascade_irq, desc);
500 else
501 generic_handle_irq(cascade_irq);
502
503 out:
504 chained_irq_exit(chip, desc);
505}
506
507static struct irq_chip combiner_chip = {
508 .name = "COMBINER",
509 .irq_mask = combiner_mask_irq,
510 .irq_unmask = combiner_unmask_irq,
511};
512
513static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq)
514{
515 unsigned int max_nr;
516
517 if (soc_is_exynos5250())
518 max_nr = EXYNOS5_MAX_COMBINER_NR;
519 else
520 max_nr = EXYNOS4_MAX_COMBINER_NR;
521
522 if (combiner_nr >= max_nr)
523 BUG();
524 if (irq_set_handler_data(irq, &combiner_data[combiner_nr]) != 0)
525 BUG();
526 irq_set_chained_handler(irq, combiner_handle_cascade_irq);
527}
528
529static void __init combiner_init_one(unsigned int combiner_nr,
530 void __iomem *base)
531{
532 combiner_data[combiner_nr].base = base;
533 combiner_data[combiner_nr].irq_offset = irq_find_mapping(
534 combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER);
535 combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);
536
537 /* Disable all interrupts */
538 __raw_writel(combiner_data[combiner_nr].irq_mask,
539 base + COMBINER_ENABLE_CLEAR);
540}
541
542#ifdef CONFIG_OF
543static int combiner_irq_domain_xlate(struct irq_domain *d,
544 struct device_node *controller,
545 const u32 *intspec, unsigned int intsize,
546 unsigned long *out_hwirq,
547 unsigned int *out_type)
548{
549 if (d->of_node != controller)
550 return -EINVAL;
551
552 if (intsize < 2)
553 return -EINVAL;
554
555 *out_hwirq = intspec[0] * MAX_IRQ_IN_COMBINER + intspec[1];
556 *out_type = 0;
557
558 return 0;
559}
560#else
561static int combiner_irq_domain_xlate(struct irq_domain *d,
562 struct device_node *controller,
563 const u32 *intspec, unsigned int intsize,
564 unsigned long *out_hwirq,
565 unsigned int *out_type)
566{
567 return -EINVAL;
568}
569#endif
570
571static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq,
572 irq_hw_number_t hw)
573{
574 irq_set_chip_and_handler(irq, &combiner_chip, handle_level_irq);
575 irq_set_chip_data(irq, &combiner_data[hw >> 3]);
576 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
577
578 return 0;
579}
580
581static struct irq_domain_ops combiner_irq_domain_ops = {
582 .xlate = combiner_irq_domain_xlate,
583 .map = combiner_irq_domain_map,
584};
585
586static void __init combiner_init(void __iomem *combiner_base,
587 struct device_node *np)
588{
589 int i, irq, irq_base;
590 unsigned int max_nr, nr_irq;
591
592 if (np) {
593 if (of_property_read_u32(np, "samsung,combiner-nr", &max_nr)) {
594 pr_warning("%s: number of combiners not specified, "
595 "setting default as %d.\n",
596 __func__, EXYNOS4_MAX_COMBINER_NR);
597 max_nr = EXYNOS4_MAX_COMBINER_NR;
598 }
599 } else {
600 max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR :
601 EXYNOS4_MAX_COMBINER_NR;
602 }
603 nr_irq = max_nr * MAX_IRQ_IN_COMBINER;
604
605 irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0);
606 if (IS_ERR_VALUE(irq_base)) {
607 irq_base = COMBINER_IRQ(0, 0);
608 pr_warning("%s: irq desc alloc failed. Continuing with %d as linux irq base\n", __func__, irq_base);
609 }
610
611 combiner_irq_domain = irq_domain_add_legacy(np, nr_irq, irq_base, 0,
612 &combiner_irq_domain_ops, &combiner_data);
613 if (WARN_ON(!combiner_irq_domain)) {
614 pr_warning("%s: irq domain init failed\n", __func__);
615 return;
616 }
617
618 for (i = 0; i < max_nr; i++) {
619 combiner_init_one(i, combiner_base + (i >> 2) * 0x10);
620 irq = IRQ_SPI(i);
621#ifdef CONFIG_OF
622 if (np)
623 irq = irq_of_parse_and_map(np, i);
624#endif
625 combiner_cascade_irq(i, irq);
626 }
627}
628
629#ifdef CONFIG_OF
630static int __init combiner_of_init(struct device_node *np,
631 struct device_node *parent)
632{
633 void __iomem *combiner_base;
634
635 combiner_base = of_iomap(np, 0);
636 if (!combiner_base) {
637 pr_err("%s: failed to map combiner registers\n", __func__);
638 return -ENXIO;
639 }
640
641 combiner_init(combiner_base, np);
642
643 return 0;
644}
645
646static const struct of_device_id exynos_dt_irq_match[] = {
647 { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
648 { .compatible = "arm,cortex-a15-gic", .data = gic_of_init, },
649 { .compatible = "samsung,exynos4210-combiner",
650 .data = combiner_of_init, },
651 {},
652};
653#endif
654
655void __init exynos4_init_irq(void) 444void __init exynos4_init_irq(void)
656{ 445{
657 unsigned int gic_bank_offset; 446 unsigned int gic_bank_offset;
@@ -662,7 +451,7 @@ void __init exynos4_init_irq(void)
662 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);
663#ifdef CONFIG_OF 452#ifdef CONFIG_OF
664 else 453 else
665 of_irq_init(exynos_dt_irq_match); 454 irqchip_init();
666#endif 455#endif
667 456
668 if (!of_have_populated_dt()) 457 if (!of_have_populated_dt())
@@ -679,7 +468,7 @@ void __init exynos4_init_irq(void)
679void __init exynos5_init_irq(void) 468void __init exynos5_init_irq(void)
680{ 469{
681#ifdef CONFIG_OF 470#ifdef CONFIG_OF
682 of_irq_init(exynos_dt_irq_match); 471 irqchip_init();
683#endif 472#endif
684 /* 473 /*
685 * The parameters of s5p_init_irq() are for VIC init. 474 * The parameters of s5p_init_irq() are for VIC init.
@@ -1031,8 +820,8 @@ static int __init exynos_init_irq_eint(void)
1031 * interrupt support code here can be completely removed. 820 * interrupt support code here can be completely removed.
1032 */ 821 */
1033 static const struct of_device_id exynos_pinctrl_ids[] = { 822 static const struct of_device_id exynos_pinctrl_ids[] = {
1034 { .compatible = "samsung,pinctrl-exynos4210", }, 823 { .compatible = "samsung,exynos4210-pinctrl", },
1035 { .compatible = "samsung,pinctrl-exynos4x12", }, 824 { .compatible = "samsung,exynos4x12-pinctrl", },
1036 }; 825 };
1037 struct device_node *pctrl_np, *wkup_np; 826 struct device_node *pctrl_np, *wkup_np;
1038 const char *wkup_compat = "samsung,exynos4210-wakeup-eint"; 827 const char *wkup_compat = "samsung,exynos4210-wakeup-eint";