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