diff options
Diffstat (limited to 'arch/arm/mach-exynos/common.c')
-rw-r--r-- | arch/arm/mach-exynos/common.c | 182 |
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 | ||
405 | static struct irq_domain *combiner_irq_domain; | ||
402 | static struct combiner_chip_data combiner_data[MAX_COMBINER_NR]; | 406 | static struct combiner_chip_data combiner_data[MAX_COMBINER_NR]; |
403 | 407 | ||
404 | static inline void __iomem *combiner_base(struct irq_data *data) | 408 | static 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 | ||
412 | static void combiner_mask_irq(struct irq_data *data) | 416 | static 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 | ||
419 | static void combiner_unmask_irq(struct irq_data *data) | 423 | static 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 | ||
477 | static void __init combiner_init(unsigned int combiner_nr, void __iomem *base, | 481 | static 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 | ||
495 | static 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 | ||
513 | static 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 | |||
523 | static 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 | |||
533 | static 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 | 538 | void __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 |
581 | int __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 | |||
511 | static const struct of_device_id exynos4_dt_irq_match[] = { | 596 | static 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 | ||
517 | void __init exynos4_init_irq(void) | 604 | void __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 | ||
546 | void __init exynos5_init_irq(void) | 628 | void __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 | ||
568 | struct bus_type exynos4_subsys = { | 641 | struct bus_type exynos_subsys = { |
569 | .name = "exynos4-core", | 642 | .name = "exynos-core", |
570 | .dev_name = "exynos4-core", | 643 | .dev_name = "exynos-core", |
571 | }; | ||
572 | |||
573 | struct bus_type exynos5_subsys = { | ||
574 | .name = "exynos5-core", | ||
575 | .dev_name = "exynos5-core", | ||
576 | }; | 644 | }; |
577 | 645 | ||
578 | static struct device exynos4_dev = { | 646 | static struct device exynos4_dev = { |
579 | .bus = &exynos4_subsys, | 647 | .bus = &exynos_subsys, |
580 | }; | ||
581 | |||
582 | static struct device exynos5_dev = { | ||
583 | .bus = &exynos5_subsys, | ||
584 | }; | 648 | }; |
585 | 649 | ||
586 | static int __init exynos_core_init(void) | 650 | static 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 | } |
593 | core_initcall(exynos_core_init); | 654 | core_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 */ |