summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-tegra/cpu-tegra.c6
-rw-r--r--arch/arm/mach-tegra/dvfs.h4
-rw-r--r--arch/arm/mach-tegra/tegra3_dvfs.c42
3 files changed, 50 insertions, 2 deletions
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
index 5599c298ac5b..24ed5d229a5d 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -41,6 +41,7 @@
#include "clock.h"
#include "cpu-tegra.h"
+#include "dvfs.h"
/* tegra throttling and edp governors require frequencies in the table
to be in ascending order */
@@ -226,11 +227,14 @@ int tegra_edp_update_thermal_zone(int temperature)
mutex_lock(&tegra_cpu_lock);
edp_thermal_index = index;
- /* Update cpu rate if cpufreq (at least on cpu0) is already started */
+ /* Update cpu rate if cpufreq (at least on cpu0) is already started;
+ alter cpu dvfs table for this thermal zone if necessary */
+ tegra_cpu_dvfs_alter(edp_thermal_index, true);
if (target_cpu_speed[0]) {
edp_update_limit();
tegra_cpu_set_speed_cap(NULL);
}
+ tegra_cpu_dvfs_alter(edp_thermal_index, false);
mutex_unlock(&tegra_cpu_lock);
return ret;
diff --git a/arch/arm/mach-tegra/dvfs.h b/arch/arm/mach-tegra/dvfs.h
index f7e863f14f39..eaecf425fe87 100644
--- a/arch/arm/mach-tegra/dvfs.h
+++ b/arch/arm/mach-tegra/dvfs.h
@@ -125,6 +125,7 @@ int tegra_dvfs_predict_millivolts(struct clk *c, unsigned long rate);
void tegra_dvfs_core_cap_enable(bool enable);
void tegra_dvfs_core_cap_level_set(int level);
int tegra_dvfs_alt_freqs_set(struct dvfs *d, bool enable);
+void tegra_cpu_dvfs_alter(int edp_thermal_index, bool before_clk_update);
#else
static inline void tegra_soc_init_dvfs(void)
{}
@@ -161,6 +162,9 @@ static inline void tegra_dvfs_core_cap_level_set(int level)
{}
static inline int tegra_dvfs_alt_freqs_set(struct dvfs *d, bool enable)
{ return 0; }
+static inline void tegra_cpu_dvfs_alter(int edp_thermal_index,
+ bool before_clk_update)
+{}
#endif
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
diff --git a/arch/arm/mach-tegra/tegra3_dvfs.c b/arch/arm/mach-tegra/tegra3_dvfs.c
index 8bd8bf7b775f..8f560ca6f7b9 100644
--- a/arch/arm/mach-tegra/tegra3_dvfs.c
+++ b/arch/arm/mach-tegra/tegra3_dvfs.c
@@ -30,10 +30,14 @@
static bool tegra_dvfs_cpu_disabled;
static bool tegra_dvfs_core_disabled;
+static struct dvfs *cpu_dvfs;
static const int cpu_millivolts[MAX_DVFS_FREQS] = {
800, 825, 850, 875, 900, 912, 975, 1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175, 1200, 1212, 1237};
+static const unsigned int cpu_cold_offs_mhz[MAX_DVFS_FREQS] = {
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50};
+
static const int core_millivolts[MAX_DVFS_FREQS] =
{1000, 1050, 1100, 1150, 1200, 1250, 1300};
@@ -422,6 +426,31 @@ static void __init init_dvfs_one(struct dvfs *d, int nominal_mv_index)
}
}
+static void __init init_dvfs_cold(struct dvfs *d, int nominal_mv_index)
+{
+ int i;
+ unsigned long offs;
+
+ BUG_ON((nominal_mv_index == 0) || (nominal_mv_index > d->num_freqs));
+
+ for (i = 0; i < d->num_freqs; i++) {
+ offs = cpu_cold_offs_mhz[i] * MHZ;
+ if (i > nominal_mv_index)
+ d->alt_freqs[i] = d->alt_freqs[i - 1];
+ else if (d->freqs[i] > offs)
+ d->alt_freqs[i] = d->freqs[i] - offs;
+ else {
+ d->alt_freqs[i] = d->freqs[i];
+ pr_warn("tegra3_dvfs: cold offset %lu is too high for"
+ " regular dvfs limit %lu\n", offs, d->freqs[i]);
+ }
+
+ if (i)
+ BUG_ON(d->alt_freqs[i] < d->alt_freqs[i - 1]);
+ }
+ d->alt_freqs_state = ALT_FREQS_DISABLED;
+}
+
static bool __init match_dvfs_one(struct dvfs *d, int speedo_id, int process_id)
{
if ((d->process_id != -1 && d->process_id != process_id) ||
@@ -535,7 +564,6 @@ void __init tegra_soc_init_dvfs(void)
int i;
int core_nominal_mv_index;
int cpu_nominal_mv_index;
- struct dvfs *cpu_dvfs = NULL;
#ifndef CONFIG_TEGRA_CORE_DVFS
tegra_dvfs_core_disabled = true;
@@ -581,6 +609,7 @@ void __init tegra_soc_init_dvfs(void)
/* Initialize matching cpu dvfs entry already found when nominal
voltage was determined */
init_dvfs_one(cpu_dvfs, cpu_nominal_mv_index);
+ init_dvfs_cold(cpu_dvfs, cpu_nominal_mv_index);
/* Finally disable dvfs on rails if necessary */
if (tegra_dvfs_core_disabled)
@@ -596,6 +625,17 @@ void __init tegra_soc_init_dvfs(void)
tegra_dvfs_core_disabled ? "disabled" : "enabled");
}
+void tegra_cpu_dvfs_alter(int edp_thermal_index, bool before_clk_update)
+{
+ bool enable = !edp_thermal_index;
+
+ if (enable != before_clk_update) {
+ int ret = tegra_dvfs_alt_freqs_set(cpu_dvfs, enable);
+ WARN_ONCE(ret, "tegra dvfs: failed to set CPU alternative"
+ " frequency limits for cold temeperature\n");
+ }
+}
+
int tegra_dvfs_rail_disable_prepare(struct dvfs_rail *rail)
{
int ret = 0;