diff options
author | Alex Frid <afrid@nvidia.com> | 2014-06-18 15:02:24 -0700 |
---|---|---|
committer | Harshada Kale <hkale@nvidia.com> | 2014-06-26 09:30:06 -0700 |
commit | d85f667af7ff4bcc3837be956cf7b8cf06bfe639 (patch) | |
tree | 8004d8cc50b1f4e1e76f49ccbf7981bd7c62c4a2 /arch/arm/mach-tegra | |
parent | 97c29c19e21523e08a92a376a81af33cd75244ea (diff) |
ARM: tegra13: dvfs: Add GPU SiMon offsets
Added GPU Vmin -20mV offset for high SiMon grade on Tegra13 platforms.
Constructed the respective GPU DVFS table with offsets applied, and
SiMon notifier to switch between tables w/wo offset. Since no SiMon
grading is available only original DVFS table with no offset is used
for now.
Bug 1511506
Change-Id: I959ed2142e478b9693a5bc425ef2165b43210bab
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: http://git-master/r/425035
Reviewed-by: Sai Gurrappadi <sgurrappadi@nvidia.com>
Tested-by: Sai Gurrappadi <sgurrappadi@nvidia.com>
Reviewed-by: Thomas Cherry <tcherry@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r-- | arch/arm/mach-tegra/tegra13_dvfs.c | 73 |
1 files changed, 71 insertions, 2 deletions
diff --git a/arch/arm/mach-tegra/tegra13_dvfs.c b/arch/arm/mach-tegra/tegra13_dvfs.c index cb2ca33c678b..8fff7b633f60 100644 --- a/arch/arm/mach-tegra/tegra13_dvfs.c +++ b/arch/arm/mach-tegra/tegra13_dvfs.c @@ -44,6 +44,7 @@ static bool tegra_dvfs_gpu_disabled; #define VDD_SAFE_STEP 100 static int cpu_vmin_offsets[] = { 0, -20, }; +static int gpu_vmin_offsets[] = { 0, -20, }; static int vdd_core_vmin_trips_table[MAX_THERMAL_LIMITS] = { 20, }; static int vdd_core_therm_floors_table[MAX_THERMAL_LIMITS] = { 950, }; @@ -116,6 +117,7 @@ static struct dvfs_rail tegra13_dvfs_rail_vdd_gpu = { .version = "p4_v10", .max_millivolts = 1350, .min_millivolts = 650, + .simon_domain = TEGRA_SIMON_DOMAIN_GPU, .step = VDD_SAFE_STEP, .step_up = 1350, .in_band_pm = true, @@ -501,12 +503,15 @@ static struct gpu_cvb_dvfs gpu_cvb_dvfs_table[] = { static int gpu_vmin[MAX_THERMAL_RANGES]; static int gpu_peak_millivolts[MAX_DVFS_FREQS]; static int gpu_millivolts[MAX_THERMAL_RANGES][MAX_DVFS_FREQS]; +static int gpu_millivolts_offs[MAX_THERMAL_RANGES][MAX_DVFS_FREQS]; static struct dvfs gpu_dvfs = { .clk_name = "gbus", .auto_dvfs = true, .dvfs_rail = &tegra13_dvfs_rail_vdd_gpu, }; +static struct notifier_block gpu_simon_grade_nb; + int tegra_dvfs_disable_core_set(const char *arg, const struct kernel_param *kp) { int ret; @@ -936,7 +941,7 @@ static int __init set_cpu_dvfs_data(unsigned long max_freq, static int __init set_gpu_dvfs_data(unsigned long max_freq, struct gpu_cvb_dvfs *d, struct dvfs *gpu_dvfs, int *max_freq_index) { - int i, j, thermal_ranges, mv; + int i, j, thermal_ranges, simon_offs, mv; struct cvb_dvfs_table *table = NULL; int speedo = tegra_gpu_speedo_value(); struct dvfs_rail *rail = &tegra13_dvfs_rail_vdd_gpu; @@ -944,6 +949,11 @@ static int __init set_gpu_dvfs_data(unsigned long max_freq, d->max_mv = round_voltage(d->max_mv, align, false); + /* Init gpu Vmin SiMon offsets (Tegra13 has exactly 2 offsests) */ + BUILD_BUG_ON(ARRAY_SIZE(gpu_vmin_offsets) != 2); + tegra_dvfs_rail_init_simon_vmin_offsets(gpu_vmin_offsets, 2, rail); + simon_offs = rail->simon_vmin_offsets ? rail->simon_vmin_offsets[1] : 0; + /* * Init thermal trips, find number of thermal ranges; note that the * first trip-point is used for voltage calculations within the lowest @@ -977,6 +987,16 @@ static int __init set_gpu_dvfs_data(unsigned long max_freq, mvj, rail->min_millivolts); mvj = rail->min_millivolts; } + + /* check Vmin SiMon offset: ignore SiMon if it pushes too low */ + if (mvj + simon_offs < rail->min_millivolts) { + WARN(1, "tegra13_dvfs: gpu simon min %dmV below rail min %dmV\n", + mvj + simon_offs, rail->min_millivolts); + rail->simon_vmin_offsets = NULL; + rail->simon_vmin_offs_num = 0; + simon_offs = 0; + } + gpu_vmin[j] = mvj; } @@ -994,7 +1014,7 @@ static int __init set_gpu_dvfs_data(unsigned long max_freq, speedo, d->speedo_scale, &table->cvb_pll_param); for (j = 0; j < thermal_ranges; j++) { - int mvj = mv; + int mvj_offs, mvj = mv; int t = rail->vts_cdev->trip_temperatures[j]; /* get thermal offset for this trip-point */ @@ -1003,6 +1023,7 @@ static int __init set_gpu_dvfs_data(unsigned long max_freq, mvj = round_cvb_voltage(mvj, d->voltage_scale, align); /* clip to minimum, abort if above maximum */ + mvj_offs = max(mvj, gpu_vmin[j] + simon_offs); mvj = max(mvj, gpu_vmin[j]); if (mvj > d->max_mv) break; @@ -1012,6 +1033,10 @@ static int __init set_gpu_dvfs_data(unsigned long max_freq, gpu_millivolts[j][i] = mvj; if (j && (gpu_millivolts[j-1][i] < mvj)) gpu_millivolts[j-1][i] = mvj; + + gpu_millivolts_offs[j][i] = mvj_offs; + if (j && (gpu_millivolts_offs[j-1][i] < mvj_offs)) + gpu_millivolts_offs[j-1][i] = mvj_offs; } /* Make sure all voltages for this frequency are below max */ if (j < thermal_ranges) @@ -1052,6 +1077,50 @@ static int __init set_gpu_dvfs_data(unsigned long max_freq, return 0; } +static int gpu_simon_grade_notify_cb(struct notifier_block *nb, + unsigned long grade, void *v) +{ + struct dvfs_rail *rail = &tegra13_dvfs_rail_vdd_gpu; + int curr_domain = (int)((long)v); + int ret; + + if (curr_domain != rail->simon_domain) + return NOTIFY_DONE; + + /* Only 2 grades are supported; both voltage tables must be valid */ + ret = tegra_dvfs_replace_voltage_table(&gpu_dvfs, + grade ? &gpu_millivolts_offs[0][0] : &gpu_millivolts[0][0]); + + if (!WARN_ON(ret == -EINVAL)) + pr_info("tegra_dvfs: set %s simon grade %lu\n", + rail->reg_id, grade); + + return NOTIFY_OK; +}; + +static int __init tegra13_register_gpu_simon_notifier(void) +{ + int ret; + struct dvfs_rail *rail = &tegra13_dvfs_rail_vdd_gpu; + + /* Stay at default if no simon offsets or thermal dvfs is broken */ + if (!gpu_dvfs.therm_dvfs || !rail->simon_vmin_offsets) + return 0; + + gpu_simon_grade_nb.notifier_call = gpu_simon_grade_notify_cb; + + ret = tegra_register_simon_notifier(&gpu_simon_grade_nb); + if (ret) { + pr_err("tegra13_dvfs: failed to register %s simon notifier\n", + rail->reg_id); + return ret; + } + + pr_info("tegra dvfs: registered %s simon notifier\n", rail->reg_id); + return 0; +} +late_initcall(tegra13_register_gpu_simon_notifier); + static int __init get_core_nominal_mv_index(int speedo_id) { int i; |