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.c182
1 files changed, 120 insertions, 62 deletions
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c
index 5ccd6e80a607..49134711f4c6 100644
--- a/arch/arm/mach-exynos/common.c
+++ b/arch/arm/mach-exynos/common.c
@@ -19,6 +19,9 @@
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>
24#include <linux/of_address.h>
22 25
23#include <asm/proc-fns.h> 26#include <asm/proc-fns.h>
24#include <asm/exception.h> 27#include <asm/exception.h>
@@ -265,12 +268,12 @@ static struct map_desc exynos5_iodesc[] __initdata = {
265 }, { 268 }, {
266 .virtual = (unsigned long)S5P_VA_GIC_CPU, 269 .virtual = (unsigned long)S5P_VA_GIC_CPU,
267 .pfn = __phys_to_pfn(EXYNOS5_PA_GIC_CPU), 270 .pfn = __phys_to_pfn(EXYNOS5_PA_GIC_CPU),
268 .length = SZ_64K, 271 .length = SZ_8K,
269 .type = MT_DEVICE, 272 .type = MT_DEVICE,
270 }, { 273 }, {
271 .virtual = (unsigned long)S5P_VA_GIC_DIST, 274 .virtual = (unsigned long)S5P_VA_GIC_DIST,
272 .pfn = __phys_to_pfn(EXYNOS5_PA_GIC_DIST), 275 .pfn = __phys_to_pfn(EXYNOS5_PA_GIC_DIST),
273 .length = SZ_64K, 276 .length = SZ_4K,
274 .type = MT_DEVICE, 277 .type = MT_DEVICE,
275 }, 278 },
276}; 279};
@@ -399,6 +402,7 @@ struct combiner_chip_data {
399 void __iomem *base; 402 void __iomem *base;
400}; 403};
401 404
405static struct irq_domain *combiner_irq_domain;
402static struct combiner_chip_data combiner_data[MAX_COMBINER_NR]; 406static struct combiner_chip_data combiner_data[MAX_COMBINER_NR];
403 407
404static inline void __iomem *combiner_base(struct irq_data *data) 408static inline void __iomem *combiner_base(struct irq_data *data)
@@ -411,14 +415,14 @@ static inline void __iomem *combiner_base(struct irq_data *data)
411 415
412static void combiner_mask_irq(struct irq_data *data) 416static void combiner_mask_irq(struct irq_data *data)
413{ 417{
414 u32 mask = 1 << (data->irq % 32); 418 u32 mask = 1 << (data->hwirq % 32);
415 419
416 __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR); 420 __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR);
417} 421}
418 422
419static void combiner_unmask_irq(struct irq_data *data) 423static void combiner_unmask_irq(struct irq_data *data)
420{ 424{
421 u32 mask = 1 << (data->irq % 32); 425 u32 mask = 1 << (data->hwirq % 32);
422 426
423 __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET); 427 __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET);
424} 428}
@@ -474,49 +478,131 @@ static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int i
474 irq_set_chained_handler(irq, combiner_handle_cascade_irq); 478 irq_set_chained_handler(irq, combiner_handle_cascade_irq);
475} 479}
476 480
477static void __init combiner_init(unsigned int combiner_nr, void __iomem *base, 481static void __init combiner_init_one(unsigned int combiner_nr,
478 unsigned int irq_start) 482 void __iomem *base)
479{ 483{
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; 484 combiner_data[combiner_nr].base = base;
492 combiner_data[combiner_nr].irq_offset = irq_start; 485 combiner_data[combiner_nr].irq_offset = irq_find_mapping(
486 combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER);
493 combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3); 487 combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);
494 488
495 /* Disable all interrupts */ 489 /* Disable all interrupts */
496
497 __raw_writel(combiner_data[combiner_nr].irq_mask, 490 __raw_writel(combiner_data[combiner_nr].irq_mask,
498 base + COMBINER_ENABLE_CLEAR); 491 base + COMBINER_ENABLE_CLEAR);
492}
493
494#ifdef CONFIG_OF
495static int combiner_irq_domain_xlate(struct irq_domain *d,
496 struct device_node *controller,
497 const u32 *intspec, unsigned int intsize,
498 unsigned long *out_hwirq,
499 unsigned int *out_type)
500{
501 if (d->of_node != controller)
502 return -EINVAL;
503
504 if (intsize < 2)
505 return -EINVAL;
506
507 *out_hwirq = intspec[0] * MAX_IRQ_IN_COMBINER + intspec[1];
508 *out_type = 0;
509
510 return 0;
511}
512#else
513static int combiner_irq_domain_xlate(struct irq_domain *d,
514 struct device_node *controller,
515 const u32 *intspec, unsigned int intsize,
516 unsigned long *out_hwirq,
517 unsigned int *out_type)
518{
519 return -EINVAL;
520}
521#endif
522
523static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq,
524 irq_hw_number_t hw)
525{
526 irq_set_chip_and_handler(irq, &combiner_chip, handle_level_irq);
527 irq_set_chip_data(irq, &combiner_data[hw >> 3]);
528 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
499 529
500 /* Setup the Linux IRQ subsystem */ 530 return 0;
531}
532
533static struct irq_domain_ops combiner_irq_domain_ops = {
534 .xlate = combiner_irq_domain_xlate,
535 .map = combiner_irq_domain_map,
536};
501 537
502 for (i = irq_start; i < combiner_data[combiner_nr].irq_offset 538void __init combiner_init(void __iomem *combiner_base, struct device_node *np)
503 + MAX_IRQ_IN_COMBINER; i++) { 539{
504 irq_set_chip_and_handler(i, &combiner_chip, handle_level_irq); 540 int i, irq, irq_base;
505 irq_set_chip_data(i, &combiner_data[combiner_nr]); 541 unsigned int max_nr, nr_irq;
506 set_irq_flags(i, IRQF_VALID | IRQF_PROBE); 542
543 if (np) {
544 if (of_property_read_u32(np, "samsung,combiner-nr", &max_nr)) {
545 pr_warning("%s: number of combiners not specified, "
546 "setting default as %d.\n",
547 __func__, EXYNOS4_MAX_COMBINER_NR);
548 max_nr = EXYNOS4_MAX_COMBINER_NR;
549 }
550 } else {
551 max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR :
552 EXYNOS4_MAX_COMBINER_NR;
553 }
554 nr_irq = max_nr * MAX_IRQ_IN_COMBINER;
555
556 irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0);
557 if (IS_ERR_VALUE(irq_base)) {
558 irq_base = COMBINER_IRQ(0, 0);
559 pr_warning("%s: irq desc alloc failed. Continuing with %d as linux irq base\n", __func__, irq_base);
560 }
561
562 combiner_irq_domain = irq_domain_add_legacy(np, nr_irq, irq_base, 0,
563 &combiner_irq_domain_ops, &combiner_data);
564 if (WARN_ON(!combiner_irq_domain)) {
565 pr_warning("%s: irq domain init failed\n", __func__);
566 return;
567 }
568
569 for (i = 0; i < max_nr; i++) {
570 combiner_init_one(i, combiner_base + (i >> 2) * 0x10);
571 irq = IRQ_SPI(i);
572#ifdef CONFIG_OF
573 if (np)
574 irq = irq_of_parse_and_map(np, i);
575#endif
576 combiner_cascade_irq(i, irq);
507 } 577 }
508} 578}
509 579
510#ifdef CONFIG_OF 580#ifdef CONFIG_OF
581int __init combiner_of_init(struct device_node *np, struct device_node *parent)
582{
583 void __iomem *combiner_base;
584
585 combiner_base = of_iomap(np, 0);
586 if (!combiner_base) {
587 pr_err("%s: failed to map combiner registers\n", __func__);
588 return -ENXIO;
589 }
590
591 combiner_init(combiner_base, np);
592
593 return 0;
594}
595
511static const struct of_device_id exynos4_dt_irq_match[] = { 596static const struct of_device_id exynos4_dt_irq_match[] = {
512 { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, 597 { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
598 { .compatible = "samsung,exynos4210-combiner",
599 .data = combiner_of_init, },
513 {}, 600 {},
514}; 601};
515#endif 602#endif
516 603
517void __init exynos4_init_irq(void) 604void __init exynos4_init_irq(void)
518{ 605{
519 int irq;
520 unsigned int gic_bank_offset; 606 unsigned int gic_bank_offset;
521 607
522 gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000; 608 gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000;
@@ -528,12 +614,8 @@ void __init exynos4_init_irq(void)
528 of_irq_init(exynos4_dt_irq_match); 614 of_irq_init(exynos4_dt_irq_match);
529#endif 615#endif
530 616
531 for (irq = 0; irq < EXYNOS4_MAX_COMBINER_NR; irq++) { 617 if (!of_have_populated_dt())
532 618 combiner_init(S5P_VA_COMBINER_BASE, NULL);
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 619
538 /* 620 /*
539 * The parameters of s5p_init_irq() are for VIC init. 621 * The parameters of s5p_init_irq() are for VIC init.
@@ -545,18 +627,9 @@ void __init exynos4_init_irq(void)
545 627
546void __init exynos5_init_irq(void) 628void __init exynos5_init_irq(void)
547{ 629{
548 int irq;
549
550#ifdef CONFIG_OF 630#ifdef CONFIG_OF
551 of_irq_init(exynos4_dt_irq_match); 631 of_irq_init(exynos4_dt_irq_match);
552#endif 632#endif
553
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
560 /* 633 /*
561 * The parameters of s5p_init_irq() are for VIC init. 634 * The parameters of s5p_init_irq() are for VIC init.
562 * Theses parameters should be NULL and 0 because EXYNOS4 635 * Theses parameters should be NULL and 0 because EXYNOS4
@@ -565,30 +638,18 @@ void __init exynos5_init_irq(void)
565 s5p_init_irq(NULL, 0); 638 s5p_init_irq(NULL, 0);
566} 639}
567 640
568struct bus_type exynos4_subsys = { 641struct bus_type exynos_subsys = {
569 .name = "exynos4-core", 642 .name = "exynos-core",
570 .dev_name = "exynos4-core", 643 .dev_name = "exynos-core",
571};
572
573struct bus_type exynos5_subsys = {
574 .name = "exynos5-core",
575 .dev_name = "exynos5-core",
576}; 644};
577 645
578static struct device exynos4_dev = { 646static struct device exynos4_dev = {
579 .bus = &exynos4_subsys, 647 .bus = &exynos_subsys,
580};
581
582static struct device exynos5_dev = {
583 .bus = &exynos5_subsys,
584}; 648};
585 649
586static int __init exynos_core_init(void) 650static int __init exynos_core_init(void)
587{ 651{
588 if (soc_is_exynos5250()) 652 return subsys_system_register(&exynos_subsys, NULL);
589 return subsys_system_register(&exynos5_subsys, NULL);
590 else
591 return subsys_system_register(&exynos4_subsys, NULL);
592} 653}
593core_initcall(exynos_core_init); 654core_initcall(exynos_core_init);
594 655
@@ -675,10 +736,7 @@ static int __init exynos_init(void)
675{ 736{
676 printk(KERN_INFO "EXYNOS: Initializing architecture\n"); 737 printk(KERN_INFO "EXYNOS: Initializing architecture\n");
677 738
678 if (soc_is_exynos5250()) 739 return device_register(&exynos4_dev);
679 return device_register(&exynos5_dev);
680 else
681 return device_register(&exynos4_dev);
682} 740}
683 741
684/* uart registration process */ 742/* uart registration process */