ARM: tegra: power: Add voltage to freq convertion interface.
Amit Kamath [Mon, 17 Dec 2012 07:22:30 +0000 (12:22 +0530)]
Use EDP generated tables to calculate the frequency supported at
a specified voltage

bug 1042409

Reviewed-on: http://git-master/r/171819
(cherry picked from commit b15b288083e02f0caa7644a2e01f0703b501187f)

Change-Id: Id2aa6ac61023b9c9de1810fe6a46e4a1bc70eed0
Signed-off-by: Amit Kamath <akamath@nvidia.com>
Signed-off-by: Richard Zhao <rizhao@nvidia.com>
Reviewed-on: http://git-master/r/199964
Reviewed-by: Simone Willett <swillett@nvidia.com>
Tested-by: Simone Willett <swillett@nvidia.com>

arch/arm/mach-tegra/edp.c
arch/arm/mach-tegra/include/mach/edp.h

index 5314019..b80891f 100644 (file)
@@ -477,6 +477,8 @@ static struct tegra_edp_cpu_leakage_params leakage_params[] = {
 };
 #endif
 
+static struct tegra_edp_freq_voltage_table *freq_voltage_lut_saved;
+static unsigned int freq_voltage_lut_size_saved;
 static struct tegra_edp_freq_voltage_table *freq_voltage_lut;
 static unsigned int freq_voltage_lut_size;
 
@@ -569,13 +571,15 @@ unsigned int edp_calculate_maxf(struct tegra_edp_cpu_leakage_params *params,
 }
 
 static int edp_relate_freq_voltage(struct clk *clk_cpu_g,
-                               unsigned int cpu_speedo_idx)
+                       unsigned int cpu_speedo_idx,
+                       unsigned int freq_volt_lut_size,
+                       struct tegra_edp_freq_voltage_table *freq_volt_lut)
 {
        unsigned int i, j, freq;
        int voltage_mV;
 
        for (i = 0, j = 0, freq = 0;
-                i < freq_voltage_lut_size;
+                i < freq_volt_lut_size;
                 i++, freq += FREQ_STEP) {
 
                /* Predict voltages */
@@ -587,12 +591,24 @@ static int edp_relate_freq_voltage(struct clk *clk_cpu_g,
                }
 
                /* Cache frequency / voltage / voltage constant relationship */
-               freq_voltage_lut[i].freq = freq;
-               freq_voltage_lut[i].voltage_mV = voltage_mV;
+               freq_volt_lut[i].freq = freq;
+               freq_volt_lut[i].voltage_mV = voltage_mV;
        }
        return 0;
 }
 
+unsigned int tegra_edp_find_maxf(int volt)
+{
+       unsigned int i;
+
+       for (i = 0; i < freq_voltage_lut_size_saved; i++) {
+               if (freq_voltage_lut_saved[i].voltage_mV > volt)
+                       break;
+       }
+       return freq_voltage_lut[i - 1].freq;
+}
+
+
 int edp_find_speedo_idx(int cpu_speedo_id, unsigned int *cpu_speedo_idx)
 {
        int i;
@@ -650,7 +666,8 @@ static int init_cpu_edp_limits_calculated(void)
                return -ENOMEM;
        }
 
-       ret = edp_relate_freq_voltage(clk_cpu_g, cpu_speedo_idx);
+       ret = edp_relate_freq_voltage(clk_cpu_g, cpu_speedo_idx,
+                               freq_voltage_lut_size, freq_voltage_lut);
        if (ret) {
                kfree(power_edp_calc_limits);
                kfree(edp_calculated_limits);
@@ -658,6 +675,26 @@ static int init_cpu_edp_limits_calculated(void)
                return ret;
        }
 
+       if (freq_voltage_lut_size != freq_voltage_lut_size_saved) {
+               /* release previous table if present */
+               kfree(freq_voltage_lut_saved);
+               /* create table to save */
+               freq_voltage_lut_saved =
+                       kmalloc(sizeof(struct tegra_edp_freq_voltage_table) *
+                       freq_voltage_lut_size, GFP_KERNEL);
+               if (!freq_voltage_lut_saved) {
+                       pr_err("%s: failed alloc mem for freq/voltage LUT\n",
+                               __func__);
+                       kfree(freq_voltage_lut);
+                       return -ENOMEM;
+               }
+               freq_voltage_lut_size_saved = freq_voltage_lut_size;
+       }
+       memcpy(freq_voltage_lut_saved,
+               freq_voltage_lut,
+               sizeof(struct tegra_edp_freq_voltage_table) *
+                       freq_voltage_lut_size);
+
        /* Calculate EDP table */
        for (n_cores_idx = 0; n_cores_idx < NR_CPUS; n_cores_idx++) {
                for (temp_idx = 0;
index 988eb0d..b73dc94 100644 (file)
@@ -88,6 +88,7 @@ int tegra_system_edp_alarm(bool alarm);
 void tegra_platform_edp_init(struct thermal_trip_info *trips,
                                        int *num_trips, int margin);
 struct tegra_system_edp_entry *tegra_get_system_edp_entries(int *size);
+unsigned int tegra_edp_find_maxf(int volt);
 #else
 static inline struct thermal_cooling_device *edp_cooling_device_create(
        int index)
@@ -112,6 +113,8 @@ static inline void tegra_platform_edp_init(struct thermal_trip_info *trips,
 {}
 static inline struct tegra_system_edp_entry
                *tegra_get_system_edp_entries(int *size) { return NULL; }
+static inline unsigned int tegra_edp_find_maxf(int volt)
+{ return -1; }
 #endif
 
 #ifdef CONFIG_ARCH_TEGRA_2x_SOC