video: tegra: host: Fix NULL instead of integer
[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-2014, 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 #include <linux/tegra_cluster_control.h>
79
80 #include <linux/platform/tegra/clock.h>
81 #include "iomap.h"
82 #include "sleep.h"
83 #include "pm.h"
84
85 #define SYSFS_CLUSTER_PRINTS       1    /* Nonzero: enable status prints */
86 #define SYSFS_CLUSTER_TRACE_PRINTS 0    /* Nonzero: enable trace prints */
87 #define SYSFS_CLUSTER_POWER_MODE   1    /* Nonzero: use power modes other than LP2*/
88
89 #if SYSFS_CLUSTER_TRACE_PRINTS
90 #define TRACE_CLUSTER(x) printk x
91 #else
92 #define TRACE_CLUSTER(x)
93 #endif
94
95 #if SYSFS_CLUSTER_PRINTS
96 #define PRINT_CLUSTER(x) printk x
97 #else
98 #define PRINT_CLUSTER(x)
99 #endif
100
101 static struct kobject *cluster_kobj;
102 static spinlock_t cluster_lock;
103 static unsigned int flags = 0;
104 static unsigned int wake_ms = 0;
105
106 static ssize_t sysfscluster_show(struct kobject *kobj,
107                 struct kobj_attribute *attr, char *buf);
108
109 static ssize_t sysfscluster_store(struct kobject *kobj,
110                 struct kobj_attribute *attr, const char *buf, size_t count);
111
112 /* Active CPU: "G", "LP", "toggle" */
113 static struct kobj_attribute cluster_active_attr =
114                 __ATTR(active, 0640, sysfscluster_show, sysfscluster_store);
115
116 /* Immediate wake-up when performing switch: 0, 1 */
117 static struct kobj_attribute cluster_immediate_attr =
118                 __ATTR(immediate, 0640, sysfscluster_show, sysfscluster_store);
119
120 /* Force power transition even if already on the desired CPU: 0, 1 */
121 static struct kobj_attribute cluster_force_attr =
122                 __ATTR(force, 0640, sysfscluster_show, sysfscluster_store);
123
124 /* Wake time (in milliseconds) */
125 static struct kobj_attribute cluster_wake_ms_attr =
126                 __ATTR(wake_ms, 0640, sysfscluster_show, sysfscluster_store);
127
128 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
129 /* LPx power mode to use when switching CPUs: 1=LP1, 2=LP2 */
130 static unsigned int power_mode = 2;
131 static struct kobj_attribute cluster_powermode_attr =
132                 __ATTR(power_mode, 0640, sysfscluster_show, sysfscluster_store);
133 #endif
134
135 #ifdef CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE
136 /* Additional partitions to power gate. */
137 static unsigned int power_gate = TEGRA_POWER_CLUSTER_PART_CRAIL;
138 static struct kobj_attribute cluster_powergate_attr =
139                 __ATTR(power_gate, 0640, sysfscluster_show, sysfscluster_store);
140
141 static const char *decode_power_gate(unsigned int mode)
142 {
143         if (mode & TEGRA_POWER_CLUSTER_PART_CRAIL)
144                 return "crail";
145         else if (mode & TEGRA_POWER_CLUSTER_PART_NONCPU)
146                 return "noncpu";
147         else
148                 return "none";
149 }
150
151 #endif
152
153 #if DEBUG_CLUSTER_SWITCH
154 unsigned int tegra_cluster_debug = 0;
155 static struct kobj_attribute cluster_debug_attr =
156                 __ATTR(debug, 0640, sysfscluster_show, sysfscluster_store);
157 #endif
158
159 typedef enum
160 {
161         CLUSTER_ATTR_INVALID = 0,
162         CLUSTER_ATTR_ACTIVE,
163         CLUSTER_ATTR_IMME,
164         CLUSTER_ATTR_FORCE,
165         CLUSTER_ATTR_WAKEMS,
166 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
167         CLUSTER_ATTR_POWERMODE,
168 #endif
169 #ifdef CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE
170         CLUSTER_ATTR_POWERGATE,
171 #endif
172 #if DEBUG_CLUSTER_SWITCH
173         CLUSTER_ATTR_DEBUG
174 #endif
175 } cpu_cluster_attr;
176
177 static cpu_cluster_attr cpu_cluster_get_attr(const char *name)
178 {
179         if (!strcmp(name, "active"))
180                 return CLUSTER_ATTR_ACTIVE;
181         if (!strcmp(name, "immediate"))
182                 return CLUSTER_ATTR_IMME;
183         if (!strcmp(name, "force"))
184                 return CLUSTER_ATTR_FORCE;
185         if (!strcmp(name, "wake_ms"))
186                 return CLUSTER_ATTR_WAKEMS;
187 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
188         if (!strcmp(name, "power_mode"))
189                 return CLUSTER_ATTR_POWERMODE;
190 #endif
191 #ifdef CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE
192         if (!strcmp(name, "power_gate"))
193                 return CLUSTER_ATTR_POWERGATE;
194 #endif
195 #if DEBUG_CLUSTER_SWITCH
196         if (!strcmp(name, "debug"))
197                 return CLUSTER_ATTR_DEBUG;
198 #endif
199         TRACE_CLUSTER(("cpu_cluster_get_attr(%s): invalid\n", name));
200         return CLUSTER_ATTR_INVALID;
201 }
202
203 static ssize_t sysfscluster_show(struct kobject *kobj,
204                 struct kobj_attribute *attr, char *buf)
205 {
206         cpu_cluster_attr type;
207         ssize_t len;
208
209         TRACE_CLUSTER(("+sysfscluster_show\n"));
210
211         type = cpu_cluster_get_attr(attr->attr.name);
212         switch (type) {
213         case CLUSTER_ATTR_ACTIVE:
214                 len = sprintf(buf, "%s\n", is_lp_cluster() ? "LP" : "G");
215                 break;
216
217         case CLUSTER_ATTR_IMME:
218                 len = sprintf(buf, "%d\n",
219                               ((flags & TEGRA_POWER_CLUSTER_IMMEDIATE) != 0));
220                 break;
221
222         case CLUSTER_ATTR_FORCE:
223                 len = sprintf(buf, "%d\n",
224                               ((flags & TEGRA_POWER_CLUSTER_FORCE) != 0));
225                 break;
226
227         case CLUSTER_ATTR_WAKEMS:
228                 len = sprintf(buf, "%d\n", wake_ms);
229                 break;
230
231 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
232         case CLUSTER_ATTR_POWERMODE:
233                 len = sprintf(buf, "%d\n", power_mode);
234                 break;
235 #endif
236
237 #ifdef CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE
238         case CLUSTER_ATTR_POWERGATE:
239                 len = sprintf(buf, "%s\n", decode_power_gate(power_gate));
240                 break;
241 #endif
242
243 #if DEBUG_CLUSTER_SWITCH
244         case CLUSTER_ATTR_DEBUG:
245                 len = sprintf(buf, "%d\n", tegra_cluster_debug);
246                 break;
247 #endif
248
249         default:
250                 len = sprintf(buf, "invalid\n");
251                 break;
252         }
253
254         TRACE_CLUSTER(("-sysfscluster_show\n"));
255         return len;
256 }
257
258 static ssize_t sysfscluster_store(struct kobject *kobj,
259         struct kobj_attribute *attr, const char *buf, size_t count)
260 {
261         cpu_cluster_attr type;
262         ssize_t ret = count--;
263         unsigned request;
264         int e;
265         int tmp;
266         int cnt;
267         struct clk *cpu_clk = tegra_get_clock_by_name("cpu");
268         struct clk *cpu_g_clk = tegra_get_clock_by_name("cpu_g");
269         struct clk *cpu_lp_clk = tegra_get_clock_by_name("cpu_lp");
270         struct clk *new_parent = NULL;
271
272         if (!cpu_clk || !cpu_g_clk || !cpu_lp_clk) {
273                 ret = -ENOSYS;
274                 goto fail;
275         }
276
277         TRACE_CLUSTER(("+sysfscluster_store: %p, %d\n", buf, count));
278
279         /* The count includes data bytes follow by a line feed character. */
280         if (!buf || (count < 1)) {
281                 ret = -EINVAL;
282                 goto fail;
283         }
284
285         type = cpu_cluster_get_attr(attr->attr.name);
286
287         spin_lock(&cluster_lock);
288
289         switch (type) {
290         case CLUSTER_ATTR_ACTIVE:
291                 if (!strncasecmp(buf, "g", count)) {
292                         flags &= ~TEGRA_POWER_CLUSTER_MASK;
293                         flags |= TEGRA_POWER_CLUSTER_G;
294                 } else if (!strncasecmp(buf, "lp", count)) {
295                         flags &= ~TEGRA_POWER_CLUSTER_MASK;
296                         flags |= TEGRA_POWER_CLUSTER_LP;
297                 } else if (!strncasecmp(buf, "toggle", count)) {
298                         flags &= ~TEGRA_POWER_CLUSTER_MASK;
299                         if (is_lp_cluster())
300                                 flags |= TEGRA_POWER_CLUSTER_G;
301                         else
302                                 flags |= TEGRA_POWER_CLUSTER_LP;
303                 } else {
304                         PRINT_CLUSTER(("cluster/active: '%*.*s' invalid, "
305                                 " must be g, lp, or toggle\n",
306                                 (int)count, (int)count, buf));
307                         ret = -EINVAL;
308                         break;
309                 }
310                 PRINT_CLUSTER(("cluster/active -> %s\n",
311                         (flags & TEGRA_POWER_CLUSTER_G) ? "G" : "LP"));
312
313                 request = flags;
314 #ifdef CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE
315                 request |= power_gate;
316 #endif
317 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
318                 if (power_mode == 1) {
319                         request |= TEGRA_POWER_SDRAM_SELFREFRESH;
320                 }
321 #endif
322                 tegra_cluster_switch_set_parameters(wake_ms * 1000, request);
323                 new_parent = (flags & TEGRA_POWER_CLUSTER_LP) ?
324                         cpu_lp_clk : cpu_g_clk;
325                 break;
326
327         case CLUSTER_ATTR_IMME:
328                 if ((count == 1) && (*buf == '0'))
329                         flags &= ~TEGRA_POWER_CLUSTER_IMMEDIATE;
330                 else if ((count == 1) && *buf == '1')
331                         flags |= TEGRA_POWER_CLUSTER_IMMEDIATE;
332                 else {
333                         PRINT_CLUSTER(("cluster/immediate: '%*.*s' invalid, "
334                                 "must be 0 or 1\n", (int)count, (int)count,
335                                 buf));
336                         ret = -EINVAL;
337                         break;
338                 }
339                 PRINT_CLUSTER(("cluster/immediate -> %c\n",
340                         (flags & TEGRA_POWER_CLUSTER_IMMEDIATE) ? '1' : '0'));
341                 break;
342
343         case CLUSTER_ATTR_FORCE:
344                 if ((count == 1) && (*buf == '0'))
345                         flags &= ~TEGRA_POWER_CLUSTER_FORCE;
346                 else if ((count == 1) && (*buf == '1'))
347                         flags |= TEGRA_POWER_CLUSTER_FORCE;
348                 else {
349                         PRINT_CLUSTER(("cluster/force: '%*.*s' invalid, "
350                                 "must be 0 or 1\n", (int)count, (int)count,
351                                 buf));
352                         ret = -EINVAL;
353                         break;
354                 }
355                 PRINT_CLUSTER(("cluster/force -> %c\n",
356                         (flags & TEGRA_POWER_CLUSTER_FORCE) ? '1' : '0'));
357                 break;
358
359         case CLUSTER_ATTR_WAKEMS:
360                 tmp = 0;
361                 cnt = sscanf(buf, "%d\n", &tmp);
362                 if ((cnt != 1) || (tmp < 0)) {
363                         PRINT_CLUSTER(("cluster/wake_ms: '%*.*s' is invalid\n",
364                                 (int)count, (int)count, buf));
365                         ret = -EINVAL;
366                         break;
367                 }
368                 wake_ms = tmp;
369                 PRINT_CLUSTER(("cluster/wake_ms -> %d\n", wake_ms));
370                 break;
371
372 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
373         case CLUSTER_ATTR_POWERMODE:
374                 if ((count == 1) && (*buf == '2'))
375                         power_mode = 2;
376                 else if ((count == 1) && *buf == '1')
377                         power_mode = 1;
378                 else {
379                         PRINT_CLUSTER(("cluster/power_mode: '%*.*s' invalid, "
380                                 "must be 2 or 1\n", (int)count, (int)count,
381                                 buf));
382                         ret = -EINVAL;
383                         break;
384                 }
385                 PRINT_CLUSTER(("cluster/power_mode -> %d\n", power_mode));
386                 break;
387 #endif
388
389 #ifdef CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE
390         case CLUSTER_ATTR_POWERGATE:
391                 if (!strncasecmp(buf, "crail", count))
392                         power_gate = TEGRA_POWER_CLUSTER_PART_CRAIL;
393                 else if (!strncasecmp(buf, "noncpu", count))
394                         power_gate = TEGRA_POWER_CLUSTER_PART_NONCPU;
395                 else if (!strncasecmp(buf, "none", count))
396                         power_gate = 0;
397                 else {
398                         PRINT_CLUSTER(("cluster/power_gate: '%*.*s' invalid, "
399                                 "must be 'none', 'crail', or 'noncpu'\n",
400                                 count, count, buf));
401                         ret = -EINVAL;
402                         break;
403                 }
404                 PRINT_CLUSTER(("cluster/power_gate -> %s\n",
405                                 decode_power_gate(power_gate)));
406                 break;
407 #endif
408
409 #if DEBUG_CLUSTER_SWITCH
410         case CLUSTER_ATTR_DEBUG:
411                 if ((count == 1) && (*buf == '0'))
412                         tegra_cluster_debug = 0;
413                 else if ((count == 1) && (*buf == '1'))
414                         tegra_cluster_debug = 1;
415                 else {
416                         PRINT_CLUSTER(("cluster/debug: '%*.*s' invalid, "
417                                 "must be 0 or 1\n", count, count, buf));
418                         ret = -EINVAL;
419                         break;
420                 }
421                 PRINT_CLUSTER(("cluster/debug -> %d\n",tegra_cluster_debug));
422                 break;
423 #endif
424
425         default:
426                 ret = -ENOENT;
427                 break;
428         }
429
430         spin_unlock(&cluster_lock);
431
432         if (new_parent) {
433                 e = tegra_cluster_switch(cpu_clk, new_parent);
434                 if (e) {
435                         PRINT_CLUSTER(("cluster/active: request failed (%d)\n",
436                                        e));
437                         ret = e;
438                 }
439         }
440 fail:
441         TRACE_CLUSTER(("-sysfscluster_store: %d\n", count));
442         return ret;
443 }
444
445 #define CREATE_FILE(x) \
446         do { \
447                 e = sysfs_create_file(cluster_kobj, &cluster_##x##_attr.attr); \
448                 if (e) { \
449                         TRACE_CLUSTER(("cluster/" __stringify(x) \
450                                 ": sysfs_create_file failed!\n")); \
451                         goto fail; \
452                 } \
453         } while (0)
454
455 static int __init sysfscluster_init(void)
456 {
457         int e;
458
459         TRACE_CLUSTER(("+sysfscluster_init\n"));
460
461         spin_lock_init(&cluster_lock);
462         cluster_kobj = kobject_create_and_add("cluster", kernel_kobj);
463
464         CREATE_FILE(active);
465         CREATE_FILE(immediate);
466         CREATE_FILE(force);
467         CREATE_FILE(wake_ms);
468 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
469         CREATE_FILE(powermode);
470 #endif
471 #ifdef CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE
472         CREATE_FILE(powergate);
473 #endif
474 #if DEBUG_CLUSTER_SWITCH
475         CREATE_FILE(debug);
476 #endif
477
478         spin_lock(&cluster_lock);
479         if (is_lp_cluster())
480                 flags |= TEGRA_POWER_CLUSTER_LP;
481         else
482                 flags |= TEGRA_POWER_CLUSTER_G;
483         spin_unlock(&cluster_lock);
484
485 fail:
486         TRACE_CLUSTER(("-sysfscluster_init\n"));
487         return e;
488 }
489
490 #define REMOVE_FILE(x) \
491                 sysfs_remove_file(cluster_kobj, &cluster_##x##_attr.attr)
492
493 static void __exit sysfscluster_exit(void)
494 {
495         TRACE_CLUSTER(("+sysfscluster_exit\n"));
496 #if DEBUG_CLUSTER_SWITCH
497         REMOVE_FILE(debug);
498 #endif
499 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
500         REMOVE_FILE(powermode);
501 #endif
502         REMOVE_FILE(wake_ms);
503         REMOVE_FILE(force);
504         REMOVE_FILE(immediate);
505         REMOVE_FILE(active);
506         kobject_del(cluster_kobj);
507         TRACE_CLUSTER(("-sysfscluster_exit\n"));
508 }
509
510 module_init(sysfscluster_init);
511 module_exit(sysfscluster_exit);
512 MODULE_LICENSE("GPL");