ARM: Tegra: power: Tegra3 T33 set EDP limits correctly
[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, 0x73, 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, 0x5a,
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, 0x5a, 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, 0x73, 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, 0x5a, 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, 0x5a, 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, 0x6e, 0x02, 0x28, 0x55,
86         0x8c, 0x82, 0x73, 0x5f, 0x02, 0x23, 0x2d, 0x8c,
87         0x82, 0x82, 0x6e, 0x02, 0x23, 0x3c, 0x8c, 0x82,
88         0x78, 0x69, 0x02, 0x23, 0x4b, 0x8c, 0x82, 0x73,
89         0x5f, 0x02, 0x23, 0x55, 0x8c, 0x82, 0x69, 0x55,
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         0x73, 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, 0x7d, 0x6e, 0x03, 0x28, 0x55,
100         0x8c, 0x82, 0x73, 0x5f, 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,
138 };
139
140
141 /*
142  * "Safe entry" to be used when no match for speedo_id /
143  * regulator_cur is found; must be the last one
144  */
145 static struct tegra_edp_limits edp_default_limits[] = {
146         {85, {1000000, 1000000, 1000000, 1000000} },
147 };
148
149
150
151 /*
152  * Specify regulator current in mA, e.g. 5000mA
153  * Use 0 for default
154  */
155 void __init tegra_init_cpu_edp_limits(unsigned int regulator_mA)
156 {
157         int cpu_speedo_id = tegra_cpu_speedo_id;
158         int i, j;
159         struct tegra_edp_limits *e;
160         struct tegra_edp_entry *t = (struct tegra_edp_entry *)tegra_edp_map;
161         int tsize = sizeof(tegra_edp_map)/sizeof(struct tegra_edp_entry);
162
163         if (!regulator_mA) {
164                 edp_limits = edp_default_limits;
165                 edp_limits_size = ARRAY_SIZE(edp_default_limits);
166                 return;
167         }
168
169         for (i = 0; i < tsize; i++) {
170                 if (t[i].speedo_id == cpu_speedo_id &&
171                     t[i].regulator_100mA <= regulator_mA / 100)
172                         break;
173         }
174
175         /* No entry found in tegra_edp_map */
176         if (i >= tsize) {
177                 edp_limits = edp_default_limits;
178                 edp_limits_size = ARRAY_SIZE(edp_default_limits);
179                 return;
180         }
181
182         /* Find all rows for this entry */
183         for (j = i + 1; j < tsize; j++) {
184                 if (t[i].speedo_id != t[j].speedo_id ||
185                     t[i].regulator_100mA != t[j].regulator_100mA)
186                         break;
187         }
188
189         edp_limits_size = j - i;
190         e = kmalloc(sizeof(struct tegra_edp_limits) * edp_limits_size,
191                     GFP_KERNEL);
192         BUG_ON(!e);
193
194         for (j = 0; j < edp_limits_size; j++) {
195                 e[j].temperature = (int)t[i+j].temperature;
196                 e[j].freq_limits[0] = (unsigned int)t[i+j].freq_limits[0] * 10000;
197                 e[j].freq_limits[1] = (unsigned int)t[i+j].freq_limits[1] * 10000;
198                 e[j].freq_limits[2] = (unsigned int)t[i+j].freq_limits[2] * 10000;
199                 e[j].freq_limits[3] = (unsigned int)t[i+j].freq_limits[3] * 10000;
200         }
201
202         if (edp_limits && edp_limits != edp_default_limits)
203                 kfree(edp_limits);
204
205         edp_limits = e;
206 }
207
208 void tegra_get_cpu_edp_limits(const struct tegra_edp_limits **limits, int *size)
209 {
210         *limits = edp_limits;
211         *size = edp_limits_size;
212 }
213
214 #ifdef CONFIG_DEBUG_FS
215
216 static int edp_limit_debugfs_show(struct seq_file *s, void *data)
217 {
218         seq_printf(s, "%u\n", tegra_get_edp_limit());
219         return 0;
220 }
221
222 static int edp_debugfs_show(struct seq_file *s, void *data)
223 {
224         int i;
225         const struct tegra_edp_limits *limits;
226         int size;
227
228         tegra_get_cpu_edp_limits(&limits, &size);
229
230         seq_printf(s, "-- EDP table --\n");
231         for (i = 0; i < size; i++) {
232                 seq_printf(s, "%4dC: %10d %10d %10d %10d\n",
233                            limits[i].temperature,
234                            limits[i].freq_limits[0],
235                            limits[i].freq_limits[1],
236                            limits[i].freq_limits[2],
237                            limits[i].freq_limits[3]);
238         }
239
240         return 0;
241 }
242
243
244 static int edp_debugfs_open(struct inode *inode, struct file *file)
245 {
246         return single_open(file, edp_debugfs_show, inode->i_private);
247 }
248
249 static int edp_limit_debugfs_open(struct inode *inode, struct file *file)
250 {
251         return single_open(file, edp_limit_debugfs_show, inode->i_private);
252 }
253
254
255 static const struct file_operations edp_debugfs_fops = {
256         .open           = edp_debugfs_open,
257         .read           = seq_read,
258         .llseek         = seq_lseek,
259         .release        = single_release,
260 };
261
262 static const struct file_operations edp_limit_debugfs_fops = {
263         .open           = edp_limit_debugfs_open,
264         .read           = seq_read,
265         .llseek         = seq_lseek,
266         .release        = single_release,
267 };
268
269 static int __init tegra_edp_debugfs_init(void)
270 {
271         struct dentry *d;
272
273         d = debugfs_create_file("edp", S_IRUGO, NULL, NULL,
274                                 &edp_debugfs_fops);
275         if (!d)
276                 return -ENOMEM;
277
278         d = debugfs_create_file("edp_limit", S_IRUGO, NULL, NULL,
279                                 &edp_limit_debugfs_fops);
280
281         return 0;
282 }
283
284 late_initcall(tegra_edp_debugfs_init);
285 #endif /* CONFIG_DEBUG_FS */