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