ARM: tegra: power: Update to 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
30 static const struct tegra_edp_limits *edp_limits;
31 static int edp_limits_size;
32
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, 0x5a,
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, 0x5a, 0x82, 0x78, 0x73, 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, 0x5a,
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, 0x5a, 0x82, 0x78, 0x64, 0x5a,
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, 0x5a,
59         0x82, 0x73, 0x5a, 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, 0x5a, 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, 0x5a,
66         0x82, 0x78, 0x73, 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, 0x5a, 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, 0x5a,
73         0x82, 0x78, 0x64, 0x5a, 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, 0x5a, 0x82, 0x73, 0x5a, 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, 0x5a,
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, 0x5a, 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, 0x6e, 0x02, 0x28, 0x5a,
87         0x8c, 0x82, 0x73, 0x5f, 0x02, 0x23, 0x2d, 0x8c,
88         0x82, 0x82, 0x6e, 0x02, 0x23, 0x3c, 0x8c, 0x82,
89         0x78, 0x69, 0x02, 0x23, 0x4b, 0x8c, 0x82, 0x73,
90         0x5f, 0x02, 0x23, 0x5a, 0x8c, 0x82, 0x69, 0x55,
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, 0x5a,
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         0x73, 0x03, 0x32, 0x5a, 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, 0x7d, 0x6e, 0x03, 0x28, 0x5a,
101         0x8c, 0x82, 0x73, 0x5f, 0x03, 0x23, 0x2d, 0x8c,
102         0x82, 0x82, 0x6e, 0x03, 0x23, 0x3c, 0x8c, 0x82,
103         0x78, 0x6e, 0x03, 0x23, 0x4b, 0x8c, 0x82, 0x78,
104         0x5f, 0x03, 0x23, 0x5a, 0x8c, 0x82, 0x6e, 0x5a,
105 };
106
107
108 /*
109  * "Safe entry" to be used when no match for speedo_id /
110  * regulator_cur is found; must be the last one
111  */
112 static struct tegra_edp_limits edp_default_limits[] = {
113         {90, {1000000, 1000000, 1000000, 1000000} },
114 };
115
116
117
118 /*
119  * Specify regulator current in mA, e.g. 5000mA
120  * Use 0 for default
121  */
122 void __init tegra_init_cpu_edp_limits(unsigned int regulator_mA)
123 {
124         int cpu_speedo_id = tegra_cpu_speedo_id;
125         int i, j;
126         struct tegra_edp_limits *e;
127         struct tegra_edp_entry *t = (struct tegra_edp_entry *)tegra_edp_map;
128         int tsize = sizeof(tegra_edp_map)/sizeof(struct tegra_edp_entry);
129
130         if (!regulator_mA) {
131                 edp_limits = edp_default_limits;
132                 edp_limits_size = ARRAY_SIZE(edp_default_limits);
133                 return;
134         }
135
136         for (i = 0; i < tsize; i++) {
137                 if (t[i].speedo_id == cpu_speedo_id &&
138                     t[i].regulator_100mA <= regulator_mA / 100)
139                         break;
140         }
141
142         /* No entry found in tegra_edp_map */
143         if (i >= tsize) {
144                 edp_limits = edp_default_limits;
145                 edp_limits_size = ARRAY_SIZE(edp_default_limits);
146                 return;
147         }
148
149         /* Find all rows for this entry */
150         for (j = i + 1; j < tsize; j++) {
151                 if (t[i].speedo_id != t[j].speedo_id ||
152                     t[i].regulator_100mA != t[j].regulator_100mA)
153                         break;
154         }
155
156         edp_limits_size = j - i;
157         e = kmalloc(sizeof(struct tegra_edp_limits) * edp_limits_size,
158                     GFP_KERNEL);
159         BUG_ON(!e);
160
161         for (j = 0; j < edp_limits_size; j++) {
162                 e[j].temperature = (int)t[i+j].temperature;
163                 e[j].freq_limits[0] = (unsigned int)t[i+j].freq_limits[0] * 10000;
164                 e[j].freq_limits[1] = (unsigned int)t[i+j].freq_limits[1] * 10000;
165                 e[j].freq_limits[2] = (unsigned int)t[i+j].freq_limits[2] * 10000;
166                 e[j].freq_limits[3] = (unsigned int)t[i+j].freq_limits[3] * 10000;
167         }
168
169         if (edp_limits && edp_limits != edp_default_limits)
170                 kfree(edp_limits);
171
172         edp_limits = e;
173 }
174
175 void tegra_get_cpu_edp_limits(const struct tegra_edp_limits **limits, int *size)
176 {
177         *limits = edp_limits;
178         *size = edp_limits_size;
179 }
180
181 #ifdef CONFIG_DEBUG_FS
182
183 static int edp_debugfs_show(struct seq_file *s, void *data)
184 {
185         int i;
186         const struct tegra_edp_limits *limits;
187         int size;
188
189         tegra_get_cpu_edp_limits(&limits, &size);
190
191         seq_printf(s, "-- EDP table --\n");
192         for (i = 0; i < size; i++) {
193                 seq_printf(s, "%4dC: %10d %10d %10d %10d\n",
194                            limits[i].temperature,
195                            limits[i].freq_limits[0],
196                            limits[i].freq_limits[1],
197                            limits[i].freq_limits[2],
198                            limits[i].freq_limits[3]);
199         }
200
201         return 0;
202 }
203
204
205 static int edp_debugfs_open(struct inode *inode, struct file *file)
206 {
207         return single_open(file, edp_debugfs_show, inode->i_private);
208 }
209
210
211 static const struct file_operations edp_debugfs_fops = {
212         .open           = edp_debugfs_open,
213         .read           = seq_read,
214         .llseek         = seq_lseek,
215         .release        = single_release,
216 };
217
218
219 static int __init tegra_edp_debugfs_init(void)
220 {
221         struct dentry *d;
222
223         d = debugfs_create_file("edp", S_IRUGO, NULL, NULL,
224                                 &edp_debugfs_fops);
225         if (!d)
226                 return -ENOMEM;
227
228         return 0;
229 }
230
231 late_initcall(tegra_edp_debugfs_init);
232 #endif /* CONFIG_DEBUG_FS */