diff options
-rw-r--r-- | arch/arm/mach-tegra/cpu-tegra.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-tegra/dvfs.h | 4 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra3_dvfs.c | 42 |
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; |