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