diff options
author | Diwakar Tundlam <dtundlam@nvidia.com> | 2013-01-22 12:48:25 -0800 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2013-09-14 12:57:11 -0700 |
commit | e64e89719a5c55f6c6d333b3fe668dfa5b1cae6b (patch) | |
tree | 9984d18669558ea113ece982141cbd9af6d908c4 /arch | |
parent | 8faeddc6c8b69e31654bc5307f728d60e3e4765e (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')
-rw-r--r-- | arch/arm/mach-tegra/edp.c | 108 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/mach/edp.h | 5 |
2 files changed, 95 insertions, 18 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", diff --git a/arch/arm/mach-tegra/include/mach/edp.h b/arch/arm/mach-tegra/include/mach/edp.h index 88500fab15e7..e2560a25a168 100644 --- a/arch/arm/mach-tegra/include/mach/edp.h +++ b/arch/arm/mach-tegra/include/mach/edp.h @@ -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 |