ARM: tegra: Clear speedo_id on incorrectly fused Tegra3
[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 PROCESS_CORNERS_NUM     4
29
30 #define FUSE_SPEEDO_CALIB_0     0x114
31
32 /* Maximum speedo levels for each core process corner */
33 static const u32 core_process_speedos[][PROCESS_CORNERS_NUM] = {
34 // proc_id 0    1
35         {180, 240}, // soc_speedo_id 0
36         {180, 240}, // soc_speedo_id 1
37         {200, 240}, // soc_speedo_id 2
38 };
39
40 /* Maximum speedo levels for each CPU process corner */
41 static const u32 cpu_process_speedos[][PROCESS_CORNERS_NUM] = {
42 // proc_id 0    1    2    3
43         {306, 338, 360, 376}, // soc_speedo_id 0
44         {306, 338, 360, 376}, // soc_speedo_id 1
45         {338, 338, 360, 376}, // soc_speedo_id 2
46 };
47
48 static int cpu_process_id;
49 static int core_process_id;
50 static int soc_speedo_id;
51
52 static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp)
53 {
54         u32 reg;
55
56         BUG_ON(!speedo_g || !speedo_lp);
57         reg = tegra_fuse_readl(FUSE_SPEEDO_CALIB_0);
58
59         // Speedo LP = Lower 16-bits Multiplied by 4
60         *speedo_lp = (reg & 0xFFFF) * 4;
61
62         // Speedo G = Upper 16-bits Multiplied by 4
63         *speedo_g = ((reg >> 16) & 0xFFFF) * 4;
64 }
65
66 static int rev_sku_to_soc_speedo(int rev, int sku)
67 {
68         int soc_speedo;
69
70         switch (rev) {
71         case TEGRA_REVISION_A01:
72                 soc_speedo = 0;
73                 break;
74         case TEGRA_REVISION_A02:
75                 switch (sku) {
76                 case 0x87: // AP30
77                         soc_speedo = 1;
78                         break;
79                 case 0x81: // T30
80                 case 0:    // ENG
81                         soc_speedo = 2;
82                         break;
83                 default:
84                         // FIXME: replace with BUG() when all SKU's valid
85                         pr_err("Tegra3 Rev-A02: Unknown SKU %d\n", sku);
86                         soc_speedo = 0;
87                         break;
88                 }
89                 break;
90         default:
91                 BUG();
92                 break;
93         }
94
95         pr_debug("Tegra3 SKU: %d Rev: %s Speedo: %d ",
96                  sku, tegra_get_revision_name(), soc_speedo);
97         return soc_speedo;
98 }
99
100 void tegra_init_speedo_data(void)
101 {
102         u32 cpu_speedo_val, core_speedo_val;
103         int iv;
104
105         soc_speedo_id = rev_sku_to_soc_speedo(tegra_get_revision(),
106                                               tegra_sku_id());
107         BUG_ON(soc_speedo_id >= ARRAY_SIZE(cpu_process_speedos));
108
109         fuse_speedo_calib(&cpu_speedo_val, &core_speedo_val);
110         pr_debug("%s CPU speedo value %u\n", __func__, cpu_speedo_val);
111         pr_debug("%s Core speedo value %u\n", __func__, core_speedo_val);
112
113         for (iv = 0; iv < PROCESS_CORNERS_NUM; iv++) {
114                 if (cpu_speedo_val < cpu_process_speedos[soc_speedo_id][iv]) {
115                         break;
116                 }
117         }
118         cpu_process_id = iv -1;
119
120         if (cpu_process_id == -1) {
121                 pr_err("****************************************************");
122                 pr_err("****************************************************");
123                 pr_err("* tegra3_speedo: CPU speedo value %3d out of range *",
124                        cpu_speedo_val);
125                 pr_err("****************************************************");
126                 pr_err("****************************************************");
127
128                 cpu_process_id = INVALID_PROCESS_ID;
129                 soc_speedo_id = 0;
130         }
131
132         for (iv = 0; iv < PROCESS_CORNERS_NUM; iv++) {
133                 if (core_speedo_val < core_process_speedos[soc_speedo_id][iv]) {
134                         break;
135                 }
136         }
137         core_process_id = iv -1;
138
139         if (core_process_id == -1) {
140                 pr_err("*****************************************************");
141                 pr_err("*****************************************************");
142                 pr_err("* tegra3_speedo: CORE speedo value %3d out of range *",
143                        core_speedo_val);
144                 pr_err("*****************************************************");
145                 pr_err("*****************************************************");
146
147                 core_process_id = INVALID_PROCESS_ID;
148                 soc_speedo_id = 0;
149         }
150
151         pr_debug("%s Soc speedo value %d", __func__, soc_speedo_id);
152 }
153
154 int tegra_cpu_process_id(void)
155 {
156         // FIXME: remove this when ready to deprecate invalid process-id boards
157         if (cpu_process_id == INVALID_PROCESS_ID)
158                 return 0;
159         else
160                 return cpu_process_id;
161 }
162
163 int tegra_core_process_id(void)
164 {
165         // FIXME: remove this when ready to deprecate invalid process-id boards
166         if (core_process_id == INVALID_PROCESS_ID)
167                 return 0;
168         else
169                 return core_process_id;
170 }
171
172 int tegra_soc_speedo_id(void)
173 {
174         return soc_speedo_id;
175 }