diff options
Diffstat (limited to 'extras/recipes-kernel/linux/linux-omap-2.6.39/pm')
34 files changed, 3447 insertions, 0 deletions
diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0001-OMAP2-cpufreq-free-up-table-on-exit.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0001-OMAP2-cpufreq-free-up-table-on-exit.patch new file mode 100644 index 00000000..9e9a8a0b --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0001-OMAP2-cpufreq-free-up-table-on-exit.patch @@ -0,0 +1,38 @@ +From 38dd5aadc86725f6018d23679e9daa60ca0a8319 Mon Sep 17 00:00:00 2001 +From: Nishanth Menon <nm@ti.com> +Date: Thu, 12 May 2011 07:59:52 -0500 +Subject: [PATCH 1/6] OMAP2+: cpufreq: free up table on exit + +freq_table allocated by opp_init_cpufreq_table in omap_cpu_init +needs to be freed in omap_cpu_exit. + +Signed-off-by: Nishanth Menon <nm@ti.com> +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/mach-omap2/omap2plus-cpufreq.c | 3 +++ + 1 files changed, 3 insertions(+), 0 deletions(-) + +diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c +index d53ce23..e38ebb8 100644 +--- a/arch/arm/mach-omap2/omap2plus-cpufreq.c ++++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c +@@ -26,6 +26,7 @@ + #include <linux/clk.h> + #include <linux/io.h> + #include <linux/opp.h> ++#include <linux/slab.h> + #include <linux/cpu.h> + + #include <asm/system.h> +@@ -216,6 +217,8 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) + static int omap_cpu_exit(struct cpufreq_policy *policy) + { + clk_exit_cpufreq_table(&freq_table); ++ kfree(freq_table); ++ freq_table = NULL; + clk_put(mpu_clk); + return 0; + } +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0002-OMAP2-cpufreq-handle-invalid-cpufreq-table.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0002-OMAP2-cpufreq-handle-invalid-cpufreq-table.patch new file mode 100644 index 00000000..087724d1 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0002-OMAP2-cpufreq-handle-invalid-cpufreq-table.patch @@ -0,0 +1,44 @@ +From 5febdc0482e545c2a598f035c5e03931e0c3c808 Mon Sep 17 00:00:00 2001 +From: Nishanth Menon <nm@ti.com> +Date: Thu, 12 May 2011 08:14:41 -0500 +Subject: [PATCH 2/6] OMAP2+: cpufreq: handle invalid cpufreq table + +Handle the case when cpufreq_frequency_table_cpuinfo fails. freq_table +that we passed failed the internal test of cpufreq generic driver, +so we should'nt be using the freq_table as such. Instead, warn and +fallback to clock functions for validation and operation. + +Signed-off-by: Nishanth Menon <nm@ti.com> +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/mach-omap2/omap2plus-cpufreq.c | 12 ++++++++++-- + 1 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c +index e38ebb8..6e3666a 100644 +--- a/arch/arm/mach-omap2/omap2plus-cpufreq.c ++++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c +@@ -182,10 +182,18 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) + + if (freq_table) { + result = cpufreq_frequency_table_cpuinfo(policy, freq_table); +- if (!result) ++ if (!result) { + cpufreq_frequency_table_get_attr(freq_table, + policy->cpu); +- } else { ++ } else { ++ WARN(true, "%s: fallback to clk_round(freq_table=%d)\n", ++ __func__, result); ++ kfree(freq_table); ++ freq_table = NULL; ++ } ++ } ++ ++ if (!freq_table) { + policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000; + policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, + VERY_HI_RATE) / 1000; +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0003-OMAP2-cpufreq-minor-comment-cleanup.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0003-OMAP2-cpufreq-minor-comment-cleanup.patch new file mode 100644 index 00000000..4f4cdb14 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0003-OMAP2-cpufreq-minor-comment-cleanup.patch @@ -0,0 +1,33 @@ +From aef7e862873e6125159a18d22a2e37b1fbab2153 Mon Sep 17 00:00:00 2001 +From: Nishanth Menon <nm@ti.com> +Date: Thu, 12 May 2011 16:27:45 -0700 +Subject: [PATCH 3/6] OMAP2+: cpufreq: minor comment cleanup + +this should probably get squashed in.. + +Signed-off-by: Nishanth Menon <nm@ti.com> +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/mach-omap2/omap2plus-cpufreq.c | 6 ++++-- + 1 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c +index 6e3666a..45f1e9e 100644 +--- a/arch/arm/mach-omap2/omap2plus-cpufreq.c ++++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c +@@ -84,8 +84,10 @@ static int omap_target(struct cpufreq_policy *policy, + if (is_smp() && (num_online_cpus() < NR_CPUS)) + return ret; + +- /* Ensure desired rate is within allowed range. Some govenors +- * (ondemand) will just pass target_freq=0 to get the minimum. */ ++ /* ++ * Ensure desired rate is within allowed range. Some govenors ++ * (ondemand) will just pass target_freq=0 to get the minimum. ++ */ + if (target_freq < policy->min) + target_freq = policy->min; + if (target_freq > policy->max) +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0004-OMAP2-cpufreq-use-clk_init_cpufreq_table-if-OPPs-not.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0004-OMAP2-cpufreq-use-clk_init_cpufreq_table-if-OPPs-not.patch new file mode 100644 index 00000000..dd23c082 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0004-OMAP2-cpufreq-use-clk_init_cpufreq_table-if-OPPs-not.patch @@ -0,0 +1,48 @@ +From f231980dbd0f05229f2020e59b7242872576416f Mon Sep 17 00:00:00 2001 +From: Nishanth Menon <nm@ti.com> +Date: Fri, 13 May 2011 05:34:35 -0700 +Subject: [PATCH 4/6] OMAP2: cpufreq: use clk_init_cpufreq_table if OPPs not available + +OMAP2 does not use OPP tables at the moment for DVFS. Currently, +we depend on opp table initialization to give us the freq_table, +which makes sense for OMAP3+. for OMAP2, we should be using +clk_init_cpufreq_table - so if the opp based frequency table +initilization fails, fall back to clk_init_cpufreq_table to give +us the table. + +Signed-off-by: Nishanth Menon <nm@ti.com> +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/mach-omap2/omap2plus-cpufreq.c | 9 ++++++++- + 1 files changed, 8 insertions(+), 1 deletions(-) + +diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c +index 45f1e9e..854f4b3 100644 +--- a/arch/arm/mach-omap2/omap2plus-cpufreq.c ++++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c +@@ -180,7 +180,13 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) + pr_warning("%s: unable to get the mpu device\n", __func__); + return -EINVAL; + } +- opp_init_cpufreq_table(mpu_dev, &freq_table); ++ ++ /* ++ * if we dont get cpufreq table using opp, use traditional omap2 lookup ++ * as a fallback ++ */ ++ if (opp_init_cpufreq_table(mpu_dev, &freq_table)) ++ clk_init_cpufreq_table(&freq_table); + + if (freq_table) { + result = cpufreq_frequency_table_cpuinfo(policy, freq_table); +@@ -188,6 +194,7 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) + cpufreq_frequency_table_get_attr(freq_table, + policy->cpu); + } else { ++ clk_exit_cpufreq_table(&freq_table); + WARN(true, "%s: fallback to clk_round(freq_table=%d)\n", + __func__, result); + kfree(freq_table); +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0005-OMAP2-cpufreq-use-cpufreq_frequency_table_target.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0005-OMAP2-cpufreq-use-cpufreq_frequency_table_target.patch new file mode 100644 index 00000000..504d1916 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0005-OMAP2-cpufreq-use-cpufreq_frequency_table_target.patch @@ -0,0 +1,78 @@ +From 272d76bcb22b9509ccc1b59d3a62e3930d902d17 Mon Sep 17 00:00:00 2001 +From: Nishanth Menon <nm@ti.com> +Date: Fri, 13 May 2011 05:43:49 -0700 +Subject: [PATCH 5/6] OMAP2+: cpufreq: use cpufreq_frequency_table_target + +Use cpufreq_frequency_table_target for finding the proper target +instead of seeing if the frequency requested is divisible alone. +if we have a frequency table, we should restrict ourselves to +selecting the "approved" frequencies alone and only in the case +where the frequency table is not available should we attempt at +closest roundable clock frequency. + +Signed-off-by: Nishanth Menon <nm@ti.com> +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/mach-omap2/omap2plus-cpufreq.c | 38 ++++++++++++++++++++++-------- + 1 files changed, 28 insertions(+), 10 deletions(-) + +diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c +index 854f4b3..d0b4f97 100644 +--- a/arch/arm/mach-omap2/omap2plus-cpufreq.c ++++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c +@@ -77,24 +77,42 @@ static int omap_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) + { +- int i, ret = 0; ++ unsigned int i; ++ int ret = 0; + struct cpufreq_freqs freqs; + + /* Changes not allowed until all CPUs are online */ + if (is_smp() && (num_online_cpus() < NR_CPUS)) + return ret; + +- /* +- * Ensure desired rate is within allowed range. Some govenors +- * (ondemand) will just pass target_freq=0 to get the minimum. +- */ +- if (target_freq < policy->min) +- target_freq = policy->min; +- if (target_freq > policy->max) +- target_freq = policy->max; ++ if (freq_table) { ++ ret = cpufreq_frequency_table_target(policy, freq_table, ++ target_freq, relation, &i); ++ if (ret) { ++ pr_debug("%s: cpu%d: no freq match for %d(ret=%d)\n", ++ __func__, policy->cpu, target_freq, ret); ++ return ret; ++ } ++ freqs.new = freq_table[i].frequency; ++ } else { ++ /* ++ * Ensure desired rate is within allowed range. Some govenors ++ * (ondemand) will just pass target_freq=0 to get the minimum. ++ */ ++ if (target_freq < policy->min) ++ target_freq = policy->min; ++ if (target_freq > policy->max) ++ target_freq = policy->max; ++ ++ freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000; ++ } ++ if (!freqs.new) { ++ pr_err("%s: cpu%d: no match for freq %d\n", __func__, ++ policy->cpu, target_freq); ++ return -EINVAL; ++ } + + freqs.old = omap_getspeed(policy->cpu); +- freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000; + freqs.cpu = policy->cpu; + + if (freqs.old == freqs.new) +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0006-OMAP2-cpufreq-fix-freq_table-leak.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0006-OMAP2-cpufreq-fix-freq_table-leak.patch new file mode 100644 index 00000000..0cb4c91f --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0006-OMAP2-cpufreq-fix-freq_table-leak.patch @@ -0,0 +1,100 @@ +From 42a384af80e07534913d9002ec8d9caf5d4d305c Mon Sep 17 00:00:00 2001 +From: Nishanth Menon <nm@ti.com> +Date: Wed, 18 May 2011 01:48:23 -0500 +Subject: [PATCH 6/6] OMAP2+: cpufreq: fix freq_table leak + +Since we have two cpus the cpuinit call for cpu1 causes +freq_table of cpu0 to be overwritten. instead, we maintain +a counter to keep track of cpus who use the cpufreq table +allocate it once(one freq table for all CPUs) and free them +once the last user is done with it. + +Signed-off-by: Nishanth Menon <nm@ti.com> +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/mach-omap2/omap2plus-cpufreq.c | 33 ++++++++++++++++++++++++------ + 1 files changed, 26 insertions(+), 7 deletions(-) + +diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c +index d0b4f97..fc3d0fb 100644 +--- a/arch/arm/mach-omap2/omap2plus-cpufreq.c ++++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c +@@ -42,6 +42,9 @@ + #define VERY_HI_RATE 900000000 + + static struct cpufreq_frequency_table *freq_table; ++static int freq_table_users; ++static DEFINE_MUTEX(freq_table_lock); ++ + static struct clk *mpu_clk; + + static int omap_verify_speed(struct cpufreq_policy *policy) +@@ -172,6 +175,18 @@ skip_lpj: + return ret; + } + ++static void freq_table_free(void) ++{ ++ if (!freq_table_users) ++ return; ++ freq_table_users--; ++ if (freq_table_users) ++ return; ++ clk_exit_cpufreq_table(&freq_table); ++ kfree(freq_table); ++ freq_table = NULL; ++} ++ + static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) + { + int result = 0; +@@ -199,14 +214,18 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) + return -EINVAL; + } + ++ mutex_lock(&freq_table_lock); + /* + * if we dont get cpufreq table using opp, use traditional omap2 lookup + * as a fallback + */ +- if (opp_init_cpufreq_table(mpu_dev, &freq_table)) +- clk_init_cpufreq_table(&freq_table); ++ if (!freq_table) { ++ if (opp_init_cpufreq_table(mpu_dev, &freq_table)) ++ clk_init_cpufreq_table(&freq_table); ++ } + + if (freq_table) { ++ freq_table_users++; + result = cpufreq_frequency_table_cpuinfo(policy, freq_table); + if (!result) { + cpufreq_frequency_table_get_attr(freq_table, +@@ -215,10 +234,10 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) + clk_exit_cpufreq_table(&freq_table); + WARN(true, "%s: fallback to clk_round(freq_table=%d)\n", + __func__, result); +- kfree(freq_table); +- freq_table = NULL; ++ freq_table_free(); + } + } ++ mutex_unlock(&freq_table_lock); + + if (!freq_table) { + policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000; +@@ -251,9 +270,9 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) + + static int omap_cpu_exit(struct cpufreq_policy *policy) + { +- clk_exit_cpufreq_table(&freq_table); +- kfree(freq_table); +- freq_table = NULL; ++ mutex_lock(&freq_table_lock); ++ freq_table_free(); ++ mutex_unlock(&freq_table_lock); + clk_put(mpu_clk); + return 0; + } +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-hotplug/0001-cpufreq-helpers-for-walking-the-frequency-table.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-hotplug/0001-cpufreq-helpers-for-walking-the-frequency-table.patch new file mode 100644 index 00000000..576cd08f --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-hotplug/0001-cpufreq-helpers-for-walking-the-frequency-table.patch @@ -0,0 +1,134 @@ +From 8726f3a7218b72a1003904a24bb000b3e4f9b4d1 Mon Sep 17 00:00:00 2001 +From: Mike Turquette <mturquette@ti.com> +Date: Tue, 17 May 2011 09:35:54 -0500 +Subject: [PATCH 1/2] cpufreq: helpers for walking the frequency table + +Two new functions for getting the next higher and next lower frequencies +in the cpufreq table, based upon a frequency supplied in kHz. + +This is useful for cpufreq governors that do not target frequencies +based upon a percentage or a pre-determined value, but instead access +the cpufreq table directly. + +Signed-off-by: Mike Turquette <mturquette@ti.com> +Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com> +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + drivers/cpufreq/freq_table.c | 73 ++++++++++++++++++++++++++++++++++++++++++ + include/linux/cpufreq.h | 9 +++++ + 2 files changed, 82 insertions(+), 0 deletions(-) + +diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c +index 0543221..11a307b 100644 +--- a/drivers/cpufreq/freq_table.c ++++ b/drivers/cpufreq/freq_table.c +@@ -13,6 +13,7 @@ + #include <linux/module.h> + #include <linux/init.h> + #include <linux/cpufreq.h> ++#include <linux/err.h> + + #define dprintk(msg...) \ + cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "freq-table", msg) +@@ -174,6 +175,78 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, + } + EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target); + ++int cpufreq_frequency_table_next_lowest(struct cpufreq_policy *policy, ++ struct cpufreq_frequency_table *table, int *index) ++{ ++ unsigned int cur_freq; ++ unsigned int next_lowest_freq; ++ int optimal_index = -1; ++ int i = 0; ++ ++ if (!policy || IS_ERR(policy) || !table || IS_ERR(table) || ++ !index || IS_ERR(index)) ++ return -ENOMEM; ++ ++ cur_freq = policy->cur; ++ next_lowest_freq = policy->min; ++ ++ /* we're at the lowest frequency in the table already, bail out */ ++ if (cur_freq == policy->min) ++ return -EINVAL; ++ ++ /* walk the list, find closest freq to cur_freq that is below it */ ++ while(table[i].frequency != CPUFREQ_TABLE_END) { ++ if (table[i].frequency < cur_freq && ++ table[i].frequency >= next_lowest_freq) { ++ next_lowest_freq = table[i].frequency; ++ optimal_index = table[i].index; ++ } ++ ++ i++; ++ } ++ ++ *index = optimal_index; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(cpufreq_frequency_table_next_lowest); ++ ++int cpufreq_frequency_table_next_highest(struct cpufreq_policy *policy, ++ struct cpufreq_frequency_table *table, int *index) ++{ ++ unsigned int cur_freq; ++ unsigned int next_higher_freq; ++ int optimal_index = -1; ++ int i = 0; ++ ++ if (!policy || IS_ERR(policy) || !table || IS_ERR(table) || ++ !index || IS_ERR(index)) ++ return -ENOMEM; ++ ++ cur_freq = policy->cur; ++ next_higher_freq = policy->max; ++ ++ /* we're at the highest frequency in the table already, bail out */ ++ if (cur_freq == policy->max) ++ return -EINVAL; ++ ++ /* walk the list, find closest freq to cur_freq that is above it */ ++ while(table[i].frequency != CPUFREQ_TABLE_END) { ++ if (table[i].frequency > cur_freq && ++ table[i].frequency <= next_higher_freq) { ++ next_higher_freq = table[i].frequency; ++ optimal_index = table[i].index; ++ } ++ ++ i++; ++ } ++ ++ *index = optimal_index; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(cpufreq_frequency_table_next_highest); ++ + static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table); + /** + * show_available_freqs - show available frequencies for the specified CPU +diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h +index 9343dd3..a38fca8 100644 +--- a/include/linux/cpufreq.h ++++ b/include/linux/cpufreq.h +@@ -396,6 +396,15 @@ void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table, + + void cpufreq_frequency_table_put_attr(unsigned int cpu); + ++/* the following are for use in governors, or anywhere else */ ++extern int cpufreq_frequency_table_next_lowest(struct cpufreq_policy *policy, ++ struct cpufreq_frequency_table *table, ++ int *index); ++ ++extern int cpufreq_frequency_table_next_highest(struct cpufreq_policy *policy, ++ struct cpufreq_frequency_table *table, ++ int *index); ++ + + /********************************************************************* + * UNIFIED DEBUG HELPERS * +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-hotplug/0002-cpufreq-introduce-hotplug-governor.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-hotplug/0002-cpufreq-introduce-hotplug-governor.patch new file mode 100644 index 00000000..731906cc --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-hotplug/0002-cpufreq-introduce-hotplug-governor.patch @@ -0,0 +1,879 @@ +From e4c777d8314d7925e4895f00b3a7ebd64a4d830b Mon Sep 17 00:00:00 2001 +From: Mike Turquette <mturquette@ti.com> +Date: Tue, 17 May 2011 09:43:09 -0500 +Subject: [PATCH 2/2] cpufreq: introduce hotplug governor + +The "hotplug" governor scales CPU frequency based on load, similar to +"ondemand". It scales up to the highest frequency when "up_threshold" +is crossed and scales down one frequency at a time when "down_threshold" +is crossed. Unlike those governors, target frequencies are determined +by directly accessing the CPUfreq frequency table, instead of taking +some percentage of maximum available frequency. + +The key difference in the "hotplug" governor is that it will disable +auxillary CPUs when the system is very idle, and enable them again once +the system becomes busy. This is achieved by averaging load over +multiple sampling periods; if CPUs were online or offlined based on a +single sampling period then thrashing will occur. + +Sysfs entries exist for "hotplug_in_sampling_periods" and for +"hotplug_out_sampling_periods" which determine how many consecutive +periods get averaged to determine if auxillery CPUs should be onlined or +offlined. Defaults are 5 periods and 20 periods respectively. +Otherwise the standard sysfs entries you might find for "ondemand" and +"conservative" governors are there. + +To use this governor it is assumed that your CPUfreq driver has +populated the CPUfreq table, CONFIG_NO_HZ is enabled and +CONFIG_HOTPLUG_CPU is enabled. + +Changes in V2: + Corrected default sampling periods + Optimized load history array resizing + Maintain load history when resizing array + Add locking to dbs_check_cpu + Switch from enable_nonboot_cpus to cpu_up + Switch from disable_nonboot_cpus to down_cpu + Fix some printks + Coding style around for-loops + +Signed-off-by: Mike Turquette <mturquette@ti.com> +Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com> +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + Documentation/cpu-freq/governors.txt | 28 ++ + drivers/cpufreq/Kconfig | 33 ++ + drivers/cpufreq/Makefile | 1 + + drivers/cpufreq/cpufreq_hotplug.c | 705 ++++++++++++++++++++++++++++++++++ + include/linux/cpufreq.h | 3 + + 5 files changed, 770 insertions(+), 0 deletions(-) + create mode 100644 drivers/cpufreq/cpufreq_hotplug.c + +diff --git a/Documentation/cpu-freq/governors.txt b/Documentation/cpu-freq/governors.txt +index e74d0a2..c2e3d3d 100644 +--- a/Documentation/cpu-freq/governors.txt ++++ b/Documentation/cpu-freq/governors.txt +@@ -193,6 +193,34 @@ governor but for the opposite direction. For example when set to its + default value of '20' it means that if the CPU usage needs to be below + 20% between samples to have the frequency decreased. + ++ ++2.6 Hotplug ++----------- ++ ++The CPUfreq governor "hotplug" operates similary to "ondemand" and ++"conservative". It's decisions are based primarily on CPU load. Like ++"ondemand" the "hotplug" governor will ramp up to the highest frequency ++once the run-time tunable "up_threshold" parameter is crossed. Like ++"conservative", the "hotplug" governor exports a "down_threshold" ++parameter that is also tunable at run-time. When the "down_threshold" ++is crossed the CPU transitions to the next lowest frequency in the ++CPUfreq frequency table instead of decrementing the frequency based on a ++percentage of maximum load. ++ ++The main reason "hotplug" governor exists is for architectures requiring ++that only the master CPU be online in order to hit low-power states ++(C-states). OMAP4 is one such example of this. The "hotplug" governor ++is also helpful in reducing thermal output in devices with tight thermal ++constraints. ++ ++Auxillary CPUs are onlined/offline based on CPU load, but the decision ++to do so is made after averaging several sampling windows. This is to ++reduce CPU hotplug "thrashing", which can be caused by normal system ++entropy and leads to lots of spurious plug-in and plug-out transitions. ++The number of sampling periods averaged together is tunable via the ++"hotplug_in_sampling_periods" and "hotplug_out_sampling_periods" ++run-time tunable parameters. ++ + 3. The Governor Interface in the CPUfreq Core + ============================================= + +diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig +index ca8ee80..c716a0e 100644 +--- a/drivers/cpufreq/Kconfig ++++ b/drivers/cpufreq/Kconfig +@@ -110,6 +110,19 @@ config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE + Be aware that not all cpufreq drivers support the conservative + governor. If unsure have a look at the help section of the + driver. Fallback governor will be the performance governor. ++ ++config CPU_FREQ_DEFAULT_GOV_HOTPLUG ++ bool "hotplug" ++ select CPU_FREQ_GOV_HOTPLUG ++ select CPU_FREQ_GOV_PERFORMANCE ++ help ++ Use the CPUFreq governor 'hotplug' as default. This allows you ++ to get a full dynamic frequency capable system with CPU ++ hotplug support by simply loading your cpufreq low-level ++ hardware driver. Be aware that not all cpufreq drivers ++ support the hotplug governor. If unsure have a look at ++ the help section of the driver. Fallback governor will be the ++ performance governor. + endchoice + + config CPU_FREQ_GOV_PERFORMANCE +@@ -190,4 +203,24 @@ config CPU_FREQ_GOV_CONSERVATIVE + + If in doubt, say N. + ++config CPU_FREQ_GOV_HOTPLUG ++ tristate "'hotplug' cpufreq governor" ++ depends on CPU_FREQ && NO_HZ && HOTPLUG_CPU ++ help ++ 'hotplug' - this driver mimics the frequency scaling behavior ++ in 'ondemand', but with several key differences. First is ++ that frequency transitions use the CPUFreq table directly, ++ instead of incrementing in a percentage of the maximum ++ available frequency. Second 'hotplug' will offline auxillary ++ CPUs when the system is idle, and online those CPUs once the ++ system becomes busy again. This last feature is needed for ++ architectures which transition to low power states when only ++ the "master" CPU is online, or for thermally constrained ++ devices. ++ ++ If you don't have one of these architectures or devices, use ++ 'ondemand' instead. ++ ++ If in doubt, say N. ++ + endif # CPU_FREQ +diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile +index 71fc3b4..05d564c 100644 +--- a/drivers/cpufreq/Makefile ++++ b/drivers/cpufreq/Makefile +@@ -9,6 +9,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o + obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o + obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o + obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o ++obj-$(CONFIG_CPU_FREQ_GOV_HOTPLUG) += cpufreq_hotplug.o + + # CPUfreq cross-arch helpers + obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o +diff --git a/drivers/cpufreq/cpufreq_hotplug.c b/drivers/cpufreq/cpufreq_hotplug.c +new file mode 100644 +index 0000000..85aa6d2 +--- /dev/null ++++ b/drivers/cpufreq/cpufreq_hotplug.c +@@ -0,0 +1,705 @@ ++/* ++ * CPUFreq hotplug governor ++ * ++ * Copyright (C) 2010 Texas Instruments, Inc. ++ * Mike Turquette <mturquette@ti.com> ++ * Santosh Shilimkar <santosh.shilimkar@ti.com> ++ * ++ * Based on ondemand governor ++ * Copyright (C) 2001 Russell King ++ * (C) 2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>, ++ * Jun Nakajima <jun.nakajima@intel.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/cpufreq.h> ++#include <linux/cpu.h> ++#include <linux/jiffies.h> ++#include <linux/kernel_stat.h> ++#include <linux/mutex.h> ++#include <linux/hrtimer.h> ++#include <linux/tick.h> ++#include <linux/ktime.h> ++#include <linux/sched.h> ++#include <linux/err.h> ++#include <linux/slab.h> ++ ++/* greater than 80% avg load across online CPUs increases frequency */ ++#define DEFAULT_UP_FREQ_MIN_LOAD (80) ++ ++/* less than 20% avg load across online CPUs decreases frequency */ ++#define DEFAULT_DOWN_FREQ_MAX_LOAD (20) ++ ++/* default sampling period (uSec) is bogus; 10x ondemand's default for x86 */ ++#define DEFAULT_SAMPLING_PERIOD (100000) ++ ++/* default number of sampling periods to average before hotplug-in decision */ ++#define DEFAULT_HOTPLUG_IN_SAMPLING_PERIODS (5) ++ ++/* default number of sampling periods to average before hotplug-out decision */ ++#define DEFAULT_HOTPLUG_OUT_SAMPLING_PERIODS (20) ++ ++static void do_dbs_timer(struct work_struct *work); ++static int cpufreq_governor_dbs(struct cpufreq_policy *policy, ++ unsigned int event); ++ ++#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_HOTPLUG ++static ++#endif ++struct cpufreq_governor cpufreq_gov_hotplug = { ++ .name = "hotplug", ++ .governor = cpufreq_governor_dbs, ++ .owner = THIS_MODULE, ++}; ++ ++struct cpu_dbs_info_s { ++ cputime64_t prev_cpu_idle; ++ cputime64_t prev_cpu_wall; ++ cputime64_t prev_cpu_nice; ++ struct cpufreq_policy *cur_policy; ++ struct delayed_work work; ++ struct cpufreq_frequency_table *freq_table; ++ int cpu; ++ /* ++ * percpu mutex that serializes governor limit change with ++ * do_dbs_timer invocation. We do not want do_dbs_timer to run ++ * when user is changing the governor or limits. ++ */ ++ struct mutex timer_mutex; ++}; ++static DEFINE_PER_CPU(struct cpu_dbs_info_s, hp_cpu_dbs_info); ++ ++static unsigned int dbs_enable; /* number of CPUs using this policy */ ++ ++/* ++ * dbs_mutex protects data in dbs_tuners_ins from concurrent changes on ++ * different CPUs. It protects dbs_enable in governor start/stop. ++ */ ++static DEFINE_MUTEX(dbs_mutex); ++ ++static struct workqueue_struct *khotplug_wq; ++ ++static struct dbs_tuners { ++ unsigned int sampling_rate; ++ unsigned int up_threshold; ++ unsigned int down_threshold; ++ unsigned int hotplug_in_sampling_periods; ++ unsigned int hotplug_out_sampling_periods; ++ unsigned int hotplug_load_index; ++ unsigned int *hotplug_load_history; ++ unsigned int ignore_nice; ++ unsigned int io_is_busy; ++} dbs_tuners_ins = { ++ .sampling_rate = DEFAULT_SAMPLING_PERIOD, ++ .up_threshold = DEFAULT_UP_FREQ_MIN_LOAD, ++ .down_threshold = DEFAULT_DOWN_FREQ_MAX_LOAD, ++ .hotplug_in_sampling_periods = DEFAULT_HOTPLUG_IN_SAMPLING_PERIODS, ++ .hotplug_out_sampling_periods = DEFAULT_HOTPLUG_OUT_SAMPLING_PERIODS, ++ .hotplug_load_index = 0, ++ .ignore_nice = 0, ++ .io_is_busy = 0, ++}; ++ ++/* ++ * A corner case exists when switching io_is_busy at run-time: comparing idle ++ * times from a non-io_is_busy period to an io_is_busy period (or vice-versa) ++ * will misrepresent the actual change in system idleness. We ignore this ++ * corner case: enabling io_is_busy might cause freq increase and disabling ++ * might cause freq decrease, which probably matches the original intent. ++ */ ++static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall) ++{ ++ u64 idle_time; ++ u64 iowait_time; ++ ++ /* cpufreq-hotplug always assumes CONFIG_NO_HZ */ ++ idle_time = get_cpu_idle_time_us(cpu, wall); ++ ++ /* add time spent doing I/O to idle time */ ++ if (dbs_tuners_ins.io_is_busy) { ++ iowait_time = get_cpu_iowait_time_us(cpu, wall); ++ /* cpufreq-hotplug always assumes CONFIG_NO_HZ */ ++ if (iowait_time != -1ULL && idle_time >= iowait_time) ++ idle_time -= iowait_time; ++ } ++ ++ return idle_time; ++} ++ ++/************************** sysfs interface ************************/ ++ ++/* XXX look at global sysfs macros in cpufreq.h, can those be used here? */ ++ ++/* cpufreq_hotplug Governor Tunables */ ++#define show_one(file_name, object) \ ++static ssize_t show_##file_name \ ++(struct kobject *kobj, struct attribute *attr, char *buf) \ ++{ \ ++ return sprintf(buf, "%u\n", dbs_tuners_ins.object); \ ++} ++show_one(sampling_rate, sampling_rate); ++show_one(up_threshold, up_threshold); ++show_one(down_threshold, down_threshold); ++show_one(hotplug_in_sampling_periods, hotplug_in_sampling_periods); ++show_one(hotplug_out_sampling_periods, hotplug_out_sampling_periods); ++show_one(ignore_nice_load, ignore_nice); ++show_one(io_is_busy, io_is_busy); ++ ++static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b, ++ const char *buf, size_t count) ++{ ++ unsigned int input; ++ int ret; ++ ret = sscanf(buf, "%u", &input); ++ if (ret != 1) ++ return -EINVAL; ++ ++ mutex_lock(&dbs_mutex); ++ dbs_tuners_ins.sampling_rate = input; ++ mutex_unlock(&dbs_mutex); ++ ++ return count; ++} ++ ++static ssize_t store_up_threshold(struct kobject *a, struct attribute *b, ++ const char *buf, size_t count) ++{ ++ unsigned int input; ++ int ret; ++ ret = sscanf(buf, "%u", &input); ++ ++ if (ret != 1 || input <= dbs_tuners_ins.down_threshold) { ++ return -EINVAL; ++ } ++ ++ mutex_lock(&dbs_mutex); ++ dbs_tuners_ins.up_threshold = input; ++ mutex_unlock(&dbs_mutex); ++ ++ return count; ++} ++ ++static ssize_t store_down_threshold(struct kobject *a, struct attribute *b, ++ const char *buf, size_t count) ++{ ++ unsigned int input; ++ int ret; ++ ret = sscanf(buf, "%u", &input); ++ ++ if (ret != 1 || input >= dbs_tuners_ins.up_threshold) { ++ return -EINVAL; ++ } ++ ++ mutex_lock(&dbs_mutex); ++ dbs_tuners_ins.down_threshold = input; ++ mutex_unlock(&dbs_mutex); ++ ++ return count; ++} ++ ++static ssize_t store_hotplug_in_sampling_periods(struct kobject *a, ++ struct attribute *b, const char *buf, size_t count) ++{ ++ unsigned int input; ++ unsigned int *temp; ++ unsigned int max_windows; ++ int ret; ++ ret = sscanf(buf, "%u", &input); ++ ++ if (ret != 1) ++ return -EINVAL; ++ ++ /* already using this value, bail out */ ++ if (input == dbs_tuners_ins.hotplug_in_sampling_periods) ++ return count; ++ ++ mutex_lock(&dbs_mutex); ++ ret = count; ++ max_windows = max(dbs_tuners_ins.hotplug_in_sampling_periods, ++ dbs_tuners_ins.hotplug_out_sampling_periods); ++ ++ /* no need to resize array */ ++ if (input <= max_windows) { ++ dbs_tuners_ins.hotplug_in_sampling_periods = input; ++ goto out; ++ } ++ ++ /* resize array */ ++ temp = kmalloc((sizeof(unsigned int) * input), GFP_KERNEL); ++ ++ if (!temp || IS_ERR(temp)) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ memcpy(temp, dbs_tuners_ins.hotplug_load_history, ++ (max_windows * sizeof(unsigned int))); ++ kfree(dbs_tuners_ins.hotplug_load_history); ++ ++ /* replace old buffer, old number of sampling periods & old index */ ++ dbs_tuners_ins.hotplug_load_history = temp; ++ dbs_tuners_ins.hotplug_in_sampling_periods = input; ++ dbs_tuners_ins.hotplug_load_index = max_windows; ++out: ++ mutex_unlock(&dbs_mutex); ++ ++ return ret; ++} ++ ++static ssize_t store_hotplug_out_sampling_periods(struct kobject *a, ++ struct attribute *b, const char *buf, size_t count) ++{ ++ unsigned int input; ++ unsigned int *temp; ++ unsigned int max_windows; ++ int ret; ++ ret = sscanf(buf, "%u", &input); ++ ++ if (ret != 1) ++ return -EINVAL; ++ ++ /* already using this value, bail out */ ++ if (input == dbs_tuners_ins.hotplug_out_sampling_periods) ++ return count; ++ ++ mutex_lock(&dbs_mutex); ++ ret = count; ++ max_windows = max(dbs_tuners_ins.hotplug_in_sampling_periods, ++ dbs_tuners_ins.hotplug_out_sampling_periods); ++ ++ /* no need to resize array */ ++ if (input <= max_windows) { ++ dbs_tuners_ins.hotplug_out_sampling_periods = input; ++ goto out; ++ } ++ ++ /* resize array */ ++ temp = kmalloc((sizeof(unsigned int) * input), GFP_KERNEL); ++ ++ if (!temp || IS_ERR(temp)) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ memcpy(temp, dbs_tuners_ins.hotplug_load_history, ++ (max_windows * sizeof(unsigned int))); ++ kfree(dbs_tuners_ins.hotplug_load_history); ++ ++ /* replace old buffer, old number of sampling periods & old index */ ++ dbs_tuners_ins.hotplug_load_history = temp; ++ dbs_tuners_ins.hotplug_out_sampling_periods = input; ++ dbs_tuners_ins.hotplug_load_index = max_windows; ++out: ++ mutex_unlock(&dbs_mutex); ++ ++ return ret; ++} ++ ++static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b, ++ const char *buf, size_t count) ++{ ++ unsigned int input; ++ int ret; ++ ++ unsigned int j; ++ ++ ret = sscanf(buf, "%u", &input); ++ if (ret != 1) ++ return -EINVAL; ++ ++ if (input > 1) ++ input = 1; ++ ++ mutex_lock(&dbs_mutex); ++ if (input == dbs_tuners_ins.ignore_nice) { /* nothing to do */ ++ mutex_unlock(&dbs_mutex); ++ return count; ++ } ++ dbs_tuners_ins.ignore_nice = input; ++ ++ /* we need to re-evaluate prev_cpu_idle */ ++ for_each_online_cpu(j) { ++ struct cpu_dbs_info_s *dbs_info; ++ dbs_info = &per_cpu(hp_cpu_dbs_info, j); ++ dbs_info->prev_cpu_idle = get_cpu_idle_time(j, ++ &dbs_info->prev_cpu_wall); ++ if (dbs_tuners_ins.ignore_nice) ++ dbs_info->prev_cpu_nice = kstat_cpu(j).cpustat.nice; ++ ++ } ++ mutex_unlock(&dbs_mutex); ++ ++ return count; ++} ++ ++static ssize_t store_io_is_busy(struct kobject *a, struct attribute *b, ++ const char *buf, size_t count) ++{ ++ unsigned int input; ++ int ret; ++ ++ ret = sscanf(buf, "%u", &input); ++ if (ret != 1) ++ return -EINVAL; ++ ++ mutex_lock(&dbs_mutex); ++ dbs_tuners_ins.io_is_busy = !!input; ++ mutex_unlock(&dbs_mutex); ++ ++ return count; ++} ++ ++define_one_global_rw(sampling_rate); ++define_one_global_rw(up_threshold); ++define_one_global_rw(down_threshold); ++define_one_global_rw(hotplug_in_sampling_periods); ++define_one_global_rw(hotplug_out_sampling_periods); ++define_one_global_rw(ignore_nice_load); ++define_one_global_rw(io_is_busy); ++ ++static struct attribute *dbs_attributes[] = { ++ &sampling_rate.attr, ++ &up_threshold.attr, ++ &down_threshold.attr, ++ &hotplug_in_sampling_periods.attr, ++ &hotplug_out_sampling_periods.attr, ++ &ignore_nice_load.attr, ++ &io_is_busy.attr, ++ NULL ++}; ++ ++static struct attribute_group dbs_attr_group = { ++ .attrs = dbs_attributes, ++ .name = "hotplug", ++}; ++ ++/************************** sysfs end ************************/ ++ ++static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info) ++{ ++ /* combined load of all enabled CPUs */ ++ unsigned int total_load = 0; ++ /* single largest CPU load */ ++ unsigned int max_load = 0; ++ /* average load across all enabled CPUs */ ++ unsigned int avg_load = 0; ++ /* average load across multiple sampling periods for hotplug events */ ++ unsigned int hotplug_in_avg_load = 0; ++ unsigned int hotplug_out_avg_load = 0; ++ /* number of sampling periods averaged for hotplug decisions */ ++ unsigned int periods; ++ ++ struct cpufreq_policy *policy; ++ unsigned int index = 0; ++ unsigned int i, j; ++ ++ policy = this_dbs_info->cur_policy; ++ ++ /* ++ * cpu load accounting ++ * get highest load, total load and average load across all CPUs ++ */ ++ for_each_cpu(j, policy->cpus) { ++ unsigned int load; ++ unsigned int idle_time, wall_time; ++ cputime64_t cur_wall_time, cur_idle_time; ++ struct cpu_dbs_info_s *j_dbs_info; ++ ++ j_dbs_info = &per_cpu(hp_cpu_dbs_info, j); ++ ++ /* update both cur_idle_time and cur_wall_time */ ++ cur_idle_time = get_cpu_idle_time(j, &cur_wall_time); ++ ++ /* how much wall time has passed since last iteration? */ ++ wall_time = (unsigned int) cputime64_sub(cur_wall_time, ++ j_dbs_info->prev_cpu_wall); ++ j_dbs_info->prev_cpu_wall = cur_wall_time; ++ ++ /* how much idle time has passed since last iteration? */ ++ idle_time = (unsigned int) cputime64_sub(cur_idle_time, ++ j_dbs_info->prev_cpu_idle); ++ j_dbs_info->prev_cpu_idle = cur_idle_time; ++ ++ if (unlikely(!wall_time || wall_time < idle_time)) ++ continue; ++ ++ /* load is the percentage of time not spent in idle */ ++ load = 100 * (wall_time - idle_time) / wall_time; ++ ++ /* keep track of combined load across all CPUs */ ++ total_load += load; ++ ++ /* keep track of highest single load across all CPUs */ ++ if (load > max_load) ++ max_load = load; ++ } ++ ++ /* calculate the average load across all related CPUs */ ++ avg_load = total_load / num_online_cpus(); ++ ++ ++ /* ++ * hotplug load accounting ++ * average load over multiple sampling periods ++ */ ++ ++ /* how many sampling periods do we use for hotplug decisions? */ ++ periods = max(dbs_tuners_ins.hotplug_in_sampling_periods, ++ dbs_tuners_ins.hotplug_out_sampling_periods); ++ ++ /* store avg_load in the circular buffer */ ++ dbs_tuners_ins.hotplug_load_history[dbs_tuners_ins.hotplug_load_index] ++ = avg_load; ++ ++ /* compute average load across in & out sampling periods */ ++ for (i = 0, j = dbs_tuners_ins.hotplug_load_index; ++ i < periods; i++, j--) { ++ if (i < dbs_tuners_ins.hotplug_in_sampling_periods) ++ hotplug_in_avg_load += ++ dbs_tuners_ins.hotplug_load_history[j]; ++ if (i < dbs_tuners_ins.hotplug_out_sampling_periods) ++ hotplug_out_avg_load += ++ dbs_tuners_ins.hotplug_load_history[j]; ++ ++ if (j == 0) ++ j = periods; ++ } ++ ++ hotplug_in_avg_load = hotplug_in_avg_load / ++ dbs_tuners_ins.hotplug_in_sampling_periods; ++ ++ hotplug_out_avg_load = hotplug_out_avg_load / ++ dbs_tuners_ins.hotplug_out_sampling_periods; ++ ++ /* return to first element if we're at the circular buffer's end */ ++ if (++dbs_tuners_ins.hotplug_load_index == periods) ++ dbs_tuners_ins.hotplug_load_index = 0; ++ ++ /* check for frequency increase */ ++ if (avg_load > dbs_tuners_ins.up_threshold) { ++ /* should we enable auxillary CPUs? */ ++ if (num_online_cpus() < 2 && hotplug_in_avg_load > ++ dbs_tuners_ins.up_threshold) { ++ /* hotplug with cpufreq is nasty ++ * a call to cpufreq_governor_dbs may cause a lockup. ++ * wq is not running here so its safe. ++ */ ++ mutex_unlock(&this_dbs_info->timer_mutex); ++ cpu_up(1); ++ mutex_lock(&this_dbs_info->timer_mutex); ++ goto out; ++ } ++ ++ /* increase to highest frequency supported */ ++ if (policy->cur < policy->max) ++ __cpufreq_driver_target(policy, policy->max, ++ CPUFREQ_RELATION_H); ++ ++ goto out; ++ } ++ ++ /* check for frequency decrease */ ++ if (avg_load < dbs_tuners_ins.down_threshold) { ++ /* are we at the minimum frequency already? */ ++ if (policy->cur == policy->min) { ++ /* should we disable auxillary CPUs? */ ++ if (num_online_cpus() > 1 && hotplug_out_avg_load < ++ dbs_tuners_ins.down_threshold) { ++ mutex_unlock(&this_dbs_info->timer_mutex); ++ cpu_down(1); ++ mutex_lock(&this_dbs_info->timer_mutex); ++ } ++ goto out; ++ } ++ ++ /* bump down to the next lowest frequency in the table */ ++ if (cpufreq_frequency_table_next_lowest(policy, ++ this_dbs_info->freq_table, &index)) { ++ pr_err("%s: failed to get next lowest frequency\n", ++ __func__); ++ goto out; ++ } ++ ++ __cpufreq_driver_target(policy, ++ this_dbs_info->freq_table[index].frequency, ++ CPUFREQ_RELATION_L); ++ } ++out: ++ return; ++} ++ ++static void do_dbs_timer(struct work_struct *work) ++{ ++ struct cpu_dbs_info_s *dbs_info = ++ container_of(work, struct cpu_dbs_info_s, work.work); ++ unsigned int cpu = dbs_info->cpu; ++ ++ /* We want all related CPUs to do sampling nearly on same jiffy */ ++ int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); ++ ++ mutex_lock(&dbs_info->timer_mutex); ++ dbs_check_cpu(dbs_info); ++ queue_delayed_work_on(cpu, khotplug_wq, &dbs_info->work, delay); ++ mutex_unlock(&dbs_info->timer_mutex); ++} ++ ++static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info) ++{ ++ /* We want all related CPUs to do sampling nearly on same jiffy */ ++ int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); ++ delay -= jiffies % delay; ++ ++ INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer); ++ queue_delayed_work_on(dbs_info->cpu, khotplug_wq, &dbs_info->work, ++ delay); ++} ++ ++static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info) ++{ ++ cancel_delayed_work_sync(&dbs_info->work); ++} ++ ++static int cpufreq_governor_dbs(struct cpufreq_policy *policy, ++ unsigned int event) ++{ ++ unsigned int cpu = policy->cpu; ++ struct cpu_dbs_info_s *this_dbs_info; ++ unsigned int i, j, max_periods; ++ int rc; ++ ++ this_dbs_info = &per_cpu(hp_cpu_dbs_info, cpu); ++ ++ switch (event) { ++ case CPUFREQ_GOV_START: ++ if ((!cpu_online(cpu)) || (!policy->cur)) ++ return -EINVAL; ++ ++ mutex_lock(&dbs_mutex); ++ dbs_enable++; ++ for_each_cpu(j, policy->cpus) { ++ struct cpu_dbs_info_s *j_dbs_info; ++ j_dbs_info = &per_cpu(hp_cpu_dbs_info, j); ++ j_dbs_info->cur_policy = policy; ++ ++ j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j, ++ &j_dbs_info->prev_cpu_wall); ++ if (dbs_tuners_ins.ignore_nice) { ++ j_dbs_info->prev_cpu_nice = ++ kstat_cpu(j).cpustat.nice; ++ } ++ ++ max_periods = max(DEFAULT_HOTPLUG_IN_SAMPLING_PERIODS, ++ DEFAULT_HOTPLUG_OUT_SAMPLING_PERIODS); ++ dbs_tuners_ins.hotplug_load_history = kmalloc( ++ (sizeof(unsigned int) * max_periods), ++ GFP_KERNEL); ++ if (!dbs_tuners_ins.hotplug_load_history) { ++ WARN_ON(1); ++ return -ENOMEM; ++ } ++ for (i = 0; i < max_periods; i++) ++ dbs_tuners_ins.hotplug_load_history[i] = 50; ++ } ++ this_dbs_info->cpu = cpu; ++ this_dbs_info->freq_table = cpufreq_frequency_get_table(cpu); ++ /* ++ * Start the timerschedule work, when this governor ++ * is used for first time ++ */ ++ if (dbs_enable == 1) { ++ rc = sysfs_create_group(cpufreq_global_kobject, ++ &dbs_attr_group); ++ if (rc) { ++ mutex_unlock(&dbs_mutex); ++ return rc; ++ } ++ } ++ mutex_unlock(&dbs_mutex); ++ ++ mutex_init(&this_dbs_info->timer_mutex); ++ dbs_timer_init(this_dbs_info); ++ break; ++ ++ case CPUFREQ_GOV_STOP: ++ dbs_timer_exit(this_dbs_info); ++ ++ mutex_lock(&dbs_mutex); ++ mutex_destroy(&this_dbs_info->timer_mutex); ++ dbs_enable--; ++ mutex_unlock(&dbs_mutex); ++ if (!dbs_enable) ++ sysfs_remove_group(cpufreq_global_kobject, ++ &dbs_attr_group); ++ kfree(dbs_tuners_ins.hotplug_load_history); ++ /* ++ * XXX BIG CAVEAT: Stopping the governor with CPU1 offline ++ * will result in it remaining offline until the user onlines ++ * it again. It is up to the user to do this (for now). ++ */ ++ break; ++ ++ case CPUFREQ_GOV_LIMITS: ++ mutex_lock(&this_dbs_info->timer_mutex); ++ if (policy->max < this_dbs_info->cur_policy->cur) ++ __cpufreq_driver_target(this_dbs_info->cur_policy, ++ policy->max, CPUFREQ_RELATION_H); ++ else if (policy->min > this_dbs_info->cur_policy->cur) ++ __cpufreq_driver_target(this_dbs_info->cur_policy, ++ policy->min, CPUFREQ_RELATION_L); ++ mutex_unlock(&this_dbs_info->timer_mutex); ++ break; ++ } ++ return 0; ++} ++ ++static int __init cpufreq_gov_dbs_init(void) ++{ ++ int err; ++ cputime64_t wall; ++ u64 idle_time; ++ int cpu = get_cpu(); ++ ++ idle_time = get_cpu_idle_time_us(cpu, &wall); ++ put_cpu(); ++ if (idle_time != -1ULL) { ++ dbs_tuners_ins.up_threshold = DEFAULT_UP_FREQ_MIN_LOAD; ++ } else { ++ pr_err("cpufreq-hotplug: %s: assumes CONFIG_NO_HZ\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ khotplug_wq = create_workqueue("khotplug"); ++ if (!khotplug_wq) { ++ pr_err("Creation of khotplug failed\n"); ++ return -EFAULT; ++ } ++ err = cpufreq_register_governor(&cpufreq_gov_hotplug); ++ if (err) ++ destroy_workqueue(khotplug_wq); ++ ++ return err; ++} ++ ++static void __exit cpufreq_gov_dbs_exit(void) ++{ ++ cpufreq_unregister_governor(&cpufreq_gov_hotplug); ++ destroy_workqueue(khotplug_wq); ++} ++ ++MODULE_AUTHOR("Mike Turquette <mturquette@ti.com>"); ++MODULE_DESCRIPTION("'cpufreq_hotplug' - cpufreq governor for dynamic frequency scaling and CPU hotplugging"); ++MODULE_LICENSE("GPL"); ++ ++#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_HOTPLUG ++fs_initcall(cpufreq_gov_dbs_init); ++#else ++module_init(cpufreq_gov_dbs_init); ++#endif ++module_exit(cpufreq_gov_dbs_exit); +diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h +index a38fca8..6cbc3df 100644 +--- a/include/linux/cpufreq.h ++++ b/include/linux/cpufreq.h +@@ -355,6 +355,9 @@ extern struct cpufreq_governor cpufreq_gov_ondemand; + #elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE) + extern struct cpufreq_governor cpufreq_gov_conservative; + #define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_conservative) ++#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_HOTPLUG) ++extern struct cpufreq_governor cpufreq_gov_hotplug; ++#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_hotplug) + #endif + + +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0001-OMAP-CPUfreq-ensure-driver-initializes-after-cpufreq.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0001-OMAP-CPUfreq-ensure-driver-initializes-after-cpufreq.patch new file mode 100644 index 00000000..d150dfc6 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0001-OMAP-CPUfreq-ensure-driver-initializes-after-cpufreq.patch @@ -0,0 +1,27 @@ +From 33668b07abd5e66a263cc8b4b88587646f38bed0 Mon Sep 17 00:00:00 2001 +From: Peter 'p2' De Schrijver <peter.de-schrijver@nokia.com> +Date: Wed, 11 Aug 2010 17:02:43 -0700 +Subject: [PATCH 1/8] OMAP: CPUfreq: ensure driver initializes after cpufreq framework and governors + +Signed-off-by: Peter 'p2' De Schrijver <peter.de-schrijver@nokia.com> +Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com> +--- + arch/arm/plat-omap/cpu-omap.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c +index da4f68d..cd09d4b 100644 +--- a/arch/arm/plat-omap/cpu-omap.c ++++ b/arch/arm/plat-omap/cpu-omap.c +@@ -160,7 +160,7 @@ static int __init omap_cpufreq_init(void) + return cpufreq_register_driver(&omap_driver); + } + +-arch_initcall(omap_cpufreq_init); ++late_initcall(omap_cpufreq_init); + + /* + * if ever we want to remove this, upon cleanup call: +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0002-OMAP-CPUfreq-ensure-policy-is-fully-initialized.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0002-OMAP-CPUfreq-ensure-policy-is-fully-initialized.patch new file mode 100644 index 00000000..d62e04d1 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0002-OMAP-CPUfreq-ensure-policy-is-fully-initialized.patch @@ -0,0 +1,31 @@ +From e89b1544450fb8410a44004e48d6b330bc39f0ce Mon Sep 17 00:00:00 2001 +From: Kevin Hilman <khilman@deeprootsystems.com> +Date: Wed, 11 Aug 2010 17:05:38 -0700 +Subject: [PATCH 2/8] OMAP: CPUfreq: ensure policy is fully initialized + +Ensure policy min/max/cur values are initialized when OMAP +CPUfreq driver starts. + +Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com> +--- + arch/arm/plat-omap/cpu-omap.c | 4 ++++ + 1 files changed, 4 insertions(+), 0 deletions(-) + +diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c +index cd09d4b..1b36664 100644 +--- a/arch/arm/plat-omap/cpu-omap.c ++++ b/arch/arm/plat-omap/cpu-omap.c +@@ -126,6 +126,10 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) + VERY_HI_RATE) / 1000; + } + ++ policy->min = policy->cpuinfo.min_freq; ++ policy->max = policy->cpuinfo.max_freq; ++ policy->cur = omap_getspeed(0); ++ + /* FIXME: what's the actual transition time? */ + policy->cpuinfo.transition_latency = 300 * 1000; + +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0003-OMAP3-PM-CPUFreq-driver-for-OMAP3.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0003-OMAP3-PM-CPUFreq-driver-for-OMAP3.patch new file mode 100644 index 00000000..fbe16213 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0003-OMAP3-PM-CPUFreq-driver-for-OMAP3.patch @@ -0,0 +1,263 @@ +From 948b868e4a83b054e8a58362238bc6cd61c0aeab Mon Sep 17 00:00:00 2001 +From: Rajendra Nayak <rnayak@ti.com> +Date: Mon, 10 Nov 2008 17:00:25 +0530 +Subject: [PATCH 3/8] OMAP3 PM: CPUFreq driver for OMAP3 + +CPUFreq driver for OMAP3 + +With additional fixes and cleanups from Tero Kristo: +- Fix rate calculation bug in omap3_select_table_rate +- Refreshed DVFS VDD1 control against latest clock fw + +Signed-off-by: Tero Kristo <tero.kristo@nokia.com> +Signed-off-by: Rajendra Nayak <rnayak@ti.com> + +OMAP3: PM: CPUFreq: Fix omap_getspeed. + +Signed-off-by: Peter 'p2' De Schrijver <peter.de-schrijver@nokia.com> + +Make sure omap cpufreq driver initializes after cpufreq framework and governors + +Signed-off-by: Peter 'p2' De Schrijver <peter.de-schrijver@nokia.com> + +merge: CPUFreq: remove obsolete funcs + +OMAP3 clock: Update cpufreq driver + +This patch removes all refrences to virtual clock +nodes in CPUFreq driver. + +Signed-off-by: Rajendra Nayak <rnayak@ti.com> +Signed-off-by: Tero Kristo <tero.kristo@nokia.com> +Signed-off-by: Jean Pihet <jpihet@mvista.com> + +PM: Prevent direct cpufreq scaling during initialization + +It is seen that the OMAP specific cpufreq initialization code tries to +scale the MPU frequency to the highest possible without taking care of +the voltage level. On power on reset the power IC does not provide the +necessary voltage for the highest available MPU frequency (that would +satisfy all Si families). This potentially is an window of opportunity +for things to go wrong. + +Signed-off-by: Romit Dasgupta <romit@ti.com> +Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com> + +OMAP3: PM: enable 600MHz (overdrive) OPP + +Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com> + +omap3: introduce cpufreq + +OMAP OPP layer functions now have dependencies of CONFIG_CPU_FREQ only. + +With this patch, omap opp layer now has its compilation flags +bound to CONFIG_CPU_FREQ. Also its code has been removed from pm34xx.c. + +A new file has been created to contain cpu freq code related to +OMAP3: cpufreq34xx.c + +OMAP34xx and OMAP36xx family OPPs are made available + +Signed-off-by: Eduardo Valentin <eduardo.valentin@nokia.com> +Signed-off-by: Paul Walmsley <paul@pwsan.com> +Signed-off-by: Nishanth Menon <nm@ti.com> +Signed-off-by: Vishwanath BS <vishwanath.bs@ti.com> +Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com> +Signed-off-by: Romit Dasgupta <romit@ti.com> +Signed-off-by: Rajendra Nayak <rnayak@ti.com> + +omap3: cpufreq: allow default opp table init + +For board files which choose to override the defaults, the existing +mechanism will work, for boards that would like to work with defaults, +allow init_common_hw to call init_opp_table to initialize if not +already initialized. this will allow all omap boards which have opp +tables predefined for a silicon to use the same. + +Originally reported for overo: +http://marc.info/?t=127265269400004&r=1&w=2 + +Signed-off-by: Nishanth Menon <nm@ti.com> +Reported-by: Peter Tseng <tsenpet09@gmail.com> +Cc: Cliff Brake <cliff.brake@gmail.com> +Cc: Kevin Hilman <khilman@deeprootsystems.com> + +OMAP2: update OPP data to be device based + +Cc: Nishanth Menon <nm@ti.com> +Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com> + +OMAP3: CPUfreq: update to device-based OPP API + +Update usage of OPP API to use new device-based API. This requires +getting the 'struct device' for the MPU and using that with the OPP +API. + +Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com> + +omap3: opp: make independent of cpufreq + +Make opp3xx data which is registered with the opp layer +dependent purely on CONFIG_PM as opp layer and pm.c users +are CONFIG_PM dependent not cpufreq dependent. +so we rename the data definition to opp3xxx_data.c (inline with what +we have for omap2), also move the build definition to be under +the existing CONFIG_PM build instead of CPUFREQ. + +Cc: Eduardo Valentin <eduardo.valentin@nokia.com> +Cc: Kevin Hilman <khilman@deeprootsystems.com> +Cc: Paul Walmsley <paul@pwsan.com> +Cc: Rajendra Nayak <rnayak@ti.com> +Cc: Sanjeev Premi <premi@ti.com> +Cc: Thara Gopinath <thara@ti.com> +Cc: Tony Lindgren <tony@atomide.com> + +Signed-off-by: Nishanth Menon <nm@ti.com> +--- + arch/arm/mach-omap2/clock.h | 14 +++++++++++++- + arch/arm/mach-omap2/clock34xx.c | 2 ++ + arch/arm/plat-omap/cpu-omap.c | 34 +++++++++++++++++++++++++++++++--- + 3 files changed, 46 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h +index e10ff2b..0a07e50 100644 +--- a/arch/arm/mach-omap2/clock.h ++++ b/arch/arm/mach-omap2/clock.h +@@ -141,7 +141,9 @@ extern const struct clksel_rate gpt_sys_rates[]; + extern const struct clksel_rate gfx_l3_rates[]; + extern const struct clksel_rate dsp_ick_rates[]; + +-#if defined(CONFIG_ARCH_OMAP2) && defined(CONFIG_CPU_FREQ) ++#ifdef CONFIG_CPU_FREQ ++ ++#ifdef CONFIG_ARCH_OMAP2 + extern void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table); + extern void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table); + #else +@@ -149,6 +151,16 @@ extern void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table) + #define omap2_clk_exit_cpufreq_table 0 + #endif + ++#ifdef CONFIG_ARCH_OMAP3 ++extern void omap3_clk_init_cpufreq_table(struct cpufreq_frequency_table **table); ++extern void omap3_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table); ++#else ++#define omap3_clk_init_cpufreq_table 0 ++#define omap3_clk_exit_cpufreq_table 0 ++#endif ++ ++#endif /* CONFIG_CPU_FREQ */ ++ + extern const struct clkops clkops_omap2_iclk_dflt_wait; + extern const struct clkops clkops_omap2_iclk_dflt; + extern const struct clkops clkops_omap2_iclk_idle_only; +diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c +index 1fc96b9..119e135 100644 +--- a/arch/arm/mach-omap2/clock34xx.c ++++ b/arch/arm/mach-omap2/clock34xx.c +@@ -20,6 +20,8 @@ + #include <linux/kernel.h> + #include <linux/clk.h> + #include <linux/io.h> ++#include <linux/err.h> ++#include <linux/cpufreq.h> + + #include <plat/clock.h> + +diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c +index 1b36664..f0f9430 100644 +--- a/arch/arm/plat-omap/cpu-omap.c ++++ b/arch/arm/plat-omap/cpu-omap.c +@@ -8,6 +8,10 @@ + * + * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King + * ++ * Copyright (C) 2007-2008 Texas Instruments, Inc. ++ * Updated to support OMAP3 ++ * Rajendra Nayak <rnayak@ti.com> ++ * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +@@ -26,12 +30,19 @@ + #include <plat/clock.h> + #include <asm/system.h> + ++#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) ++#include <plat/omap-pm.h> ++#include <plat/opp.h> ++#endif ++ + #define VERY_HI_RATE 900000000 + + static struct cpufreq_frequency_table *freq_table; + + #ifdef CONFIG_ARCH_OMAP1 + #define MPU_CLK "mpu" ++#elif CONFIG_ARCH_OMAP3 ++#define MPU_CLK "arm_fck" + #else + #define MPU_CLK "virt_prcm_set" + #endif +@@ -73,7 +84,13 @@ static int omap_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) + { ++#ifdef CONFIG_ARCH_OMAP1 + struct cpufreq_freqs freqs; ++#endif ++#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) ++ unsigned long freq; ++ struct device *mpu_dev = omap2_get_mpuss_device(); ++#endif + int ret = 0; + + /* Ensure desired rate is within allowed range. Some govenors +@@ -83,13 +100,13 @@ static int omap_target(struct cpufreq_policy *policy, + if (target_freq > policy->max) + target_freq = policy->max; + ++#ifdef CONFIG_ARCH_OMAP1 + freqs.old = omap_getspeed(0); + freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000; + freqs.cpu = 0; + + if (freqs.old == freqs.new) + return ret; +- + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + #ifdef CONFIG_CPU_FREQ_DEBUG + printk(KERN_DEBUG "cpufreq-omap: transition: %u --> %u\n", +@@ -97,7 +114,11 @@ static int omap_target(struct cpufreq_policy *policy, + #endif + ret = clk_set_rate(mpu_clk, freqs.new * 1000); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); +- ++#elif defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) ++ freq = target_freq * 1000; ++ if (opp_find_freq_ceil(mpu_dev, &freq)) ++ omap_pm_cpu_set_freq(freq); ++#endif + return ret; + } + +@@ -114,7 +135,14 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) + + policy->cur = policy->min = policy->max = omap_getspeed(0); + +- clk_init_cpufreq_table(&freq_table); ++ if (!cpu_is_omap34xx()) { ++ clk_init_cpufreq_table(&freq_table); ++ } else { ++ struct device *mpu_dev = omap2_get_mpuss_device(); ++ ++ opp_init_cpufreq_table(mpu_dev, &freq_table); ++ } ++ + if (freq_table) { + result = cpufreq_frequency_table_cpuinfo(policy, freq_table); + if (!result) +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0004-OMAP-PM-CPUFREQ-Fix-conditional-compilation.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0004-OMAP-PM-CPUFREQ-Fix-conditional-compilation.patch new file mode 100644 index 00000000..36742e43 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0004-OMAP-PM-CPUFREQ-Fix-conditional-compilation.patch @@ -0,0 +1,32 @@ +From 86227f1eb341e571163464cb0a412ed2179f2541 Mon Sep 17 00:00:00 2001 +From: Silesh C V <silesh@ti.com> +Date: Wed, 29 Sep 2010 14:52:54 +0530 +Subject: [PATCH 4/8] OMAP: PM: CPUFREQ: Fix conditional compilation + +Fix conditional compilation. A conditional expresiion +should follow "#elif", in this case #elif clause should +check whether CONFIG_ARCH_OMAP3 is defined or not +(ie. defined(CONFIG_ARCH_OMAP3)) rather than checking for +the value of the macro. + +Signed-off-by: Silesh C V <silesh@ti.com> +--- + arch/arm/plat-omap/cpu-omap.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c +index f0f9430..c3ac065 100644 +--- a/arch/arm/plat-omap/cpu-omap.c ++++ b/arch/arm/plat-omap/cpu-omap.c +@@ -41,7 +41,7 @@ static struct cpufreq_frequency_table *freq_table; + + #ifdef CONFIG_ARCH_OMAP1 + #define MPU_CLK "mpu" +-#elif CONFIG_ARCH_OMAP3 ++#elif defined(CONFIG_ARCH_OMAP3) + #define MPU_CLK "arm_fck" + #else + #define MPU_CLK "virt_prcm_set" +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0005-cpufreq-fixup-after-new-OPP-layer-merged.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0005-cpufreq-fixup-after-new-OPP-layer-merged.patch new file mode 100644 index 00000000..7cf69325 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0005-cpufreq-fixup-after-new-OPP-layer-merged.patch @@ -0,0 +1,33 @@ +From 4764137dd613362656726a15cb8184724aeb99bb Mon Sep 17 00:00:00 2001 +From: Kevin Hilman <khilman@deeprootsystems.com> +Date: Tue, 16 Nov 2010 11:48:41 -0800 +Subject: [PATCH 5/8] cpufreq: fixup after new OPP layer merged + +--- + arch/arm/plat-omap/cpu-omap.c | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + +diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c +index c3ac065..9cd2709 100644 +--- a/arch/arm/plat-omap/cpu-omap.c ++++ b/arch/arm/plat-omap/cpu-omap.c +@@ -25,6 +25,7 @@ + #include <linux/err.h> + #include <linux/clk.h> + #include <linux/io.h> ++#include <linux/opp.h> + + #include <mach/hardware.h> + #include <plat/clock.h> +@@ -32,7 +33,7 @@ + + #if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) + #include <plat/omap-pm.h> +-#include <plat/opp.h> ++#include <plat/common.h> + #endif + + #define VERY_HI_RATE 900000000 +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0006-OMAP-cpufreq-Split-OMAP1-and-OMAP2PLUS-CPUfreq-drive.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0006-OMAP-cpufreq-Split-OMAP1-and-OMAP2PLUS-CPUfreq-drive.patch new file mode 100644 index 00000000..cfc257e0 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0006-OMAP-cpufreq-Split-OMAP1-and-OMAP2PLUS-CPUfreq-drive.patch @@ -0,0 +1,669 @@ +From e16548716c5cbc3c9885d05f1654d83d5411a3a7 Mon Sep 17 00:00:00 2001 +From: Santosh Shilimkar <santosh.shilimkar@ti.com> +Date: Mon, 14 Mar 2011 17:08:48 +0530 +Subject: [PATCH 6/8] OMAP: cpufreq: Split OMAP1 and OMAP2PLUS CPUfreq drivers. + +This patch is an attempt to cleanup the #ifdeferry in the +omap CPUfreq drivers. + +The split betwenn OMAP1 and OMAP2PLUS is logical because + - OMAP1 doesn't support opp layer. + - OMAP1 build is seperate from omap2plus. + +Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com> +Cc: Kevin Hilman <khilman@ti.com> +Cc: Vishwanath BS <vishwanath.bs@ti.com> +--- + arch/arm/mach-omap1/Makefile | 3 + + arch/arm/mach-omap1/omap1-cpufreq.c | 176 ++++++++++++++++++++++++++ + arch/arm/mach-omap2/Makefile | 3 + + arch/arm/mach-omap2/omap2plus-cpufreq.c | 201 ++++++++++++++++++++++++++++++ + arch/arm/plat-omap/Makefile | 1 - + arch/arm/plat-omap/cpu-omap.c | 204 ------------------------------- + 6 files changed, 383 insertions(+), 205 deletions(-) + create mode 100644 arch/arm/mach-omap1/omap1-cpufreq.c + create mode 100644 arch/arm/mach-omap2/omap2plus-cpufreq.c + delete mode 100644 arch/arm/plat-omap/cpu-omap.c + +diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile +index af98117..e5082b0 100644 +--- a/arch/arm/mach-omap1/Makefile ++++ b/arch/arm/mach-omap1/Makefile +@@ -10,6 +10,9 @@ obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o + + obj-$(CONFIG_OMAP_32K_TIMER) += timer32k.o + ++# CPUFREQ driver ++obj-$(CONFIG_CPU_FREQ) += omap1-cpufreq.o ++ + # Power Management + obj-$(CONFIG_PM) += pm.o sleep.o pm_bus.o + +diff --git a/arch/arm/mach-omap1/omap1-cpufreq.c b/arch/arm/mach-omap1/omap1-cpufreq.c +new file mode 100644 +index 0000000..682cdc8 +--- /dev/null ++++ b/arch/arm/mach-omap1/omap1-cpufreq.c +@@ -0,0 +1,176 @@ ++/* ++ * OMAP1 cpufreq driver ++ * ++ * CPU frequency scaling for OMAP ++ * ++ * Copyright (C) 2005 Nokia Corporation ++ * Written by Tony Lindgren <tony@atomide.com> ++ * ++ * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King ++ * ++ * Copyright (C) 2007-2008 Texas Instruments, Inc. ++ * Updated to support OMAP3 ++ * Rajendra Nayak <rnayak@ti.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/cpufreq.h> ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/err.h> ++#include <linux/clk.h> ++#include <linux/io.h> ++#include <linux/opp.h> ++ ++#include <asm/system.h> ++ ++#include <plat/clock.h> ++#include <plat/omap-pm.h> ++ ++#include <mach/hardware.h> ++ ++#define VERY_HI_RATE 900000000 ++ ++static struct cpufreq_frequency_table *freq_table; ++static struct clk *mpu_clk; ++ ++static int omap_verify_speed(struct cpufreq_policy *policy) ++{ ++ if (freq_table) ++ return cpufreq_frequency_table_verify(policy, freq_table); ++ ++ if (policy->cpu) ++ return -EINVAL; ++ ++ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, ++ policy->cpuinfo.max_freq); ++ ++ policy->min = clk_round_rate(mpu_clk, policy->min * 1000) / 1000; ++ policy->max = clk_round_rate(mpu_clk, policy->max * 1000) / 1000; ++ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, ++ policy->cpuinfo.max_freq); ++ return 0; ++} ++ ++static unsigned int omap_getspeed(unsigned int cpu) ++{ ++ unsigned long rate; ++ ++ if (cpu) ++ return 0; ++ ++ rate = clk_get_rate(mpu_clk) / 1000; ++ return rate; ++} ++ ++static int omap_target(struct cpufreq_policy *policy, ++ unsigned int target_freq, ++ unsigned int relation) ++{ ++ struct cpufreq_freqs freqs; ++ int ret = 0; ++ ++ /* Ensure desired rate is within allowed range. Some govenors ++ * (ondemand) will just pass target_freq=0 to get the minimum. */ ++ if (target_freq < policy->min) ++ target_freq = policy->min; ++ if (target_freq > policy->max) ++ target_freq = policy->max; ++ ++ freqs.old = omap_getspeed(0); ++ freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000; ++ freqs.cpu = 0; ++ ++ if (freqs.old == freqs.new) ++ return ret; ++ ++ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); ++ ++#ifdef CONFIG_CPU_FREQ_DEBUG ++ pr_info("cpufreq-omap: transition: %u --> %u\n", freqs.old, freqs.new); ++#endif ++ ret = clk_set_rate(mpu_clk, freqs.new * 1000); ++ ++ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); ++ ++ return ret; ++} ++ ++static int __init omap_cpu_init(struct cpufreq_policy *policy) ++{ ++ int result = 0; ++ ++ mpu_clk = clk_get(NULL, "mpu"); ++ if (IS_ERR(mpu_clk)) ++ return PTR_ERR(mpu_clk); ++ ++ if (policy->cpu != 0) ++ return -EINVAL; ++ ++ policy->cur = policy->min = policy->max = omap_getspeed(0); ++ ++ clk_init_cpufreq_table(&freq_table); ++ ++ if (freq_table) { ++ result = cpufreq_frequency_table_cpuinfo(policy, freq_table); ++ if (!result) ++ cpufreq_frequency_table_get_attr(freq_table, ++ policy->cpu); ++ } else { ++ policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000; ++ policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, ++ VERY_HI_RATE) / 1000; ++ } ++ ++ policy->min = policy->cpuinfo.min_freq; ++ policy->max = policy->cpuinfo.max_freq; ++ policy->cur = omap_getspeed(0); ++ ++ /* FIXME: what's the actual transition time? */ ++ policy->cpuinfo.transition_latency = 300 * 1000; ++ ++ return 0; ++} ++ ++static int omap_cpu_exit(struct cpufreq_policy *policy) ++{ ++ clk_exit_cpufreq_table(&freq_table); ++ clk_put(mpu_clk); ++ return 0; ++} ++ ++static struct freq_attr *omap_cpufreq_attr[] = { ++ &cpufreq_freq_attr_scaling_available_freqs, ++ NULL, ++}; ++ ++static struct cpufreq_driver omap_driver = { ++ .flags = CPUFREQ_STICKY, ++ .verify = omap_verify_speed, ++ .target = omap_target, ++ .get = omap_getspeed, ++ .init = omap_cpu_init, ++ .exit = omap_cpu_exit, ++ .name = "omap1", ++ .attr = omap_cpufreq_attr, ++}; ++ ++static int __init omap_cpufreq_init(void) ++{ ++ return cpufreq_register_driver(&omap_driver); ++} ++ ++static void __exit omap_cpufreq_exit(void) ++{ ++ cpufreq_unregister_driver(&omap_driver); ++} ++ ++MODULE_DESCRIPTION("cpufreq driver for OMAP1 SOCs"); ++MODULE_LICENSE("GPL"); ++module_init(omap_cpufreq_init); ++module_exit(omap_cpufreq_exit); +diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile +index 05cd983..e9c2445 100644 +--- a/arch/arm/mach-omap2/Makefile ++++ b/arch/arm/mach-omap2/Makefile +@@ -56,6 +56,9 @@ obj-$(CONFIG_ARCH_OMAP3) += opp3xxx_data.o + obj-$(CONFIG_ARCH_OMAP4) += opp4xxx_data.o + endif + ++# CPUFREQ driver ++obj-$(CONFIG_CPU_FREQ) += omap2plus-cpufreq.o ++ + # Power Management + ifeq ($(CONFIG_PM),y) + obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o +diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c +new file mode 100644 +index 0000000..14f84cc +--- /dev/null ++++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c +@@ -0,0 +1,201 @@ ++/* ++ * OMAP2PLUS cpufreq driver ++ * ++ * CPU frequency scaling for OMAP ++ * ++ * Copyright (C) 2005 Nokia Corporation ++ * Written by Tony Lindgren <tony@atomide.com> ++ * ++ * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King ++ * ++ * Copyright (C) 2007-2008 Texas Instruments, Inc. ++ * Updated to support OMAP3 ++ * Rajendra Nayak <rnayak@ti.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/cpufreq.h> ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/err.h> ++#include <linux/clk.h> ++#include <linux/io.h> ++#include <linux/opp.h> ++ ++#include <asm/system.h> ++#include <asm/smp_plat.h> ++ ++#include <plat/clock.h> ++#include <plat/omap-pm.h> ++#include <plat/common.h> ++ ++#include <mach/hardware.h> ++ ++#define VERY_HI_RATE 900000000 ++ ++static struct cpufreq_frequency_table *freq_table; ++static struct clk *mpu_clk; ++ ++static int omap_verify_speed(struct cpufreq_policy *policy) ++{ ++ if (freq_table) ++ return cpufreq_frequency_table_verify(policy, freq_table); ++ ++ if (policy->cpu) ++ return -EINVAL; ++ ++ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, ++ policy->cpuinfo.max_freq); ++ ++ policy->min = clk_round_rate(mpu_clk, policy->min * 1000) / 1000; ++ policy->max = clk_round_rate(mpu_clk, policy->max * 1000) / 1000; ++ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, ++ policy->cpuinfo.max_freq); ++ return 0; ++} ++ ++static unsigned int omap_getspeed(unsigned int cpu) ++{ ++ unsigned long rate; ++ ++ if (cpu) ++ return 0; ++ ++ rate = clk_get_rate(mpu_clk) / 1000; ++ return rate; ++} ++ ++static int omap_target(struct cpufreq_policy *policy, ++ unsigned int target_freq, ++ unsigned int relation) ++{ ++ int ret = 0; ++ struct cpufreq_freqs freqs; ++ ++ /* Ensure desired rate is within allowed range. Some govenors ++ * (ondemand) will just pass target_freq=0 to get the minimum. */ ++ if (target_freq < policy->min) ++ target_freq = policy->min; ++ if (target_freq > policy->max) ++ target_freq = policy->max; ++ ++ freqs.old = omap_getspeed(0); ++ freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000; ++ freqs.cpu = 0; ++ ++ if (freqs.old == freqs.new) ++ return ret; ++ ++ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); ++ ++#ifdef CONFIG_CPU_FREQ_DEBUG ++ pr_info("cpufreq-omap: transition: %u --> %u\n", freqs.old, freqs.new); ++#endif ++ ++ ret = clk_set_rate(mpu_clk, freqs.new * 1000); ++ ++ /* ++ * Generic CPUFREQ driver jiffy update is under !SMP. So jiffies ++ * won't get updated when UP machine cpufreq build with ++ * CONFIG_SMP enabled. Below code is added only to manage that ++ * scenario ++ */ ++ if (!is_smp()) ++ loops_per_jiffy = ++ cpufreq_scale(loops_per_jiffy, freqs.old, freqs.new); ++ ++ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); ++ ++ return ret; ++} ++ ++static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) ++{ ++ int result = 0; ++ struct device *mpu_dev; ++ ++ if (cpu_is_omap24xx()) ++ mpu_clk = clk_get(NULL, "virt_prcm_set"); ++ else if (cpu_is_omap34xx()) ++ mpu_clk = clk_get(NULL, "dpll1_ck"); ++ else if (cpu_is_omap34xx()) ++ mpu_clk = clk_get(NULL, "dpll_mpu_ck"); ++ ++ if (IS_ERR(mpu_clk)) ++ return PTR_ERR(mpu_clk); ++ ++ if (policy->cpu != 0) ++ return -EINVAL; ++ ++ policy->cur = policy->min = policy->max = omap_getspeed(0); ++ ++ mpu_dev = omap2_get_mpuss_device(); ++ if (!mpu_dev) { ++ pr_warning("%s: unable to get the mpu device\n", __func__); ++ return -EINVAL; ++ } ++ opp_init_cpufreq_table(mpu_dev, &freq_table); ++ ++ if (freq_table) { ++ result = cpufreq_frequency_table_cpuinfo(policy, freq_table); ++ if (!result) ++ cpufreq_frequency_table_get_attr(freq_table, ++ policy->cpu); ++ } else { ++ policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000; ++ policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, ++ VERY_HI_RATE) / 1000; ++ } ++ ++ policy->min = policy->cpuinfo.min_freq; ++ policy->max = policy->cpuinfo.max_freq; ++ policy->cur = omap_getspeed(0); ++ ++ /* FIXME: what's the actual transition time? */ ++ policy->cpuinfo.transition_latency = 300 * 1000; ++ ++ return 0; ++} ++ ++static int omap_cpu_exit(struct cpufreq_policy *policy) ++{ ++ clk_exit_cpufreq_table(&freq_table); ++ clk_put(mpu_clk); ++ return 0; ++} ++ ++static struct freq_attr *omap_cpufreq_attr[] = { ++ &cpufreq_freq_attr_scaling_available_freqs, ++ NULL, ++}; ++ ++static struct cpufreq_driver omap_driver = { ++ .flags = CPUFREQ_STICKY, ++ .verify = omap_verify_speed, ++ .target = omap_target, ++ .get = omap_getspeed, ++ .init = omap_cpu_init, ++ .exit = omap_cpu_exit, ++ .name = "omap2plus", ++ .attr = omap_cpufreq_attr, ++}; ++ ++static int __init omap_cpufreq_init(void) ++{ ++ return cpufreq_register_driver(&omap_driver); ++} ++ ++static void __exit omap_cpufreq_exit(void) ++{ ++ cpufreq_unregister_driver(&omap_driver); ++} ++ ++MODULE_DESCRIPTION("cpufreq driver for OMAP2PLUS SOCs"); ++MODULE_LICENSE("GPL"); ++module_init(omap_cpufreq_init); ++module_exit(omap_cpufreq_exit); +diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile +index a4a1285..ec7862e 100644 +--- a/arch/arm/plat-omap/Makefile ++++ b/arch/arm/plat-omap/Makefile +@@ -21,7 +21,6 @@ obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o + obj-$(CONFIG_OMAP_IOMMU) += iommu.o iovmm.o + obj-$(CONFIG_OMAP_IOMMU_DEBUG) += iommu-debug.o + +-obj-$(CONFIG_CPU_FREQ) += cpu-omap.o + obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o + obj-$(CONFIG_OMAP_DEBUG_DEVICES) += debug-devices.o + obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o +diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c +deleted file mode 100644 +index 9cd2709..0000000 +--- a/arch/arm/plat-omap/cpu-omap.c ++++ /dev/null +@@ -1,204 +0,0 @@ +-/* +- * linux/arch/arm/plat-omap/cpu-omap.c +- * +- * CPU frequency scaling for OMAP +- * +- * Copyright (C) 2005 Nokia Corporation +- * Written by Tony Lindgren <tony@atomide.com> +- * +- * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King +- * +- * Copyright (C) 2007-2008 Texas Instruments, Inc. +- * Updated to support OMAP3 +- * Rajendra Nayak <rnayak@ti.com> +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- */ +-#include <linux/types.h> +-#include <linux/kernel.h> +-#include <linux/sched.h> +-#include <linux/cpufreq.h> +-#include <linux/delay.h> +-#include <linux/init.h> +-#include <linux/err.h> +-#include <linux/clk.h> +-#include <linux/io.h> +-#include <linux/opp.h> +- +-#include <mach/hardware.h> +-#include <plat/clock.h> +-#include <asm/system.h> +- +-#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) +-#include <plat/omap-pm.h> +-#include <plat/common.h> +-#endif +- +-#define VERY_HI_RATE 900000000 +- +-static struct cpufreq_frequency_table *freq_table; +- +-#ifdef CONFIG_ARCH_OMAP1 +-#define MPU_CLK "mpu" +-#elif defined(CONFIG_ARCH_OMAP3) +-#define MPU_CLK "arm_fck" +-#else +-#define MPU_CLK "virt_prcm_set" +-#endif +- +-static struct clk *mpu_clk; +- +-/* TODO: Add support for SDRAM timing changes */ +- +-static int omap_verify_speed(struct cpufreq_policy *policy) +-{ +- if (freq_table) +- return cpufreq_frequency_table_verify(policy, freq_table); +- +- if (policy->cpu) +- return -EINVAL; +- +- cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, +- policy->cpuinfo.max_freq); +- +- policy->min = clk_round_rate(mpu_clk, policy->min * 1000) / 1000; +- policy->max = clk_round_rate(mpu_clk, policy->max * 1000) / 1000; +- cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, +- policy->cpuinfo.max_freq); +- return 0; +-} +- +-static unsigned int omap_getspeed(unsigned int cpu) +-{ +- unsigned long rate; +- +- if (cpu) +- return 0; +- +- rate = clk_get_rate(mpu_clk) / 1000; +- return rate; +-} +- +-static int omap_target(struct cpufreq_policy *policy, +- unsigned int target_freq, +- unsigned int relation) +-{ +-#ifdef CONFIG_ARCH_OMAP1 +- struct cpufreq_freqs freqs; +-#endif +-#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) +- unsigned long freq; +- struct device *mpu_dev = omap2_get_mpuss_device(); +-#endif +- int ret = 0; +- +- /* Ensure desired rate is within allowed range. Some govenors +- * (ondemand) will just pass target_freq=0 to get the minimum. */ +- if (target_freq < policy->min) +- target_freq = policy->min; +- if (target_freq > policy->max) +- target_freq = policy->max; +- +-#ifdef CONFIG_ARCH_OMAP1 +- freqs.old = omap_getspeed(0); +- freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000; +- freqs.cpu = 0; +- +- if (freqs.old == freqs.new) +- return ret; +- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); +-#ifdef CONFIG_CPU_FREQ_DEBUG +- printk(KERN_DEBUG "cpufreq-omap: transition: %u --> %u\n", +- freqs.old, freqs.new); +-#endif +- ret = clk_set_rate(mpu_clk, freqs.new * 1000); +- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); +-#elif defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) +- freq = target_freq * 1000; +- if (opp_find_freq_ceil(mpu_dev, &freq)) +- omap_pm_cpu_set_freq(freq); +-#endif +- return ret; +-} +- +-static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) +-{ +- int result = 0; +- +- mpu_clk = clk_get(NULL, MPU_CLK); +- if (IS_ERR(mpu_clk)) +- return PTR_ERR(mpu_clk); +- +- if (policy->cpu != 0) +- return -EINVAL; +- +- policy->cur = policy->min = policy->max = omap_getspeed(0); +- +- if (!cpu_is_omap34xx()) { +- clk_init_cpufreq_table(&freq_table); +- } else { +- struct device *mpu_dev = omap2_get_mpuss_device(); +- +- opp_init_cpufreq_table(mpu_dev, &freq_table); +- } +- +- if (freq_table) { +- result = cpufreq_frequency_table_cpuinfo(policy, freq_table); +- if (!result) +- cpufreq_frequency_table_get_attr(freq_table, +- policy->cpu); +- } else { +- policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000; +- policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, +- VERY_HI_RATE) / 1000; +- } +- +- policy->min = policy->cpuinfo.min_freq; +- policy->max = policy->cpuinfo.max_freq; +- policy->cur = omap_getspeed(0); +- +- /* FIXME: what's the actual transition time? */ +- policy->cpuinfo.transition_latency = 300 * 1000; +- +- return 0; +-} +- +-static int omap_cpu_exit(struct cpufreq_policy *policy) +-{ +- clk_exit_cpufreq_table(&freq_table); +- clk_put(mpu_clk); +- return 0; +-} +- +-static struct freq_attr *omap_cpufreq_attr[] = { +- &cpufreq_freq_attr_scaling_available_freqs, +- NULL, +-}; +- +-static struct cpufreq_driver omap_driver = { +- .flags = CPUFREQ_STICKY, +- .verify = omap_verify_speed, +- .target = omap_target, +- .get = omap_getspeed, +- .init = omap_cpu_init, +- .exit = omap_cpu_exit, +- .name = "omap", +- .attr = omap_cpufreq_attr, +-}; +- +-static int __init omap_cpufreq_init(void) +-{ +- return cpufreq_register_driver(&omap_driver); +-} +- +-late_initcall(omap_cpufreq_init); +- +-/* +- * if ever we want to remove this, upon cleanup call: +- * +- * cpufreq_unregister_driver() +- * cpufreq_frequency_table_put_attr() +- */ +- +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0007-OMAP2PLUS-cpufreq-Add-SMP-support-to-cater-OMAP4430.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0007-OMAP2PLUS-cpufreq-Add-SMP-support-to-cater-OMAP4430.patch new file mode 100644 index 00000000..6624d1ec --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0007-OMAP2PLUS-cpufreq-Add-SMP-support-to-cater-OMAP4430.patch @@ -0,0 +1,170 @@ +From f375d3c39d2835929d34c2a046b8c43cea6d1467 Mon Sep 17 00:00:00 2001 +From: Santosh Shilimkar <santosh.shilimkar@ti.com> +Date: Mon, 14 Mar 2011 17:08:49 +0530 +Subject: [PATCH 7/8] OMAP2PLUS: cpufreq: Add SMP support to cater OMAP4430 + +On OMAP SMP configuartion, both processors share the voltage +and clock. So both CPUs needs to be scaled together and hence +needs software co-ordination. + +Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com> +Cc: Kevin Hilman <khilman@ti.com> +cc: Vishwanath BS <vishwanath.bs@ti.com> +--- + arch/arm/mach-omap2/omap2plus-cpufreq.c | 73 ++++++++++++++++++++++++++----- + 1 files changed, 62 insertions(+), 11 deletions(-) + +diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c +index 14f84cc..8d472f6 100644 +--- a/arch/arm/mach-omap2/omap2plus-cpufreq.c ++++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c +@@ -26,9 +26,11 @@ + #include <linux/clk.h> + #include <linux/io.h> + #include <linux/opp.h> ++#include <linux/cpu.h> + + #include <asm/system.h> + #include <asm/smp_plat.h> ++#include <asm/cpu.h> + + #include <plat/clock.h> + #include <plat/omap-pm.h> +@@ -63,7 +65,7 @@ static unsigned int omap_getspeed(unsigned int cpu) + { + unsigned long rate; + +- if (cpu) ++ if (cpu >= NR_CPUS) + return 0; + + rate = clk_get_rate(mpu_clk) / 1000; +@@ -74,9 +76,13 @@ static int omap_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) + { +- int ret = 0; ++ int i, ret = 0; + struct cpufreq_freqs freqs; + ++ /* Changes not allowed until all CPUs are online */ ++ if (is_smp() && (num_online_cpus() < NR_CPUS)) ++ return ret; ++ + /* Ensure desired rate is within allowed range. Some govenors + * (ondemand) will just pass target_freq=0 to get the minimum. */ + if (target_freq < policy->min) +@@ -84,15 +90,25 @@ static int omap_target(struct cpufreq_policy *policy, + if (target_freq > policy->max) + target_freq = policy->max; + +- freqs.old = omap_getspeed(0); ++ freqs.old = omap_getspeed(policy->cpu); + freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000; +- freqs.cpu = 0; ++ freqs.cpu = policy->cpu; + + if (freqs.old == freqs.new) + return ret; + +- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); ++ if (!is_smp()) { ++ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); ++ goto set_freq; ++ } ++ ++ /* notifiers */ ++ for_each_cpu(i, policy->cpus) { ++ freqs.cpu = i; ++ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); ++ } + ++set_freq: + #ifdef CONFIG_CPU_FREQ_DEBUG + pr_info("cpufreq-omap: transition: %u --> %u\n", freqs.old, freqs.new); + #endif +@@ -105,12 +121,33 @@ static int omap_target(struct cpufreq_policy *policy, + * CONFIG_SMP enabled. Below code is added only to manage that + * scenario + */ +- if (!is_smp()) ++ freqs.new = omap_getspeed(policy->cpu); ++ if (!is_smp()) { + loops_per_jiffy = + cpufreq_scale(loops_per_jiffy, freqs.old, freqs.new); ++ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); ++ goto skip_lpj; ++ } + +- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); ++#ifdef CONFIG_SMP ++ /* ++ * Note that loops_per_jiffy is not updated on SMP systems in ++ * cpufreq driver. So, update the per-CPU loops_per_jiffy value ++ * on frequency transition. We need to update all dependent CPUs. ++ */ ++ for_each_cpu(i, policy->cpus) ++ per_cpu(cpu_data, i).loops_per_jiffy = ++ cpufreq_scale(per_cpu(cpu_data, i).loops_per_jiffy, ++ freqs.old, freqs.new); ++#endif + ++ /* notifiers */ ++ for_each_cpu(i, policy->cpus) { ++ freqs.cpu = i; ++ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); ++ } ++ ++skip_lpj: + return ret; + } + +@@ -118,6 +155,7 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) + { + int result = 0; + struct device *mpu_dev; ++ static cpumask_var_t cpumask; + + if (cpu_is_omap24xx()) + mpu_clk = clk_get(NULL, "virt_prcm_set"); +@@ -129,12 +167,12 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) + if (IS_ERR(mpu_clk)) + return PTR_ERR(mpu_clk); + +- if (policy->cpu != 0) ++ if (policy->cpu >= NR_CPUS) + return -EINVAL; + +- policy->cur = policy->min = policy->max = omap_getspeed(0); +- ++ policy->cur = policy->min = policy->max = omap_getspeed(policy->cpu); + mpu_dev = omap2_get_mpuss_device(); ++ + if (!mpu_dev) { + pr_warning("%s: unable to get the mpu device\n", __func__); + return -EINVAL; +@@ -154,7 +192,20 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) + + policy->min = policy->cpuinfo.min_freq; + policy->max = policy->cpuinfo.max_freq; +- policy->cur = omap_getspeed(0); ++ policy->cur = omap_getspeed(policy->cpu); ++ ++ /* ++ * On OMAP SMP configuartion, both processors share the voltage ++ * and clock. So both CPUs needs to be scaled together and hence ++ * needs software co-ordination. Use cpufreq affected_cpus ++ * interface to handle this scenario. Additional is_smp() check ++ * is to keep SMP_ON_UP build working. ++ */ ++ if (is_smp()) { ++ policy->shared_type = CPUFREQ_SHARED_TYPE_ANY; ++ cpumask_or(cpumask, cpumask_of(policy->cpu), cpumask); ++ cpumask_copy(policy->cpus, cpumask); ++ } + + /* FIXME: what's the actual transition time? */ + policy->cpuinfo.transition_latency = 300 * 1000; +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0008-OMAP2PLUS-cpufreq-Fix-typo-when-attempting-to-set-mp.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0008-OMAP2PLUS-cpufreq-Fix-typo-when-attempting-to-set-mp.patch new file mode 100644 index 00000000..3797443c --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0008-OMAP2PLUS-cpufreq-Fix-typo-when-attempting-to-set-mp.patch @@ -0,0 +1,29 @@ +From 6e101764a47cb6975a555e2237843ad391a542a4 Mon Sep 17 00:00:00 2001 +From: Jarkko Nikula <jhnikula@gmail.com> +Date: Thu, 14 Apr 2011 16:21:58 +0300 +Subject: [PATCH 8/8] OMAP2PLUS: cpufreq: Fix typo when attempting to set mpu_clk for OMAP4 + +Fix this typo as there is no dpll_mpu_ck for OMAP3 and code flow is clearly +trying to set mpu_clk for OMAP4 for which this dpll_mpu_ck is available. + +Signed-off-by: Jarkko Nikula <jhnikula@gmail.com> +--- + arch/arm/mach-omap2/omap2plus-cpufreq.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c +index 8d472f6..d53ce23 100644 +--- a/arch/arm/mach-omap2/omap2plus-cpufreq.c ++++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c +@@ -161,7 +161,7 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) + mpu_clk = clk_get(NULL, "virt_prcm_set"); + else if (cpu_is_omap34xx()) + mpu_clk = clk_get(NULL, "dpll1_ck"); +- else if (cpu_is_omap34xx()) ++ else if (cpu_is_omap44xx()) + mpu_clk = clk_get(NULL, "dpll_mpu_ck"); + + if (IS_ERR(mpu_clk)) +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0001-OMAP2-clockdomain-Add-an-api-to-read-idle-mode.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0001-OMAP2-clockdomain-Add-an-api-to-read-idle-mode.patch new file mode 100644 index 00000000..d9b05173 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0001-OMAP2-clockdomain-Add-an-api-to-read-idle-mode.patch @@ -0,0 +1,77 @@ +From 988f50cb51d18e81ed2f7673a09694d28c9d086a Mon Sep 17 00:00:00 2001 +From: Rajendra Nayak <rnayak@ti.com> +Date: Tue, 5 Apr 2011 15:22:31 +0530 +Subject: [PATCH 1/6] OMAP2+: clockdomain: Add an api to read idle mode + +Add a clockdomain api to check if hardware supervised +idle transitions are enabled on a clockdomain. + +Signed-off-by: Rajendra Nayak <rnayak@ti.com> +--- + arch/arm/mach-omap2/clockdomain.c | 21 +++++++++++++++++++++ + arch/arm/mach-omap2/clockdomain.h | 3 +++ + 2 files changed, 24 insertions(+), 0 deletions(-) + +diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c +index 6cb6c03..2ab3686 100644 +--- a/arch/arm/mach-omap2/clockdomain.c ++++ b/arch/arm/mach-omap2/clockdomain.c +@@ -795,6 +795,27 @@ void clkdm_deny_idle(struct clockdomain *clkdm) + arch_clkdm->clkdm_deny_idle(clkdm); + } + ++/** ++ * clkdm_is_idle - Check if the clkdm hwsup/autoidle is enabled ++ * @clkdm: struct clockdomain * ++ * ++ * Returns true if the clockdomain is in hardware-supervised ++ * idle mode, or 0 otherwise. ++ * ++ */ ++int clkdm_is_idle(struct clockdomain *clkdm) ++{ ++ if (!clkdm) ++ return -EINVAL; ++ ++ if (!arch_clkdm || !arch_clkdm->clkdm_is_idle) ++ return -EINVAL; ++ ++ pr_debug("clockdomain: reading idle state for %s\n", clkdm->name); ++ ++ return arch_clkdm->clkdm_is_idle(clkdm); ++} ++ + + /* Clockdomain-to-clock framework interface code */ + +diff --git a/arch/arm/mach-omap2/clockdomain.h b/arch/arm/mach-omap2/clockdomain.h +index 5823584..085ed82 100644 +--- a/arch/arm/mach-omap2/clockdomain.h ++++ b/arch/arm/mach-omap2/clockdomain.h +@@ -138,6 +138,7 @@ struct clockdomain { + * @clkdm_wakeup: Force a clockdomain to wakeup + * @clkdm_allow_idle: Enable hw supervised idle transitions for clock domain + * @clkdm_deny_idle: Disable hw supervised idle transitions for clock domain ++ * @clkdm_is_idle: Check if hw supervised idle transitions are enabled + * @clkdm_clk_enable: Put the clkdm in right state for a clock enable + * @clkdm_clk_disable: Put the clkdm in right state for a clock disable + */ +@@ -154,6 +155,7 @@ struct clkdm_ops { + int (*clkdm_wakeup)(struct clockdomain *clkdm); + void (*clkdm_allow_idle)(struct clockdomain *clkdm); + void (*clkdm_deny_idle)(struct clockdomain *clkdm); ++ int (*clkdm_is_idle)(struct clockdomain *clkdm); + int (*clkdm_clk_enable)(struct clockdomain *clkdm); + int (*clkdm_clk_disable)(struct clockdomain *clkdm); + }; +@@ -177,6 +179,7 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm); + + void clkdm_allow_idle(struct clockdomain *clkdm); + void clkdm_deny_idle(struct clockdomain *clkdm); ++int clkdm_is_idle(struct clockdomain *clkdm); + + int clkdm_wakeup(struct clockdomain *clkdm); + int clkdm_sleep(struct clockdomain *clkdm); +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0002-OMAP2-clockdomain-Add-SoC-support-for-clkdm_is_idle.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0002-OMAP2-clockdomain-Add-SoC-support-for-clkdm_is_idle.patch new file mode 100644 index 00000000..c7c1ea0b --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0002-OMAP2-clockdomain-Add-SoC-support-for-clkdm_is_idle.patch @@ -0,0 +1,86 @@ +From e3ba8d41bfafd782f3ee7f8930d9bf393986c662 Mon Sep 17 00:00:00 2001 +From: Rajendra Nayak <rnayak@ti.com> +Date: Tue, 5 Apr 2011 15:22:36 +0530 +Subject: [PATCH 2/6] OMAP2+: clockdomain: Add SoC support for clkdm_is_idle + +Add the SoC specific implemenation for clkdm_is_idle +for OMAP2/3 and OMAP4. + +Signed-off-by: Rajendra Nayak <rnayak@ti.com> +--- + arch/arm/mach-omap2/clockdomain2xxx_3xxx.c | 12 ++++++++++++ + arch/arm/mach-omap2/clockdomain44xx.c | 7 +++++++ + 2 files changed, 19 insertions(+), 0 deletions(-) + +diff --git a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c +index 48d0db7..db49baa 100644 +--- a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c ++++ b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c +@@ -13,6 +13,7 @@ + */ + + #include <linux/types.h> ++#include <linux/errno.h> + #include <plat/prcm.h> + #include "prm.h" + #include "prm2xxx_3xxx.h" +@@ -146,6 +147,15 @@ static void omap2_clkdm_deny_idle(struct clockdomain *clkdm) + _clkdm_del_autodeps(clkdm); + } + ++static int omap2_clkdm_is_idle(struct clockdomain *clkdm) ++{ ++ if (!clkdm->clktrctrl_mask) ++ return -1; ++ ++ return omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, ++ clkdm->clktrctrl_mask); ++} ++ + static void _enable_hwsup(struct clockdomain *clkdm) + { + if (cpu_is_omap24xx()) +@@ -252,6 +262,7 @@ struct clkdm_ops omap2_clkdm_operations = { + .clkdm_wakeup = omap2_clkdm_wakeup, + .clkdm_allow_idle = omap2_clkdm_allow_idle, + .clkdm_deny_idle = omap2_clkdm_deny_idle, ++ .clkdm_is_idle = omap2_clkdm_is_idle, + .clkdm_clk_enable = omap2_clkdm_clk_enable, + .clkdm_clk_disable = omap2_clkdm_clk_disable, + }; +@@ -269,6 +280,7 @@ struct clkdm_ops omap3_clkdm_operations = { + .clkdm_wakeup = omap3_clkdm_wakeup, + .clkdm_allow_idle = omap3_clkdm_allow_idle, + .clkdm_deny_idle = omap3_clkdm_deny_idle, ++ .clkdm_is_idle = omap2_clkdm_is_idle, + .clkdm_clk_enable = omap2_clkdm_clk_enable, + .clkdm_clk_disable = omap2_clkdm_clk_disable, + }; +diff --git a/arch/arm/mach-omap2/clockdomain44xx.c b/arch/arm/mach-omap2/clockdomain44xx.c +index a1a4ecd..4b10727 100644 +--- a/arch/arm/mach-omap2/clockdomain44xx.c ++++ b/arch/arm/mach-omap2/clockdomain44xx.c +@@ -93,6 +93,12 @@ static void omap4_clkdm_deny_idle(struct clockdomain *clkdm) + clkdm->cm_inst, clkdm->clkdm_offs); + } + ++static int omap4_clkdm_is_idle(struct clockdomain *clkdm) ++{ ++ return omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition, ++ clkdm->cm_inst, clkdm->clkdm_offs); ++} ++ + static int omap4_clkdm_clk_enable(struct clockdomain *clkdm) + { + bool hwsup = false; +@@ -132,6 +138,7 @@ struct clkdm_ops omap4_clkdm_operations = { + .clkdm_wakeup = omap4_clkdm_wakeup, + .clkdm_allow_idle = omap4_clkdm_allow_idle, + .clkdm_deny_idle = omap4_clkdm_deny_idle, ++ .clkdm_is_idle = omap4_clkdm_is_idle, + .clkdm_clk_enable = omap4_clkdm_clk_enable, + .clkdm_clk_disable = omap4_clkdm_clk_disable, + }; +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0003-OMAP2-PM-Initialise-sleep_switch-to-a-non-valid-valu.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0003-OMAP2-PM-Initialise-sleep_switch-to-a-non-valid-valu.patch new file mode 100644 index 00000000..cbe5ca20 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0003-OMAP2-PM-Initialise-sleep_switch-to-a-non-valid-valu.patch @@ -0,0 +1,35 @@ +From 7cdc87071a4bb390ad5d7ddea210bd2b4d662114 Mon Sep 17 00:00:00 2001 +From: Rajendra Nayak <rnayak@ti.com> +Date: Tue, 5 Apr 2011 15:22:41 +0530 +Subject: [PATCH 3/6] OMAP2+: PM: Initialise sleep_switch to a non-valid value + +sleep_switch which is initialised to 0 in omap_set_pwrdm_state +happens to be a valid sleep_switch type (FORCEWAKEUP_SWITCH) +which are defined as +#define FORCEWAKEUP_SWITCH 0 +#define LOWPOWERSTATE_SWITCH 1 + +This causes the function to wrongly program some clock domains +even when the Powerdomain is in ON state. + +Signed-off-by: Rajendra Nayak <rnayak@ti.com> +--- + arch/arm/mach-omap2/pm.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c +index 49486f5..d48813f 100644 +--- a/arch/arm/mach-omap2/pm.c ++++ b/arch/arm/mach-omap2/pm.c +@@ -106,7 +106,7 @@ static void omap2_init_processor_devices(void) + int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) + { + u32 cur_state; +- int sleep_switch = 0; ++ int sleep_switch = -1; + int ret = 0; + + if (pwrdm == NULL || IS_ERR(pwrdm)) +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0004-OMAP2-PM-idle-clkdms-only-if-already-in-idle.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0004-OMAP2-PM-idle-clkdms-only-if-already-in-idle.patch new file mode 100644 index 00000000..16eedf9a --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0004-OMAP2-PM-idle-clkdms-only-if-already-in-idle.patch @@ -0,0 +1,50 @@ +From cec133850aa42c03d912c764aaa441677e782eca Mon Sep 17 00:00:00 2001 +From: Rajendra Nayak <rnayak@ti.com> +Date: Tue, 5 Apr 2011 15:22:48 +0530 +Subject: [PATCH 4/6] OMAP2+: PM: idle clkdms only if already in idle + +The omap_set_pwrdm_state function forces clockdomains +to idle, without checking the existing idle state +programmed, instead based solely on the HW capability +of the clockdomain to support idle. +This is wrong and the clockdomains should be idled +post a state_switch *only* if idle transitions on the +clockdomain were already enabled. + +Signed-off-by: Rajendra Nayak <rnayak@ti.com> +--- + arch/arm/mach-omap2/pm.c | 4 +++- + 1 files changed, 3 insertions(+), 1 deletions(-) + +diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c +index d48813f..840b0e1 100644 +--- a/arch/arm/mach-omap2/pm.c ++++ b/arch/arm/mach-omap2/pm.c +@@ -108,6 +108,7 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) + u32 cur_state; + int sleep_switch = -1; + int ret = 0; ++ int hwsup = 0; + + if (pwrdm == NULL || IS_ERR(pwrdm)) + return -EINVAL; +@@ -127,6 +128,7 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) + (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) { + sleep_switch = LOWPOWERSTATE_SWITCH; + } else { ++ hwsup = clkdm_is_idle(pwrdm->pwrdm_clkdms[0]); + clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); + pwrdm_wait_transition(pwrdm); + sleep_switch = FORCEWAKEUP_SWITCH; +@@ -142,7 +144,7 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) + + switch (sleep_switch) { + case FORCEWAKEUP_SWITCH: +- if (pwrdm->pwrdm_clkdms[0]->flags & CLKDM_CAN_ENABLE_AUTO) ++ if (hwsup) + clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); + else + clkdm_sleep(pwrdm->pwrdm_clkdms[0]); +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0005-OMAP2-hwmod-Follow-the-recomended-PRCM-sequence.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0005-OMAP2-hwmod-Follow-the-recomended-PRCM-sequence.patch new file mode 100644 index 00000000..b0af9e7f --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0005-OMAP2-hwmod-Follow-the-recomended-PRCM-sequence.patch @@ -0,0 +1,46 @@ +From 8fb6b7c488b31fbff5b81bdeea5dbb236342458b Mon Sep 17 00:00:00 2001 +From: Rajendra Nayak <rnayak@ti.com> +Date: Tue, 29 Mar 2011 22:37:43 +0530 +Subject: [PATCH 5/6] OMAP2+: hwmod: Follow the recomended PRCM sequence + +Follow the recomended PRCM sequence. +This still does not take care of Optional clocks. + +Signed-off-by: Rajendra Nayak <rnayak@ti.com> +--- + arch/arm/mach-omap2/omap_hwmod.c | 9 ++++++++- + 1 files changed, 8 insertions(+), 1 deletions(-) + +diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c +index e034294..fc0db0c 100644 +--- a/arch/arm/mach-omap2/omap_hwmod.c ++++ b/arch/arm/mach-omap2/omap_hwmod.c +@@ -1223,6 +1223,7 @@ static int _reset(struct omap_hwmod *oh) + static int _enable(struct omap_hwmod *oh) + { + int r; ++ int hwsup = 0; + + if (oh->_state != _HWMOD_STATE_INITIALIZED && + oh->_state != _HWMOD_STATE_IDLE && +@@ -1250,10 +1251,16 @@ static int _enable(struct omap_hwmod *oh) + omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED); + + _add_initiator_dep(oh, mpu_oh); ++ if (oh->_clk && oh->_clk->clkdm) { ++ hwsup = clkdm_is_idle(oh->_clk->clkdm); ++ clkdm_wakeup(oh->_clk->clkdm); ++ } + _enable_clocks(oh); +- + r = _wait_target_ready(oh); + if (!r) { ++ if (oh->_clk && oh->_clk->clkdm && hwsup) ++ clkdm_allow_idle(oh->_clk->clkdm); ++ + oh->_state = _HWMOD_STATE_ENABLED; + + /* Access the sysconfig only if the target is ready */ +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0006-OMAP-Serial-Check-wk_st-only-if-present.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0006-OMAP-Serial-Check-wk_st-only-if-present.patch new file mode 100644 index 00000000..a8fc0c07 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0006-OMAP-Serial-Check-wk_st-only-if-present.patch @@ -0,0 +1,33 @@ +From 7b74888d198c260992349fab214cad3adf853ef9 Mon Sep 17 00:00:00 2001 +From: Rajendra Nayak <rnayak@ti.com> +Date: Tue, 2 Mar 2010 17:25:30 +0530 +Subject: [PATCH 6/6] OMAP: Serial: Check wk_st only if present + +Uart on the resume path tries to read wk_st registers, even +on architectures were its not present/populated. +This patch fixes the issue. + +Signed-off-by: Rajendra Nayak <rnayak@ti.com> +--- + arch/arm/mach-omap2/serial.c | 5 +++-- + 1 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c +index 1ac361b..a0046ce 100644 +--- a/arch/arm/mach-omap2/serial.c ++++ b/arch/arm/mach-omap2/serial.c +@@ -418,8 +418,9 @@ void omap_uart_resume_idle(int num) + } + + /* Check for normal UART wakeup */ +- if (__raw_readl(uart->wk_st) & uart->wk_mask) +- omap_uart_block_sleep(uart); ++ if (uart->wk_st && uart->wk_mask) ++ if (__raw_readl(uart->wk_st) & uart->wk_mask) ++ omap_uart_block_sleep(uart); + return; + } + } +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0001-OMAP3-voltage-remove-spurious-pr_notice-for-debugfs.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0001-OMAP3-voltage-remove-spurious-pr_notice-for-debugfs.patch new file mode 100644 index 00000000..0d1cbce6 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0001-OMAP3-voltage-remove-spurious-pr_notice-for-debugfs.patch @@ -0,0 +1,30 @@ +From 4af697edf9d1d85d2735e86e86e1203c3509dcba Mon Sep 17 00:00:00 2001 +From: Nishanth Menon <nm@ti.com> +Date: Sat, 12 Feb 2011 17:27:14 +0530 +Subject: [PATCH 01/12] OMAP3+: voltage: remove spurious pr_notice for debugfs + +cat of debugfs entry for vp_volt provides voltage. The additional pr_notice +is just spam on console and provides no additional information. + +Signed-off-by: Nishanth Menon <nm@ti.com> +Signed-off-by: Kevin Hilman <khilman@ti.com> +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/mach-omap2/voltage.c | 1 - + 1 files changed, 0 insertions(+), 1 deletions(-) + +diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c +index 0c1552d..9ef3789 100644 +--- a/arch/arm/mach-omap2/voltage.c ++++ b/arch/arm/mach-omap2/voltage.c +@@ -148,7 +148,6 @@ static int vp_volt_debug_get(void *data, u64 *val) + } + + vsel = vdd->read_reg(prm_mod_offs, vdd->vp_data->voltage); +- pr_notice("curr_vsel = %x\n", vsel); + + if (!vdd->pmic_info->vsel_to_uv) { + pr_warning("PMIC function to convert vsel to voltage" +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0002-OMAP4-PM-remove-redundant-ifdef-CONFIG_PM.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0002-OMAP4-PM-remove-redundant-ifdef-CONFIG_PM.patch new file mode 100644 index 00000000..7b137925 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0002-OMAP4-PM-remove-redundant-ifdef-CONFIG_PM.patch @@ -0,0 +1,41 @@ +From 37fb1c8eeecd39542716d3d0c7c5e3ca0eb198f8 Mon Sep 17 00:00:00 2001 +From: Nishanth Menon <nm@ti.com> +Date: Sun, 13 Mar 2011 09:07:23 +0530 +Subject: [PATCH 02/12] OMAP4: PM: remove redundant #ifdef CONFIG_PM + +pm44xx.c is built only when CONFIG_PM is setup, +remove redundant CONFIG_PM check. + +This also fixes: +https://bugzilla.kernel.org/show_bug.cgi?id=25022 + +Reported-by: Martin Etti <ettl.martin@gmx.de> + +Signed-off-by: Nishanth Menon <nm@ti.com> +Signed-off-by: Kevin Hilman <khilman@ti.com> +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/mach-omap2/pm44xx.c | 2 -- + 1 files changed, 0 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c +index 76cfff2..59a870b 100644 +--- a/arch/arm/mach-omap2/pm44xx.c ++++ b/arch/arm/mach-omap2/pm44xx.c +@@ -105,13 +105,11 @@ static int __init omap4_pm_init(void) + + pr_err("Power Management for TI OMAP4.\n"); + +-#ifdef CONFIG_PM + ret = pwrdm_for_each(pwrdms_setup, NULL); + if (ret) { + pr_err("Failed to setup powerdomains\n"); + goto err2; + } +-#endif + + #ifdef CONFIG_SUSPEND + suspend_set_ops(&omap_pm_ops); +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0003-OMAP3-smartreflex-fix-sr_late_init-error-path-in-pro.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0003-OMAP3-smartreflex-fix-sr_late_init-error-path-in-pro.patch new file mode 100644 index 00000000..6c37b622 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0003-OMAP3-smartreflex-fix-sr_late_init-error-path-in-pro.patch @@ -0,0 +1,30 @@ +From a22a0dcefe99c8ee260e0c489bc44e6e14bb1ccb Mon Sep 17 00:00:00 2001 +From: Aaro Koskinen <aaro.koskinen@nokia.com> +Date: Thu, 24 Mar 2011 18:35:31 +0200 +Subject: [PATCH 03/12] OMAP3+: smartreflex: fix sr_late_init() error path in probe + +sr_late_init() will take care of freeing the resources. + +Signed-off-by: Aaro Koskinen <aaro.koskinen@nokia.com> +Signed-off-by: Kevin Hilman <khilman@ti.com> +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/mach-omap2/smartreflex.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c +index 13e24f9..dbc4b6f 100644 +--- a/arch/arm/mach-omap2/smartreflex.c ++++ b/arch/arm/mach-omap2/smartreflex.c +@@ -883,7 +883,7 @@ static int __init omap_sr_probe(struct platform_device *pdev) + ret = sr_late_init(sr_info); + if (ret) { + pr_warning("%s: Error in SR late init\n", __func__); +- goto err_release_region; ++ return ret; + } + } + +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0004-OMAP3-smartreflex-request-the-memory-region.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0004-OMAP3-smartreflex-request-the-memory-region.patch new file mode 100644 index 00000000..263094d5 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0004-OMAP3-smartreflex-request-the-memory-region.patch @@ -0,0 +1,36 @@ +From db9c7da6a78be8584c96c83a3a2d1c8aeb623da8 Mon Sep 17 00:00:00 2001 +From: Aaro Koskinen <aaro.koskinen@nokia.com> +Date: Thu, 24 Mar 2011 18:35:32 +0200 +Subject: [PATCH 04/12] OMAP3+: smartreflex: request the memory region + +We are releasing the memory region, but never actually request it. + +Signed-off-by: Aaro Koskinen <aaro.koskinen@nokia.com> +Signed-off-by: Kevin Hilman <khilman@ti.com> +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/mach-omap2/smartreflex.c | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c +index dbc4b6f..703143a 100644 +--- a/arch/arm/mach-omap2/smartreflex.c ++++ b/arch/arm/mach-omap2/smartreflex.c +@@ -847,6 +847,14 @@ static int __init omap_sr_probe(struct platform_device *pdev) + goto err_free_devinfo; + } + ++ mem = request_mem_region(mem->start, resource_size(mem), ++ dev_name(&pdev->dev)); ++ if (!mem) { ++ dev_err(&pdev->dev, "%s: no mem region\n", __func__); ++ ret = -EBUSY; ++ goto err_free_devinfo; ++ } ++ + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + + pm_runtime_enable(&pdev->dev); +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0005-OMAP3-smartreflex-fix-ioremap-leak-on-probe-error.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0005-OMAP3-smartreflex-fix-ioremap-leak-on-probe-error.patch new file mode 100644 index 00000000..ea1e5673 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0005-OMAP3-smartreflex-fix-ioremap-leak-on-probe-error.patch @@ -0,0 +1,66 @@ +From b3ca51ac09da7c260c28df396d4c830814697ff0 Mon Sep 17 00:00:00 2001 +From: Aaro Koskinen <aaro.koskinen@nokia.com> +Date: Thu, 24 Mar 2011 18:35:33 +0200 +Subject: [PATCH 05/12] OMAP3+: smartreflex: fix ioremap leak on probe error + +Add missing iounmap() to error paths. + +Signed-off-by: Aaro Koskinen <aaro.koskinen@nokia.com> +Signed-off-by: Kevin Hilman <khilman@ti.com> +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/mach-omap2/smartreflex.c | 10 ++++++---- + 1 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c +index 703143a..156807e 100644 +--- a/arch/arm/mach-omap2/smartreflex.c ++++ b/arch/arm/mach-omap2/smartreflex.c +@@ -904,7 +904,7 @@ static int __init omap_sr_probe(struct platform_device *pdev) + vdd_dbg_dir = omap_voltage_get_dbgdir(sr_info->voltdm); + if (!vdd_dbg_dir) { + ret = -EINVAL; +- goto err_release_region; ++ goto err_iounmap; + } + + sr_info->dbg_dir = debugfs_create_dir("smartreflex", vdd_dbg_dir); +@@ -912,7 +912,7 @@ static int __init omap_sr_probe(struct platform_device *pdev) + dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n", + __func__); + ret = PTR_ERR(sr_info->dbg_dir); +- goto err_release_region; ++ goto err_iounmap; + } + + (void) debugfs_create_file("autocomp", S_IRUGO | S_IWUSR, +@@ -929,7 +929,7 @@ static int __init omap_sr_probe(struct platform_device *pdev) + dev_err(&pdev->dev, "%s: Unable to create debugfs directory" + "for n-values\n", __func__); + ret = PTR_ERR(nvalue_dir); +- goto err_release_region; ++ goto err_iounmap; + } + + omap_voltage_get_volttable(sr_info->voltdm, &volt_data); +@@ -939,7 +939,7 @@ static int __init omap_sr_probe(struct platform_device *pdev) + "entries for n-values\n", + __func__, sr_info->voltdm->name); + ret = -ENODATA; +- goto err_release_region; ++ goto err_iounmap; + } + + for (i = 0; i < sr_info->nvalue_count; i++) { +@@ -953,6 +953,8 @@ static int __init omap_sr_probe(struct platform_device *pdev) + + return ret; + ++err_iounmap: ++ iounmap(sr_info->base); + err_release_region: + release_mem_region(mem->start, resource_size(mem)); + err_free_devinfo: +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0006-OMAP3-smartreflex-delete-instance-from-sr_list-on-pr.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0006-OMAP3-smartreflex-delete-instance-from-sr_list-on-pr.patch new file mode 100644 index 00000000..cda6da63 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0006-OMAP3-smartreflex-delete-instance-from-sr_list-on-pr.patch @@ -0,0 +1,29 @@ +From 92e63a2f098ce344cfc51ec9a7420e1a5cf85c3e Mon Sep 17 00:00:00 2001 +From: Aaro Koskinen <aaro.koskinen@nokia.com> +Date: Thu, 24 Mar 2011 18:35:34 +0200 +Subject: [PATCH 06/12] OMAP3+: smartreflex: delete instance from sr_list on probe error + +If the probe fails, the node should be deleted from sr_list. + +Signed-off-by: Aaro Koskinen <aaro.koskinen@nokia.com> +Signed-off-by: Kevin Hilman <khilman@ti.com> +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/mach-omap2/smartreflex.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c +index 156807e..f0a488a 100644 +--- a/arch/arm/mach-omap2/smartreflex.c ++++ b/arch/arm/mach-omap2/smartreflex.c +@@ -954,6 +954,7 @@ static int __init omap_sr_probe(struct platform_device *pdev) + return ret; + + err_iounmap: ++ list_del(&sr_info->node); + iounmap(sr_info->base); + err_release_region: + release_mem_region(mem->start, resource_size(mem)); +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0007-OMAP3-smartreflex-delete-debugfs-entries-on-probe-er.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0007-OMAP3-smartreflex-delete-debugfs-entries-on-probe-er.patch new file mode 100644 index 00000000..d4543a46 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0007-OMAP3-smartreflex-delete-debugfs-entries-on-probe-er.patch @@ -0,0 +1,48 @@ +From c194377152df812bcb29fff8f217ffbde59089be Mon Sep 17 00:00:00 2001 +From: Aaro Koskinen <aaro.koskinen@nokia.com> +Date: Thu, 24 Mar 2011 18:35:35 +0200 +Subject: [PATCH 07/12] OMAP3+: smartreflex: delete debugfs entries on probe error + +Delete created debugfs entries if probe fails. + +Signed-off-by: Aaro Koskinen <aaro.koskinen@nokia.com> +Signed-off-by: Kevin Hilman <khilman@ti.com> +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/mach-omap2/smartreflex.c | 6 ++++-- + 1 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c +index f0a488a..fb7dc52 100644 +--- a/arch/arm/mach-omap2/smartreflex.c ++++ b/arch/arm/mach-omap2/smartreflex.c +@@ -929,7 +929,7 @@ static int __init omap_sr_probe(struct platform_device *pdev) + dev_err(&pdev->dev, "%s: Unable to create debugfs directory" + "for n-values\n", __func__); + ret = PTR_ERR(nvalue_dir); +- goto err_iounmap; ++ goto err_debugfs; + } + + omap_voltage_get_volttable(sr_info->voltdm, &volt_data); +@@ -939,7 +939,7 @@ static int __init omap_sr_probe(struct platform_device *pdev) + "entries for n-values\n", + __func__, sr_info->voltdm->name); + ret = -ENODATA; +- goto err_iounmap; ++ goto err_debugfs; + } + + for (i = 0; i < sr_info->nvalue_count; i++) { +@@ -953,6 +953,8 @@ static int __init omap_sr_probe(struct platform_device *pdev) + + return ret; + ++err_debugfs: ++ debugfs_remove_recursive(sr_info->dbg_dir); + err_iounmap: + list_del(&sr_info->node); + iounmap(sr_info->base); +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0008-OMAP3-cpuidle-remove-useless-SDP-specific-timings.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0008-OMAP3-cpuidle-remove-useless-SDP-specific-timings.patch new file mode 100644 index 00000000..e3ee0412 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0008-OMAP3-cpuidle-remove-useless-SDP-specific-timings.patch @@ -0,0 +1,57 @@ +From 2b9e07516cc3853340b5e06e9ae7244ca5681466 Mon Sep 17 00:00:00 2001 +From: Jean Pihet <j-pihet@ti.com> +Date: Fri, 29 Apr 2011 11:26:22 +0200 +Subject: [PATCH 08/12] OMAP3 cpuidle: remove useless SDP specific timings + +The cpuidle states settings can be overriden by some board- +specific settings, by calling omap3_pm_init_cpuidle. +Remove the 3430SDP specific states settings registration +since the figures are identical to the default ones (in cpuidle34xx.c). + +Signed-off-by: Jean Pihet <j-pihet@ti.com> +Signed-off-by: Kevin Hilman <khilman@ti.com> +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/mach-omap2/board-3430sdp.c | 19 ------------------- + 1 files changed, 0 insertions(+), 19 deletions(-) + +diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c +index 9afd087..7ffad7b 100644 +--- a/arch/arm/mach-omap2/board-3430sdp.c ++++ b/arch/arm/mach-omap2/board-3430sdp.c +@@ -59,24 +59,6 @@ + + #define TWL4030_MSECURE_GPIO 22 + +-/* FIXME: These values need to be updated based on more profiling on 3430sdp*/ +-static struct cpuidle_params omap3_cpuidle_params_table[] = { +- /* C1 */ +- {1, 2, 2, 5}, +- /* C2 */ +- {1, 10, 10, 30}, +- /* C3 */ +- {1, 50, 50, 300}, +- /* C4 */ +- {1, 1500, 1800, 4000}, +- /* C5 */ +- {1, 2500, 7500, 12000}, +- /* C6 */ +- {1, 3000, 8500, 15000}, +- /* C7 */ +- {1, 10000, 30000, 300000}, +-}; +- + static uint32_t board_keymap[] = { + KEY(0, 0, KEY_LEFT), + KEY(0, 1, KEY_RIGHT), +@@ -883,7 +865,6 @@ static void __init omap_3430sdp_init(void) + omap3_mux_init(board_mux, OMAP_PACKAGE_CBB); + omap_board_config = sdp3430_config; + omap_board_config_size = ARRAY_SIZE(sdp3430_config); +- omap3_pm_init_cpuidle(omap3_cpuidle_params_table); + omap3430_i2c_init(); + omap_display_init(&sdp3430_dss_data); + if (omap_rev() > OMAP3430_REV_ES1_0) +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0009-OMAP3-SR-make-notify-independent-of-class.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0009-OMAP3-SR-make-notify-independent-of-class.patch new file mode 100644 index 00000000..c44371df --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0009-OMAP3-SR-make-notify-independent-of-class.patch @@ -0,0 +1,48 @@ +From a0f28097b944930e479998780863b9e5a39e30b3 Mon Sep 17 00:00:00 2001 +From: Nishanth Menon <nm@ti.com> +Date: Mon, 14 Feb 2011 12:16:36 +0530 +Subject: [PATCH 09/12] OMAP3+: SR: make notify independent of class + +Interrupt notification mechanism of SmartReflex can be used by the +choice of implementation of the class driver. For example, Class 2 and +Class 1.5 of SmartReflex can both use the interrupt notification to +identify the transition of voltage or other events. + +Hence, the actual class does not matter for notifier. Let the class +driver's handling decide how it should be used. SmartReflex driver +should provide just the primitives. + +Signed-off-by: Nishanth Menon <nm@ti.com> +Signed-off-by: Kevin Hilman <khilman@ti.com> +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/mach-omap2/smartreflex.c | 6 ++---- + 1 files changed, 2 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c +index fb7dc52..3ee7261 100644 +--- a/arch/arm/mach-omap2/smartreflex.c ++++ b/arch/arm/mach-omap2/smartreflex.c +@@ -143,7 +143,7 @@ static irqreturn_t sr_interrupt(int irq, void *data) + sr_write_reg(sr_info, IRQSTATUS, status); + } + +- if (sr_class->class_type == SR_CLASS2 && sr_class->notify) ++ if (sr_class->notify) + sr_class->notify(sr_info->voltdm, status); + + return IRQ_HANDLED; +@@ -258,9 +258,7 @@ static int sr_late_init(struct omap_sr *sr_info) + struct resource *mem; + int ret = 0; + +- if (sr_class->class_type == SR_CLASS2 && +- sr_class->notify_flags && sr_info->irq) { +- ++ if (sr_class->notify && sr_class->notify_flags && sr_info->irq) { + name = kasprintf(GFP_KERNEL, "sr_%s", sr_info->voltdm->name); + if (name == NULL) { + ret = -ENOMEM; +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0010-OMAP3-SR-disable-interrupt-by-default.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0010-OMAP3-SR-disable-interrupt-by-default.patch new file mode 100644 index 00000000..e25c3e86 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0010-OMAP3-SR-disable-interrupt-by-default.patch @@ -0,0 +1,37 @@ +From ca5dc57538a566681731102e09a9d1865a4a7020 Mon Sep 17 00:00:00 2001 +From: Nishanth Menon <nm@ti.com> +Date: Mon, 14 Feb 2011 12:41:10 +0530 +Subject: [PATCH 10/12] OMAP3+: SR: disable interrupt by default + +We will enable and disable interrupt on a need basis in the class +driver. We need to keep the IRQ disabled by default else the +forceupdate or vcbypass events could trigger events that we don't +need/expect to handle. + +This is a preparation for SmartReflex AVS class drivers such as +class 2 and class 1.5 which would need to use interrupts. Existing +SmartReflex AVS class 3 driver does not require to use interrupts +and is not impacted by this change. + +Signed-off-by: Nishanth Menon <nm@ti.com> +Signed-off-by: Kevin Hilman <khilman@ti.com> +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/mach-omap2/smartreflex.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c +index 3ee7261..616ef62 100644 +--- a/arch/arm/mach-omap2/smartreflex.c ++++ b/arch/arm/mach-omap2/smartreflex.c +@@ -268,6 +268,7 @@ static int sr_late_init(struct omap_sr *sr_info) + 0, name, (void *)sr_info); + if (ret) + goto error; ++ disable_irq(sr_info->irq); + } + + if (pdata && pdata->enable_on_init) +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0011-OMAP3-SR-enable-disable-SR-only-on-need.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0011-OMAP3-SR-enable-disable-SR-only-on-need.patch new file mode 100644 index 00000000..b96682ea --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0011-OMAP3-SR-enable-disable-SR-only-on-need.patch @@ -0,0 +1,41 @@ +From 4aa67e94d6b13905abcf3e95cb66ea7be9c2e8dd Mon Sep 17 00:00:00 2001 +From: Nishanth Menon <nm@ti.com> +Date: Mon, 14 Feb 2011 21:14:17 +0530 +Subject: [PATCH 11/12] OMAP3+: SR: enable/disable SR only on need + +Since we already know the state of the autocomp enablement, we can +see if the requested state is different from the current state and +enable/disable SR only on the need basis. + +Signed-off-by: Nishanth Menon <nm@ti.com> +Signed-off-by: Kevin Hilman <khilman@ti.com> +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/mach-omap2/smartreflex.c | 11 +++++++---- + 1 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c +index 616ef62..3bd9fac 100644 +--- a/arch/arm/mach-omap2/smartreflex.c ++++ b/arch/arm/mach-omap2/smartreflex.c +@@ -807,10 +807,13 @@ static int omap_sr_autocomp_store(void *data, u64 val) + return -EINVAL; + } + +- if (!val) +- sr_stop_vddautocomp(sr_info); +- else +- sr_start_vddautocomp(sr_info); ++ /* control enable/disable only if there is a delta in value */ ++ if (sr_info->autocomp_active != val) { ++ if (!val) ++ sr_stop_vddautocomp(sr_info); ++ else ++ sr_start_vddautocomp(sr_info); ++ } + + return 0; + } +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0012-OMAP3-SR-fix-cosmetic-indentation.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0012-OMAP3-SR-fix-cosmetic-indentation.patch new file mode 100644 index 00000000..eda76a0d --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/pm/linux-omap-2.6.39-ti-pm/0012-OMAP3-SR-fix-cosmetic-indentation.patch @@ -0,0 +1,49 @@ +From 0c2089eecdfc3a85a376eddf9c77857f3d575be6 Mon Sep 17 00:00:00 2001 +From: Nishanth Menon <nm@ti.com> +Date: Mon, 14 Feb 2011 12:33:13 +0530 +Subject: [PATCH 12/12] OMAP3+: SR: fix cosmetic indentation + +Error label case seems to have a 2 tab indentation when just 1 is +necessary. + +Signed-off-by: Nishanth Menon <nm@ti.com> +Signed-off-by: Kevin Hilman <khilman@ti.com> +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> +--- + arch/arm/mach-omap2/smartreflex.c | 20 ++++++++++---------- + 1 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c +index 3bd9fac..2ce2fb7 100644 +--- a/arch/arm/mach-omap2/smartreflex.c ++++ b/arch/arm/mach-omap2/smartreflex.c +@@ -277,16 +277,16 @@ static int sr_late_init(struct omap_sr *sr_info) + return ret; + + error: +- iounmap(sr_info->base); +- mem = platform_get_resource(sr_info->pdev, IORESOURCE_MEM, 0); +- release_mem_region(mem->start, resource_size(mem)); +- list_del(&sr_info->node); +- dev_err(&sr_info->pdev->dev, "%s: ERROR in registering" +- "interrupt handler. Smartreflex will" +- "not function as desired\n", __func__); +- kfree(name); +- kfree(sr_info); +- return ret; ++ iounmap(sr_info->base); ++ mem = platform_get_resource(sr_info->pdev, IORESOURCE_MEM, 0); ++ release_mem_region(mem->start, resource_size(mem)); ++ list_del(&sr_info->node); ++ dev_err(&sr_info->pdev->dev, "%s: ERROR in registering" ++ "interrupt handler. Smartreflex will" ++ "not function as desired\n", __func__); ++ kfree(name); ++ kfree(sr_info); ++ return ret; + } + + static void sr_v1_disable(struct omap_sr *sr) +-- +1.6.6.1 + |