f927be7800d6181f5bb7b1b2a665ad84b8f3209f
[linux-3.10.git] / arch / arm / mach-tegra / tegra3_throttle.c
1 /*
2  * arch/arm/mach-tegra/tegra3_throttle.c
3  *
4  * Copyright (c) 2011, NVIDIA Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  */
19
20 #include <linux/kernel.h>
21 #include <linux/cpufreq.h>
22 #include <linux/delay.h>
23 #include <linux/init.h>
24 #include <linux/err.h>
25 #include <linux/clk.h>
26 #include <linux/debugfs.h>
27 #include <linux/seq_file.h>
28 #include <linux/uaccess.h>
29 #include <linux/thermal.h>
30
31 #include "clock.h"
32 #include "cpu-tegra.h"
33 #include "dvfs.h"
34
35 /* tegra throttling require frequencies in the table to be in ascending order */
36 static struct cpufreq_frequency_table *cpu_freq_table;
37 static struct mutex *cpu_throttle_lock;
38
39 static struct {
40         unsigned int cpu_freq;
41         int core_cap_level;
42         int ms;
43 } throttle_table[] = {
44         {      0, 1000, 2000 }, /* placeholder for cpu floor rate */
45         { 640000, 1000, 2000 },
46         { 640000, 1000, 2000 },
47         { 640000, 1000, 2000 },
48         { 640000, 1000, 2000 },
49         { 640000, 1000, 2000 },
50         { 760000, 1000, 2000 },
51         { 760000, 1050, 2000 },
52         {1000000, 1050, 2000 },
53         {1000000, 1100, 2000 },
54 };
55
56 static int is_throttling;
57 static int throttle_index;
58 static struct delayed_work throttle_work;
59 static struct workqueue_struct *workqueue;
60 static DEFINE_MUTEX(tegra_throttle_lock);
61 #ifdef CONFIG_TEGRA_THERMAL_SYSFS
62 static struct thermal_cooling_device *cdev;
63 #endif
64
65 static unsigned int clip_to_table(unsigned int cpu_freq)
66 {
67         int i;
68
69         for (i = 0; cpu_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
70                 if (cpu_freq_table[i].frequency > cpu_freq)
71                         break;
72         }
73         i = (i == 0) ? 0 : i-1;
74         return cpu_freq_table[i].frequency;
75 }
76
77 static void tegra_throttle_work_func(struct work_struct *work)
78 {
79         unsigned int cpu_freq;
80         int core_level;
81
82         mutex_lock(cpu_throttle_lock);
83         if (!is_throttling) {
84                 mutex_unlock(cpu_throttle_lock);
85                 return;
86         }
87
88         cpu_freq = tegra_getspeed(0);
89         throttle_index -= throttle_index ? 1 : 0;
90
91         core_level = throttle_table[throttle_index].core_cap_level;
92         if (throttle_table[throttle_index].cpu_freq < cpu_freq)
93                 tegra_cpu_set_speed_cap(NULL);
94
95         if (throttle_index || (throttle_table[0].cpu_freq < cpu_freq))
96                 queue_delayed_work(workqueue, &throttle_work,
97                         msecs_to_jiffies(throttle_table[throttle_index].ms));
98
99         mutex_unlock(cpu_throttle_lock);
100
101         tegra_dvfs_core_cap_level_set(core_level);
102 }
103
104 /*
105  * tegra_throttling_enable
106  * This function may sleep
107  */
108 void tegra_throttling_enable(bool enable)
109 {
110         mutex_lock(&tegra_throttle_lock);
111         mutex_lock(cpu_throttle_lock);
112
113         if (enable && !(is_throttling++)) {
114                 int core_level;
115                 unsigned int cpu_freq = tegra_getspeed(0);
116                 throttle_index = ARRAY_SIZE(throttle_table) - 1;
117
118                 core_level = throttle_table[throttle_index].core_cap_level;
119                 if (throttle_table[throttle_index].cpu_freq < cpu_freq)
120                         tegra_cpu_set_speed_cap(NULL);
121
122                 queue_delayed_work(workqueue, &throttle_work,
123                         msecs_to_jiffies(throttle_table[throttle_index].ms));
124
125                 mutex_unlock(cpu_throttle_lock);
126
127                 tegra_dvfs_core_cap_level_set(core_level);
128                 tegra_dvfs_core_cap_enable(true);
129
130                 mutex_unlock(&tegra_throttle_lock);
131                 return;
132         }
133
134         if (!enable && is_throttling) {
135                 if (!(--is_throttling)) {
136                         /* restore speed requested by governor */
137                         tegra_cpu_set_speed_cap(NULL);
138                         mutex_unlock(cpu_throttle_lock);
139
140                         tegra_dvfs_core_cap_enable(false);
141                         cancel_delayed_work_sync(&throttle_work);
142                         mutex_unlock(&tegra_throttle_lock);
143                         return;
144                 }
145         }
146
147         mutex_unlock(cpu_throttle_lock);
148         mutex_unlock(&tegra_throttle_lock);
149 }
150 EXPORT_SYMBOL_GPL(tegra_throttling_enable);
151
152 unsigned int tegra_throttle_governor_speed(unsigned int requested_speed)
153 {
154         return is_throttling ?
155                 min(requested_speed, throttle_table[throttle_index].cpu_freq) :
156                 requested_speed;
157 }
158
159 bool tegra_is_throttling(void)
160 {
161         return is_throttling;
162 }
163
164 #ifdef CONFIG_TEGRA_THERMAL_SYSFS
165
166 static int
167 tegra_throttle_get_max_state(struct thermal_cooling_device *cdev,
168                                 unsigned long *max_state)
169 {
170         *max_state = ARRAY_SIZE(throttle_table);
171         return 0;
172 }
173
174 static int
175 tegra_throttle_get_cur_state(struct thermal_cooling_device *cdev,
176                                 unsigned long *cur_state)
177 {
178         mutex_lock(cpu_throttle_lock);
179         *cur_state = is_throttling ?
180                         (ARRAY_SIZE(throttle_table) - throttle_index) :
181                         0;
182         mutex_unlock(cpu_throttle_lock);
183
184         return 0;
185 }
186
187 static int
188 tegra_throttle_set_cur_state(struct thermal_cooling_device *cdev,
189                                 unsigned long cur_state)
190 {
191         int core_level;
192
193         mutex_lock(cpu_throttle_lock);
194         if (cur_state == 0) {
195                 /* restore speed requested by governor */
196                 if (is_throttling) {
197                         tegra_dvfs_core_cap_enable(false);
198                         is_throttling = false;
199                 }
200
201                 tegra_cpu_set_speed_cap(NULL);
202         } else {
203                 if (!is_throttling) {
204                         tegra_dvfs_core_cap_enable(true);
205                         is_throttling = true;
206                 }
207
208                 throttle_index = ARRAY_SIZE(throttle_table) - cur_state;
209                 core_level = throttle_table[throttle_index].core_cap_level;
210                 tegra_dvfs_core_cap_level_set(core_level);
211
212                 tegra_cpu_set_speed_cap(NULL);
213         }
214
215         mutex_unlock(cpu_throttle_lock);
216
217         return 0;
218 }
219
220 struct thermal_cooling_device_ops tegra_throttle_cooling_ops = {
221         .get_max_state = tegra_throttle_get_max_state,
222         .get_cur_state = tegra_throttle_get_cur_state,
223         .set_cur_state = tegra_throttle_set_cur_state,
224 };
225 #endif
226
227 int __init tegra_throttle_init(struct mutex *cpu_lock)
228 {
229         int i;
230         struct tegra_cpufreq_table_data *table_data =
231                 tegra_cpufreq_table_get();
232         if (IS_ERR_OR_NULL(table_data))
233                 return -EINVAL;
234
235         /*
236          * High-priority, others flags default: not bound to a specific
237          * CPU, has rescue worker task (in case of allocation deadlock,
238          * etc.).  Single-threaded.
239          */
240         workqueue = alloc_workqueue("cpu-tegra",
241                                     WQ_HIGHPRI | WQ_UNBOUND | WQ_RESCUER, 1);
242         if (!workqueue)
243                 return -ENOMEM;
244         INIT_DELAYED_WORK(&throttle_work, tegra_throttle_work_func);
245
246         cpu_throttle_lock = cpu_lock;
247         cpu_freq_table = table_data->freq_table;
248         throttle_table[0].cpu_freq =
249                 cpu_freq_table[table_data->throttle_lowest_index].frequency;
250
251         for (i = 0; i < ARRAY_SIZE(throttle_table); i++) {
252                 unsigned int cpu_freq = throttle_table[i].cpu_freq;
253                 throttle_table[i].cpu_freq = clip_to_table(cpu_freq);
254         }
255
256 #ifdef CONFIG_TEGRA_THERMAL_SYSFS
257         cdev = thermal_cooling_device_register("Throttle", NULL,
258                                                 &tegra_throttle_cooling_ops);
259
260         if (IS_ERR(cdev)) {
261                 cdev = NULL;
262                 return -ENODEV;
263         }
264 #endif
265
266         return 0;
267 }
268
269 void tegra_throttle_exit(void)
270 {
271 #ifdef CONFIG_TEGRA_THERMAL_SYSFS
272         if (cdev) {
273                 thermal_cooling_device_unregister(cdev);
274                 cdev = NULL;
275         }
276 #endif
277         destroy_workqueue(workqueue);
278 }
279
280 #ifdef CONFIG_DEBUG_FS
281
282 static int throttle_debug_set(void *data, u64 val)
283 {
284         tegra_throttling_enable(val);
285         return 0;
286 }
287 static int throttle_debug_get(void *data, u64 *val)
288 {
289         *val = (u64) is_throttling;
290         return 0;
291 }
292 DEFINE_SIMPLE_ATTRIBUTE(throttle_fops, throttle_debug_get, throttle_debug_set,
293                         "%llu\n");
294 static int table_show(struct seq_file *s, void *data)
295 {
296         int i;
297
298         for (i = 0; i < ARRAY_SIZE(throttle_table); i++)
299                 seq_printf(s, "[%d] = %7u %4d %5d\n",
300                         i, throttle_table[i].cpu_freq,
301                         throttle_table[i].core_cap_level, throttle_table[i].ms);
302         return 0;
303 }
304
305 static int table_open(struct inode *inode, struct file *file)
306 {
307         return single_open(file, table_show, inode->i_private);
308 }
309
310 static ssize_t table_write(struct file *file,
311         const char __user *userbuf, size_t count, loff_t *ppos)
312 {
313         char buf[80];
314         int table_idx;
315         unsigned int cpu_freq;
316         int core_cap_level;
317         int ms;
318
319         if (sizeof(buf) <= count)
320                 return -EINVAL;
321
322         if (copy_from_user(buf, userbuf, count))
323                 return -EFAULT;
324
325         /* terminate buffer and trim - white spaces may be appended
326          *  at the end when invoked from shell command line */
327         buf[count] = '\0';
328         strim(buf);
329
330         if (sscanf(buf, "[%d] = %u %d %d",
331                    &table_idx, &cpu_freq, &core_cap_level, &ms) != 4)
332                 return -1;
333
334         if ((table_idx < 0) || (table_idx >= ARRAY_SIZE(throttle_table)))
335                 return -EINVAL;
336
337         /* round new settings before updating table */
338         throttle_table[table_idx].cpu_freq = clip_to_table(cpu_freq);
339         throttle_table[table_idx].core_cap_level = (core_cap_level / 50) * 50;
340         throttle_table[table_idx].ms = jiffies_to_msecs(msecs_to_jiffies(ms));
341
342         return count;
343 }
344
345 static const struct file_operations table_fops = {
346         .open           = table_open,
347         .read           = seq_read,
348         .write          = table_write,
349         .llseek         = seq_lseek,
350         .release        = single_release,
351 };
352
353
354 int __init tegra_throttle_debug_init(struct dentry *cpu_tegra_debugfs_root)
355 {
356         if (!debugfs_create_file("throttle", 0644, cpu_tegra_debugfs_root,
357                                  NULL, &throttle_fops))
358                 return -ENOMEM;
359
360         if (!debugfs_create_file("throttle_table", 0644, cpu_tegra_debugfs_root,
361                                  NULL, &table_fops))
362                 return -ENOMEM;
363
364         return 0;
365 }
366 #endif /* CONFIG_DEBUG_FS */
367