diff options
author | Alex Frid <afrid@nvidia.com> | 2011-03-13 00:41:14 -0800 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-04-26 15:54:49 -0700 |
commit | e0cd8649ffcc2401a2dac987ac196f9ff2221d87 (patch) | |
tree | 204f99d24386cc2624fe31c5035001b75a652173 /arch/arm/mach-tegra/clock.c | |
parent | 2e12d89ac51fe1358f0b01b9ff5cb4978fdcbe9d (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>
Change-Id: I23ae80edbf14fb22727a6fc317cd9e5baf8bd6be
Diffstat (limited to 'arch/arm/mach-tegra/clock.c')
-rw-r--r-- | arch/arm/mach-tegra/clock.c | 31 |
1 files changed, 22 insertions, 9 deletions
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index d892d2571101..5f656690020a 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c @@ -150,9 +150,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 / 2; /* round up */ @@ -162,11 +159,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; } @@ -436,8 +430,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; @@ -588,6 +580,26 @@ void __init tegra_init_clock(void) } /* + * 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; +} + +/* * Iterate through all clocks, disabling any for which the refcount is 0 * but the clock init detected the bootloader left the clock on. */ @@ -619,6 +631,7 @@ int __init tegra_disable_boot_clocks(void) int __init tegra_late_init_clock(void) { tegra_dvfs_late_init(); + tegra_sync_cpu_clock(); tegra_disable_boot_clocks(); return 0; } |