summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/devfreq/governor_wmark_active.c45
-rw-r--r--drivers/video/tegra/host/host1x/host1x_actmon_t186.c56
-rw-r--r--drivers/video/tegra/host/host1x/hw_host1x5_actmon.h6
-rw-r--r--drivers/video/tegra/host/nvhost_acm.c25
-rw-r--r--drivers/video/tegra/host/nvhost_scale.c15
-rw-r--r--drivers/video/tegra/host/t186/actmon_regs.c22
-rw-r--r--drivers/video/tegra/host/t186/t186.c5
-rw-r--r--include/linux/nvhost.h8
8 files changed, 166 insertions, 16 deletions
diff --git a/drivers/devfreq/governor_wmark_active.c b/drivers/devfreq/governor_wmark_active.c
index 4f6d41c7a..8e98c809d 100644
--- a/drivers/devfreq/governor_wmark_active.c
+++ b/drivers/devfreq/governor_wmark_active.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved. 2 * Copyright (c) 2014-2019, NVIDIA CORPORATION. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify it 4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License, 5 * under the terms and conditions of the GNU General Public License,
@@ -46,6 +46,9 @@ struct wmark_gov_info {
46 46
47 /* variable for keeping the average frequency request */ 47 /* variable for keeping the average frequency request */
48 unsigned long long average_target_freq; 48 unsigned long long average_target_freq;
49
50 /* devfreq notifier_block */
51 struct notifier_block nb;
49}; 52};
50 53
51static unsigned long freqlist_up(struct wmark_gov_info *wmarkinfo, 54static unsigned long freqlist_up(struct wmark_gov_info *wmarkinfo,
@@ -185,9 +188,6 @@ static int devfreq_watermark_target_freq(struct devfreq *df,
185 (wmarkinfo->p_smooth * wmarkinfo->average_target_freq + 188 (wmarkinfo->p_smooth * wmarkinfo->average_target_freq +
186 ideal_freq) / (wmarkinfo->p_smooth + 1); 189 ideal_freq) / (wmarkinfo->p_smooth + 1);
187 190
188 /* update watermarks to match the ideal frequency */
189 update_watermarks(df, dev_stat.current_frequency, ideal_freq);
190
191 /* do not scale too often */ 191 /* do not scale too often */
192 if (dt < wmarkinfo->p_block_window) 192 if (dt < wmarkinfo->p_block_window)
193 return 0; 193 return 0;
@@ -276,11 +276,38 @@ static int devfreq_watermark_start(struct devfreq *df)
276 return 0; 276 return 0;
277} 277}
278 278
279static int devfreq_watermark_notifier_call(struct notifier_block *nb,
280 unsigned long event, void *ptr)
281{
282 struct wmark_gov_info *data
283 = container_of(nb, struct wmark_gov_info, nb);
284 struct devfreq *df = (struct devfreq *)data->df;
285 unsigned long freq = 0;
286
287 switch (event) {
288 case DEVFREQ_PRECHANGE:
289 break;
290 case DEVFREQ_POSTCHANGE:
291 /* get device freq. */
292 df->profile->get_cur_freq(df->dev.parent, &freq);
293
294 /* update watermarks by current device freq. */
295 if (freq)
296 update_watermarks(df, freq, freq);
297 break;
298 default:
299 break;
300 }
301
302 return NOTIFY_DONE;
303}
304
279static int devfreq_watermark_event_handler(struct devfreq *df, 305static int devfreq_watermark_event_handler(struct devfreq *df,
280 unsigned int event, void *wmark_type) 306 unsigned int event, void *wmark_type)
281{ 307{
282 struct wmark_gov_info *wmarkinfo; 308 struct wmark_gov_info *wmarkinfo;
283 int ret = 0; 309 int ret = 0;
310 struct notifier_block *nb;
284 311
285 switch (event) { 312 switch (event) {
286 case DEVFREQ_GOV_START: 313 case DEVFREQ_GOV_START:
@@ -300,10 +327,20 @@ static int devfreq_watermark_event_handler(struct devfreq *df,
300 327
301 update_watermarks(df, dev_stat.current_frequency, 328 update_watermarks(df, dev_stat.current_frequency,
302 dev_stat.current_frequency); 329 dev_stat.current_frequency);
330
331 nb = &wmarkinfo->nb;
332 nb->notifier_call = devfreq_watermark_notifier_call;
333 ret = devm_devfreq_register_notifier(df->dev.parent,
334 df, nb, DEVFREQ_TRANSITION_NOTIFIER);
303 break; 335 break;
304 } 336 }
305 case DEVFREQ_GOV_STOP: 337 case DEVFREQ_GOV_STOP:
306 devfreq_watermark_debug_stop(df); 338 devfreq_watermark_debug_stop(df);
339
340 wmarkinfo = df->data;
341 nb = &wmarkinfo->nb;
342 devm_devfreq_unregister_notifier(df->dev.parent,
343 df, nb, DEVFREQ_TRANSITION_NOTIFIER);
307 break; 344 break;
308 case DEVFREQ_GOV_SUSPEND: 345 case DEVFREQ_GOV_SUSPEND:
309 devfreq_monitor_suspend(df); 346 devfreq_monitor_suspend(df);
diff --git a/drivers/video/tegra/host/host1x/host1x_actmon_t186.c b/drivers/video/tegra/host/host1x/host1x_actmon_t186.c
index 656e56469..8d2a3a52d 100644
--- a/drivers/video/tegra/host/host1x/host1x_actmon_t186.c
+++ b/drivers/video/tegra/host/host1x/host1x_actmon_t186.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * Tegra Graphics Host Actmon support for T186 2 * Tegra Graphics Host Actmon support for T186
3 * 3 *
4 * Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved. 4 * Copyright (c) 2015-2019, NVIDIA CORPORATION. All rights reserved.
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify it 6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License, 7 * under the terms and conditions of the GNU General Public License,
@@ -181,6 +181,21 @@ static void __iomem *host1x_actmon_get_regs(struct host1x_actmon *actmon)
181 return NULL; 181 return NULL;
182} 182}
183 183
184static unsigned long get_module_freq(struct host1x_actmon *actmon)
185{
186 unsigned long freq = 0;
187
188 struct platform_device *pdev = actmon->pdev;
189 struct nvhost_device_data *engine_pdata = platform_get_drvdata(pdev);
190 struct devfreq *df = engine_pdata->power_manager;
191 struct nvhost_device_data *pdata = dev_get_drvdata(df->dev.parent);
192 struct nvhost_device_profile *profile = pdata->power_profile;
193
194 freq = clk_get_rate(profile->clk);
195
196 return freq;
197}
198
184static int host1x_actmon_init(struct host1x_actmon *actmon) 199static int host1x_actmon_init(struct host1x_actmon *actmon)
185{ 200{
186 struct platform_device *host_pdev = actmon->host->dev; 201 struct platform_device *host_pdev = actmon->host->dev;
@@ -226,6 +241,10 @@ static int host1x_actmon_init(struct host1x_actmon *actmon)
226 val |= actmon_local_ctrl_enb_cumulative_f(1); 241 val |= actmon_local_ctrl_enb_cumulative_f(1);
227 actmon_writel(actmon, val, actmon_local_ctrl_r()); 242 actmon_writel(actmon, val, actmon_local_ctrl_r());
228 243
244 /* Set COUNT_WEIGHT @actmon */
245 actmon_writel(actmon, engine_pdata->actmon_weight_count,
246 actmon_local_count_weight_r());
247
229 /* Enable global interrupt */ 248 /* Enable global interrupt */
230 if (engine_pdata->actmon_irq) 249 if (engine_pdata->actmon_irq)
231 actmon_writel(actmon, 0x1, actmon_glb_intr_en_r()); 250 actmon_writel(actmon, 0x1, actmon_glb_intr_en_r());
@@ -297,6 +316,8 @@ static int host1x_actmon_avg_norm(struct host1x_actmon *actmon, u32 *avg)
297{ 316{
298 long val; 317 long val;
299 int err; 318 int err;
319 unsigned long freq = 0;
320 u32 dev_cycle_per_sample = 0;
300 321
301 if (!(actmon->init == ACTMON_READY && actmon->clks_per_sample > 0 && 322 if (!(actmon->init == ACTMON_READY && actmon->clks_per_sample > 0 &&
302 actmon->divider)) { 323 actmon->divider)) {
@@ -313,7 +334,11 @@ static int host1x_actmon_avg_norm(struct host1x_actmon *actmon, u32 *avg)
313 val = actmon_readl(actmon, actmon_local_avg_count_r()); 334 val = actmon_readl(actmon, actmon_local_avg_count_r());
314 nvhost_module_idle(actmon->host->dev); 335 nvhost_module_idle(actmon->host->dev);
315 336
316 *avg = (val * 1000) / (actmon->clks_per_sample * actmon->divider); 337 freq = get_module_freq(actmon);
338 dev_cycle_per_sample = ((freq / 1000) * actmon->usecs_per_sample)
339 / 1000;
340
341 *avg = (val * 1000) / dev_cycle_per_sample;
317 342
318 return 0; 343 return 0;
319} 344}
@@ -366,13 +391,20 @@ static int host1x_actmon_count_norm(struct host1x_actmon *actmon, u32 *avg)