b8d60489a1f539802852080c664f91226f561dac
[linux-3.10.git] / arch / arm / mach-tegra / edp.c
1 /*
2  * arch/arm/mach-tegra/edp.c
3  *
4  * Copyright (C) 2011 NVIDIA, Inc.
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 version 2 as
8  * published by the Free Software Foundation.
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  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18  * 02111-1307, USA
19  */
20
21 #include <linux/kernel.h>
22 #include <linux/init.h>
23 #include <linux/seq_file.h>
24 #include <linux/slab.h>
25 #include <mach/edp.h>
26
27 #include "fuse.h"
28
29 static const struct tegra_edp_limits *edp_limits;
30 static int edp_limits_size;
31
32 static const unsigned int *system_edp_limits;
33
34 /*
35  * Temperature step size cannot be less than 4C because of hysteresis
36  * delta
37  * Code assumes different temperatures for the same speedo_id /
38  * regulator_cur are adjacent in the table, and higest regulator_cur
39  * comes first
40  */
41 static char __initdata tegra_edp_map[] = {
42         0x00, 0x2f, 0x2d, 0x82, 0x78, 0x78, 0x78, 0x00,
43         0x2f, 0x3c, 0x82, 0x78, 0x78, 0x78, 0x00, 0x2f,
44         0x4b, 0x82, 0x78, 0x78, 0x78, 0x00, 0x2f, 0x55,
45         0x82, 0x78, 0x78, 0x78, 0x00, 0x28, 0x2d, 0x82,
46         0x78, 0x78, 0x78, 0x00, 0x28, 0x3c, 0x82, 0x78,
47         0x78, 0x78, 0x00, 0x28, 0x4b, 0x82, 0x78, 0x78,
48         0x73, 0x00, 0x28, 0x55, 0x82, 0x78, 0x78, 0x69,
49         0x00, 0x23, 0x2d, 0x82, 0x78, 0x78, 0x78, 0x00,
50         0x23, 0x3c, 0x82, 0x78, 0x78, 0x6e, 0x00, 0x23,
51         0x4b, 0x82, 0x78, 0x78, 0x64, 0x00, 0x23, 0x55,
52         0x82, 0x78, 0x6e, 0x5a, 0x00, 0x1e, 0x2d, 0x82,
53         0x78, 0x78, 0x69, 0x00, 0x1e, 0x3c, 0x82, 0x78,
54         0x78, 0x64, 0x00, 0x1e, 0x4b, 0x82, 0x78, 0x6e,
55         0x5a, 0x00, 0x1e, 0x55, 0x82, 0x78, 0x64, 0x50,
56         0x00, 0x19, 0x2d, 0x82, 0x78, 0x6e, 0x5a, 0x00,
57         0x19, 0x3c, 0x82, 0x78, 0x69, 0x55, 0x00, 0x19,
58         0x4b, 0x82, 0x78, 0x5f, 0x4b, 0x00, 0x19, 0x55,
59         0x82, 0x73, 0x55, 0x3c, 0x01, 0x2f, 0x2d, 0x82,
60         0x78, 0x78, 0x78, 0x01, 0x2f, 0x3c, 0x82, 0x78,
61         0x78, 0x78, 0x01, 0x2f, 0x4b, 0x82, 0x78, 0x78,
62         0x78, 0x01, 0x2f, 0x55, 0x82, 0x78, 0x78, 0x78,
63         0x01, 0x28, 0x2d, 0x82, 0x78, 0x78, 0x78, 0x01,
64         0x28, 0x3c, 0x82, 0x78, 0x78, 0x78, 0x01, 0x28,
65         0x4b, 0x82, 0x78, 0x78, 0x73, 0x01, 0x28, 0x55,
66         0x82, 0x78, 0x78, 0x69, 0x01, 0x23, 0x2d, 0x82,
67         0x78, 0x78, 0x78, 0x01, 0x23, 0x3c, 0x82, 0x78,
68         0x78, 0x6e, 0x01, 0x23, 0x4b, 0x82, 0x78, 0x78,
69         0x64, 0x01, 0x23, 0x55, 0x82, 0x78, 0x6e, 0x5a,
70         0x01, 0x1e, 0x2d, 0x82, 0x78, 0x78, 0x69, 0x01,
71         0x1e, 0x3c, 0x82, 0x78, 0x78, 0x64, 0x01, 0x1e,
72         0x4b, 0x82, 0x78, 0x6e, 0x5a, 0x01, 0x1e, 0x55,
73         0x82, 0x78, 0x64, 0x50, 0x01, 0x19, 0x2d, 0x82,
74         0x78, 0x6e, 0x5a, 0x01, 0x19, 0x3c, 0x82, 0x78,
75         0x69, 0x55, 0x01, 0x19, 0x4b, 0x82, 0x78, 0x5f,
76         0x4b, 0x01, 0x19, 0x55, 0x82, 0x73, 0x55, 0x3c,
77         0x02, 0x3d, 0x2d, 0x8c, 0x82, 0x82, 0x82, 0x02,
78         0x3d, 0x3c, 0x8c, 0x82, 0x82, 0x82, 0x02, 0x3d,
79         0x4b, 0x8c, 0x82, 0x82, 0x82, 0x02, 0x3d, 0x55,
80         0x8c, 0x82, 0x82, 0x82, 0x02, 0x32, 0x2d, 0x8c,
81         0x82, 0x82, 0x82, 0x02, 0x32, 0x3c, 0x8c, 0x82,
82         0x82, 0x82, 0x02, 0x32, 0x4b, 0x8c, 0x82, 0x82,
83         0x78, 0x02, 0x32, 0x55, 0x8c, 0x82, 0x82, 0x6e,
84         0x02, 0x28, 0x2d, 0x8c, 0x82, 0x82, 0x78, 0x02,
85         0x28, 0x3c, 0x8c, 0x82, 0x82, 0x73, 0x02, 0x28,
86         0x4b, 0x8c, 0x82, 0x78, 0x69, 0x02, 0x28, 0x55,
87         0x8c, 0x82, 0x6e, 0x5a, 0x02, 0x23, 0x2d, 0x8c,
88         0x82, 0x82, 0x6e, 0x02, 0x23, 0x3c, 0x8c, 0x82,
89         0x78, 0x69, 0x02, 0x23, 0x4b, 0x8c, 0x82, 0x6e,
90         0x5a, 0x02, 0x23, 0x55, 0x8c, 0x82, 0x64, 0x50,
91         0x03, 0x3d, 0x2d, 0x8c, 0x82, 0x82, 0x82, 0x03,
92         0x3d, 0x3c, 0x8c, 0x82, 0x82, 0x82, 0x03, 0x3d,
93         0x4b, 0x8c, 0x82, 0x82, 0x82, 0x03, 0x3d, 0x55,
94         0x8c, 0x82, 0x82, 0x82, 0x03, 0x32, 0x2d, 0x8c,
95         0x82, 0x82, 0x82, 0x03, 0x32, 0x3c, 0x8c, 0x82,
96         0x82, 0x82, 0x03, 0x32, 0x4b, 0x8c, 0x82, 0x82,
97         0x78, 0x03, 0x32, 0x55, 0x8c, 0x82, 0x82, 0x6e,
98         0x03, 0x28, 0x2d, 0x8c, 0x82, 0x82, 0x78, 0x03,
99         0x28, 0x3c, 0x8c, 0x82, 0x82, 0x73, 0x03, 0x28,
100         0x4b, 0x8c, 0x82, 0x78, 0x69, 0x03, 0x28, 0x55,
101         0x8c, 0x82, 0x6e, 0x5a, 0x03, 0x23, 0x2d, 0x8c,
102         0x82, 0x82, 0x6e, 0x03, 0x23, 0x3c, 0x8c, 0x82,
103         0x78, 0x69, 0x03, 0x23, 0x4b, 0x8c, 0x82, 0x6e,
104         0x5a, 0x03, 0x23, 0x55, 0x8c, 0x82, 0x64, 0x50,
105         0x04, 0x32, 0x2d, 0x96, 0x8c, 0x8c, 0x8c, 0x04,
106         0x32, 0x3c, 0x96, 0x8c, 0x8c, 0x8c, 0x04, 0x32,
107         0x46, 0x96, 0x8c, 0x8c, 0x8c, 0x04, 0x32, 0x4b,
108         0x82, 0x78, 0x78, 0x78, 0x04, 0x32, 0x55, 0x82,
109         0x78, 0x78, 0x78, 0x04, 0x2f, 0x2d, 0x96, 0x8c,
110         0x8c, 0x8c, 0x04, 0x2f, 0x3c, 0x96, 0x8c, 0x8c,
111         0x8c, 0x04, 0x2f, 0x46, 0x96, 0x8c, 0x8c, 0x82,
112         0x04, 0x2f, 0x4b, 0x82, 0x78, 0x78, 0x78, 0x04,
113         0x2f, 0x55, 0x82, 0x78, 0x78, 0x78, 0x04, 0x28,
114         0x2d, 0x96, 0x8c, 0x8c, 0x82, 0x04, 0x28, 0x3c,
115         0x96, 0x8c, 0x8c, 0x82, 0x04, 0x28, 0x46, 0x96,
116         0x8c, 0x8c, 0x78, 0x04, 0x28, 0x4b, 0x82, 0x78,
117         0x78, 0x78, 0x04, 0x28, 0x55, 0x82, 0x78, 0x78,
118         0x6e, 0x04, 0x23, 0x2d, 0x96, 0x8c, 0x8c, 0x78,
119         0x04, 0x23, 0x3c, 0x96, 0x8c, 0x82, 0x78, 0x04,
120         0x23, 0x46, 0x96, 0x8c, 0x82, 0x6e, 0x04, 0x23,
121         0x4b, 0x82, 0x78, 0x78, 0x6e, 0x04, 0x23, 0x55,
122         0x82, 0x78, 0x78, 0x64, 0x04, 0x1e, 0x2d, 0x96,
123         0x8c, 0x82, 0x6e, 0x04, 0x1e, 0x3c, 0x96, 0x8c,
124         0x78, 0x64, 0x04, 0x1e, 0x46, 0x96, 0x8c, 0x78,
125         0x5a, 0x04, 0x1e, 0x4b, 0x82, 0x78, 0x78, 0x5a,
126         0x04, 0x1e, 0x55, 0x82, 0x78, 0x69, 0x50, 0x04,
127         0x19, 0x2d, 0x96, 0x8c, 0x6e, 0x5a, 0x04, 0x19,
128         0x3c, 0x96, 0x82, 0x6e, 0x55, 0x04, 0x19, 0x46,
129         0x96, 0x82, 0x64, 0x50, 0x04, 0x19, 0x4b, 0x82,
130         0x78, 0x64, 0x50, 0x04, 0x19, 0x55, 0x82, 0x78,
131         0x55, 0x3c, 0x05, 0x64, 0x3c, 0xaa, 0xa0, 0xa0,
132         0xa0, 0x05, 0x64, 0x55, 0x8c, 0x82, 0x82, 0x82,
133         0x05, 0x3c, 0x3c, 0x8c, 0x82, 0x82, 0x82, 0x05,
134         0x3c, 0x55, 0x8c, 0x82, 0x82, 0x82, 0x06, 0x64,
135         0x3c, 0xaa, 0xa0, 0x82, 0x82, 0x06, 0x64, 0x55,
136         0x8c, 0x82, 0x82, 0x82, 0x06, 0x3c, 0x3c, 0x8c,
137         0x82, 0x82, 0x82, 0x06, 0x3c, 0x55, 0x8c, 0x82,
138         0x82, 0x82, 0x07, 0x3b, 0x2d, 0x82, 0x78, 0x78,
139         0x78, 0x07, 0x3b, 0x3c, 0x82, 0x78, 0x78, 0x78,
140         0x07, 0x3b, 0x4b, 0x82, 0x78, 0x78, 0x78, 0x07,
141         0x3b, 0x5a, 0x82, 0x78, 0x78, 0x78, 0x07, 0x32,
142         0x2d, 0x82, 0x78, 0x78, 0x78, 0x07, 0x32, 0x3c,
143         0x82, 0x78, 0x78, 0x78, 0x07, 0x32, 0x4b, 0x82,
144         0x78, 0x78, 0x78, 0x07, 0x32, 0x5a, 0x82, 0x78,
145         0x6e, 0x64, 0x07, 0x28, 0x2d, 0x82, 0x78, 0x78,
146         0x6e, 0x07, 0x28, 0x3c, 0x82, 0x78, 0x78, 0x64,
147         0x07, 0x28, 0x4b, 0x82, 0x78, 0x78, 0x64, 0x07,
148         0x28, 0x5a, 0x82, 0x78, 0x64, 0x50, 0x07, 0x23,
149         0x2d, 0x82, 0x78, 0x78, 0x64, 0x07, 0x23, 0x3c,
150         0x82, 0x78, 0x78, 0x64, 0x07, 0x23, 0x4b, 0x82,
151         0x78, 0x64, 0x50, 0x07, 0x23, 0x5a, 0x82, 0x78,
152         0x5a, 0x46, 0x08, 0x3b, 0x2d, 0x82, 0x78, 0x78,
153         0x78, 0x08, 0x3b, 0x3c, 0x82, 0x78, 0x78, 0x78,
154         0x08, 0x3b, 0x4b, 0x82, 0x78, 0x78, 0x78, 0x08,
155         0x3b, 0x5a, 0x82, 0x78, 0x78, 0x78, 0x08, 0x32,
156         0x2d, 0x82, 0x78, 0x78, 0x78, 0x08, 0x32, 0x3c,
157         0x82, 0x78, 0x78, 0x78, 0x08, 0x32, 0x4b, 0x82,
158         0x78, 0x78, 0x78, 0x08, 0x32, 0x5a, 0x82, 0x78,
159         0x6e, 0x64, 0x08, 0x28, 0x2d, 0x82, 0x78, 0x78,
160         0x6e, 0x08, 0x28, 0x3c, 0x82, 0x78, 0x78, 0x64,
161         0x08, 0x28, 0x4b, 0x82, 0x78, 0x78, 0x64, 0x08,
162         0x28, 0x5a, 0x82, 0x78, 0x64, 0x50, 0x08, 0x23,
163         0x2d, 0x82, 0x78, 0x78, 0x64, 0x08, 0x23, 0x3c,
164         0x82, 0x78, 0x78, 0x64, 0x08, 0x23, 0x4b, 0x82,
165         0x78, 0x64, 0x50, 0x08, 0x23, 0x5a, 0x82, 0x78,
166         0x5a, 0x46,
167 };
168
169
170 static struct system_edp_entry __initdata tegra_system_edp_map[] = {
171
172 /* {SKU, power-limit (in 100mW), {freq limits (in 10Mhz)} } */
173
174         {  1,  49, {130, 120, 120, 120} },
175         {  1,  44, {130, 120, 120, 110} },
176         {  1,  37, {130, 120, 110, 100} },
177         {  1,  35, {130, 120, 110,  90} },
178         {  1,  29, {130, 120, 100,  80} },
179         {  1,  27, {130, 120,  90,  80} },
180         {  1,  25, {130, 110,  80,  60} },
181         {  1,  21, {130, 100,  80,  40} },
182 };
183
184 /*
185  * "Safe entry" to be used when no match for speedo_id /
186  * regulator_cur is found; must be the last one
187  */
188 static struct tegra_edp_limits edp_default_limits[] = {
189         {85, {1000000, 1000000, 1000000, 1000000} },
190 };
191
192
193
194 /*
195  * Specify regulator current in mA, e.g. 5000mA
196  * Use 0 for default
197  */
198 void __init tegra_init_cpu_edp_limits(unsigned int regulator_mA)
199 {
200         int cpu_speedo_id = tegra_cpu_speedo_id;
201         int i, j;
202         struct tegra_edp_limits *e;
203         struct tegra_edp_entry *t = (struct tegra_edp_entry *)tegra_edp_map;
204         int tsize = sizeof(tegra_edp_map)/sizeof(struct tegra_edp_entry);
205
206         if (!regulator_mA) {
207                 edp_limits = edp_default_limits;
208                 edp_limits_size = ARRAY_SIZE(edp_default_limits);
209                 return;
210         }
211
212         for (i = 0; i < tsize; i++) {
213                 if (t[i].speedo_id == cpu_speedo_id &&
214                     t[i].regulator_100mA <= regulator_mA / 100)
215                         break;
216         }
217
218         /* No entry found in tegra_edp_map */
219         if (i >= tsize) {
220                 edp_limits = edp_default_limits;
221                 edp_limits_size = ARRAY_SIZE(edp_default_limits);
222                 return;
223         }
224
225         /* Find all rows for this entry */
226         for (j = i + 1; j < tsize; j++) {
227                 if (t[i].speedo_id != t[j].speedo_id ||
228                     t[i].regulator_100mA != t[j].regulator_100mA)
229                         break;
230         }
231
232         edp_limits_size = j - i;
233         e = kmalloc(sizeof(struct tegra_edp_limits) * edp_limits_size,
234                     GFP_KERNEL);
235         BUG_ON(!e);
236
237         for (j = 0; j < edp_limits_size; j++) {
238                 e[j].temperature = (int)t[i+j].temperature;
239                 e[j].freq_limits[0] = (unsigned int)t[i+j].freq_limits[0] * 10000;
240                 e[j].freq_limits[1] = (unsigned int)t[i+j].freq_limits[1] * 10000;
241                 e[j].freq_limits[2] = (unsigned int)t[i+j].freq_limits[2] * 10000;
242                 e[j].freq_limits[3] = (unsigned int)t[i+j].freq_limits[3] * 10000;
243         }
244
245         if (edp_limits != edp_default_limits)
246                 kfree(edp_limits);
247
248         edp_limits = e;
249 }
250
251
252 void __init tegra_init_system_edp_limits(unsigned int power_limit_mW)
253 {
254         int cpu_speedo_id = tegra_cpu_speedo_id;
255         int i;
256         unsigned int *e;
257         struct system_edp_entry *t =
258                 (struct system_edp_entry *)tegra_system_edp_map;
259         int tsize = sizeof(tegra_system_edp_map) /
260                 sizeof(struct system_edp_entry);
261
262         if (!power_limit_mW) {
263                 e = NULL;
264                 goto out;
265         }
266
267         for (i = 0; i < tsize; i++)
268                 if (t[i].speedo_id == cpu_speedo_id)
269                         break;
270
271         if (i >= tsize) {
272                 e = NULL;
273                 goto out;
274         }
275
276         do {
277                 if (t[i].power_limit_100mW <= power_limit_mW / 100)
278                         break;
279                 i++;
280         } while (i < tsize && t[i].speedo_id == cpu_speedo_id);
281
282         if (i >= tsize || t[i].speedo_id != cpu_speedo_id)
283                 i--; /* No low enough entry in the table, use best possible */
284
285         e = kmalloc(sizeof(unsigned int) * 4, GFP_KERNEL);
286         BUG_ON(!e);
287
288         e[0] = (unsigned int)t[i].freq_limits[0] * 10000;
289         e[1] = (unsigned int)t[i].freq_limits[1] * 10000;
290         e[2] = (unsigned int)t[i].freq_limits[2] * 10000;
291         e[3] = (unsigned int)t[i].freq_limits[3] * 10000;
292
293 out:
294         kfree(system_edp_limits);
295
296         system_edp_limits = e;
297 }
298
299
300 void tegra_get_cpu_edp_limits(const struct tegra_edp_limits **limits, int *size)
301 {
302         *limits = edp_limits;
303         *size = edp_limits_size;
304 }
305
306 void tegra_get_system_edp_limits(const unsigned int **limits)
307 {
308         *limits = system_edp_limits;
309 }
310
311 #ifdef CONFIG_DEBUG_FS
312
313 static int edp_limit_debugfs_show(struct seq_file *s, void *data)
314 {
315         seq_printf(s, "%u\n", tegra_get_edp_limit());
316         return 0;
317 }
318
319 static int edp_debugfs_show(struct seq_file *s, void *data)
320 {
321         int i;
322
323         seq_printf(s, "-- CPU EDP table --\n");
324         for (i = 0; i < edp_limits_size; i++) {
325                 seq_printf(s, "%4dC: %10u %10u %10u %10u\n",
326                            edp_limits[i].temperature,
327                            edp_limits[i].freq_limits[0],
328                            edp_limits[i].freq_limits[1],
329                            edp_limits[i].freq_limits[2],
330                            edp_limits[i].freq_limits[3]);
331         }
332
333         if (system_edp_limits) {
334                 seq_printf(s, "\n-- System EDP table --\n");
335                 seq_printf(s, "%10u %10u %10u %10u\n",
336                            system_edp_limits[0],
337                            system_edp_limits[1],
338                            system_edp_limits[2],
339                            system_edp_limits[3]);
340         }
341
342         return 0;
343 }
344
345
346 static int edp_debugfs_open(struct inode *inode, struct file *file)
347 {
348         return single_open(file, edp_debugfs_show, inode->i_private);
349 }
350
351 static int edp_limit_debugfs_open(struct inode *inode, struct file *file)
352 {
353         return single_open(file, edp_limit_debugfs_show, inode->i_private);
354 }
355
356
357 static const struct file_operations edp_debugfs_fops = {
358         .open           = edp_debugfs_open,
359         .read           = seq_read,
360         .llseek         = seq_lseek,
361         .release        = single_release,
362 };
363
364 static const struct file_operations edp_limit_debugfs_fops = {
365         .open           = edp_limit_debugfs_open,
366         .read           = seq_read,
367         .llseek         = seq_lseek,
368         .release        = single_release,
369 };
370
371 static int __init tegra_edp_debugfs_init(void)
372 {
373         struct dentry *d;
374
375         d = debugfs_create_file("edp", S_IRUGO, NULL, NULL,
376                                 &edp_debugfs_fops);
377         if (!d)
378                 return -ENOMEM;
379
380         d = debugfs_create_file("edp_limit", S_IRUGO, NULL, NULL,
381                                 &edp_limit_debugfs_fops);
382
383         return 0;
384 }
385
386 late_initcall(tegra_edp_debugfs_init);
387 #endif /* CONFIG_DEBUG_FS */