ARM: tegra: power-edp table
Diwakar Tundlam [Tue, 22 Jan 2013 20:48:25 +0000 (12:48 -0800)]
Added code for populating cpu power edp table during init. This is
needed for the AP+DRAM super system EDP client.

Bug 1159974

Change-Id: If1f5c3e53416a1edb1df42ff1cb356e0b1d507c6
Signed-off-by: Diwakar Tundlam <dtundlam@nvidia.com>
Signed-off-by: Sivaram Nair <sivaramn@nvidia.com>
Reviewed-on: http://git-master/r/198023

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

index 26ea066..c76e7e8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/arm/mach-tegra/edp.c
  *
- * Copyright (C) 2011-2012, NVIDIA CORPORATION. All Rights Reserved.
+ * Copyright (C) 2011-2013, NVIDIA CORPORATION. All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -42,6 +42,9 @@ static unsigned int edp_reg_override_mA = OVERRIDE_DEFAULT;
 
 static const unsigned int *system_edp_limits;
 
+static struct tegra_system_edp_entry *power_edp_limits;
+static int power_edp_limits_size;
+
 /*
  * Temperature step size cannot be less than 4C because of hysteresis
  * delta
@@ -324,8 +327,22 @@ static struct tegra_edp_limits edp_default_limits[] = {
        {85, {1000000, 1000000, 1000000, 1000000} },
 };
 
+static struct tegra_system_edp_entry power_edp_default_limits[] = {
+       {0, 20, {1000000, 1000000, 1000000, 1000000} },
+};
+
 /* Constants for EDP calculations */
-static int temperatures[] = { 23, 40, 50, 60, 70, 75, 80, 85, 90, 95, 100, 105 };
+static const int temperatures[] = { /* degree celcius (C) */
+       23, 40, 50, 60, 70, 75, 80, 85, 90, 95, 100, 105,
+};
+static const int power_cap_levels[] = { /* milliwatts (mW) */
+       500, 1000, 1500, 2000, 2500, 3000, 3500,
+       4000, 4500, 5000, 5500, 6000, 6500, 7000, 7500,
+       8000, 8500, 9000, 9500, 10000, 10500, 11000, 11500,
+       12000, 12500, 13000, 13500, 14000, 14500, 15000, 15500,
+       16000, 16500, 17000,
+};
+
 static struct tegra_edp_cpu_leakage_params leakage_params[] = {
        {
                .cpu_speedo_id      = 0, /* A01 CPU */
@@ -445,9 +462,11 @@ static inline s64 edp_pow(s64 val, int pwr)
 /*
  * Find the maximum frequency that results in dynamic and leakage current that
  * is less than the regulator current limit.
+ * temp_C - always valid
+ * power_mW - valid or -1 (infinite)
  */
 unsigned int edp_calculate_maxf(struct tegra_edp_cpu_leakage_params *params,
-                               int temp_C,
+                               int temp_C, int power_mW,
                                int iddq_mA,
                                int n_cores_idx)
 {
@@ -455,6 +474,7 @@ unsigned int edp_calculate_maxf(struct tegra_edp_cpu_leakage_params *params,
        unsigned int cur_effective = regulator_cur - edp_reg_override_mA;
        int f, i, j, k;
        s64 leakage_mA, dyn_mA, leakage_calc_step;
+       s64 leakage_mW, dyn_mW;
 
        for (f = freq_voltage_lut_size - 1; f >= 0; f--) {
                freq_KHz = freq_voltage_lut[f].freq / 1000;
@@ -500,8 +520,14 @@ unsigned int edp_calculate_maxf(struct tegra_edp_cpu_leakage_params *params,
                /* dyn_const_n was pre-multiplied by 1,000,000 */
                dyn_mA = div64_s64(dyn_mA, 1000000);
 
-               if ((leakage_mA + dyn_mA) <= cur_effective)
+               if (power_mW != -1) {
+                       leakage_mW = leakage_mA * voltage_mV;
+                       dyn_mW = dyn_mA * voltage_mV;
+                       if (div64_s64(leakage_mW + dyn_mW, 1000) <= power_mW)
+                               return freq_KHz;
+               } else if ((leakage_mA + dyn_mA) <= cur_effective) {
                        return freq_KHz;
+               }
        }
        return 0;
 }
@@ -548,11 +574,13 @@ int edp_find_speedo_idx(int cpu_speedo_id, unsigned int *cpu_speedo_idx)
 
 static int init_cpu_edp_limits_calculated(void)
 {
-       unsigned int temp_idx, n_cores_idx;
+       unsigned int temp_idx, n_cores_idx, pwr_idx;
        unsigned int cpu_g_minf, cpu_g_maxf;
        unsigned int iddq_mA;
        unsigned int cpu_speedo_idx;
+       unsigned int cap, limit;
        struct tegra_edp_limits *edp_calculated_limits;
+       struct tegra_system_edp_entry *power_edp_calc_limits;
        struct tegra_edp_cpu_leakage_params *params;
        int ret;
        struct clk *clk_cpu_g = tegra_get_clock_by_name("cpu_g");
@@ -570,6 +598,10 @@ static int init_cpu_edp_limits_calculated(void)
                                        * ARRAY_SIZE(temperatures), GFP_KERNEL);
        BUG_ON(!edp_calculated_limits);
 
+       power_edp_calc_limits = kmalloc(sizeof(struct tegra_system_edp_entry)
+                               * ARRAY_SIZE(power_cap_levels), GFP_KERNEL);
+       BUG_ON(!power_edp_calc_limits);
+
        cpu_g_minf = 0;
        cpu_g_maxf = clk_get_max_rate(clk_cpu_g);
        freq_voltage_lut_size = (cpu_g_maxf - cpu_g_minf) / FREQ_STEP + 1;
@@ -587,14 +619,14 @@ static int init_cpu_edp_limits_calculated(void)
        }
 
        /* Calculate EDP table */
-       for (temp_idx = 0; temp_idx < ARRAY_SIZE(temperatures); temp_idx++) {
-               edp_calculated_limits[temp_idx].
-                       temperature = temperatures[temp_idx];
-               for (n_cores_idx = 0; n_cores_idx < NR_CPUS; n_cores_idx++) {
-                       unsigned int cap;
-                       unsigned int limit =
-                               edp_calculate_maxf(params,
+       for (n_cores_idx = 0; n_cores_idx < NR_CPUS; n_cores_idx++) {
+               for (temp_idx = 0;
+                    temp_idx < ARRAY_SIZE(temperatures); temp_idx++) {
+                       edp_calculated_limits[temp_idx]. temperature =
+                               temperatures[temp_idx];
+                       limit = edp_calculate_maxf(params,
                                                   temperatures[temp_idx],
+                                                  -1,
                                                   iddq_mA,
                                                   n_cores_idx);
                        /* apply safety cap if it is specified */
@@ -606,6 +638,19 @@ static int init_cpu_edp_limits_calculated(void)
                        edp_calculated_limits[temp_idx].
                                freq_limits[n_cores_idx] = limit;
                }
+
+               for (pwr_idx = 0;
+                    pwr_idx < ARRAY_SIZE(power_cap_levels); pwr_idx++) {
+                       power_edp_calc_limits[pwr_idx].power_limit_100mW =
+                               power_cap_levels[pwr_idx] / 100;
+                       limit = edp_calculate_maxf(params,
+                                                  90,
+                                                  power_cap_levels[pwr_idx],
+                                                  iddq_mA,
+                                                  n_cores_idx);
+                       power_edp_calc_limits[pwr_idx].
+                               freq_limits[n_cores_idx] = limit;
+               }
        }
 
        /*
@@ -623,6 +668,16 @@ static int init_cpu_edp_limits_calculated(void)
                edp_limits_size = ARRAY_SIZE(temperatures);
        }
 
+       if (power_edp_limits != power_edp_default_limits) {
+               memcpy(power_edp_limits, power_edp_calc_limits,
+                      sizeof(struct tegra_system_edp_entry)
+                      * ARRAY_SIZE(power_cap_levels));
+               kfree(power_edp_calc_limits);
+       } else {
+               power_edp_limits = power_edp_calc_limits;
+               power_edp_limits_size = ARRAY_SIZE(power_cap_levels);
+       }
+
        kfree(freq_voltage_lut);
        return 0;
 }
@@ -688,11 +743,8 @@ void tegra_recalculate_cpu_edp_limits(void)
  */
 void __init tegra_init_cpu_edp_limits(unsigned int regulator_mA)
 {
-       if (!regulator_mA) {
-               edp_limits = edp_default_limits;
-               edp_limits_size = ARRAY_SIZE(edp_default_limits);
-               return;
-       }
+       if (!regulator_mA)
+               goto end;
        regulator_cur = regulator_mA + OVERRIDE_DEFAULT;
 
        switch (tegra_chip_id) {
@@ -710,8 +762,12 @@ void __init tegra_init_cpu_edp_limits(unsigned int regulator_mA)
                break;
        }
 
+ end:
        edp_limits = edp_default_limits;
        edp_limits_size = ARRAY_SIZE(edp_default_limits);
+
+       power_edp_limits = power_edp_default_limits;
+       power_edp_limits_size = ARRAY_SIZE(power_edp_default_limits);
 }
 
 void __init tegra_init_system_edp_limits(unsigned int power_limit_mW)
@@ -803,6 +859,12 @@ void tegra_platform_edp_init(struct thermal_trip_info *trips, int *num_trips)
        }
 }
 
+struct tegra_system_edp_entry *tegra_get_system_edp_entries(int *size)
+{
+       *size = power_edp_limits_size;
+       return power_edp_limits;
+}
+
 #ifdef CONFIG_DEBUG_FS
 
 static int edp_limit_debugfs_show(struct seq_file *s, void *data)
@@ -832,6 +894,18 @@ static int edp_debugfs_show(struct seq_file *s, void *data)
                           edp_limits[i].freq_limits[3]);
        }
 
+       seq_printf(s, "-- VDD_CPU Power EDP table --\n");
+       seq_printf(s, "%6s %10s %10s %10s %10s\n",
+                  " Power", "1-core", "2-cores", "3-cores", "4-cores");
+       for (i = 0; i < power_edp_limits_size; i++) {
+               seq_printf(s, "%5dmW: %10u %10u %10u %10u\n",
+                          power_edp_limits[i].power_limit_100mW * 100,
+                          power_edp_limits[i].freq_limits[0],
+                          power_edp_limits[i].freq_limits[1],
+                          power_edp_limits[i].freq_limits[2],
+                          power_edp_limits[i].freq_limits[3]);
+       }
+
        if (system_edp_limits) {
                seq_printf(s, "\n-- System EDP table --\n");
                seq_printf(s, "%10u %10u %10u %10u\n",
index 88500fa..e2560a2 100644 (file)
@@ -41,7 +41,7 @@ struct tegra_edp_limits {
 struct tegra_system_edp_entry {
        char speedo_id;
        char power_limit_100mW;
-       char freq_limits[4];
+       unsigned int freq_limits[4];
 };
 
 struct tegra_edp_cpu_leakage_params {
@@ -86,6 +86,7 @@ unsigned int tegra_get_edp_limit(int *get_edp_thermal_index);
 void tegra_get_system_edp_limits(const unsigned int **limits);
 int tegra_system_edp_alarm(bool alarm);
 void tegra_platform_edp_init(struct thermal_trip_info *trips, int *num_trips);
+struct tegra_system_edp_entry *tegra_get_system_edp_entries(int *size);
 #else
 static inline struct thermal_cooling_device *edp_cooling_device_create(
        int index)
@@ -108,6 +109,8 @@ static inline int tegra_system_edp_alarm(bool alarm)
 static inline void tegra_platform_edp_init(struct thermal_trip_info *trips,
                                           int *num_trips)
 {}
+static inline struct tegra_system_edp_entry
+               *tegra_get_system_edp_entries(int *size) { return NULL; }
 #endif
 
 #ifdef CONFIG_ARCH_TEGRA_2x_SOC