aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource/arm_arch_timer.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-04-24 11:23:45 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-04-24 11:23:45 -0400
commit836ee4874e201a5907f9658fb2bf3527dd952d30 (patch)
tree34a9e521bbba61d127794278e7b14d96797273f4 /drivers/clocksource/arm_arch_timer.c
parentfb65d872d7a8dc629837a49513911d0281577bfd (diff)
parent7676fa70feb2f3bcdd4b854a553a57d8ef8505aa (diff)
Merge tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
Pull initial ACPI support for arm64 from Will Deacon: "This series introduces preliminary ACPI 5.1 support to the arm64 kernel using the "hardware reduced" profile. We don't support any peripherals yet, so it's fairly limited in scope: - MEMORY init (UEFI) - ACPI discovery (RSDP via UEFI) - CPU init (FADT) - GIC init (MADT) - SMP boot (MADT + PSCI) - ACPI Kconfig options (dependent on EXPERT) ACPI for arm64 has been in development for a while now and hardware has been available that can boot with either FDT or ACPI tables. This has been made possible by both changes to the ACPI spec to cater for ARM-based machines (known as "hardware-reduced" in ACPI parlance) but also a Linaro-driven effort to get this supported on top of the Linux kernel. This pull request is the result of that work. These changes allow us to initialise the CPUs, interrupt controller, and timers via ACPI tables, with memory information and cmdline coming from EFI. We don't support a hybrid ACPI/FDT scheme. Of course, there is still plenty of work to do (a serial console would be nice!) but I expect that to happen on a per-driver basis after this core series has been merged. Anyway, the diff stat here is fairly horrible, but splitting this up and merging it via all the different subsystems would have been extremely painful. Instead, we've got all the relevant Acks in place and I've not seen anything other than trivial (Kconfig) conflicts in -next (for completeness, I've included my resolution below). Nearly half of the insertions fall under Documentation/. So, we'll see how this goes. Right now, it all depends on EXPERT and I fully expect people to use FDT by default for the immediate future" * tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: (31 commits) ARM64 / ACPI: make acpi_map_gic_cpu_interface() as void function ARM64 / ACPI: Ignore the return error value of acpi_map_gic_cpu_interface() ARM64 / ACPI: fix usage of acpi_map_gic_cpu_interface ARM64: kernel: acpi: honour acpi=force command line parameter ARM64: kernel: acpi: refactor ACPI tables init and checks ARM64: kernel: psci: let ACPI probe PSCI version ARM64: kernel: psci: factor out probe function ACPI: move arm64 GSI IRQ model to generic GSI IRQ layer ARM64 / ACPI: Don't unflatten device tree if acpi=force is passed ARM64 / ACPI: additions of ACPI documentation for arm64 Documentation: ACPI for ARM64 ARM64 / ACPI: Enable ARM64 in Kconfig XEN / ACPI: Make XEN ACPI depend on X86 ARM64 / ACPI: Select ACPI_REDUCED_HARDWARE_ONLY if ACPI is enabled on ARM64 clocksource / arch_timer: Parse GTDT to initialize arch timer irqchip: Add GICv2 specific ACPI boot support ARM64 / ACPI: Introduce ACPI_IRQ_MODEL_GIC and register device's gsi ACPI / processor: Make it possible to get CPU hardware ID via GICC ACPI / processor: Introduce phys_cpuid_t for CPU hardware ID ARM64 / ACPI: Parse MADT for SMP initialization ...
Diffstat (limited to 'drivers/clocksource/arm_arch_timer.c')
-rw-r--r--drivers/clocksource/arm_arch_timer.c132
1 files changed, 105 insertions, 27 deletions
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 266469691e58..0aa135ddbf80 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
694static void __init arch_timer_init(struct device_node *np) 699static 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}
739CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_init); 722
740CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_init); 723static 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}
750CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init);
751CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init);
741 752
742static void __init arch_timer_mem_init(struct device_node *np) 753static 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}
805CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", 816CLOCKSOURCE_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
820static 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 */
837static 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 */
877void __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