1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2013-2022, NVIDIA CORPORATION.  All rights reserved.
4  */
5 
6 #include <linux/device.h>
7 #include <linux/clk.h>
8 #include <linux/err.h>
9 #include <linux/io.h>
10 #include <linux/kernel.h>
11 #include <linux/nvmem-consumer.h>
12 #include <linux/of_device.h>
13 #include <linux/of_address.h>
14 #include <linux/platform_device.h>
15 #include <linux/pm_runtime.h>
16 #include <linux/random.h>
17 
18 #include <soc/tegra/fuse.h>
19 
20 #include "fuse.h"
21 
22 #define FUSE_BEGIN	0x100
23 
24 /* Tegra30 and later */
25 #define FUSE_VENDOR_CODE	0x100
26 #define FUSE_FAB_CODE		0x104
27 #define FUSE_LOT_CODE_0		0x108
28 #define FUSE_LOT_CODE_1		0x10c
29 #define FUSE_WAFER_ID		0x110
30 #define FUSE_X_COORDINATE	0x114
31 #define FUSE_Y_COORDINATE	0x118
32 
33 #define FUSE_HAS_REVISION_INFO	BIT(0)
34 
35 #if defined(CONFIG_ARCH_TEGRA_3x_SOC) || \
36     defined(CONFIG_ARCH_TEGRA_114_SOC) || \
37     defined(CONFIG_ARCH_TEGRA_124_SOC) || \
38     defined(CONFIG_ARCH_TEGRA_132_SOC) || \
39     defined(CONFIG_ARCH_TEGRA_210_SOC) || \
40     defined(CONFIG_ARCH_TEGRA_186_SOC) || \
41     defined(CONFIG_ARCH_TEGRA_194_SOC) || \
42     defined(CONFIG_ARCH_TEGRA_234_SOC)
43 static u32 tegra30_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset)
44 {
45 	if (WARN_ON(!fuse->base))
46 		return 0;
47 
48 	return readl_relaxed(fuse->base + FUSE_BEGIN + offset);
49 }
50 
51 static u32 tegra30_fuse_read(struct tegra_fuse *fuse, unsigned int offset)
52 {
53 	u32 value;
54 	int err;
55 
56 	err = pm_runtime_resume_and_get(fuse->dev);
57 	if (err)
58 		return 0;
59 
60 	value = readl_relaxed(fuse->base + FUSE_BEGIN + offset);
61 
62 	pm_runtime_put(fuse->dev);
63 
64 	return value;
65 }
66 
67 static void __init tegra30_fuse_add_randomness(void)
68 {
69 	u32 randomness[12];
70 
71 	randomness[0] = tegra_sku_info.sku_id;
72 	randomness[1] = tegra_read_straps();
73 	randomness[2] = tegra_read_chipid();
74 	randomness[3] = tegra_sku_info.cpu_process_id << 16;
75 	randomness[3] |= tegra_sku_info.soc_process_id;
76 	randomness[4] = tegra_sku_info.cpu_speedo_id << 16;
77 	randomness[4] |= tegra_sku_info.soc_speedo_id;
78 	randomness[5] = tegra_fuse_read_early(FUSE_VENDOR_CODE);
79 	randomness[6] = tegra_fuse_read_early(FUSE_FAB_CODE);
80 	randomness[7] = tegra_fuse_read_early(FUSE_LOT_CODE_0);
81 	randomness[8] = tegra_fuse_read_early(FUSE_LOT_CODE_1);
82 	randomness[9] = tegra_fuse_read_early(FUSE_WAFER_ID);
83 	randomness[10] = tegra_fuse_read_early(FUSE_X_COORDINATE);
84 	randomness[11] = tegra_fuse_read_early(FUSE_Y_COORDINATE);
85 
86 	add_device_randomness(randomness, sizeof(randomness));
87 }
88 
89 static void __init tegra30_fuse_init(struct tegra_fuse *fuse)
90 {
91 	fuse->read_early = tegra30_fuse_read_early;
92 	fuse->read = tegra30_fuse_read;
93 
94 	tegra_init_revision();
95 
96 	if (fuse->soc->speedo_init)
97 		fuse->soc->speedo_init(&tegra_sku_info);
98 
99 	tegra30_fuse_add_randomness();
100 }
101 #endif
102 
103 #ifdef CONFIG_ARCH_TEGRA_3x_SOC
104 static const struct tegra_fuse_info tegra30_fuse_info = {
105 	.read = tegra30_fuse_read,
106 	.size = 0x2a4,
107 	.spare = 0x144,
108 };
109 
110 const struct tegra_fuse_soc tegra30_fuse_soc = {
111 	.init = tegra30_fuse_init,
112 	.speedo_init = tegra30_init_speedo_data,
113 	.info = &tegra30_fuse_info,
114 	.soc_attr_group = &tegra_soc_attr_group,
115 	.clk_suspend_on = false,
116 };
117 #endif
118 
119 #ifdef CONFIG_ARCH_TEGRA_114_SOC
120 static const struct tegra_fuse_info tegra114_fuse_info = {
121 	.read = tegra30_fuse_read,
122 	.size = 0x2a0,
123 	.spare = 0x180,
124 };
125 
126 const struct tegra_fuse_soc tegra114_fuse_soc = {
127 	.init = tegra30_fuse_init,
128 	.speedo_init = tegra114_init_speedo_data,
129 	.info = &tegra114_fuse_info,
130 	.soc_attr_group = &tegra_soc_attr_group,
131 	.clk_suspend_on = false,
132 };
133 #endif
134 
135 #if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC)
136 static const struct nvmem_cell_lookup tegra124_fuse_lookups[] = {
137 	{
138 		.nvmem_name = "fuse",
139 		.cell_name = "xusb-pad-calibration",
140 		.dev_id = "7009f000.padctl",
141 		.con_id = "calibration",
142 	}, {
143 		.nvmem_name = "fuse",
144 		.cell_name = "sata-calibration",
145 		.dev_id = "70020000.sata",
146 		.con_id = "calibration",
147 	}, {
148 		.nvmem_name = "fuse",
149 		.cell_name = "tsensor-common",
150 		.dev_id = "700e2000.thermal-sensor",
151 		.con_id = "common",
152 	}, {
153 		.nvmem_name = "fuse",
154 		.cell_name = "tsensor-realignment",
155 		.dev_id = "700e2000.thermal-sensor",
156 		.con_id = "realignment",
157 	}, {
158 		.nvmem_name = "fuse",
159 		.cell_name = "tsensor-cpu0",
160 		.dev_id = "700e2000.thermal-sensor",
161 		.con_id = "cpu0",
162 	}, {
163 		.nvmem_name = "fuse",
164 		.cell_name = "tsensor-cpu1",
165 		.dev_id = "700e2000.thermal-sensor",
166 		.con_id = "cpu1",
167 	}, {
168 		.nvmem_name = "fuse",
169 		.cell_name = "tsensor-cpu2",
170 		.dev_id = "700e2000.thermal-sensor",
171 		.con_id = "cpu2",
172 	}, {
173 		.nvmem_name = "fuse",
174 		.cell_name = "tsensor-cpu3",
175 		.dev_id = "700e2000.thermal-sensor",
176 		.con_id = "cpu3",
177 	}, {
178 		.nvmem_name = "fuse",
179 		.cell_name = "tsensor-mem0",
180 		.dev_id = "700e2000.thermal-sensor",
181 		.con_id = "mem0",
182 	}, {
183 		.nvmem_name = "fuse",
184 		.cell_name = "tsensor-mem1",
185 		.dev_id = "700e2000.thermal-sensor",
186 		.con_id = "mem1",
187 	}, {
188 		.nvmem_name = "fuse",
189 		.cell_name = "tsensor-gpu",
190 		.dev_id = "700e2000.thermal-sensor",
191 		.con_id = "gpu",
192 	}, {
193 		.nvmem_name = "fuse",
194 		.cell_name = "tsensor-pllx",
195 		.dev_id = "700e2000.thermal-sensor",
196 		.con_id = "pllx",
197 	},
198 };
199 
200 static const struct tegra_fuse_info tegra124_fuse_info = {
201 	.read = tegra30_fuse_read,
202 	.size = 0x300,
203 	.spare = 0x200,
204 };
205 
206 const struct tegra_fuse_soc tegra124_fuse_soc = {
207 	.init = tegra30_fuse_init,
208 	.speedo_init = tegra124_init_speedo_data,
209 	.info = &tegra124_fuse_info,
210 	.lookups = tegra124_fuse_lookups,
211 	.num_lookups = ARRAY_SIZE(tegra124_fuse_lookups),
212 	.soc_attr_group = &tegra_soc_attr_group,
213 	.clk_suspend_on = true,
214 };
215 #endif
216 
217 #if defined(CONFIG_ARCH_TEGRA_210_SOC)
218 static const struct nvmem_cell_lookup tegra210_fuse_lookups[] = {
219 	{
220 		.nvmem_name = "fuse",
221 		.cell_name = "tsensor-cpu1",
222 		.dev_id = "700e2000.thermal-sensor",
223 		.con_id = "cpu1",
224 	}, {
225 		.nvmem_name = "fuse",
226 		.cell_name = "tsensor-cpu2",
227 		.dev_id = "700e2000.thermal-sensor",
228 		.con_id = "cpu2",
229 	}, {
230 		.nvmem_name = "fuse",
231 		.cell_name = "tsensor-cpu0",
232 		.dev_id = "700e2000.thermal-sensor",
233 		.con_id = "cpu0",
234 	}, {
235 		.nvmem_name = "fuse",
236 		.cell_name = "xusb-pad-calibration",
237 		.dev_id = "7009f000.padctl",
238 		.con_id = "calibration",
239 	}, {
240 		.nvmem_name = "fuse",
241 		.cell_name = "tsensor-cpu3",
242 		.dev_id = "700e2000.thermal-sensor",
243 		.con_id = "cpu3",
244 	}, {
245 		.nvmem_name = "fuse",
246 		.cell_name = "sata-calibration",
247 		.dev_id = "70020000.sata",
248 		.con_id = "calibration",
249 	}, {
250 		.nvmem_name = "fuse",
251 		.cell_name = "tsensor-gpu",
252 		.dev_id = "700e2000.thermal-sensor",
253 		.con_id = "gpu",
254 	}, {
255 		.nvmem_name = "fuse",
256 		.cell_name = "tsensor-mem0",
257 		.dev_id = "700e2000.thermal-sensor",
258 		.con_id = "mem0",
259 	}, {
260 		.nvmem_name = "fuse",
261 		.cell_name = "tsensor-mem1",
262 		.dev_id = "700e2000.thermal-sensor",
263 		.con_id = "mem1",
264 	}, {
265 		.nvmem_name = "fuse",
266 		.cell_name = "tsensor-pllx",
267 		.dev_id = "700e2000.thermal-sensor",
268 		.con_id = "pllx",
269 	}, {
270 		.nvmem_name = "fuse",
271 		.cell_name = "tsensor-common",
272 		.dev_id = "700e2000.thermal-sensor",
273 		.con_id = "common",
274 	}, {
275 		.nvmem_name = "fuse",
276 		.cell_name = "gpu-calibration",
277 		.dev_id = "57000000.gpu",
278 		.con_id = "calibration",
279 	}, {
280 		.nvmem_name = "fuse",
281 		.cell_name = "xusb-pad-calibration-ext",
282 		.dev_id = "7009f000.padctl",
283 		.con_id = "calibration-ext",
284 	},
285 };
286 
287 static const struct tegra_fuse_info tegra210_fuse_info = {
288 	.read = tegra30_fuse_read,
289 	.size = 0x300,
290 	.spare = 0x280,
291 };
292 
293 const struct tegra_fuse_soc tegra210_fuse_soc = {
294 	.init = tegra30_fuse_init,
295 	.speedo_init = tegra210_init_speedo_data,
296 	.info = &tegra210_fuse_info,
297 	.lookups = tegra210_fuse_lookups,
298 	.num_lookups = ARRAY_SIZE(tegra210_fuse_lookups),
299 	.soc_attr_group = &tegra_soc_attr_group,
300 	.clk_suspend_on = false,
301 };
302 #endif
303 
304 #if defined(CONFIG_ARCH_TEGRA_186_SOC)
305 static const struct nvmem_cell_lookup tegra186_fuse_lookups[] = {
306 	{
307 		.nvmem_name = "fuse",
308 		.cell_name = "xusb-pad-calibration",
309 		.dev_id = "3520000.padctl",
310 		.con_id = "calibration",
311 	}, {
312 		.nvmem_name = "fuse",
313 		.cell_name = "xusb-pad-calibration-ext",
314 		.dev_id = "3520000.padctl",
315 		.con_id = "calibration-ext",
316 	},
317 };
318 
319 static const struct tegra_fuse_info tegra186_fuse_info = {
320 	.read = tegra30_fuse_read,
321 	.size = 0x300,
322 	.spare = 0x280,
323 };
324 
325 const struct tegra_fuse_soc tegra186_fuse_soc = {
326 	.init = tegra30_fuse_init,
327 	.info = &tegra186_fuse_info,
328 	.lookups = tegra186_fuse_lookups,
329 	.num_lookups = ARRAY_SIZE(tegra186_fuse_lookups),
330 	.soc_attr_group = &tegra_soc_attr_group,
331 	.clk_suspend_on = false,
332 };
333 #endif
334 
335 #if defined(CONFIG_ARCH_TEGRA_194_SOC)
336 static const struct nvmem_cell_lookup tegra194_fuse_lookups[] = {
337 	{
338 		.nvmem_name = "fuse",
339 		.cell_name = "xusb-pad-calibration",
340 		.dev_id = "3520000.padctl",
341 		.con_id = "calibration",
342 	}, {
343 		.nvmem_name = "fuse",
344 		.cell_name = "xusb-pad-calibration-ext",
345 		.dev_id = "3520000.padctl",
346 		.con_id = "calibration-ext",
347 	}, {
348 		.nvmem_name = "fuse",
349 		.cell_name = "gpu-gcplex-config-fuse",
350 		.dev_id = "17000000.gpu",
351 		.con_id = "gcplex-config-fuse",
352 	}, {
353 		.nvmem_name = "fuse",
354 		.cell_name = "gpu-pdi0",
355 		.dev_id = "17000000.gpu",
356 		.con_id = "pdi0",
357 	}, {
358 		.nvmem_name = "fuse",
359 		.cell_name = "gpu-pdi1",
360 		.dev_id = "17000000.gpu",
361 		.con_id = "pdi1",
362 	},
363 };
364 
365 static const struct tegra_fuse_info tegra194_fuse_info = {
366 	.read = tegra30_fuse_read,
367 	.size = 0x300,
368 	.spare = 0x280,
369 };
370 
371 const struct tegra_fuse_soc tegra194_fuse_soc = {
372 	.init = tegra30_fuse_init,
373 	.info = &tegra194_fuse_info,
374 	.lookups = tegra194_fuse_lookups,
375 	.num_lookups = ARRAY_SIZE(tegra194_fuse_lookups),
376 	.soc_attr_group = &tegra194_soc_attr_group,
377 	.clk_suspend_on = false,
378 };
379 #endif
380 
381 #if defined(CONFIG_ARCH_TEGRA_234_SOC)
382 static const struct nvmem_cell_lookup tegra234_fuse_lookups[] = {
383 	{
384 		.nvmem_name = "fuse",
385 		.cell_name = "xusb-pad-calibration",
386 		.dev_id = "3520000.padctl",
387 		.con_id = "calibration",
388 	}, {
389 		.nvmem_name = "fuse",
390 		.cell_name = "xusb-pad-calibration-ext",
391 		.dev_id = "3520000.padctl",
392 		.con_id = "calibration-ext",
393 	},
394 };
395 
396 static const struct tegra_fuse_info tegra234_fuse_info = {
397 	.read = tegra30_fuse_read,
398 	.size = 0x300,
399 	.spare = 0x280,
400 };
401 
402 const struct tegra_fuse_soc tegra234_fuse_soc = {
403 	.init = tegra30_fuse_init,
404 	.info = &tegra234_fuse_info,
405 	.lookups = tegra234_fuse_lookups,
406 	.num_lookups = ARRAY_SIZE(tegra234_fuse_lookups),
407 	.soc_attr_group = &tegra194_soc_attr_group,
408 	.clk_suspend_on = false,
409 };
410 #endif
411