summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-tegra/clock.h6
-rw-r--r--arch/arm/mach-tegra/cpu-tegra.c20
-rw-r--r--arch/arm/mach-tegra/tegra3_clocks.c24
3 files changed, 47 insertions, 3 deletions
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index 33dfe3e47718..b47821e12274 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -298,6 +298,12 @@ struct tegra_cpufreq_table_data {
};
struct tegra_cpufreq_table_data *tegra_cpufreq_table_get(void);
unsigned long tegra_emc_to_cpu_ratio(unsigned long cpu_rate);
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+static inline int tegra_update_mselect_rate(unsigned long cpu_rate)
+{ return 0; }
+#else
+int tegra_update_mselect_rate(unsigned long cpu_rate);
+#endif
#endif
#endif
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
index 24ed5d229a5d..de290ce65804 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -473,8 +473,20 @@ static int tegra_update_cpu_speed(unsigned long rate)
* Vote on memory bus frequency based on cpu frequency
* This sets the minimum frequency, display or avp may request higher
*/
- if (freqs.old < freqs.new)
- clk_set_rate(emc_clk, tegra_emc_to_cpu_ratio(freqs.new));
+ if (freqs.old < freqs.new) {
+ ret = tegra_update_mselect_rate(freqs.new);
+ if (ret) {
+ pr_err("cpu-tegra: Failed to scale mselect for cpu"
+ " frequency %u kHz\n", freqs.new);
+ return ret;
+ }
+ ret = clk_set_rate(emc_clk, tegra_emc_to_cpu_ratio(freqs.new));
+ if (ret) {
+ pr_err("cpu-tegra: Failed to scale emc for cpu"
+ " frequency %u kHz\n", freqs.new);
+ return ret;
+ }
+ }
for_each_online_cpu(freqs.cpu)
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
@@ -494,8 +506,10 @@ static int tegra_update_cpu_speed(unsigned long rate)
for_each_online_cpu(freqs.cpu)
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
- if (freqs.old > freqs.new)
+ if (freqs.old > freqs.new) {
clk_set_rate(emc_clk, tegra_emc_to_cpu_ratio(freqs.new));
+ tegra_update_mselect_rate(freqs.new);
+ }
return 0;
}
diff --git a/arch/arm/mach-tegra/tegra3_clocks.c b/arch/arm/mach-tegra/tegra3_clocks.c
index 9d82186dc5f0..ff7c0d09e7c6 100644
--- a/arch/arm/mach-tegra/tegra3_clocks.c
+++ b/arch/arm/mach-tegra/tegra3_clocks.c
@@ -4728,6 +4728,30 @@ unsigned long tegra_emc_to_cpu_ratio(unsigned long cpu_rate)
else
return 0; /* emc min */
}
+
+int tegra_update_mselect_rate(unsigned long cpu_rate)
+{
+ static struct clk *mselect = NULL;
+
+ unsigned long mselect_rate;
+
+ if (!mselect) {
+ mselect = tegra_get_clock_by_name("mselect");
+ if (!mselect)
+ return -ENODEV;
+ }
+
+ /* Vote on mselect frequency based on cpu frequency:
+ keep mselect at half of cpu rate up to 102 MHz;
+ cpu rate is in kHz, mselect rate is in Hz */
+ mselect_rate = DIV_ROUND_UP(cpu_rate, 2) * 1000;
+ mselect_rate = min(mselect_rate, 102000000UL);
+
+ if (mselect_rate != clk_get_rate(mselect))
+ return clk_set_rate(mselect, mselect_rate);
+
+ return 0;
+}
#endif
#ifdef CONFIG_PM_SLEEP