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
30enum {
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
46static 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
61static 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
76static int threshold_index __initdata;
77
78static 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
111static 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
235void __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

source code of linux/drivers/soc/tegra/fuse/speedo-tegra30.c