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