ARM: tegra12: set CPU rate to 2.2GHz for sku 0x87
[linux-3.10.git] / arch / arm / mach-tegra / sysfs-cluster.c
1 /*
2  * arch/arm/mach-tegra/sysfs-cluster.c
3  *
4  * Copyright (c) 2010-2013, NVIDIA CORPORATION, All rights reserved.
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16
17 /*
18  * This driver creates the /sys/kernel/cluster node and attributes for CPU
19  * switch testing. Node attributes:
20  *
21  * active: currently active CPU (G or LP)
22  *              write:  'g'      = switch to G CPU
23  *                      'lp'     = switch to LP CPU
24  *                      'toggle' = switch to the other CPU
25  *              read: returns the currently active CPU (g or lp)
26  *
27  * force: force switch even if already on target CPU
28  *              write:  '0' = do not perform switch if
29  *                            active CPU == target CPU (default)
30  *                      '1' = force switch regardless of
31  *                            currently active CPU
32  *              read: returns the current status of the force flag
33  *
34  * immediate: request immediate wake-up from switch request
35  *              write:  '0' = non-immediate wake-up on next interrupt (default)
36  *                      '1' = immediate wake-up
37  *              read: returns the current status of the immediate flag
38  *
39  * power_mode: power mode to use for switch (LP1 or LP2)
40  *              write:  '1' = use LP1 power mode
41  *                      '2' = use LP2 power mode (default)
42  *              read: returns the current status of the immediate flag
43  *
44  * wake_ms: wake time (in milliseconds) -- ignored if immediate==1
45  *              write:  '0' = wake up at the next non-timer interrupt
46  *                      'n' = (n > 0) wake-up after 'n' milliseconds or the
47  *                            next non-timer interrupt (whichever comes first)
48  *              read: returns the current wake_ms value
49  *
50  * power_gate: additional power gate partitions
51  *              write:  'none' = no additional partitions
52  *                      'noncpu' = CxNC partition
53  *                      'crail' = CRAIL partition (implies noncpu also, default)
54  *              read: returns the current power_gate value
55  *
56  * Writing the force, immediate and wake_ms attributes simply updates the
57  * state of internal variables that will be used for the next switch request.
58  * Writing to the active attribute initates a switch request using the
59  * current values of the force, immediate, and wake_ms attributes.
60  *
61  * The OS tick timer is not a valid interrupt source for waking up following
62  * a switch request. This is because the kernel uses local timers that are
63  * part of the CPU complex. These get shut down when the CPU complex is
64  * placed into reset by the switch request. If you want a timed wake up
65  * from a switch, you must specify a positive wake_ms value. This will
66  * ensure that a non-local timer is programmed to fire an interrupt
67  * after the desired interval.
68  *
69  */
70
71 #include <linux/module.h>
72 #include <linux/kernel.h>
73 #include <linux/sysfs.h>
74 #include <linux/kobject.h>
75 #include <linux/smp.h>
76 #include <linux/io.h>
77 #include <linux/clk.h>
78
79 #include "clock.h"
80 #include "iomap.h"
81 #include "sleep.h"
82 #include "pm.h"
83
84 #define SYSFS_CLUSTER_PRINTS       1    /* Nonzero: enable status prints */
85 #define SYSFS_CLUSTER_TRACE_PRINTS 0    /* Nonzero: enable trace prints */
86 #define SYSFS_CLUSTER_POWER_MODE   1    /* Nonzero: use power modes other than LP2*/
87
88 #if SYSFS_CLUSTER_TRACE_PRINTS
89 #define TRACE_CLUSTER(x) printk x
90 #else
91 #define TRACE_CLUSTER(x)
92 #endif
93
94 #if SYSFS_CLUSTER_PRINTS
95 #define PRINT_CLUSTER(x) printk x
96 #else
97 #define PRINT_CLUSTER(x)
98 #endif
99
100 static struct kobject *cluster_kobj;
101 static spinlock_t cluster_lock;
102 static unsigned int flags = 0;
103 static unsigned int wake_ms = 0;
104
105 static ssize_t sysfscluster_show(struct kobject *kobj,
106                 struct kobj_attribute *attr, char *buf);
107
108 static ssize_t sysfscluster_store(struct kobject *kobj,
109                 struct kobj_attribute *attr, const char *buf, size_t count);
110
111 /* Active CPU: "G", "LP", "toggle" */
112 static struct kobj_attribute cluster_active_attr =
113                 __ATTR(active, 0640, sysfscluster_show, sysfscluster_store);
114
115 /* Immediate wake-up when performing switch: 0, 1 */
116 static struct kobj_attribute cluster_immediate_attr =
117                 __ATTR(immediate, 0640, sysfscluster_show, sysfscluster_store);
118
119 /* Force power transition even if already on the desired CPU: 0, 1 */
120 static struct kobj_attribute cluster_force_attr =
121                 __ATTR(force, 0640, sysfscluster_show, sysfscluster_store);
122
123 /* Wake time (in milliseconds) */
124 static struct kobj_attribute cluster_wake_ms_attr =
125                 __ATTR(wake_ms, 0640, sysfscluster_show, sysfscluster_store);
126
127 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
128 /* LPx power mode to use when switching CPUs: 1=LP1, 2=LP2 */
129 static unsigned int power_mode = 2;
130 static struct kobj_attribute cluster_powermode_attr =
131                 __ATTR(power_mode, 0640, sysfscluster_show, sysfscluster_store);
132 #endif
133
134 #ifdef CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE
135 /* Additional partitions to power gate. */
136 static unsigned int power_gate = TEGRA_POWER_CLUSTER_PART_CRAIL;
137 static struct kobj_attribute cluster_powergate_attr =
138                 __ATTR(power_gate, 0640, sysfscluster_show, sysfscluster_store);
139
140 static const char *decode_power_gate(unsigned int mode)
141 {
142         if (mode & TEGRA_POWER_CLUSTER_PART_CRAIL)
143                 return "crail";
144         else if (mode & TEGRA_POWER_CLUSTER_PART_NONCPU)
145                 return "noncpu";
146         else
147                 return "none";
148 }
149
150 #endif
151
152 #if DEBUG_CLUSTER_SWITCH
153 unsigned int tegra_cluster_debug = 0;
154 static struct kobj_attribute cluster_debug_attr =
155                 __ATTR(debug, 0640, sysfscluster_show, sysfscluster_store);
156 #endif
157
158 typedef enum
159 {
160         CLUSTER_ATTR_INVALID = 0,
161         CLUSTER_ATTR_ACTIVE,
162         CLUSTER_ATTR_IMME,
163         CLUSTER_ATTR_FORCE,
164         CLUSTER_ATTR_WAKEMS,
165 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
166         CLUSTER_ATTR_POWERMODE,
167 #endif
168 #ifdef CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE
169         CLUSTER_ATTR_POWERGATE,
170 #endif
171 #if DEBUG_CLUSTER_SWITCH
172         CLUSTER_ATTR_DEBUG
173 #endif
174 } cpu_cluster_attr;
175
176 static cpu_cluster_attr cpu_cluster_get_attr(const char *name)
177 {
178         if (!strcmp(name, "active"))
179                 return CLUSTER_ATTR_ACTIVE;
180         if (!strcmp(name, "immediate"))
181                 return CLUSTER_ATTR_IMME;
182         if (!strcmp(name, "force"))
183                 return CLUSTER_ATTR_FORCE;
184         if (!strcmp(name, "wake_ms"))
185                 return CLUSTER_ATTR_WAKEMS;
186 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
187         if (!strcmp(name, "power_mode"))
188                 return CLUSTER_ATTR_POWERMODE;
189 #endif
190 #ifdef CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE
191         if (!strcmp(name, "power_gate"))
192                 return CLUSTER_ATTR_POWERGATE;
193 #endif
194 #if DEBUG_CLUSTER_SWITCH
195         if (!strcmp(name, "debug"))
196                 return CLUSTER_ATTR_DEBUG;
197 #endif
198         TRACE_CLUSTER(("cpu_cluster_get_attr(%s): invalid\n", name));
199         return CLUSTER_ATTR_INVALID;
200 }
201
202 static ssize_t sysfscluster_show(struct kobject *kobj,
203                 struct kobj_attribute *attr, char *buf)
204 {
205         cpu_cluster_attr type;
206         ssize_t len;
207
208         TRACE_CLUSTER(("+sysfscluster_show\n"));
209
210         type = cpu_cluster_get_attr(attr->attr.name);
211         switch (type) {
212         case CLUSTER_ATTR_ACTIVE:
213                 len = sprintf(buf, "%s\n", is_lp_cluster() ? "LP" : "G");
214                 break;
215
216         case CLUSTER_ATTR_IMME:
217                 len = sprintf(buf, "%d\n",
218                               ((flags & TEGRA_POWER_CLUSTER_IMMEDIATE) != 0));
219                 break;
220
221         case CLUSTER_ATTR_FORCE:
222                 len = sprintf(buf, "%d\n",
223                               ((flags & TEGRA_POWER_CLUSTER_FORCE) != 0));
224                 break;
225
226         case CLUSTER_ATTR_WAKEMS:
227                 len = sprintf(buf, "%d\n", wake_ms);
228                 break;
229
230 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
231         case CLUSTER_ATTR_POWERMODE:
232                 len = sprintf(buf, "%d\n", power_mode);
233                 break;
234 #endif
235
236 #ifdef CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE
237         case CLUSTER_ATTR_POWERGATE:
238                 len = sprintf(buf, "%s\n", decode_power_gate(power_gate));
239                 break;
240 #endif
241
242 #if DEBUG_CLUSTER_SWITCH
243         case CLUSTER_ATTR_DEBUG:
244                 len = sprintf(buf, "%d\n", tegra_cluster_debug);
245                 break;
246 #endif
247
248         default:
249                 len = sprintf(buf, "invalid\n");
250                 break;
251         }
252
253         TRACE_CLUSTER(("-sysfscluster_show\n"));
254         return len;
255 }
256
257 static ssize_t sysfscluster_store(struct kobject *kobj,
258         struct kobj_attribute *attr, const char *buf, size_t count)
259 {
260         cpu_cluster_attr type;
261         ssize_t ret = count--;
262         unsigned request;
263         int e;
264         int tmp;
265         int cnt;
266         struct clk *cpu_clk = tegra_get_clock_by_name("cpu");
267         struct clk *cpu_g_clk = tegra_get_clock_by_name("cpu_g");
268         struct clk *cpu_lp_clk = tegra_get_clock_by_name("cpu_lp");
269         struct clk *new_parent = NULL;
270
271         if (!cpu_clk || !cpu_g_clk || !cpu_lp_clk) {
272                 ret = -ENOSYS;
273                 goto fail;
274         }
275
276         TRACE_CLUSTER(("+sysfscluster_store: %p, %d\n", buf, count));
277
278         /* The count includes data bytes follow by a line feed character. */
279         if (!buf || (count < 1)) {
280                 ret = -EINVAL;
281                 goto fail;
282         }
283
284         type = cpu_cluster_get_attr(attr->attr.name);
285
286         spin_lock(&cluster_lock);
287
288         switch (type) {
289         case CLUSTER_ATTR_ACTIVE:
290                 if (!strncasecmp(buf, "g", count)) {
291                         flags &= ~TEGRA_POWER_CLUSTER_MASK;
292                         flags |= TEGRA_POWER_CLUSTER_G;
293                 } else if (!strncasecmp(buf, "lp", count)) {
294                         flags &= ~TEGRA_POWER_CLUSTER_MASK;
295                         flags |= TEGRA_POWER_CLUSTER_LP;
296                 } else if (!strncasecmp(buf, "toggle", count)) {
297                         flags &= ~TEGRA_POWER_CLUSTER_MASK;
298                         if (is_lp_cluster())
299                                 flags |= TEGRA_POWER_CLUSTER_G;
300                         else
301                                 flags |= TEGRA_POWER_CLUSTER_LP;
302                 } else {
303                         PRINT_CLUSTER(("cluster/active: '%*.*s' invalid, "
304                                 " must be g, lp, or toggle\n",
305                                 count, count, buf));
306                         ret = -EINVAL;
307                         break;
308                 }
309                 PRINT_CLUSTER(("cluster/active -> %s\n",
310                         (flags & TEGRA_POWER_CLUSTER_G) ? "G" : "LP"));
311
312                 request = flags;
313 #ifdef CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE
314                 request |= power_gate;
315 #endif
316 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
317                 if (power_mode == 1) {
318                         request |= TEGRA_POWER_SDRAM_SELFREFRESH;
319                 }
320 #endif
321                 tegra_cluster_switch_set_parameters(wake_ms * 1000, request);
322                 new_parent = (flags & TEGRA_POWER_CLUSTER_LP) ?
323                         cpu_lp_clk : cpu_g_clk;
324                 break;
325
326         case CLUSTER_ATTR_IMME:
327                 if ((count == 1) && (*buf == '0'))
328                         flags &= ~TEGRA_POWER_CLUSTER_IMMEDIATE;
329                 else if ((count == 1) && *buf == '1')
330                         flags |= TEGRA_POWER_CLUSTER_IMMEDIATE;
331                 else {
332                         PRINT_CLUSTER(("cluster/immediate: '%*.*s' invalid, "
333                                 "must be 0 or 1\n", count, count, buf));
334                         ret = -EINVAL;
335                         break;
336                 }
337                 PRINT_CLUSTER(("cluster/immediate -> %c\n",
338                         (flags & TEGRA_POWER_CLUSTER_IMMEDIATE) ? '1' : '0'));
339                 break;
340
341         case CLUSTER_ATTR_FORCE:
342                 if ((count == 1) && (*buf == '0'))
343                         flags &= ~TEGRA_POWER_CLUSTER_FORCE;
344                 else if ((count == 1) && (*buf == '1'))
345                         flags |= TEGRA_POWER_CLUSTER_FORCE;
346                 else {
347                         PRINT_CLUSTER(("cluster/force: '%*.*s' invalid, "
348                                 "must be 0 or 1\n", count, count, buf));
349                         ret = -EINVAL;
350                         break;
351                 }
352                 PRINT_CLUSTER(("cluster/force -> %c\n",
353                         (flags & TEGRA_POWER_CLUSTER_FORCE) ? '1' : '0'));
354                 break;
355
356         case CLUSTER_ATTR_WAKEMS:
357                 tmp = 0;
358                 cnt = sscanf(buf, "%d\n", &tmp);
359                 if ((cnt != 1) || (tmp < 0)) {
360                         PRINT_CLUSTER(("cluster/wake_ms: '%*.*s' is invalid\n",
361                                 count, count, buf));
362                         ret = -EINVAL;
363                         break;
364                 }
365                 wake_ms = tmp;
366                 PRINT_CLUSTER(("cluster/wake_ms -> %d\n", wake_ms));
367                 break;
368
369 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
370         case CLUSTER_ATTR_POWERMODE:
371                 if ((count == 1) && (*buf == '2'))
372                         power_mode = 2;
373                 else if ((count == 1) && *buf == '1')
374                         power_mode = 1;
375                 else {
376                         PRINT_CLUSTER(("cluster/power_mode: '%*.*s' invalid, "
377                                 "must be 2 or 1\n", count, count, buf));
378                         ret = -EINVAL;
379                         break;
380                 }
381                 PRINT_CLUSTER(("cluster/power_mode -> %d\n", power_mode));
382                 break;
383 #endif
384
385 #ifdef CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE
386         case CLUSTER_ATTR_POWERGATE:
387                 if (!strncasecmp(buf, "crail", count))
388                         power_gate = TEGRA_POWER_CLUSTER_PART_CRAIL;
389                 else if (!strncasecmp(buf, "noncpu", count))
390                         power_gate = TEGRA_POWER_CLUSTER_PART_NONCPU;
391                 else if (!strncasecmp(buf, "none", count))
392                         power_gate = 0;
393                 else {
394                         PRINT_CLUSTER(("cluster/power_gate: '%*.*s' invalid, "
395                                 "must be 'none', 'crail', or 'noncpu'\n",
396                                 count, count, buf));
397                         ret = -EINVAL;
398                         break;
399                 }
400                 PRINT_CLUSTER(("cluster/power_gate -> %s\n",
401                                 decode_power_gate(power_gate)));
402                 break;
403 #endif
404
405 #if DEBUG_CLUSTER_SWITCH
406         case CLUSTER_ATTR_DEBUG:
407                 if ((count == 1) && (*buf == '0'))
408                         tegra_cluster_debug = 0;
409                 else if ((count == 1) && (*buf == '1'))
410                         tegra_cluster_debug = 1;
411                 else {
412                         PRINT_CLUSTER(("cluster/debug: '%*.*s' invalid, "
413                                 "must be 0 or 1\n", count, count, buf));
414                         ret = -EINVAL;
415                         break;
416                 }
417                 PRINT_CLUSTER(("cluster/debug -> %d\n",tegra_cluster_debug));
418                 break;
419 #endif
420
421         default:
422                 ret = -ENOENT;
423                 break;
424         }
425
426         spin_unlock(&cluster_lock);
427
428         if (new_parent) {
429                 e = tegra_cluster_switch(cpu_clk, new_parent);
430                 if (e) {
431                         PRINT_CLUSTER(("cluster/active: request failed (%d)\n",
432                                        e));
433                         ret = e;
434                 }
435         }
436 fail:
437         TRACE_CLUSTER(("-sysfscluster_store: %d\n", count));
438         return ret;
439 }
440
441 #define CREATE_FILE(x) \
442         do { \
443                 e = sysfs_create_file(cluster_kobj, &cluster_##x##_attr.attr); \
444                 if (e) { \
445                         TRACE_CLUSTER(("cluster/" __stringify(x) \
446                                 ": sysfs_create_file failed!\n")); \
447                         goto fail; \
448                 } \
449         } while (0)
450
451 static int __init sysfscluster_init(void)
452 {
453         int e;
454
455         TRACE_CLUSTER(("+sysfscluster_init\n"));
456
457         spin_lock_init(&cluster_lock);
458         cluster_kobj = kobject_create_and_add("cluster", kernel_kobj);
459
460         CREATE_FILE(active);
461         CREATE_FILE(immediate);
462         CREATE_FILE(force);
463         CREATE_FILE(wake_ms);
464 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
465         CREATE_FILE(powermode);
466 #endif
467 #ifdef CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE
468         CREATE_FILE(powergate);
469 #endif
470 #if DEBUG_CLUSTER_SWITCH
471         CREATE_FILE(debug);
472 #endif
473
474         spin_lock(&cluster_lock);
475         if (is_lp_cluster())
476                 flags |= TEGRA_POWER_CLUSTER_LP;
477         else
478                 flags |= TEGRA_POWER_CLUSTER_G;
479         spin_unlock(&cluster_lock);
480
481 fail:
482         TRACE_CLUSTER(("-sysfscluster_init\n"));
483         return e;
484 }
485
486 #define REMOVE_FILE(x) \
487                 sysfs_remove_file(cluster_kobj, &cluster_##x##_attr.attr)
488
489 static void __exit sysfscluster_exit(void)
490 {
491         TRACE_CLUSTER(("+sysfscluster_exit\n"));
492 #if DEBUG_CLUSTER_SWITCH
493         REMOVE_FILE(debug);
494 #endif
495 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
496         REMOVE_FILE(powermode);
497 #endif
498         REMOVE_FILE(wake_ms);
499         REMOVE_FILE(force);
500         REMOVE_FILE(immediate);
501         REMOVE_FILE(active);
502         kobject_del(cluster_kobj);
503         TRACE_CLUSTER(("-sysfscluster_exit\n"));
504 }
505
506 module_init(sysfscluster_init);
507 module_exit(sysfscluster_exit);
508 MODULE_LICENSE("GPL");