diff options
author | Hanjun Guo <hanjun.guo@linaro.org> | 2014-01-17 20:25:11 +0800 |
---|---|---|
committer | Graeme Gregory <graeme.gregory@linaro.org> | 2014-06-03 09:24:10 +0100 |
commit | af1a87558f1be03360e77ba148bb84399847e3d1 (patch) | |
tree | c7142582ff0c22096d45979e81f6fe03d96b58ae | |
parent | f631b5d8b267d58be19e7c08e4cf970c0294a10e (diff) | |
download | leg-kernel-af1a87558f1be03360e77ba148bb84399847e3d1.tar.gz |
clocksource / arch_timer: Use ACPI GTDT table to initialize arch timer
ACPI GTDT (Generic Timer Description Table) contains information for
arch timer initialization, this patch use this table to probe arm timer.
GTDT table is used for ARM/ARM64 only, please refer to chapter 5.2.24
of ACPI 5.0 spec for detailed inforamtion
Signed-off-by: Amit Daniel Kachhap <amit.daniel@samsung.com>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
-rw-r--r-- | drivers/clocksource/arm_arch_timer.c | 104 |
1 files changed, 87 insertions, 17 deletions
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 5163ec13429d..e34ce1bf46da 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -21,6 +21,7 @@ #include <linux/io.h> #include <linux/slab.h> #include <linux/sched_clock.h> +#include <linux/acpi.h> #include <asm/arch_timer.h> #include <asm/virt.h> @@ -635,20 +636,8 @@ static void __init arch_timer_common_init(void) arch_timer_arch_init(); } -static void __init arch_timer_init(struct device_node *np) +static void __init arch_timer_init(void) { - int i; - - if (arch_timers_present & ARCH_CP15_TIMER) { - pr_warn("arch_timer: multiple nodes in dt, skipping\n"); - return; - } - - arch_timers_present |= ARCH_CP15_TIMER; - for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++) - arch_timer_ppi[i] = irq_of_parse_and_map(np, i); - arch_timer_detect_rate(NULL, np); - /* * If HYP mode is available, we know that the physical timer * has been configured to be accessible from PL1. Use it, so @@ -667,13 +656,94 @@ static void __init arch_timer_init(struct device_node *np) } } - arch_timer_c3stop = !of_property_read_bool(np, "always-on"); - arch_timer_register(); arch_timer_common_init(); } -CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_init); -CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_init); + +static void __init arch_timer_of_init(struct device_node *np) +{ + int i; + + if (arch_timers_present & ARCH_CP15_TIMER) { + pr_warn("arch_timer: multiple nodes in dt, skipping\n"); + return; + } + + arch_timers_present |= ARCH_CP15_TIMER; + for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++) + arch_timer_ppi[i] = irq_of_parse_and_map(np, i); + arch_timer_detect_rate(NULL, np); + + arch_timer_c3stop = !of_property_read_bool(np, "always-on"); + + arch_timer_init(); +} +CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init); +CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init); + +#ifdef CONFIG_ACPI +static void __init register_arch_interrupt(u32 interrupt, u32 flags, + int *arch_timer_ppi) +{ + int trigger, polarity; + + if (!interrupt || !arch_timer_ppi) + return; + + trigger = (flags & ACPI_GTDT_INTERRUPT_MODE) ? ACPI_EDGE_SENSITIVE + : ACPI_LEVEL_SENSITIVE; + + polarity = (flags & ACPI_GTDT_INTERRUPT_POLARITY) ? ACPI_ACTIVE_LOW + : ACPI_ACTIVE_HIGH; + + *arch_timer_ppi = acpi_register_gsi(NULL, interrupt, trigger, + polarity); +} + +static int __init acpi_parse_gtdt(struct acpi_table_header *table) +{ + struct acpi_table_gtdt *gtdt; + + gtdt = (struct acpi_table_gtdt *)table; + if (!gtdt) + return -EINVAL; + + arch_timer_rate = arch_timer_get_cntfrq(); + + if (!arch_timer_rate) { + pr_warn("arch_timer: Could not get frequency from CNTFREG\n"); + return -EINVAL; + } + + register_arch_interrupt(gtdt->secure_pl1_interrupt, + gtdt->secure_pl1_flags, &arch_timer_ppi[PHYS_SECURE_PPI]); + + register_arch_interrupt(gtdt->non_secure_pl1_interrupt, + gtdt->non_secure_pl1_flags, &arch_timer_ppi[PHYS_NONSECURE_PPI]); + + register_arch_interrupt(gtdt->virtual_timer_interrupt, + gtdt->virtual_timer_flags, &arch_timer_ppi[VIRT_PPI]); + + register_arch_interrupt(gtdt->non_secure_pl2_interrupt, + gtdt->non_secure_pl2_flags, &arch_timer_ppi[HYP_PPI]); + + return 0; +} + +void __init arch_timer_acpi_init(struct acpi_table_header *table) +{ + if (arch_timers_present & ARCH_CP15_TIMER) { + pr_warn("arch_timer: already initialized, skipping\n"); + return; + } + + if (acpi_parse_gtdt(table)) + return; + + arch_timers_present |= ARCH_CP15_TIMER; + arch_timer_init(); +} +#endif static void __init arch_timer_mem_init(struct device_node *np) { |