#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, };
.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,
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;
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;
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
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;
}
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 */
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;
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)
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;