diff options
| -rw-r--r-- | drivers/devfreq/governor_wmark_active.c | 45 | ||||
| -rw-r--r-- | drivers/video/tegra/host/host1x/host1x_actmon_t186.c | 56 | ||||
| -rw-r--r-- | drivers/video/tegra/host/host1x/hw_host1x5_actmon.h | 6 | ||||
| -rw-r--r-- | drivers/video/tegra/host/nvhost_acm.c | 25 | ||||
| -rw-r--r-- | drivers/video/tegra/host/nvhost_scale.c | 15 | ||||
| -rw-r--r-- | drivers/video/tegra/host/t186/actmon_regs.c | 22 | ||||
| -rw-r--r-- | drivers/video/tegra/host/t186/t186.c | 5 | ||||
| -rw-r--r-- | include/linux/nvhost.h | 8 |
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 | ||
| 51 | static unsigned long freqlist_up(struct wmark_gov_info *wmarkinfo, | 54 | static 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 | ||
| 279 | static 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 | |||
| 279 | static int devfreq_watermark_event_handler(struct devfreq *df, | 305 | static 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 | ||
| 184 | static 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 | |||
| 184 | static int host1x_actmon_init(struct host1x_actmon *actmon) | 199 | static 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) | |||
