diff options
author | Diwakar Tundlam <dtundlam@nvidia.com> | 2013-12-12 17:53:55 -0800 |
---|---|---|
committer | Diwakar Tundlam <dtundlam@nvidia.com> | 2013-12-13 17:15:13 -0800 |
commit | 69b660ea1c22e7d97b3b7634392eb8b91bdb2484 (patch) | |
tree | 2c1a5862673cbb307da4fbd955c8bab38f1cb593 /arch/arm/mach-tegra/edp.c | |
parent | 2267d376673dd077c51d2e30146053a0fef396d6 (diff) |
arm: tegra: edp: Add GPU EDP override debugfs
Added ability to override VDD_GPU EDP limit just as for CPU mainly for
SQA testing. Other minor change and typo fixes
Bug 1411163
Bug 1307919
Change-Id: I603592ae1a0d4e0db31c70075d6ce20b99bd117a
Signed-off-by: Diwakar Tundlam <dtundlam@nvidia.com>
Reviewed-on: http://git-master/r/345136
Diffstat (limited to 'arch/arm/mach-tegra/edp.c')
-rw-r--r-- | arch/arm/mach-tegra/edp.c | 310 |
1 files changed, 211 insertions, 99 deletions
diff --git a/arch/arm/mach-tegra/edp.c b/arch/arm/mach-tegra/edp.c index bbf87ebf4a17..ed386ee6701f 100644 --- a/arch/arm/mach-tegra/edp.c +++ b/arch/arm/mach-tegra/edp.c @@ -85,9 +85,9 @@ static struct tegra_edp_freq_voltage_table *freq_voltage_lut; static unsigned int freq_voltage_lut_size; #ifdef CONFIG_TEGRA_GPU_EDP -static struct tegra_edp_gpu_limits *edp_gpu_limits; -static int edp_gpu_limits_size; -static int edp_gpu_thermal_idx; +static struct tegra_edp_gpu_limits *gpu_edp_limits; +static int gpu_edp_limits_size; +static int gpu_edp_thermal_idx; static struct clk *gpu_cap_clk; static DEFINE_MUTEX(gpu_edp_lock); @@ -95,8 +95,10 @@ static struct tegra_edp_freq_voltage_table *freq_voltage_gpu_lut; static unsigned int freq_voltage_gpu_lut_size; static unsigned int gpu_regulator_cur; +/* Value to subtract from regulator current limit */ +static unsigned int gpu_edp_reg_override_mA = OVERRIDE_DEFAULT; -static struct tegra_edp_gpu_limits edp_gpu_default_limits[] = { +static struct tegra_edp_gpu_limits gpu_edp_default_limits[] = { {85, 350000}, }; @@ -669,8 +671,8 @@ struct tegra_system_edp_entry *tegra_get_system_edp_entries(int *size) void tegra_get_gpu_edp_limits(const struct tegra_edp_gpu_limits **limits, int *size) { - *limits = edp_gpu_limits; - *size = edp_gpu_limits_size; + *limits = gpu_edp_limits; + *size = gpu_edp_limits_size; } void tegra_platform_gpu_edp_init(struct thermal_trip_info *trips, @@ -709,7 +711,8 @@ static unsigned int edp_gpu_calculate_maxf( int temp_C, int iddq_mA) { unsigned int voltage_mV, freq_KHz = 0; - unsigned int cur_effective = gpu_regulator_cur; + unsigned int cur_effective = gpu_regulator_cur - + gpu_edp_reg_override_mA; int f, i, j, k; s64 leakage_mA, dyn_mA, leakage_calc_step; @@ -788,7 +791,7 @@ static int __init start_gpu_edp(void) cap_name); return -EINVAL; } - edp_gpu_thermal_idx = 0; + gpu_edp_thermal_idx = 0; return 0; } @@ -822,13 +825,12 @@ static int edp_gpu_relate_freq_voltage(struct clk *clk_gpu, static int init_gpu_edp_limits_calculated(void) { - unsigned int temp_idx; unsigned int gpu_minf, gpu_maxf; unsigned int limit; - struct tegra_edp_gpu_limits *edp_gpu_calculated_limits; + struct tegra_edp_gpu_limits *gpu_edp_calculated_limits; struct tegra_edp_gpu_limits *temp; struct tegra_edp_gpu_leakage_params *params; - int ret; + int i, ret; unsigned int gpu_iddq_mA; u32 tegra_chip_id; struct clk *gpu_clk = clk_get_parent(gpu_cap_clk); @@ -840,9 +842,9 @@ static int init_gpu_edp_limits_calculated(void) } else return -EINVAL; - edp_gpu_calculated_limits = kmalloc(sizeof(struct tegra_edp_gpu_limits) + gpu_edp_calculated_limits = kmalloc(sizeof(struct tegra_edp_gpu_limits) * ARRAY_SIZE(gpu_temperatures), GFP_KERNEL); - BUG_ON(!edp_gpu_calculated_limits); + BUG_ON(!gpu_edp_calculated_limits); gpu_minf = 0; gpu_maxf = clk_get_max_rate(gpu_clk); @@ -853,7 +855,7 @@ static int init_gpu_edp_limits_calculated(void) if (!freq_voltage_gpu_lut) { pr_err("%s: failed alloc mem for gpu freq/voltage LUT\n", __func__); - kfree(edp_gpu_calculated_limits); + kfree(gpu_edp_calculated_limits); return -ENOMEM; } @@ -861,40 +863,39 @@ static int init_gpu_edp_limits_calculated(void) freq_voltage_gpu_lut_size, freq_voltage_gpu_lut); if (ret) { - kfree(edp_gpu_calculated_limits); + kfree(gpu_edp_calculated_limits); kfree(freq_voltage_gpu_lut); return ret; } - for (temp_idx = 0; - temp_idx < ARRAY_SIZE(gpu_temperatures); temp_idx++) { - edp_gpu_calculated_limits[temp_idx].temperature = - gpu_temperatures[temp_idx]; - limit = edp_gpu_calculate_maxf(params, - gpu_temperatures[temp_idx], - gpu_iddq_mA); - if (limit == -EINVAL) { - kfree(edp_gpu_calculated_limits); - kfree(freq_voltage_gpu_lut); - return -EINVAL; - } + for (i = 0; i < ARRAY_SIZE(gpu_temperatures); i++) { + gpu_edp_calculated_limits[i].temperature = + gpu_temperatures[i]; + limit = edp_gpu_calculate_maxf(params, + gpu_temperatures[i], + gpu_iddq_mA); + if (limit == -EINVAL) { + kfree(gpu_edp_calculated_limits); + kfree(freq_voltage_gpu_lut); + return -EINVAL; + } - edp_gpu_calculated_limits[temp_idx].freq_limits = limit; + gpu_edp_calculated_limits[i].freq_limits = limit; } /* * If this is an EDP table update, need to overwrite old table. * The old table's address must remain valid. */ - if (edp_gpu_limits != edp_gpu_default_limits && - edp_gpu_limits != edp_gpu_calculated_limits) { - temp = edp_gpu_limits; - edp_gpu_limits = edp_gpu_calculated_limits; - edp_gpu_limits_size = ARRAY_SIZE(gpu_temperatures); + if (gpu_edp_limits != gpu_edp_default_limits && + gpu_edp_limits != gpu_edp_calculated_limits) { + temp = gpu_edp_limits; + gpu_edp_limits = gpu_edp_calculated_limits; + gpu_edp_limits_size = ARRAY_SIZE(gpu_temperatures); kfree(temp); } else { - edp_gpu_limits = edp_gpu_calculated_limits; - edp_gpu_limits_size = ARRAY_SIZE(gpu_temperatures); + gpu_edp_limits = gpu_edp_calculated_limits; + gpu_edp_limits_size = ARRAY_SIZE(gpu_temperatures); } kfree(freq_voltage_gpu_lut); @@ -940,10 +941,10 @@ void __init tegra_init_gpu_edp_limits(unsigned int regulator_mA) if (!regulator_mA) goto end; - gpu_regulator_cur = regulator_mA; + gpu_regulator_cur = regulator_mA + OVERRIDE_DEFAULT; if (start_gpu_edp()) { - WARN(1, "GPU EDP failed to set initialial limits"); + WARN(1, "GPU EDP failed to set initial limits"); return; } @@ -959,21 +960,21 @@ void __init tegra_init_gpu_edp_limits(unsigned int regulator_mA) } end: - edp_gpu_limits = edp_gpu_default_limits; - edp_gpu_limits_size = ARRAY_SIZE(edp_gpu_default_limits); + gpu_edp_limits = gpu_edp_default_limits; + gpu_edp_limits_size = ARRAY_SIZE(gpu_edp_default_limits); } static int gpu_edp_get_cdev_max_state(struct thermal_cooling_device *cdev, unsigned long *max_state) { - *max_state = edp_gpu_limits_size - 1; + *max_state = gpu_edp_limits_size - 1; return 0; } static int gpu_edp_get_cdev_cur_state(struct thermal_cooling_device *cdev, unsigned long *cur_state) { - *cur_state = edp_gpu_thermal_idx; + *cur_state = gpu_edp_thermal_idx; return 0; } @@ -981,10 +982,10 @@ static int gpu_edp_set_cdev_state(struct thermal_cooling_device *cdev, unsigned long cur_state) { unsigned long clk_rate; - BUG_ON(cur_state >= edp_gpu_limits_size); - clk_rate = edp_gpu_limits[cur_state].freq_limits; + BUG_ON(cur_state >= gpu_edp_limits_size); + clk_rate = gpu_edp_limits[cur_state].freq_limits; mutex_lock(&gpu_edp_lock); - edp_gpu_thermal_idx = cur_state; + gpu_edp_thermal_idx = cur_state; clk_set_rate(gpu_cap_clk, clk_rate * 1000); mutex_unlock(&gpu_edp_lock); return 0; @@ -1145,28 +1146,97 @@ static int edp_debugfs_show(struct seq_file *s, void *data) } #ifdef CONFIG_TEGRA_GPU_EDP +static int gpu_edp_limit_debugfs_show(struct seq_file *s, void *data) +{ + seq_printf(s, "%u\n", gpu_edp_limits[gpu_edp_thermal_idx].freq_limits); + return 0; +} + static inline void gpu_edp_show_table(struct seq_file *s) { int i; seq_printf(s, "%6s %10s\n", " Temp.", "Freq_limit"); - for (i = 0; i < edp_gpu_limits_size; i++) { - seq_printf(s, "%3dC: %10u \n", - edp_gpu_limits[i].temperature, - edp_gpu_limits[i].freq_limits); + for (i = 0; i < gpu_edp_limits_size; i++) { + seq_printf(s, "%3dC: %10u\n", + gpu_edp_limits[i].temperature, + gpu_edp_limits[i].freq_limits); } } - static int gpu_edp_debugfs_show(struct seq_file *s, void *data) { - seq_printf(s, "-- VDD_GPU EDP table --\n"); + seq_printf(s, "-- VDD_GPU %sEDP table (%umA = %umA - %umA) --\n", + gpu_edp_limits == gpu_edp_default_limits ? + "**default** " : "", + gpu_regulator_cur - gpu_edp_reg_override_mA, + gpu_regulator_cur, gpu_edp_reg_override_mA); gpu_edp_show_table(s); return 0; } + +static int gpu_edp_reg_override_show(struct seq_file *s, void *data) +{ + seq_printf(s, "Limit override: %u mA. Effective limit: %u mA\n", + gpu_edp_reg_override_mA, + gpu_regulator_cur - gpu_edp_reg_override_mA); + return 0; +} + +static int gpu_edp_reg_override_write(struct file *file, + const char __user *userbuf, size_t count, loff_t *ppos) +{ + char buf[32], *end; + unsigned int gpu_edp_reg_override_mA_temp; + unsigned int gpu_edp_reg_override_mA_prev = gpu_edp_reg_override_mA; + u32 tegra_chip_id; + + tegra_chip_id = tegra_get_chip_id(); + if (tegra_chip_id != TEGRA_CHIPID_TEGRA12) + goto override_err; + + if (sizeof(buf) <= count) + goto override_err; + + if (copy_from_user(buf, userbuf, count)) + goto override_err; + + /* terminate buffer and trim - white spaces may be appended + * at the end when invoked from shell command line */ + buf[count] ='\0'; + strim(buf); + + gpu_edp_reg_override_mA_temp = simple_strtoul(buf, &end, 10); + if (*end != '\0') + goto override_err; + + if (gpu_edp_reg_override_mA_temp >= gpu_regulator_cur) + goto override_err; + + if (gpu_edp_reg_override_mA == gpu_edp_reg_override_mA_temp) + return count; + + gpu_edp_reg_override_mA = gpu_edp_reg_override_mA_temp; + if (init_gpu_edp_limits_calculated()) { + /* Revert to previous override value if new value fails */ + gpu_edp_reg_override_mA = gpu_edp_reg_override_mA_prev; + goto override_err; + } + + gpu_edp_set_cdev_state(NULL, gpu_edp_thermal_idx); + pr_info("Reinitialized VDD_GPU EDP table with regulator current limit" + " %u mA\n", gpu_regulator_cur - gpu_edp_reg_override_mA); + + return count; + + override_err: + pr_err("FAILED: Override VDD_GPU EDP table with \"%s\"", + buf); + return -EINVAL; +} #endif static int edp_reg_override_show(struct seq_file *s, void *data) @@ -1251,6 +1321,16 @@ static int gpu_edp_debugfs_open(struct inode *inode, struct file *file) { return single_open(file, gpu_edp_debugfs_show, inode->i_private); } + +static int gpu_edp_limit_debugfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, gpu_edp_limit_debugfs_show, inode->i_private); +} + +static int gpu_edp_reg_override_open(struct inode *inode, struct file *file) +{ + return single_open(file, gpu_edp_reg_override_show, inode->i_private); +} #endif static int edp_limit_debugfs_open(struct inode *inode, struct file *file) @@ -1277,6 +1357,21 @@ static const struct file_operations gpu_edp_debugfs_fops = { .llseek = seq_lseek, .release = single_release, }; + +static const struct file_operations gpu_edp_limit_debugfs_fops = { + .open = gpu_edp_limit_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations gpu_edp_reg_override_debugfs_fops = { + .open = gpu_edp_reg_override_open, + .read = seq_read, + .write = gpu_edp_reg_override_write, + .llseek = seq_lseek, + .release = single_release, +}; #endif static const struct file_operations edp_limit_debugfs_fops = { @@ -1316,6 +1411,50 @@ static int reg_idle_cur_set(void *data, u64 val) DEFINE_SIMPLE_ATTRIBUTE(reg_idle_cur_debugfs_fops, reg_idle_cur_get, reg_idle_cur_set, "%llu\n"); +#ifdef CONFIG_TEGRA_GPU_EDP +static int __init tegra_gpu_edp_debugfs_init(struct dentry *edp_dir) +{ + struct dentry *d_edp; + struct dentry *d_edp_limit; + struct dentry *d_edp_reg_override; + struct dentry *vdd_gpu_dir; + + if (!tegra_platform_is_silicon()) + return -ENOSYS; + + vdd_gpu_dir = debugfs_create_dir("vdd_gpu", edp_dir); + if (!vdd_gpu_dir) + goto err_0; + + d_edp = debugfs_create_file("gpu_edp", S_IRUGO, vdd_gpu_dir, NULL, + &gpu_edp_debugfs_fops); + if (!d_edp) + goto err_1; + + d_edp_limit = debugfs_create_file("gpu_edp_limit", S_IRUGO, vdd_gpu_dir, + NULL, &gpu_edp_limit_debugfs_fops); + if (!d_edp_limit) + goto err_2; + + d_edp_reg_override = debugfs_create_file("gpu_edp_reg_override", + S_IRUGO | S_IWUSR, vdd_gpu_dir, NULL, + &gpu_edp_reg_override_debugfs_fops); + if (!d_edp_reg_override) + goto err_3; + + return 0; + +err_3: + debugfs_remove(d_edp_limit); +err_2: + debugfs_remove(d_edp); +err_1: + debugfs_remove(vdd_gpu_dir); +err_0: + return -ENOMEM; +} +#endif + #if defined(CONFIG_EDP_FRAMEWORK) || defined(CONFIG_SYSEDP_FRAMEWORK) static __init struct dentry *tegra_edp_debugfs_dir(void) { @@ -1339,86 +1478,59 @@ static int __init tegra_edp_debugfs_init(void) struct dentry *d_edp_reg_override; struct dentry *edp_dir; struct dentry *vdd_cpu_dir; -#ifdef CONFIG_TEGRA_GPU_EDP - struct dentry *gpu_edp; - struct dentry *vdd_gpu_dir; -#endif if (!tegra_platform_is_silicon()) return -ENOSYS; edp_dir = tegra_edp_debugfs_dir(); - if (!edp_dir) - goto edp_dir_err; + goto err_0; vdd_cpu_dir = debugfs_create_dir("vdd_cpu", edp_dir); - if (!vdd_cpu_dir) - goto vdd_cpu_dir_err; - -#ifdef CONFIG_TEGRA_GPU_EDP - vdd_gpu_dir = debugfs_create_dir("vdd_gpu", edp_dir); - - if (!vdd_gpu_dir) - goto vdd_gpu_dir_err; -#endif + goto err_0; d_edp = debugfs_create_file("edp", S_IRUGO, vdd_cpu_dir, NULL, - &edp_debugfs_fops); - + &edp_debugfs_fops); if (!d_edp) - goto edp_err; -#ifdef CONFIG_TEGRA_GPU_EDP - gpu_edp = debugfs_create_file("gpu_edp", S_IRUGO, vdd_gpu_dir, NULL, - &gpu_edp_debugfs_fops); - if (!gpu_edp) - goto gpu_edp_err; -#endif + goto err_1; d_edp_limit = debugfs_create_file("edp_limit", S_IRUGO, vdd_cpu_dir, - NULL, &edp_limit_debugfs_fops); - + NULL, &edp_limit_debugfs_fops); if (!d_edp_limit) - goto edp_limit_err; + goto err_2; d_edp_reg_override = debugfs_create_file("edp_reg_override", - S_IRUGO | S_IWUSR, vdd_cpu_dir, NULL, - &edp_reg_override_debugfs_fops); - + S_IRUGO | S_IWUSR, vdd_cpu_dir, NULL, + &edp_reg_override_debugfs_fops); if (!d_edp_reg_override) - goto edp_reg_override_err; + goto err_3; d_reg_idle_cur = debugfs_create_file("reg_idle_mA", - S_IRUGO | S_IWUSR, vdd_cpu_dir, NULL, - ®_idle_cur_debugfs_fops); + S_IRUGO | S_IWUSR, vdd_cpu_dir, NULL, + ®_idle_cur_debugfs_fops); if (!d_reg_idle_cur) - goto reg_idle_cur_err; + goto err_4; if (tegra_core_edp_debugfs_init(edp_dir)) return -ENOMEM; +#ifdef CONFIG_TEGRA_GPU_EDP + if (tegra_gpu_edp_debugfs_init(edp_dir)) + return -ENOMEM; +#endif + return 0; -reg_idle_cur_err: +err_4: debugfs_remove(d_edp_reg_override); -edp_reg_override_err: +err_3: debugfs_remove(d_edp_limit); -edp_limit_err: -#ifdef CONFIG_TEGRA_GPU_EDP - debugfs_remove(gpu_edp); -gpu_edp_err: -#endif +err_2: debugfs_remove(d_edp); -edp_err: -#ifdef CONFIG_TEGRA_GPU_EDP - debugfs_remove(vdd_gpu_dir); -vdd_gpu_dir_err: -#endif +err_1: debugfs_remove(vdd_cpu_dir); -vdd_cpu_dir_err: - debugfs_remove(edp_dir); -edp_dir_err: +err_0: return -ENOMEM; } |