aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/tegra3_speedo.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/tegra3_speedo.c')
-rw-r--r--arch/arm/mach-tegra/tegra3_speedo.c541
1 files changed, 541 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/tegra3_speedo.c b/arch/arm/mach-tegra/tegra3_speedo.c
new file mode 100644
index 00000000000..bd880bc7ca8
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra3_speedo.c
@@ -0,0 +1,541 @@
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#include <mach/tegra_fuse.h>
26
27#include "fuse.h"
28
29#define CORE_PROCESS_CORNERS_NUM 1
30#define CPU_PROCESS_CORNERS_NUM 7
31
32#define FUSE_SPEEDO_CALIB_0 0x114
33#define FUSE_PACKAGE_INFO 0X1FC
34#define FUSE_TEST_PROG_VER 0X128
35#define FUSE_SPARE_BIT_58 0x32c
36#define FUSE_SPARE_BIT_59 0x330
37#define FUSE_SPARE_BIT_60 0x334
38#define FUSE_SPARE_BIT_61 0x338
39#define FUSE_SPARE_BIT_62 0x33c
40#define FUSE_SPARE_BIT_63 0x340
41#define FUSE_SPARE_BIT_64 0x344
42#define FUSE_SPARE_BIT_65 0x348
43
44#define G_SPEEDO_BIT_MINUS1 FUSE_SPARE_BIT_58
45#define G_SPEEDO_BIT_MINUS1_R FUSE_SPARE_BIT_59
46#define G_SPEEDO_BIT_MINUS2 FUSE_SPARE_BIT_60
47#define G_SPEEDO_BIT_MINUS2_R FUSE_SPARE_BIT_61
48#define LP_SPEEDO_BIT_MINUS1 FUSE_SPARE_BIT_62
49#define LP_SPEEDO_BIT_MINUS1_R FUSE_SPARE_BIT_63
50#define LP_SPEEDO_BIT_MINUS2 FUSE_SPARE_BIT_64
51#define LP_SPEEDO_BIT_MINUS2_R FUSE_SPARE_BIT_65
52
53/* Maximum speedo levels for each core process corner */
54static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
55/* proc_id 0 */
56 {180}, /* [0]: soc_speedo_id 0: any A01 */
57
58/* T30 family */
59 {170}, /* [1]: soc_speedo_id 1: AP30 */
60 {195}, /* [2]: soc_speedo_id 2: T30 */
61 {180}, /* [3]: soc_speedo_id 2: T30S */
62
63/* Characterization SKUs */
64 {168}, /* [4]: soc_speedo_id 1: AP30 char */
65 {192}, /* [5]: soc_speedo_id 2: T30 char */
66 {180}, /* [6]: soc_speedo_id 2: T30S char */
67
68/* T33 family */
69 {170}, /* [7]: soc_speedo_id = 1 - AP33 */
70 {195}, /* [8]: soc_speedo_id = 2 - T33 */
71 {180}, /* [9]: soc_speedo_id = 2 - T33S/AP37 */
72
73/* T30 'L' family */
74 {180}, /* [10]: soc_speedo_id 1: T30L */
75 {180}, /* [11]: soc_speedo_id 1: T30SL */
76
77/* T30 Automotives */
78 {185}, /* [12]: soc_speedo_id = 3 - Automotives */
79 {185}, /* [13]: soc_speedo_id = 3 - Automotives */
80
81/* T37 Family*/
82 {210}, /* [14]: soc_speedo_id 2: T37 */
83};
84
85/* Maximum speedo levels for each CPU process corner */
86static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
87/* proc_id 0 1 2 3 4*/
88 {306, 338, 360, 376, UINT_MAX}, /* [0]: cpu_speedo_id 0: any A01 */
89
90/* T30 family */
91 {295, 336, 358, 375, UINT_MAX}, /* [1]: cpu_speedo_id 1: AP30 */
92 {325, 325, 358, 375, UINT_MAX}, /* [2]: cpu_speedo_id 2: T30 */
93 {325, 325, 358, 375, UINT_MAX}, /* [3]: cpu_speedo_id 3: T30S */
94
95/* Characterization SKUs */
96 {292, 324, 348, 364, UINT_MAX}, /* [4]: cpu_speedo_id 1: AP30char */
97 {324, 324, 348, 364, UINT_MAX}, /* [5]: cpu_speedo_id 2: T30char */
98 {324, 324, 348, 364, UINT_MAX}, /* [6]: cpu_speedo_id 3: T30Schar */
99
100/* T33 family */
101 {295, 336, 358, 375, UINT_MAX}, /* [7]: cpu_speedo_id: 4: AP33 */
102 {358, 358, 358, 358, 397, UINT_MAX}, /* [8]: cpu_speedo_id: 5: T33 */
103 {364, 364, 364, 364, 397, UINT_MAX}, /* [9]: cpu_speedo_id: 6/12: T33S/AP37 */
104
105/* T30 'L' family */
106 {295, 336, 358, 375, 391, UINT_MAX}, /* [10]: cpu_speedo_id 7: T30L */
107 {295, 336, 358, 375, 391, UINT_MAX}, /* [11]: cpu_speedo_id 8: T30SL */
108
109/* T30 Automotives */
110 /* threshold_index 12: cpu_speedo_id 9 & 10
111 * 0,1,2 values correspond to speedo_id 9
112 * 3,4,5 values correspond to speedo_id 10 */
113 {300, 311, 360, 371, 381, 415, 431},
114 {300, 311, 410, 431, UINT_MAX}, /* [13]: cpu_speedo_id 11: T30 auto */
115
116/* T37 family */
117 {358, 358, 358, 358, 397, UINT_MAX}, /* [14]: cpu_speedo_id 13: T37 */
118};
119
120/*
121 * Common speedo_value array threshold index for both core_process_speedos and
122 * cpu_process_speedos arrays. Make sure these two arrays are always in synch.
123 */
124static int threshold_index;
125
126static int cpu_process_id;
127static int core_process_id;
128static int cpu_speedo_id;
129static int soc_speedo_id;
130static int package_id;
131
132static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp)
133{
134 u32 reg;
135 int ate_ver, bit_minus1, bit_minus2;
136
137 BUG_ON(!speedo_g || !speedo_lp);
138 reg = tegra_fuse_readl(FUSE_SPEEDO_CALIB_0);
139
140 /* Speedo LP = Lower 16-bits Multiplied by 4 */
141 *speedo_lp = (reg & 0xFFFF) * 4;
142
143 /* Speedo G = Upper 16-bits Multiplied by 4 */
144 *speedo_g = ((reg >> 16) & 0xFFFF) * 4;
145
146 if (tegra_fuse_get_revision(&ate_ver))
147 return;
148 pr_info("%s: ATE prog ver %d.%d\n", __func__, ate_ver/10, ate_ver%10);
149
150 pr_debug("CPU speedo base value %u (0x%3x)\n", *speedo_g, *speedo_g);
151 pr_debug("Core speedo base value %u (0x%3x)\n", *speedo_lp, *speedo_lp);
152
153 if (ate_ver >= 26) {
154 /* read lower 2 bits of LP speedo from spare fuses */
155 bit_minus1 = tegra_fuse_readl(LP_SPEEDO_BIT_MINUS1) & 0x1;
156 bit_minus1 |= tegra_fuse_readl(LP_SPEEDO_BIT_MINUS1_R) & 0x1;
157 bit_minus2 = tegra_fuse_readl(LP_SPEEDO_BIT_MINUS2) & 0x1;
158 bit_minus2 |= tegra_fuse_readl(LP_SPEEDO_BIT_MINUS2_R) & 0x1;
159 *speedo_lp |= (bit_minus1 << 1) | bit_minus2;
160
161 /* read lower 2 bits of G speedo from spare fuses */
162 bit_minus1 = tegra_fuse_readl(G_SPEEDO_BIT_MINUS1) & 0x1;
163 bit_minus1 |= tegra_fuse_readl(G_SPEEDO_BIT_MINUS1_R) & 0x1;
164 bit_minus2 = tegra_fuse_readl(G_SPEEDO_BIT_MINUS2) & 0x1;
165 bit_minus2 |= tegra_fuse_readl(G_SPEEDO_BIT_MINUS2_R) & 0x1;
166 *speedo_g |= (bit_minus1 << 1) | bit_minus2;
167 } else {
168 /* set lower 2 bits for speedo ate-ver independent comparison */
169 *speedo_lp |= 0x3;
170 *speedo_g |= 0x3;
171 }
172}
173
174static void rev_sku_to_speedo_ids(int rev, int sku)
175{
176 switch (rev) {
177 case TEGRA_REVISION_A01: /* any A01 */
178 cpu_speedo_id = 0;
179 soc_speedo_id = 0;
180 threshold_index = 0;
181 break;
182
183 case TEGRA_REVISION_A02:
184 case TEGRA_REVISION_A03:
185 switch (sku) {
186 case 0x87: /* AP30 */
187 case 0x82: /* T30V */
188 cpu_speedo_id = 1;
189 soc_speedo_id = 1;
190 threshold_index = 1;
191 break;
192
193 case 0x81: /* T30 */
194 switch (package_id) {
195 case 1: /* MID => T30 */
196 cpu_speedo_id = 2;
197 soc_speedo_id = 2;
198 threshold_index = 2;
199 break;
200 case 2: /* DSC => AP33 */
201 cpu_speedo_id = 4;
202 soc_speedo_id = 1;
203 threshold_index = 7;
204 break;
205 default:
206 pr_err("Tegra3 Rev-A02: Reserved pkg: %d\n",
207 package_id);
208 BUG();
209 break;
210 }
211 break;
212
213 case 0x80: /* T33 or T33S */
214 switch (package_id) {
215 case 1: /* MID => T33 */
216 cpu_speedo_id = 5;
217 soc_speedo_id = 2;
218 threshold_index = 8;
219 break;
220 case 2: /* DSC => T33S */
221 cpu_speedo_id = 6;
222 soc_speedo_id = 2;
223 threshold_index = 9;
224 break;
225 default:
226 pr_err("Tegra3 Rev-A02: Reserved pkg: %d\n",
227 package_id);
228 BUG();
229 break;
230 }
231 break;
232
233 case 0x83: /* T30L or T30S */
234 switch (package_id) {
235 case 1: /* MID => T30L */
236 cpu_speedo_id = 7;
237 soc_speedo_id = 1;
238 threshold_index = 10;
239 break;
240 case 2: /* DSC => T30S */
241 cpu_speedo_id = 3;
242 soc_speedo_id = 2;
243 threshold_index = 3;
244 break;
245 default:
246 pr_err("Tegra3 Rev-A02: Reserved pkg: %d\n",
247 package_id);
248 BUG();
249 break;
250 }
251 break;
252
253 case 0x8F: /* T30SL */
254 cpu_speedo_id = 8;
255 soc_speedo_id = 1;
256 threshold_index = 11;
257 break;
258
259 case 0xA0: /* T37 or A37 */
260 switch (package_id) {
261 case 1: /* MID => T37 */
262 cpu_speedo_id = 13;
263 soc_speedo_id = 2;
264 threshold_index = 14;
265 break;
266 case 2: /* DSC => AP37 */
267 cpu_speedo_id = 12;
268 soc_speedo_id = 2;
269 threshold_index = 9;
270 break;
271 default:
272 pr_err("Tegra3 Rev-A02: Reserved pkg: %d\n",
273 package_id);
274 BUG();
275 break;
276 }
277 break;
278
279/* Characterization SKUs */
280 case 0x08: /* AP30 char */
281 cpu_speedo_id = 1;
282 soc_speedo_id = 1;
283 threshold_index = 4;
284 break;
285 case 0x02: /* T30 char */
286 cpu_speedo_id = 2;
287 soc_speedo_id = 2;
288 threshold_index = 5;
289 break;
290 case 0x04: /* T30S char */
291 cpu_speedo_id = 3;
292 soc_speedo_id = 2;
293 threshold_index = 6;
294 break;
295
296 case 0x91: /* T30AGS-Ax */
297 case 0xb0: /* T30IQS-Ax */
298 case 0xb1: /* T30MQS-Ax */
299 case 0x90: /* T30AQS-Ax */
300 soc_speedo_id = 3;
301 threshold_index = 12;
302 break;
303 case 0x93: /* T30AG-Ax */
304 cpu_speedo_id = 11;
305 soc_speedo_id = 3;
306 threshold_index = 13;
307 break;
308 case 0: /* ENG - check package_id */
309 pr_info("Tegra3 ENG SKU: Checking package_id\n");
310 switch (package_id) {
311 case 1: /* MID => assume T30 */
312 cpu_speedo_id = 2;
313 soc_speedo_id = 2;
314 threshold_index = 2;
315 break;
316 case 2: /* DSC => assume T30S */
317 cpu_speedo_id = 3;
318 soc_speedo_id = 2;
319 threshold_index = 3;
320 break;
321 default:
322 pr_err("Tegra3 Rev-A02: Reserved pkg: %d\n",
323 package_id);
324 BUG();
325 break;
326 }
327 break;
328
329 default:
330 /* FIXME: replace with BUG() when all SKU's valid */
331 pr_err("Tegra3 Rev-A02: Unknown SKU %d\n", sku);
332 cpu_speedo_id = 0;
333 soc_speedo_id = 0;
334 threshold_index = 0;
335 break;
336 }
337 break;
338 default:
339 BUG();
340 break;
341 }
342}
343
344void tegra_init_speedo_data(void)
345{
346 u32 cpu_speedo_val, core_speedo_val;
347 int iv;
348 int fuse_sku = tegra_sku_id();
349 int sku_override = tegra_get_sku_override();
350 int new_sku = fuse_sku;
351
352 /* Package info: 4 bits - 0,3:reserved 1:MID 2:DSC */
353 package_id = tegra_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F;
354
355 /* Arrays must be of equal size - each index corresponds to a SKU */
356 BUG_ON(ARRAY_SIZE(cpu_process_speedos) !=
357 ARRAY_SIZE(core_process_speedos));
358
359 /* SKU Overrides
360 * T33 => T30, T30L
361 * T33S => T30S, T30SL
362 * T30 => T30L
363 * T30S => T30SL
364 * AP33 => AP30
365 */
366 switch (sku_override) {
367 case 1:
368 /* Base sku override */
369 if (fuse_sku == 0x80) {
370 if (package_id == 1) {
371 /* T33 to T30 */
372 pr_info("%s: SKU OR: T33->T30\n", __func__);
373 new_sku = 0x81;
374 } else if (package_id == 2) {
375 /* T33S->T30S */
376 pr_info("%s: SKU OR: T33S->T30S\n", __func__);
377 new_sku = 0x83;
378 }
379 } else if (fuse_sku == 0x81) {
380 if (package_id == 2) {
381 /* AP33->AP30 */
382 pr_info("%s: SKU OR: AP33->AP30\n", __func__);
383 new_sku = 0x87;
384 }
385 }
386 break;
387 case 2:
388 /* L sku override */
389 if (fuse_sku == 0x80) {
390 if (package_id == 1) {
391 /* T33->T30L */
392 pr_info("%s: SKU OR: T33->T30L\n", __func__);
393 new_sku = 0x83;
394 } else if (package_id == 2) {
395 /* T33S->T33SL */
396 pr_info("%s: SKU OR: T33S->T30SL\n", __func__);
397 new_sku = 0x8f;
398 }
399 } else if (fuse_sku == 0x81) {
400 if (package_id == 1) {
401 pr_info("%s: SKU OR: T30->T30L\n", __func__);
402 /* T30->T30L */
403 new_sku = 0x83;
404 }
405 } else if (fuse_sku == 0x83) {
406 if (package_id == 2) {
407 pr_info("%s: SKU OR: T30S->T30SL\n", __func__);
408 /* T30S to T30SL */
409 new_sku = 0x8f;
410 }
411 }
412 break;
413 default:
414 /* no override */
415 break;
416 }
417
418 rev_sku_to_speedo_ids(tegra_get_revision(), new_sku);
419 BUG_ON(threshold_index >= ARRAY_SIZE(cpu_process_speedos));
420
421 fuse_speedo_calib(&cpu_speedo_val, &core_speedo_val);
422 pr_debug("%s CPU speedo value %u\n", __func__, cpu_speedo_val);
423 pr_debug("%s Core speedo value %u\n", __func__, core_speedo_val);
424
425 for (iv = 0; iv < CPU_PROCESS_CORNERS_NUM; iv++) {
426 if (cpu_speedo_val <
427 cpu_process_speedos[threshold_index][iv]) {
428 break;
429 }
430 }
431 cpu_process_id = iv -1;
432
433 if (cpu_process_id == -1) {
434 pr_err("****************************************************");
435 pr_err("****************************************************");
436 pr_err("* tegra3_speedo: CPU speedo value %3d out of range *",
437 cpu_speedo_val);
438 pr_err("****************************************************");
439 pr_err("****************************************************");
440
441 cpu_process_id = INVALID_PROCESS_ID;
442 cpu_speedo_id = 1;
443 }
444
445 for (iv = 0; iv < CORE_PROCESS_CORNERS_NUM; iv++) {
446 if (core_speedo_val <
447 core_process_speedos[threshold_index][iv]) {
448 break;
449 }
450 }
451 core_process_id = iv -1;
452
453 if (core_process_id == -1) {
454 pr_err("****************************************************");
455 pr_err("****************************************************");
456 pr_err("* tegra3_speedo: CORE speedo value %3d out of range *",
457 core_speedo_val);
458 pr_err("****************************************************");
459 pr_err("****************************************************");
460
461 core_process_id = INVALID_PROCESS_ID;
462 soc_speedo_id = 1;
463 }
464 if (threshold_index == 12 && cpu_process_id != INVALID_PROCESS_ID) {
465 if (cpu_process_id <= 2)
466 cpu_speedo_id = 9;
467 else if (cpu_process_id >= 3 && cpu_process_id < 6)
468 cpu_speedo_id = 10;
469 }
470 pr_info("Tegra3: CPU Speedo ID %d, Soc Speedo ID %d",
471 cpu_speedo_id, soc_speedo_id);
472}
473
474int tegra_cpu_process_id(void)
475{
476 /* FIXME: remove when ready to deprecate invalid process-id boards */
477 if (cpu_process_id == INVALID_PROCESS_ID)
478 return 0;
479 else
480 return cpu_process_id;
481}
482
483int tegra_core_process_id(void)
484{
485 /* FIXME: remove when ready to deprecate invalid process-id boards */
486 if (core_process_id == INVALID_PROCESS_ID)
487 return 0;
488 else
489 return core_process_id;
490}
491
492int tegra_cpu_speedo_id(void)
493{
494 return cpu_speedo_id;
495}
496
497int tegra_soc_speedo_id(void)
498{
499 return soc_speedo_id;
500}
501
502int tegra_package_id(void)
503{
504 return package_id;
505}
506
507/*
508 * CPU and core nominal voltage levels as determined by chip SKU and speedo
509 * (not final - can be lowered by dvfs tables and rail dependencies; the
510 * latter is resolved by the dvfs code)
511 */
512static const int cpu_speedo_nominal_millivolts[] =
513/* speedo_id 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 */
514 { 1125, 1150, 1150, 1150, 1237, 1237, 1237, 1150, 1150, 912, 850, 850, 1237, 1237};
515
516int tegra_cpu_speedo_mv(void)
517{
518 BUG_ON(cpu_speedo_id >= ARRAY_SIZE(cpu_speedo_nominal_millivolts));
519 return cpu_speedo_nominal_millivolts[cpu_speedo_id];
520}
521
522int tegra_core_speedo_mv(void)
523{
524 switch (soc_speedo_id) {
525 case 0:
526 return 1200;
527 case 1:
528 if ((cpu_speedo_id != 7) && (cpu_speedo_id != 8))
529 return 1200;
530 /* fall thru for T30L or T30SL */
531 case 2:
532 if (cpu_speedo_id != 13)
533 return 1300;
534 /* T37 */
535 return 1350;
536 case 3:
537 return 1250;
538 default:
539 BUG();
540 }
541}