summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2012-11-18 00:45:43 -0800
committerSimone Willett <swillett@nvidia.com>2012-11-27 12:30:25 -0800
commit2f656f2396599ad06278821284f3ea43a5718f46 (patch)
tree661a9d30180d3b68481ea21a9c61378b79f1f7c1 /arch
parent5091fa5b6b8b18de0bed1d852d46f7316a9f4b9d (diff)
ARM: tegra11: power: Update core EDP on CPU cluster switch
Update core EDP limits when CPU cluster is switched between fast (G-mode) CPU, and slow (LP-mode) CPU. Bug 1165638 Change-Id: I956eb5ab2d8fbe873f998cca1e22984413cf5743 Signed-off-by: Alex Frid <afrid@nvidia.com> Reviewed-on: http://git-master/r/165617 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-tegra/cpuquiet.c4
-rw-r--r--arch/arm/mach-tegra/edp_core.c31
-rw-r--r--arch/arm/mach-tegra/include/mach/edp.h3
-rw-r--r--arch/arm/mach-tegra/platsmp.c2
-rw-r--r--arch/arm/mach-tegra/pm-t3.c24
-rw-r--r--arch/arm/mach-tegra/pm.h6
-rw-r--r--arch/arm/mach-tegra/sysfs-cluster.c2
7 files changed, 66 insertions, 6 deletions
diff --git a/arch/arm/mach-tegra/cpuquiet.c b/arch/arm/mach-tegra/cpuquiet.c
index cdfa16a89d81..7fe6b644e34b 100644
--- a/arch/arm/mach-tegra/cpuquiet.c
+++ b/arch/arm/mach-tegra/cpuquiet.c
@@ -214,7 +214,7 @@ static int __apply_cluster_config(int state, int target_state)
clk_get_min_rate(cpu_g_clk) / 1000);
tegra_update_cpu_speed(speed);
- if (!clk_set_parent(cpu_clk, cpu_g_clk)) {
+ if (!tegra_cluster_switch(cpu_clk, cpu_g_clk)) {
hp_stats_update(CONFIG_NR_CPUS, false);
hp_stats_update(0, true);
new_state = TEGRA_CPQ_G;
@@ -222,7 +222,7 @@ static int __apply_cluster_config(int state, int target_state)
}
} else if (target_state == TEGRA_CPQ_LP && !no_lp &&
num_online_cpus() == 1) {
- if (!clk_set_parent(cpu_clk, cpu_lp_clk)) {
+ if (!tegra_cluster_switch(cpu_clk, cpu_lp_clk)) {
hp_stats_update(CONFIG_NR_CPUS, true);
hp_stats_update(0, false);
new_state = TEGRA_CPQ_LP;
diff --git a/arch/arm/mach-tegra/edp_core.c b/arch/arm/mach-tegra/edp_core.c
index ffbe56743a1a..1dfc6f29d672 100644
--- a/arch/arm/mach-tegra/edp_core.c
+++ b/arch/arm/mach-tegra/edp_core.c
@@ -78,7 +78,6 @@ static int set_cap_rates(unsigned long *new_rates)
return 0;
}
-#if 0
static int update_cap_rates(unsigned long *new_rates, unsigned long *old_rates)
{
int i, ret;
@@ -112,7 +111,6 @@ static int update_cap_rates(unsigned long *new_rates, unsigned long *old_rates)
}
return 0;
}
-#endif
/* FIXME: resume sync ? */
@@ -170,6 +168,35 @@ void __init tegra_init_core_edp_limits(unsigned int regulator_mA)
limits->cap_clocks[i]->name, cap_rates[i]);
}
+/* core edp cpu state update */
+int tegra_core_edp_cpu_state_update(bool scpu_state)
+{
+ int ret = 0;
+ unsigned long *old_cap_rates;
+ unsigned long *new_cap_rates;
+
+ if (!limits) {
+ core_edp_scpu_state = scpu_state;
+ return 0;
+ }
+
+ mutex_lock(&core_edp_lock);
+
+ if (core_edp_scpu_state != scpu_state) {
+ old_cap_rates = get_current_cap_rates();
+ new_cap_rates = get_cap_rates(scpu_state, core_edp_profile,
+ core_edp_modules_state, core_edp_thermal_idx);
+ ret = update_cap_rates(new_cap_rates, old_cap_rates);
+ if (ret)
+ update_cap_rates(old_cap_rates, new_cap_rates);
+ else
+ core_edp_scpu_state = scpu_state;
+ }
+ mutex_unlock(&core_edp_lock);
+
+ return ret;
+}
+
#ifdef CONFIG_DEBUG_FS
static int edp_table_show(struct seq_file *s, void *data)
diff --git a/arch/arm/mach-tegra/include/mach/edp.h b/arch/arm/mach-tegra/include/mach/edp.h
index 34c3a828d6d8..ead5d9380700 100644
--- a/arch/arm/mach-tegra/include/mach/edp.h
+++ b/arch/arm/mach-tegra/include/mach/edp.h
@@ -121,11 +121,14 @@ static inline void tegra_battery_edp_init(unsigned int cap) {}
#ifdef CONFIG_TEGRA_CORE_EDP_LIMITS
void tegra_init_core_edp_limits(unsigned int regulator_mA);
int tegra_core_edp_debugfs_init(struct dentry *edp_dir);
+int tegra_core_edp_cpu_state_update(bool scpu_state);
#else
static inline void tegra_init_core_edp_limits(unsigned int regulator_mA)
{}
static inline int tegra_core_edp_debugfs_init(struct dentry *edp_dir)
{ return 0; }
+static inline int tegra_core_edp_cpu_state_update(bool scpu_state)
+{ return 0; }
#endif
int tegra11x_select_core_edp_table(unsigned int regulator_mA,
struct tegra_core_edp_limits *limits);
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index 4c79e9f52a54..a307bd521bce 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -311,7 +311,7 @@ int tegra_boot_secondary(unsigned int cpu, struct task_struct *idle)
clk_get_min_rate(cpu_g_clk) / 1000);
tegra_update_cpu_speed(speed);
#endif
- status = clk_set_parent(cpu_clk, cpu_g_clk);
+ status = tegra_cluster_switch(cpu_clk, cpu_g_clk);
}
if (status)
diff --git a/arch/arm/mach-tegra/pm-t3.c b/arch/arm/mach-tegra/pm-t3.c
index ac1834c18f2e..0ef39ef71327 100644
--- a/arch/arm/mach-tegra/pm-t3.c
+++ b/arch/arm/mach-tegra/pm-t3.c
@@ -33,6 +33,7 @@
#include <mach/iomap.h>
#include <mach/irqs.h>
#include <mach/io_dpd.h>
+#include <mach/edp.h>
#include <asm/smp_plat.h>
#include <asm/cputype.h>
@@ -538,6 +539,29 @@ int tegra_switch_to_g_cluster()
return e;
}
+int tegra_cluster_switch(struct clk *cpu_clk, struct clk *new_cluster_clk)
+{
+ int ret;
+ bool is_target_lp = is_lp_cluster() ^
+ (clk_get_parent(cpu_clk) != new_cluster_clk);
+
+ /* Update core edp limits before switch to LP cluster; abort on error */
+ if (is_target_lp) {
+ ret = tegra_core_edp_cpu_state_update(is_target_lp);
+ if (ret)
+ return ret;
+ }
+
+ ret = clk_set_parent(cpu_clk, new_cluster_clk);
+ if (ret)
+ return ret;
+
+ /* Update core edp limits after switch to G cluster; ignore error */
+ if (!is_target_lp)
+ tegra_core_edp_cpu_state_update(is_target_lp);
+
+ return 0;
+}
#endif
#ifdef CONFIG_PM_SLEEP
diff --git a/arch/arm/mach-tegra/pm.h b/arch/arm/mach-tegra/pm.h
index b2c7bf820bf9..8be42e0d002b 100644
--- a/arch/arm/mach-tegra/pm.h
+++ b/arch/arm/mach-tegra/pm.h
@@ -157,6 +157,7 @@ void tegra_cluster_switch_prolog(unsigned int flags);
void tegra_cluster_switch_epilog(unsigned int flags);
int tegra_switch_to_g_cluster(void);
int tegra_switch_to_lp_cluster(void);
+int tegra_cluster_switch(struct clk *cpu_clk, struct clk *new_cluster_clk);
#else
#define INSTRUMENT_CLUSTER_SWITCH 0 /* Must be zero for ARCH_TEGRA_2x_SOC */
#define DEBUG_CLUSTER_SWITCH 0 /* Must be zero for ARCH_TEGRA_2x_SOC */
@@ -178,6 +179,11 @@ static inline int tegra_switch_to_lp_cluster(void)
{
return -EPERM;
}
+static inline int tegra_cluster_switch(struct clk *cpu_clk,
+ struct clk *new_cluster_clk)
+{
+ return -EPERM;
+}
#endif
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
diff --git a/arch/arm/mach-tegra/sysfs-cluster.c b/arch/arm/mach-tegra/sysfs-cluster.c
index 3b37af28984e..7792354449a4 100644
--- a/arch/arm/mach-tegra/sysfs-cluster.c
+++ b/arch/arm/mach-tegra/sysfs-cluster.c
@@ -442,7 +442,7 @@ static ssize_t sysfscluster_store(struct kobject *kobj,
spin_unlock(&cluster_lock);
if (new_parent) {
- e = clk_set_parent(cpu_clk, new_parent);
+ e = tegra_cluster_switch(cpu_clk, new_parent);
if (e) {
PRINT_CLUSTER(("cluster/active: request failed (%d)\n",
e));