summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2011-11-03 21:07:03 -0700
committerVarun Colbert <vcolbert@nvidia.com>2011-11-15 11:52:02 -0800
commita213668b4f54b8ea7603a6d1e71f8b4ab1998bf7 (patch)
treeef997b887460a4f2ffc040ded63bc2834cbb127b
parentfb9d21cbfd0ff1c57792a7156f009c681ade953b (diff)
ARM: tegra: dvfs: Update Tegra3 EMC DVFS
- Moved validation of EMC maximum rate against nominal core voltage from common dvfs initialization to board specific EMC scaling table setup (a logical place to do it, since EMC DVFS is board dependent) - Used current rate as rounded EMC rate if no EMC scaling table is provided (instead of maximum EMC rate - no sense in attempt to set maximum rate, or any rate, for that matter, if there is no table). - Cleaned EMC initialization procedure (cherry picked from commit 4f655077e09c0dc4abc50d190d82c91473e2e81c) Change-Id: Ibe5c689db58f0aab3a24eceda1f4b639d073a4dc Signed-off-by: Alex Frid <afrid@nvidia.com> Reviewed-on: http://git-master/r/63975 Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/tegra3_dvfs.c11
-rw-r--r--arch/arm/mach-tegra/tegra3_emc.c45
2 files changed, 39 insertions, 17 deletions
diff --git a/arch/arm/mach-tegra/tegra3_dvfs.c b/arch/arm/mach-tegra/tegra3_dvfs.c
index d39d383e1be6..98b68c97bfcd 100644
--- a/arch/arm/mach-tegra/tegra3_dvfs.c
+++ b/arch/arm/mach-tegra/tegra3_dvfs.c
@@ -340,8 +340,15 @@ static void __init init_dvfs_one(struct dvfs *d, int nominal_mv_index)
return;
}
- if (d->auto_dvfs) {
- /* Update max rate for auto-dvfs clocks */
+ if (!(c->flags & PERIPH_EMC_ENB) && d->auto_dvfs) {
+ /* Update max rate for auto-dvfs clocks, except EMC.
+ * EMC is a special case, since EMC dvfs is board dependent:
+ * max rate and EMC scaling frequencies are determined by tegra
+ * BCT (flashed together with the image) and board specific EMC
+ * DFS table; we will check the scaling ladder against nominal
+ * core voltage when the table is loaded (and if on particular
+ * board the table is not loaded, EMC scaling is disabled).
+ */
BUG_ON(!d->freqs[nominal_mv_index]);
tegra_init_max_rate(
c, d->freqs[nominal_mv_index] * d->freqs_mult);
diff --git a/arch/arm/mach-tegra/tegra3_emc.c b/arch/arm/mach-tegra/tegra3_emc.c
index 56d579972369..e820801f96da 100644
--- a/arch/arm/mach-tegra/tegra3_emc.c
+++ b/arch/arm/mach-tegra/tegra3_emc.c
@@ -678,7 +678,7 @@ long tegra_emc_round_rate(unsigned long rate)
unsigned long distance = ULONG_MAX;
if (!tegra_emc_table)
- return -EINVAL;
+ return clk_get_rate_locked(emc); /* no table - no rate change */
if (!emc_enable)
return -EINVAL;
@@ -821,7 +821,7 @@ static struct notifier_block tegra_emc_resume_nb = {
void tegra_init_emc(const struct tegra_emc_table *table, int table_size)
{
- int i;
+ int i, mv;
u32 reg, div_value;
bool max_entry = false;
unsigned long boot_rate, max_rate;
@@ -834,14 +834,19 @@ void tegra_init_emc(const struct tegra_emc_table *table, int table_size)
boot_rate = clk_get_rate(emc) / 1000;
max_rate = clk_get_max_rate(emc) / 1000;
+ if ((dram_type != DRAM_TYPE_DDR3) && (dram_type != DRAM_TYPE_LPDDR2)) {
+ pr_err("tegra: not supported DRAM type %u\n", dram_type);
+ return;
+ }
+
if (emc->parent != tegra_get_clock_by_name("pll_m")) {
- pr_warn("tegra: boot parent %s is not supported by EMC DFS\n",
+ pr_err("tegra: boot parent %s is not supported by EMC DFS\n",
emc->parent->name);
return;
}
if (!table || !table_size) {
- pr_warn("tegra: EMC DFS table is empty\n");
+ pr_err("tegra: EMC DFS table is empty\n");
return;
}
@@ -855,16 +860,19 @@ void tegra_init_emc(const struct tegra_emc_table *table, int table_size)
emc_num_burst_regs = 107;
break;
default:
- pr_warn("tegra: invalid EMC DFS table: unknown rev 0x%x\n",
+ pr_err("tegra: invalid EMC DFS table: unknown rev 0x%x\n",
table[0].rev);
return;
}
+ /* Match EMC source/divider settings with table entries */
for (i = 0; i < tegra_emc_table_size; i++) {
unsigned long table_rate = table[i].rate;
if (!table_rate)
continue;
+ BUG_ON(table[i].rev != table[0].rev);
+
sel = find_matching_input(table_rate, &div_value);
if (!sel)
continue;
@@ -891,16 +899,7 @@ void tegra_init_emc(const struct tegra_emc_table *table, int table_size)
tegra_emc_clk_sel[i].value |= EMC_CLK_MC_SAME_FREQ;
}
- /* Configure clock change mode according to dram type */
- if ((dram_type != DRAM_TYPE_DDR3) && (dram_type != DRAM_TYPE_LPDDR2)) {
- pr_err("tegra: not supported DRAM type %u\n", dram_type);
- return;
- }
- reg = emc_readl(EMC_CFG_2) & (~EMC_CFG_2_MODE_MASK);
- reg |= ((dram_type == DRAM_TYPE_LPDDR2) ? EMC_CFG_2_PD_MODE :
- EMC_CFG_2_SREF_MODE) << EMC_CFG_2_MODE_SHIFT;
- emc_writel(reg, EMC_CFG_2);
-
+ /* Validate EMC rate and voltage limits */
if (!max_entry) {
pr_err("tegra: invalid EMC DFS table: entry for max rate"
" %lu kHz is not found\n", max_rate);
@@ -909,12 +908,28 @@ void tegra_init_emc(const struct tegra_emc_table *table, int table_size)
tegra_emc_table = table;
+ mv = tegra_dvfs_predict_millivolts(emc, max_rate * 1000);
+ if ((mv <= 0) || (mv > emc->dvfs->max_millivolts)) {
+ tegra_emc_table = NULL;
+ pr_err("tegra: invalid EMC DFS table: maximum rate %lu kHz does"
+ " not match nominal voltage %d\n",
+ max_rate, emc->dvfs->max_millivolts);
+ return;
+ }
+
if (!is_emc_bridge()) {
tegra_emc_table = NULL;
pr_err("tegra: invalid EMC DFS table: emc bridge not found");
+ return;
}
pr_info("tegra: validated EMC DFS table\n");
+ /* Configure clock change mode according to dram type */
+ reg = emc_readl(EMC_CFG_2) & (~EMC_CFG_2_MODE_MASK);
+ reg |= ((dram_type == DRAM_TYPE_LPDDR2) ? EMC_CFG_2_PD_MODE :
+ EMC_CFG_2_SREF_MODE) << EMC_CFG_2_MODE_SHIFT;
+ emc_writel(reg, EMC_CFG_2);
+
register_pm_notifier(&tegra_emc_suspend_nb);
register_pm_notifier(&tegra_emc_resume_nb);
}