]> nv-tegra.nvidia Code Review - linux-3.10.git/blob - arch/arm/mach-tegra/tegra3_throttle.c
ARM: tegra11: power: Update core EDP 6A limit table
[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-2012, 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 #include <linux/module.h>
31
32 #include "clock.h"
33 #include "cpu-tegra.h"
34 #include "dvfs.h"
35
36 static struct mutex *cpu_throttle_lock;
37 static DEFINE_MUTEX(bthrot_list_lock);
38 static LIST_HEAD(bthrot_list);
39 static int num_throt;
40
41 #ifndef CONFIG_TEGRA_THERMAL_THROTTLE_EXACT_FREQ
42 static unsigned int clip_to_table(unsigned int cpu_freq)
43 {
44         int i;
45         struct cpufreq_frequency_table *cpu_freq_table;
46         struct tegra_cpufreq_table_data *table_data =
47                 tegra_cpufreq_table_get();
48
49         if (IS_ERR_OR_NULL(table_data))
50                 return -EINVAL;
51
52         cpu_freq_table = table_data->freq_table;
53
54         for (i = 0; cpu_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
55                 if (cpu_freq_table[i].frequency > cpu_freq)
56                         break;
57         }
58         i = (i == 0) ? 0 : i-1;
59         return cpu_freq_table[i].frequency;
60 }
61 #else
62 static unsigned int clip_to_table(unsigned int cpu_freq)
63 {
64         return cpu_freq;
65 }
66 #endif /* CONFIG_TEGRA_THERMAL_THROTTLE_EXACT_FREQ */
67
68 unsigned int tegra_throttle_governor_speed(unsigned int requested_speed)
69 {
70         struct balanced_throttle *bthrot;
71         unsigned int throttle_speed = requested_speed;
72         int index;
73         unsigned int bthrot_speed;
74         unsigned int lowest_speed;
75         struct cpufreq_frequency_table *cpu_freq_table;
76         struct tegra_cpufreq_table_data *table_data =
77                 tegra_cpufreq_table_get();
78
79         if (!table_data)
80                 return requested_speed;
81
82
83         cpu_freq_table = table_data->freq_table;
84         lowest_speed = cpu_freq_table[table_data->throttle_lowest_index].frequency;
85
86         mutex_lock(&bthrot_list_lock);
87
88         list_for_each_entry(bthrot, &bthrot_list, node) {
89                 if (bthrot->is_throttling) {
90                         index = bthrot->throttle_index;
91                         bthrot_speed = bthrot->throt_tab[index].cpu_freq;
92
93                         if (bthrot_speed == 0)
94                                 bthrot_speed = lowest_speed;
95                         else
96                                 bthrot_speed = clip_to_table(bthrot_speed);
97
98                         throttle_speed = min(throttle_speed, bthrot_speed);
99                 }
100         }
101         mutex_unlock(&bthrot_list_lock);
102
103         return throttle_speed;
104 }
105
106 static void tegra_throttle_set_core_level(void)
107 {
108         struct balanced_throttle *bthrot;
109         int core_level = INT_MAX;
110
111         mutex_lock(&bthrot_list_lock);
112         list_for_each_entry(bthrot, &bthrot_list, node) {
113                 if (bthrot->is_throttling) {
114                         int idx = bthrot->throttle_index;
115                         core_level = min(core_level,
116                                          bthrot->throt_tab[idx].core_cap_level);
117                 }
118         }
119         mutex_unlock(&bthrot_list_lock);
120
121         tegra_dvfs_core_cap_level_set(core_level);
122 }
123
124 bool tegra_is_throttling(int *count)
125 {
126         struct balanced_throttle *bthrot;
127         bool is_throttling = false;
128         int lcount = 0;
129
130         mutex_lock(&bthrot_list_lock);
131         list_for_each_entry(bthrot, &bthrot_list, node) {
132                 if (bthrot->is_throttling)
133                         is_throttling = true;
134                 lcount += bthrot->throttle_count;
135         }
136         mutex_unlock(&bthrot_list_lock);
137
138         if (count)
139                 *count = lcount;
140         return is_throttling;
141 }
142
143 static int
144 tegra_throttle_get_max_state(struct thermal_cooling_device *cdev,
145                                 unsigned long *max_state)
146 {
147         struct balanced_throttle *bthrot = cdev->devdata;
148
149         *max_state = bthrot->throt_tab_size;
150
151         return 0;
152 }
153
154 static int
155 tegra_throttle_get_cur_state(struct thermal_cooling_device *cdev,
156                                 unsigned long *cur_state)
157 {
158         struct balanced_throttle *bthrot = cdev->devdata;
159
160         mutex_lock(cpu_throttle_lock);
161         *cur_state = bthrot->is_throttling ?
162                         (bthrot->throt_tab_size - bthrot->throttle_index) :
163                         0;
164         mutex_unlock(cpu_throttle_lock);
165
166         return 0;
167 }
168
169 static int
170 tegra_throttle_set_cur_state(struct thermal_cooling_device *cdev,
171                                 unsigned long cur_state)
172 {
173         struct balanced_throttle *bthrot = cdev->devdata;
174
175         mutex_lock(cpu_throttle_lock);
176         if (cur_state == 0) {
177                 /* restore speed requested by governor */
178                 if (bthrot->is_throttling) {
179                         tegra_dvfs_core_cap_enable(false);
180                         bthrot->is_throttling = false;
181                 }
182         } else {
183                 if (!bthrot->is_throttling) {
184                         tegra_dvfs_core_cap_enable(true);
185                         bthrot->is_throttling = true;
186                         bthrot->throttle_count++;
187                 }
188
189                 bthrot->throttle_index = bthrot->throt_tab_size - cur_state;
190                 tegra_throttle_set_core_level();
191         }
192
193         tegra_cpu_set_speed_cap(NULL);
194
195         mutex_unlock(cpu_throttle_lock);
196
197         return 0;
198 }
199
200 static struct thermal_cooling_device_ops tegra_throttle_cooling_ops = {
201         .get_max_state = tegra_throttle_get_max_state,
202         .get_cur_state = tegra_throttle_get_cur_state,
203         .set_cur_state = tegra_throttle_set_cur_state,
204 };
205
206 #ifdef CONFIG_DEBUG_FS
207 static int table_show(struct seq_file *s, void *data)
208 {
209         struct balanced_throttle *bthrot = s->private;
210         int i;
211
212         for (i = 0; i < bthrot->throt_tab_size; i++)
213                 seq_printf(s, "[%d] = %7u %4d\n",
214                         i, bthrot->throt_tab[i].cpu_freq,
215                         bthrot->throt_tab[i].core_cap_level);
216
217         return 0;
218 }
219
220 static int table_open(struct inode *inode, struct file *file)
221 {
222         return single_open(file, table_show, inode->i_private);
223 }
224
225 static ssize_t table_write(struct file *file,
226         const char __user *userbuf, size_t count, loff_t *ppos)
227 {
228         struct balanced_throttle *bthrot = file->private_data;
229         char buf[80];
230         int table_idx;
231         unsigned int cpu_freq;
232         int core_cap_level;
233
234         if (sizeof(buf) <= count)
235                 return -EINVAL;
236
237         if (copy_from_user(buf, userbuf, count))
238                 return -EFAULT;
239
240         /* terminate buffer and trim - white spaces may be appended
241          *  at the end when invoked from shell command line */
242         buf[count] = '\0';
243         strim(buf);
244
245         if (sscanf(buf, "[%d] = %u %d",
246                    &table_idx, &cpu_freq, &core_cap_level) != 3)
247                 return -1;
248
249         if ((table_idx < 0) || (table_idx >= bthrot->throt_tab_size))
250                 return -EINVAL;
251
252         /* round new settings before updating table */
253         bthrot->throt_tab[table_idx].cpu_freq = clip_to_table(cpu_freq);
254         bthrot->throt_tab[table_idx].core_cap_level = (core_cap_level / 50) * 50;
255
256         return count;
257 }
258
259 static const struct file_operations table_fops = {
260         .open           = table_open,
261         .read           = seq_read,
262         .write          = table_write,
263         .llseek         = seq_lseek,
264         .release        = single_release,
265 };
266
267 static struct dentry *throttle_debugfs_root;
268 #endif /* CONFIG_DEBUG_FS */
269
270
271 struct thermal_cooling_device *balanced_throttle_register(
272                 struct balanced_throttle *bthrot,
273                 char *type)
274 {
275 #ifdef CONFIG_DEBUG_FS
276         char name[32];
277 #endif
278         mutex_lock(&bthrot_list_lock);
279         num_throt++;
280         list_add(&bthrot->node, &bthrot_list);
281         mutex_unlock(&bthrot_list_lock);
282
283         bthrot->cdev = thermal_cooling_device_register(
284                                                 type,
285                                                 bthrot,
286                                                 &tegra_throttle_cooling_ops);
287
288         if (IS_ERR(bthrot->cdev)) {
289                 bthrot->cdev = NULL;
290                 return ERR_PTR(-ENODEV);
291         }
292
293 #ifdef CONFIG_DEBUG_FS
294         sprintf(name, "throttle_table%d", num_throt);
295         debugfs_create_file(name,0644, throttle_debugfs_root,
296                                 bthrot, &table_fops);
297 #endif
298
299         return bthrot->cdev;
300 }
301
302 int __init tegra_throttle_init(struct mutex *cpu_lock)
303 {
304         cpu_throttle_lock = cpu_lock;
305 #ifdef CONFIG_DEBUG_FS
306         throttle_debugfs_root = debugfs_create_dir("tegra_throttle", 0);
307 #endif
308         return 0;
309 }
310
311 void tegra_throttle_exit(void)
312 {
313 #ifdef CONFIG_DEBUG_FS
314         debugfs_remove_recursive(throttle_debugfs_root);
315 #endif
316 }
317