aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/tegra3_actmon.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/tegra3_actmon.c')
-rw-r--r--arch/arm/mach-tegra/tegra3_actmon.c847
1 files changed, 847 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/tegra3_actmon.c b/arch/arm/mach-tegra/tegra3_actmon.c
new file mode 100644
index 00000000000..43130f960ec
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra3_actmon.c
@@ -0,0 +1,847 @@
1/*
2 * Copyright (c) 2011, NVIDIA Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 */
17
18#include <linux/kernel.h>
19#include <linux/spinlock.h>
20#include <linux/err.h>
21#include <linux/io.h>
22#include <linux/clk.h>
23#include <linux/interrupt.h>
24#include <linux/suspend.h>
25#include <linux/debugfs.h>
26#include <linux/seq_file.h>
27#include <linux/uaccess.h>
28
29#include <mach/iomap.h>
30#include <mach/irqs.h>
31#include <mach/clk.h>
32
33#include "clock.h"
34
35#define ACTMON_GLB_STATUS 0x00
36#define ACTMON_GLB_PERIOD_CTRL 0x04
37
38#define ACTMON_DEV_CTRL 0x00
39#define ACTMON_DEV_CTRL_ENB (0x1 << 31)
40#define ACTMON_DEV_CTRL_UP_WMARK_ENB (0x1 << 30)
41#define ACTMON_DEV_CTRL_DOWN_WMARK_ENB (0x1 << 29)
42#define ACTMON_DEV_CTRL_UP_WMARK_NUM_SHIFT 26
43#define ACTMON_DEV_CTRL_UP_WMARK_NUM_MASK (0x7 << 26)
44#define ACTMON_DEV_CTRL_DOWN_WMARK_NUM_SHIFT 23
45#define ACTMON_DEV_CTRL_DOWN_WMARK_NUM_MASK (0x7 << 23)
46#define ACTMON_DEV_CTRL_AVG_UP_WMARK_ENB (0x1 << 21)
47#define ACTMON_DEV_CTRL_AVG_DOWN_WMARK_ENB (0x1 << 20)
48#define ACTMON_DEV_CTRL_PERIODIC_ENB (0x1 << 18)
49#define ACTMON_DEV_CTRL_K_VAL_SHIFT 10
50#define ACTMON_DEV_CTRL_K_VAL_MASK (0x7 << 10)
51
52#define ACTMON_DEV_UP_WMARK 0x04
53#define ACTMON_DEV_DOWN_WMARK 0x08
54#define ACTMON_DEV_INIT_AVG 0x0c
55#define ACTMON_DEV_AVG_UP_WMARK 0x10
56#define ACTMON_DEV_AVG_DOWN_WMARK 0x14
57
58#define ACTMON_DEV_COUNT_WEGHT 0x18
59#define ACTMON_DEV_COUNT 0x1c
60#define ACTMON_DEV_AVG_COUNT 0x20
61
62#define ACTMON_DEV_INTR_STATUS 0x24
63#define ACTMON_DEV_INTR_UP_WMARK (0x1 << 31)
64#define ACTMON_DEV_INTR_DOWN_WMARK (0x1 << 30)
65#define ACTMON_DEV_INTR_AVG_DOWN_WMARK (0x1 << 25)
66#define ACTMON_DEV_INTR_AVG_UP_WMARK (0x1 << 24)
67
68#define ACTMON_DEFAULT_AVG_WINDOW_LOG2 6
69#define ACTMON_DEFAULT_AVG_BAND 6 /* 1/10 of % */
70
71enum actmon_type {
72 ACTMON_LOAD_SAMPLER,
73 ACTMON_FREQ_SAMPLER,
74};
75
76enum actmon_state {
77 ACTMON_UNINITIALIZED = -1,
78 ACTMON_OFF = 0,
79 ACTMON_ON = 1,
80 ACTMON_SUSPENDED = 2,
81};
82
83#define ACTMON_DEFAULT_SAMPLING_PERIOD 12
84static u8 actmon_sampling_period;
85
86static unsigned long actmon_clk_freq;
87
88
89/* Units:
90 * - frequency in kHz
91 * - coefficients, and thresholds in %
92 * - sampling period in ms
93 * - window in sample periods (value = setting + 1)
94 */
95struct actmon_dev {
96 u32 reg;
97 u32 glb_status_irq_mask;
98 const char *dev_id;
99 const char *con_id;
100 struct clk *clk;
101
102 unsigned long max_freq;
103 unsigned long target_freq;
104 unsigned long cur_freq;
105
106 unsigned long avg_actv_freq;
107 unsigned long avg_band_freq;
108 unsigned int avg_sustain_coef;
109 u32 avg_count;
110
111 unsigned long boost_freq;
112 unsigned long boost_freq_step;
113 unsigned int boost_up_coef;
114 unsigned int boost_down_coef;
115 unsigned int boost_up_threshold;
116 unsigned int boost_down_threshold;
117
118 u8 up_wmark_window;
119 u8 down_wmark_window;
120 u8 avg_window_log2;
121 u32 count_weight;
122
123 enum actmon_type type;
124 enum actmon_state state;
125 enum actmon_state saved_state;
126
127 spinlock_t lock;
128
129 struct notifier_block rate_change_nb;
130};
131
132static void __iomem *actmon_base = IO_ADDRESS(TEGRA_ACTMON_BASE);
133
134static inline u32 actmon_readl(u32 offset)
135{
136 return __raw_readl((u32)actmon_base + offset);
137}
138static inline void actmon_writel(u32 val, u32 offset)
139{
140 __raw_writel(val, (u32)actmon_base + offset);
141}
142static inline void actmon_wmb(void)
143{
144 wmb();
145 actmon_readl(ACTMON_GLB_STATUS);
146}
147
148#define offs(x) (dev->reg + x)
149
150static inline unsigned long do_percent(unsigned long val, unsigned int pct)
151{
152 return val * pct / 100;
153}
154
155static inline void actmon_dev_up_wmark_set(struct actmon_dev *dev)
156{
157 u32 val;
158 unsigned long freq = (dev->type == ACTMON_FREQ_SAMPLER) ?
159 dev->cur_freq : actmon_clk_freq;
160
161 val = freq * actmon_sampling_period;
162 actmon_writel(do_percent(val, dev->boost_up_threshold),
163 offs(ACTMON_DEV_UP_WMARK));
164}
165
166static inline void actmon_dev_down_wmark_set(struct actmon_dev *dev)
167{
168 u32 val;
169 unsigned long freq = (dev->type == ACTMON_FREQ_SAMPLER) ?
170 dev->cur_freq : actmon_clk_freq;
171
172 val = freq * actmon_sampling_period;
173 actmon_writel(do_percent(val, dev->boost_down_threshold),
174 offs(ACTMON_DEV_DOWN_WMARK));
175}
176
177static inline void actmon_dev_wmark_set(struct actmon_dev *dev)
178{
179 u32 val;
180 unsigned long freq = (dev->type == ACTMON_FREQ_SAMPLER) ?
181 dev->cur_freq : actmon_clk_freq;
182
183 val = freq * actmon_sampling_period;
184 actmon_writel(do_percent(val, dev->boost_up_threshold),
185 offs(ACTMON_DEV_UP_WMARK));
186 actmon_writel(do_percent(val, dev->boost_down_threshold),
187 offs(ACTMON_DEV_DOWN_WMARK));
188}
189
190static inline void actmon_dev_avg_wmark_set(struct actmon_dev *dev)
191{
192 u32 avg = dev->avg_count;
193 u32 band = dev->avg_band_freq * actmon_sampling_period;
194
195 actmon_writel(avg + band, offs(ACTMON_DEV_AVG_UP_WMARK));
196 avg = max(avg, band);
197 actmon_writel(avg - band, offs(ACTMON_DEV_AVG_DOWN_WMARK));
198}
199
200static unsigned long actmon_dev_avg_freq_get(struct actmon_dev *dev)
201{
202 u64 val;
203
204 if (dev->type == ACTMON_FREQ_SAMPLER)
205 return dev->avg_count / actmon_sampling_period;
206
207 val = (u64)dev->avg_count * dev->cur_freq;
208 do_div(val, actmon_clk_freq * actmon_sampling_period);
209 return (u32)val;
210}
211
212/* Activity monitor sampling operations */
213irqreturn_t actmon_dev_isr(int irq, void *dev_id)
214{
215 u32 val;
216 unsigned long flags;
217 struct actmon_dev *dev = (struct actmon_dev *)dev_id;
218
219 val = actmon_readl(ACTMON_GLB_STATUS) & dev->glb_status_irq_mask;
220 if (!val)
221 return IRQ_NONE;
222
223 spin_lock_irqsave(&dev->lock, flags);
224
225 dev->avg_count = actmon_readl(offs(ACTMON_DEV_AVG_COUNT));
226 actmon_dev_avg_wmark_set(dev);
227
228 val = actmon_readl(offs(ACTMON_DEV_INTR_STATUS));
229 if (val & ACTMON_DEV_INTR_UP_WMARK) {
230 val = actmon_readl(offs(ACTMON_DEV_CTRL)) |
231 ACTMON_DEV_CTRL_UP_WMARK_ENB |
232 ACTMON_DEV_CTRL_DOWN_WMARK_ENB;
233
234 dev->boost_freq = dev->boost_freq_step +
235 do_percent(dev->boost_freq, dev->boost_up_coef);
236 if (dev->boost_freq >= dev->max_freq) {
237 dev->boost_freq = dev->max_freq;
238 val &= ~ACTMON_DEV_CTRL_UP_WMARK_ENB;
239 }
240 actmon_writel(val, offs(ACTMON_DEV_CTRL));
241 } else if (val & ACTMON_DEV_INTR_DOWN_WMARK) {
242 val = actmon_readl(offs(ACTMON_DEV_CTRL)) |
243 ACTMON_DEV_CTRL_UP_WMARK_ENB |
244 ACTMON_DEV_CTRL_DOWN_WMARK_ENB;
245
246 dev->boost_freq =
247 do_percent(dev->boost_freq, dev->boost_down_coef);
248 if (dev->boost_freq < (dev->boost_freq_step >> 1)) {
249 dev->boost_freq = 0;
250 val &= ~ACTMON_DEV_CTRL_DOWN_WMARK_ENB;
251 }
252 actmon_writel(val, offs(ACTMON_DEV_CTRL));
253 }
254
255 actmon_writel(0xffffffff, offs(ACTMON_DEV_INTR_STATUS)); /* clr all */
256 actmon_wmb();
257
258 spin_unlock_irqrestore(&dev->lock, flags);
259 return IRQ_WAKE_THREAD;
260}
261
262irqreturn_t actmon_dev_fn(int irq, void *dev_id)
263{
264 unsigned long flags, freq;
265 struct actmon_dev *dev = (struct actmon_dev *)dev_id;
266
267 spin_lock_irqsave(&dev->lock, flags);
268
269 if (dev->state != ACTMON_ON) {
270 spin_unlock_irqrestore(&dev->lock, flags);
271 return IRQ_HANDLED;
272 }
273
274 freq = actmon_dev_avg_freq_get(dev);
275 dev->avg_actv_freq = freq;
276 freq = do_percent(freq, dev->avg_sustain_coef);
277 freq += dev->boost_freq;
278 dev->target_freq = freq;
279
280 spin_unlock_irqrestore(&dev->lock, flags);
281
282 pr_debug("%s.%s(kHz): avg: %lu, target: %lu current: %lu\n",
283 dev->dev_id, dev->con_id, dev->avg_actv_freq,
284 dev->target_freq, dev->cur_freq);
285 clk_set_rate(dev->clk, freq * 1000);
286
287 return IRQ_HANDLED;
288}
289
290static int actmon_rate_notify_cb(
291 struct notifier_block *nb, unsigned long rate, void *v)
292{
293 unsigned long flags;
294 struct actmon_dev *dev = container_of(
295 nb, struct actmon_dev, rate_change_nb);
296
297 spin_lock_irqsave(&dev->lock, flags);
298
299 dev->cur_freq = rate / 1000;
300 if (dev->type == ACTMON_FREQ_SAMPLER) {
301 actmon_dev_wmark_set(dev);
302 actmon_wmb();
303 }
304
305 spin_unlock_irqrestore(&dev->lock, flags);
306 return NOTIFY_OK;
307};
308
309/* Activity monitor configuration and control */
310static void actmon_dev_configure(struct actmon_dev *dev, unsigned long freq)
311{
312 u32 val;
313
314 dev->cur_freq = freq;
315 dev->target_freq = freq;
316 dev->avg_actv_freq = freq;
317
318 if (dev->type == ACTMON_FREQ_SAMPLER) {
319 dev->avg_count = dev->cur_freq * actmon_sampling_period;
320 dev->avg_band_freq = dev->max_freq *
321 ACTMON_DEFAULT_AVG_BAND / 1000;
322 } else {
323 dev->avg_count = actmon_clk_freq * actmon_sampling_period;
324 dev->avg_band_freq = actmon_clk_freq *
325 ACTMON_DEFAULT_AVG_BAND / 1000;
326 }
327 actmon_writel(dev->avg_count, offs(ACTMON_DEV_INIT_AVG));
328
329 BUG_ON(!dev->boost_up_threshold);
330 dev->avg_sustain_coef = 100 * 100 / dev->boost_up_threshold;
331 actmon_dev_avg_wmark_set(dev);
332 actmon_dev_wmark_set(dev);
333
334 actmon_writel(dev->count_weight, offs(ACTMON_DEV_COUNT_WEGHT));
335 actmon_writel(0xffffffff, offs(ACTMON_DEV_INTR_STATUS)); /* clr all */
336
337 val = ACTMON_DEV_CTRL_PERIODIC_ENB | ACTMON_DEV_CTRL_AVG_UP_WMARK_ENB |
338 ACTMON_DEV_CTRL_AVG_DOWN_WMARK_ENB;
339 val |= ((dev->avg_window_log2 - 1) << ACTMON_DEV_CTRL_K_VAL_SHIFT) &
340 ACTMON_DEV_CTRL_K_VAL_MASK;
341 val |= ((dev->down_wmark_window - 1) <<
342 ACTMON_DEV_CTRL_DOWN_WMARK_NUM_SHIFT) &
343 ACTMON_DEV_CTRL_DOWN_WMARK_NUM_MASK;
344 val |= ((dev->up_wmark_window - 1) <<
345 ACTMON_DEV_CTRL_UP_WMARK_NUM_SHIFT) &
346 ACTMON_DEV_CTRL_UP_WMARK_NUM_MASK;
347 val |= ACTMON_DEV_CTRL_DOWN_WMARK_ENB | ACTMON_DEV_CTRL_UP_WMARK_ENB;
348 actmon_writel(val, offs(ACTMON_DEV_CTRL));
349 actmon_wmb();
350}
351
352static void actmon_dev_enable(struct actmon_dev *dev)
353{
354 u32 val;
355 unsigned long flags;
356
357 spin_lock_irqsave(&dev->lock, flags);
358
359 if (dev->state == ACTMON_OFF) {
360 dev->state = ACTMON_ON;
361
362 val = actmon_readl(offs(ACTMON_DEV_CTRL));
363 val |= ACTMON_DEV_CTRL_ENB;
364 actmon_writel(val, offs(ACTMON_DEV_CTRL));
365 actmon_wmb();
366 }
367 spin_unlock_irqrestore(&dev->lock, flags);
368}
369
370static void actmon_dev_disable(struct actmon_dev *dev)
371{
372 u32 val;
373 unsigned long flags;
374
375 spin_lock_irqsave(&dev->lock, flags);
376
377 if (dev->state == ACTMON_ON) {
378 dev->state = ACTMON_OFF;
379
380 val = actmon_readl(offs(ACTMON_DEV_CTRL));
381 val &= ~ACTMON_DEV_CTRL_ENB;
382 actmon_writel(val, offs(ACTMON_DEV_CTRL));
383 actmon_writel(0xffffffff, offs(ACTMON_DEV_INTR_STATUS));
384 actmon_wmb();
385 }
386 spin_unlock_irqrestore(&dev->lock, flags);
387}
388
389static void actmon_dev_suspend(struct actmon_dev *dev)
390{
391 u32 val;
392 unsigned long flags;
393
394 spin_lock_irqsave(&dev->lock, flags);
395
396 if ((dev->state == ACTMON_ON) || (dev->state == ACTMON_OFF)){
397 dev->saved_state = dev->state;
398 dev->state = ACTMON_SUSPENDED;
399
400 val = actmon_readl(offs(ACTMON_DEV_CTRL));
401 val &= ~ACTMON_DEV_CTRL_ENB;
402 actmon_writel(val, offs(ACTMON_DEV_CTRL));
403 actmon_writel(0xffffffff, offs(ACTMON_DEV_INTR_STATUS));
404 actmon_wmb();
405 }
406 spin_unlock_irqrestore(&dev->lock, flags);
407}
408
409static void actmon_dev_resume(struct actmon_dev *dev)
410{
411 u32 val;
412 unsigned long flags;
413 unsigned long freq = clk_get_rate(dev->clk) / 1000;
414
415 spin_lock_irqsave(&dev->lock, flags);
416
417 if (dev->state == ACTMON_SUSPENDED) {
418 actmon_dev_configure(dev, freq);
419 dev->state = dev->saved_state;
420 if (dev->state == ACTMON_ON) {
421 val = actmon_readl(offs(ACTMON_DEV_CTRL));
422 val |= ACTMON_DEV_CTRL_ENB;
423 actmon_writel(val, offs(ACTMON_DEV_CTRL));
424 actmon_wmb();
425 }
426 }
427 spin_unlock_irqrestore(&dev->lock, flags);
428}
429
430static int __init actmon_dev_init(struct actmon_dev *dev)
431{
432 int ret;
433 struct clk *p;
434 unsigned long freq;
435
436 spin_lock_init(&dev->lock);
437
438 dev->clk = clk_get_sys(dev->dev_id, dev->con_id);
439 if (IS_ERR(dev->clk)) {
440 pr_err("Failed to find %s.%s clock\n",
441 dev->dev_id, dev->con_id);
442 return -ENODEV;
443 }
444 dev->max_freq = clk_round_rate(dev->clk, ULONG_MAX);
445 clk_set_rate(dev->clk, dev->max_freq);
446 dev->max_freq /= 1000;
447 freq = clk_get_rate(dev->clk) / 1000;
448 actmon_dev_configure(dev, freq);
449
450 /* actmon device controls shared bus user clock, but rate
451 change notification should come from bus clock itself */
452 p = clk_get_parent(dev->clk);
453 BUG_ON(!p);
454
455 if (dev->rate_change_nb.notifier_call) {
456 ret = tegra_register_clk_rate_notifier(p, &dev->rate_change_nb);
457 if (ret) {
458 pr_err("Failed to register %s rate change notifier"
459 " for %s\n", p->name, dev->dev_id);
460 return ret;
461 }
462 }
463
464 ret = request_threaded_irq(INT_ACTMON, actmon_dev_isr, actmon_dev_fn,
465 IRQF_SHARED, dev->dev_id, dev);
466 if (ret) {
467 pr_err("Failed irq %d request for %s.%s\n",
468 INT_ACTMON, dev->dev_id, dev->con_id);
469 tegra_unregister_clk_rate_notifier(p, &dev->rate_change_nb);
470 return ret;
471 }
472
473 dev->state = ACTMON_OFF;
474 actmon_dev_enable(dev);
475 clk_enable(dev->clk);
476 return 0;
477}
478
479/* EMC activity monitor: frequency sampling device:
480 * activity counter is incremented every 256 memory transactions, and
481 * each transaction takes 2 EMC clocks; count_weight = 512.
482 */
483static struct actmon_dev actmon_dev_emc = {
484 .reg = 0x1c0,
485 .glb_status_irq_mask = (0x1 << 26),
486 .dev_id = "tegra_actmon",
487 .con_id = "emc",
488
489 .boost_freq_step = 16000,
490 .boost_up_coef = 200,
491 .boost_down_coef = 50,
492 .boost_up_threshold = 60,
493 .boost_down_threshold = 40,
494
495 .up_wmark_window = 1,
496 .down_wmark_window = 3,
497 .avg_window_log2 = ACTMON_DEFAULT_AVG_WINDOW_LOG2,
498 .count_weight = 0x200,
499
500 .type = ACTMON_FREQ_SAMPLER,
501 .state = ACTMON_UNINITIALIZED,
502
503 .rate_change_nb = {
504 .notifier_call = actmon_rate_notify_cb,
505 },
506};
507
508/* AVP activity monitor: load sampling device:
509 * activity counter is incremented on every actmon clock pulse while
510 * AVP is not halted by flow controller; count_weight = 1.
511 */
512static struct actmon_dev actmon_dev_avp = {
513 .reg = 0x0c0,
514 .glb_status_irq_mask = (0x1 << 30),
515 .dev_id = "tegra_actmon",
516 .con_id = "avp",
517
518 .boost_freq_step = 8000,
519 .boost_up_coef = 200,
520 .boost_down_coef = 50,
521 .boost_up_threshold = 75,
522 .boost_down_threshold = 50,
523
524 .up_wmark_window = 1,
525 .down_wmark_window = 3,
526 .avg_window_log2 = ACTMON_DEFAULT_AVG_WINDOW_LOG2,
527 .count_weight = 0x1,
528
529 .type = ACTMON_LOAD_SAMPLER,
530 .state = ACTMON_UNINITIALIZED,
531
532 .rate_change_nb = {
533 .notifier_call = actmon_rate_notify_cb,
534 },
535};
536
537static struct actmon_dev *actmon_devices[] = {
538 &actmon_dev_emc,
539 &actmon_dev_avp,
540};
541
542/* Activity monitor suspend/resume */
543static int actmon_pm_notify(struct notifier_block *nb,
544 unsigned long event, void *data)
545{
546 int i;
547
548 switch (event) {
549 case PM_SUSPEND_PREPARE:
550 for (i = 0; i < ARRAY_SIZE(actmon_devices); i++)
551 actmon_dev_suspend(actmon_devices[i]);
552 break;
553 case PM_POST_SUSPEND:
554 actmon_writel(actmon_sampling_period - 1,
555 ACTMON_GLB_PERIOD_CTRL);
556 for (i = 0; i < ARRAY_SIZE(actmon_devices); i++)
557 actmon_dev_resume(actmon_devices[i]);
558 break;
559 }
560
561 return NOTIFY_OK;
562};
563
564static struct notifier_block actmon_pm_nb = {
565 .notifier_call = actmon_pm_notify,
566};
567
568#ifdef CONFIG_DEBUG_FS
569
570#define RW_MODE (S_IWUSR | S_IRUGO)
571#define RO_MODE S_IRUGO
572
573static struct dentry *clk_debugfs_root;
574
575static int type_show(struct seq_file *s, void *data)
576{
577 struct actmon_dev *dev = s->private;
578
579 seq_printf(s, "%s\n", (dev->type == ACTMON_LOAD_SAMPLER) ?
580 "Load Activity Monitor" : "Frequency Activity Monitor");
581 return 0;
582}
583static int type_open(struct inode *inode, struct file *file)
584{
585 return single_open(file, type_show, inode->i_private);
586}
587static const struct file_operations type_fops = {
588 .open = type_open,
589 .read = seq_read,
590 .llseek = seq_lseek,
591 .release = single_release,
592};
593
594static int actv_get(void *data, u64 *val)
595{
596 unsigned long flags;
597 struct actmon_dev *dev = data;
598
599 spin_lock_irqsave(&dev->lock, flags);
600 *val = actmon_dev_avg_freq_get(dev);
601 spin_unlock_irqrestore(&dev->lock, flags);
602 return 0;
603}
604DEFINE_SIMPLE_ATTRIBUTE(actv_fops, actv_get, NULL, "%llu\n");
605
606static int step_get(void *data, u64 *val)
607{
608 struct actmon_dev *dev = data;
609 *val = dev->boost_freq_step * 100 / dev->max_freq;
610 return 0;
611}
612static int step_set(void *data, u64 val)
613{
614 unsigned long flags;
615 struct actmon_dev *dev = data;
616
617 if (val > 100)
618 val = 100;
619
620 spin_lock_irqsave(&dev->lock, flags);
621 dev->boost_freq_step = do_percent(dev->max_freq, (unsigned int)val);
622 spin_unlock_irqrestore(&dev->lock, flags);
623 return 0;
624}
625DEFINE_SIMPLE_ATTRIBUTE(step_fops, step_get, step_set, "%llu\n");
626
627static int up_threshold_get(void *data, u64 *val)
628{
629 struct actmon_dev *dev = data;
630 *val = dev->boost_up_threshold;
631 return 0;
632}
633static int up_threshold_set(void *data, u64 val)
634{
635 unsigned long flags;
636 struct actmon_dev *dev = data;
637 unsigned int up_threshold = (unsigned int)val;
638
639 if (up_threshold > 100)
640 up_threshold = 100;
641
642 spin_lock_irqsave(&dev->lock, flags);
643
644 if (up_threshold <= dev->boost_down_threshold)
645 up_threshold = dev->boost_down_threshold;
646 if (up_threshold)
647 dev->avg_sustain_coef = 100 * 100 / up_threshold;
648 dev->boost_up_threshold = up_threshold;
649
650 actmon_dev_up_wmark_set(dev);
651 actmon_wmb();
652
653 spin_unlock_irqrestore(&dev->lock, flags);
654 return 0;
655}
656DEFINE_SIMPLE_ATTRIBUTE(up_threshold_fops, up_threshold_get,
657 up_threshold_set, "%llu\n");
658
659static int down_threshold_get(void *data, u64 *val)
660{
661 struct actmon_dev *dev = data;
662 *val = dev->boost_down_threshold;
663 return 0;
664}
665static int down_threshold_set(void *data, u64 val)
666{
667 unsigned long flags;
668 struct actmon_dev *dev = data;
669 unsigned int down_threshold = (unsigned int)val;
670
671 spin_lock_irqsave(&dev->lock, flags);
672
673 if (down_threshold >= dev->boost_up_threshold)
674 down_threshold = dev->boost_up_threshold;
675 dev->boost_down_threshold = down_threshold;
676
677 actmon_dev_down_wmark_set(dev);
678 actmon_wmb();
679
680 spin_unlock_irqrestore(&dev->lock, flags);
681 return 0;
682}
683DEFINE_SIMPLE_ATTRIBUTE(down_threshold_fops, down_threshold_get,
684 down_threshold_set, "%llu\n");
685
686static int state_get(void *data, u64 *val)
687{
688 struct actmon_dev *dev = data;
689 *val = dev->state;
690 return 0;
691}
692static int state_set(void *data, u64 val)
693{
694 struct actmon_dev *dev = data;
695
696 if (val)
697 actmon_dev_enable(dev);
698 else
699 actmon_dev_disable(dev);
700 return 0;
701}
702DEFINE_SIMPLE_ATTRIBUTE(state_fops, state_get, state_set, "%llu\n");
703
704static int period_get(void *data, u64 *val)
705{
706 *val = actmon_sampling_period;
707 return 0;
708}
709static int period_set(void *data, u64 val)
710{
711 int i;
712 unsigned long flags;
713 u8 period = (u8)val;
714
715 if (period) {
716 actmon_sampling_period = period;
717 actmon_writel(period - 1, ACTMON_GLB_PERIOD_CTRL);
718
719 for (i = 0; i < ARRAY_SIZE(actmon_devices); i++) {
720 struct actmon_dev *dev = actmon_devices[i];
721 spin_lock_irqsave(&dev->lock, flags);
722 actmon_dev_wmark_set(dev);
723 spin_unlock_irqrestore(&dev->lock, flags);
724 }
725 actmon_wmb();
726 return 0;
727 }
728 return -EINVAL;
729}
730DEFINE_SIMPLE_ATTRIBUTE(period_fops, period_get, period_set, "%llu\n");
731
732
733static int actmon_debugfs_create_dev(struct actmon_dev *dev)
734{
735 struct dentry *dir, *d;
736
737 if (dev->state == ACTMON_UNINITIALIZED)
738 return 0;
739
740 dir = debugfs_create_dir(dev->con_id, clk_debugfs_root);
741 if (!dir)
742 return -ENOMEM;
743
744 d = debugfs_create_file(
745 "actv_type", RO_MODE, dir, dev, &type_fops);
746 if (!d)
747 return -ENOMEM;
748
749 d = debugfs_create_file(
750 "avg_activity", RO_MODE, dir, dev, &actv_fops);
751 if (!d)
752 return -ENOMEM;
753
754 d = debugfs_create_file(
755 "boost_step", RW_MODE, dir, dev, &step_fops);
756 if (!d)
757 return -ENOMEM;
758
759 d = debugfs_create_u32(
760 "boost_rate_dec", RW_MODE, dir, (u32 *)&dev->boost_down_coef);
761 if (!d)
762 return -ENOMEM;
763
764 d = debugfs_create_u32(
765 "boost_rate_inc", RW_MODE, dir, (u32 *)&dev->boost_up_coef);
766 if (!d)
767 return -ENOMEM;
768
769 d = debugfs_create_file(
770 "boost_threshold_dn", RW_MODE, dir, dev, &down_threshold_fops);
771 if (!d)
772 return -ENOMEM;
773
774 d = debugfs_create_file(
775 "boost_threshold_up", RW_MODE, dir, dev, &up_threshold_fops);
776 if (!d)
777 return -ENOMEM;
778
779 d = debugfs_create_file(
780 "state", RW_MODE, dir, dev, &state_fops);
781 if (!d)
782 return -ENOMEM;
783
784 return 0;
785}
786
787static int __init actmon_debugfs_init(void)
788{
789 int i;
790 int ret = -ENOMEM;
791 struct dentry *d;
792
793 d = debugfs_create_dir("tegra_actmon", NULL);
794 if (!d)
795 return ret;
796 clk_debugfs_root = d;
797
798 d = debugfs_create_file("period", RW_MODE, d, NULL, &period_fops);
799 if (!d)
800 goto err_out;
801
802 for (i = 0; i < ARRAY_SIZE(actmon_devices); i++) {
803 ret = actmon_debugfs_create_dev(actmon_devices[i]);
804 if (ret)
805 goto err_out;
806 }
807 return 0;
808
809err_out:
810 debugfs_remove_recursive(clk_debugfs_root);
811 return ret;
812}
813
814#endif
815
816static int __init tegra_actmon_init(void)
817{
818 int i, ret;
819 struct clk *c = tegra_get_clock_by_name("actmon");
820
821 if (!c) {
822 pr_err("%s: Failed to find actmon clock\n", __func__);
823 return 0;
824 }
825 actmon_clk_freq = clk_get_rate(c) / 1000;
826 ret = clk_enable(c);
827 if (ret) {
828 pr_err("%s: Failed to enable actmon clock\n", __func__);
829 return 0;
830 }
831 actmon_sampling_period = ACTMON_DEFAULT_SAMPLING_PERIOD;
832 actmon_writel(actmon_sampling_period - 1, ACTMON_GLB_PERIOD_CTRL);
833
834 for (i = 0; i < ARRAY_SIZE(actmon_devices); i++) {
835 ret = actmon_dev_init(actmon_devices[i]);
836 pr_info("%s.%s: %s initialization (%d)\n",
837 actmon_devices[i]->dev_id, actmon_devices[i]->con_id,
838 ret ? "Failed" : "Completed", ret);
839 }
840 register_pm_notifier(&actmon_pm_nb);
841
842#ifdef CONFIG_DEBUG_FS
843 actmon_debugfs_init();
844#endif
845 return 0;
846}
847late_initcall(tegra_actmon_init);