diff options
author | Alex Frid <afrid@nvidia.com> | 2012-11-18 00:45:43 -0800 |
---|---|---|
committer | Simone Willett <swillett@nvidia.com> | 2012-11-27 12:30:25 -0800 |
commit | 2f656f2396599ad06278821284f3ea43a5718f46 (patch) | |
tree | 661a9d30180d3b68481ea21a9c61378b79f1f7c1 /arch | |
parent | 5091fa5b6b8b18de0bed1d852d46f7316a9f4b9d (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.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-tegra/edp_core.c | 31 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/mach/edp.h | 3 | ||||
-rw-r--r-- | arch/arm/mach-tegra/platsmp.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-tegra/pm-t3.c | 24 | ||||
-rw-r--r-- | arch/arm/mach-tegra/pm.h | 6 | ||||
-rw-r--r-- | arch/arm/mach-tegra/sysfs-cluster.c | 2 |
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)); |