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