arm: tegra: power: Added EDP table for Tegra3 xL
[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
33 /*
34  * Temperature step size cannot be less than 4C because of hysteresis
35  * delta
36  * Code assumes different temperatures for the same speedo_id /
37  * regulator_cur are adjacent in the table, and higest regulator_cur
38  * comes first
39  */
40 static char __initdata tegra_edp_map[] = {
41         0x00, 0x2f, 0x2d, 0x82, 0x78, 0x78, 0x78, 0x00,
42         0x2f, 0x3c, 0x82, 0x78, 0x78, 0x78, 0x00, 0x2f,
43         0x4b, 0x82, 0x78, 0x78, 0x78, 0x00, 0x2f, 0x55,
44         0x82, 0x78, 0x78, 0x78, 0x00, 0x28, 0x2d, 0x82,
45         0x78, 0x78, 0x78, 0x00, 0x28, 0x3c, 0x82, 0x78,
46         0x78, 0x78, 0x00, 0x28, 0x4b, 0x82, 0x78, 0x78,
47         0x73, 0x00, 0x28, 0x55, 0x82, 0x78, 0x78, 0x69,
48         0x00, 0x23, 0x2d, 0x82, 0x78, 0x78, 0x78, 0x00,
49         0x23, 0x3c, 0x82, 0x78, 0x78, 0x6e, 0x00, 0x23,
50         0x4b, 0x82, 0x78, 0x78, 0x64, 0x00, 0x23, 0x55,
51         0x82, 0x78, 0x6e, 0x5a, 0x00, 0x1e, 0x2d, 0x82,
52         0x78, 0x78, 0x69, 0x00, 0x1e, 0x3c, 0x82, 0x78,
53         0x78, 0x64, 0x00, 0x1e, 0x4b, 0x82, 0x78, 0x6e,
54         0x5a, 0x00, 0x1e, 0x55, 0x82, 0x78, 0x64, 0x50,
55         0x00, 0x19, 0x2d, 0x82, 0x78, 0x6e, 0x5a, 0x00,
56         0x19, 0x3c, 0x82, 0x78, 0x69, 0x55, 0x00, 0x19,
57         0x4b, 0x82, 0x78, 0x5f, 0x4b, 0x00, 0x19, 0x55,
58         0x82, 0x73, 0x55, 0x3c, 0x01, 0x2f, 0x2d, 0x82,
59         0x78, 0x78, 0x78, 0x01, 0x2f, 0x3c, 0x82, 0x78,
60         0x78, 0x78, 0x01, 0x2f, 0x4b, 0x82, 0x78, 0x78,
61         0x78, 0x01, 0x2f, 0x55, 0x82, 0x78, 0x78, 0x78,
62         0x01, 0x28, 0x2d, 0x82, 0x78, 0x78, 0x78, 0x01,
63         0x28, 0x3c, 0x82, 0x78, 0x78, 0x78, 0x01, 0x28,
64         0x4b, 0x82, 0x78, 0x78, 0x73, 0x01, 0x28, 0x55,
65         0x82, 0x78, 0x78, 0x69, 0x01, 0x23, 0x2d, 0x82,
66         0x78, 0x78, 0x78, 0x01, 0x23, 0x3c, 0x82, 0x78,
67         0x78, 0x6e, 0x01, 0x23, 0x4b, 0x82, 0x78, 0x78,
68         0x64, 0x01, 0x23, 0x55, 0x82, 0x78, 0x6e, 0x5a,
69         0x01, 0x1e, 0x2d, 0x82, 0x78, 0x78, 0x69, 0x01,
70         0x1e, 0x3c, 0x82, 0x78, 0x78, 0x64, 0x01, 0x1e,
71         0x4b, 0x82, 0x78, 0x6e, 0x5a, 0x01, 0x1e, 0x55,
72         0x82, 0x78, 0x64, 0x50, 0x01, 0x19, 0x2d, 0x82,
73         0x78, 0x6e, 0x5a, 0x01, 0x19, 0x3c, 0x82, 0x78,
74         0x69, 0x55, 0x01, 0x19, 0x4b, 0x82, 0x78, 0x5f,
75         0x4b, 0x01, 0x19, 0x55, 0x82, 0x73, 0x55, 0x3c,
76         0x02, 0x3d, 0x2d, 0x8c, 0x82, 0x82, 0x82, 0x02,
77         0x3d, 0x3c, 0x8c, 0x82, 0x82, 0x82, 0x02, 0x3d,
78         0x4b, 0x8c, 0x82, 0x82, 0x82, 0x02, 0x3d, 0x55,
79         0x8c, 0x82, 0x82, 0x82, 0x02, 0x32, 0x2d, 0x8c,
80         0x82, 0x82, 0x82, 0x02, 0x32, 0x3c, 0x8c, 0x82,
81         0x82, 0x82, 0x02, 0x32, 0x4b, 0x8c, 0x82, 0x82,
82         0x78, 0x02, 0x32, 0x55, 0x8c, 0x82, 0x82, 0x6e,
83         0x02, 0x28, 0x2d, 0x8c, 0x82, 0x82, 0x78, 0x02,
84         0x28, 0x3c, 0x8c, 0x82, 0x82, 0x73, 0x02, 0x28,
85         0x4b, 0x8c, 0x82, 0x78, 0x69, 0x02, 0x28, 0x55,
86         0x8c, 0x82, 0x6e, 0x5a, 0x02, 0x23, 0x2d, 0x8c,
87         0x82, 0x82, 0x6e, 0x02, 0x23, 0x3c, 0x8c, 0x82,
88         0x78, 0x69, 0x02, 0x23, 0x4b, 0x8c, 0x82, 0x6e,
89         0x5a, 0x02, 0x23, 0x55, 0x8c, 0x82, 0x64, 0x50,
90         0x03, 0x3d, 0x2d, 0x8c, 0x82, 0x82, 0x82, 0x03,
91         0x3d, 0x3c, 0x8c, 0x82, 0x82, 0x82, 0x03, 0x3d,
92         0x4b, 0x8c, 0x82, 0x82, 0x82, 0x03, 0x3d, 0x55,
93         0x8c, 0x82, 0x82, 0x82, 0x03, 0x32, 0x2d, 0x8c,
94         0x82, 0x82, 0x82, 0x03, 0x32, 0x3c, 0x8c, 0x82,
95         0x82, 0x82, 0x03, 0x32, 0x4b, 0x8c, 0x82, 0x82,
96         0x78, 0x03, 0x32, 0x55, 0x8c, 0x82, 0x82, 0x6e,
97         0x03, 0x28, 0x2d, 0x8c, 0x82, 0x82, 0x78, 0x03,
98         0x28, 0x3c, 0x8c, 0x82, 0x82, 0x73, 0x03, 0x28,
99         0x4b, 0x8c, 0x82, 0x78, 0x69, 0x03, 0x28, 0x55,
100         0x8c, 0x82, 0x6e, 0x5a, 0x03, 0x23, 0x2d, 0x8c,
101         0x82, 0x82, 0x6e, 0x03, 0x23, 0x3c, 0x8c, 0x82,
102         0x78, 0x69, 0x03, 0x23, 0x4b, 0x8c, 0x82, 0x6e,
103         0x5a, 0x03, 0x23, 0x55, 0x8c, 0x82, 0x64, 0x50,
104         0x04, 0x32, 0x2d, 0x96, 0x8c, 0x8c, 0x8c, 0x04,
105         0x32, 0x3c, 0x96, 0x8c, 0x8c, 0x8c, 0x04, 0x32,
106         0x46, 0x96, 0x8c, 0x8c, 0x8c, 0x04, 0x32, 0x4b,
107         0x82, 0x78, 0x78, 0x78, 0x04, 0x32, 0x55, 0x82,
108         0x78, 0x78, 0x78, 0x04, 0x2f, 0x2d, 0x96, 0x8c,
109         0x8c, 0x8c, 0x04, 0x2f, 0x3c, 0x96, 0x8c, 0x8c,
110         0x8c, 0x04, 0x2f, 0x46, 0x96, 0x8c, 0x8c, 0x82,
111         0x04, 0x2f, 0x4b, 0x82, 0x78, 0x78, 0x78, 0x04,
112         0x2f, 0x55, 0x82, 0x78, 0x78, 0x78, 0x04, 0x28,
113         0x2d, 0x96, 0x8c, 0x8c, 0x82, 0x04, 0x28, 0x3c,
114         0x96, 0x8c, 0x8c, 0x82, 0x04, 0x28, 0x46, 0x96,
115         0x8c, 0x8c, 0x78, 0x04, 0x28, 0x4b, 0x82, 0x78,
116         0x78, 0x78, 0x04, 0x28, 0x55, 0x82, 0x78, 0x78,
117         0x6e, 0x04, 0x23, 0x2d, 0x96, 0x8c, 0x8c, 0x78,
118         0x04, 0x23, 0x3c, 0x96, 0x8c, 0x82, 0x78, 0x04,
119         0x23, 0x46, 0x96, 0x8c, 0x82, 0x6e, 0x04, 0x23,
120         0x4b, 0x82, 0x78, 0x78, 0x6e, 0x04, 0x23, 0x55,
121         0x82, 0x78, 0x78, 0x64, 0x04, 0x1e, 0x2d, 0x96,
122         0x8c, 0x82, 0x6e, 0x04, 0x1e, 0x3c, 0x96, 0x8c,
123         0x78, 0x64, 0x04, 0x1e, 0x46, 0x96, 0x8c, 0x78,
124         0x5a, 0x04, 0x1e, 0x4b, 0x82, 0x78, 0x78, 0x5a,
125         0x04, 0x1e, 0x55, 0x82, 0x78, 0x69, 0x50, 0x04,
126         0x19, 0x2d, 0x96, 0x8c, 0x6e, 0x5a, 0x04, 0x19,
127         0x3c, 0x96, 0x82, 0x6e, 0x55, 0x04, 0x19, 0x46,
128         0x96, 0x82, 0x64, 0x50, 0x04, 0x19, 0x4b, 0x82,
129         0x78, 0x64, 0x50, 0x04, 0x19, 0x55, 0x82, 0x78,
130         0x55, 0x3c, 0x05, 0x64, 0x3c, 0xaa, 0xa0, 0xa0,
131         0xa0, 0x05, 0x64, 0x55, 0x8c, 0x82, 0x82, 0x82,
132         0x05, 0x3c, 0x3c, 0x8c, 0x82, 0x82, 0x82, 0x05,
133         0x3c, 0x55, 0x8c, 0x82, 0x82, 0x82, 0x06, 0x64,
134         0x3c, 0xaa, 0xa0, 0x82, 0x82, 0x06, 0x64, 0x55,
135         0x8c, 0x82, 0x82, 0x82, 0x06, 0x3c, 0x3c, 0x8c,
136         0x82, 0x82, 0x82, 0x06, 0x3c, 0x55, 0x8c, 0x82,
137         0x82, 0x82, 0x07, 0x3b, 0x2d, 0x82, 0x78, 0x78,
138         0x78, 0x07, 0x3b, 0x3c, 0x82, 0x78, 0x78, 0x78,
139         0x07, 0x3b, 0x4b, 0x82, 0x78, 0x78, 0x78, 0x07,
140         0x3b, 0x5a, 0x82, 0x78, 0x78, 0x78, 0x07, 0x32,
141         0x2d, 0x82, 0x78, 0x78, 0x78, 0x07, 0x32, 0x3c,
142         0x82, 0x78, 0x78, 0x78, 0x07, 0x32, 0x4b, 0x82,
143         0x78, 0x78, 0x78, 0x07, 0x32, 0x5a, 0x82, 0x78,
144         0x6e, 0x64, 0x07, 0x28, 0x2d, 0x82, 0x78, 0x78,
145         0x6e, 0x07, 0x28, 0x3c, 0x82, 0x78, 0x78, 0x64,
146         0x07, 0x28, 0x4b, 0x82, 0x78, 0x78, 0x64, 0x07,
147         0x28, 0x5a, 0x82, 0x78, 0x64, 0x50, 0x07, 0x23,
148         0x2d, 0x82, 0x78, 0x78, 0x64, 0x07, 0x23, 0x3c,
149         0x82, 0x78, 0x78, 0x64, 0x07, 0x23, 0x4b, 0x82,
150         0x78, 0x64, 0x50, 0x07, 0x23, 0x5a, 0x82, 0x78,
151         0x5a, 0x46, 0x08, 0x3b, 0x2d, 0x82, 0x78, 0x78,
152         0x78, 0x08, 0x3b, 0x3c, 0x82, 0x78, 0x78, 0x78,
153         0x08, 0x3b, 0x4b, 0x82, 0x78, 0x78, 0x78, 0x08,
154         0x3b, 0x5a, 0x82, 0x78, 0x78, 0x78, 0x08, 0x32,
155         0x2d, 0x82, 0x78, 0x78, 0x78, 0x08, 0x32, 0x3c,
156         0x82, 0x78, 0x78, 0x78, 0x08, 0x32, 0x4b, 0x82,
157         0x78, 0x78, 0x78, 0x08, 0x32, 0x5a, 0x82, 0x78,
158         0x6e, 0x64, 0x08, 0x28, 0x2d, 0x82, 0x78, 0x78,
159         0x6e, 0x08, 0x28, 0x3c, 0x82, 0x78, 0x78, 0x64,
160         0x08, 0x28, 0x4b, 0x82, 0x78, 0x78, 0x64, 0x08,
161         0x28, 0x5a, 0x82, 0x78, 0x64, 0x50, 0x08, 0x23,
162         0x2d, 0x82, 0x78, 0x78, 0x64, 0x08, 0x23, 0x3c,
163         0x82, 0x78, 0x78, 0x64, 0x08, 0x23, 0x4b, 0x82,
164         0x78, 0x64, 0x50, 0x08, 0x23, 0x5a, 0x82, 0x78,
165         0x5a, 0x46,
166 };
167
168
169 /*
170  * "Safe entry" to be used when no match for speedo_id /
171  * regulator_cur is found; must be the last one
172  */
173 static struct tegra_edp_limits edp_default_limits[] = {
174         {85, {1000000, 1000000, 1000000, 1000000} },
175 };
176
177
178
179 /*
180  * Specify regulator current in mA, e.g. 5000mA
181  * Use 0 for default
182  */
183 void __init tegra_init_cpu_edp_limits(unsigned int regulator_mA)
184 {
185         int cpu_speedo_id = tegra_cpu_speedo_id;
186         int i, j;
187         struct tegra_edp_limits *e;
188         struct tegra_edp_entry *t = (struct tegra_edp_entry *)tegra_edp_map;
189         int tsize = sizeof(tegra_edp_map)/sizeof(struct tegra_edp_entry);
190
191         if (!regulator_mA) {
192                 edp_limits = edp_default_limits;
193                 edp_limits_size = ARRAY_SIZE(edp_default_limits);
194                 return;
195         }
196
197         for (i = 0; i < tsize; i++) {
198                 if (t[i].speedo_id == cpu_speedo_id &&
199                     t[i].regulator_100mA <= regulator_mA / 100)
200                         break;
201         }
202
203         /* No entry found in tegra_edp_map */
204         if (i >= tsize) {
205                 edp_limits = edp_default_limits;
206                 edp_limits_size = ARRAY_SIZE(edp_default_limits);
207                 return;
208         }
209
210         /* Find all rows for this entry */
211         for (j = i + 1; j < tsize; j++) {
212                 if (t[i].speedo_id != t[j].speedo_id ||
213                     t[i].regulator_100mA != t[j].regulator_100mA)
214                         break;
215         }
216
217         edp_limits_size = j - i;
218         e = kmalloc(sizeof(struct tegra_edp_limits) * edp_limits_size,
219                     GFP_KERNEL);
220         BUG_ON(!e);
221
222         for (j = 0; j < edp_limits_size; j++) {
223                 e[j].temperature = (int)t[i+j].temperature;
224                 e[j].freq_limits[0] = (unsigned int)t[i+j].freq_limits[0] * 10000;
225                 e[j].freq_limits[1] = (unsigned int)t[i+j].freq_limits[1] * 10000;
226                 e[j].freq_limits[2] = (unsigned int)t[i+j].freq_limits[2] * 10000;
227                 e[j].freq_limits[3] = (unsigned int)t[i+j].freq_limits[3] * 10000;
228         }
229
230         if (edp_limits && edp_limits != edp_default_limits)
231                 kfree(edp_limits);
232
233         edp_limits = e;
234 }
235
236 void tegra_get_cpu_edp_limits(const struct tegra_edp_limits **limits, int *size)
237 {
238         *limits = edp_limits;
239         *size = edp_limits_size;
240 }
241
242 #ifdef CONFIG_DEBUG_FS
243
244 static int edp_limit_debugfs_show(struct seq_file *s, void *data)
245 {
246         seq_printf(s, "%u\n", tegra_get_edp_limit());
247         return 0;
248 }
249
250 static int edp_debugfs_show(struct seq_file *s, void *data)
251 {
252         int i;
253         const struct tegra_edp_limits *limits;
254         int size;
255
256         tegra_get_cpu_edp_limits(&limits, &size);
257
258         seq_printf(s, "-- EDP table --\n");
259         for (i = 0; i < size; i++) {
260                 seq_printf(s, "%4dC: %10d %10d %10d %10d\n",
261                            limits[i].temperature,
262                            limits[i].freq_limits[0],
263                            limits[i].freq_limits[1],
264                            limits[i].freq_limits[2],
265                            limits[i].freq_limits[3]);
266         }
267
268         return 0;
269 }
270
271
272 static int edp_debugfs_open(struct inode *inode, struct file *file)
273 {
274         return single_open(file, edp_debugfs_show, inode->i_private);
275 }
276
277 static int edp_limit_debugfs_open(struct inode *inode, struct file *file)
278 {
279         return single_open(file, edp_limit_debugfs_show, inode->i_private);
280 }
281
282
283 static const struct file_operations edp_debugfs_fops = {
284         .open           = edp_debugfs_open,
285         .read           = seq_read,
286         .llseek         = seq_lseek,
287         .release        = single_release,
288 };
289
290 static const struct file_operations edp_limit_debugfs_fops = {
291         .open           = edp_limit_debugfs_open,
292         .read           = seq_read,
293         .llseek         = seq_lseek,
294         .release        = single_release,
295 };
296
297 static int __init tegra_edp_debugfs_init(void)
298 {
299         struct dentry *d;
300
301         d = debugfs_create_file("edp", S_IRUGO, NULL, NULL,
302                                 &edp_debugfs_fops);
303         if (!d)
304                 return -ENOMEM;
305
306         d = debugfs_create_file("edp_limit", S_IRUGO, NULL, NULL,
307                                 &edp_limit_debugfs_fops);
308
309         return 0;
310 }
311
312 late_initcall(tegra_edp_debugfs_init);
313 #endif /* CONFIG_DEBUG_FS */