lkml.org 
[lkml]   [2014]   [Aug]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v2 13/18] ARM64 / ACPI: Parse GTDT to initialize arch timer
    Date
    Using the information presented by GTDT to initialize the arch
    timer (not memory-mapped).

    Originally-by: Amit Daniel Kachhap <amit.daniel@samsung.com>
    Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
    ---
    arch/arm64/kernel/time.c | 7 ++
    drivers/clocksource/arm_arch_timer.c | 117 ++++++++++++++++++++++++++++------
    include/linux/clocksource.h | 6 ++
    3 files changed, 111 insertions(+), 19 deletions(-)

    diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c
    index 1a7125c..42f9195 100644
    --- a/arch/arm64/kernel/time.c
    +++ b/arch/arm64/kernel/time.c
    @@ -35,6 +35,7 @@
    #include <linux/delay.h>
    #include <linux/clocksource.h>
    #include <linux/clk-provider.h>
    +#include <linux/acpi.h>

    #include <clocksource/arm_arch_timer.h>

    @@ -72,6 +73,12 @@ void __init time_init(void)

    tick_setup_hrtimer_broadcast();

    + /*
    + * Since ACPI or FDT will only one be available in the system,
    + * we can use acpi_generic_timer_init() here safely
    + */
    + acpi_generic_timer_init();
    +
    arch_timer_rate = arch_timer_get_rate();
    if (!arch_timer_rate)
    panic("Unable to initialise architected timer.\n");
    diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
    index 5163ec1..397783f 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>
    @@ -338,8 +339,12 @@ arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np)
    if (arch_timer_rate)
    return;

    - /* Try to determine the frequency from the device tree or CNTFRQ */
    - if (of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) {
    + /*
    + * Try to determine the frequency from the device tree or CNTFRQ,
    + * if ACPI is enabled, get the frequency from CNTFRQ ONLY.
    + */
    + if (!acpi_disabled ||
    + of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) {
    if (cntbase)
    arch_timer_rate = readl_relaxed(cntbase + CNTFRQ);
    else
    @@ -635,20 +640,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 +660,31 @@ 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);

    static void __init arch_timer_mem_init(struct device_node *np)
    {
    @@ -740,3 +751,71 @@ static void __init arch_timer_mem_init(struct device_node *np)
    }
    CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem",
    arch_timer_mem_init);
    +
    +#ifdef CONFIG_ACPI
    +static int __init
    +map_generic_timer_interrupt(u32 interrupt, u32 flags)
    +{
    + int trigger, polarity;
    +
    + if (!interrupt)
    + return 0;
    +
    + trigger = (flags & ACPI_GTDT_INTERRUPT_MODE) ? ACPI_EDGE_SENSITIVE
    + : ACPI_LEVEL_SENSITIVE;
    +
    + polarity = (flags & ACPI_GTDT_INTERRUPT_POLARITY) ? ACPI_ACTIVE_LOW
    + : ACPI_ACTIVE_HIGH;
    +
    + return acpi_register_gsi(NULL, interrupt, trigger, polarity);
    +}
    +
    +/* Initialize per-processor generic timer */
    +static int __init arch_timer_acpi_init(struct acpi_table_header *table)
    +{
    + struct acpi_table_gtdt *gtdt;
    +
    + if (arch_timers_present & ARCH_CP15_TIMER) {
    + pr_warn("arch_timer: already initialized, skipping\n");
    + return -EINVAL;
    + }
    +
    + gtdt = container_of(table, struct acpi_table_gtdt, header);
    +
    + arch_timers_present |= ARCH_CP15_TIMER;
    +
    + arch_timer_ppi[PHYS_SECURE_PPI] =
    + map_generic_timer_interrupt(gtdt->secure_el1_interrupt,
    + gtdt->secure_el1_flags);
    +
    + arch_timer_ppi[PHYS_NONSECURE_PPI] =
    + map_generic_timer_interrupt(gtdt->non_secure_el1_interrupt,
    + gtdt->non_secure_el1_flags);
    +
    + arch_timer_ppi[VIRT_PPI] =
    + map_generic_timer_interrupt(gtdt->virtual_timer_interrupt,
    + gtdt->virtual_timer_flags);
    +
    + arch_timer_ppi[HYP_PPI] =
    + map_generic_timer_interrupt(gtdt->non_secure_el2_interrupt,
    + gtdt->non_secure_el2_flags);
    +
    + /* Get the frequency from CNTFRQ */
    + arch_timer_detect_rate(NULL, NULL);
    +
    + /* Always-on capability */
    + arch_timer_c3stop = !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON);
    +
    + arch_timer_init();
    + return 0;
    +}
    +
    +/* Initialize all the generic timers presented in GTDT */
    +void __init acpi_generic_timer_init(void)
    +{
    + if (acpi_disabled)
    + return;
    +
    + acpi_table_parse(ACPI_SIG_GTDT, arch_timer_acpi_init);
    +}
    +#endif
    diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
    index a16b497..544e298 100644
    --- a/include/linux/clocksource.h
    +++ b/include/linux/clocksource.h
    @@ -348,4 +348,10 @@ extern void clocksource_of_init(void);
    static inline void clocksource_of_init(void) {}
    #endif

    +#ifdef CONFIG_ACPI
    +void acpi_generic_timer_init(void);
    +#else
    +static inline void acpi_generic_timer_init(void) {}
    +#endif
    +
    #endif /* _LINUX_CLOCKSOURCE_H */
    --
    1.7.9.5


    \
     
     \ /
      Last update: 2014-08-04 18:01    [W:4.289 / U:0.004 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site