summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2011-09-28 22:42:06 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 00:57:36 -0700
commit36c6bc2d5618a69ebc3b0e2133d83b640837179b (patch)
tree2d779b8db20ff18d0eede9b787a00212aa5517ef /arch
parent78acfb482da84de0b8b212593954904d555edbe9 (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> Rebase-Id: R577246dfe6bce06bf7a1f87d0ab488322d98b631
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-tegra/cpuidle-t3.c17
-rw-r--r--arch/arm/mach-tegra/cpuidle.c4
-rw-r--r--arch/arm/mach-tegra/cpuidle.h10
3 files changed, 30 insertions, 1 deletions
diff --git a/arch/arm/mach-tegra/cpuidle-t3.c b/arch/arm/mach-tegra/cpuidle-t3.c
index 6e3496da2aef..928ba90ca0d4 100644
--- a/arch/arm/mach-tegra/cpuidle-t3.c
+++ b/arch/arm/mach-tegra/cpuidle-t3.c
@@ -38,10 +38,12 @@
#include <linux/suspend.h>
#include <linux/tick.h>
#include <linux/cpu_pm.h>
+#include <linux/clk.h>
#include <asm/cacheflush.h>
#include <asm/hardware/gic.h>
#include <asm/localtimer.h>
+#include <asm/smp_twd.h>
#include <mach/iomap.h>
#include <mach/irqs.h>
@@ -67,6 +69,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 +271,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 +321,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 f203bf1f1774..fa0c9449d387 100644
--- a/arch/arm/mach-tegra/cpuidle.c
+++ b/arch/arm/mach-tegra/cpuidle.c
@@ -196,6 +196,10 @@ static int __init tegra_cpuidle_init(void)
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;
+
tegra_idle_driver.states[1].exit_latency = tegra_cpu_power_good_time();
tegra_idle_driver.states[1].target_residency = tegra_cpu_power_off_time() +
tegra_cpu_power_good_time();
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