diff options
author | Alex Frid <afrid@nvidia.com> | 2011-03-13 00:41:14 -0800 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:42:27 -0800 |
commit | 4f325a029dc651dd924002a456b039a7bc00385b (patch) | |
tree | fc46cbc51917b61184ba5392446916ef04423336 /arch/arm/mach-tegra/cpu-tegra3.c | |
parent | e630c3d716c0a883995c0b7a2938c35d5de25b72 (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/cpu-tegra3.c')
-rw-r--r-- | arch/arm/mach-tegra/cpu-tegra3.c | 33 |
1 files changed, 23 insertions, 10 deletions
diff --git a/arch/arm/mach-tegra/cpu-tegra3.c b/arch/arm/mach-tegra/cpu-tegra3.c index b7c6e9726e5c..c8059030df7c 100644 --- a/arch/arm/mach-tegra/cpu-tegra3.c +++ b/arch/arm/mach-tegra/cpu-tegra3.c @@ -29,10 +29,12 @@ #include <linux/err.h> #include <linux/io.h> #include <linux/cpu.h> +#include <linux/clk.h> #include <linux/debugfs.h> #include <linux/seq_file.h> #include "pm.h" +#include "clock.h" #define INITIAL_STATE TEGRA_HP_DISABLED #define IDLE_HYSTERESIS 100000 @@ -62,6 +64,9 @@ module_param(idle_bottom_freq, uint, 0644); static unsigned int lpcpu_max_freq; +static struct clk *cpu_clk; +static struct clk *cpu_g_clk; +static struct clk *cpu_lp_clk; static struct { cputime64_t time_up_total; @@ -189,18 +194,20 @@ static void tegra_auto_hotplug_work_func(struct work_struct *work) hotplug_wq, &hotplug_work, down_delay); hp_stats_update(cpu, false); } else if (!is_lp_cluster() && !no_lp) { - tegra_cluster_control(0, TEGRA_POWER_CLUSTER_LP | - TEGRA_POWER_CLUSTER_IMMEDIATE); - hp_stats_update(CONFIG_NR_CPUS, true); - hp_stats_update(0, false); + if(!clk_set_parent(cpu_clk, cpu_lp_clk)) { + hp_stats_update(CONFIG_NR_CPUS, true); + hp_stats_update(0, false); + } else + queue_delayed_work( + hotplug_wq, &hotplug_work, down_delay); } break; case TEGRA_HP_UP: if (is_lp_cluster() && !no_lp) { - tegra_cluster_control(0, TEGRA_POWER_CLUSTER_G | - TEGRA_POWER_CLUSTER_IMMEDIATE); - hp_stats_update(CONFIG_NR_CPUS, false); - hp_stats_update(0, true); + if(!clk_set_parent(cpu_clk, cpu_g_clk)) { + hp_stats_update(CONFIG_NR_CPUS, false); + hp_stats_update(0, true); + } queue_delayed_work( hotplug_wq, &hotplug_work, up2gn_delay); } else { @@ -281,7 +288,7 @@ int tegra_auto_hotplug_init(void) { /* * Not bound to the issuer CPU (=> high-priority), has rescue worker - * task, single-threaded, frrezeable. + * task, single-threaded, freezable. */ hotplug_wq = alloc_workqueue( "cpu-tegra3", WQ_UNBOUND | WQ_RESCUER | WQ_FREEZEABLE, 1); @@ -289,7 +296,13 @@ int tegra_auto_hotplug_init(void) return -ENOMEM; INIT_DELAYED_WORK(&hotplug_work, tegra_auto_hotplug_work_func); - lpcpu_max_freq = tegra_get_lpcpu_max_rate() / 1000; + cpu_clk = clk_get_sys(NULL, "cpu"); + cpu_g_clk = clk_get_sys(NULL, "cpu_g"); + cpu_lp_clk = clk_get_sys(NULL, "cpu_lp"); + if (IS_ERR(cpu_clk) || IS_ERR(cpu_g_clk) || IS_ERR(cpu_lp_clk)) + return -ENOENT; + + lpcpu_max_freq = clk_get_max_rate(cpu_lp_clk) / 1000; idle_top_freq = lpcpu_max_freq; idle_bottom_freq = idle_top_freq - IDLE_HYSTERESIS; |