diff options
Diffstat (limited to 'arch/arm/mach-exynos/common.c')
-rw-r--r-- | arch/arm/mach-exynos/common.c | 187 |
1 files changed, 125 insertions, 62 deletions
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index 5ccd6e80a607..742edd3bbec3 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 | }; |
@@ -285,6 +288,11 @@ void exynos5_restart(char mode, const char *cmd) | |||
285 | __raw_writel(0x1, EXYNOS_SWRESET); | 288 | __raw_writel(0x1, EXYNOS_SWRESET); |
286 | } | 289 | } |
287 | 290 | ||
291 | void __init exynos_init_late(void) | ||
292 | { | ||
293 | exynos_pm_late_initcall(); | ||
294 | } | ||
295 | |||
288 | /* | 296 | /* |
289 | * exynos_map_io | 297 | * exynos_map_io |
290 | * | 298 | * |
@@ -399,6 +407,7 @@ struct combiner_chip_data { | |||
399 | void __iomem *base; | 407 | void __iomem *base; |
400 | }; | 408 | }; |
401 | 409 | ||
410 | static struct irq_domain *combiner_irq_domain; | ||
402 | static struct combiner_chip_data combiner_data[MAX_COMBINER_NR]; | 411 | static struct combiner_chip_data combiner_data[MAX_COMBINER_NR]; |
403 | 412 | ||
404 | static inline void __iomem *combiner_base(struct irq_data *data) | 413 | static inline void __iomem *combiner_base(struct irq_data *data) |
@@ -411,14 +420,14 @@ static inline void __iomem *combiner_base(struct irq_data *data) | |||
411 | 420 | ||
412 | static void combiner_mask_irq(struct irq_data *data) | 421 | static void combiner_mask_irq(struct irq_data *data) |
413 | { | 422 | { |
414 | u32 mask = 1 << (data->irq % 32); | 423 | u32 mask = 1 << (data->hwirq % 32); |
415 | 424 | ||
416 | __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR); | 425 | __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR); |
417 | } | 426 | } |
418 | 427 | ||
419 | static void combiner_unmask_irq(struct irq_data *data) | 428 | static void combiner_unmask_irq(struct irq_data *data) |
420 | { | 429 | { |
421 | u32 mask = 1 << (data->irq % 32); | 430 | u32 mask = 1 << (data->hwirq % 32); |
422 | 431 | ||
423 | __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET); | 432 | __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET); |
424 | } | 433 | } |
@@ -474,49 +483,131 @@ static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int i | |||
474 | irq_set_chained_handler(irq, combiner_handle_cascade_irq); | 483 | irq_set_chained_handler(irq, combiner_handle_cascade_irq); |
475 | } | 484 | } |
476 | 485 | ||
477 | static void __init combiner_init(unsigned int combiner_nr, void __iomem *base, | 486 | static void __init combiner_init_one(unsigned int combiner_nr, |
478 | unsigned int irq_start) | 487 | void __iomem *base) |
479 | { | 488 | { |
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; | 489 | combiner_data[combiner_nr].base = base; |
492 | combiner_data[combiner_nr].irq_offset = irq_start; | 490 | combiner_data[combiner_nr].irq_offset = irq_find_mapping( |
491 | combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER); | ||
493 | combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3); | 492 | combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3); |
494 | 493 | ||
495 | /* Disable all interrupts */ | 494 | /* Disable all interrupts */ |
496 | |||
497 | __raw_writel(combiner_data[combiner_nr].irq_mask, | 495 | __raw_writel(combiner_data[combiner_nr].irq_mask, |
498 | base + COMBINER_ENABLE_CLEAR); | 496 | base + COMBINER_ENABLE_CLEAR); |
497 | } | ||
498 | |||
499 | #ifdef CONFIG_OF | ||
500 | static int combiner_irq_domain_xlate(struct irq_domain *d, | ||
501 | struct device_node *controller, | ||
502 | const u32 *intspec, unsigned int intsize, | ||
503 | unsigned long *out_hwirq, | ||
504 | unsigned int *out_type) | ||
505 | { | ||
506 | if (d->of_node != controller) | ||
507 | return -EINVAL; | ||
508 | |||
509 | if (intsize < 2) | ||
510 | return -EINVAL; | ||
511 | |||
512 | *out_hwirq = intspec[0] * MAX_IRQ_IN_COMBINER + intspec[1]; | ||
513 | *out_type = 0; | ||
514 | |||
515 | return 0; | ||
516 | } | ||
517 | #else | ||
518 | static int combiner_irq_domain_xlate(struct irq_domain *d, | ||
519 | struct device_node *controller, | ||
520 | const u32 *intspec, unsigned int intsize, | ||
521 | unsigned long *out_hwirq, | ||
522 | unsigned int *out_type) | ||
523 | { | ||
524 | return -EINVAL; | ||
525 | } | ||
526 | #endif | ||
527 | |||
528 | static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq, | ||
529 | irq_hw_number_t hw) | ||
530 | { | ||
531 | irq_set_chip_and_handler(irq, &combiner_chip, handle_level_irq); | ||
532 | irq_set_chip_data(irq, &combiner_data[hw >> 3]); | ||
533 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
534 | |||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | static struct irq_domain_ops combiner_irq_domain_ops = { | ||
539 | .xlate = combiner_irq_domain_xlate, | ||
540 | .map = combiner_irq_domain_map, | ||
541 | }; | ||
542 | |||
543 | void __init combiner_init(void __iomem *combiner_base, struct device_node *np) | ||
544 | { | ||
545 | int i, irq, irq_base; | ||
546 | unsigned int max_nr, nr_irq; | ||
547 | |||
548 | if (np) { | ||
549 | if (of_property_read_u32(np, "samsung,combiner-nr", &max_nr)) { | ||
550 | pr_warning("%s: number of combiners not specified, " | ||
551 | "setting default as %d.\n", | ||
552 | __func__, EXYNOS4_MAX_COMBINER_NR); | ||
553 | max_nr = EXYNOS4_MAX_COMBINER_NR; | ||
554 | } | ||
555 | } else { | ||
556 | max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR : | ||
557 | EXYNOS4_MAX_COMBINER_NR; | ||
558 | } | ||
559 | nr_irq = max_nr * MAX_IRQ_IN_COMBINER; | ||
499 | 560 | ||
500 | /* Setup the Linux IRQ subsystem */ | 561 | irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0); |
562 | if (IS_ERR_VALUE(irq_base)) { | ||
563 | irq_base = COMBINER_IRQ(0, 0); | ||
564 | pr_warning("%s: irq desc alloc failed. Continuing with %d as linux irq base\n", __func__, irq_base); | ||
565 | } | ||
501 | 566 | ||
502 | for (i = irq_start; i < combiner_data[combiner_nr].irq_offset | 567 | combiner_irq_domain = irq_domain_add_legacy(np, nr_irq, irq_base, 0, |
503 | + MAX_IRQ_IN_COMBINER; i++) { | 568 | &combiner_irq_domain_ops, &combiner_data); |
504 | irq_set_chip_and_handler(i, &combiner_chip, handle_level_irq); | 569 | if (WARN_ON(!combiner_irq_domain)) { |
505 | irq_set_chip_data(i, &combiner_data[combiner_nr]); | 570 | pr_warning("%s: irq domain init failed\n", __func__); |
506 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); | 571 | return; |
572 | } | ||
573 | |||
574 | for (i = 0; i < max_nr; i++) { | ||
575 | combiner_init_one(i, combiner_base + (i >> 2) * 0x10); | ||
576 | irq = IRQ_SPI(i); | ||
577 | #ifdef CONFIG_OF | ||
578 | if (np) | ||
579 | irq = irq_of_parse_and_map(np, i); | ||
580 | #endif | ||
581 | combiner_cascade_irq(i, irq); | ||
507 | } | 582 | } |
508 | } | 583 | } |
509 | 584 | ||
510 | #ifdef CONFIG_OF | 585 | #ifdef CONFIG_OF |
586 | int __init combiner_of_init(struct device_node *np, struct device_node *parent) | ||
587 | { | ||
588 | void __iomem *combiner_base; | ||
589 | |||
590 | combiner_base = of_iomap(np, 0); | ||
591 | if (!combiner_base) { | ||
592 | pr_err("%s: failed to map combiner registers\n", __func__); | ||
593 | return -ENXIO; | ||
594 | } | ||
595 | |||
596 | combiner_init(combiner_base, np); | ||
597 | |||
598 | return 0; | ||
599 | } | ||
600 | |||
511 | static const struct of_device_id exynos4_dt_irq_match[] = { | 601 | static const struct of_device_id exynos4_dt_irq_match[] = { |
512 | { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, | 602 | { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, |
603 | { .compatible = "samsung,exynos4210-combiner", | ||
604 | .data = combiner_of_init, }, | ||
513 | {}, | 605 | {}, |
514 | }; | 606 | }; |
515 | #endif | 607 | #endif |
516 | 608 | ||
517 | void __init exynos4_init_irq(void) | 609 | void __init exynos4_init_irq(void) |
518 | { | 610 | { |
519 | int irq; | ||
520 | unsigned int gic_bank_offset; | 611 | unsigned int gic_bank_offset; |
521 | 612 | ||
522 | gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000; | 613 | gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000; |
@@ -528,12 +619,8 @@ void __init exynos4_init_irq(void) | |||
528 | of_irq_init(exynos4_dt_irq_match); | 619 | of_irq_init(exynos4_dt_irq_match); |
529 | #endif | 620 | #endif |
530 | 621 | ||
531 | for (irq = 0; irq < EXYNOS4_MAX_COMBINER_NR; irq++) { | 622 | if (!of_have_populated_dt()) |
532 | 623 | 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 | 624 | ||
538 | /* | 625 | /* |
539 | * The parameters of s5p_init_irq() are for VIC init. | 626 | * The parameters of s5p_init_irq() are for VIC init. |
@@ -545,18 +632,9 @@ void __init exynos4_init_irq(void) | |||
545 | 632 | ||
546 | void __init exynos5_init_irq(void) | 633 | void __init exynos5_init_irq(void) |
547 | { | 634 | { |
548 | int irq; | ||
549 | |||
550 | #ifdef CONFIG_OF | 635 | #ifdef CONFIG_OF |
551 | of_irq_init(exynos4_dt_irq_match); | 636 | of_irq_init(exynos4_dt_irq_match); |
552 | #endif | 637 | #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 | /* | 638 | /* |
561 | * The parameters of s5p_init_irq() are for VIC init. | 639 | * The parameters of s5p_init_irq() are for VIC init. |
562 | * Theses parameters should be NULL and 0 because EXYNOS4 | 640 | * Theses parameters should be NULL and 0 because EXYNOS4 |
@@ -565,30 +643,18 @@ void __init exynos5_init_irq(void) | |||
565 | s5p_init_irq(NULL, 0); | 643 | s5p_init_irq(NULL, 0); |
566 | } | 644 | } |
567 | 645 | ||
568 | struct bus_type exynos4_subsys = { | 646 | struct bus_type exynos_subsys = { |
569 | .name = "exynos4-core", | 647 | .name = "exynos-core", |
570 | .dev_name = "exynos4-core", | 648 | .dev_name = "exynos-core", |
571 | }; | ||
572 | |||
573 | struct bus_type exynos5_subsys = { | ||
574 | .name = "exynos5-core", | ||
575 | .dev_name = "exynos5-core", | ||
576 | }; | 649 | }; |
577 | 650 | ||
578 | static struct device exynos4_dev = { | 651 | static struct device exynos4_dev = { |
579 | .bus = &exynos4_subsys, | 652 | .bus = &exynos_subsys, |
580 | }; | ||
581 | |||
582 | static struct device exynos5_dev = { | ||
583 | .bus = &exynos5_subsys, | ||
584 | }; | 653 | }; |
585 | 654 | ||
586 | static int __init exynos_core_init(void) | 655 | static int __init exynos_core_init(void) |
587 | { | 656 | { |
588 | if (soc_is_exynos5250()) | 657 | 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 | } | 658 | } |
593 | core_initcall(exynos_core_init); | 659 | core_initcall(exynos_core_init); |
594 | 660 | ||
@@ -675,10 +741,7 @@ static int __init exynos_init(void) | |||
675 | { | 741 | { |
676 | printk(KERN_INFO "EXYNOS: Initializing architecture\n"); | 742 | printk(KERN_INFO "EXYNOS: Initializing architecture\n"); |
677 | 743 | ||
678 | if (soc_is_exynos5250()) | 744 | return device_register(&exynos4_dev); |
679 | return device_register(&exynos5_dev); | ||
680 | else | ||
681 | return device_register(&exynos4_dev); | ||
682 | } | 745 | } |
683 | 746 | ||
684 | /* uart registration process */ | 747 | /* uart registration process */ |