1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2012-2014, NVIDIA CORPORATION. All rights reserved. |
4 | */ |
5 | |
6 | #include <linux/bug.h> |
7 | #include <linux/device.h> |
8 | #include <linux/kernel.h> |
9 | |
10 | #include <soc/tegra/fuse.h> |
11 | |
12 | #include "fuse.h" |
13 | |
14 | #define SOC_PROCESS_CORNERS 1 |
15 | #define CPU_PROCESS_CORNERS 6 |
16 | |
17 | #define FUSE_SPEEDO_CALIB_0 0x14 |
18 | #define FUSE_PACKAGE_INFO 0XFC |
19 | #define FUSE_TEST_PROG_VER 0X28 |
20 | |
21 | #define G_SPEEDO_BIT_MINUS1 58 |
22 | #define G_SPEEDO_BIT_MINUS1_R 59 |
23 | #define G_SPEEDO_BIT_MINUS2 60 |
24 | #define G_SPEEDO_BIT_MINUS2_R 61 |
25 | #define LP_SPEEDO_BIT_MINUS1 62 |
26 | #define LP_SPEEDO_BIT_MINUS1_R 63 |
27 | #define LP_SPEEDO_BIT_MINUS2 64 |
28 | #define LP_SPEEDO_BIT_MINUS2_R 65 |
29 | |
30 | enum { |
31 | THRESHOLD_INDEX_0, |
32 | THRESHOLD_INDEX_1, |
33 | THRESHOLD_INDEX_2, |
34 | THRESHOLD_INDEX_3, |
35 | THRESHOLD_INDEX_4, |
36 | THRESHOLD_INDEX_5, |
37 | THRESHOLD_INDEX_6, |
38 | THRESHOLD_INDEX_7, |
39 | THRESHOLD_INDEX_8, |
40 | THRESHOLD_INDEX_9, |
41 | THRESHOLD_INDEX_10, |
42 | THRESHOLD_INDEX_11, |
43 | THRESHOLD_INDEX_COUNT, |
44 | }; |
45 | |
46 | static const u32 __initconst soc_process_speedos[][SOC_PROCESS_CORNERS] = { |
47 | {180}, |
48 | {170}, |
49 | {195}, |
50 | {180}, |
51 | {168}, |
52 | {192}, |
53 | {180}, |
54 | {170}, |
55 | {195}, |
56 | {180}, |
57 | {180}, |
58 | {180}, |
59 | }; |
60 | |
61 | static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = { |
62 | {306, 338, 360, 376, UINT_MAX}, |
63 | {295, 336, 358, 375, UINT_MAX}, |
64 | {325, 325, 358, 375, UINT_MAX}, |
65 | {325, 325, 358, 375, UINT_MAX}, |
66 | {292, 324, 348, 364, UINT_MAX}, |
67 | {324, 324, 348, 364, UINT_MAX}, |
68 | {324, 324, 348, 364, UINT_MAX}, |
69 | {295, 336, 358, 375, UINT_MAX}, |
70 | {358, 358, 358, 358, 397, UINT_MAX}, |
71 | {364, 364, 364, 364, 397, UINT_MAX}, |
72 | {295, 336, 358, 375, 391, UINT_MAX}, |
73 | {295, 336, 358, 375, 391, UINT_MAX}, |
74 | }; |
75 | |
76 | static int threshold_index __initdata; |
77 | |
78 | static void __init fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp) |
79 | { |
80 | u32 reg; |
81 | int ate_ver; |
82 | int bit_minus1; |
83 | int bit_minus2; |
84 | |
85 | reg = tegra_fuse_read_early(FUSE_SPEEDO_CALIB_0); |
86 | |
87 | *speedo_lp = (reg & 0xFFFF) * 4; |
88 | *speedo_g = ((reg >> 16) & 0xFFFF) * 4; |
89 | |
90 | ate_ver = tegra_fuse_read_early(FUSE_TEST_PROG_VER); |
91 | pr_debug("Tegra ATE prog ver %d.%d\n" , ate_ver/10, ate_ver%10); |
92 | |
93 | if (ate_ver >= 26) { |
94 | bit_minus1 = tegra_fuse_read_spare(LP_SPEEDO_BIT_MINUS1); |
95 | bit_minus1 |= tegra_fuse_read_spare(LP_SPEEDO_BIT_MINUS1_R); |
96 | bit_minus2 = tegra_fuse_read_spare(LP_SPEEDO_BIT_MINUS2); |
97 | bit_minus2 |= tegra_fuse_read_spare(LP_SPEEDO_BIT_MINUS2_R); |
98 | *speedo_lp |= (bit_minus1 << 1) | bit_minus2; |
99 | |
100 | bit_minus1 = tegra_fuse_read_spare(G_SPEEDO_BIT_MINUS1); |
101 | bit_minus1 |= tegra_fuse_read_spare(G_SPEEDO_BIT_MINUS1_R); |
102 | bit_minus2 = tegra_fuse_read_spare(G_SPEEDO_BIT_MINUS2); |
103 | bit_minus2 |= tegra_fuse_read_spare(G_SPEEDO_BIT_MINUS2_R); |
104 | *speedo_g |= (bit_minus1 << 1) | bit_minus2; |
105 | } else { |
106 | *speedo_lp |= 0x3; |
107 | *speedo_g |= 0x3; |
108 | } |
109 | } |
110 | |
111 | static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info) |
112 | { |
113 | int package_id = tegra_fuse_read_early(FUSE_PACKAGE_INFO) & 0x0F; |
114 | |
115 | switch (sku_info->revision) { |
116 | case TEGRA_REVISION_A01: |
117 | sku_info->cpu_speedo_id = 0; |
118 | sku_info->soc_speedo_id = 0; |
119 | threshold_index = THRESHOLD_INDEX_0; |
120 | break; |
121 | case TEGRA_REVISION_A02: |
122 | case TEGRA_REVISION_A03: |
123 | switch (sku_info->sku_id) { |
124 | case 0x87: |
125 | case 0x82: |
126 | sku_info->cpu_speedo_id = 1; |
127 | sku_info->soc_speedo_id = 1; |
128 | threshold_index = THRESHOLD_INDEX_1; |
129 | break; |
130 | case 0x81: |
131 | switch (package_id) { |
132 | case 1: |
133 | sku_info->cpu_speedo_id = 2; |
134 | sku_info->soc_speedo_id = 2; |
135 | threshold_index = THRESHOLD_INDEX_2; |
136 | break; |
137 | case 2: |
138 | sku_info->cpu_speedo_id = 4; |
139 | sku_info->soc_speedo_id = 1; |
140 | threshold_index = THRESHOLD_INDEX_7; |
141 | break; |
142 | default: |
143 | pr_err("Tegra Unknown pkg %d\n" , package_id); |
144 | break; |
145 | } |
146 | break; |
147 | case 0x80: |
148 | switch (package_id) { |
149 | case 1: |
150 | sku_info->cpu_speedo_id = 5; |
151 | sku_info->soc_speedo_id = 2; |
152 | threshold_index = THRESHOLD_INDEX_8; |
153 | break; |
154 | case 2: |
155 | sku_info->cpu_speedo_id = 6; |
156 | sku_info->soc_speedo_id = 2; |
157 | threshold_index = THRESHOLD_INDEX_9; |
158 | break; |
159 | default: |
160 | pr_err("Tegra Unknown pkg %d\n" , package_id); |
161 | break; |
162 | } |
163 | break; |
164 | case 0x83: |
165 | switch (package_id) { |
166 | case 1: |
167 | sku_info->cpu_speedo_id = 7; |
168 | sku_info->soc_speedo_id = 1; |
169 | threshold_index = THRESHOLD_INDEX_10; |
170 | break; |
171 | case 2: |
172 | sku_info->cpu_speedo_id = 3; |
173 | sku_info->soc_speedo_id = 2; |
174 | threshold_index = THRESHOLD_INDEX_3; |
175 | break; |
176 | default: |
177 | pr_err("Tegra Unknown pkg %d\n" , package_id); |
178 | break; |
179 | } |
180 | break; |
181 | case 0x8F: |
182 | sku_info->cpu_speedo_id = 8; |
183 | sku_info->soc_speedo_id = 1; |
184 | threshold_index = THRESHOLD_INDEX_11; |
185 | break; |
186 | case 0x08: |
187 | sku_info->cpu_speedo_id = 1; |
188 | sku_info->soc_speedo_id = 1; |
189 | threshold_index = THRESHOLD_INDEX_4; |
190 | break; |
191 | case 0x02: |
192 | sku_info->cpu_speedo_id = 2; |
193 | sku_info->soc_speedo_id = 2; |
194 | threshold_index = THRESHOLD_INDEX_5; |
195 | break; |
196 | case 0x04: |
197 | sku_info->cpu_speedo_id = 3; |
198 | sku_info->soc_speedo_id = 2; |
199 | threshold_index = THRESHOLD_INDEX_6; |
200 | break; |
201 | case 0: |
202 | switch (package_id) { |
203 | case 1: |
204 | sku_info->cpu_speedo_id = 2; |
205 | sku_info->soc_speedo_id = 2; |
206 | threshold_index = THRESHOLD_INDEX_2; |
207 | break; |
208 | case 2: |
209 | sku_info->cpu_speedo_id = 3; |
210 | sku_info->soc_speedo_id = 2; |
211 | threshold_index = THRESHOLD_INDEX_3; |
212 | break; |
213 | default: |
214 | pr_err("Tegra Unknown pkg %d\n" , package_id); |
215 | break; |
216 | } |
217 | break; |
218 | default: |
219 | pr_warn("Tegra Unknown SKU %d\n" , sku_info->sku_id); |
220 | sku_info->cpu_speedo_id = 0; |
221 | sku_info->soc_speedo_id = 0; |
222 | threshold_index = THRESHOLD_INDEX_0; |
223 | break; |
224 | } |
225 | break; |
226 | default: |
227 | pr_warn("Tegra Unknown chip rev %d\n" , sku_info->revision); |
228 | sku_info->cpu_speedo_id = 0; |
229 | sku_info->soc_speedo_id = 0; |
230 | threshold_index = THRESHOLD_INDEX_0; |
231 | break; |
232 | } |
233 | } |
234 | |
235 | void __init tegra30_init_speedo_data(struct tegra_sku_info *sku_info) |
236 | { |
237 | u32 cpu_speedo_val; |
238 | u32 soc_speedo_val; |
239 | int i; |
240 | |
241 | BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != |
242 | THRESHOLD_INDEX_COUNT); |
243 | BUILD_BUG_ON(ARRAY_SIZE(soc_process_speedos) != |
244 | THRESHOLD_INDEX_COUNT); |
245 | |
246 | |
247 | rev_sku_to_speedo_ids(sku_info); |
248 | fuse_speedo_calib(speedo_g: &cpu_speedo_val, speedo_lp: &soc_speedo_val); |
249 | pr_debug("Tegra CPU speedo value %u\n" , cpu_speedo_val); |
250 | pr_debug("Tegra Core speedo value %u\n" , soc_speedo_val); |
251 | |
252 | for (i = 0; i < CPU_PROCESS_CORNERS; i++) { |
253 | if (cpu_speedo_val < cpu_process_speedos[threshold_index][i]) |
254 | break; |
255 | } |
256 | sku_info->cpu_process_id = i - 1; |
257 | |
258 | if (sku_info->cpu_process_id == -1) { |
259 | pr_warn("Tegra CPU speedo value %3d out of range" , |
260 | cpu_speedo_val); |
261 | sku_info->cpu_process_id = 0; |
262 | sku_info->cpu_speedo_id = 1; |
263 | } |
264 | |
265 | for (i = 0; i < SOC_PROCESS_CORNERS; i++) { |
266 | if (soc_speedo_val < soc_process_speedos[threshold_index][i]) |
267 | break; |
268 | } |
269 | sku_info->soc_process_id = i - 1; |
270 | |
271 | if (sku_info->soc_process_id == -1) { |
272 | pr_warn("Tegra SoC speedo value %3d out of range" , |
273 | soc_speedo_val); |
274 | sku_info->soc_process_id = 0; |
275 | sku_info->soc_speedo_id = 1; |
276 | } |
277 | } |
278 | |