Blame view
drivers/devfreq/tegra30-devfreq.c
19 KB
9952f6918
|
1 |
// SPDX-License-Identifier: GPL-2.0-only |
6234f3801
|
2 3 4 5 6 |
/* * A devfreq driver for NVIDIA Tegra SoCs * * Copyright (c) 2014 NVIDIA CORPORATION. All rights reserved. * Copyright (C) 2014 Google, Inc |
6234f3801
|
7 8 9 10 11 12 13 14 |
*/ #include <linux/clk.h> #include <linux/cpufreq.h> #include <linux/devfreq.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/module.h> |
ac3167257
|
15 |
#include <linux/mod_devicetable.h> |
6234f3801
|
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
#include <linux/platform_device.h> #include <linux/pm_opp.h> #include <linux/reset.h> #include "governor.h" #define ACTMON_GLB_STATUS 0x0 #define ACTMON_GLB_PERIOD_CTRL 0x4 #define ACTMON_DEV_CTRL 0x0 #define ACTMON_DEV_CTRL_K_VAL_SHIFT 10 #define ACTMON_DEV_CTRL_ENB_PERIODIC BIT(18) #define ACTMON_DEV_CTRL_AVG_BELOW_WMARK_EN BIT(20) #define ACTMON_DEV_CTRL_AVG_ABOVE_WMARK_EN BIT(21) #define ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_NUM_SHIFT 23 #define ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_NUM_SHIFT 26 #define ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN BIT(29) #define ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN BIT(30) #define ACTMON_DEV_CTRL_ENB BIT(31) #define ACTMON_DEV_UPPER_WMARK 0x4 #define ACTMON_DEV_LOWER_WMARK 0x8 #define ACTMON_DEV_INIT_AVG 0xc #define ACTMON_DEV_AVG_UPPER_WMARK 0x10 #define ACTMON_DEV_AVG_LOWER_WMARK 0x14 #define ACTMON_DEV_COUNT_WEIGHT 0x18 #define ACTMON_DEV_AVG_COUNT 0x20 #define ACTMON_DEV_INTR_STATUS 0x24 #define ACTMON_INTR_STATUS_CLEAR 0xffffffff #define ACTMON_DEV_INTR_CONSECUTIVE_UPPER BIT(31) #define ACTMON_DEV_INTR_CONSECUTIVE_LOWER BIT(30) #define ACTMON_ABOVE_WMARK_WINDOW 1 #define ACTMON_BELOW_WMARK_WINDOW 3 #define ACTMON_BOOST_FREQ_STEP 16000 |
11573e913
|
53 54 |
/* * Activity counter is incremented every 256 memory transactions, and each |
6234f3801
|
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
* transaction takes 4 EMC clocks for Tegra124; So the COUNT_WEIGHT is * 4 * 256 = 1024. */ #define ACTMON_COUNT_WEIGHT 0x400 /* * ACTMON_AVERAGE_WINDOW_LOG2: default value for @DEV_CTRL_K_VAL, which * translates to 2 ^ (K_VAL + 1). ex: 2 ^ (6 + 1) = 128 */ #define ACTMON_AVERAGE_WINDOW_LOG2 6 #define ACTMON_SAMPLING_PERIOD 12 /* ms */ #define ACTMON_DEFAULT_AVG_BAND 6 /* 1/10 of % */ #define KHZ 1000 /* Assume that the bus is saturated if the utilization is 25% */ #define BUS_SATURATION_RATIO 25 /** * struct tegra_devfreq_device_config - configuration specific to an ACTMON * device * |
11573e913
|
77 |
* Coefficients and thresholds are percentages unless otherwise noted |
6234f3801
|
78 79 80 81 |
*/ struct tegra_devfreq_device_config { u32 offset; u32 irq_mask; |
11573e913
|
82 |
/* Factors applied to boost_freq every consecutive watermark breach */ |
6234f3801
|
83 84 |
unsigned int boost_up_coeff; unsigned int boost_down_coeff; |
11573e913
|
85 86 |
/* Define the watermark bounds when applied to the current avg */ |
6234f3801
|
87 88 |
unsigned int boost_up_threshold; unsigned int boost_down_threshold; |
11573e913
|
89 90 91 92 93 94 |
/* * Threshold of activity (cycles) below which the CPU frequency isn't * to be taken into account. This is to avoid increasing the EMC * frequency when the CPU is very busy but not accessing the bus often. */ |
6234f3801
|
95 96 97 98 99 100 101 102 103 104 |
u32 avg_dependency_threshold; }; enum tegra_actmon_device { MCALL = 0, MCCPU, }; static struct tegra_devfreq_device_config actmon_device_configs[] = { { |
11573e913
|
105 |
/* MCALL: All memory accesses (including from the CPUs) */ |
6234f3801
|
106 107 108 109 110 111 112 113 |
.offset = 0x1c0, .irq_mask = 1 << 26, .boost_up_coeff = 200, .boost_down_coeff = 50, .boost_up_threshold = 60, .boost_down_threshold = 40, }, { |
11573e913
|
114 |
/* MCCPU: memory accesses from the CPUs */ |
6234f3801
|
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
.offset = 0x200, .irq_mask = 1 << 25, .boost_up_coeff = 800, .boost_down_coeff = 90, .boost_up_threshold = 27, .boost_down_threshold = 10, .avg_dependency_threshold = 50000, }, }; /** * struct tegra_devfreq_device - state specific to an ACTMON device * * Frequencies are in kHz. */ struct tegra_devfreq_device { const struct tegra_devfreq_device_config *config; |
11573e913
|
132 |
void __iomem *regs; |
6234f3801
|
133 |
|
11573e913
|
134 135 |
/* Average event count sampled in the last interrupt */ u32 avg_count; |
6234f3801
|
136 |
|
11573e913
|
137 138 139 140 141 142 143 144 |
/* * Extra frequency to increase the target by due to consecutive * watermark breaches. */ unsigned long boost_freq; /* Optimal frequency calculated from the stats for this device */ unsigned long target_freq; |
6234f3801
|
145 146 147 148 |
}; struct tegra_devfreq { struct devfreq *devfreq; |
6234f3801
|
149 150 151 |
struct reset_control *reset; struct clk *clock; void __iomem *regs; |
6234f3801
|
152 153 154 155 156 157 |
struct clk *emc_clock; unsigned long max_freq; unsigned long cur_freq; struct notifier_block rate_change_nb; struct tegra_devfreq_device devices[ARRAY_SIZE(actmon_device_configs)]; |
7514dd05e
|
158 159 |
int irq; |
6234f3801
|
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
}; struct tegra_actmon_emc_ratio { unsigned long cpu_freq; unsigned long emc_freq; }; static struct tegra_actmon_emc_ratio actmon_emc_ratios[] = { { 1400000, ULONG_MAX }, { 1200000, 750000 }, { 1100000, 600000 }, { 1000000, 500000 }, { 800000, 375000 }, { 500000, 200000 }, { 250000, 100000 }, }; |
11573e913
|
176 177 |
static u32 actmon_readl(struct tegra_devfreq *tegra, u32 offset) { |
efe9043db
|
178 |
return readl_relaxed(tegra->regs + offset); |
11573e913
|
179 180 181 182 |
} static void actmon_writel(struct tegra_devfreq *tegra, u32 val, u32 offset) { |
efe9043db
|
183 |
writel_relaxed(val, tegra->regs + offset); |
11573e913
|
184 185 186 187 |
} static u32 device_readl(struct tegra_devfreq_device *dev, u32 offset) { |
efe9043db
|
188 |
return readl_relaxed(dev->regs + offset); |
11573e913
|
189 190 191 192 193 |
} static void device_writel(struct tegra_devfreq_device *dev, u32 val, u32 offset) { |
efe9043db
|
194 |
writel_relaxed(val, dev->regs + offset); |
11573e913
|
195 |
} |
6234f3801
|
196 197 198 199 |
static unsigned long do_percent(unsigned long val, unsigned int pct) { return val * pct / 100; } |
11573e913
|
200 201 |
static void tegra_devfreq_update_avg_wmark(struct tegra_devfreq *tegra, struct tegra_devfreq_device *dev) |
6234f3801
|
202 203 |
{ u32 avg = dev->avg_count; |
11573e913
|
204 205 206 207 |
u32 avg_band_freq = tegra->max_freq * ACTMON_DEFAULT_AVG_BAND / KHZ; u32 band = avg_band_freq * ACTMON_SAMPLING_PERIOD; device_writel(dev, avg + band, ACTMON_DEV_AVG_UPPER_WMARK); |
6234f3801
|
208 |
|
11573e913
|
209 210 |
avg = max(dev->avg_count, band); device_writel(dev, avg - band, ACTMON_DEV_AVG_LOWER_WMARK); |
6234f3801
|
211 212 213 214 215 216 |
} static void tegra_devfreq_update_wmark(struct tegra_devfreq *tegra, struct tegra_devfreq_device *dev) { u32 val = tegra->cur_freq * ACTMON_SAMPLING_PERIOD; |
11573e913
|
217 218 |
device_writel(dev, do_percent(val, dev->config->boost_up_threshold), ACTMON_DEV_UPPER_WMARK); |
6234f3801
|
219 |
|
11573e913
|
220 221 |
device_writel(dev, do_percent(val, dev->config->boost_down_threshold), ACTMON_DEV_LOWER_WMARK); |
6234f3801
|
222 223 224 225 226 |
} static void actmon_write_barrier(struct tegra_devfreq *tegra) { /* ensure the update has reached the ACTMON */ |
ed2a8dd22
|
227 |
readl(tegra->regs + ACTMON_GLB_STATUS); |
6234f3801
|
228 |
} |
11573e913
|
229 230 |
static void actmon_isr_device(struct tegra_devfreq *tegra, struct tegra_devfreq_device *dev) |
6234f3801
|
231 |
{ |
11573e913
|
232 |
u32 intr_status, dev_ctrl; |
6234f3801
|
233 |
|
11573e913
|
234 235 |
dev->avg_count = device_readl(dev, ACTMON_DEV_AVG_COUNT); tegra_devfreq_update_avg_wmark(tegra, dev); |
6234f3801
|
236 |
|
11573e913
|
237 238 |
intr_status = device_readl(dev, ACTMON_DEV_INTR_STATUS); dev_ctrl = device_readl(dev, ACTMON_DEV_CTRL); |
6234f3801
|
239 |
|
11573e913
|
240 |
if (intr_status & ACTMON_DEV_INTR_CONSECUTIVE_UPPER) { |
6234f3801
|
241 242 243 244 245 246 |
/* * new_boost = min(old_boost * up_coef + step, max_freq) */ dev->boost_freq = do_percent(dev->boost_freq, dev->config->boost_up_coeff); dev->boost_freq += ACTMON_BOOST_FREQ_STEP; |
6234f3801
|
247 |
|
11573e913
|
248 249 250 251 252 253 254 |
dev_ctrl |= ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN; if (dev->boost_freq >= tegra->max_freq) dev->boost_freq = tegra->max_freq; else dev_ctrl |= ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN; } else if (intr_status & ACTMON_DEV_INTR_CONSECUTIVE_LOWER) { |
6234f3801
|
255 256 257 258 259 260 |
/* * new_boost = old_boost * down_coef * or 0 if (old_boost * down_coef < step / 2) */ dev->boost_freq = do_percent(dev->boost_freq, dev->config->boost_down_coeff); |
11573e913
|
261 262 263 264 |
dev_ctrl |= ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN; if (dev->boost_freq < (ACTMON_BOOST_FREQ_STEP >> 1)) |
6234f3801
|
265 |
dev->boost_freq = 0; |
11573e913
|
266 267 |
else dev_ctrl |= ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN; |
6234f3801
|
268 269 270 |
} if (dev->config->avg_dependency_threshold) { |
6234f3801
|
271 |
if (dev->avg_count >= dev->config->avg_dependency_threshold) |
11573e913
|
272 |
dev_ctrl |= ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN; |
6234f3801
|
273 |
else if (dev->boost_freq == 0) |
11573e913
|
274 |
dev_ctrl &= ~ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN; |
6234f3801
|
275 |
} |
11573e913
|
276 277 278 |
device_writel(dev, dev_ctrl, ACTMON_DEV_CTRL); device_writel(dev, ACTMON_INTR_STATUS_CLEAR, ACTMON_DEV_INTR_STATUS); |
6234f3801
|
279 280 |
actmon_write_barrier(tegra); |
6234f3801
|
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
} static unsigned long actmon_cpu_to_emc_rate(struct tegra_devfreq *tegra, unsigned long cpu_freq) { unsigned int i; struct tegra_actmon_emc_ratio *ratio = actmon_emc_ratios; for (i = 0; i < ARRAY_SIZE(actmon_emc_ratios); i++, ratio++) { if (cpu_freq >= ratio->cpu_freq) { if (ratio->emc_freq >= tegra->max_freq) return tegra->max_freq; else return ratio->emc_freq; } } return 0; } static void actmon_update_target(struct tegra_devfreq *tegra, struct tegra_devfreq_device *dev) { unsigned long cpu_freq = 0; unsigned long static_cpu_emc_freq = 0; unsigned int avg_sustain_coef; |
6234f3801
|
307 308 309 310 311 |
if (dev->config->avg_dependency_threshold) { cpu_freq = cpufreq_get(0); static_cpu_emc_freq = actmon_cpu_to_emc_rate(tegra, cpu_freq); } |
6234f3801
|
312 313 314 315 316 317 318 |
dev->target_freq = dev->avg_count / ACTMON_SAMPLING_PERIOD; avg_sustain_coef = 100 * 100 / dev->config->boost_up_threshold; dev->target_freq = do_percent(dev->target_freq, avg_sustain_coef); dev->target_freq += dev->boost_freq; if (dev->avg_count >= dev->config->avg_dependency_threshold) dev->target_freq = max(dev->target_freq, static_cpu_emc_freq); |
6234f3801
|
319 320 321 322 323 |
} static irqreturn_t actmon_thread_isr(int irq, void *data) { struct tegra_devfreq *tegra = data; |
dd3f2616b
|
324 325 326 |
bool handled = false; unsigned int i; u32 val; |
6234f3801
|
327 328 |
mutex_lock(&tegra->devfreq->lock); |
dd3f2616b
|
329 330 331 332 333 334 335 336 337 338 339 |
val = actmon_readl(tegra, ACTMON_GLB_STATUS); for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) { if (val & tegra->devices[i].config->irq_mask) { actmon_isr_device(tegra, tegra->devices + i); handled = true; } } if (handled) update_devfreq(tegra->devfreq); |
6234f3801
|
340 |
mutex_unlock(&tegra->devfreq->lock); |
dd3f2616b
|
341 |
return handled ? IRQ_HANDLED : IRQ_NONE; |
6234f3801
|
342 343 344 345 346 347 |
} static int tegra_actmon_rate_notify_cb(struct notifier_block *nb, unsigned long action, void *ptr) { struct clk_notifier_data *data = ptr; |
11573e913
|
348 349 |
struct tegra_devfreq *tegra; struct tegra_devfreq_device *dev; |
6234f3801
|
350 |
unsigned int i; |
6234f3801
|
351 |
|
11573e913
|
352 353 |
if (action != POST_RATE_CHANGE) return NOTIFY_OK; |
6234f3801
|
354 |
|
11573e913
|
355 |
tegra = container_of(nb, struct tegra_devfreq, rate_change_nb); |
6234f3801
|
356 |
|
11573e913
|
357 |
tegra->cur_freq = data->new_rate / KHZ; |
6234f3801
|
358 |
|
11573e913
|
359 360 |
for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) { dev = &tegra->devices[i]; |
11573e913
|
361 |
tegra_devfreq_update_wmark(tegra, dev); |
11573e913
|
362 |
} |
6234f3801
|
363 |
|
11573e913
|
364 |
actmon_write_barrier(tegra); |
6234f3801
|
365 366 367 |
return NOTIFY_OK; } |
11573e913
|
368 369 |
static void tegra_actmon_configure_device(struct tegra_devfreq *tegra, struct tegra_devfreq_device *dev) |
6234f3801
|
370 |
{ |
11573e913
|
371 |
u32 val = 0; |
6234f3801
|
372 |
|
11573e913
|
373 |
dev->target_freq = tegra->cur_freq; |
6234f3801
|
374 |
|
11573e913
|
375 376 |
dev->avg_count = tegra->cur_freq * ACTMON_SAMPLING_PERIOD; device_writel(dev, dev->avg_count, ACTMON_DEV_INIT_AVG); |
6234f3801
|
377 |
|
11573e913
|
378 379 |
tegra_devfreq_update_avg_wmark(tegra, dev); tegra_devfreq_update_wmark(tegra, dev); |
6234f3801
|
380 |
|
11573e913
|
381 382 383 384 385 386 387 388 389 390 |
device_writel(dev, ACTMON_COUNT_WEIGHT, ACTMON_DEV_COUNT_WEIGHT); device_writel(dev, ACTMON_INTR_STATUS_CLEAR, ACTMON_DEV_INTR_STATUS); val |= ACTMON_DEV_CTRL_ENB_PERIODIC; val |= (ACTMON_AVERAGE_WINDOW_LOG2 - 1) << ACTMON_DEV_CTRL_K_VAL_SHIFT; val |= (ACTMON_BELOW_WMARK_WINDOW - 1) << ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_NUM_SHIFT; val |= (ACTMON_ABOVE_WMARK_WINDOW - 1) << ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_NUM_SHIFT; |
546ff0938
|
391 392 393 394 |
val |= ACTMON_DEV_CTRL_AVG_ABOVE_WMARK_EN; val |= ACTMON_DEV_CTRL_AVG_BELOW_WMARK_EN; val |= ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN; val |= ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN; |
11573e913
|
395 396 397 |
val |= ACTMON_DEV_CTRL_ENB; device_writel(dev, val, ACTMON_DEV_CTRL); |
546ff0938
|
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 |
} static void tegra_actmon_start(struct tegra_devfreq *tegra) { unsigned int i; disable_irq(tegra->irq); actmon_writel(tegra, ACTMON_SAMPLING_PERIOD - 1, ACTMON_GLB_PERIOD_CTRL); for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) tegra_actmon_configure_device(tegra, &tegra->devices[i]); actmon_write_barrier(tegra); enable_irq(tegra->irq); } static void tegra_actmon_stop(struct tegra_devfreq *tegra) { unsigned int i; disable_irq(tegra->irq); for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) { device_writel(&tegra->devices[i], 0x00000000, ACTMON_DEV_CTRL); device_writel(&tegra->devices[i], ACTMON_INTR_STATUS_CLEAR, ACTMON_DEV_INTR_STATUS); } |
11573e913
|
428 429 |
actmon_write_barrier(tegra); |
546ff0938
|
430 431 |
enable_irq(tegra->irq); |
6234f3801
|
432 433 434 435 436 |
} static int tegra_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) { |
11573e913
|
437 |
struct tegra_devfreq *tegra = dev_get_drvdata(dev); |
30af44fae
|
438 |
struct devfreq *devfreq = tegra->devfreq; |
6234f3801
|
439 |
struct dev_pm_opp *opp; |
62bacb06b
|
440 |
unsigned long rate; |
30af44fae
|
441 |
int err; |
6234f3801
|
442 |
|
62bacb06b
|
443 |
opp = devfreq_recommended_opp(dev, freq, flags); |
6234f3801
|
444 |
if (IS_ERR(opp)) { |
62bacb06b
|
445 446 |
dev_err(dev, "Failed to find opp for %lu Hz ", *freq); |
6234f3801
|
447 448 449 |
return PTR_ERR(opp); } rate = dev_pm_opp_get_freq(opp); |
8a31d9d94
|
450 |
dev_pm_opp_put(opp); |
6234f3801
|
451 |
|
30af44fae
|
452 453 454 455 456 457 458 |
err = clk_set_min_rate(tegra->emc_clock, rate); if (err) return err; err = clk_set_rate(tegra->emc_clock, 0); if (err) goto restore_min_rate; |
6234f3801
|
459 460 |
return 0; |
30af44fae
|
461 462 463 464 465 |
restore_min_rate: clk_set_min_rate(tegra->emc_clock, devfreq->previous_freq); return err; |
6234f3801
|
466 467 468 469 470 |
} static int tegra_devfreq_get_dev_status(struct device *dev, struct devfreq_dev_status *stat) { |
11573e913
|
471 |
struct tegra_devfreq *tegra = dev_get_drvdata(dev); |
6234f3801
|
472 |
struct tegra_devfreq_device *actmon_dev; |
151531f79
|
473 |
unsigned long cur_freq; |
6234f3801
|
474 |
|
151531f79
|
475 |
cur_freq = READ_ONCE(tegra->cur_freq); |
6234f3801
|
476 477 478 479 480 |
/* To be used by the tegra governor */ stat->private_data = tegra; /* The below are to be used by the other governors */ |
151531f79
|
481 |
stat->current_frequency = cur_freq * KHZ; |
6234f3801
|
482 483 484 485 |
actmon_dev = &tegra->devices[MCALL]; /* Number of cycles spent on memory access */ |
11573e913
|
486 |
stat->busy_time = device_readl(actmon_dev, ACTMON_DEV_AVG_COUNT); |
6234f3801
|
487 488 489 490 491 |
/* The bus can be considered to be saturated way before 100% */ stat->busy_time *= 100 / BUS_SATURATION_RATIO; /* Number of cycles in a sampling period */ |
151531f79
|
492 |
stat->total_time = ACTMON_SAMPLING_PERIOD * cur_freq; |
6234f3801
|
493 |
|
11573e913
|
494 |
stat->busy_time = min(stat->busy_time, stat->total_time); |
6234f3801
|
495 496 |
return 0; } |
11573e913
|
497 498 499 500 501 502 503 504 |
static struct devfreq_dev_profile tegra_devfreq_profile = { .polling_ms = 0, .target = tegra_devfreq_target, .get_dev_status = tegra_devfreq_get_dev_status, }; static int tegra_governor_get_target(struct devfreq *devfreq, unsigned long *freq) |
6234f3801
|
505 |
{ |
14de39031
|
506 |
struct devfreq_dev_status *stat; |
6234f3801
|
507 508 509 510 511 |
struct tegra_devfreq *tegra; struct tegra_devfreq_device *dev; unsigned long target_freq = 0; unsigned int i; int err; |
14de39031
|
512 |
err = devfreq_update_stats(devfreq); |
6234f3801
|
513 514 |
if (err) return err; |
14de39031
|
515 516 517 |
stat = &devfreq->last_status; tegra = stat->private_data; |
6234f3801
|
518 519 520 521 522 523 524 525 |
for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) { dev = &tegra->devices[i]; actmon_update_target(tegra, dev); target_freq = max(target_freq, dev->target_freq); } |
62bacb06b
|
526 |
*freq = target_freq * KHZ; |
6234f3801
|
527 528 529 |
return 0; } |
11573e913
|
530 531 |
static int tegra_governor_event_handler(struct devfreq *devfreq, unsigned int event, void *data) |
6234f3801
|
532 |
{ |
1d1397c3e
|
533 |
struct tegra_devfreq *tegra = dev_get_drvdata(devfreq->dev.parent); |
11573e913
|
534 535 536 |
switch (event) { case DEVFREQ_GOV_START: |
11573e913
|
537 |
devfreq_monitor_start(devfreq); |
546ff0938
|
538 |
tegra_actmon_start(tegra); |
11573e913
|
539 540 541 |
break; case DEVFREQ_GOV_STOP: |
546ff0938
|
542 |
tegra_actmon_stop(tegra); |
11573e913
|
543 544 545 546 |
devfreq_monitor_stop(devfreq); break; case DEVFREQ_GOV_SUSPEND: |
546ff0938
|
547 |
tegra_actmon_stop(tegra); |
11573e913
|
548 549 550 551 |
devfreq_monitor_suspend(devfreq); break; case DEVFREQ_GOV_RESUME: |
11573e913
|
552 |
devfreq_monitor_resume(devfreq); |
546ff0938
|
553 |
tegra_actmon_start(tegra); |
11573e913
|
554 555 |
break; } |
1d1397c3e
|
556 |
return 0; |
6234f3801
|
557 558 559 |
} static struct devfreq_governor tegra_devfreq_governor = { |
11573e913
|
560 561 562 |
.name = "tegra_actmon", .get_target_freq = tegra_governor_get_target, .event_handler = tegra_governor_event_handler, |
386789ebb
|
563 |
.immutable = true, |
6234f3801
|
564 |
}; |
6234f3801
|
565 566 567 568 |
static int tegra_devfreq_probe(struct platform_device *pdev) { struct tegra_devfreq *tegra; struct tegra_devfreq_device *dev; |
6234f3801
|
569 |
unsigned int i; |
5d498b463
|
570 |
unsigned long rate; |
6234f3801
|
571 572 573 574 575 |
int err; tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL); if (!tegra) return -ENOMEM; |
8fda5c1fa
|
576 |
tegra->regs = devm_platform_ioremap_resource(pdev, 0); |
11573e913
|
577 |
if (IS_ERR(tegra->regs)) |
6234f3801
|
578 |
return PTR_ERR(tegra->regs); |
6234f3801
|
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 |
tegra->reset = devm_reset_control_get(&pdev->dev, "actmon"); if (IS_ERR(tegra->reset)) { dev_err(&pdev->dev, "Failed to get reset "); return PTR_ERR(tegra->reset); } tegra->clock = devm_clk_get(&pdev->dev, "actmon"); if (IS_ERR(tegra->clock)) { dev_err(&pdev->dev, "Failed to get actmon clock "); return PTR_ERR(tegra->clock); } tegra->emc_clock = devm_clk_get(&pdev->dev, "emc"); if (IS_ERR(tegra->emc_clock)) { dev_err(&pdev->dev, "Failed to get emc clock "); return PTR_ERR(tegra->emc_clock); } |
8fda5c1fa
|
600 601 602 603 604 |
tegra->irq = platform_get_irq(pdev, 0); if (tegra->irq < 0) { err = tegra->irq; dev_err(&pdev->dev, "Failed to get IRQ: %d ", err); |
6234f3801
|
605 606 607 608 609 610 611 |
return err; } reset_control_assert(tegra->reset); err = clk_prepare_enable(tegra->clock); if (err) { |
11573e913
|
612 613 614 |
dev_err(&pdev->dev, "Failed to prepare and enable ACTMON clock "); |
6234f3801
|
615 616 617 618 |
return err; } reset_control_deassert(tegra->reset); |
c70eea739
|
619 |
tegra->max_freq = clk_round_rate(tegra->emc_clock, ULONG_MAX) / KHZ; |
6234f3801
|
620 |
tegra->cur_freq = clk_get_rate(tegra->emc_clock) / KHZ; |
6234f3801
|
621 622 623 624 |
for (i = 0; i < ARRAY_SIZE(actmon_device_configs); i++) { dev = tegra->devices + i; dev->config = actmon_device_configs + i; dev->regs = tegra->regs + dev->config->offset; |
6234f3801
|
625 |
} |
5d498b463
|
626 627 |
for (rate = 0; rate <= tegra->max_freq * KHZ; rate++) { rate = clk_round_rate(tegra->emc_clock, rate); |
5d498b463
|
628 |
|
8fda5c1fa
|
629 630 631 632 633 634 |
err = dev_pm_opp_add(&pdev->dev, rate, 0); if (err) { dev_err(&pdev->dev, "Failed to add OPP: %d ", err); goto remove_opps; } |
6234f3801
|
635 |
} |
2da19b1a4
|
636 |
platform_set_drvdata(pdev, tegra); |
8fda5c1fa
|
637 638 639 640 641 642 643 644 |
tegra->rate_change_nb.notifier_call = tegra_actmon_rate_notify_cb; err = clk_notifier_register(tegra->emc_clock, &tegra->rate_change_nb); if (err) { dev_err(&pdev->dev, "Failed to register rate change notifier "); goto remove_opps; } |
5a7e10c89
|
645 646 647 648 649 650 |
err = devfreq_add_governor(&tegra_devfreq_governor); if (err) { dev_err(&pdev->dev, "Failed to add governor: %d ", err); goto unreg_notifier; } |
8fda5c1fa
|
651 652 653 654 655 656 657 |
tegra_devfreq_profile.initial_freq = clk_get_rate(tegra->emc_clock); tegra->devfreq = devfreq_add_device(&pdev->dev, &tegra_devfreq_profile, "tegra_actmon", NULL); if (IS_ERR(tegra->devfreq)) { err = PTR_ERR(tegra->devfreq); |
5a7e10c89
|
658 |
goto remove_governor; |
8fda5c1fa
|
659 |
} |
7514dd05e
|
660 |
err = devm_request_threaded_irq(&pdev->dev, tegra->irq, NULL, |
dd3f2616b
|
661 |
actmon_thread_isr, IRQF_ONESHOT, |
6234f3801
|
662 663 |
"tegra-devfreq", tegra); if (err) { |
8fda5c1fa
|
664 665 666 |
dev_err(&pdev->dev, "Interrupt request failed: %d ", err); goto remove_devfreq; |
6234f3801
|
667 |
} |
6234f3801
|
668 |
return 0; |
8fda5c1fa
|
669 670 671 |
remove_devfreq: devfreq_remove_device(tegra->devfreq); |
5a7e10c89
|
672 673 |
remove_governor: devfreq_remove_governor(&tegra_devfreq_governor); |
8fda5c1fa
|
674 675 676 677 678 679 680 681 682 683 |
unreg_notifier: clk_notifier_unregister(tegra->emc_clock, &tegra->rate_change_nb); remove_opps: dev_pm_opp_remove_all_dynamic(&pdev->dev); reset_control_reset(tegra->reset); clk_disable_unprepare(tegra->clock); return err; |
6234f3801
|
684 685 686 687 688 |
} static int tegra_devfreq_remove(struct platform_device *pdev) { struct tegra_devfreq *tegra = platform_get_drvdata(pdev); |
11573e913
|
689 |
|
8fda5c1fa
|
690 |
devfreq_remove_device(tegra->devfreq); |
5a7e10c89
|
691 |
devfreq_remove_governor(&tegra_devfreq_governor); |
6234f3801
|
692 693 |
clk_notifier_unregister(tegra->emc_clock, &tegra->rate_change_nb); |
8fda5c1fa
|
694 |
dev_pm_opp_remove_all_dynamic(&pdev->dev); |
6234f3801
|
695 |
|
8fda5c1fa
|
696 |
reset_control_reset(tegra->reset); |
6234f3801
|
697 698 699 700 |
clk_disable_unprepare(tegra->clock); return 0; } |
11573e913
|
701 |
static const struct of_device_id tegra_devfreq_of_match[] = { |
1ac347488
|
702 |
{ .compatible = "nvidia,tegra30-actmon" }, |
6234f3801
|
703 704 705 |
{ .compatible = "nvidia,tegra124-actmon" }, { }, }; |
11573e913
|
706 |
MODULE_DEVICE_TABLE(of, tegra_devfreq_of_match); |
6234f3801
|
707 708 709 710 |
static struct platform_driver tegra_devfreq_driver = { .probe = tegra_devfreq_probe, .remove = tegra_devfreq_remove, .driver = { |
11573e913
|
711 |
.name = "tegra-devfreq", |
6234f3801
|
712 |
.of_match_table = tegra_devfreq_of_match, |
6234f3801
|
713 714 |
}, }; |
5a7e10c89
|
715 |
module_platform_driver(tegra_devfreq_driver); |
6234f3801
|
716 |
|
11573e913
|
717 |
MODULE_LICENSE("GPL v2"); |
6234f3801
|
718 719 |
MODULE_DESCRIPTION("Tegra devfreq driver"); MODULE_AUTHOR("Tomeu Vizoso <tomeu.vizoso@collabora.com>"); |