summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorDaniel Solomon <daniels@nvidia.com>2012-09-03 19:09:43 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 12:39:24 -0700
commit8a348bb967adcd0af46cf16769452c09c1531577 (patch)
tree069558e7ac0fde03b7fceab8ce41a2ccc9b2fbf0 /arch
parent38edde50c301b545cab6c9cc6191404d6b68457b (diff)
arm: tegra: power: Update dynamic CPU EDP model
Update the model used to calculate max frequency for a given VDD_CPU EDP. Change-Id: Id220f25b58880c936f621f07faae414be42e8971 Signed-off-by: Daniel Solomon <daniels@nvidia.com> Reviewed-on: http://git-master/r/133051 (cherry picked from commit eca6edfc4220c5d0a004e9655926ea805c485152) Signed-off-by: Gaurav Batra <gbatra@nvidia.com> Reviewed-on: http://git-master/r/132941 Reviewed-by: Diwakar Tundlam <dtundlam@nvidia.com> Tested-by: Diwakar Tundlam <dtundlam@nvidia.com> Rebase-Id: Rc0a772f04ed867da313d2044f6bc6a26ae58cd57
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-tegra/edp.c396
1 files changed, 220 insertions, 176 deletions
diff --git a/arch/arm/mach-tegra/edp.c b/arch/arm/mach-tegra/edp.c
index b37c12fd7054..9d779e8b7660 100644
--- a/arch/arm/mach-tegra/edp.c
+++ b/arch/arm/mach-tegra/edp.c
@@ -32,8 +32,8 @@
#include "cpu-tegra.h"
#define FREQ_STEP 10000000
-#define A_TEMP_LUT_MAX 7
-#define A_VOLTAGE_LUT_MAX 49
+#define TEMP_LUT_MAX 68
+#define EDP_CALCULATED_LIMITS_SIZE TEMP_LUT_MAX
static struct tegra_edp_limits *edp_limits;
static int edp_limits_size;
@@ -328,142 +328,195 @@ static struct tegra_edp_limits edp_default_limits[] = {
/*
* Constants for EDP calculations
*/
-
-struct a_voltage_lut_t {
- unsigned int voltage;
- unsigned int a_voltage;
-};
-
-struct a_temp_lut_t {
- unsigned int temp;
- unsigned int a_temp;
+int temps_lut[TEMP_LUT_MAX] = {
+ 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
+ 90,
};
/* TODO: This struct will get large for 13 speedo IDs... relocate. */
struct edp_constants_lut_t {
int cpu_speedo_id;
-
- struct a_temp_lut_t a_temp_lut [A_TEMP_LUT_MAX];
- unsigned int a_temp_lut_size;
-
- struct a_voltage_lut_t a_voltage_lut [A_VOLTAGE_LUT_MAX];
- unsigned int a_voltage_lut_size;
-
- unsigned int a_cores_lut[NR_CPUS];
+ /* All constants are pre-multiplied by 1,000,000 */
+ int leakage_consts_ijk[64];
+ int leakage_consts_n[NR_CPUS];
+ int dyn_consts_n[NR_CPUS];
} edp_constants_lut[] = {
{
.cpu_speedo_id = -1,
- .a_temp_lut = {
- {23, 23270},
- {45, 37559},
- {60, 52056},
- {70, 64712},
- {75, 72150},
- {85, 89690},
- {90, 100000}
- },
- .a_temp_lut_size = 7,
- .a_voltage_lut = {
- {700, 321},
- {713, 336},
- {725, 352},
- {738, 369},
- {750, 386},
- {763, 405},
- {775, 423},
- {788, 444},
- {800, 464},
- {813, 487},
- {825, 509},
- {838, 534},
- {850, 558},
- {863, 585},
- {875, 612},
- {888, 642},
- {900, 671},
- {913, 704},
- {925, 736},
- {938, 772},
- {950, 807},
- {963, 847},
- {975, 885},
- {988, 929},
- {1000, 971},
- {1013, 1019},
- {1025, 1066},
- {1038, 1119},
- {1050, 1170},
- {1063, 1228},
- {1075, 1284},
- {1088, 1348},
- {1100, 1410},
- {1113, 1480},
- {1125, 1548},
- {1138, 1625},
- {1150, 1699},
- {1163, 1784},
- {1175, 1865},
- {1188, 1958},
- {1200, 2048},
- {1213, 2150},
- {1225, 2248},
- {1238, 2360},
- {1250, 2468},
- {1263, 2591},
- {1275, 2709},
- {1288, 2844},
- {1300, 2974}
- },
- .a_voltage_lut_size = 49,
- .a_cores_lut = {
- 3565,
- 5710,
- 7855,
- 10000
+ .leakage_consts_n = {
+ 641026,
+ 757576,
+ 878500,
+ 1000000
},
+ /* Constants order: C(i,j,k), i,j,k = {0,1,2,3}, with k
+ * being the least significant index and i being the most
+ * significant index */
+ .leakage_consts_ijk = {
+ 0,
+ -21481846,
+ 519650,
+ -3254,
+ 0,
+ 65678948,
+ -1572498,
+ 9850,
+ 0,
+ -65988168,
+ 1565063,
+ -9808,
+ 0,
+ 22109316,
+ -522158,
+ 3281,
+ 0,
+ 24840561,
+ -565618,
+ 5196,
+ 0,
+ -65603470,
+ 1592186,
+ -13823,
+ 0,
+ 56585242,
+ -1488977,
+ 12944,
+ 0,
+ -14740016,
+ 470284,
+ -3670,
+ 0,
+ -7050232,
+ 244771,
+ -1779,
+ 0,
+ 20985919,
+ -701848,
+ 5008,
+ 0,
+ -20478304,
+ 677782,
+ -4766,
+ 0,
+ 7093793,
+ -218579,
+ 1454,
+ 0,
+ 942881,
+ -29599,
+ 203,
+ 0,
+ -2750253,
+ 84116,
+ -569,
+ 0,
+ 2643026,
+ -80080,
+ 536,
+ 0,
+ -868855,
+ 25062,
+ -161,
+ }, /* consts_ijk */
+ .dyn_consts_n = {
+ 1560207,
+ 2378136,
+ 3196066,
+ 4013995
+ }
}
};
struct freq_voltage_lut_t {
unsigned int freq;
- struct a_voltage_lut_t *a_voltage_lut;
+ int voltage_mV;
} *freq_voltage_lut = 0;
unsigned int freq_voltage_lut_size;
+static s64 edp_pwr(s64 val, int pwr)
+{
+ int i;
+ s64 retval = 1;
+
+ for (i = 0; i < pwr; i++)
+ retval *= val;
+
+ return retval;
+}
+
/*
* Find the maximum frequency that results in dynamic and leakage current that
* is less than the regulator current limit.
*/
-unsigned int edp_calculate_maxf(unsigned int a_temp,
- unsigned int a_cores,
- unsigned int n_cores,
- unsigned int iddq_mA)
+unsigned int edp_calculate_maxf(struct edp_constants_lut_t *edp_constants,
+ int temp_C,
+ int iddq_mA,
+ int n_cores_idx)
{
- unsigned int voltage_mV, a_voltage, leakage_mA, op_mA, freq_MHz;
+ unsigned int voltage_mV, freq_MHz;
unsigned int regulator_cur_effective = regulator_cur - edp_reg_override_mA;
- int i;
-
- for (i = freq_voltage_lut_size - 1; i >= 0; i--) {
- freq_MHz = freq_voltage_lut[i].freq / 1000000;
- voltage_mV = freq_voltage_lut[i].a_voltage_lut->voltage;
- a_voltage = freq_voltage_lut[i].a_voltage_lut->a_voltage;
-
- leakage_mA = a_temp * a_voltage;
- /* a_voltage was pre-multiplied by 1000 */
- leakage_mA /= 1000;
- leakage_mA *= a_cores;
- /* a_temp was pre-multiplied by 100,000 */
- leakage_mA /= 100000;
- leakage_mA *= iddq_mA;
- /* a_cores was pre-multiplied by 10,000 */
- leakage_mA /= 10000;
-
- op_mA = 55 * voltage_mV * freq_MHz * n_cores;
- /* 55 was pre-multiplied by 100000 */
- op_mA /= 100000;
-
- /* TODO: Apply additional margin to total current calculated? */
- if ((leakage_mA + op_mA) <= regulator_cur_effective)
+ int f_v_pair, i, j, k, leakage_const_n, dyn_const_n;
+ int *leakage_consts_ijk;
+ s64 leakage_mA, dyn_mA, leakage_calc_step;
+ /* WAR for GCC 4.4.3 bug 43949 - compiler throws an array bounds warning
+ * if these arrays are dereferenced in the calling function*/
+ leakage_consts_ijk = edp_constants->leakage_consts_ijk;
+ dyn_const_n = edp_constants->dyn_consts_n[n_cores_idx];
+ leakage_const_n = edp_constants->leakage_consts_n[n_cores_idx];
+
+ for (f_v_pair = freq_voltage_lut_size - 1; f_v_pair >= 0; f_v_pair--) {
+ freq_MHz = freq_voltage_lut[f_v_pair].freq / 1000000;
+ voltage_mV = freq_voltage_lut[f_v_pair].voltage_mV;
+
+ /*
+ * Calculate leakage current
+ */
+ leakage_mA = 0;
+ for (i = 0; i <= 3; i++)
+ for (j = 0; j <= 3; j++)
+ for (k = 0; k <= 3; k++) {
+ leakage_calc_step =
+ leakage_consts_ijk[i*16 + j*4 + k]
+ * edp_pwr(iddq_mA, i);
+ /* Convert (mA)^i to (A)^i */
+ leakage_calc_step =
+ div64_s64(leakage_calc_step,
+ edp_pwr(1000, i));
+ leakage_calc_step *=
+ edp_pwr(voltage_mV, j);
+ /* Convert (mV)^i to (V)^i */
+ leakage_calc_step =
+ div64_s64(leakage_calc_step,
+ edp_pwr(1000, j));
+ leakage_calc_step *=
+ edp_pwr(temp_C, k);
+ /* const_ijk was X 1,000,000 */
+ leakage_calc_step =
+ div64_s64(leakage_calc_step,
+ 1000000);
+ leakage_mA += leakage_calc_step;
+ }
+ leakage_mA *= leakage_const_n;
+ /* leakage_const_n was pre-multiplied by 1,000,000 */
+ leakage_mA = div64_s64(leakage_mA, 1000000);
+
+ /*
+ * Calculate dynamic current
+ */
+ dyn_mA = voltage_mV * freq_MHz;
+ /* Convert mV to V */
+ dyn_mA = div64_s64(dyn_mA, 1000);
+ dyn_mA *= dyn_const_n;
+ /* dyn_const_n was pre-multiplied by 1,000,000 */
+ dyn_mA = div64_s64(dyn_mA, 1000000);
+
+ if ((leakage_mA + dyn_mA) <= regulator_cur_effective)
return freq_MHz * 1000;
}
return 0;
@@ -472,12 +525,8 @@ unsigned int edp_calculate_maxf(unsigned int a_temp,
static int edp_relate_freq_voltage(struct clk *clk_cpu_g,
unsigned int cpu_speedo_idx)
{
- unsigned int i, j, freq, a_voltage_lut_size;
+ unsigned int i, j, freq;
int voltage_mV;
- struct a_voltage_lut_t *a_voltage_lut;
-
- a_voltage_lut = edp_constants_lut[cpu_speedo_idx].a_voltage_lut;
- a_voltage_lut_size = edp_constants_lut[cpu_speedo_idx].a_voltage_lut_size;
for (i = 0, j = 0, freq = clk_get_min_rate(clk_cpu_g);
i < freq_voltage_lut_size;
@@ -486,26 +535,14 @@ static int edp_relate_freq_voltage(struct clk *clk_cpu_g,
/* Predict voltages */
voltage_mV = tegra_dvfs_predict_millivolts(clk_cpu_g, freq);
if (voltage_mV < 0) {
- pr_err("%s: could not predict voltage for freqency %u, err %d\n",
- __func__, freq, voltage_mV);
- return -EINVAL;
- }
-
- /* Look up voltage constant */
- for (;j < a_voltage_lut_size; j++) {
- if (voltage_mV <= a_voltage_lut[j].voltage) {
- break;
- }
- }
- if (j == a_voltage_lut_size) {
- pr_err("%s: couldn't find voltage const for predicted voltage %d\n",
- __func__, voltage_mV);
+ pr_err("%s: couldn't predict voltage for freq %u, err %d",
+ __func__, freq, voltage_mV);
return -EINVAL;
}
/* Cache frequency / voltage / voltage constant relationship */
freq_voltage_lut[i].freq = freq;
- freq_voltage_lut[i].a_voltage_lut = &a_voltage_lut[j];
+ freq_voltage_lut[i].voltage_mV = voltage_mV;
}
return 0;
@@ -521,18 +558,19 @@ int edp_find_speedo_idx(int cpu_speedo_id, unsigned int *cpu_speedo_idx)
return 0;
}
- pr_err("%s: couldn't find cpu speedo id in freq/voltage LUT\n", __func__);
+ pr_err("%s: couldn't find cpu speedo id %d in freq/voltage LUT\n",
+ __func__, cpu_speedo_id);
return -EINVAL;
}
-
int init_cpu_edp_limits_calculated(int cpu_speedo_id)
{
- unsigned int temp_idx, n_cores_idx, cpu_speedo_idx;
+ unsigned int temp_idx, n_cores_idx;
unsigned int cpu_g_minf, cpu_g_maxf;
- unsigned int *a_cores_lut, a_temp_lut_size, iddq_mA;
- struct a_temp_lut_t *a_temp_lut;
+ unsigned int iddq_mA;
+ unsigned int cpu_speedo_idx;
struct tegra_edp_limits *edp_calculated_limits;
- int ret, edp_calculated_limits_size;
+ struct edp_constants_lut_t *edp_constants;
+ int ret;
struct clk *clk_cpu_g = tegra_get_clock_by_name("cpu_g");
/* Determine all inputs to EDP formula */
@@ -542,24 +580,21 @@ int init_cpu_edp_limits_calculated(int cpu_speedo_id)
if (ret)
return ret;
- a_temp_lut = edp_constants_lut[cpu_speedo_idx].a_temp_lut;
- a_temp_lut_size = edp_constants_lut[cpu_speedo_idx].a_temp_lut_size;
-
- a_cores_lut = edp_constants_lut[cpu_speedo_idx].a_cores_lut;
+ edp_constants = &edp_constants_lut[cpu_speedo_idx];
edp_calculated_limits =
- kmalloc(sizeof(struct tegra_edp_limits) * a_temp_lut_size, GFP_KERNEL);
+ kmalloc(sizeof(struct tegra_edp_limits) * EDP_CALCULATED_LIMITS_SIZE,
+ GFP_KERNEL);
BUG_ON(!edp_calculated_limits);
- edp_calculated_limits_size = a_temp_lut_size;
cpu_g_minf = clk_get_min_rate(clk_cpu_g);
cpu_g_maxf = clk_get_max_rate(clk_cpu_g);
freq_voltage_lut_size = (cpu_g_maxf - cpu_g_minf) / FREQ_STEP + 1;
freq_voltage_lut =
- kmalloc(sizeof(struct freq_voltage_lut_t) * freq_voltage_lut_size,
- GFP_KERNEL);
+ kmalloc(sizeof(struct freq_voltage_lut_t)*freq_voltage_lut_size,
+ GFP_KERNEL);
if (!freq_voltage_lut) {
- pr_err("%s: failed to allocate mem for freq/voltage LUT\n", __func__);
+ pr_err("%s: failed alloc mem for freq/voltage LUT\n", __func__);
return -ENOMEM;
}
@@ -570,15 +605,16 @@ int init_cpu_edp_limits_calculated(int cpu_speedo_id)
}
/* Calculate EDP table */
- for (temp_idx = 0; temp_idx < a_temp_lut_size; temp_idx++) {
- edp_calculated_limits[temp_idx].temperature = a_temp_lut[temp_idx].temp;
+ for (temp_idx = 0; temp_idx < ARRAY_SIZE(temps_lut); temp_idx++) {
+ edp_calculated_limits[temp_idx].temperature = temps_lut[temp_idx];
for (n_cores_idx = 0; n_cores_idx < NR_CPUS; n_cores_idx++)
- edp_calculated_limits[temp_idx].freq_limits[n_cores_idx] =
- edp_calculate_maxf(a_temp_lut[temp_idx].a_temp,
- a_cores_lut[n_cores_idx],
- n_cores_idx + 1,
- iddq_mA);
+ edp_calculated_limits[temp_idx].
+ freq_limits[n_cores_idx] =
+ edp_calculate_maxf(edp_constants,
+ temps_lut[temp_idx],
+ iddq_mA,
+ n_cores_idx);
}
/*
@@ -587,19 +623,19 @@ int init_cpu_edp_limits_calculated(int cpu_speedo_id)
*/
if (edp_limits != edp_default_limits) {
memcpy(edp_limits, edp_calculated_limits,
- sizeof(struct tegra_edp_limits) * edp_calculated_limits_size);
+ sizeof(struct tegra_edp_limits) * EDP_CALCULATED_LIMITS_SIZE);
kfree(edp_calculated_limits);
}
else {
edp_limits = edp_calculated_limits;
- edp_limits_size = edp_calculated_limits_size;
+ edp_limits_size = EDP_CALCULATED_LIMITS_SIZE;
}
kfree(freq_voltage_lut);
return 0;
}
-int init_cpu_edp_limits_lookup(int cpu_speedo_id)
+int __init init_cpu_edp_limits_lookup(int cpu_speedo_id)
{
int i, j;
struct tegra_edp_limits *e;
@@ -630,10 +666,10 @@ int init_cpu_edp_limits_lookup(int cpu_speedo_id)
for (j = 0; j < edp_limits_size; j++) {
e[j].temperature = (int)t[i+j].temperature;
- e[j].freq_limits[0] = (unsigned int)t[i+j].freq_limits[0] * 10000;
- e[j].freq_limits[1] = (unsigned int)t[i+j].freq_limits[1] * 10000;
- e[j].freq_limits[2] = (unsigned int)t[i+j].freq_limits[2] * 10000;
- e[j].freq_limits[3] = (unsigned int)t[i+j].freq_limits[3] * 10000;
+ e[j].freq_limits[0] = (unsigned int)t[i+j].freq_limits[0]*10000;
+ e[j].freq_limits[1] = (unsigned int)t[i+j].freq_limits[1]*10000;
+ e[j].freq_limits[2] = (unsigned int)t[i+j].freq_limits[2]*10000;
+ e[j].freq_limits[3] = (unsigned int)t[i+j].freq_limits[3]*10000;
}
if (edp_limits != edp_default_limits)
@@ -650,6 +686,7 @@ int init_cpu_edp_limits_lookup(int cpu_speedo_id)
void __init tegra_init_cpu_edp_limits(unsigned int regulator_mA)
{
int cpu_speedo_id = tegra_cpu_speedo_id();
+
if (!regulator_mA) {
edp_limits = edp_default_limits;
edp_limits_size = ARRAY_SIZE(edp_default_limits);
@@ -657,10 +694,10 @@ void __init tegra_init_cpu_edp_limits(unsigned int regulator_mA)
}
regulator_cur = regulator_mA;
- if (!init_cpu_edp_limits_lookup(cpu_speedo_id))
+ if (init_cpu_edp_limits_lookup(cpu_speedo_id) == 0)
return;
- if (!init_cpu_edp_limits_calculated(cpu_speedo_id))
+ if (init_cpu_edp_limits_calculated(cpu_speedo_id) == 0)
return;
edp_limits = edp_default_limits;
@@ -774,9 +811,11 @@ static int edp_debugfs_show(struct seq_file *s, void *data)
{
int i;
- seq_printf(s, "-- CPU %sEDP table (%umA) --\n",
+ seq_printf(s, "-- VDD_CPU %sEDP table (%umA) --\n",
edp_limits == edp_default_limits ? "default " : "",
regulator_cur);
+ seq_printf(s, "%6s %10s %10s %10s %10s\n",
+ " Temp.", "1-core", "2-cores", "3-cores", "4-cores");
for (i = 0; i < edp_limits_size; i++) {
seq_printf(s, "%4dC: %10u %10u %10u %10u\n",
edp_limits[i].temperature,
@@ -800,9 +839,8 @@ static int edp_debugfs_show(struct seq_file *s, void *data)
static int edp_reg_override_show(struct seq_file *s, void *data)
{
- seq_printf(s,
- "Regulator limit override: %u mA. Effective regulator limit: %u mA\n",
- edp_reg_override_mA, regulator_cur - edp_reg_override_mA);
+ seq_printf(s, "Regulator limit override: %u mA. Effective regulator limit: %u mA\n",
+ edp_reg_override_mA, regulator_cur - edp_reg_override_mA);
return 0;
}
@@ -811,6 +849,7 @@ static int edp_reg_override_write(struct file *file,
{
char buf[32], *end;
unsigned int edp_reg_override_mA_temp;
+ unsigned int edp_reg_override_mA_prev = edp_reg_override_mA;
int cpu_speedo_id;
if (sizeof(buf) <= count)
@@ -833,11 +872,16 @@ static int edp_reg_override_write(struct file *file,
edp_reg_override_mA = edp_reg_override_mA_temp;
cpu_speedo_id = tegra_cpu_speedo_id();
- if(init_cpu_edp_limits_calculated(cpu_speedo_id))
+ if(init_cpu_edp_limits_calculated(cpu_speedo_id)) {
+ /* Revert to previous override value if new value fails */
+ edp_reg_override_mA = edp_reg_override_mA_prev;
goto override_err;
+ }
- if (tegra_cpu_set_speed_cap(NULL))
- goto override_err;
+ if (tegra_cpu_set_speed_cap(NULL)) {
+ pr_err("Failed to apply CPU freq cap using new VDD_CPU EDP table.\n");
+ goto override_out;
+ }
pr_info("Reinitialized VDD_CPU EDP table with regulator current limit"
" %u mA\n", regulator_cur - edp_reg_override_mA);
@@ -845,9 +889,9 @@ static int edp_reg_override_write(struct file *file,
return count;
override_err:
- pr_err("Failed to reinitialized VDD_CPU EDP table with override \"%s\"\n"
- ,buf);
-
+ pr_err("Failed to reinitialized VDD_CPU EDP table with override \"%s\"",
+ buf);
+override_out:
return -EINVAL;
}