rtc: tps80031: register as mfd sub device
[linux-2.6.git] / arch / arm / mach-tegra / tegra2_mc.c
1 /*
2  * arch/arm/mach-tegra/tegra2_mc.c
3  *
4  * Memory controller bandwidth profiling interface
5  *
6  * Copyright (c) 2009-2011, NVIDIA Corporation.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16  * more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21  */
22
23 #include <linux/slab.h>
24 #include <linux/kobject.h>
25 #include <linux/string.h>
26 #include <linux/sysfs.h>
27 #include <linux/sysdev.h>
28 #include <linux/ktime.h>
29 #include <linux/hrtimer.h>
30 #include <linux/parser.h>
31 #include <linux/io.h>
32 #include <linux/module.h>
33 #include <linux/init.h>
34 #include <linux/clk.h>
35
36 #include <mach/iomap.h>
37
38 #include <asm/uaccess.h>
39
40 #include "clock.h"
41 #include "tegra2_mc.h"
42
43 static void stat_start(void);
44 static void stat_stop(void);
45 static void stat_log(void);
46
47 static struct hrtimer sample_timer;
48
49 #define MC_COUNTER_INITIALIZER()                        \
50         {                                               \
51                 .enabled = false,                       \
52                 .period = 10,                           \
53                 .mode = FILTER_CLIENT,                  \
54                 .address_low = 0,                       \
55                 .address_length = 0xfffffffful,         \
56                 .sample_data = {                        \
57                         .signature = 0xdeadbeef,        \
58                 }                                       \
59         }
60
61 static struct tegra_mc_counter mc_counter0 = MC_COUNTER_INITIALIZER();
62 static struct tegra_mc_counter mc_counter1 = MC_COUNTER_INITIALIZER();
63 static struct tegra_mc_counter emc_llp_counter = MC_COUNTER_INITIALIZER();
64
65 /* /sys/devices/system/tegra_mc */
66 static bool sample_enable       = SAMPLE_ENABLE_DEFAULT;
67 static u16 sample_quantum       = SAMPLE_QUANTUM_DEFAULT;
68 static u8 sample_log[SAMPLE_LOG_SIZE];
69
70 static DEFINE_SPINLOCK(sample_enable_lock);
71 static DEFINE_SPINLOCK(sample_log_lock);
72
73 static u8 *sample_log_wptr = sample_log, *sample_log_rptr = sample_log;
74 static int sample_log_size = SAMPLE_LOG_SIZE - 1;
75 static struct clk *emc_clock = NULL;
76
77 static bool sampling(void)
78 {
79         bool ret;
80
81         spin_lock_bh(&sample_enable_lock);
82         ret = (sample_enable == true)? true : false;
83         spin_unlock_bh(&sample_enable_lock);
84
85         return ret;
86 }
87
88 static struct sysdev_class tegra_mc_sysclass = {
89         .name = "tegra_mc",
90 };
91
92 static ssize_t tegra_mc_enable_show(struct sysdev_class *class,
93         struct sysdev_class_attribute *attr, char *buf)
94 {
95         return sprintf(buf, "%d\n", sample_enable);
96 }
97
98 static ssize_t tegra_mc_enable_store(struct sysdev_class *class,
99         struct sysdev_class_attribute *attr,
100         const char *buf, size_t count)
101 {
102         int value, i;
103         struct tegra_mc_counter *counters[] = {
104                 &mc_counter0,
105                 &mc_counter1,
106                 &emc_llp_counter
107         };
108
109         sscanf(buf, "%d", &value);
110
111         if (value == 0 || value == 1)
112                 sample_enable = value;
113         else
114                 return -EINVAL;
115
116         if (!sample_enable) {
117                 stat_stop();
118                 hrtimer_cancel(&sample_timer);
119                 return count;
120         }
121
122         hrtimer_cancel(&sample_timer);
123
124         /* we need to initialize variables that change during sampling */
125         sample_log_wptr = sample_log_rptr = sample_log;
126         sample_log_size = SAMPLE_LOG_SIZE - 1;
127
128         for (i = 0; i < ARRAY_SIZE(counters); i++) {
129                 struct tegra_mc_counter *c = counters[i];
130
131                 if (!c->enabled)
132                         continue;
133
134                 c->current_client_index = 0;
135         }
136
137         stat_start();
138
139         hrtimer_start(&sample_timer,
140                 ktime_add_ns(ktime_get(), (u64)sample_quantum * 1000000),
141                 HRTIMER_MODE_ABS);
142
143         return count;
144 }
145
146 static ssize_t tegra_mc_log_show(struct sysdev_class *class,
147         struct sysdev_class_attribute *attr, char *buf)
148 {
149         int index = 0, count = 0;
150         unsigned long flags;
151
152         spin_lock_irqsave(&sample_log_lock, flags);
153
154         while (sample_log_rptr != sample_log_wptr) {
155                 if (sample_log_rptr < sample_log_wptr) {
156                         count = sample_log_wptr - sample_log_rptr;
157                         memcpy(buf + index, sample_log_rptr, count);
158                         sample_log_rptr = sample_log_wptr;
159                         sample_log_size += count;
160                 } else {
161                         count = SAMPLE_LOG_SIZE -
162                                 (sample_log_rptr - sample_log);
163                         memcpy(buf + index, sample_log_rptr, count);
164                         sample_log_rptr = sample_log;
165                         sample_log_size += count;
166                 }
167                 index += count;
168         }
169
170         spin_unlock_irqrestore(&sample_log_lock, flags);
171
172         return index;
173 }
174
175 static ssize_t tegra_mc_log_store(struct sysdev_class *class,
176         struct sysdev_class_attribute *attr,
177         const char *buf, size_t count)
178 {
179         return -EPERM;
180 }
181
182 static ssize_t tegra_mc_quantum_show(struct sysdev_class *class,
183         struct sysdev_class_attribute *attr, char *buf)
184 {
185         return sprintf(buf, "%d\n", sample_quantum);
186 }
187
188 static ssize_t tegra_mc_quantum_store(struct sysdev_class *class,
189         struct sysdev_class_attribute *attr,
190         const char *buf, size_t count)
191 {
192         int value;
193
194         if (sampling())
195                 return -EINVAL;
196
197         sscanf(buf, "%d", &value);
198         sample_quantum = value;
199
200         return count;
201 }
202
203 #define TEGRA_MC_EXPAND(_attr,_mode) \
204         static SYSDEV_CLASS_ATTR( \
205           _attr, _mode, tegra_mc_##_attr##_show, tegra_mc_##_attr##_store);
206
207 #define TEGRA_MC_ATTRIBUTES(_attr1,_mode1,_attr2,_mode2,_attr3,_mode3) \
208         TEGRA_MC_EXPAND(_attr1,_mode1) \
209         TEGRA_MC_EXPAND(_attr2,_mode2) \
210         TEGRA_MC_EXPAND(_attr3,_mode3)
211
212 TEGRA_MC_ATTRIBUTES(enable,0666,log,0444,quantum,0666)
213
214 #undef TEGRA_MC_EXPAND
215
216 #define TEGRA_MC_EXPAND(_attr,_mode) \
217         &attr_##_attr,
218
219 static struct sysdev_class_attribute *tegra_mc_attrs[] = {
220         TEGRA_MC_ATTRIBUTES(enable,0666,log,0444,quantum,0666)
221         NULL
222 };
223
224 /* /sys/devices/system/tegra_mc/client */
225 static bool tegra_mc_client_0_enabled = CLIENT_ENABLED_DEFAULT;
226 static u8 tegra_mc_client_0_on_schedule_buffer[CLIENT_ON_SCHEDULE_LENGTH];
227 static struct kobject *tegra_mc_client_kobj, *tegra_mc_client_0_kobj;
228
229 struct match_mode {
230         const char *name;
231         int mode;
232 };
233
234 static const struct match_mode mode_list[] = {
235         [0] = {
236                 .name = "none",
237                 .mode = FILTER_NONE,
238         },
239         [1] = {
240                 .name = "address",
241                 .mode = FILTER_ADDR,
242         },
243         [2] = {
244                 .name = "client",
245                 .mode = FILTER_CLIENT,
246         },
247 };
248
249 static int tegra_mc_parse_mode(const char* str) {
250         int i;
251
252         for (i = 0; i < ARRAY_SIZE(mode_list); i++) {
253                 if (!strncmp(str, mode_list[i].name, strlen(mode_list[i].name)))
254                         return mode_list[i].mode;
255         }
256         return -EINVAL;
257 }
258
259 static int tegra_mc_client_parse(const char *buf, size_t count,
260         tegra_mc_counter_t *counter0, tegra_mc_counter_t *counter1,
261         tegra_mc_counter_t *llp)
262 {
263         char *options, *p, *ptr;
264         tegra_mc_counter_t *counter;
265         substring_t args[MAX_OPT_ARGS];
266         enum {
267                 opt_period,
268                 opt_mode,
269                 opt_client,
270                 opt_address_low,
271                 opt_address_length,
272                 opt_err,
273         };
274         const match_table_t tokens = {
275                 {opt_period, "period=%s"},
276                 {opt_mode, "mode=%s"},
277                 {opt_client, "client=%s"},
278                 {opt_address_low, "address_low=%s"},
279                 {opt_address_length, "address_length=%s"},
280                 {opt_err, NULL},
281         };
282         int ret = 0, i, token, index = 0;
283         bool aggregate = false;
284         int period, *client_ids;
285         int mode = FILTER_NONE;
286         u64 address_low = 0;
287         u64 address_length = 1ull << 32;
288
289         client_ids = kmalloc(sizeof(int) * (MC_COUNTER_CLIENT_SIZE + 1),
290                 GFP_KERNEL);
291         if (!client_ids)
292                 return -ENOMEM;
293
294         memset(client_ids, -1, (sizeof(int) * (MC_COUNTER_CLIENT_SIZE + 1)));
295
296         options = kstrdup(buf, GFP_KERNEL);
297         if (!options) {
298                 ret = -ENOMEM;
299                 goto end;
300         }
301
302         while ((p = strsep(&options, " ")) != NULL) {
303                 if (!*p)
304                         continue;
305
306                 pr_debug("\t %s\n", p);
307
308                 token = match_token(p, tokens, args);
309                 switch (token) {
310                 case opt_period:
311                         if (match_int(&args[0], &period) || period <= 0) {
312                                 ret = -EINVAL;
313                                 goto end;
314                         }
315                         break;
316
317                 case opt_mode:
318                         mode = tegra_mc_parse_mode(args[0].from);
319                         if (mode < 0) {
320                                 ret = mode;
321                                 goto end;
322                         }
323                         break;
324
325                 case opt_client:
326                         ptr = get_options(args[0].from,
327                                 MC_COUNTER_CLIENT_SIZE + 1, client_ids);
328
329                         if (client_ids[1] == MC_STAT_AGGREGATE) {
330                                 aggregate = true;
331                                 break;
332                         }
333                         break;
334
335                 case opt_address_low:
336                         address_low = simple_strtoull(args[0].from, NULL, 0);
337                         break;
338
339                 case opt_address_length:
340                         address_length = simple_strtoull(args[0].from, NULL, 0);
341                         break;
342
343                 default:
344                         ret = -EINVAL;
345                         goto end;
346                 }
347         }
348
349         address_low &= PAGE_MASK;
350         address_length += PAGE_SIZE - 1;
351         address_length &= ~((1ull << PAGE_SHIFT) - 1ull);
352
353         if (mode == FILTER_CLIENT) {
354                 counter = counter0;
355                 llp->enabled = false;
356                 counter1->enabled = false;
357         } else if (mode == FILTER_ADDR || mode == FILTER_NONE) {
358                 if (aggregate) {
359                         counter = counter1;
360                         llp->enabled = false;
361                         counter0->enabled = false;
362                 } else {
363                         counter = counter0;
364                         counter1->enabled = false;
365                         llp->enabled = false;
366                 }
367         } else {
368                 ret = -EINVAL;
369                 goto end;
370         }
371
372         counter->mode = mode;
373         counter->enabled = true;
374         counter->address_low = (u32)address_low;
375         counter->address_length = (u32)(address_length - 1);
376
377         for (i = 1; i < MC_COUNTER_CLIENT_SIZE; i++) {
378                 if (client_ids[i] != -1)
379                         counter->clients[index++] = client_ids[i];
380         }
381
382         counter->total_clients = index;
383
384         if (llp->enabled) {
385                 llp->mode = counter->mode;
386                 llp->period = counter->period;
387                 llp->address_low = counter->address_low;
388                 llp->address_length = counter->address_length;
389         }
390
391 end:
392         if (options)
393                 kfree(options);
394         if (client_ids)
395                 kfree(client_ids);
396
397         return ret;
398 }
399
400 static ssize_t tegra_mc_client_0_show(struct kobject *kobj,
401         struct kobj_attribute *attr, char *buf)
402 {
403         if (strcmp(attr->attr.name, "enable") == 0)
404                 return sprintf(buf, "%d\n", tegra_mc_client_0_enabled);
405         else if (strcmp(attr->attr.name, "on_schedule") == 0)
406                 return sprintf(buf, "%s", tegra_mc_client_0_on_schedule_buffer);
407         else
408                 return -EINVAL;
409 }
410
411 static ssize_t tegra_mc_client_0_store(struct kobject *kobj,
412         struct kobj_attribute *attr, const char *buf, size_t count)
413 {
414         int value;
415
416         if (sampling())
417                 return -EINVAL;
418
419         if (strcmp(attr->attr.name, "enable") == 0) {
420                 sscanf(buf, "%d\n", &value);
421                 if (value == 0 || value == 1)
422                         tegra_mc_client_0_enabled = value;
423                 else
424                         return -EINVAL;
425
426                 return count;
427         } else if (strcmp(attr->attr.name, "on_schedule") == 0) {
428                 if (tegra_mc_client_parse(buf, count,
429                         &mc_counter0, &mc_counter1,
430                         &emc_llp_counter) == 0) {
431
432                         strncpy(tegra_mc_client_0_on_schedule_buffer,
433                                 buf, count);
434
435                         return count;
436                 } else
437                         return -EINVAL;
438         } else
439                 return -EINVAL;
440 }
441
442 static struct kobj_attribute tegra_mc_client_0_enable =
443         __ATTR(enable, 0660, tegra_mc_client_0_show, tegra_mc_client_0_store);
444
445 static struct kobj_attribute tegra_mc_client_0_on_schedule =
446         __ATTR(on_schedule, 0660, tegra_mc_client_0_show, tegra_mc_client_0_store);
447
448 static struct attribute *tegra_mc_client_0_attrs[] = {
449         &tegra_mc_client_0_enable.attr,
450         &tegra_mc_client_0_on_schedule.attr,
451         NULL,
452 };
453
454 static struct attribute_group tegra_mc_client_0_attr_group = {
455         .attrs = tegra_mc_client_0_attrs
456 };
457
458 /* /sys/devices/system/tegra_mc/dram */
459 #define dram_counters(_x)                                        \
460         _x(activate_cnt, ACTIVATE_CNT)                           \
461         _x(read_cnt, READ_CNT)                                   \
462         _x(write_cnt, WRITE_CNT)                                 \
463         _x(ref_cnt, REF_CNT)                                     \
464         _x(cumm_banks_active_cke_eq1, CUMM_BANKS_ACTIVE_CKE_EQ1) \
465         _x(cumm_banks_active_cke_eq0, CUMM_BANKS_ACTIVE_CKE_EQ0) \
466         _x(cke_eq1_clks, CKE_EQ1_CLKS)                           \
467         _x(extclks_cke_eq1, EXTCLKS_CKE_EQ1)                     \
468         _x(extclks_cke_eq0, EXTCLKS_CKE_EQ0)                     \
469         _x(no_banks_active_cke_eq1, NO_BANKS_ACTIVE_CKE_EQ1)     \
470         _x(no_banks_active_cke_eq0, NO_BANKS_ACTIVE_CKE_EQ0)
471
472 #define DEFINE_COUNTER(_name, _val) { .enabled = false, .device_mask = 0, },
473
474 static tegra_emc_dram_counter_t dram_counters[] = {
475         dram_counters(DEFINE_COUNTER)
476 };
477
478 #define DEFINE_SYSFS(_name, _val)                                       \
479                                                                         \
480 static struct kobject *tegra_mc_dram_##_name##_kobj;                    \
481                                                                         \
482 static ssize_t tegra_mc_dram_##_name##_show(struct kobject *kobj,       \
483         struct kobj_attribute *attr, char *buf)                         \
484 {                                                                       \
485         return tegra_mc_dram_show(kobj, attr, buf,                      \
486                                   _val - EMC_DRAM_STAT_BEGIN);          \
487 }                                                                       \
488                                                                         \
489 static ssize_t tegra_mc_dram_##_name##_store(struct kobject *kobj,      \
490         struct kobj_attribute *attr, const char *buf, size_t count)     \
491 {                                                                       \
492         if (sampling())                                                 \
493                 return 0;                                               \
494                                                                         \
495         return tegra_mc_dram_store(kobj, attr, buf, count,              \
496                                    _val - EMC_DRAM_STAT_BEGIN);         \
497 }                                                                       \
498                                                                         \
499                                                                         \
500 static struct kobj_attribute tegra_mc_dram_##_name##_enable =           \
501                __ATTR(enable, 0660, tegra_mc_dram_##_name##_show,       \
502                       tegra_mc_dram_##_name##_store);                   \
503                                                                         \
504 static struct kobj_attribute tegra_mc_dram_##_name##_device_mask =      \
505                __ATTR(device_mask, 0660, tegra_mc_dram_##_name##_show,  \
506                       tegra_mc_dram_##_name##_store);                   \
507                                                                         \
508 static struct attribute *tegra_mc_dram_##_name##_attrs[] = {            \
509         &tegra_mc_dram_##_name##_enable.attr,                           \
510         &tegra_mc_dram_##_name##_device_mask.attr,                      \
511         NULL,                                                           \
512 };                                                                      \
513                                                                         \
514 static struct attribute_group tegra_mc_dram_##_name##_attr_group = {    \
515         .attrs = tegra_mc_dram_##_name##_attrs,                         \
516 };
517
518 static struct kobject *tegra_mc_dram_kobj;
519
520 static ssize_t tegra_mc_dram_show(struct kobject *kobj,
521         struct kobj_attribute *attr, char *buf, int index)
522 {
523         if (index >= EMC_DRAM_STAT_END - EMC_DRAM_STAT_BEGIN)
524                 return -EINVAL;
525
526         if (strcmp(attr->attr.name, "enable") == 0)
527                 return sprintf(buf, "%d\n", dram_counters[index].enabled);
528         else if (strcmp(attr->attr.name, "device_mask") == 0)
529                 return sprintf(buf, "%d\n", dram_counters[index].device_mask);
530         else
531                 return -EINVAL;
532 }
533 static ssize_t tegra_mc_dram_store(struct kobject *kobj,
534         struct kobj_attribute *attr, const char *buf, size_t count, int index)
535 {
536         int value;
537
538         if (index >= EMC_DRAM_STAT_END - EMC_DRAM_STAT_BEGIN)
539                 return -EINVAL;
540
541         if (strcmp(attr->attr.name, "enable") == 0) {
542                 sscanf(buf, "%d\n", &value);
543                 if (value == 0 || value == 1)
544                         dram_counters[index].enabled = value;
545                 else
546                         return -EINVAL;
547
548                 return count;
549         } else if (strcmp(attr->attr.name, "device_mask") == 0) {
550                 sscanf(buf, "%d\n", &value);
551                 dram_counters[index].device_mask = (u8)value;
552
553                 return count;
554         } else
555                 return -EINVAL;
556 }
557
558 dram_counters(DEFINE_SYSFS)
559
560 /* Tegra Statistics */
561 typedef struct {
562         void __iomem *mmio;
563 } tegra_device_t;
564
565 static tegra_device_t mc = {
566         .mmio = IO_ADDRESS(TEGRA_MC_BASE),
567 };
568
569 static tegra_device_t emc = {
570         .mmio = IO_ADDRESS(TEGRA_EMC_BASE),
571 };
572
573 void mc_stat_start(tegra_mc_counter_t *counter0, tegra_mc_counter_t *counter1)
574 {
575         struct tegra_mc_counter *c;
576         u32 filter_client = ARMC_STAT_CONTROL_FILTER_CLIENT_DISABLE;
577         u32 filter_addr = ARMC_STAT_CONTROL_FILTER_ADDR_DISABLE;
578
579         if (!tegra_mc_client_0_enabled)
580                 return;
581
582         c = (counter0->enabled) ? counter0 : counter1;
583
584         /* disable statistics */
585         writel((MC_STAT_CONTROL_0_EMC_GATHER_DISABLE << MC_STAT_CONTROL_0_EMC_GATHER_SHIFT),
586                 mc.mmio + MC_STAT_CONTROL_0);
587
588         if (c->enabled && c->mode == FILTER_ADDR)
589                 filter_addr = ARMC_STAT_CONTROL_FILTER_ADDR_ENABLE;
590         else if (c->enabled && c->mode == FILTER_CLIENT)
591                 filter_client = ARMC_STAT_CONTROL_FILTER_CLIENT_ENABLE;
592
593         filter_addr <<= ARMC_STAT_CONTROL_FILTER_ADDR_SHIFT;
594         filter_client <<= ARMC_STAT_CONTROL_FILTER_CLIENT_SHIFT;
595
596         if (c->enabled) {
597                 u32 reg = 0;
598                 reg |= (ARMC_STAT_CONTROL_MODE_BANDWIDTH <<
599                         ARMC_STAT_CONTROL_MODE_SHIFT);
600                 reg |= (ARMC_STAT_CONTROL_EVENT_QUALIFIED <<
601                         ARMC_STAT_CONTROL_EVENT_SHIFT);
602                 reg |= (ARMC_STAT_CONTROL_FILTER_PRI_DISABLE <<
603                         ARMC_STAT_CONTROL_FILTER_PRI_SHIFT);
604                 reg |= (ARMC_STAT_CONTROL_FILTER_COALESCED_DISABLE <<
605                         ARMC_STAT_CONTROL_FILTER_COALESCED_SHIFT);
606                 reg |= filter_client;
607                 reg |= filter_addr;
608                 reg |= (c->clients[c->current_client_index] <<
609                         ARMC_STAT_CONTROL_CLIENT_ID_SHIFT);
610
611                 /* note these registers are shared */
612                 writel(c->address_low,
613                        mc.mmio + MC_STAT_EMC_ADDR_LOW_0);
614                 writel((c->address_low + c->address_length),
615                        mc.mmio + MC_STAT_EMC_ADDR_HIGH_0);
616                 writel(0xFFFFFFFF, mc.mmio + MC_STAT_EMC_CLOCK_LIMIT_0);
617
618                 writel(reg, mc.mmio + MC_STAT_EMC_CONTROL_0_0);
619         }
620
621         /* reset then enable statistics */
622         writel((MC_STAT_CONTROL_0_EMC_GATHER_CLEAR << MC_STAT_CONTROL_0_EMC_GATHER_SHIFT),
623                 mc.mmio + MC_STAT_CONTROL_0);
624
625         writel((MC_STAT_CONTROL_0_EMC_GATHER_ENABLE << MC_STAT_CONTROL_0_EMC_GATHER_SHIFT),
626                 mc.mmio + MC_STAT_CONTROL_0);
627 }
628
629 void mc_stat_stop(tegra_mc_counter_t *counter0,
630         tegra_mc_counter_t *counter1)
631 {
632         u32 total_counts = readl(mc.mmio + MC_STAT_EMC_CLOCKS_0);
633
634         /* Disable statistics */
635         writel((MC_STAT_CONTROL_0_EMC_GATHER_DISABLE << MC_STAT_CONTROL_0_EMC_GATHER_SHIFT),
636                 mc.mmio + MC_STAT_CONTROL_0);
637
638         if (counter0->enabled) {
639                 counter0->sample_data.client_counts = readl(mc.mmio + MC_STAT_EMC_COUNT_0_0);
640                 counter0->sample_data.total_counts = total_counts;
641                 counter0->sample_data.emc_clock_rate = clk_get_rate(emc_clock);
642         }
643         else {
644                 counter1->sample_data.client_counts = readl(mc.mmio + MC_STAT_EMC_COUNT_1_0);
645                 counter1->sample_data.total_counts = total_counts;
646                 counter1->sample_data.emc_clock_rate = clk_get_rate(emc_clock);
647         }
648 }
649
650 void emc_stat_start(tegra_mc_counter_t *llp_counter,
651         tegra_emc_dram_counter_t *dram_counter)
652 {
653         u32 llmc_stat = 0;
654         u32 llmc_ctrl =
655                 (AREMC_STAT_CONTROL_MODE_BANDWIDTH <<
656                         AREMC_STAT_CONTROL_MODE_SHIFT) |
657                 (AREMC_STAT_CONTROL_CLIENT_TYPE_MPCORER <<
658                         AREMC_STAT_CONTROL_CLIENT_TYPE_SHIFT) |
659                 (AREMC_STAT_CONTROL_EVENT_QUALIFIED <<
660                         AREMC_STAT_CONTROL_EVENT_SHIFT);
661
662         /* disable statistics */
663         llmc_stat |= (EMC_STAT_CONTROL_0_LLMC_GATHER_DISABLE <<
664                         EMC_STAT_CONTROL_0_LLMC_GATHER_SHIFT);
665         llmc_stat |= (EMC_STAT_CONTROL_0_DRAM_GATHER_DISABLE <<
666                         EMC_STAT_CONTROL_0_DRAM_GATHER_SHIFT);
667         writel(llmc_stat, emc.mmio + EMC_STAT_CONTROL_0);
668
669         if (tegra_mc_client_0_enabled && llp_counter->enabled) {
670                 if (llp_counter->mode == FILTER_ADDR) {
671                         llmc_ctrl |=
672                                 (AREMC_STAT_CONTROL_FILTER_ADDR_ENABLE <<
673                                  AREMC_STAT_CONTROL_FILTER_ADDR_SHIFT);
674                         llmc_ctrl |=
675                                 (AREMC_STAT_CONTROL_FILTER_CLIENT_DISABLE <<
676                                  AREMC_STAT_CONTROL_FILTER_CLIENT_SHIFT);
677                 } else if (llp_counter->mode == FILTER_CLIENT) {
678                         /* not allow aggregate client in client mode */
679                         llmc_ctrl |=
680                                 (AREMC_STAT_CONTROL_FILTER_ADDR_DISABLE <<
681                                  AREMC_STAT_CONTROL_FILTER_ADDR_SHIFT);
682                         llmc_ctrl |=
683                                 (AREMC_STAT_CONTROL_FILTER_CLIENT_DISABLE <<
684                                  AREMC_STAT_CONTROL_FILTER_CLIENT_SHIFT);
685                 } else if (llp_counter->mode == FILTER_NONE) {
686                         llmc_ctrl |=
687                                 (AREMC_STAT_CONTROL_FILTER_ADDR_DISABLE <<
688                                  AREMC_STAT_CONTROL_FILTER_ADDR_SHIFT);
689                         llmc_ctrl |=
690                                 (AREMC_STAT_CONTROL_FILTER_CLIENT_DISABLE <<
691                                  AREMC_STAT_CONTROL_FILTER_CLIENT_SHIFT);
692                 }
693
694                 writel(llp_counter->address_low,
695                        emc.mmio + EMC_STAT_LLMC_ADDR_LOW_0);
696                 writel( (llp_counter->address_low + llp_counter->address_length),
697                        emc.mmio + EMC_STAT_LLMC_ADDR_HIGH_0);
698                 writel(0xFFFFFFFF, emc.mmio + EMC_STAT_LLMC_CLOCK_LIMIT_0);
699                 writel(llmc_ctrl, emc.mmio + EMC_STAT_LLMC_CONTROL_0_0);
700         }
701
702         writel(0xFFFFFFFF, emc.mmio + EMC_STAT_DRAM_CLOCK_LIMIT_LO_0);
703         writel(0xFF, emc.mmio + EMC_STAT_DRAM_CLOCK_LIMIT_HI_0);
704
705         llmc_stat = 0;
706         /* Reset then enable statistics */
707         llmc_stat |= (EMC_STAT_CONTROL_0_LLMC_GATHER_CLEAR <<
708                         EMC_STAT_CONTROL_0_LLMC_GATHER_SHIFT);
709         llmc_stat |= (EMC_STAT_CONTROL_0_DRAM_GATHER_CLEAR <<
710                         EMC_STAT_CONTROL_0_DRAM_GATHER_SHIFT);
711         writel(llmc_stat, emc.mmio + EMC_STAT_CONTROL_0);
712
713         llmc_stat = 0;
714         llmc_stat |= (EMC_STAT_CONTROL_0_LLMC_GATHER_ENABLE <<
715                         EMC_STAT_CONTROL_0_LLMC_GATHER_SHIFT);
716         llmc_stat |= (EMC_STAT_CONTROL_0_DRAM_GATHER_ENABLE <<
717                         EMC_STAT_CONTROL_0_DRAM_GATHER_SHIFT);
718         writel(llmc_stat, emc.mmio + EMC_STAT_CONTROL_0);
719 }
720
721 void emc_stat_stop(tegra_mc_counter_t *llp_counter,
722         tegra_emc_dram_counter_t *dram_counter)
723 {
724         u32 llmc_stat = 0;
725         int i;
726         int dev0_offsets_lo[] = {
727                 EMC_STAT_DRAM_DEV0_ACTIVATE_CNT_LO_0,
728                 EMC_STAT_DRAM_DEV0_READ_CNT_LO_0,
729                 EMC_STAT_DRAM_DEV0_WRITE_CNT_LO_0,
730                 EMC_STAT_DRAM_DEV0_REF_CNT_LO_0,
731                 EMC_STAT_DRAM_DEV0_CUMM_BANKS_ACTIVE_CKE_EQ1_LO_0,
732                 EMC_STAT_DRAM_DEV0_CUMM_BANKS_ACTIVE_CKE_EQ0_LO_0,
733                 EMC_STAT_DRAM_DEV0_CKE_EQ1_CLKS_LO_0,
734                 EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_LO_0,
735                 EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_LO_0,
736                 EMC_STAT_DRAM_DEV0_NO_BANKS_ACTIVE_CKE_EQ1_LO_0,
737                 EMC_STAT_DRAM_DEV0_NO_BANKS_ACTIVE_CKE_EQ0_LO_0,
738         };
739         int dev0_offsets_hi[] = {
740                 EMC_STAT_DRAM_DEV0_ACTIVATE_CNT_HI_0,
741                 EMC_STAT_DRAM_DEV0_READ_CNT_HI_0,
742                 EMC_STAT_DRAM_DEV0_WRITE_CNT_HI_0,
743                 EMC_STAT_DRAM_DEV0_REF_CNT_HI_0,
744                 EMC_STAT_DRAM_DEV0_CUMM_BANKS_ACTIVE_CKE_EQ1_HI_0,
745                 EMC_STAT_DRAM_DEV0_CUMM_BANKS_ACTIVE_CKE_EQ0_HI_0,
746                 EMC_STAT_DRAM_DEV0_CKE_EQ1_CLKS_HI_0,
747                 EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_HI_0,
748                 EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_HI_0,
749                 EMC_STAT_DRAM_DEV0_NO_BANKS_ACTIVE_CKE_EQ1_HI_0,
750                 EMC_STAT_DRAM_DEV0_NO_BANKS_ACTIVE_CKE_EQ0_HI_0,
751         };
752         int dev1_offsets_lo[] = {
753                 EMC_STAT_DRAM_DEV1_ACTIVATE_CNT_LO_0,
754                 EMC_STAT_DRAM_DEV1_READ_CNT_LO_0,
755                 EMC_STAT_DRAM_DEV1_WRITE_CNT_LO_0,
756                 EMC_STAT_DRAM_DEV1_REF_CNT_LO_0,
757                 EMC_STAT_DRAM_DEV1_CUMM_BANKS_ACTIVE_CKE_EQ1_LO_0,
758                 EMC_STAT_DRAM_DEV1_CUMM_BANKS_ACTIVE_CKE_EQ0_LO_0,
759                 EMC_STAT_DRAM_DEV1_CKE_EQ1_CLKS_LO_0,
760                 EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_LO_0,
761                 EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_LO_0,
762                 EMC_STAT_DRAM_DEV1_NO_BANKS_ACTIVE_CKE_EQ1_LO_0,
763                 EMC_STAT_DRAM_DEV1_NO_BANKS_ACTIVE_CKE_EQ0_LO_0,
764         };
765         int dev1_offsets_hi[] = {
766                 EMC_STAT_DRAM_DEV1_ACTIVATE_CNT_HI_0,
767                 EMC_STAT_DRAM_DEV1_READ_CNT_HI_0,
768                 EMC_STAT_DRAM_DEV1_WRITE_CNT_HI_0,
769                 EMC_STAT_DRAM_DEV1_REF_CNT_HI_0,
770                 EMC_STAT_DRAM_DEV1_CUMM_BANKS_ACTIVE_CKE_EQ1_HI_0,
771                 EMC_STAT_DRAM_DEV1_CUMM_BANKS_ACTIVE_CKE_EQ0_HI_0,
772                 EMC_STAT_DRAM_DEV1_CKE_EQ1_CLKS_HI_0,
773                 EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_HI_0,
774                 EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_HI_0,
775                 EMC_STAT_DRAM_DEV1_NO_BANKS_ACTIVE_CKE_EQ1_HI_0,
776                 EMC_STAT_DRAM_DEV1_NO_BANKS_ACTIVE_CKE_EQ0_HI_0,
777         };
778
779         /* Disable statistics */
780         llmc_stat |= (EMC_STAT_CONTROL_0_LLMC_GATHER_DISABLE <<
781                         EMC_STAT_CONTROL_0_LLMC_GATHER_SHIFT);
782         llmc_stat |= (EMC_STAT_CONTROL_0_DRAM_GATHER_DISABLE <<
783                         EMC_STAT_CONTROL_0_DRAM_GATHER_SHIFT);
784         writel(llmc_stat, emc.mmio + EMC_STAT_CONTROL_0);
785
786         if (tegra_mc_client_0_enabled == true && llp_counter->enabled) {
787                 u32 total_counts = readl(mc.mmio + MC_STAT_EMC_CLOCKS_0);
788                 llp_counter->sample_data.client_counts = readl(emc.mmio + EMC_STAT_LLMC_COUNT_0_0);
789                 llp_counter->sample_data.total_counts = total_counts;
790                 llp_counter->sample_data.emc_clock_rate = clk_get_rate(emc_clock);
791         }
792
793         for (i = 0; i < EMC_DRAM_STAT_END - EMC_DRAM_STAT_BEGIN; i++) {
794                 if (dram_counter[i].enabled) {
795
796                         dram_counter[i].sample_data.client_counts = 0;
797                         dram_counter[i].sample_data.emc_clock_rate = clk_get_rate(emc_clock);
798
799                         if (!(dram_counter[i].device_mask & 0x1)) {
800                                 if (readl(emc.mmio + dev0_offsets_hi[i]) != 0) {
801                                         dram_counter[i].sample_data.client_counts = 0xFFFFFFFF;
802                                         continue;
803                                 }
804                                 dram_counter[i].sample_data.client_counts +=
805                                         readl(emc.mmio + dev0_offsets_lo[i]);
806                         }
807
808                         if (!(dram_counter[i].device_mask & 0x2)) {
809                                 if (readl(emc.mmio + dev1_offsets_hi[i]) != 0) {
810                                         dram_counter[i].sample_data.client_counts = 0xFFFFFFFF;
811                                         continue;
812                                 }
813                                 dram_counter[i].sample_data.client_counts +=
814                                         readl(emc.mmio + dev1_offsets_lo[i]);
815                         }
816                 }
817         }
818 }
819
820 static void stat_start(void)
821 {
822         mc_stat_start(&mc_counter0, &mc_counter1);
823         emc_stat_start(&emc_llp_counter, dram_counters);
824 }
825
826 static void stat_stop(void)
827 {
828         mc_stat_stop(&mc_counter0, &mc_counter1);
829         emc_stat_stop(&emc_llp_counter, dram_counters);
830 }
831
832 #define statcpy(_buf, _bufstart, _buflen, _elem)        \
833         do {                                            \
834                 size_t s = sizeof(_elem);               \
835                 memcpy(_buf, &_elem, s);                \
836                 _buf += s;                              \
837                 if (_buf >= _bufstart + _buflen)        \
838                         _buf = _bufstart;               \
839         } while (0);
840
841 static void stat_log(void)
842 {
843         int             i;
844         unsigned long   flags;
845
846         struct tegra_mc_counter *counters[] = {
847                 &mc_counter0,
848                 &mc_counter1,
849                 &emc_llp_counter
850         };
851
852         spin_lock_irqsave(&sample_log_lock, flags);
853
854         if (tegra_mc_client_0_enabled) {
855                 for (i = 0; i < ARRAY_SIZE(counters); i++) {
856                         struct tegra_mc_counter *c = counters[i];
857
858                         if (!c->enabled)
859                                 continue;
860
861                         c->sample_data.client_number = c->clients[c->current_client_index];
862
863                         c->current_client_index++;
864                         if (c->current_client_index == c->total_clients)
865                                 c->current_client_index = 0;
866
867                         statcpy(sample_log_wptr, sample_log,
868                                 SAMPLE_LOG_SIZE, c->sample_data);
869                 }
870         }
871
872         for (i = 0; i < EMC_DRAM_STAT_END - EMC_DRAM_STAT_BEGIN; i++) {
873                 if (dram_counters[i].enabled) {
874                         statcpy(sample_log_wptr, sample_log,
875                                 SAMPLE_LOG_SIZE, dram_counters[i].sample_data);
876                 }
877         }
878
879         spin_unlock_irqrestore(&sample_log_lock, flags);
880 }
881
882 static enum hrtimer_restart sample_timer_function(struct hrtimer *handle)
883 {
884         stat_stop();
885         stat_log();
886
887         if (!sample_enable)
888                 return HRTIMER_NORESTART;
889
890         stat_start();
891
892         hrtimer_add_expires_ns(&sample_timer, (u64)sample_quantum * 1000000);
893         return HRTIMER_RESTART;
894 }
895
896 /* module init */
897 #define REGISTER_SYSFS(_name, _val)                                     \
898         tegra_mc_dram_##_name##_kobj =                                  \
899                 kobject_create_and_add(#_name, tegra_mc_dram_kobj);     \
900         if (sysfs_create_group(tegra_mc_dram_##_name##_kobj,            \
901                            &tegra_mc_dram_##_name##_attr_group))        \
902                 printk(KERN_ERR "\n sysfs_create_group failed at %s"    \
903                                 " line %d\n", __FILE__, __LINE__);
904
905 static int tegra_mc_init(void)
906 {
907         int i;
908         int rc;
909
910         /* /sys/devices/system/tegra_mc */
911         rc = sysdev_class_register(&tegra_mc_sysclass);
912         if(rc)
913                 goto out;
914
915         for (i = 0;  i < ARRAY_SIZE(tegra_mc_attrs)-1; i++) {
916                 rc = sysdev_class_create_file(&tegra_mc_sysclass,
917                         tegra_mc_attrs[i]);
918                 if(rc) {
919                         printk("\n sysdev_class_create_file : failed \n");
920                         goto out_unreg_class;
921                 }
922         }
923
924         /* /sys/devices/system/tegra_mc/client */
925         tegra_mc_client_kobj = kobject_create_and_add("client",
926                 &tegra_mc_sysclass.kset.kobj);
927         if(!tegra_mc_client_kobj)
928                 goto out_remove_sysdev_files;
929
930         tegra_mc_client_0_kobj = kobject_create_and_add("0",
931                 tegra_mc_client_kobj);
932         if(!tegra_mc_client_0_kobj)
933                 goto out_put_kobject_client;
934
935         rc = sysfs_create_group(tegra_mc_client_0_kobj,
936                 &tegra_mc_client_0_attr_group);
937         if(rc)
938                 goto out_put_kobject_client_0;
939
940         /* /sys/devices/system/tegra_mc/dram */
941         tegra_mc_dram_kobj = kobject_create_and_add("dram",
942                 &tegra_mc_sysclass.kset.kobj);
943         if(!tegra_mc_dram_kobj)
944                 goto out_remove_group_client_0;
945
946         dram_counters(REGISTER_SYSFS)
947
948         /* hrtimer */
949         hrtimer_init(&sample_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
950         sample_timer.function = sample_timer_function;
951
952         for (i = 0; i < EMC_DRAM_STAT_END - EMC_DRAM_STAT_BEGIN; i++) {
953                 dram_counters[i].sample_data.client_number = EMC_DRAM_STAT_BEGIN + i;
954                 dram_counters[i].sample_data.signature = 0xdeadbeef;
955         }
956
957         emc_clock = clk_get_sys(NULL, "emc");
958         if (!emc_clock) {
959                 pr_err("Could not get EMC clock\n");
960                 goto out_remove_group_client_0;
961         }
962
963         return 0;
964
965 out_remove_group_client_0:
966         sysfs_remove_group(tegra_mc_client_0_kobj, &tegra_mc_client_0_attr_group);
967
968 out_put_kobject_client_0:
969         kobject_put(tegra_mc_client_0_kobj);
970
971 out_put_kobject_client:
972         kobject_put(tegra_mc_client_kobj);
973
974 out_remove_sysdev_files:
975         for (i = 0;  i < ARRAY_SIZE(tegra_mc_attrs)-1; i++) {
976                 sysdev_class_remove_file(&tegra_mc_sysclass, tegra_mc_attrs[i]);
977         }
978
979 out_unreg_class:
980         sysdev_class_unregister(&tegra_mc_sysclass);
981
982 out:
983         return rc;
984 }
985
986 /* module deinit */
987 #define REMOVE_SYSFS(_name, _val)                                       \
988         sysfs_remove_group(tegra_mc_dram_##_name##_kobj,                \
989                            &tegra_mc_dram_##_name##_attr_group);        \
990         kobject_put(tegra_mc_dram_##_name##_kobj);
991
992 static void tegra_mc_exit(void)
993 {
994         int i;
995
996         stat_stop();
997
998         /* hrtimer */
999         hrtimer_cancel(&sample_timer);
1000
1001         /* /sys/devices/system/tegra_mc/client */
1002         sysfs_remove_group(tegra_mc_client_0_kobj,
1003                 &tegra_mc_client_0_attr_group);
1004         kobject_put(tegra_mc_client_0_kobj);
1005         kobject_put(tegra_mc_client_kobj);
1006
1007         /* /sys/devices/system/tegra_mc/dram */
1008         dram_counters(REMOVE_SYSFS)
1009         kobject_put(tegra_mc_dram_kobj);
1010
1011         /* /sys/devices/system/tegra_mc */
1012         for (i = 0;  i < ARRAY_SIZE(tegra_mc_attrs)-1; i++) {
1013                 sysdev_class_remove_file(&tegra_mc_sysclass, tegra_mc_attrs[i]);
1014         }
1015         sysdev_class_unregister(&tegra_mc_sysclass);
1016 }
1017
1018 module_init(tegra_mc_init);
1019 module_exit(tegra_mc_exit);
1020 MODULE_LICENSE("Dual BSD/GPL");