ARM: tegra11: clock: Add direct access to CPU DFLL
Alex Frid [Wed, 30 Jan 2013 01:04:19 +0000 (17:04 -0800)]
Added CPU DFLL access API for CPU idle driver to directly manipulate
DFLL rate underneath cpufreq governor, provided CPU rail is under DFLL
control.

Change-Id: I108cbffe530e8620513fb11e89707b003cb34b9d
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: http://git-master/r/195399
(cherry picked from commit 70ba214be307f805944ba3e3386201689ddec287)
Reviewed-on: http://git-master/r/199164
Reviewed-by: Simone Willett <swillett@nvidia.com>
Tested-by: Simone Willett <swillett@nvidia.com>

arch/arm/mach-tegra/cpuidle.h
arch/arm/mach-tegra/dvfs.h
arch/arm/mach-tegra/tegra11_clocks.c

index a9fe5a7..d94f2b1 100644 (file)
@@ -42,6 +42,7 @@ int tegra3_cpuidle_init_soc(struct tegra_cpuidle_ops *ops);
 int tegra11x_cpuidle_init_soc(struct tegra_cpuidle_ops *ops);
 int tegra14x_cpuidle_init_soc(struct tegra_cpuidle_ops *ops);
 int tegra11_cpu_backup_rate_exchange(unsigned long *rate);
+int tegra11_cpu_dfll_rate_exchange(unsigned long *rate);
 
 static inline int tegra_cpuidle_init_soc(struct tegra_cpuidle_ops *ops)
 {
@@ -59,6 +60,15 @@ static inline int tegra_cpuidle_init_soc(struct tegra_cpuidle_ops *ops)
 #endif
 }
 
+static inline int tegra_cpu_dfll_rate_exchange(unsigned long *rate)
+{
+#ifdef CONFIG_ARCH_TEGRA_11x_SOC
+       return tegra11_cpu_dfll_rate_exchange(rate);
+#else
+       return -ENOSYS;
+#endif
+}
+
 static inline int tegra_cpu_backup_rate_exchange(unsigned long *rate)
 {
 #ifdef CONFIG_ARCH_TEGRA_11x_SOC
index 067717f..c5473bc 100644 (file)
@@ -230,7 +230,7 @@ int tegra_init_core_cap(struct core_dvfs_cap_table *table, int table_size,
 
 static inline bool tegra_dvfs_rail_is_dfll_mode(struct dvfs_rail *rail)
 {
-       return rail->dfll_mode;
+       return rail ? rail->dfll_mode : false;
 }
 static inline bool tegra_dvfs_is_dfll_scale(struct dvfs *d, unsigned long rate)
 {
index ad7c03a..96e9128 100644 (file)
@@ -6941,6 +6941,30 @@ static void tegra11_init_one_clock(struct clk *c)
        clkdev_add(&c->lookup);
 }
 
+/* Direct access to CPU clock sources fot CPU idle driver */
+int tegra11_cpu_dfll_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 tegra11_cpu_backup_rate_exchange(unsigned long *rate)
 {
        int ret = 0;