summaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2011-11-11 18:19:16 -0800
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:50:19 -0800
commite6fa3337de9a8d0ee7236f424905d7ccdcc2401e (patch)
tree57f2818152896472b26a40dd636d05ceb1c4d711 /arch/arm
parent7f650285a37030a14bf9036a95a1d8d66e4cb666 (diff)
ARM: tegra: clock: Support restricted PLLM usage
Added configuration option TEGRA_PLLM_RESTRICTED - when enabled, PLLM - memory PLL - usage may be restricted to modules with dividers capable of dividing maximum PLLM frequency at minimum voltage. When disabled, PLLM is available as a clock source with no restrictions (current configuration), which may effectively increase lower limit for core voltage if high grade SDRAM is used. Implemented PLLM restrictions in Tegra3 clock framework and DVFS, but keep them disabled by default. Bug 884419 Signed-off-by: Alex Frid <afrid@nvidia.com> (cherry picked from commit 5313ebcae92839146870d5865bc0f4cd08b35c61) (cherry picked from commit 634647a9d2a8c1e03c8d98d0b2199950c947acc3) Change-Id: I012452d92830ad6b63ec407350568b8c316b3caa Reviewed-on: http://git-master/r/66512 Reviewed-by: Lokesh Pathak <lpathak@nvidia.com> Tested-by: Lokesh Pathak <lpathak@nvidia.com> Rebase-Id: R22de0f09e7af2640499ec8cd96e974328d78bace
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-tegra/Kconfig10
-rw-r--r--arch/arm/mach-tegra/board-cardhu.c6
-rw-r--r--arch/arm/mach-tegra/board-enterprise.c2
-rw-r--r--arch/arm/mach-tegra/tegra3_clocks.c6
-rw-r--r--arch/arm/mach-tegra/tegra3_dvfs.c49
5 files changed, 61 insertions, 12 deletions
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 70c1f988331f..d376c8e22e16 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -390,4 +390,14 @@ config TEGRA_THERMAL_SYSFS
bool "Enable Thermal driver to use Thermal Sysfs infrastructure"
depends on THERMAL
default n
+
+config TEGRA_PLLM_RESTRICTED
+ bool "Restrict PLLM usage as module clock source"
+ depends on !ARCH_TEGRA_2x_SOC
+ default n
+ help
+ When enabled, PLLM usage may be restricted to modules with dividers
+ capable of dividing maximum PLLM frequency at minimum voltage. When
+ disabled, PLLM is used as a clock source with no restrictions (which
+ may effectively increase lower limit for core voltage).
endif
diff --git a/arch/arm/mach-tegra/board-cardhu.c b/arch/arm/mach-tegra/board-cardhu.c
index 1365e04d65d7..da4b14c0e35d 100644
--- a/arch/arm/mach-tegra/board-cardhu.c
+++ b/arch/arm/mach-tegra/board-cardhu.c
@@ -324,7 +324,9 @@ static struct platform_device *cardhu_uart_devices[] __initdata = {
static struct uart_clk_parent uart_parent_clk[] = {
[0] = {.name = "clk_m"},
[1] = {.name = "pll_p"},
+#ifndef CONFIG_TEGRA_PLLM_RESTRICTED
[2] = {.name = "pll_m"},
+#endif
};
static struct tegra_uart_platform_data cardhu_uart_pdata;
@@ -467,8 +469,12 @@ static struct platform_device *cardhu_spi_devices[] __initdata = {
struct spi_clk_parent spi_parent_clk[] = {
[0] = {.name = "pll_p"},
+#ifndef CONFIG_TEGRA_PLLM_RESTRICTED
[1] = {.name = "pll_m"},
[2] = {.name = "clk_m"},
+#else
+ [1] = {.name = "clk_m"},
+#endif
};
static struct tegra_spi_platform_data cardhu_spi_pdata = {
diff --git a/arch/arm/mach-tegra/board-enterprise.c b/arch/arm/mach-tegra/board-enterprise.c
index dafee77f9638..a5736c7d40de 100644
--- a/arch/arm/mach-tegra/board-enterprise.c
+++ b/arch/arm/mach-tegra/board-enterprise.c
@@ -385,7 +385,9 @@ static struct platform_device *enterprise_uart_devices[] __initdata = {
static struct uart_clk_parent uart_parent_clk[] = {
[0] = {.name = "clk_m"},
[1] = {.name = "pll_p"},
+#ifndef CONFIG_TEGRA_PLLM_RESTRICTED
[2] = {.name = "pll_m"},
+#endif
};
static struct tegra_uart_platform_data enterprise_uart_pdata;
diff --git a/arch/arm/mach-tegra/tegra3_clocks.c b/arch/arm/mach-tegra/tegra3_clocks.c
index 9d8128f35a6b..f0086e0ebd22 100644
--- a/arch/arm/mach-tegra/tegra3_clocks.c
+++ b/arch/arm/mach-tegra/tegra3_clocks.c
@@ -3783,7 +3783,9 @@ static struct clk_mux_sel mux_pllm_pllc_pllp_clkm[] = {
static struct clk_mux_sel mux_pllp_pllc_pllm_clkm[] = {
{ .input = &tegra_pll_p, .value = 0},
{ .input = &tegra_pll_c, .value = 1},
+#ifndef CONFIG_TEGRA_PLLM_RESTRICTED
{ .input = &tegra_pll_m, .value = 2},
+#endif
{ .input = &tegra_clk_m, .value = 3},
{ 0, 0},
};
@@ -3804,7 +3806,9 @@ static struct clk_mux_sel mux_pllp_plld_pllc_clkm[] = {
static struct clk_mux_sel mux_pllp_pllm_plld_plla_pllc_plld2_clkm[] = {
{.input = &tegra_pll_p, .value = 0},
+#ifndef CONFIG_TEGRA_PLLM_RESTRICTED
{.input = &tegra_pll_m, .value = 1},
+#endif
{.input = &tegra_pll_d_out0, .value = 2},
{.input = &tegra_pll_a_out0, .value = 3},
{.input = &tegra_pll_c, .value = 4},
@@ -3840,7 +3844,9 @@ static struct clk_mux_sel mux_pllp_pllc_clkm_clk32[] = {
static struct clk_mux_sel mux_pllp_pllc_pllm[] = {
{.input = &tegra_pll_p, .value = 0},
{.input = &tegra_pll_c, .value = 1},
+#ifndef CONFIG_TEGRA_PLLM_RESTRICTED
{.input = &tegra_pll_m, .value = 2},
+#endif
{ 0, 0},
};
diff --git a/arch/arm/mach-tegra/tegra3_dvfs.c b/arch/arm/mach-tegra/tegra3_dvfs.c
index 98b68c97bfcd..2ad2c90629f9 100644
--- a/arch/arm/mach-tegra/tegra3_dvfs.c
+++ b/arch/arm/mach-tegra/tegra3_dvfs.c
@@ -329,6 +329,23 @@ module_param_cb(disable_core, &tegra_dvfs_disable_core_ops,
module_param_cb(disable_cpu, &tegra_dvfs_disable_cpu_ops,
&tegra_dvfs_cpu_disabled, 0644);
+static bool __init is_pllm_dvfs(struct clk *c, struct dvfs *d)
+{
+#ifdef CONFIG_TEGRA_PLLM_RESTRICTED
+ /* Restricting PLLM usage on T30 and T33, rev A02+, allows to apply
+ maximum PLLM frequency to clock tree at minimum core voltage;
+ no need to enable dvfs on PLLM in this case */
+ if ((tegra_cpu_speedo_id() == 2) || (tegra_cpu_speedo_id() == 5))
+ return false;
+#endif
+ /* Check if PLLM boot frequency can be applied to clock tree at
+ minimum voltage. If yes, no need to enable dvfs on PLLM */
+ if (clk_get_rate_all_locked(c) <= d->freqs[0] * d->freqs_mult)
+ return false;
+
+ return true;
+}
+
static void __init init_dvfs_one(struct dvfs *d, int nominal_mv_index)
{
int ret;
@@ -340,25 +357,33 @@ static void __init init_dvfs_one(struct dvfs *d, int nominal_mv_index)
return;
}
+ /*
+ * 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).
+ */
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);
}
d->max_millivolts = d->dvfs_rail->nominal_millivolts;
- ret = tegra_enable_dvfs_on_clk(c, d);
- if (ret)
- pr_err("tegra3_dvfs: failed to enable dvfs on %s\n",
- c->name);
+ /*
+ * Check if we may skip enabling dvfs on PLLM. PLLM is a special case,
+ * since its frequency never exceeds boot rate, and configuration with
+ * restricted PLLM usage is possible.
+ */
+ if (!(c->flags & PLLM) || is_pllm_dvfs(c, d)) {
+ ret = tegra_enable_dvfs_on_clk(c, d);
+ if (ret)
+ pr_err("tegra3_dvfs: failed to enable dvfs on %s\n",
+ c->name);
+ }
}
static bool __init match_dvfs_one(struct dvfs *d, int speedo_id, int process_id)