summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/clock.c
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2011-03-13 00:41:14 -0800
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:42:27 -0800
commit4f325a029dc651dd924002a456b039a7bc00385b (patch)
treefc46cbc51917b61184ba5392446916ef04423336 /arch/arm/mach-tegra/clock.c
parente630c3d716c0a883995c0b7a2938c35d5de25b72 (diff)
ARM: tegra: clock: Re-factor Tegra3 cpu clocks
Added second level virtualization (on top of virtual cpu rate control) to support different Tegra3 CPU power modes: low power (LP) mode and geared performance (G) mode. Virtual cpu complex (cpu_cmplx) clock is defined as a child with two parents: virtual cpu_lp and virtual cpu_g clocks for the respective modes. Mode switch sequence was integrated into cpu_cmplx set parent implementation. (Before this commit mode switch was triggered outside the clock framework, which created cpu clock/mode synchronization problems). Each mode clock is derived from its own super clock mux (cclk_lp and cclk_g) to statically match Tegra3 h/w layout. (Before this commit the code had to dynamically synchronize CPU mode and active mux selection). This change also allowed to support PLLX output divider for low power mode as fixed 1:2 divider with bypass control embedded into cclk_lp parent section. Updated auto and sysfs CPU mode switch calls to use new clock framework, and removed clock manipulation from the low level mode switch implementation. Original-Change-Id: Ibc3cc495b2ff29e2d3417eff2bfd45535cbd015b Reviewed-on: http://git-master/r/24734 Reviewed-by: Aleksandr Frid <afrid@nvidia.com> Tested-by: Aleksandr Frid <afrid@nvidia.com> Tested-by: Jin Qian <jqian@nvidia.com> Reviewed-by: Scott Williams <scwilliams@nvidia.com> Original-Change-Id: I23ae80edbf14fb22727a6fc317cd9e5baf8bd6be Rebase-Id: Rdcd4a2165ebd92bf4caa35d68ca81d19a3789351
Diffstat (limited to 'arch/arm/mach-tegra/clock.c')
-rw-r--r--arch/arm/mach-tegra/clock.c31
1 files changed, 22 insertions, 9 deletions
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index b2085a73faf9..8131c723e1cb 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -111,9 +111,6 @@ static unsigned long clk_predict_rate_from_parent(struct clk *c, struct clk *p)
rate = clk_get_rate(p);
- if (c->ops && c->ops->recalculate_rate)
- c->ops->recalculate_rate(c);
-
if (c->mul != 0 && c->div != 0) {
rate *= c->mul;
rate += c->div - 1; /* round up */
@@ -123,11 +120,8 @@ static unsigned long clk_predict_rate_from_parent(struct clk *c, struct clk *p)
return rate;
}
-static unsigned long clk_get_max_rate(struct clk *c)
+unsigned long clk_get_max_rate(struct clk *c)
{
- if (c->ops && c->ops->get_max_rate)
- return c->ops->get_max_rate(c);
- else
return c->max_rate;
}
@@ -404,8 +398,6 @@ unsigned long clk_get_rate_all_locked(struct clk *c)
while (p) {
c = p;
- if (c->ops && c->ops->recalculate_rate)
- c->ops->recalculate_rate(c);
if (c->mul != 0 && c->div != 0) {
mul *= c->mul;
div *= c->div;
@@ -578,6 +570,27 @@ static int __init tegra_keep_boot_clocks_setup(char *__unused)
__setup("tegra_keep_boot_clocks", tegra_keep_boot_clocks_setup);
/*
+ * Bootloader may not match kernel restrictions on CPU clock sources.
+ * Make sure CPU clock is sourced from either main or backup parent.
+ */
+static int tegra_sync_cpu_clock(void)
+{
+ int ret;
+ unsigned long rate;
+ struct clk *c = tegra_get_clock_by_name("cpu");
+
+ BUG_ON(!c);
+ rate = clk_get_rate(c);
+ ret = clk_set_rate(c, rate);
+ if (ret)
+ pr_err("%s: Failed to sync CPU at rate %lu\n", __func__, rate);
+ else
+ pr_info("CPU rate: %lu MHz\n", clk_get_rate(c) / 1000000);
+ return ret;
+}
+late_initcall(tegra_sync_cpu_clock);
+
+/*
* Iterate through all clocks, disabling any for which the refcount is 0
* but the clock init detected the bootloader left the clock on.
*/