summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/cpuidle-t11x.c
diff options
context:
space:
mode:
authorBo Yan <byan@nvidia.com>2013-02-05 14:48:37 -0800
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 12:57:40 -0700
commitfc2b1d1c345d6e8a3d5594ee29c6325f1f4654f0 (patch)
treee293f690f8fc57e2f1b53e4a2c70c0f4d25dd4c1 /arch/arm/mach-tegra/cpuidle-t11x.c
parentc4b85b9f1560f3a3a223216708b74a9737b60b4a (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.c66
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);