ARM: tegra: Tegra30 speedo-based process identification
[linux-2.6-microblaze.git] / arch / arm / mach-tegra / tegra30_speedo.c
1 /*
2  * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms and conditions of the GNU General Public License,
6  * version 2, as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
16
17 #include <linux/kernel.h>
18 #include <linux/bug.h>
19
20 #include "fuse.h"
21
22 #define CORE_PROCESS_CORNERS_NUM        1
23 #define CPU_PROCESS_CORNERS_NUM         6
24
25 #define FUSE_SPEEDO_CALIB_0     0x114
26 #define FUSE_PACKAGE_INFO       0X1FC
27 #define FUSE_TEST_PROG_VER      0X128
28
29 #define G_SPEEDO_BIT_MINUS1     58
30 #define G_SPEEDO_BIT_MINUS1_R   59
31 #define G_SPEEDO_BIT_MINUS2     60
32 #define G_SPEEDO_BIT_MINUS2_R   61
33 #define LP_SPEEDO_BIT_MINUS1    62
34 #define LP_SPEEDO_BIT_MINUS1_R  63
35 #define LP_SPEEDO_BIT_MINUS2    64
36 #define LP_SPEEDO_BIT_MINUS2_R  65
37
38 enum {
39         THRESHOLD_INDEX_0,
40         THRESHOLD_INDEX_1,
41         THRESHOLD_INDEX_2,
42         THRESHOLD_INDEX_3,
43         THRESHOLD_INDEX_4,
44         THRESHOLD_INDEX_5,
45         THRESHOLD_INDEX_6,
46         THRESHOLD_INDEX_7,
47         THRESHOLD_INDEX_8,
48         THRESHOLD_INDEX_9,
49         THRESHOLD_INDEX_10,
50         THRESHOLD_INDEX_11,
51         THRESHOLD_INDEX_COUNT,
52 };
53
54 static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
55         {180},
56         {170},
57         {195},
58         {180},
59         {168},
60         {192},
61         {180},
62         {170},
63         {195},
64         {180},
65         {180},
66         {180},
67 };
68
69 static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
70         {306, 338, 360, 376, UINT_MAX},
71         {295, 336, 358, 375, UINT_MAX},
72         {325, 325, 358, 375, UINT_MAX},
73         {325, 325, 358, 375, UINT_MAX},
74         {292, 324, 348, 364, UINT_MAX},
75         {324, 324, 348, 364, UINT_MAX},
76         {324, 324, 348, 364, UINT_MAX},
77         {295, 336, 358, 375, UINT_MAX},
78         {358, 358, 358, 358, 397, UINT_MAX},
79         {364, 364, 364, 364, 397, UINT_MAX},
80         {295, 336, 358, 375, 391, UINT_MAX},
81         {295, 336, 358, 375, 391, UINT_MAX},
82 };
83
84 static int threshold_index;
85 static int package_id;
86
87 static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp)
88 {
89         u32 reg;
90         int ate_ver;
91         int bit_minus1;
92         int bit_minus2;
93
94         reg = tegra_fuse_readl(FUSE_SPEEDO_CALIB_0);
95
96         *speedo_lp = (reg & 0xFFFF) * 4;
97         *speedo_g = ((reg >> 16) & 0xFFFF) * 4;
98
99         ate_ver = tegra_fuse_readl(FUSE_TEST_PROG_VER);
100         pr_info("%s: ATE prog ver %d.%d\n", __func__, ate_ver/10, ate_ver%10);
101
102         if (ate_ver >= 26) {
103                 bit_minus1 = tegra_spare_fuse(LP_SPEEDO_BIT_MINUS1);
104                 bit_minus1 |= tegra_spare_fuse(LP_SPEEDO_BIT_MINUS1_R);
105                 bit_minus2 = tegra_spare_fuse(LP_SPEEDO_BIT_MINUS2);
106                 bit_minus2 |= tegra_spare_fuse(LP_SPEEDO_BIT_MINUS2_R);
107                 *speedo_lp |= (bit_minus1 << 1) | bit_minus2;
108
109                 bit_minus1 = tegra_spare_fuse(G_SPEEDO_BIT_MINUS1);
110                 bit_minus1 |= tegra_spare_fuse(G_SPEEDO_BIT_MINUS1_R);
111                 bit_minus2 = tegra_spare_fuse(G_SPEEDO_BIT_MINUS2);
112                 bit_minus2 |= tegra_spare_fuse(G_SPEEDO_BIT_MINUS2_R);
113                 *speedo_g |= (bit_minus1 << 1) | bit_minus2;
114         } else {
115                 *speedo_lp |= 0x3;
116                 *speedo_g |= 0x3;
117         }
118 }
119
120 static void rev_sku_to_speedo_ids(int rev, int sku)
121 {
122         switch (rev) {
123         case TEGRA_REVISION_A01:
124                 tegra_cpu_speedo_id = 0;
125                 tegra_soc_speedo_id = 0;
126                 threshold_index = THRESHOLD_INDEX_0;
127                 break;
128         case TEGRA_REVISION_A02:
129         case TEGRA_REVISION_A03:
130                 switch (sku) {
131                 case 0x87:
132                 case 0x82:
133                         tegra_cpu_speedo_id = 1;
134                         tegra_soc_speedo_id = 1;
135                         threshold_index = THRESHOLD_INDEX_1;
136                         break;
137                 case 0x81:
138                         switch (package_id) {
139                         case 1:
140                                 tegra_cpu_speedo_id = 2;
141                                 tegra_soc_speedo_id = 2;
142                                 threshold_index = THRESHOLD_INDEX_2;
143                                 break;
144                         case 2:
145                                 tegra_cpu_speedo_id = 4;
146                                 tegra_soc_speedo_id = 1;
147                                 threshold_index = THRESHOLD_INDEX_7;
148                                 break;
149                         default:
150                                 pr_err("Tegra30: Unknown pkg %d\n", package_id);
151                                 BUG();
152                                 break;
153                         }
154                         break;
155                 case 0x80:
156                         switch (package_id) {
157                         case 1:
158                                 tegra_cpu_speedo_id = 5;
159                                 tegra_soc_speedo_id = 2;
160                                 threshold_index = THRESHOLD_INDEX_8;
161                                 break;
162                         case 2:
163                                 tegra_cpu_speedo_id = 6;
164                                 tegra_soc_speedo_id = 2;
165                                 threshold_index = THRESHOLD_INDEX_9;
166                                 break;
167                         default:
168                                 pr_err("Tegra30: Unknown pkg %d\n", package_id);
169                                 BUG();
170                                 break;
171                         }
172                         break;
173                 case 0x83:
174                         switch (package_id) {
175                         case 1:
176                                 tegra_cpu_speedo_id = 7;
177                                 tegra_soc_speedo_id = 1;
178                                 threshold_index = THRESHOLD_INDEX_10;
179                                 break;
180                         case 2:
181                                 tegra_cpu_speedo_id = 3;
182                                 tegra_soc_speedo_id = 2;
183                                 threshold_index = THRESHOLD_INDEX_3;
184                                 break;
185                         default:
186                                 pr_err("Tegra30: Unknown pkg %d\n", package_id);
187                                 BUG();
188                                 break;
189                         }
190                         break;
191                 case 0x8F:
192                         tegra_cpu_speedo_id = 8;
193                         tegra_soc_speedo_id = 1;
194                         threshold_index = THRESHOLD_INDEX_11;
195                         break;
196                 case 0x08:
197                         tegra_cpu_speedo_id = 1;
198                         tegra_soc_speedo_id = 1;
199                         threshold_index = THRESHOLD_INDEX_4;
200                         break;
201                 case 0x02:
202                         tegra_cpu_speedo_id = 2;
203                         tegra_soc_speedo_id = 2;
204                         threshold_index = THRESHOLD_INDEX_5;
205                         break;
206                 case 0x04:
207                         tegra_cpu_speedo_id = 3;
208                         tegra_soc_speedo_id = 2;
209                         threshold_index = THRESHOLD_INDEX_6;
210                         break;
211                 case 0:
212                         switch (package_id) {
213                         case 1:
214                                 tegra_cpu_speedo_id = 2;
215                                 tegra_soc_speedo_id = 2;
216                                 threshold_index = THRESHOLD_INDEX_2;
217                                 break;
218                         case 2:
219                                 tegra_cpu_speedo_id = 3;
220                                 tegra_soc_speedo_id = 2;
221                                 threshold_index = THRESHOLD_INDEX_3;
222                                 break;
223                         default:
224                                 pr_err("Tegra30: Unknown pkg %d\n", package_id);
225                                 BUG();
226                                 break;
227                         }
228                         break;
229                 default:
230                         pr_warn("Tegra30: Unknown SKU %d\n", sku);
231                         tegra_cpu_speedo_id = 0;
232                         tegra_soc_speedo_id = 0;
233                         threshold_index = THRESHOLD_INDEX_0;
234                         break;
235                 }
236                 break;
237         default:
238                 pr_warn("Tegra30: Unknown chip rev %d\n", rev);
239                 tegra_cpu_speedo_id = 0;
240                 tegra_soc_speedo_id = 0;
241                 threshold_index = THRESHOLD_INDEX_0;
242                 break;
243         }
244 }
245
246 void tegra30_init_speedo_data(void)
247 {
248         u32 cpu_speedo_val;
249         u32 core_speedo_val;
250         int i;
251
252         BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) !=
253                         THRESHOLD_INDEX_COUNT);
254         BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) !=
255                         THRESHOLD_INDEX_COUNT);
256
257         package_id = tegra_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F;
258
259         rev_sku_to_speedo_ids(tegra_revision, tegra_sku_id);
260         fuse_speedo_calib(&cpu_speedo_val, &core_speedo_val);
261         pr_debug("%s CPU speedo value %u\n", __func__, cpu_speedo_val);
262         pr_debug("%s Core speedo value %u\n", __func__, core_speedo_val);
263
264         for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++) {
265                 if (cpu_speedo_val < cpu_process_speedos[threshold_index][i])
266                         break;
267         }
268         tegra_cpu_process_id = i - 1;
269
270         if (tegra_cpu_process_id == -1) {
271                 pr_warn("Tegra30: CPU speedo value %3d out of range",
272                        cpu_speedo_val);
273                 tegra_cpu_process_id = 0;
274                 tegra_cpu_speedo_id = 1;
275         }
276
277         for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++) {
278                 if (core_speedo_val < core_process_speedos[threshold_index][i])
279                         break;
280         }
281         tegra_core_process_id = i - 1;
282
283         if (tegra_core_process_id == -1) {
284                 pr_warn("Tegra30: CORE speedo value %3d out of range",
285                        core_speedo_val);
286                 tegra_core_process_id = 0;
287                 tegra_soc_speedo_id = 1;
288         }
289
290         pr_info("Tegra30: CPU Speedo ID %d, Soc Speedo ID %d",
291                 tegra_cpu_speedo_id, tegra_soc_speedo_id);
292 }