19952f691SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2783c8f4cSPeter De Schrijver /*
3783c8f4cSPeter De Schrijver  * Copyright (c) 2012-2014, NVIDIA CORPORATION.  All rights reserved.
4783c8f4cSPeter De Schrijver  */
5783c8f4cSPeter De Schrijver 
6783c8f4cSPeter De Schrijver #include <linux/bug.h>
7783c8f4cSPeter De Schrijver #include <linux/device.h>
8783c8f4cSPeter De Schrijver #include <linux/kernel.h>
9783c8f4cSPeter De Schrijver 
10783c8f4cSPeter De Schrijver #include <soc/tegra/fuse.h>
11783c8f4cSPeter De Schrijver 
12783c8f4cSPeter De Schrijver #include "fuse.h"
13783c8f4cSPeter De Schrijver 
1403b3f4c8SThierry Reding #define SOC_PROCESS_CORNERS	1
15783c8f4cSPeter De Schrijver #define CPU_PROCESS_CORNERS	6
16783c8f4cSPeter De Schrijver 
17783c8f4cSPeter De Schrijver #define FUSE_SPEEDO_CALIB_0	0x14
18783c8f4cSPeter De Schrijver #define FUSE_PACKAGE_INFO	0XFC
19783c8f4cSPeter De Schrijver #define FUSE_TEST_PROG_VER	0X28
20783c8f4cSPeter De Schrijver 
21783c8f4cSPeter De Schrijver #define G_SPEEDO_BIT_MINUS1	58
22783c8f4cSPeter De Schrijver #define G_SPEEDO_BIT_MINUS1_R	59
23783c8f4cSPeter De Schrijver #define G_SPEEDO_BIT_MINUS2	60
24783c8f4cSPeter De Schrijver #define G_SPEEDO_BIT_MINUS2_R	61
25783c8f4cSPeter De Schrijver #define LP_SPEEDO_BIT_MINUS1	62
26783c8f4cSPeter De Schrijver #define LP_SPEEDO_BIT_MINUS1_R	63
27783c8f4cSPeter De Schrijver #define LP_SPEEDO_BIT_MINUS2	64
28783c8f4cSPeter De Schrijver #define LP_SPEEDO_BIT_MINUS2_R	65
29783c8f4cSPeter De Schrijver 
30783c8f4cSPeter De Schrijver enum {
31783c8f4cSPeter De Schrijver 	THRESHOLD_INDEX_0,
32783c8f4cSPeter De Schrijver 	THRESHOLD_INDEX_1,
33783c8f4cSPeter De Schrijver 	THRESHOLD_INDEX_2,
34783c8f4cSPeter De Schrijver 	THRESHOLD_INDEX_3,
35783c8f4cSPeter De Schrijver 	THRESHOLD_INDEX_4,
36783c8f4cSPeter De Schrijver 	THRESHOLD_INDEX_5,
37783c8f4cSPeter De Schrijver 	THRESHOLD_INDEX_6,
38783c8f4cSPeter De Schrijver 	THRESHOLD_INDEX_7,
39783c8f4cSPeter De Schrijver 	THRESHOLD_INDEX_8,
40783c8f4cSPeter De Schrijver 	THRESHOLD_INDEX_9,
41783c8f4cSPeter De Schrijver 	THRESHOLD_INDEX_10,
42783c8f4cSPeter De Schrijver 	THRESHOLD_INDEX_11,
43783c8f4cSPeter De Schrijver 	THRESHOLD_INDEX_COUNT,
44783c8f4cSPeter De Schrijver };
45783c8f4cSPeter De Schrijver 
4603b3f4c8SThierry Reding static const u32 __initconst soc_process_speedos[][SOC_PROCESS_CORNERS] = {
47783c8f4cSPeter De Schrijver 	{180},
48783c8f4cSPeter De Schrijver 	{170},
49783c8f4cSPeter De Schrijver 	{195},
50783c8f4cSPeter De Schrijver 	{180},
51783c8f4cSPeter De Schrijver 	{168},
52783c8f4cSPeter De Schrijver 	{192},
53783c8f4cSPeter De Schrijver 	{180},
54783c8f4cSPeter De Schrijver 	{170},
55783c8f4cSPeter De Schrijver 	{195},
56783c8f4cSPeter De Schrijver 	{180},
57783c8f4cSPeter De Schrijver 	{180},
58783c8f4cSPeter De Schrijver 	{180},
59783c8f4cSPeter De Schrijver };
60783c8f4cSPeter De Schrijver 
61783c8f4cSPeter De Schrijver static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = {
62783c8f4cSPeter De Schrijver 	{306, 338, 360, 376, UINT_MAX},
63783c8f4cSPeter De Schrijver 	{295, 336, 358, 375, UINT_MAX},
64783c8f4cSPeter De Schrijver 	{325, 325, 358, 375, UINT_MAX},
65783c8f4cSPeter De Schrijver 	{325, 325, 358, 375, UINT_MAX},
66783c8f4cSPeter De Schrijver 	{292, 324, 348, 364, UINT_MAX},
67783c8f4cSPeter De Schrijver 	{324, 324, 348, 364, UINT_MAX},
68783c8f4cSPeter De Schrijver 	{324, 324, 348, 364, UINT_MAX},
69783c8f4cSPeter De Schrijver 	{295, 336, 358, 375, UINT_MAX},
70783c8f4cSPeter De Schrijver 	{358, 358, 358, 358, 397, UINT_MAX},
71783c8f4cSPeter De Schrijver 	{364, 364, 364, 364, 397, UINT_MAX},
72783c8f4cSPeter De Schrijver 	{295, 336, 358, 375, 391, UINT_MAX},
73783c8f4cSPeter De Schrijver 	{295, 336, 358, 375, 391, UINT_MAX},
74783c8f4cSPeter De Schrijver };
75783c8f4cSPeter De Schrijver 
76783c8f4cSPeter De Schrijver static int threshold_index __initdata;
77783c8f4cSPeter De Schrijver 
fuse_speedo_calib(u32 * speedo_g,u32 * speedo_lp)78783c8f4cSPeter De Schrijver static void __init fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp)
79783c8f4cSPeter De Schrijver {
80783c8f4cSPeter De Schrijver 	u32 reg;
81783c8f4cSPeter De Schrijver 	int ate_ver;
82783c8f4cSPeter De Schrijver 	int bit_minus1;
83783c8f4cSPeter De Schrijver 	int bit_minus2;
84783c8f4cSPeter De Schrijver 
857e939de1SThierry Reding 	reg = tegra_fuse_read_early(FUSE_SPEEDO_CALIB_0);
86783c8f4cSPeter De Schrijver 
87783c8f4cSPeter De Schrijver 	*speedo_lp = (reg & 0xFFFF) * 4;
88783c8f4cSPeter De Schrijver 	*speedo_g = ((reg >> 16) & 0xFFFF) * 4;
89783c8f4cSPeter De Schrijver 
907e939de1SThierry Reding 	ate_ver = tegra_fuse_read_early(FUSE_TEST_PROG_VER);
91783c8f4cSPeter De Schrijver 	pr_debug("Tegra ATE prog ver %d.%d\n", ate_ver/10, ate_ver%10);
92783c8f4cSPeter De Schrijver 
93783c8f4cSPeter De Schrijver 	if (ate_ver >= 26) {
947e939de1SThierry Reding 		bit_minus1 = tegra_fuse_read_spare(LP_SPEEDO_BIT_MINUS1);
957e939de1SThierry Reding 		bit_minus1 |= tegra_fuse_read_spare(LP_SPEEDO_BIT_MINUS1_R);
967e939de1SThierry Reding 		bit_minus2 = tegra_fuse_read_spare(LP_SPEEDO_BIT_MINUS2);
977e939de1SThierry Reding 		bit_minus2 |= tegra_fuse_read_spare(LP_SPEEDO_BIT_MINUS2_R);
98783c8f4cSPeter De Schrijver 		*speedo_lp |= (bit_minus1 << 1) | bit_minus2;
99783c8f4cSPeter De Schrijver 
1007e939de1SThierry Reding 		bit_minus1 = tegra_fuse_read_spare(G_SPEEDO_BIT_MINUS1);
1017e939de1SThierry Reding 		bit_minus1 |= tegra_fuse_read_spare(G_SPEEDO_BIT_MINUS1_R);
1027e939de1SThierry Reding 		bit_minus2 = tegra_fuse_read_spare(G_SPEEDO_BIT_MINUS2);
1037e939de1SThierry Reding 		bit_minus2 |= tegra_fuse_read_spare(G_SPEEDO_BIT_MINUS2_R);
104783c8f4cSPeter De Schrijver 		*speedo_g |= (bit_minus1 << 1) | bit_minus2;
105783c8f4cSPeter De Schrijver 	} else {
106783c8f4cSPeter De Schrijver 		*speedo_lp |= 0x3;
107783c8f4cSPeter De Schrijver 		*speedo_g |= 0x3;
108783c8f4cSPeter De Schrijver 	}
109783c8f4cSPeter De Schrijver }
110783c8f4cSPeter De Schrijver 
rev_sku_to_speedo_ids(struct tegra_sku_info * sku_info)111783c8f4cSPeter De Schrijver static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info)
112783c8f4cSPeter De Schrijver {
1137e939de1SThierry Reding 	int package_id = tegra_fuse_read_early(FUSE_PACKAGE_INFO) & 0x0F;
114783c8f4cSPeter De Schrijver 
115783c8f4cSPeter De Schrijver 	switch (sku_info->revision) {
116783c8f4cSPeter De Schrijver 	case TEGRA_REVISION_A01:
117783c8f4cSPeter De Schrijver 		sku_info->cpu_speedo_id = 0;
118783c8f4cSPeter De Schrijver 		sku_info->soc_speedo_id = 0;
119783c8f4cSPeter De Schrijver 		threshold_index = THRESHOLD_INDEX_0;
120783c8f4cSPeter De Schrijver 		break;
121783c8f4cSPeter De Schrijver 	case TEGRA_REVISION_A02:
122783c8f4cSPeter De Schrijver 	case TEGRA_REVISION_A03:
123783c8f4cSPeter De Schrijver 		switch (sku_info->sku_id) {
124783c8f4cSPeter De Schrijver 		case 0x87:
125783c8f4cSPeter De Schrijver 		case 0x82:
126783c8f4cSPeter De Schrijver 			sku_info->cpu_speedo_id = 1;
127783c8f4cSPeter De Schrijver 			sku_info->soc_speedo_id = 1;
128783c8f4cSPeter De Schrijver 			threshold_index = THRESHOLD_INDEX_1;
129783c8f4cSPeter De Schrijver 			break;
130783c8f4cSPeter De Schrijver 		case 0x81:
131783c8f4cSPeter De Schrijver 			switch (package_id) {
132783c8f4cSPeter De Schrijver 			case 1:
133783c8f4cSPeter De Schrijver 				sku_info->cpu_speedo_id = 2;
134783c8f4cSPeter De Schrijver 				sku_info->soc_speedo_id = 2;
135783c8f4cSPeter De Schrijver 				threshold_index = THRESHOLD_INDEX_2;
136783c8f4cSPeter De Schrijver 				break;
137783c8f4cSPeter De Schrijver 			case 2:
138783c8f4cSPeter De Schrijver 				sku_info->cpu_speedo_id = 4;
139783c8f4cSPeter De Schrijver 				sku_info->soc_speedo_id = 1;
140783c8f4cSPeter De Schrijver 				threshold_index = THRESHOLD_INDEX_7;
141783c8f4cSPeter De Schrijver 				break;
142783c8f4cSPeter De Schrijver 			default:
143783c8f4cSPeter De Schrijver 				pr_err("Tegra Unknown pkg %d\n", package_id);
144783c8f4cSPeter De Schrijver 				break;
145783c8f4cSPeter De Schrijver 			}
146783c8f4cSPeter De Schrijver 			break;
147783c8f4cSPeter De Schrijver 		case 0x80:
148783c8f4cSPeter De Schrijver 			switch (package_id) {
149783c8f4cSPeter De Schrijver 			case 1:
150783c8f4cSPeter De Schrijver 				sku_info->cpu_speedo_id = 5;
151783c8f4cSPeter De Schrijver 				sku_info->soc_speedo_id = 2;
152783c8f4cSPeter De Schrijver 				threshold_index = THRESHOLD_INDEX_8;
153783c8f4cSPeter De Schrijver 				break;
154783c8f4cSPeter De Schrijver 			case 2:
155783c8f4cSPeter De Schrijver 				sku_info->cpu_speedo_id = 6;
156783c8f4cSPeter De Schrijver 				sku_info->soc_speedo_id = 2;
157783c8f4cSPeter De Schrijver 				threshold_index = THRESHOLD_INDEX_9;
158783c8f4cSPeter De Schrijver 				break;
159783c8f4cSPeter De Schrijver 			default:
160783c8f4cSPeter De Schrijver 				pr_err("Tegra Unknown pkg %d\n", package_id);
161783c8f4cSPeter De Schrijver 				break;
162783c8f4cSPeter De Schrijver 			}
163783c8f4cSPeter De Schrijver 			break;
164783c8f4cSPeter De Schrijver 		case 0x83:
165783c8f4cSPeter De Schrijver 			switch (package_id) {
166783c8f4cSPeter De Schrijver 			case 1:
167783c8f4cSPeter De Schrijver 				sku_info->cpu_speedo_id = 7;
168783c8f4cSPeter De Schrijver 				sku_info->soc_speedo_id = 1;
169783c8f4cSPeter De Schrijver 				threshold_index = THRESHOLD_INDEX_10;
170783c8f4cSPeter De Schrijver 				break;
171783c8f4cSPeter De Schrijver 			case 2:
172783c8f4cSPeter De Schrijver 				sku_info->cpu_speedo_id = 3;
173783c8f4cSPeter De Schrijver 				sku_info->soc_speedo_id = 2;
174783c8f4cSPeter De Schrijver 				threshold_index = THRESHOLD_INDEX_3;
175783c8f4cSPeter De Schrijver 				break;
176783c8f4cSPeter De Schrijver 			default:
177783c8f4cSPeter De Schrijver 				pr_err("Tegra Unknown pkg %d\n", package_id);
178783c8f4cSPeter De Schrijver 				break;
179783c8f4cSPeter De Schrijver 			}
180783c8f4cSPeter De Schrijver 			break;
181783c8f4cSPeter De Schrijver 		case 0x8F:
182783c8f4cSPeter De Schrijver 			sku_info->cpu_speedo_id = 8;
183783c8f4cSPeter De Schrijver 			sku_info->soc_speedo_id = 1;
184783c8f4cSPeter De Schrijver 			threshold_index = THRESHOLD_INDEX_11;
185783c8f4cSPeter De Schrijver 			break;
186783c8f4cSPeter De Schrijver 		case 0x08:
187783c8f4cSPeter De Schrijver 			sku_info->cpu_speedo_id = 1;
188783c8f4cSPeter De Schrijver 			sku_info->soc_speedo_id = 1;
189783c8f4cSPeter De Schrijver 			threshold_index = THRESHOLD_INDEX_4;
190783c8f4cSPeter De Schrijver 			break;
191783c8f4cSPeter De Schrijver 		case 0x02:
192783c8f4cSPeter De Schrijver 			sku_info->cpu_speedo_id = 2;
193783c8f4cSPeter De Schrijver 			sku_info->soc_speedo_id = 2;
194783c8f4cSPeter De Schrijver 			threshold_index = THRESHOLD_INDEX_5;
195783c8f4cSPeter De Schrijver 			break;
196783c8f4cSPeter De Schrijver 		case 0x04:
197783c8f4cSPeter De Schrijver 			sku_info->cpu_speedo_id = 3;
198783c8f4cSPeter De Schrijver 			sku_info->soc_speedo_id = 2;
199783c8f4cSPeter De Schrijver 			threshold_index = THRESHOLD_INDEX_6;
200783c8f4cSPeter De Schrijver 			break;
201783c8f4cSPeter De Schrijver 		case 0:
202783c8f4cSPeter De Schrijver 			switch (package_id) {
203783c8f4cSPeter De Schrijver 			case 1:
204783c8f4cSPeter De Schrijver 				sku_info->cpu_speedo_id = 2;
205783c8f4cSPeter De Schrijver 				sku_info->soc_speedo_id = 2;
206783c8f4cSPeter De Schrijver 				threshold_index = THRESHOLD_INDEX_2;
207783c8f4cSPeter De Schrijver 				break;
208783c8f4cSPeter De Schrijver 			case 2:
209783c8f4cSPeter De Schrijver 				sku_info->cpu_speedo_id = 3;
210783c8f4cSPeter De Schrijver 				sku_info->soc_speedo_id = 2;
211783c8f4cSPeter De Schrijver 				threshold_index = THRESHOLD_INDEX_3;
212783c8f4cSPeter De Schrijver 				break;
213783c8f4cSPeter De Schrijver 			default:
214783c8f4cSPeter De Schrijver 				pr_err("Tegra Unknown pkg %d\n", package_id);
215783c8f4cSPeter De Schrijver 				break;
216783c8f4cSPeter De Schrijver 			}
217783c8f4cSPeter De Schrijver 			break;
218783c8f4cSPeter De Schrijver 		default:
219783c8f4cSPeter De Schrijver 			pr_warn("Tegra Unknown SKU %d\n", sku_info->sku_id);
220783c8f4cSPeter De Schrijver 			sku_info->cpu_speedo_id = 0;
221783c8f4cSPeter De Schrijver 			sku_info->soc_speedo_id = 0;
222783c8f4cSPeter De Schrijver 			threshold_index = THRESHOLD_INDEX_0;
223783c8f4cSPeter De Schrijver 			break;
224783c8f4cSPeter De Schrijver 		}
225783c8f4cSPeter De Schrijver 		break;
226783c8f4cSPeter De Schrijver 	default:
227783c8f4cSPeter De Schrijver 		pr_warn("Tegra Unknown chip rev %d\n", sku_info->revision);
228783c8f4cSPeter De Schrijver 		sku_info->cpu_speedo_id = 0;
229783c8f4cSPeter De Schrijver 		sku_info->soc_speedo_id = 0;
230783c8f4cSPeter De Schrijver 		threshold_index = THRESHOLD_INDEX_0;
231783c8f4cSPeter De Schrijver 		break;
232783c8f4cSPeter De Schrijver 	}
233783c8f4cSPeter De Schrijver }
234783c8f4cSPeter De Schrijver 
tegra30_init_speedo_data(struct tegra_sku_info * sku_info)235783c8f4cSPeter De Schrijver void __init tegra30_init_speedo_data(struct tegra_sku_info *sku_info)
236783c8f4cSPeter De Schrijver {
237783c8f4cSPeter De Schrijver 	u32 cpu_speedo_val;
23803b3f4c8SThierry Reding 	u32 soc_speedo_val;
239783c8f4cSPeter De Schrijver 	int i;
240783c8f4cSPeter De Schrijver 
241783c8f4cSPeter De Schrijver 	BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) !=
242783c8f4cSPeter De Schrijver 			THRESHOLD_INDEX_COUNT);
24303b3f4c8SThierry Reding 	BUILD_BUG_ON(ARRAY_SIZE(soc_process_speedos) !=
244783c8f4cSPeter De Schrijver 			THRESHOLD_INDEX_COUNT);
245783c8f4cSPeter De Schrijver 
246783c8f4cSPeter De Schrijver 
247783c8f4cSPeter De Schrijver 	rev_sku_to_speedo_ids(sku_info);
24803b3f4c8SThierry Reding 	fuse_speedo_calib(&cpu_speedo_val, &soc_speedo_val);
249783c8f4cSPeter De Schrijver 	pr_debug("Tegra CPU speedo value %u\n", cpu_speedo_val);
25003b3f4c8SThierry Reding 	pr_debug("Tegra Core speedo value %u\n", soc_speedo_val);
251783c8f4cSPeter De Schrijver 
252783c8f4cSPeter De Schrijver 	for (i = 0; i < CPU_PROCESS_CORNERS; i++) {
253783c8f4cSPeter De Schrijver 		if (cpu_speedo_val < cpu_process_speedos[threshold_index][i])
254783c8f4cSPeter De Schrijver 			break;
255783c8f4cSPeter De Schrijver 	}
256783c8f4cSPeter De Schrijver 	sku_info->cpu_process_id = i - 1;
257783c8f4cSPeter De Schrijver 
258783c8f4cSPeter De Schrijver 	if (sku_info->cpu_process_id == -1) {
259783c8f4cSPeter De Schrijver 		pr_warn("Tegra CPU speedo value %3d out of range",
260783c8f4cSPeter De Schrijver 			 cpu_speedo_val);
261783c8f4cSPeter De Schrijver 		sku_info->cpu_process_id = 0;
262783c8f4cSPeter De Schrijver 		sku_info->cpu_speedo_id = 1;
263783c8f4cSPeter De Schrijver 	}
264783c8f4cSPeter De Schrijver 
26503b3f4c8SThierry Reding 	for (i = 0; i < SOC_PROCESS_CORNERS; i++) {
26603b3f4c8SThierry Reding 		if (soc_speedo_val < soc_process_speedos[threshold_index][i])
267783c8f4cSPeter De Schrijver 			break;
268783c8f4cSPeter De Schrijver 	}
26903b3f4c8SThierry Reding 	sku_info->soc_process_id = i - 1;
270783c8f4cSPeter De Schrijver 
27103b3f4c8SThierry Reding 	if (sku_info->soc_process_id == -1) {
27203b3f4c8SThierry Reding 		pr_warn("Tegra SoC speedo value %3d out of range",
27303b3f4c8SThierry Reding 			soc_speedo_val);
27403b3f4c8SThierry Reding 		sku_info->soc_process_id = 0;
275783c8f4cSPeter De Schrijver 		sku_info->soc_speedo_id = 1;
276783c8f4cSPeter De Schrijver 	}
277783c8f4cSPeter De Schrijver }
278