ARM: tegra: dvfs: Always apply dvfs rail thermal floors
Alex Frid [Fri, 22 Mar 2013 04:32:10 +0000 (21:32 -0700)]
Re-factored dvfs rail thermal control so that thermal floors are
applied even when cooling devices are not present or not supported.
Maximum (cold) floor will be set in such case to be safe at any
temperature. Added warnings on different thermal floors and cooling
devices configuration missmatches.

Bug 1248374

Change-Id: I7e0917d15c44587d32d4fad446dcb2dae12c6fb7
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: http://git-master/r/212323
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>

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

index d91bffc..8cd13fd 100644 (file)
@@ -69,15 +69,28 @@ void tegra_dvfs_add_relationships(struct dvfs_relationship *rels, int n)
 
 /*
  * Make sure that DFLL and PLL mode cooling devices have identical set of
- * trip-points (needed for DFLL/PLL auto-switch)
+ * trip-points (needed for DFLL/PLL auto-switch) and matching thermal floors.
  */
 static void dvfs_validate_cdevs(struct dvfs_rail *rail)
 {
-       if (rail->pll_mode_cdev && !rail->therm_mv_floors) {
-               rail->pll_mode_cdev = NULL;
-               WARN(1, "%s: invalid thermal floors\n", rail->reg_id);
+       if (!rail->therm_mv_floors != !rail->therm_mv_floors_num) {
+               rail->therm_mv_floors_num = 0;
+               rail->therm_mv_floors = NULL;
+               WARN(1, "%s: not matching thermal floors/num\n", rail->reg_id);
        }
 
+       if (rail->pll_mode_cdev) {
+               if (rail->pll_mode_cdev->trip_temperatures_num !=
+                   rail->therm_mv_floors_num) {
+                       rail->pll_mode_cdev = NULL;
+                       WARN(1, "%s: not matching thermal floors/trips\n",
+                            rail->reg_id);
+               }
+       }
+
+       if (rail->therm_mv_floors && !rail->pll_mode_cdev)
+               WARN(1, "%s: missing pll mode cooling device\n", rail->reg_id);
+
        if (rail->dfll_mode_cdev) {
                if (rail->dfll_mode_cdev != rail->pll_mode_cdev) {
                        rail->dfll_mode_cdev = NULL;
@@ -307,9 +320,9 @@ static inline int dvfs_rail_apply_limits(struct dvfs_rail *rail, int millivolts)
 {
        int min_mv = rail->min_millivolts;
 
-       if (rail->pll_mode_cdev) {
+       if (rail->therm_mv_floors) {
                int i = rail->thermal_idx;
-               if (i < rail->pll_mode_cdev->trip_temperatures_num)
+               if (i < rail->therm_mv_floors_num)
                        min_mv = rail->therm_mv_floors[i];
        }
 
@@ -948,9 +961,8 @@ int tegra_dvfs_rail_dfll_mode_set_cold(struct dvfs_rail *rail)
 {
        int ret = 0;
 
-#ifdef CONFIG_THERMAL
-       /* No cooling in dfll mode - nothing to do */
-       if (!rail || !rail->dfll_mode_cdev)
+       /* No thermal floors - nothing to do */
+       if (!rail || !rail->therm_mv_floors)
                return ret;
 
        /*
@@ -960,12 +972,12 @@ int tegra_dvfs_rail_dfll_mode_set_cold(struct dvfs_rail *rail)
         */
        mutex_lock(&dvfs_lock);
        if (rail->dfll_mode &&
-           (rail->thermal_idx < rail->pll_mode_cdev->trip_temperatures_num)) {
+           (rail->thermal_idx < rail->therm_mv_floors_num)) {
                        int mv = rail->therm_mv_floors[rail->thermal_idx];
                        ret = dvfs_rail_set_voltage_reg(rail, mv);
        }
        mutex_unlock(&dvfs_lock);
-#endif
+
        return ret;
 }
 
@@ -1092,10 +1104,9 @@ static int dvfs_tree_show(struct seq_file *s, void *data)
                }
                seq_printf(s, "   offset     %-7d mV\n", rail->offs_millivolts);
 
-               if ((!rail->dfll_mode && rail->pll_mode_cdev) ||
-                   rail->dfll_mode_cdev) {
+               if (rail->therm_mv_floors) {
                        int i = rail->thermal_idx;
-                       if (i < rail->pll_mode_cdev->trip_temperatures_num)
+                       if (i < rail->therm_mv_floors_num)
                                thermal_mv_floor = rail->therm_mv_floors[i];
                }
                seq_printf(s, "   thermal    %-7d mV\n", thermal_mv_floor);
index bfdca6a..d79a0aa 100644 (file)
@@ -64,6 +64,7 @@ struct dvfs_rail {
        int reg_max_millivolts;
        int nominal_millivolts;
        const int *therm_mv_floors;
+       int therm_mv_floors_num;
 
        int step;
        bool jmp_to_zero;
index 2c2f817..f3140ad 100644 (file)
@@ -426,13 +426,21 @@ static void __init init_rail_thermal_profile(
                        break;
 
                if ((therm_trips_table[i] >= therm_trips_table[i+1]) ||
-                   (therm_floors_table[i] < therm_floors_table[i+1]))
+                   (therm_floors_table[i] < therm_floors_table[i+1])) {
+                       WARN(1, "%s: invalid thermal floors\n", rail->reg_id);
                        return;
+               }
        }
 
        min_mv = max(rail->min_millivolts, d ? d->min_millivolts : 0);
-       if (therm_floors_table[i] < min_mv)
+       if (therm_floors_table[i] < min_mv) {
+               WARN(1, "%s: thermal floor below Vmin\n", rail->reg_id);
                return;
+       }
+
+       /* Install validated thermal floors */
+       rail->therm_mv_floors = therm_floors_table;
+       rail->therm_mv_floors_num = i + 1;
 
        /* Setup trip-points, use the same trips in dfll mode (if applicable) */
        if (rail->pll_mode_cdev) {
@@ -441,7 +449,6 @@ static void __init init_rail_thermal_profile(
                if (d)
                        rail->dfll_mode_cdev = rail->pll_mode_cdev;
        }
-       rail->therm_mv_floors = therm_floors_table;
 }
 
 static bool __init can_update_max_rate(struct clk *c, struct dvfs *d)
index 0a5fd77..b77f473 100644 (file)
@@ -186,8 +186,9 @@ struct tegra_cl_dvfs {
        u8                              safe_output;
        u8                              tune_high_out_start;
        u8                              tune_high_out_min;
-       u8                              thermal_out_floors[MAX_THERMAL_FLOORS];
        u8                              minimax_output;
+       u8                              thermal_out_floors[MAX_THERMAL_FLOORS];
+       int                             therm_floors_num;
        unsigned long                   dvco_rate_min;
 
        u8                              lut_min;
@@ -362,7 +363,7 @@ static inline u8 get_output_min(struct tegra_cl_dvfs *cld)
        tune_min = cld->tune_state == TEGRA_CL_DVFS_TUNE_LOW ?
                0 : cld->tune_high_out_min;
        thermal_min = 0;
-       if (cld->cdev && (cld->thermal_idx < cld->cdev->trip_temperatures_num))
+       if (cld->thermal_idx < cld->therm_floors_num)
                thermal_min = cld->thermal_out_floors[cld->thermal_idx];
 
        return max(tune_min, thermal_min);
@@ -688,7 +689,7 @@ static unsigned long find_dvco_rate_min(struct tegra_cl_dvfs *cld, u8 out_min)
 static void cl_dvfs_set_dvco_rate_min(struct tegra_cl_dvfs *cld)
 {
        unsigned long rate = cld->safe_dvfs->dfll_data.out_rate_min;
-       if (cld->cdev && (cld->thermal_idx < cld->cdev->trip_temperatures_num))
+       if (cld->thermal_idx < cld->therm_floors_num)
                rate = find_dvco_rate_min(
                                cld, cld->thermal_out_floors[cld->thermal_idx]);
 
@@ -792,14 +793,20 @@ static void cl_dvfs_init_tuning_thresholds(struct tegra_cl_dvfs *cld)
 static void cl_dvfs_init_cold_output_floor(struct tegra_cl_dvfs *cld)
 {
        int i;
-       if (!cld->cdev)
+       if (!cld->safe_dvfs->dvfs_rail->therm_mv_floors ||
+           !cld->safe_dvfs->dvfs_rail->therm_mv_floors_num)
                return;
+
+       if (!cld->cdev)
+               WARN(1, "%s: missing dfll mode cooling device\n",
+                    cld->safe_dvfs->dvfs_rail->reg_id);
        /*
         * Convert monotonically decreasing thermal floors at low temperature
         * into output LUT indexes; make sure there is a room for regulation
         * above maximum thermal floor.
         */
-       for (i = 0; i < cld->cdev->trip_temperatures_num; i++) {
+       cld->therm_floors_num = cld->safe_dvfs->dvfs_rail->therm_mv_floors_num;
+       for (i = 0; i < cld->therm_floors_num; i++) {
                cld->thermal_out_floors[i] = find_mv_out_cap(
                        cld, cld->safe_dvfs->dvfs_rail->therm_mv_floors[i]);
        }