ARM: tegra: cpu: Ensure CPU freq with suspend freq during pre/post suspend
Jinyoung Park [Mon, 2 Sep 2013 06:02:05 +0000 (15:02 +0900)]
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

Signed-off-by: Jinyoung Park <jinyoungp@nvidia.com>
Reviewed-on: http://git-master/r/268955
(cherry picked from commit 9c8338e70cddd6c4518f75944d20611c90e33ad5)

Change-Id: I8efa6dd438a37adc7cadfb1d36eb7340a4e85c79
Signed-off-by: Jinyoung Park <jinyoungp@nvidia.com>
Reviewed-on: http://git-master/r/301040
Reviewed-by: Harry Hong <hhong@nvidia.com>
Tested-by: Harry Hong <hhong@nvidia.com>

arch/arm/mach-tegra/cpu-tegra.c

index fdcfd1e..85bb701 100644 (file)
@@ -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>
@@ -54,6 +55,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;
@@ -686,15 +688,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);
 
@@ -705,23 +710,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;
 }
@@ -845,6 +867,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)