summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/edp.c
diff options
context:
space:
mode:
authorDiwakar Tundlam <dtundlam@nvidia.com>2013-01-22 12:48:25 -0800
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 12:57:11 -0700
commite64e89719a5c55f6c6d333b3fe668dfa5b1cae6b (patch)
tree9984d18669558ea113ece982141cbd9af6d908c4 /arch/arm/mach-tegra/edp.c
parent8faeddc6c8b69e31654bc5307f728d60e3e4765e (diff)
ARM: tegra: power-edp table
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
Diffstat (limited to 'arch/arm/mach-tegra/edp.c')
-rw-r--r--arch/arm/mach-tegra/edp.c108
1 files changed, 91 insertions, 17 deletions
diff --git a/arch/arm/mach-tegra/edp.c b/arch/arm/mach-tegra/edp.c
index 26ea066c5f25..c76e7e84585d 100644
--- a/arch/arm/mach-tegra/edp.c
+++ b/arch/arm/mach-tegra/edp.c
@@ -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",