diff options
author | Alex Frid <afrid@nvidia.com> | 2011-06-18 00:35:46 -0700 |
---|---|---|
committer | Varun Colbert <vcolbert@nvidia.com> | 2011-07-01 10:46:12 -0700 |
commit | 7bdd9a4971c68170b58dc855fd71ea3a6875b7f4 (patch) | |
tree | 146f6368c54326d4ecbecc62fa0bf29eb1937739 /arch/arm/mach-tegra/tegra3_clocks.c | |
parent | b5f28ca169a8f4c8667ba845fddc7742af03caa7 (diff) |
ARM: tegra: dvfs: Update Tegra3 cpufreq table selection
- For selection of cpufreq scaling table used top-most rate in G CPU
dvfs table, instead of G CPU max rate. Commonly the above rates are
the same, however, in case when PMU limitations on core voltage
indirectly (VDD_CPU on VDD_CORE dependency) lower cpu max rate, the
top-most dvfs rate should be used for table selection, and the max
rate clipped to table entry.
- Replaced BUGs in table selection implementation with errors. Thus,
when no table is found cpufreq is not installed, but the system boots
with respective error messages.
- Step up suspend frequency index in cpufreq tables to reduce suspend
entry latency (the selected rate is still low enough to work under
Vmin voltage setting).
Change-Id: I45db19dbf5b48cef80db35663db2df3b68473993
Reviewed-on: http://git-master/r/37415
Reviewed-by: Varun Colbert <vcolbert@nvidia.com>
Tested-by: Varun Colbert <vcolbert@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/tegra3_clocks.c')
-rw-r--r-- | arch/arm/mach-tegra/tegra3_clocks.c | 54 |
1 files changed, 41 insertions, 13 deletions
diff --git a/arch/arm/mach-tegra/tegra3_clocks.c b/arch/arm/mach-tegra/tegra3_clocks.c index 1e17751d2213..1084d7b70251 100644 --- a/arch/arm/mach-tegra/tegra3_clocks.c +++ b/arch/arm/mach-tegra/tegra3_clocks.c @@ -4011,12 +4011,12 @@ static struct cpufreq_frequency_table freq_table_1p4GHz[] = { static struct tegra_cpufreq_table_data cpufreq_tables[] = { { freq_table_300MHz, 0, 1 }, - { freq_table_1p0GHz, 2, 7 }, - { freq_table_1p3GHz, 2, 9, 1}, - { freq_table_1p4GHz, 2, 10, 1}, + { freq_table_1p0GHz, 2, 7, 2}, + { freq_table_1p3GHz, 2, 9, 2}, + { freq_table_1p4GHz, 2, 10, 2}, }; -static void clip_cpu_rate_limits( +static int clip_cpu_rate_limits( struct cpufreq_frequency_table *freq_table, struct cpufreq_policy *policy, struct clk *cpu_clk_g, @@ -4024,6 +4024,21 @@ static void clip_cpu_rate_limits( { int idx, ret; + /* clip CPU G mode maximum frequency to table entry */ + ret = cpufreq_frequency_table_target(policy, freq_table, + cpu_clk_g->max_rate / 1000, CPUFREQ_RELATION_H, &idx); + if (ret) { + pr_err("%s: G CPU max rate %lu outside of cpufreq table", + __func__, cpu_clk_g->max_rate); + return ret; + } + cpu_clk_g->max_rate = freq_table[idx].frequency * 1000; + if (cpu_clk_g->max_rate < cpu_clk_lp->max_rate) { + pr_err("%s: G CPU max rate %lu is below LP CPU max rate %lu", + __func__, cpu_clk_g->max_rate, cpu_clk_lp->max_rate); + return -EINVAL; + } + /* 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, @@ -4031,33 +4046,46 @@ static void clip_cpu_rate_limits( 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(); + return ret; } cpu_clk_lp->max_rate = freq_table[idx].frequency * 1000; cpu_clk_g->min_rate = freq_table[idx-1].frequency * 1000; + return 0; } struct tegra_cpufreq_table_data *tegra_cpufreq_table_get(void) { int i, ret; + unsigned long selection_rate; struct clk *cpu_clk_g = tegra_get_clock_by_name("cpu_g"); struct clk *cpu_clk_lp = tegra_get_clock_by_name("cpu_lp"); + /* For table selection use top cpu_g rate in dvfs ladder; selection + rate may exceed cpu max_rate (e.g., because of edp limitations on + cpu voltage) - in any case max_rate will be clipped to the table */ + if (cpu_clk_g->dvfs && cpu_clk_g->dvfs->num_freqs) + selection_rate = + cpu_clk_g->dvfs->freqs[cpu_clk_g->dvfs->num_freqs - 1]; + else + selection_rate = cpu_clk_g->max_rate; + 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_g->max_rate) { - clip_cpu_rate_limits(cpufreq_tables[i].freq_table, - &policy, cpu_clk_g, cpu_clk_lp); - return &cpufreq_tables[i]; + if (!ret) { + if ((policy.max * 1000) == selection_rate) { + ret = clip_cpu_rate_limits( + cpufreq_tables[i].freq_table, + &policy, cpu_clk_g, cpu_clk_lp); + if (!ret) + return &cpufreq_tables[i]; + } } } - pr_err("%s: No cpufreq table matching cpu range", __func__); - BUG(); - return &cpufreq_tables[0]; + WARN(1, "%s: No cpufreq table matching G & LP cpu ranges", __func__); + return NULL; } unsigned long tegra_emc_to_cpu_ratio(unsigned long cpu_rate) |