xref: /OK3568_Linux_fs/kernel/drivers/soc/tegra/fuse/speedo-tegra30.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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