2 * Copyright (c) 2010-2011 NVIDIA Corporation.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
15 * Neither the name of the NVIDIA Corporation nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
34 * This driver creates the /sys/kernel/cluster node and attributes for CPU
35 * switch testing. Node attributes:
37 * active: currently active CPU (G or LP)
38 * write: 'g' = switch to G CPU
39 * 'lp' = switch to LP CPU
40 * 'toggle' = switch to the other CPU
41 * read: returns the currently active CPU (g or lp)
43 * force: force switch even if already on target CPU
44 * write: '0' = do not perform switch if
45 * active CPU == target CPU (default)
46 * '1' = force switch regardless of
47 * currently active CPU
48 * read: returns the current status of the force flag
50 * immediate: request immediate wake-up from switch request
51 * write: '0' = non-immediate wake-up on next interrupt (default)
52 * '1' = immediate wake-up
53 * read: returns the current status of the immediate flag
55 * power_mode: power mode to use for switch (LP1 or LP2)
56 * write: '1' = use LP1 power mode
57 * '2' = use LP2 power mode (default)
58 * read: returns the current status of the immediate flag
60 * wake_ms: wake time (in milliseconds) -- ignored if immediate==1
61 * write: '0' = wake up at the next non-timer interrupt
62 * 'n' = (n > 0) wake-up after 'n' milliseconds or the
63 * next non-timer interrupt (whichever comes first)
64 * read: returns the current wake_ms value
66 * Writing the force, immediate and wake_ms attributes simply updates the
67 * state of internal variables that will be used for the next switch request.
68 * Writing to the active attribute initates a switch request using the
69 * current values of the force, immediate, and wake_ms attributes.
71 * The OS tick timer is not a valid interrupt source for waking up following
72 * a switch request. This is because the kernel uses local timers that are
73 * part of the CPU complex. These get shut down when the CPU complex is
74 * placed into reset by the switch request. If you want a timed wake up
75 * from a switch, you must specify a positive wake_ms value. This will
76 * ensure that a non-local timer is programmed to fire an interrupt
77 * after the desired interval.
81 #include <linux/module.h>
82 #include <linux/kernel.h>
83 #include <linux/sysfs.h>
84 #include <linux/kobject.h>
85 #include <linux/smp.h>
87 #include <linux/clk.h>
89 #include <mach/iomap.h>
93 #define SYSFS_CLUSTER_PRINTS 1 /* Nonzero: enable status prints */
94 #define SYSFS_CLUSTER_TRACE_PRINTS 0 /* Nonzero: enable trace prints */
95 #define SYSFS_CLUSTER_POWER_MODE 0 /* Nonzero: use power modes other than LP2*/
97 #if SYSFS_CLUSTER_TRACE_PRINTS
98 #define TRACE_CLUSTER(x) printk x
100 #define TRACE_CLUSTER(x)
103 #if SYSFS_CLUSTER_PRINTS
104 #define PRINT_CLUSTER(x) printk x
106 #define PRINT_CLUSTER(x)
109 static struct kobject *cluster_kobj;
110 static spinlock_t cluster_lock;
111 static unsigned int flags = 0;
112 static unsigned int wake_ms = 0;
114 static ssize_t sysfscluster_show(struct kobject *kobj,
115 struct kobj_attribute *attr, char *buf);
117 static ssize_t sysfscluster_store(struct kobject *kobj,
118 struct kobj_attribute *attr, const char *buf, size_t count);
120 /* Active CPU: "G", "LP", "toggle" */
121 static struct kobj_attribute cluster_active_attr =
122 __ATTR(active, 0640, sysfscluster_show, sysfscluster_store);
124 /* Immediate wake-up when performing switch: 0, 1 */
125 static struct kobj_attribute cluster_immediate_attr =
126 __ATTR(immediate, 0640, sysfscluster_show, sysfscluster_store);
128 /* Force power transition even if already on the desired CPU: 0, 1 */
129 static struct kobj_attribute cluster_force_attr =
130 __ATTR(force, 0640, sysfscluster_show, sysfscluster_store);
132 /* Wake time (in milliseconds) */
133 static struct kobj_attribute cluster_wake_ms_attr =
134 __ATTR(wake_ms, 0640, sysfscluster_show, sysfscluster_store);
136 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
137 /* LPx power mode to use when switching CPUs: 1=LP1, 2=LP2 */
138 static unsigned int power_mode = 2;
139 static struct kobj_attribute cluster_powermode_attr =
140 __ATTR(power_mode, 0640, sysfscluster_show, sysfscluster_store);
143 #if DEBUG_CLUSTER_SWITCH
144 unsigned int tegra_cluster_debug = 0;
145 static struct kobj_attribute cluster_debug_attr =
146 __ATTR(debug, 0640, sysfscluster_show, sysfscluster_store);
151 ClusterAttr_Invalid = 0,
153 ClusterAttr_Immediate,
156 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
157 ClusterAttr_PowerMode,
159 #if DEBUG_CLUSTER_SWITCH
164 static ClusterAttr GetClusterAttr(const char *name)
166 if (!strcmp(name, "active"))
167 return ClusterAttr_Active;
168 if (!strcmp(name, "immediate"))
169 return ClusterAttr_Immediate;
170 if (!strcmp(name, "force"))
171 return ClusterAttr_Force;
172 if (!strcmp(name, "wake_ms"))
173 return ClusterAttr_WakeMs;
174 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
175 if (!strcmp(name, "power_mode"))
176 return ClusterAttr_PowerMode;
178 #if DEBUG_CLUSTER_SWITCH
179 if (!strcmp(name, "debug"))
180 return ClusterAttr_Debug;
182 TRACE_CLUSTER(("GetClusterAttr(%s): invalid\n", name));
183 return ClusterAttr_Invalid;
186 static ssize_t sysfscluster_show(struct kobject *kobj,
187 struct kobj_attribute *attr, char *buf)
192 TRACE_CLUSTER(("+sysfscluster_show\n"));
194 type = GetClusterAttr(attr->attr.name);
196 case ClusterAttr_Active:
197 len = sprintf(buf, "%s\n", is_lp_cluster() ? "LP" : "G");
200 case ClusterAttr_Immediate:
201 len = sprintf(buf, "%d\n",
202 ((flags & TEGRA_POWER_CLUSTER_IMMEDIATE) != 0));
205 case ClusterAttr_Force:
206 len = sprintf(buf, "%d\n",
207 ((flags & TEGRA_POWER_CLUSTER_FORCE) != 0));
210 case ClusterAttr_WakeMs:
211 len = sprintf(buf, "%d\n", wake_ms);
214 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
215 case ClusterAttr_PowerMode:
216 len = sprintf(buf, "%d\n", power_mode);
220 #if DEBUG_CLUSTER_SWITCH
221 case ClusterAttr_Debug:
222 len = sprintf(buf, "%d\n", tegra_cluster_debug);
227 len = sprintf(buf, "invalid\n");
231 TRACE_CLUSTER(("-sysfscluster_show\n"));
235 static ssize_t sysfscluster_store(struct kobject *kobj,
236 struct kobj_attribute *attr, const char *buf, size_t count)
239 ssize_t ret = count--;
244 struct clk *cpu_clk = tegra_get_clock_by_name("cpu");
245 struct clk *cpu_g_clk = tegra_get_clock_by_name("cpu_g");
246 struct clk *cpu_lp_clk = tegra_get_clock_by_name("cpu_lp");
247 struct clk *new_parent = NULL;
249 if (!cpu_clk || !cpu_g_clk || !cpu_lp_clk) {
254 TRACE_CLUSTER(("+sysfscluster_store: %p, %d\n", buf, count));
256 /* The count includes data bytes follow by a line feed character. */
257 if (!buf || (count < 1)) {
262 type = GetClusterAttr(attr->attr.name);
264 spin_lock(&cluster_lock);
267 case ClusterAttr_Active:
268 if (!strncasecmp(buf, "g", count)) {
269 flags &= ~TEGRA_POWER_CLUSTER_MASK;
270 flags |= TEGRA_POWER_CLUSTER_G;
271 } else if (!strncasecmp(buf, "lp", count)) {
272 flags &= ~TEGRA_POWER_CLUSTER_MASK;
273 flags |= TEGRA_POWER_CLUSTER_LP;
274 } else if (!strncasecmp(buf, "toggle", count)) {
275 flags &= ~TEGRA_POWER_CLUSTER_MASK;
277 flags |= TEGRA_POWER_CLUSTER_G;
279 flags |= TEGRA_POWER_CLUSTER_LP;
281 PRINT_CLUSTER(("cluster/active: '%*.*s' invalid, "
282 " must be g, lp, or toggle\n",
287 PRINT_CLUSTER(("cluster/active -> %s\n",
288 (flags & TEGRA_POWER_CLUSTER_G) ? "G" : "LP"));
291 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
292 if (power_mode == 1) {
293 request |= TEGRA_POWER_SDRAM_SELFREFRESH;
296 tegra_cluster_switch_set_parameters(wake_ms * 1000, request);
297 new_parent = (flags & TEGRA_POWER_CLUSTER_LP) ?
298 cpu_lp_clk : cpu_g_clk;
301 case ClusterAttr_Immediate:
302 if ((count == 1) && (*buf == '0'))
303 flags &= ~TEGRA_POWER_CLUSTER_IMMEDIATE;
304 else if ((count == 1) && *buf == '1')
305 flags |= TEGRA_POWER_CLUSTER_IMMEDIATE;
307 PRINT_CLUSTER(("cluster/immediate: '%*.*s' invalid, "
308 "must be 0 or 1\n", count, count, buf));
312 PRINT_CLUSTER(("cluster/immediate -> %c\n",
313 (flags & TEGRA_POWER_CLUSTER_IMMEDIATE) ? '1' : '0'));
316 case ClusterAttr_Force:
317 if ((count == 1) && (*buf == '0'))
318 flags &= ~TEGRA_POWER_CLUSTER_FORCE;
319 else if ((count == 1) && (*buf == '1'))
320 flags |= TEGRA_POWER_CLUSTER_FORCE;
322 PRINT_CLUSTER(("cluster/force: '%*.*s' invalid, "
323 "must be 0 or 1\n", count, count, buf));
327 PRINT_CLUSTER(("cluster/force -> %c\n",
328 (flags & TEGRA_POWER_CLUSTER_FORCE) ? '1' : '0'));
331 case ClusterAttr_WakeMs:
333 cnt = sscanf(buf, "%d\n", &tmp);
334 if ((cnt != 1) || (tmp < 0)) {
335 PRINT_CLUSTER(("cluster/wake_ms: '%*.*s' is invalid\n",
341 PRINT_CLUSTER(("cluster/wake_ms -> %d\n", wake_ms));
344 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
345 case ClusterAttr_PowerMode:
346 if ((count == 1) && (*buf == '2'))
348 else if ((count == 1) && *buf == '1')
351 PRINT_CLUSTER(("cluster/power_mode: '%*.*s' invalid, "
352 "must be 2 or 1\n", count, count, buf));
356 PRINT_CLUSTER(("cluster/power_mode -> %d\n", power_mode));
360 #if DEBUG_CLUSTER_SWITCH
361 case ClusterAttr_Debug:
362 if ((count == 1) && (*buf == '0'))
363 tegra_cluster_debug = 0;
364 else if ((count == 1) && (*buf == '1'))
365 tegra_cluster_debug = 1;
367 PRINT_CLUSTER(("cluster/debug: '%*.*s' invalid, "
368 "must be 0 or 1\n", count, count, buf));
372 PRINT_CLUSTER(("cluster/debug -> %d\n",tegra_cluster_debug));
381 spin_unlock(&cluster_lock);
384 e = clk_set_parent(cpu_clk, new_parent);
386 PRINT_CLUSTER(("cluster/active: request failed (%d)\n",
392 TRACE_CLUSTER(("-sysfscluster_store: %d\n", count));
396 #define CREATE_FILE(x) \
398 e = sysfs_create_file(cluster_kobj, &cluster_##x##_attr.attr); \
400 TRACE_CLUSTER(("cluster/" __stringify(x) \
401 ": sysfs_create_file failed!\n")); \
406 static int __init sysfscluster_init(void)
410 TRACE_CLUSTER(("+sysfscluster_init\n"));
412 spin_lock_init(&cluster_lock);
413 cluster_kobj = kobject_create_and_add("cluster", kernel_kobj);
416 CREATE_FILE(immediate);
418 CREATE_FILE(wake_ms);
419 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
420 CREATE_FILE(powermode);
422 #if DEBUG_CLUSTER_SWITCH
426 spin_lock(&cluster_lock);
428 flags |= TEGRA_POWER_CLUSTER_LP;
430 flags |= TEGRA_POWER_CLUSTER_G;
431 spin_unlock(&cluster_lock);
434 TRACE_CLUSTER(("-sysfscluster_init\n"));
438 #define REMOVE_FILE(x) \
439 sysfs_remove_file(cluster_kobj, &cluster_##x##_attr.attr)
441 static void __exit sysfscluster_exit(void)
443 TRACE_CLUSTER(("+sysfscluster_exit\n"));
444 #if DEBUG_CLUSTER_SWITCH
447 #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE
448 REMOVE_FILE(powermode);
450 REMOVE_FILE(wake_ms);
452 REMOVE_FILE(immediate);
454 kobject_del(cluster_kobj);
455 TRACE_CLUSTER(("-sysfscluster_exit\n"));
458 module_init(sysfscluster_init);
459 module_exit(sysfscluster_exit);
460 MODULE_LICENSE("GPL");