ARM: Tegra: power: T33 SKU EDP table for 10A regulator
[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, 0x6e, 0x03, 0x23, 0x4b, 0x8c, 0x82, 0x78,
103         0x5f, 0x03, 0x23, 0x55, 0x8c, 0x82, 0x6e, 0x5a,
104         0x05, 0x64, 0x3c, 0xaa, 0xa0, 0xa0, 0xa0, 0x05,
105         0x64, 0x55, 0x8c, 0x82, 0x82, 0x82, 0x05, 0x3c,
106         0x3c, 0x8c, 0x82, 0x82, 0x82, 0x05, 0x3c, 0x55,
107         0x8c, 0x82, 0x82, 0x82, 0x06, 0x64, 0x3c, 0xaa,
108         0xa0, 0xa0, 0xa0, 0x06, 0x64, 0x55, 0x8c, 0x82,
109         0x82, 0x82, 0x06, 0x3c, 0x3c, 0x8c, 0x82, 0x82,
110         0x82, 0x06, 0x3c, 0x55, 0x8c, 0x82, 0x82, 0x82,
111 };
112
113
114 /*
115  * "Safe entry" to be used when no match for speedo_id /
116  * regulator_cur is found; must be the last one
117  */
118 static struct tegra_edp_limits edp_default_limits[] = {
119         {85, {1000000, 1000000, 1000000, 1000000} },
120 };
121
122
123
124 /*
125  * Specify regulator current in mA, e.g. 5000mA
126  * Use 0 for default
127  */
128 void __init tegra_init_cpu_edp_limits(unsigned int regulator_mA)
129 {
130         int cpu_speedo_id = tegra_cpu_speedo_id;
131         int i, j;
132         struct tegra_edp_limits *e;
133         struct tegra_edp_entry *t = (struct tegra_edp_entry *)tegra_edp_map;
134         int tsize = sizeof(tegra_edp_map)/sizeof(struct tegra_edp_entry);
135
136         /* FIXME: Now for T33 we use 6A limit - fix this later */
137         if (cpu_speedo_id > 3)
138                 regulator_mA = 6000;
139
140         if (!regulator_mA) {
141                 edp_limits = edp_default_limits;
142                 edp_limits_size = ARRAY_SIZE(edp_default_limits);
143                 return;
144         }
145
146         for (i = 0; i < tsize; i++) {
147                 if (t[i].speedo_id == cpu_speedo_id &&
148                     t[i].regulator_100mA <= regulator_mA / 100)
149                         break;
150         }
151
152         /* No entry found in tegra_edp_map */
153         if (i >= tsize) {
154                 edp_limits = edp_default_limits;
155                 edp_limits_size = ARRAY_SIZE(edp_default_limits);
156                 return;
157         }
158
159         /* Find all rows for this entry */
160         for (j = i + 1; j < tsize; j++) {
161                 if (t[i].speedo_id != t[j].speedo_id ||
162                     t[i].regulator_100mA != t[j].regulator_100mA)
163                         break;
164         }
165
166         edp_limits_size = j - i;
167         e = kmalloc(sizeof(struct tegra_edp_limits) * edp_limits_size,
168                     GFP_KERNEL);
169         BUG_ON(!e);
170
171         for (j = 0; j < edp_limits_size; j++) {
172                 e[j].temperature = (int)t[i+j].temperature;
173                 e[j].freq_limits[0] = (unsigned int)t[i+j].freq_limits[0] * 10000;
174                 e[j].freq_limits[1] = (unsigned int)t[i+j].freq_limits[1] * 10000;
175                 e[j].freq_limits[2] = (unsigned int)t[i+j].freq_limits[2] * 10000;
176                 e[j].freq_limits[3] = (unsigned int)t[i+j].freq_limits[3] * 10000;
177         }
178
179         if (edp_limits && edp_limits != edp_default_limits)
180                 kfree(edp_limits);
181
182         edp_limits = e;
183 }
184
185 void tegra_get_cpu_edp_limits(const struct tegra_edp_limits **limits, int *size)
186 {
187         *limits = edp_limits;
188         *size = edp_limits_size;
189 }
190
191 #ifdef CONFIG_DEBUG_FS
192
193 static int edp_limit_debugfs_show(struct seq_file *s, void *data)
194 {
195         seq_printf(s, "%u\n", tegra_get_edp_limit());
196         return 0;
197 }
198
199 static int edp_debugfs_show(struct seq_file *s, void *data)
200 {
201         int i;
202         const struct tegra_edp_limits *limits;
203         int size;
204
205         tegra_get_cpu_edp_limits(&limits, &size);
206
207         seq_printf(s, "-- EDP table --\n");
208         for (i = 0; i < size; i++) {
209                 seq_printf(s, "%4dC: %10d %10d %10d %10d\n",
210                            limits[i].temperature,
211                            limits[i].freq_limits[0],
212                            limits[i].freq_limits[1],
213                            limits[i].freq_limits[2],
214                            limits[i].freq_limits[3]);
215         }
216
217         return 0;
218 }
219
220
221 static int edp_debugfs_open(struct inode *inode, struct file *file)
222 {
223         return single_open(file, edp_debugfs_show, inode->i_private);
224 }
225
226 static int edp_limit_debugfs_open(struct inode *inode, struct file *file)
227 {
228         return single_open(file, edp_limit_debugfs_show, inode->i_private);
229 }
230
231
232 static const struct file_operations edp_debugfs_fops = {
233         .open           = edp_debugfs_open,
234         .read           = seq_read,
235         .llseek         = seq_lseek,
236         .release        = single_release,
237 };
238
239 static const struct file_operations edp_limit_debugfs_fops = {
240         .open           = edp_limit_debugfs_open,
241         .read           = seq_read,
242         .llseek         = seq_lseek,
243         .release        = single_release,
244 };
245
246 static int __init tegra_edp_debugfs_init(void)
247 {
248         struct dentry *d;
249
250         d = debugfs_create_file("edp", S_IRUGO, NULL, NULL,
251                                 &edp_debugfs_fops);
252         if (!d)
253                 return -ENOMEM;
254
255         d = debugfs_create_file("edp_limit", S_IRUGO, NULL, NULL,
256                                 &edp_limit_debugfs_fops);
257
258         return 0;
259 }
260
261 late_initcall(tegra_edp_debugfs_init);
262 #endif /* CONFIG_DEBUG_FS */