summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/tegra3_clocks.c
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2011-06-18 00:35:46 -0700
committerVarun Colbert <vcolbert@nvidia.com>2011-07-01 10:46:12 -0700
commit7bdd9a4971c68170b58dc855fd71ea3a6875b7f4 (patch)
tree146f6368c54326d4ecbecc62fa0bf29eb1937739 /arch/arm/mach-tegra/tegra3_clocks.c
parentb5f28ca169a8f4c8667ba845fddc7742af03caa7 (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.c54
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)