summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJinyoung Park <jinyoungp@nvidia.com>2013-09-02 15:02:05 +0900
committerGabby Lee <galee@nvidia.com>2013-09-02 06:38:11 -0700
commit9c8338e70cddd6c4518f75944d20611c90e33ad5 (patch)
tree11e224e107f27c1f32f0704168271bb84d16e2a8
parent57de2dbf25c025834fa7fbcd1d440b9e05179ce1 (diff)
ARM: tegra: cpu: Ensure CPU freq with suspend freq during pre/post suspend
Tegra CPU driver fixes CPU freq with a selected suspend freq between pre-suspend and post-suspend. In this pre/post suspend period, the Tegra CPU driver ignores CPU freq scaling requests from the CPU freq governor. But the CPU freq governor keep working until the system suspended. So the CPU freq governor updates its status even if the system is in the pre/post suspend period. This makes unexpected CPU freq setting issue on post-suspend. To ensure CPU freq with the selected suspend freq in the pre/post suspend period, set a policy max freq on CPU freq governor to the selected suspend freq via PM QoS at pre-suspend and release the setting via PM QoS at post-suspend. Bug 1354391 Change-Id: I8efa6dd438a37adc7cadfb1d36eb7340a4e85c79 Signed-off-by: Jinyoung Park <jinyoungp@nvidia.com> Reviewed-on: http://git-master/r/268955 Reviewed-by: Gabby Lee <galee@nvidia.com> Tested-by: Gabby Lee <galee@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/cpu-tegra.c43
1 files changed, 34 insertions, 9 deletions
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
index 092da7e7c02b..6f90c1c4852f 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -33,6 +33,7 @@
#include <linux/suspend.h>
#include <linux/debugfs.h>
#include <linux/cpu.h>
+#include <linux/pm_qos.h>
#include <mach/clk.h>
@@ -55,6 +56,7 @@ static DEFINE_MUTEX(tegra_cpu_lock);
static bool is_suspended;
static int suspend_index;
static unsigned int volt_capped_speed;
+static struct pm_qos_request cpufreq_max_req;
static bool force_policy_max;
@@ -695,15 +697,18 @@ static int tegra_target(struct cpufreq_policy *policy,
mutex_lock(&tegra_cpu_lock);
- ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
- relation, &idx);
- if (ret)
- goto _out;
+ if (!is_suspended) {
+ ret = cpufreq_frequency_table_target(policy, freq_table,
+ target_freq, relation, &idx);
+ if (ret)
+ goto _out;
+
+ freq = freq_table[idx].frequency;
- freq = freq_table[idx].frequency;
+ target_cpu_speed[policy->cpu] = freq;
- target_cpu_speed[policy->cpu] = freq;
- ret = tegra_cpu_set_speed_cap_locked(&new_speed);
+ ret = tegra_cpu_set_speed_cap_locked(&new_speed);
+ }
_out:
mutex_unlock(&tegra_cpu_lock);
@@ -714,23 +719,40 @@ _out:
static int tegra_pm_notify(struct notifier_block *nb, unsigned long event,
void *dummy)
{
- mutex_lock(&tegra_cpu_lock);
if (event == PM_SUSPEND_PREPARE) {
+ int i;
+
+ pm_qos_update_request(&cpufreq_max_req,
+ freq_table[suspend_index].frequency);
+
+ mutex_lock(&tegra_cpu_lock);
is_suspended = true;
+ for_each_possible_cpu(i) {
+ if (target_cpu_speed[i] >
+ freq_table[suspend_index].frequency)
+ target_cpu_speed[i] =
+ freq_table[suspend_index].frequency;
+ }
pr_info("Tegra cpufreq suspend: setting frequency to %d kHz\n",
freq_table[suspend_index].frequency);
tegra_update_cpu_speed(freq_table[suspend_index].frequency);
tegra_auto_hotplug_governor(
freq_table[suspend_index].frequency, true);
+ mutex_unlock(&tegra_cpu_lock);
} else if (event == PM_POST_SUSPEND) {
unsigned int freq;
+
+ mutex_lock(&tegra_cpu_lock);
is_suspended = false;
tegra_cpu_edp_init(true);
tegra_cpu_set_speed_cap_locked(&freq);
pr_info("Tegra cpufreq resume: restoring frequency to %d kHz\n",
freq);
+ mutex_unlock(&tegra_cpu_lock);
+
+ pm_qos_update_request(&cpufreq_max_req,
+ PM_QOS_CPU_FREQ_MAX_DEFAULT_VALUE);
}
- mutex_unlock(&tegra_cpu_lock);
return NOTIFY_OK;
}
@@ -863,6 +885,9 @@ static int __init tegra_cpufreq_init(void)
tegra_cpu_edp_init(false);
mutex_unlock(&tegra_cpu_lock);
+ pm_qos_add_request(&cpufreq_max_req, PM_QOS_CPU_FREQ_MAX,
+ PM_QOS_CPU_FREQ_MAX_DEFAULT_VALUE);
+
ret = register_pm_notifier(&tegra_cpu_pm_notifier);
if (ret)