summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2011-09-28 22:42:06 -0700
committerVarun Colbert <vcolbert@nvidia.com>2011-10-06 23:49:04 -0700
commitd1ee5938c057a6f470a4db9de9402ba03a939f75 (patch)
tree82238e76ba400e10c1d432f2b02779ba4d943f8f
parent56e79896b612955ed55ad15f097dd0670121e115 (diff)
ARM: tegra: power: Update Tegra3 LP2 time prediction
Use local timer count to predict time to be spent by secondary CPU in LP2 state instead of scheduler timing. This is more accurate, as local timer wakes CPU after counts down to zero. Change-Id: I28fe6c3153e1c527abf4cf66b556d64516582a35 Reviewed-on: http://git-master/r/55629 Reviewed-by: Aleksandr Frid <afrid@nvidia.com> Tested-by: Aleksandr Frid <afrid@nvidia.com> Reviewed-by: Scott Williams <scwilliams@nvidia.com> Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com> Reviewed-by: Antti Miettinen <amiettinen@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/cpuidle-t3.c16
-rw-r--r--arch/arm/mach-tegra/cpuidle.c4
-rw-r--r--arch/arm/mach-tegra/cpuidle.h10
3 files changed, 29 insertions, 1 deletions
diff --git a/arch/arm/mach-tegra/cpuidle-t3.c b/arch/arm/mach-tegra/cpuidle-t3.c
index e8e552c7717c..8ef8ed45e8bd 100644
--- a/arch/arm/mach-tegra/cpuidle-t3.c
+++ b/arch/arm/mach-tegra/cpuidle-t3.c
@@ -37,6 +37,7 @@
#include <linux/smp.h>
#include <linux/suspend.h>
#include <linux/tick.h>
+#include <linux/clk.h>
#include <asm/cacheflush.h>
#include <asm/cpu_pm.h>
@@ -67,6 +68,7 @@ static s64 tegra_cpu_wake_by_time[4] = {
#endif
static struct clk *cpu_clk_for_dvfs;
+static struct clk *twd_clk;
static struct {
unsigned int cpu_ready_count[5];
@@ -268,6 +270,17 @@ static void tegra3_idle_enter_lp2_cpu_n(struct cpuidle_device *dev,
struct cpuidle_state *state, s64 request)
{
#ifdef CONFIG_SMP
+
+ u32 twd_cnt;
+ u32 twd_ctrl = readl(twd_base + TWD_TIMER_CONTROL);
+ unsigned long twd_rate = clk_get_rate(twd_clk);
+
+ if ((twd_ctrl & TWD_TIMER_CONTROL_ENABLE) &&
+ (twd_ctrl & TWD_TIMER_CONTROL_IT_ENABLE)) {
+ twd_cnt = readl(twd_base + TWD_TIMER_COUNTER);
+ request = div_u64((u64)twd_cnt * 1000000, twd_rate);
+ }
+
if (request < tegra_lp2_exit_latency) {
/*
* Not enough time left to enter LP2
@@ -307,9 +320,10 @@ void tegra3_idle_lp2(struct cpuidle_device *dev,
tegra_clear_cpu_in_lp2(dev->cpu);
}
-int tegra_cpudile_init_soc(void)
+int tegra3_cpudile_init_soc(void)
{
cpu_clk_for_dvfs = tegra_get_clock_by_name("cpu_g");
+ twd_clk = tegra_get_clock_by_name("twd");
return 0;
}
diff --git a/arch/arm/mach-tegra/cpuidle.c b/arch/arm/mach-tegra/cpuidle.c
index 694ab2943fe9..a51a72a985c3 100644
--- a/arch/arm/mach-tegra/cpuidle.c
+++ b/arch/arm/mach-tegra/cpuidle.c
@@ -229,6 +229,10 @@ static int __init tegra_cpuidle_init(void)
tegra_lp2_min_residency = tegra_cpu_lp2_min_residency();
tegra_lp2_exit_latency = tegra_cpu_power_good_time();
tegra_lp2_power_off_time = tegra_cpu_power_off_time();
+
+ ret = tegra_cpudile_init_soc();
+ if (ret)
+ return ret;
#endif
for_each_possible_cpu(cpu) {
diff --git a/arch/arm/mach-tegra/cpuidle.h b/arch/arm/mach-tegra/cpuidle.h
index 406031b26c2d..12a29ff2e236 100644
--- a/arch/arm/mach-tegra/cpuidle.h
+++ b/arch/arm/mach-tegra/cpuidle.h
@@ -41,11 +41,21 @@ void tegra3_cpu_idle_stats_lp2_ready(unsigned int cpu);
void tegra3_cpu_idle_stats_lp2_time(unsigned int cpu, s64 us);
bool tegra3_lp2_is_allowed(struct cpuidle_device *dev,
struct cpuidle_state *state);
+int tegra3_cpudile_init_soc(void);
#ifdef CONFIG_DEBUG_FS
int tegra3_lp2_debug_show(struct seq_file *s, void *data);
#endif
#endif
+static inline int tegra_cpudile_init_soc(void)
+{
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ return 0;
+#else
+ return tegra3_cpudile_init_soc();
+#endif
+}
+
static inline void tegra_cpu_idle_stats_lp2_ready(unsigned int cpu)
{
#ifdef CONFIG_ARCH_TEGRA_2x_SOC