summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorTodd Poynor <toddpoynor@google.com>2010-12-17 19:36:23 -0800
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:36:50 -0800
commit81dd0074b7d32a441e31c04d0517b095114f9875 (patch)
treee34138cc015891cb559874e57fc2b8a52bc71c67 /arch
parent76f6b96694672b6ef8a68fbee5b21ce9ec933107 (diff)
ARM: tegra: Make CPU thermal throttling configurable
Based on work by Dmitriy Gruzman and Varun Wadekar. Change-Id: I64d765628223b7ef1ec493b9e409ea11e9391b94 Signed-off-by: Todd Poynor <toddpoynor@google.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-tegra/Kconfig7
-rw-r--r--arch/arm/mach-tegra/cpu-tegra.c266
2 files changed, 148 insertions, 125 deletions
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index da1d392e8f32..053b4cc2541e 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -132,3 +132,10 @@ config TEGRA_IOVMM
config TEGRA_ARB_SEMAPHORE
bool
+
+config TEGRA_THERMAL_THROTTLE
+ bool "Enable throttling of CPU speed on overtemp"
+ depends on CPU_FREQ
+ default y
+ help
+ Also requires enabling a temperature sensor such as NCT1008.
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
index fcf54ede8542..8e86009b4ac1 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -48,141 +48,32 @@ static struct cpufreq_frequency_table freq_table[] = {
{ 8, CPUFREQ_TABLE_END },
};
-/* CPU frequency is gradually lowered when throttling is enabled */
-#define THROTTLE_START_INDEX 2
-#define THROTTLE_END_INDEX 6
-#define THROTTLE_DELAY msecs_to_jiffies(2000)
-#define NO_DELAY msecs_to_jiffies(0)
-
#define NUM_CPUS 2
static struct clk *cpu_clk;
static struct clk *emc_clk;
-static struct workqueue_struct *workqueue;
-
static unsigned long target_cpu_speed[NUM_CPUS];
static DEFINE_MUTEX(tegra_cpu_lock);
static bool is_suspended;
-static DEFINE_MUTEX(throttling_lock);
-static bool is_throttling;
-static struct delayed_work throttle_work;
-
-
-int tegra_verify_speed(struct cpufreq_policy *policy)
-{
- return cpufreq_frequency_table_verify(policy, freq_table);
-}
-
-unsigned int tegra_getspeed(unsigned int cpu)
-{
- unsigned long rate;
-
- if (cpu >= NUM_CPUS)
- return 0;
-
- rate = clk_get_rate(cpu_clk) / 1000;
- return rate;
-}
-
-static int tegra_update_cpu_speed(unsigned long rate)
-{
- int ret = 0;
- struct cpufreq_freqs freqs;
-
- freqs.old = tegra_getspeed(0);
- freqs.new = rate;
-
- if (freqs.old == freqs.new)
- return ret;
-
- /*
- * Vote on memory bus frequency based on cpu frequency
- * This sets the minimum frequency, display or avp may request higher
- */
- if (rate >= 816000)
- clk_set_rate(emc_clk, 600000000); /* cpu 816 MHz, emc max */
- else if (rate >= 456000)
- clk_set_rate(emc_clk, 300000000); /* cpu 456 MHz, emc 150Mhz */
- else
- clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */
-
- for_each_online_cpu(freqs.cpu)
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-
-#ifdef CONFIG_CPU_FREQ_DEBUG
- printk(KERN_DEBUG "cpufreq-tegra: transition: %u --> %u\n",
- freqs.old, freqs.new);
-#endif
-
- ret = clk_set_rate(cpu_clk, freqs.new * 1000);
- if (ret) {
- pr_err("cpu-tegra: Failed to set cpu frequency to %d kHz\n",
- freqs.new);
- return ret;
- }
-
- for_each_online_cpu(freqs.cpu)
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-
- return 0;
-}
-
-static unsigned long tegra_cpu_highest_speed(void)
-{
- unsigned long rate = 0;
- int i;
-
- for_each_online_cpu(i)
- rate = max(rate, target_cpu_speed[i]);
- return rate;
-}
-
-static int tegra_target(struct cpufreq_policy *policy,
- unsigned int target_freq,
- unsigned int relation)
-{
- int idx;
- unsigned int freq;
- unsigned int highest_speed;
- unsigned int limit_when_throttling;
- int ret = 0;
-
- mutex_lock(&tegra_cpu_lock);
-
- if (is_suspended) {
- ret = -EBUSY;
- goto out;
- }
-
- cpufreq_frequency_table_target(policy, freq_table, target_freq,
- relation, &idx);
-
- freq = freq_table[idx].frequency;
+unsigned int tegra_getspeed(unsigned int cpu);
+static int tegra_update_cpu_speed(unsigned long rate);
- target_cpu_speed[policy->cpu] = freq;
+/* CPU frequency is gradually lowered when throttling is enabled */
+#define THROTTLE_START_INDEX 2
+#define THROTTLE_END_INDEX 6
- highest_speed = tegra_cpu_highest_speed();
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+#define THROTTLE_DELAY msecs_to_jiffies(2000)
+#define NO_DELAY msecs_to_jiffies(0)
- /* Do not go above this frequency when throttling */
- limit_when_throttling = freq_table[THROTTLE_START_INDEX].frequency;
-
- if (is_throttling && highest_speed > limit_when_throttling) {
- if (tegra_getspeed(0) < limit_when_throttling) {
- ret = tegra_update_cpu_speed(limit_when_throttling);
- goto out;
- } else {
- ret = -EBUSY;
- goto out;
- }
- }
+static DEFINE_MUTEX(throttling_lock);
+static bool is_throttling;
+static struct delayed_work throttle_work;
+static struct workqueue_struct *workqueue;
- ret = tegra_update_cpu_speed(highest_speed);
-out:
- mutex_unlock(&tegra_cpu_lock);
- return ret;
-}
+#define tegra_cpu_is_throttling() (is_throttling)
static bool tegra_throttling_needed(unsigned long *rate)
{
@@ -214,7 +105,7 @@ static void tegra_throttle_work_func(struct work_struct *work)
/**
* tegra_throttling_enable
- * This functions may sleep
+ * This function may sleep
*/
void tegra_throttling_enable(void)
{
@@ -231,7 +122,7 @@ EXPORT_SYMBOL_GPL(tegra_throttling_enable);
/**
* tegra_throttling_disable
- * This functions may sleep
+ * This function may sleep
*/
void tegra_throttling_disable(void)
{
@@ -292,8 +183,129 @@ static void __exit tegra_cpu_debug_exit(void)
late_initcall(tegra_cpu_debug_init);
module_exit(tegra_cpu_debug_exit);
+#endif /* CONFIG_DEBUG_FS */
+
+#else /* CONFIG_TEGRA_THERMAL_THROTTLE */
+#define tegra_cpu_is_throttling() (0)
+#endif /* CONFIG_TEGRA_THERMAL_THROTTLE */
+
+int tegra_verify_speed(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+unsigned int tegra_getspeed(unsigned int cpu)
+{
+ unsigned long rate;
+
+ if (cpu >= NUM_CPUS)
+ return 0;
+
+ rate = clk_get_rate(cpu_clk) / 1000;
+ return rate;
+}
+
+static int tegra_update_cpu_speed(unsigned long rate)
+{
+ int ret = 0;
+ struct cpufreq_freqs freqs;
+
+ freqs.old = tegra_getspeed(0);
+ freqs.new = rate;
+
+ if (freqs.old == freqs.new)
+ return ret;
+
+ /*
+ * Vote on memory bus frequency based on cpu frequency
+ * This sets the minimum frequency, display or avp may request higher
+ */
+ if (rate >= 816000)
+ clk_set_rate(emc_clk, 600000000); /* cpu 816 MHz, emc max */
+ else if (rate >= 456000)
+ clk_set_rate(emc_clk, 300000000); /* cpu 456 MHz, emc 150Mhz */
+ else
+ clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */
+
+ for_each_online_cpu(freqs.cpu)
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+#ifdef CONFIG_CPU_FREQ_DEBUG
+ printk(KERN_DEBUG "cpufreq-tegra: transition: %u --> %u\n",
+ freqs.old, freqs.new);
#endif
+ ret = clk_set_rate(cpu_clk, freqs.new * 1000);
+ if (ret) {
+ pr_err("cpu-tegra: Failed to set cpu frequency to %d kHz\n",
+ freqs.new);
+ return ret;
+ }
+
+ for_each_online_cpu(freqs.cpu)
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ return 0;
+}
+
+static unsigned long tegra_cpu_highest_speed(void)
+{
+ unsigned long rate = 0;
+ int i;
+
+ for_each_online_cpu(i)
+ rate = max(rate, target_cpu_speed[i]);
+ return rate;
+}
+
+static int tegra_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ int idx;
+ unsigned int freq;
+ unsigned int new_speed;
+ int ret = 0;
+
+ mutex_lock(&tegra_cpu_lock);
+
+ if (is_suspended) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ cpufreq_frequency_table_target(policy, freq_table, target_freq,
+ relation, &idx);
+
+ freq = freq_table[idx].frequency;
+
+ target_cpu_speed[policy->cpu] = freq;
+
+ new_speed = tegra_cpu_highest_speed();
+
+ /* Do not go above this frequency when throttling */
+
+ if (tegra_cpu_is_throttling()) {
+ unsigned int throttle_limit =
+ freq_table[THROTTLE_START_INDEX].frequency;
+
+ if (new_speed > throttle_limit) {
+ if (tegra_getspeed(0) < throttle_limit) {
+ new_speed = throttle_limit;
+ } else {
+ ret = -EBUSY;
+ goto out;
+ }
+ }
+ }
+
+ ret = tegra_update_cpu_speed(new_speed);
+out:
+ mutex_unlock(&tegra_cpu_lock);
+ return ret;
+}
+
+
static int tegra_pm_notify(struct notifier_block *nb, unsigned long event,
void *dummy)
{
@@ -345,7 +357,6 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)
cpumask_copy(policy->related_cpus, cpu_possible_mask);
if (policy->cpu == 0) {
- INIT_DELAYED_WORK(&throttle_work, tegra_throttle_work_func);
register_pm_notifier(&tegra_cpu_pm_notifier);
}
@@ -378,15 +389,20 @@ static struct cpufreq_driver tegra_cpufreq_driver = {
static int __init tegra_cpufreq_init(void)
{
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
workqueue = create_singlethread_workqueue("cpu-tegra");
if (!workqueue)
return -ENOMEM;
+ INIT_DELAYED_WORK(&throttle_work, tegra_throttle_work_func);
+#endif
return cpufreq_register_driver(&tegra_cpufreq_driver);
}
static void __exit tegra_cpufreq_exit(void)
{
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
destroy_workqueue(workqueue);
+#endif
cpufreq_unregister_driver(&tegra_cpufreq_driver);
}