diff options
author | Bo Yan <byan@nvidia.com> | 2013-02-05 14:48:37 -0800 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2013-09-14 12:57:40 -0700 |
commit | fc2b1d1c345d6e8a3d5594ee29c6325f1f4654f0 (patch) | |
tree | e293f690f8fc57e2f1b53e4a2c70c0f4d25dd4c1 /arch/arm/mach-tegra/cpuidle-t11x.c | |
parent | c4b85b9f1560f3a3a223216708b74a9737b60b4a (diff) |
ARM: tegra11x: clock gating at Vmin in CPU idle
Force Vmin by dropping DFLL rate to minimum in cluster idle state if
power gating non-CPU partition and rail gating are not as power
efficient.
bug 1049931
Change-Id: I83a9d1f55995c4ab14d5afb1095877b23b25de09
Signed-off-by: Bo Yan <byan@nvidia.com>
Reviewed-on: http://git-master/r/198018
(cherry picked from commit 358df5ac0b2792ac0f1c87725358ad007036e666)
Reviewed-on: http://git-master/r/200858
GVS: Gerrit_Virtual_Submit
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
Reviewed-by: Seshendra Gadagottu <sgadagottu@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/cpuidle-t11x.c')
-rw-r--r-- | arch/arm/mach-tegra/cpuidle-t11x.c | 66 |
1 files changed, 47 insertions, 19 deletions
diff --git a/arch/arm/mach-tegra/cpuidle-t11x.c b/arch/arm/mach-tegra/cpuidle-t11x.c index 4d8b4963d2bb..06d2769dbce9 100644 --- a/arch/arm/mach-tegra/cpuidle-t11x.c +++ b/arch/arm/mach-tegra/cpuidle-t11x.c @@ -72,8 +72,9 @@ #define ARCH_TIMER_CTRL_ENABLE (1 << 0) #define ARCH_TIMER_CTRL_IT_MASK (1 << 1) -#define TEGRA_MIN_RESIDENCY_NCPU_SLOW 2000 -#define TEGRA_MIN_RESIDENCY_NCPU_FAST 13000 +#define TEGRA_MIN_RESIDENCY_CLKGT_VMIN 2000 +#define TEGRA_MIN_RESIDENCY_NCPU_SLOW 2000 +#define TEGRA_MIN_RESIDENCY_NCPU_FAST 13000 #ifdef CONFIG_SMP static s64 tegra_cpu_wake_by_time[4] = { @@ -458,9 +459,10 @@ bool tegra11x_idle_power_down(struct cpuidle_device *dev, { bool power_down; bool cpu_gating_only = false; + bool clkgt_at_vmin = false; bool power_gating_cpu_only = true; int status = -1; - unsigned long rate = ULONG_MAX; + unsigned long rate; s64 request; if (tegra_cpu_timer_get_remain(&request)) { @@ -479,31 +481,57 @@ bool tegra11x_idle_power_down(struct cpuidle_device *dev, power_gating_cpu_only = false; else power_gating_cpu_only = true; - } else if (!cpu_gating_only && - (num_online_cpus() == 1) && - tegra_rail_off_is_allowed()) { - if (fast_cluster_power_down_mode && - TEGRA_POWER_CLUSTER_FORCE_MASK) - power_gating_cpu_only = cpu_gating_only; - else if (request > TEGRA_MIN_RESIDENCY_NCPU_FAST) - power_gating_cpu_only = false; - else + } else { + if (num_online_cpus() > 1) power_gating_cpu_only = true; - } else - power_gating_cpu_only = true; + else { + if (tegra_force_clkgt_at_vmin == + TEGRA_CPUIDLE_FORCE_DO_CLKGT_VMIN) + clkgt_at_vmin = true; + else if (tegra_force_clkgt_at_vmin == + TEGRA_CPUIDLE_FORCE_NO_CLKGT_VMIN) + clkgt_at_vmin = false; + else if ((request >= TEGRA_MIN_RESIDENCY_CLKGT_VMIN) && + (request < TEGRA_MIN_RESIDENCY_NCPU_FAST)) + clkgt_at_vmin = true; + + if (!cpu_gating_only && tegra_rail_off_is_allowed()) { + if (fast_cluster_power_down_mode & + TEGRA_POWER_CLUSTER_FORCE_MASK) + power_gating_cpu_only = false; + else if (request > + TEGRA_MIN_RESIDENCY_NCPU_FAST) + power_gating_cpu_only = false; + else + power_gating_cpu_only = true; + } else + power_gating_cpu_only = true; + } + } - if (power_gating_cpu_only) - power_down = tegra_cpu_core_power_down(dev, state, request); - else { - if (is_lp_cluster()) + if (clkgt_at_vmin) { + rate = 0; + status = tegra11_cpu_dfll_rate_exchange(&rate); + if (!status) { + cpu_do_idle(); + tegra11_cpu_dfll_rate_exchange(&rate); + power_down = false; + } else + power_down = tegra_cpu_core_power_down(dev, state, + request); + } else if (!power_gating_cpu_only) { + if (is_lp_cluster()) { + rate = ULONG_MAX; status = tegra_cpu_backup_rate_exchange(&rate); + } power_down = tegra_cpu_cluster_power_down(dev, state, request); /* restore cpu clock after cluster power ungating */ if (status == 0) tegra_cpu_backup_rate_exchange(&rate); - } + } else + power_down = tegra_cpu_core_power_down(dev, state, request); tegra_clear_cpu_in_pd(dev->cpu); |