ARM: Tegra: dvfs: Proc array indep of new T30 char SKUs
[linux-2.6.git] / arch / arm / mach-tegra / tegra3_speedo.c
1 /*
2  * arch/arm/mach-tegra/tegra3_speedo.c
3  *
4  * Copyright (c) 2011, NVIDIA Corporation.
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 as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20
21 #include <linux/kernel.h>
22 #include <linux/io.h>
23 #include <linux/err.h>
24 #include <mach/iomap.h>
25
26 #include "fuse.h"
27
28 #define CORE_PROCESS_CORNERS_NUM        1
29 #define CPU_PROCESS_CORNERS_NUM         4
30
31 #define FUSE_SPEEDO_CALIB_0     0x114
32 #define FUSE_PACKAGE_INFO       0X1FC
33
34 /* Maximum speedo levels for each core process corner */
35 static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
36 /* proc_id 0 */
37         {180}, /* threshold_index 0: soc_speedo_id 0: any A01 */
38
39 /* T30 family */
40         {183}, /* threshold_index 1: soc_speedo_id 1: AP30 */
41         {197}, /* threshold_index 2: soc_speedo_id 2: T30  */
42         {197}, /* threshold_index 3: soc_speedo_id 2: T30S */
43
44 /* Characterization SKUs */
45         {170}, /* threshold_index 4: soc_speedo_id 1: AP30 char */
46         {190}, /* threshold_index 5: soc_speedo_id 2: T30  char */
47         {190}, /* threshold_index 6: soc_speedo_id 2: T30S char */
48 };
49
50 /* Maximum speedo levels for each CPU process corner */
51 static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
52 /* proc_id 0    1    2    3 */
53         {306, 338, 360, 376}, /* threshold_index 0: cpu_speedo_id 0: any A01 */
54
55 /* T30 family */
56         {306, 338, 360, 376}, /* threshold_index 1: cpu_speedo_id 1: AP30 */
57         {338, 338, 360, 376}, /* threshold_index 2: cpu_speedo_id 2: T30  */
58         {338, 338, 360, 376}, /* threshold_index 3: cpu_speedo_id 3: T30S */
59
60 /* Characterization SKUs */
61         {295, 326, 348, 364}, /* threshold_index 4: cpu_speedo_id 1: AP30char */
62         {326, 326, 348, 364}, /* threshold_index 5: cpu_speedo_id 2: T30char  */
63         {326, 326, 348, 364}, /* threshold_index 6: cpu_speedo_id 3: T30Schar */
64 };
65
66 /*
67  * Common speedo_value array threshold index for both core_process_speedos and
68  * cpu_process_speedos arrays. Make sure these two arrays are always in synch.
69  */
70 static int threshold_index;
71
72 static int cpu_process_id;
73 static int core_process_id;
74 static int cpu_speedo_id;
75 static int soc_speedo_id;
76 static int package_id;
77
78 static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp)
79 {
80         u32 reg;
81
82         BUG_ON(!speedo_g || !speedo_lp);
83         reg = tegra_fuse_readl(FUSE_SPEEDO_CALIB_0);
84
85         /* Speedo LP = Lower 16-bits Multiplied by 4 */
86         *speedo_lp = (reg & 0xFFFF) * 4;
87
88         /* Speedo G = Upper 16-bits Multiplied by 4 */
89         *speedo_g = ((reg >> 16) & 0xFFFF) * 4;
90 }
91
92 static void rev_sku_to_speedo_ids(int rev, int sku)
93 {
94         switch (rev) {
95         case TEGRA_REVISION_A01: /* any A01 */
96                 cpu_speedo_id = 0;
97                 soc_speedo_id = 0;
98                 threshold_index = 0;
99                 break;
100
101         case TEGRA_REVISION_A02:
102         case TEGRA_REVISION_A03:
103                 switch (sku) {
104                 case 0x87: /* AP30 */
105                         cpu_speedo_id = 1;
106                         soc_speedo_id = 1;
107                         threshold_index = 1;
108                         break;
109
110                 case 0x81: /* T30 */
111                         switch (package_id) {
112                         case 1: /* MID => T30 */
113                                 cpu_speedo_id = 2;
114                                 soc_speedo_id = 2;
115                                 threshold_index = 2;
116                                 break;
117                         default:
118                                 pr_err("Tegra3 Rev-A02: Reserved pkg: %d\n",
119                                        package_id);
120                                 BUG();
121                                 break;
122                         }
123                         break;
124
125                 case 0x83: /* T30S */
126                         cpu_speedo_id = 3;
127                         soc_speedo_id = 2;
128                         threshold_index = 3;
129                         break;
130
131 /* Characterization SKUs */
132                 case 0x08: /* AP30 char */
133                         cpu_speedo_id = 1;
134                         soc_speedo_id = 1;
135                         threshold_index = 4;
136                         break;
137                 case 0x02: /* T30 char */
138                         cpu_speedo_id = 2;
139                         soc_speedo_id = 2;
140                         threshold_index = 5;
141                         break;
142                 case 0x04: /* T30S char */
143                         cpu_speedo_id = 3;
144                         soc_speedo_id = 2;
145                         threshold_index = 6;
146                         break;
147
148                 case 0:    /* ENG - check package_id */
149                         pr_info("Tegra3 ENG SKU: Checking package_id\n");
150                         switch (package_id) {
151                         case 1: /* MID => assume T30 */
152                                 cpu_speedo_id = 2;
153                                 soc_speedo_id = 2;
154                                 threshold_index = 2;
155                                 break;
156                         case 2: /* DSC => assume T30S */
157                                 cpu_speedo_id = 3;
158                                 soc_speedo_id = 2;
159                                 threshold_index = 3;
160                                 break;
161                         default:
162                                 pr_err("Tegra3 Rev-A02: Reserved pkg: %d\n",
163                                        package_id);
164                                 BUG();
165                                 break;
166                         }
167                         break;
168
169                 default:
170                         /* FIXME: replace with BUG() when all SKU's valid */
171                         pr_err("Tegra3 Rev-A02: Unknown SKU %d\n", sku);
172                         cpu_speedo_id = 0;
173                         soc_speedo_id = 0;
174                         threshold_index = 0;
175                         break;
176                 }
177                 break;
178         default:
179                 BUG();
180                 break;
181         }
182 }
183
184 void tegra_init_speedo_data(void)
185 {
186         u32 cpu_speedo_val, core_speedo_val;
187         int iv;
188
189         /* Package info: 4 bits - 0,3:reserved 1:MID 2:DSC */
190         package_id = tegra_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F;
191
192         /* Arrays must be of equal size - each index corresponds to a SKU */
193         BUG_ON(ARRAY_SIZE(cpu_process_speedos) !=
194                ARRAY_SIZE(core_process_speedos));
195
196         rev_sku_to_speedo_ids(tegra_get_revision(), tegra_sku_id());
197         BUG_ON(threshold_index >= ARRAY_SIZE(cpu_process_speedos));
198
199         fuse_speedo_calib(&cpu_speedo_val, &core_speedo_val);
200         pr_debug("%s CPU speedo value %u\n", __func__, cpu_speedo_val);
201         pr_debug("%s Core speedo value %u\n", __func__, core_speedo_val);
202
203         for (iv = 0; iv < CPU_PROCESS_CORNERS_NUM; iv++) {
204                 if (cpu_speedo_val <
205                     cpu_process_speedos[threshold_index][iv]) {
206                         break;
207                 }
208         }
209         cpu_process_id = iv -1;
210
211         if (cpu_process_id == -1) {
212                 pr_err("****************************************************");
213                 pr_err("****************************************************");
214                 pr_err("* tegra3_speedo: CPU speedo value %3d out of range *",
215                        cpu_speedo_val);
216                 pr_err("****************************************************");
217                 pr_err("****************************************************");
218
219                 cpu_process_id = INVALID_PROCESS_ID;
220                 cpu_speedo_id = 0;
221         }
222
223         for (iv = 0; iv < CORE_PROCESS_CORNERS_NUM; iv++) {
224                 if (core_speedo_val <
225                     core_process_speedos[threshold_index][iv]) {
226                         break;
227                 }
228         }
229         core_process_id = iv -1;
230
231         if (core_process_id == -1) {
232                 pr_err("*****************************************************");
233                 pr_err("*****************************************************");
234                 pr_err("* tegra3_speedo: CORE speedo value %3d out of range *",
235                        core_speedo_val);
236                 pr_err("*****************************************************");
237                 pr_err("*****************************************************");
238
239                 core_process_id = INVALID_PROCESS_ID;
240                 soc_speedo_id = 0;
241         }
242
243         pr_info("Tegra3: CPU Speedo ID %d, Soc Speedo ID %d",
244                  cpu_speedo_id, soc_speedo_id);
245 }
246
247 int tegra_cpu_process_id(void)
248 {
249         /* FIXME: remove when ready to deprecate invalid process-id boards */
250         if (cpu_process_id == INVALID_PROCESS_ID)
251                 return 0;
252         else
253                 return cpu_process_id;
254 }
255
256 int tegra_core_process_id(void)
257 {
258         /* FIXME: remove when ready to deprecate invalid process-id boards */
259         if (core_process_id == INVALID_PROCESS_ID)
260                 return 0;
261         else
262                 return core_process_id;
263 }
264
265 int tegra_cpu_speedo_id(void)
266 {
267         return cpu_speedo_id;
268 }
269
270 int tegra_soc_speedo_id(void)
271 {
272         return soc_speedo_id;
273 }
274
275 int tegra_package_id(void)
276 {
277         return package_id;
278 }