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