]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
drivers: clocksource: add CPU PM notifier for ARM architected timer
authorSudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
Fri, 23 Aug 2013 14:53:15 +0000 (15:53 +0100)
committerDhiren Parmar <dparmar@nvidia.com>
Fri, 8 Aug 2014 05:50:56 +0000 (22:50 -0700)
Few control settings done in architected timer as part of initialisation
can be lost when CPU enters deeper power states. They need to be
restored when the CPU is (warm)reset again.

This patch adds CPU PM notifiers to save the counter control register
when entering low power modes and restore it when CPU exits low power.

Signed-off-by: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
Change-Id: I0bad683961e4b72835ad40edf2c9ac9e0f78fad0
Reviewed-on: http://git-master/r/350844
(cherry picked from commit 1dd60414e4839c11eb99dbbd071b8accdaa3dafd)
Reviewed-on: http://git-master/r/453553
GVS: Gerrit_Virtual_Submit
Reviewed-by: Andrey Trachenko <atrachenko@nvidia.com>
Tested-by: Andrey Trachenko <atrachenko@nvidia.com>
Reviewed-by: Mitch Luban <mluban@nvidia.com>
arch/arm/include/asm/arch_timer.h
drivers/clocksource/arm_arch_timer.c

index accefe0991828e2984c5c1ff49b25dece76edcc0..4d244a680c8d06b826dac51ada2700230d2c2b8a 100644 (file)
@@ -89,16 +89,26 @@ static inline u64 arch_counter_get_cntvct(void)
        return cval;
 }
 
-static inline void __cpuinit arch_counter_set_user_access(void)
+static inline u32 arch_timer_get_cntkctl(void)
 {
        u32 cntkctl;
-
        asm volatile("mrc p15, 0, %0, c14, c1, 0" : "=r" (cntkctl));
+       return cntkctl;
+}
+
+static inline void arch_timer_set_cntkctl(u32 cntkctl)
+{
+       asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl));
+}
+
+static inline void arch_counter_set_user_access(void)
+{
+       u32 cntkctl = arch_timer_get_cntkctl();
 
        /* disable user access to everything */
        cntkctl &= ~((3 << 8) | (7 << 0));
 
-       asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl));
+       arch_timer_set_cntkctl(cntkctl);
 }
 #endif
 
index 044892e1ca746b00dd65ea85be70870c90655202..5e0a70cc5b2727cc90dce44a03d2e680bbbc06b3 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/device.h>
 #include <linux/smp.h>
 #include <linux/cpu.h>
+#include <linux/cpu_pm.h>
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
 #include <linux/of_irq.h>
@@ -262,6 +263,33 @@ static struct notifier_block arch_timer_cpu_nb __cpuinitdata = {
        .notifier_call = arch_timer_cpu_notify,
 };
 
+#ifdef CONFIG_CPU_PM
+static unsigned int saved_cntkctl;
+static int arch_timer_cpu_pm_notify(struct notifier_block *self,
+                                   unsigned long action, void *hcpu)
+{
+       if (action == CPU_PM_ENTER)
+               saved_cntkctl = arch_timer_get_cntkctl();
+       else if (action == CPU_PM_ENTER_FAILED || action == CPU_PM_EXIT)
+               arch_timer_set_cntkctl(saved_cntkctl);
+       return NOTIFY_OK;
+}
+
+static struct notifier_block arch_timer_cpu_pm_notifier = {
+       .notifier_call = arch_timer_cpu_pm_notify,
+};
+
+static int __init arch_timer_cpu_pm_init(void)
+{
+       return cpu_pm_register_notifier(&arch_timer_cpu_pm_notifier);
+}
+#else
+static int __init arch_timer_cpu_pm_init(void)
+{
+       return 0;
+}
+#endif
+
 static int __init arch_timer_register(void)
 {
        int err;
@@ -314,11 +342,17 @@ static int __init arch_timer_register(void)
        if (err)
                goto out_free_irq;
 
+       err = arch_timer_cpu_pm_init();
+       if (err)
+               goto out_unreg_notify;
+
        /* Immediately configure the timer on the boot CPU */
        arch_timer_setup(this_cpu_ptr(arch_timer_evt));
 
        return 0;
 
+out_unreg_notify:
+       unregister_cpu_notifier(&arch_timer_cpu_nb);
 out_free_irq:
        if (arch_timer_use_virtual)
                free_percpu_irq(arch_timer_ppi[VIRT_PPI], arch_timer_evt);