diff options
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-tegra/clock.c | 5 | ||||
-rw-r--r-- | arch/arm/mach-tegra/clock.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-tegra/cpu-tegra3.c | 8 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra3_clocks.c | 30 |
4 files changed, 35 insertions, 9 deletions
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index 2fe6df739fd6..cc83511ce446 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c @@ -137,6 +137,11 @@ unsigned long clk_get_max_rate(struct clk *c) return c->max_rate; } +unsigned long clk_get_min_rate(struct clk *c) +{ + return c->min_rate; +} + /* Must be called with clk_lock(c) held */ unsigned long clk_get_rate_locked(struct clk *c) { diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h index 3c109571321f..3c8710076d64 100644 --- a/arch/arm/mach-tegra/clock.h +++ b/arch/arm/mach-tegra/clock.h @@ -202,6 +202,7 @@ int clk_reparent(struct clk *c, struct clk *parent); void tegra_clk_init_from_table(struct tegra_clk_init_table *table); void clk_set_cansleep(struct clk *c); unsigned long clk_get_max_rate(struct clk *c); +unsigned long clk_get_min_rate(struct clk *c); unsigned long clk_get_rate_locked(struct clk *c); int clk_set_rate_locked(struct clk *c, unsigned long rate); void tegra2_sdmmc_tap_delay(struct clk *c, int delay); diff --git a/arch/arm/mach-tegra/cpu-tegra3.c b/arch/arm/mach-tegra/cpu-tegra3.c index acd6889e54f7..84ddc4ffb626 100644 --- a/arch/arm/mach-tegra/cpu-tegra3.c +++ b/arch/arm/mach-tegra/cpu-tegra3.c @@ -37,7 +37,6 @@ #include "clock.h" #define INITIAL_STATE TEGRA_HP_DISABLED -#define IDLE_HYSTERESIS 100000 #define UP2G0_DELAY_MS 200 #define UP2Gn_DELAY_MS 1000 #define DOWN_DELAY_MS 2000 @@ -62,8 +61,6 @@ static unsigned int idle_bottom_freq; module_param(idle_top_freq, uint, 0644); module_param(idle_bottom_freq, uint, 0644); -static unsigned int lpcpu_max_freq; - static struct clk *cpu_clk; static struct clk *cpu_g_clk; static struct clk *cpu_lp_clk; @@ -340,9 +337,8 @@ int tegra_auto_hotplug_init(struct mutex *cpu_lock) if (IS_ERR(cpu_clk) || IS_ERR(cpu_g_clk) || IS_ERR(cpu_lp_clk)) return -ENOENT; - lpcpu_max_freq = clk_get_max_rate(cpu_lp_clk) / 1000; - idle_top_freq = lpcpu_max_freq; - idle_bottom_freq = idle_top_freq - IDLE_HYSTERESIS; + idle_top_freq = clk_get_max_rate(cpu_lp_clk) / 1000; + idle_bottom_freq = clk_get_min_rate(cpu_g_clk) / 1000; up2g0_delay = msecs_to_jiffies(UP2G0_DELAY_MS); up2gn_delay = msecs_to_jiffies(UP2Gn_DELAY_MS); diff --git a/arch/arm/mach-tegra/tegra3_clocks.c b/arch/arm/mach-tegra/tegra3_clocks.c index 97534eb743b3..68c38450cf41 100644 --- a/arch/arm/mach-tegra/tegra3_clocks.c +++ b/arch/arm/mach-tegra/tegra3_clocks.c @@ -2974,7 +2974,6 @@ static struct clk tegra_clk_virtual_cpu_g = { .parent = &tegra_clk_cclk_g, .ops = &tegra_cpu_ops, .max_rate = 1000000000, - .min_rate = 312000000, .u.cpu = { .main = &tegra_pll_x, .backup = &tegra_pll_p, @@ -2986,7 +2985,7 @@ static struct clk tegra_clk_virtual_cpu_lp = { .name = "cpu_lp", .parent = &tegra_clk_cclk_lp, .ops = &tegra_cpu_ops, - .max_rate = 456000000, + .max_rate = 500000000, .u.cpu = { .main = &tegra_pll_x, .backup = &tegra_pll_p, @@ -3479,6 +3478,27 @@ static struct tegra_cpufreq_table_data cpufreq_tables[] = { { freq_table_1p0GHz, 2, 6 }, }; +static void clip_cpu_rate_limits( + struct cpufreq_frequency_table *freq_table, + struct cpufreq_policy *policy) +{ + int idx, ret; + struct clk *cpu_clk_g = tegra_get_clock_by_name("cpu_g"); + struct clk *cpu_clk_lp = tegra_get_clock_by_name("cpu_lp"); + + /* clip CPU LP mode maximum frequency to table entry, and + set CPU G mode minimum frequency one table step below */ + ret = cpufreq_frequency_table_target(policy, freq_table, + cpu_clk_lp->max_rate / 1000, CPUFREQ_RELATION_H, &idx); + if (ret || !idx) { + pr_err("%s: LP CPU max rate %lu %s of cpufreq table", __func__, + cpu_clk_lp->max_rate, ret ? "outside" : "at the bottom"); + BUG(); + } + cpu_clk_lp->max_rate = freq_table[idx].frequency * 1000; + cpu_clk_g->min_rate = freq_table[idx-1].frequency * 1000; +} + struct tegra_cpufreq_table_data *tegra_cpufreq_table_get(void) { int i, ret; @@ -3486,11 +3506,15 @@ struct tegra_cpufreq_table_data *tegra_cpufreq_table_get(void) for (i = 0; i < ARRAY_SIZE(cpufreq_tables); i++) { struct cpufreq_policy policy; + policy.cpu = 0; /* any on-line cpu */ ret = cpufreq_frequency_table_cpuinfo( &policy, cpufreq_tables[i].freq_table); BUG_ON(ret); - if ((policy.max * 1000) == cpu_clk->max_rate) + if ((policy.max * 1000) == cpu_clk->max_rate) { + clip_cpu_rate_limits( + cpufreq_tables[i].freq_table, &policy); return &cpufreq_tables[i]; + } } pr_err("%s: No cpufreq table matching cpu range", __func__); BUG(); |