ARM: tegra12: clock: Add interface to set G and LP CPU idle rate
Prashant Gaikwad [Tue, 27 Aug 2013 08:58:11 +0000 (13:58 +0530)]
Added interface to set fast and slow CPU idle rate by direct
(i.e., underneath cpufreq governor) clock source control.

This change is port of T114 implementation. T148 implements
these interfaces in different way.

Bug 1349795

Change-Id: Ie4fa646f08feee073e0a96a053667a47257c45f8
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
Reviewed-on: http://git-master/r/266692
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Tested-by: Bharat Nihalani <bnihalani@nvidia.com>

arch/arm/mach-tegra/cpuidle.h
arch/arm/mach-tegra/tegra12_clocks.c

index 5e99fac..b204955 100644 (file)
@@ -49,6 +49,8 @@ int tegra11_cpu_lp_idle_rate_exchange(unsigned long *rate);
 int tegra11_cpu_g_idle_rate_exchange(unsigned long *rate);
 int tegra14_cpu_lp_idle_rate_exchange(unsigned long *rate);
 int tegra14_cpu_g_idle_rate_exchange(unsigned long *rate);
+int tegra12_cpu_lp_idle_rate_exchange(unsigned long *rate);
+int tegra12_cpu_g_idle_rate_exchange(unsigned long *rate);
 
 static inline int tegra_cpuidle_init_soc(struct tegra_cpuidle_ops *ops)
 {
@@ -68,24 +70,26 @@ static inline int tegra_cpuidle_init_soc(struct tegra_cpuidle_ops *ops)
 
 static inline int tegra_cpu_g_idle_rate_exchange(unsigned long *rate)
 {
-#ifdef CONFIG_ARCH_TEGRA_11x_SOC
+#if defined(CONFIG_ARCH_TEGRA_11x_SOC)
        return tegra11_cpu_g_idle_rate_exchange(rate);
-#else
-#ifdef CONFIG_ARCH_TEGRA_14x_SOC
+#elif defined(CONFIG_ARCH_TEGRA_12x_SOC)
+       return tegra12_cpu_g_idle_rate_exchange(rate);
+#elif defined CONFIG_ARCH_TEGRA_14x_SOC
        return tegra14_cpu_g_idle_rate_exchange(rate);
-#endif
+#else
        return -ENOSYS;
 #endif
 }
 
 static inline int tegra_cpu_lp_idle_rate_exchange(unsigned long *rate)
 {
-#ifdef CONFIG_ARCH_TEGRA_11x_SOC
+#if defined(CONFIG_ARCH_TEGRA_11x_SOC)
        return tegra11_cpu_lp_idle_rate_exchange(rate);
-#else
-#ifdef CONFIG_ARCH_TEGRA_14x_SOC
+#elif defined(CONFIG_ARCH_TEGRA_12x_SOC)
+       return tegra12_cpu_lp_idle_rate_exchange(rate);
+#elif defined CONFIG_ARCH_TEGRA_14x_SOC
        return tegra14_cpu_lp_idle_rate_exchange(rate);
-#endif
+#else
        return -ENOSYS;
 #endif
 }
index 4e6972b..7ccfb72 100644 (file)
@@ -7799,6 +7799,49 @@ static void tegra12_init_one_clock(struct clk *c)
        clkdev_add(&c->lookup);
 }
 
+/* Direct access to CPU clock sources fot CPU idle driver */
+int tegra12_cpu_g_idle_rate_exchange(unsigned long *rate)
+{
+       int ret = 0;
+       struct clk *dfll = tegra_clk_cpu_cmplx.parent->u.cpu.dynamic;
+       unsigned long old_rate, new_rate, flags;
+
+       if (!dfll || !tegra_dvfs_rail_is_dfll_mode(tegra_cpu_rail))
+               return -EPERM;
+
+       /* Clipping min to oscillator rate is pretty much arbitrary */
+       new_rate = max(*rate, tegra_clk_m.rate);
+
+       clk_lock_save(dfll, &flags);
+
+       old_rate = clk_get_rate_locked(dfll);
+       *rate = old_rate;
+       if (new_rate != old_rate)
+               ret = clk_set_rate_locked(dfll, new_rate);
+
+       clk_unlock_restore(dfll, &flags);
+       return ret;
+}
+
+int tegra12_cpu_lp_idle_rate_exchange(unsigned long *rate)
+{
+       int ret = 0;
+       struct clk *backup = tegra_clk_cpu_cmplx.parent->u.cpu.backup;
+       unsigned long old_rate, flags;
+       unsigned long new_rate = min(
+               *rate, tegra_clk_cpu_cmplx.parent->u.cpu.backup_rate);
+
+       clk_lock_save(backup, &flags);
+
+       old_rate = clk_get_rate_locked(backup);
+       *rate = old_rate;
+       if (new_rate != old_rate)
+               ret = clk_set_rate_locked(backup, new_rate);
+
+       clk_unlock_restore(backup, &flags);
+       return ret;
+}
+
 void tegra_edp_throttle_cpu_now(u8 factor)
 {
        /* empty definition for tegra12 */