ARM: tegra: dvfs: Add predict peak voltage interface
Alex Frid [Tue, 8 Oct 2013 00:17:47 +0000 (17:17 -0700)]
With introduction of thermal dvfs, frequency-to-voltage mapping may
be changed at run time with temperature. Therefore, s/w layers that
rely on inverse voltage-to-frequency tables to determine frequency
caps, should use peak voltages across all thermal dvfs ranges. Hence,
this commit:
- added the respective peak_millivolts entry in dvfs structure
- added tetra_dvfs_predict_peak_millivolts() interface
- modified EDP table calculation to use peak voltage prediction
- modified core cap table construction to use peak voltage prediction,
changed warning reported when voltage for minimum frequency is above
core Vmin to info - this maybe true in some thermal dvfs range
- modified override range calculation to use peak voltage prediction,
added dvfs safe-guard in rail override mode to make sure that override
limit is not violated in any thermal range

For now, dvfs peak millivolts entries are not populated at all, and
predicted peak voltage are based on dvfs table active at the moment in
current thermal range (the same as standard predict voltage interface).

Bug 1307919

Change-Id: Ia8d962c66efbcb98d227dab55b36bbba8d93ef5f
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: http://git-master/r/289480
Reviewed-on: http://git-master/r/298527
Reviewed-by: Diwakar Tundlam <dtundlam@nvidia.com>
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>

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

index 4e4c763..829c976 100644 (file)
@@ -626,6 +626,13 @@ __tegra_dvfs_set_rate(struct dvfs *d, unsigned long rate)
                                __func__, d->clk_name, mv, detach_mv);
                        return -EINVAL;
                }
+
+               detach_mv = d->dvfs_rail->override_millivolts;
+               if (detach_mv && (mv > detach_mv)) {
+                       pr_warn("%s: %s: voltage %d above override level %d\n",
+                               __func__, d->clk_name, mv, detach_mv);
+                       return -EINVAL;
+               }
                d->cur_millivolts = millivolts[i];
        }
 
@@ -694,6 +701,19 @@ int tegra_dvfs_predict_millivolts(struct clk *c, unsigned long rate)
        return predict_millivolts(c, millivolts, rate);
 }
 
+int tegra_dvfs_predict_peak_millivolts(struct clk *c, unsigned long rate)
+{
+       const int *millivolts;
+
+       if (!rate || !c->dvfs)
+               return 0;
+
+       millivolts = tegra_dvfs_is_dfll_range(c->dvfs, rate) ?
+                       c->dvfs->dfll_millivolts : c->dvfs->peak_millivolts ? :
+                       tegra_dvfs_get_millivolts_pll(c->dvfs);
+       return predict_millivolts(c, millivolts, rate);
+}
+
 int tegra_dvfs_predict_millivolts_pll(struct clk *c, unsigned long rate)
 {
        const int *millivolts;
@@ -877,7 +897,7 @@ int __init tegra_enable_dvfs_on_clk(struct clk *c, struct dvfs *d)
         */
        if (i && c->ops && !c->ops->shared_bus_update &&
            !(c->flags & PERIPH_ON_CBUS) && !d->can_override) {
-               int mv = tegra_dvfs_predict_millivolts(c, d->freqs[i-1]);
+               int mv = tegra_dvfs_predict_peak_millivolts(c, d->freqs[i-1]);
                if (d->dvfs_rail->min_override_millivolts < mv)
                        d->dvfs_rail->min_override_millivolts = mv;
        }
index 0370e67..063860e 100644 (file)
@@ -144,6 +144,7 @@ struct dvfs {
        unsigned long freqs[MAX_DVFS_FREQS];
        unsigned long *alt_freqs;
        const int *millivolts;
+       const int *peak_millivolts;
        const int *dfll_millivolts;
        struct dvfs_rail *dvfs_rail;
        bool auto_dvfs;
@@ -239,6 +240,7 @@ 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_peak_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);
 const int *tegra_dvfs_get_millivolts_pll(struct dvfs *d);
index 25a803c..def33c7 100644 (file)
@@ -232,7 +232,8 @@ static int edp_relate_freq_voltage(struct clk *clk_cpu_g,
                 i++, freq += FREQ_STEP) {
 
                /* Predict voltages */
-               voltage_mV = tegra_dvfs_predict_millivolts(clk_cpu_g, freq);
+               voltage_mV = tegra_dvfs_predict_peak_millivolts(
+                       clk_cpu_g, freq);
                if (voltage_mV < 0) {
                        pr_err("%s: couldn't predict voltage: freq %u; err %d",
                               __func__, freq, voltage_mV);
index 420fa0a..a7dedf0 100644 (file)
@@ -229,18 +229,18 @@ static int __init init_core_cap_one(struct clk *c, unsigned long *freqs)
                        rate = next_rate;
                        next_rate = clk_round_rate(c->parent, rate + 1000);
                        if (IS_ERR_VALUE(next_rate)) {
-                               pr_debug("tegra11_dvfs: failed to round %s rate %lu\n",
-                                        c->name, rate);
+                               pr_debug("%s: failed to round %s rate %lu\n",
+                                        __func__, c->parent->name, rate);
                                return -EINVAL;
                        }
                        if (rate == next_rate)
                                break;
 
-                       next_v = tegra_dvfs_predict_millivolts(
+                       next_v = tegra_dvfs_predict_peak_millivolts(
                                c->parent, next_rate);
                        if (IS_ERR_VALUE(next_v)) {
-                               pr_debug("tegra11_dvfs: failed to predict %s mV for rate %lu\n",
-                                        c->name, next_rate);
+                               pr_debug("%s: failed to predict %s mV for rate %lu\n",
+                                        __func__, c->parent->name, next_rate);
                                return -EINVAL;
                        }
                        if (next_v > v)
@@ -249,8 +249,8 @@ static int __init init_core_cap_one(struct clk *c, unsigned long *freqs)
 
                if (rate == 0) {
                        rate = next_rate;
-                       pr_warn("tegra11_dvfs: minimum %s rate %lu requires %d mV\n",
-                               c->name, rate, next_v);
+                       pr_info("%s: %s V=%dmV @ min F=%luHz above Vmin=%dmV\n",
+                               __func__, c->parent->name, next_v, rate, v);
                }
                freqs[i] = rate;
                next_rate = rate;