diff options
| author | Hanjun Guo <hanjun.guo@linaro.org> | 2015-03-24 10:02:50 -0400 |
|---|---|---|
| committer | Will Deacon <will.deacon@arm.com> | 2015-03-26 11:13:07 -0400 |
| commit | b09ca1ecf6d499d5a33f978c905d2fbcc79b55d9 (patch) | |
| tree | a9b807414433367bcf647a38d7d3e5623e236ace /drivers/clocksource | |
| parent | d60fc3892c4de4a25658786f941690462c5a5bab (diff) | |
clocksource / arch_timer: Parse GTDT to initialize arch timer
Using the information presented by GTDT (Generic Timer Description Table)
to initialize the arch timer (not memory-mapped).
CC: Daniel Lezcano <daniel.lezcano@linaro.org>
CC: Thomas Gleixner <tglx@linutronix.de>
Originally-by: Amit Daniel Kachhap <amit.daniel@samsung.com>
Tested-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
Tested-by: Yijing Wang <wangyijing@huawei.com>
Tested-by: Mark Langsdorf <mlangsdo@redhat.com>
Tested-by: Jon Masters <jcm@redhat.com>
Tested-by: Timur Tabi <timur@codeaurora.org>
Tested-by: Robert Richter <rrichter@cavium.com>
Acked-by: Robert Richter <rrichter@cavium.com>
Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Reviewed-by: Grant Likely <grant.likely@linaro.org>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'drivers/clocksource')
| -rw-r--r-- | drivers/clocksource/arm_arch_timer.c | 132 |
1 files changed, 105 insertions, 27 deletions
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index a3025e7ae35f..ea62fc79e1e8 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include <linux/io.h> | 22 | #include <linux/io.h> |
| 23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
| 24 | #include <linux/sched_clock.h> | 24 | #include <linux/sched_clock.h> |
| 25 | #include <linux/acpi.h> | ||
| 25 | 26 | ||
| 26 | #include <asm/arch_timer.h> | 27 | #include <asm/arch_timer.h> |
| 27 | #include <asm/virt.h> | 28 | #include <asm/virt.h> |
| @@ -371,8 +372,12 @@ arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np) | |||
| 371 | if (arch_timer_rate) | 372 | if (arch_timer_rate) |
| 372 | return; | 373 | return; |
| 373 | 374 | ||
| 374 | /* Try to determine the frequency from the device tree or CNTFRQ */ | 375 | /* |
| 375 | if (of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) { | 376 | * Try to determine the frequency from the device tree or CNTFRQ, |
| 377 | * if ACPI is enabled, get the frequency from CNTFRQ ONLY. | ||
| 378 | */ | ||
| 379 | if (!acpi_disabled || | ||
| 380 | of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) { | ||
| 376 | if (cntbase) | 381 | if (cntbase) |
| 377 | arch_timer_rate = readl_relaxed(cntbase + CNTFRQ); | 382 | arch_timer_rate = readl_relaxed(cntbase + CNTFRQ); |
| 378 | else | 383 | else |
| @@ -691,28 +696,8 @@ static void __init arch_timer_common_init(void) | |||
| 691 | arch_timer_arch_init(); | 696 | arch_timer_arch_init(); |
| 692 | } | 697 | } |
| 693 | 698 | ||
| 694 | static void __init arch_timer_init(struct device_node *np) | 699 | static void __init arch_timer_init(void) |
| 695 | { | 700 | { |
| 696 | int i; | ||
| 697 | |||
| 698 | if (arch_timers_present & ARCH_CP15_TIMER) { | ||
| 699 | pr_warn("arch_timer: multiple nodes in dt, skipping\n"); | ||
| 700 | return; | ||
| 701 | } | ||
| 702 | |||
| 703 | arch_timers_present |= ARCH_CP15_TIMER; | ||
| 704 | for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++) | ||
| 705 | arch_timer_ppi[i] = irq_of_parse_and_map(np, i); | ||
| 706 | arch_timer_detect_rate(NULL, np); | ||
| 707 | |||
| 708 | /* | ||
| 709 | * If we cannot rely on firmware initializing the timer registers then | ||
| 710 | * we should use the physical timers instead. | ||
| 711 | */ | ||
| 712 | if (IS_ENABLED(CONFIG_ARM) && | ||
| 713 | of_property_read_bool(np, "arm,cpu-registers-not-fw-configured")) | ||
| 714 | arch_timer_use_virtual = false; | ||
| 715 | |||
| 716 | /* | 701 | /* |
| 717 | * If HYP mode is available, we know that the physical timer | 702 | * If HYP mode is available, we know that the physical timer |
| 718 | * has been configured to be accessible from PL1. Use it, so | 703 | * has been configured to be accessible from PL1. Use it, so |
| @@ -731,13 +716,39 @@ static void __init arch_timer_init(struct device_node *np) | |||
| 731 | } | 716 | } |
| 732 | } | 717 | } |
| 733 | 718 | ||
| 734 | arch_timer_c3stop = !of_property_read_bool(np, "always-on"); | ||
| 735 | |||
| 736 | arch_timer_register(); | 719 | arch_timer_register(); |
| 737 | arch_timer_common_init(); | 720 | arch_timer_common_init(); |
| 738 | } | 721 | } |
| 739 | CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_init); | 722 | |
| 740 | CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_init); | 723 | static void __init arch_timer_of_init(struct device_node *np) |
| 724 | { | ||
| 725 | int i; | ||
| 726 | |||
| 727 | if (arch_timers_present & ARCH_CP15_TIMER) { | ||
| 728 | pr_warn("arch_timer: multiple nodes in dt, skipping\n"); | ||
| 729 | return; | ||
| 730 | } | ||
| 731 | |||
| 732 | arch_timers_present |= ARCH_CP15_TIMER; | ||
| 733 | for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++) | ||
| 734 | arch_timer_ppi[i] = irq_of_parse_and_map(np, i); | ||
| 735 | |||
| 736 | arch_timer_detect_rate(NULL, np); | ||
| 737 | |||
| 738 | arch_timer_c3stop = !of_property_read_bool(np, "always-on"); | ||
| 739 | |||
| 740 | /* | ||
| 741 | * If we cannot rely on firmware initializing the timer registers then | ||
| 742 | * we should use the physical timers instead. | ||
| 743 | */ | ||
| 744 | if (IS_ENABLED(CONFIG_ARM) && | ||
| 745 | of_property_read_bool(np, "arm,cpu-registers-not-fw-configured")) | ||
| 746 | arch_timer_use_virtual = false; | ||
| 747 | |||
| 748 | arch_timer_init(); | ||
| 749 | } | ||
| 750 | CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init); | ||
| 751 | CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init); | ||
| 741 | 752 | ||
| 742 | static void __init arch_timer_mem_init(struct device_node *np) | 753 | static void __init arch_timer_mem_init(struct device_node *np) |
| 743 | { | 754 | { |
| @@ -804,3 +815,70 @@ static void __init arch_timer_mem_init(struct device_node *np) | |||
| 804 | } | 815 | } |
| 805 | CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", | 816 | CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", |
| 806 | arch_timer_mem_init); | 817 | arch_timer_mem_init); |
| 818 | |||
| 819 | #ifdef CONFIG_ACPI | ||
| 820 | static int __init map_generic_timer_interrupt(u32 interrupt, u32 flags) | ||
| 821 | { | ||
| 822 | int trigger, polarity; | ||
| 823 | |||
| 824 | if (!interrupt) | ||
| 825 | return 0; | ||
| 826 | |||
| 827 | trigger = (flags & ACPI_GTDT_INTERRUPT_MODE) ? ACPI_EDGE_SENSITIVE | ||
| 828 | : ACPI_LEVEL_SENSITIVE; | ||
| 829 | |||
| 830 | polarity = (flags & ACPI_GTDT_INTERRUPT_POLARITY) ? ACPI_ACTIVE_LOW | ||
| 831 | : ACPI_ACTIVE_HIGH; | ||
| 832 | |||
| 833 | return acpi_register_gsi(NULL, interrupt, trigger, polarity); | ||
| 834 | } | ||
| 835 | |||
| 836 | /* Initialize per-processor generic timer */ | ||
| 837 | static int __init arch_timer_acpi_init(struct acpi_table_header *table) | ||
| 838 | { | ||
| 839 | struct acpi_table_gtdt *gtdt; | ||
| 840 | |||
| 841 | if (arch_timers_present & ARCH_CP15_TIMER) { | ||
| 842 | pr_warn("arch_timer: already initialized, skipping\n"); | ||
| 843 | return -EINVAL; | ||
| 844 | } | ||
| 845 | |||
| 846 | gtdt = container_of(table, struct acpi_table_gtdt, header); | ||
| 847 | |||
| 848 | arch_timers_present |= ARCH_CP15_TIMER; | ||
| 849 | |||
| 850 | arch_timer_ppi[PHYS_SECURE_PPI] = | ||
| 851 | map_generic_timer_interrupt(gtdt->secure_el1_interrupt, | ||
| 852 | gtdt->secure_el1_flags); | ||
| 853 | |||
| 854 | arch_timer_ppi[PHYS_NONSECURE_PPI] = | ||
| 855 | map_generic_timer_interrupt(gtdt->non_secure_el1_interrupt, | ||
| 856 | gtdt->non_secure_el1_flags); | ||
| 857 | |||
| 858 | arch_timer_ppi[VIRT_PPI] = | ||
| 859 | map_generic_timer_interrupt(gtdt->virtual_timer_interrupt, | ||
| 860 | gtdt->virtual_timer_flags); | ||
| 861 | |||
| 862 | arch_timer_ppi[HYP_PPI] = | ||
| 863 | map_generic_timer_interrupt(gtdt->non_secure_el2_interrupt, | ||
| 864 | gtdt->non_secure_el2_flags); | ||
| 865 | |||
| 866 | /* Get the frequency from CNTFRQ */ | ||
| 867 | arch_timer_detect_rate(NULL, NULL); | ||
| 868 | |||
| 869 | /* Always-on capability */ | ||
| 870 | arch_timer_c3stop = !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON); | ||
| 871 | |||
| 872 | arch_timer_init(); | ||
| 873 | return 0; | ||
| 874 | } | ||
| 875 | |||
| 876 | /* Initialize all the generic timers presented in GTDT */ | ||
| 877 | void __init acpi_generic_timer_init(void) | ||
| 878 | { | ||
| 879 | if (acpi_disabled) | ||
| 880 | return; | ||
| 881 | |||
| 882 | acpi_table_parse(ACPI_SIG_GTDT, arch_timer_acpi_init); | ||
| 883 | } | ||
| 884 | #endif | ||
