summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2014-06-18 15:02:24 -0700
committerHarshada Kale <hkale@nvidia.com>2014-06-26 09:30:06 -0700
commitd85f667af7ff4bcc3837be956cf7b8cf06bfe639 (patch)
tree8004d8cc50b1f4e1e76f49ccbf7981bd7c62c4a2 /arch/arm/mach-tegra
parent97c29c19e21523e08a92a376a81af33cd75244ea (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.c73
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;