summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2011-11-03 21:07:03 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:50:13 -0800
commitd45ab1ba44d57ca3c08217c5dd1cf3db604301d9 (patch)
treeb42536e8da7ada0db21abe13c889315a66a71030 /arch
parentf6e531d7fc13b0f759f9acba93c2be0e156a918c (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) Signed-off-by: Alex Frid <afrid@nvidia.com> (cherry picked from commit a213668b4f54b8ea7603a6d1e71f8b4ab1998bf7) Change-Id: Id61f33e42556a6415e45b014bcadace600dd86d5 Reviewed-on: http://git-master/r/64765 Tested-by: Aleksandr Frid <afrid@nvidia.com> Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com> Rebase-Id: R697e04b6140eb0084bdb341febe3acdf91d93535
Diffstat (limited to 'arch')
-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);
}