ARM: tegra: dvfs: Add in-band dvfs rail state control
Alex Frid [Tue, 10 Sep 2013 03:22:00 +0000 (20:22 -0700)]
Unlike CPU and core rails, GPU rail can be turned on/off via regulator
interface by the code running on CPU (CPU and core rails can be only
controlled by side-band h/w interfaces). This commit added in-band
dvfs s/w interfaces for GPU rail state control.

Bug 1364240
Bug 1318046

Change-Id: I864e0d503387dc70e534e02c379a5e30816aedaa
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: http://git-master/r/272356
Reviewed-by: Prashant Malani <pmalani@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>

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

index 74d98d3..791e2fb 100644 (file)
@@ -1097,6 +1097,57 @@ struct dvfs_rail *tegra_dvfs_get_rail_by_name(const char *reg_id)
        return NULL;
 }
 
+int tegra_dvfs_rail_power_up(struct dvfs_rail *rail)
+{
+       int ret = -ENOENT;
+
+       if (!rail || !rail->in_band_pm)
+               return -ENOSYS;
+
+       mutex_lock(&dvfs_lock);
+       if (rail->reg) {
+               ret = regulator_enable(rail->reg);
+               if (!ret && !timekeeping_suspended)
+                       tegra_dvfs_rail_on(rail, ktime_get());
+       }
+       mutex_unlock(&dvfs_lock);
+       return ret;
+}
+
+int tegra_dvfs_rail_power_down(struct dvfs_rail *rail)
+{
+       int ret = -ENOENT;
+
+       if (!rail || !rail->in_band_pm)
+               return -ENOSYS;
+
+       mutex_lock(&dvfs_lock);
+       if (rail->reg) {
+               ret = regulator_disable(rail->reg);
+               if (!ret && !timekeeping_suspended)
+                       tegra_dvfs_rail_off(rail, ktime_get());
+       }
+       mutex_unlock(&dvfs_lock);
+       return ret;
+}
+
+bool tegra_dvfs_is_rail_up(struct dvfs_rail *rail)
+{
+       bool ret = false;
+
+       if (!rail)
+               return false;
+
+       if (!rail->in_band_pm)
+               return true;
+
+       mutex_lock(&dvfs_lock);
+       if (rail->reg)
+               ret = regulator_is_enabled(rail->reg) > 0;
+       mutex_unlock(&dvfs_lock);
+       return ret;
+}
+
 bool tegra_dvfs_rail_updating(struct clk *clk)
 {
        return (!clk ? false :
index 8d8b698..7bac2ae 100644 (file)
@@ -80,6 +80,7 @@ struct dvfs_rail {
        int step;
        int step_up;
        bool jmp_to_zero;
+       bool in_band_pm;
        bool disabled;
        bool updating;
        bool resolving_to;
@@ -215,11 +216,15 @@ int tegra_dvfs_init_rails(struct dvfs_rail *dvfs_rails[], int n);
 void tegra_dvfs_add_relationships(struct dvfs_relationship *rels, int n);
 void tegra_dvfs_rail_enable(struct dvfs_rail *rail);
 void tegra_dvfs_rail_disable(struct dvfs_rail *rail);
+int tegra_dvfs_rail_power_up(struct dvfs_rail *rail);
+int tegra_dvfs_rail_power_down(struct dvfs_rail *rail);
+bool tegra_dvfs_is_rail_up(struct dvfs_rail *rail);
 bool tegra_dvfs_rail_updating(struct clk *clk);
 void tegra_dvfs_rail_off(struct dvfs_rail *rail, ktime_t now);
 void tegra_dvfs_rail_on(struct dvfs_rail *rail, ktime_t now);
 void tegra_dvfs_rail_pause(struct dvfs_rail *rail, ktime_t delta, bool on);
 struct dvfs_rail *tegra_dvfs_get_rail_by_name(const char *reg_id);
+
 int tegra_dvfs_predict_millivolts(struct clk *c, unsigned long rate);
 int tegra_dvfs_predict_millivolts_pll(struct clk *c, unsigned long rate);
 int tegra_dvfs_predict_millivolts_dfll(struct clk *c, unsigned long rate);