summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/cpu-tegra.c
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2011-09-10 18:33:28 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:49:37 -0800
commitc9bc7e2f81aed42ccce0dea4e52d47a4e3b684c5 (patch)
tree9027143a31d76388283a17bef80240307c2e4017 /arch/arm/mach-tegra/cpu-tegra.c
parent8dc7d5c11abfc75fc6a499822001f2d83455daa0 (diff)
ARM: tegra: power: Enforce cpufreq policy maximum
Tegra cpu complex frequency is set by cpufreq driver to the maximum of per-cpu target frequencies specified by the respective governors running on each cpu core. It guarantees that final frequency is above all per-cpu policy low limits, but policy high limit set on one core, may be exceeded if the other core has higher target. This commit implements complementary mode in cpufreq driver that set final cpu frequency below all per-cpu maximum policy limits. The new mode is disabled by default, and can be activated via /sys/module/cpu_tegra/parameters/force_policy_max (cherry picked from commit d52a93527778b13efd2e4b783ce0707513f53f26) (cherry picked from commit bc1450eedb97fd2f37544e07dae15946d209866c) Change-Id: I2b51738a50312e0b3ba747747e6fa68efddc6038 Reviewed-on: http://git-master/r/61020 Tested-by: Aleksandr Frid <afrid@nvidia.com> Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com> Rebase-Id: R2fa76e42f800220db708c8720a3fe6b1792e5c59
Diffstat (limited to 'arch/arm/mach-tegra/cpu-tegra.c')
-rw-r--r--arch/arm/mach-tegra/cpu-tegra.c62
1 files changed, 61 insertions, 1 deletions
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
index 3711b9f2dc97..1524a481f2f9 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -49,11 +49,39 @@ static struct cpufreq_frequency_table *freq_table;
static struct clk *cpu_clk;
static struct clk *emc_clk;
+static unsigned long policy_max_speed[CONFIG_NR_CPUS];
static unsigned long target_cpu_speed[CONFIG_NR_CPUS];
static DEFINE_MUTEX(tegra_cpu_lock);
static bool is_suspended;
static int suspend_index;
+static bool force_policy_max;
+
+static int force_policy_max_set(const char *arg, const struct kernel_param *kp)
+{
+ int ret;
+ bool old_policy = force_policy_max;
+
+ ret = param_set_bool(arg, kp);
+
+ if ((ret == 0) && (old_policy != force_policy_max))
+ tegra_cpu_set_speed_cap(NULL);
+
+ return ret;
+}
+
+static int force_policy_max_get(char *buffer, const struct kernel_param *kp)
+{
+ return param_get_bool(buffer, kp);
+}
+
+static struct kernel_param_ops policy_ops = {
+ .set = force_policy_max_set,
+ .get = force_policy_max_get,
+};
+module_param_cb(force_policy_max, &policy_ops, &force_policy_max, 0644);
+
+
#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
static ssize_t show_throttle(struct cpufreq_policy *policy, char *buf)
@@ -387,11 +415,16 @@ unsigned long tegra_cpu_lowest_speed(void) {
}
unsigned long tegra_cpu_highest_speed(void) {
+ unsigned long policy_max = ULONG_MAX;
unsigned long rate = 0;
int i;
- for_each_online_cpu(i)
+ for_each_online_cpu(i) {
+ if (force_policy_max)
+ policy_max = min(policy_max, policy_max_speed[i]);
rate = max(rate, target_cpu_speed[i]);
+ }
+ rate = min(rate, policy_max);
return rate;
}
@@ -512,6 +545,25 @@ static int tegra_cpu_exit(struct cpufreq_policy *policy)
return 0;
}
+static int tegra_cpufreq_policy_notifier(
+ struct notifier_block *nb, unsigned long event, void *data)
+{
+ int i, ret;
+ struct cpufreq_policy *policy = data;
+
+ if (event == CPUFREQ_NOTIFY) {
+ ret = cpufreq_frequency_table_target(policy, freq_table,
+ policy->max, CPUFREQ_RELATION_H, &i);
+ policy_max_speed[policy->cpu] =
+ ret ? policy->max : freq_table[i].frequency;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block tegra_cpufreq_policy_nb = {
+ .notifier_call = tegra_cpufreq_policy_notifier,
+};
+
static struct freq_attr *tegra_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
@@ -551,6 +603,12 @@ static int __init tegra_cpufreq_init(void)
freq_table = table_data->freq_table;
tegra_cpu_edp_init(false);
+
+ ret = cpufreq_register_notifier(
+ &tegra_cpufreq_policy_nb, CPUFREQ_POLICY_NOTIFIER);
+ if (ret)
+ return ret;
+
return cpufreq_register_driver(&tegra_cpufreq_driver);
}
@@ -560,6 +618,8 @@ static void __exit tegra_cpufreq_exit(void)
tegra_cpu_edp_exit();
tegra_auto_hotplug_exit();
cpufreq_unregister_driver(&tegra_cpufreq_driver);
+ cpufreq_unregister_notifier(
+ &tegra_cpufreq_policy_nb, CPUFREQ_POLICY_NOTIFIER);
}