Commit | Line | Data |
---|---|---|
f8ddda71 DH |
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 | } |