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 | |
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>
-rw-r--r-- | arch/arm64/kernel/time.c | 7 | ||||
-rw-r--r-- | drivers/clocksource/arm_arch_timer.c | 132 | ||||
-rw-r--r-- | include/linux/clocksource.h | 6 |
3 files changed, 118 insertions, 27 deletions
diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c index 1a7125c3099b..42f9195cf2f8 100644 --- a/arch/arm64/kernel/time.c +++ b/arch/arm64/kernel/time.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/delay.h> | 35 | #include <linux/delay.h> |
36 | #include <linux/clocksource.h> | 36 | #include <linux/clocksource.h> |
37 | #include <linux/clk-provider.h> | 37 | #include <linux/clk-provider.h> |
38 | #include <linux/acpi.h> | ||
38 | 39 | ||
39 | #include <clocksource/arm_arch_timer.h> | 40 | #include <clocksource/arm_arch_timer.h> |
40 | 41 | ||
@@ -72,6 +73,12 @@ void __init time_init(void) | |||
72 | 73 | ||
73 | tick_setup_hrtimer_broadcast(); | 74 | tick_setup_hrtimer_broadcast(); |
74 | 75 | ||
76 | /* | ||
77 | * Since ACPI or FDT will only one be available in the system, | ||
78 | * we can use acpi_generic_timer_init() here safely | ||
79 | */ | ||
80 | acpi_generic_timer_init(); | ||
81 | |||
75 | arch_timer_rate = arch_timer_get_rate(); | 82 | arch_timer_rate = arch_timer_get_rate(); |
76 | if (!arch_timer_rate) | 83 | if (!arch_timer_rate) |
77 | panic("Unable to initialise architected timer.\n"); | 84 | panic("Unable to initialise architected timer.\n"); |
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 | ||
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 9c78d15d33e4..2b2e1f80c519 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h | |||
@@ -244,4 +244,10 @@ extern void clocksource_of_init(void); | |||
244 | static inline void clocksource_of_init(void) {} | 244 | static inline void clocksource_of_init(void) {} |
245 | #endif | 245 | #endif |
246 | 246 | ||
247 | #ifdef CONFIG_ACPI | ||
248 | void acpi_generic_timer_init(void); | ||
249 | #else | ||
250 | static inline void acpi_generic_timer_init(void) { } | ||
251 | #endif | ||
252 | |||
247 | #endif /* _LINUX_CLOCKSOURCE_H */ | 253 | #endif /* _LINUX_CLOCKSOURCE_H */ |