summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/cpu-tegra3.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/cpu-tegra3.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/cpu-tegra3.c')
-rw-r--r--arch/arm/mach-tegra/cpu-tegra3.c33
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;