ARM: tegra11: power: Update core EDP on CPU cluster switch
Alex Frid [Sun, 18 Nov 2012 08:45:43 +0000 (00:45 -0800)]
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>

arch/arm/mach-tegra/cpuquiet.c
arch/arm/mach-tegra/edp_core.c
arch/arm/mach-tegra/include/mach/edp.h
arch/arm/mach-tegra/platsmp.c
arch/arm/mach-tegra/pm-t3.c
arch/arm/mach-tegra/pm.h
arch/arm/mach-tegra/sysfs-cluster.c

index cdfa16a..7fe6b64 100644 (file)
@@ -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;
index ffbe567..1dfc6f2 100644 (file)
@@ -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)
index 34c3a82..ead5d93 100644 (file)
@@ -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);
index 20664e6..bd73b6e 100644 (file)
@@ -283,7 +283,7 @@ static int __cpuinit tegra_boot_secondary(unsigned int cpu, struct task_struct *
                                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)
index b6773f4..cef9de8 100644 (file)
@@ -32,6 +32,7 @@
 #include <mach/gpio.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
index b2c7bf8..8be42e0 100644 (file)
@@ -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
index c72b9b5..5e42fa0 100644 (file)
@@ -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));