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/nvmem-provider.h>
13#include <linux/platform_device.h>
14#include <linux/pm_runtime.h>
15#include <linux/random.h>
16
17#include <soc/tegra/fuse.h>
18
19#include "fuse.h"
20
21#define FUSE_BEGIN	0x100
22
23/* Tegra30 and later */
24#define FUSE_VENDOR_CODE	0x100
25#define FUSE_FAB_CODE		0x104
26#define FUSE_LOT_CODE_0		0x108
27#define FUSE_LOT_CODE_1		0x10c
28#define FUSE_WAFER_ID		0x110
29#define FUSE_X_COORDINATE	0x114
30#define FUSE_Y_COORDINATE	0x118
31
32#define FUSE_HAS_REVISION_INFO	BIT(0)
33
34#if defined(CONFIG_ARCH_TEGRA_3x_SOC) || \
35    defined(CONFIG_ARCH_TEGRA_114_SOC) || \
36    defined(CONFIG_ARCH_TEGRA_124_SOC) || \
37    defined(CONFIG_ARCH_TEGRA_132_SOC) || \
38    defined(CONFIG_ARCH_TEGRA_210_SOC) || \
39    defined(CONFIG_ARCH_TEGRA_186_SOC) || \
40    defined(CONFIG_ARCH_TEGRA_194_SOC) || \
41    defined(CONFIG_ARCH_TEGRA_234_SOC)
42static u32 tegra30_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset)
43{
44	if (WARN_ON(!fuse->base))
45		return 0;
46
47	return readl_relaxed(fuse->base + FUSE_BEGIN + offset);
48}
49
50static u32 tegra30_fuse_read(struct tegra_fuse *fuse, unsigned int offset)
51{
52	u32 value;
53	int err;
54
55	err = pm_runtime_resume_and_get(fuse->dev);
56	if (err)
57		return 0;
58
59	value = readl_relaxed(fuse->base + FUSE_BEGIN + offset);
60
61	pm_runtime_put(fuse->dev);
62
63	return value;
64}
65
66static void __init tegra30_fuse_add_randomness(void)
67{
68	u32 randomness[12];
69
70	randomness[0] = tegra_sku_info.sku_id;
71	randomness[1] = tegra_read_straps();
72	randomness[2] = tegra_read_chipid();
73	randomness[3] = tegra_sku_info.cpu_process_id << 16;
74	randomness[3] |= tegra_sku_info.soc_process_id;
75	randomness[4] = tegra_sku_info.cpu_speedo_id << 16;
76	randomness[4] |= tegra_sku_info.soc_speedo_id;
77	randomness[5] = tegra_fuse_read_early(FUSE_VENDOR_CODE);
78	randomness[6] = tegra_fuse_read_early(FUSE_FAB_CODE);
79	randomness[7] = tegra_fuse_read_early(FUSE_LOT_CODE_0);
80	randomness[8] = tegra_fuse_read_early(FUSE_LOT_CODE_1);
81	randomness[9] = tegra_fuse_read_early(FUSE_WAFER_ID);
82	randomness[10] = tegra_fuse_read_early(FUSE_X_COORDINATE);
83	randomness[11] = tegra_fuse_read_early(FUSE_Y_COORDINATE);
84
85	add_device_randomness(randomness, sizeof(randomness));
86}
87
88static void __init tegra30_fuse_init(struct tegra_fuse *fuse)
89{
90	fuse->read_early = tegra30_fuse_read_early;
91	fuse->read = tegra30_fuse_read;
92
93	tegra_init_revision();
94
95	if (fuse->soc->speedo_init)
96		fuse->soc->speedo_init(&tegra_sku_info);
97
98	tegra30_fuse_add_randomness();
99}
100#endif
101
102#ifdef CONFIG_ARCH_TEGRA_3x_SOC
103static const struct tegra_fuse_info tegra30_fuse_info = {
104	.read = tegra30_fuse_read,
105	.size = 0x2a4,
106	.spare = 0x144,
107};
108
109const struct tegra_fuse_soc tegra30_fuse_soc = {
110	.init = tegra30_fuse_init,
111	.speedo_init = tegra30_init_speedo_data,
112	.info = &tegra30_fuse_info,
113	.soc_attr_group = &tegra_soc_attr_group,
114	.clk_suspend_on = false,
115};
116#endif
117
118#ifdef CONFIG_ARCH_TEGRA_114_SOC
119static const struct tegra_fuse_info tegra114_fuse_info = {
120	.read = tegra30_fuse_read,
121	.size = 0x2a0,
122	.spare = 0x180,
123};
124
125const struct tegra_fuse_soc tegra114_fuse_soc = {
126	.init = tegra30_fuse_init,
127	.speedo_init = tegra114_init_speedo_data,
128	.info = &tegra114_fuse_info,
129	.soc_attr_group = &tegra_soc_attr_group,
130	.clk_suspend_on = false,
131};
132#endif
133
134#if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC)
135static const struct nvmem_cell_info tegra124_fuse_cells[] = {
136	{
137		.name = "tsensor-cpu1",
138		.offset = 0x084,
139		.bytes = 4,
140		.bit_offset = 0,
141		.nbits = 32,
142	}, {
143		.name = "tsensor-cpu2",
144		.offset = 0x088,
145		.bytes = 4,
146		.bit_offset = 0,
147		.nbits = 32,
148	}, {
149		.name = "tsensor-cpu0",
150		.offset = 0x098,
151		.bytes = 4,
152		.bit_offset = 0,
153		.nbits = 32,
154	}, {
155		.name = "xusb-pad-calibration",
156		.offset = 0x0f0,
157		.bytes = 4,
158		.bit_offset = 0,
159		.nbits = 32,
160	}, {
161		.name = "tsensor-cpu3",
162		.offset = 0x12c,
163		.bytes = 4,
164		.bit_offset = 0,
165		.nbits = 32,
166	}, {
167		.name = "sata-calibration",
168		.offset = 0x124,
169		.bytes = 4,
170		.bit_offset = 0,
171		.nbits = 32,
172	}, {
173		.name = "tsensor-gpu",
174		.offset = 0x154,
175		.bytes = 4,
176		.bit_offset = 0,
177		.nbits = 32,
178	}, {
179		.name = "tsensor-mem0",
180		.offset = 0x158,
181		.bytes = 4,
182		.bit_offset = 0,
183		.nbits = 32,
184	}, {
185		.name = "tsensor-mem1",
186		.offset = 0x15c,
187		.bytes = 4,
188		.bit_offset = 0,
189		.nbits = 32,
190	}, {
191		.name = "tsensor-pllx",
192		.offset = 0x160,
193		.bytes = 4,
194		.bit_offset = 0,
195		.nbits = 32,
196	}, {
197		.name = "tsensor-common",
198		.offset = 0x180,
199		.bytes = 4,
200		.bit_offset = 0,
201		.nbits = 32,
202	}, {
203		.name = "tsensor-realignment",
204		.offset = 0x1fc,
205		.bytes = 4,
206		.bit_offset = 0,
207		.nbits = 32,
208	},
209};
210
211static const struct nvmem_cell_lookup tegra124_fuse_lookups[] = {
212	{
213		.nvmem_name = "fuse",
214		.cell_name = "xusb-pad-calibration",
215		.dev_id = "7009f000.padctl",
216		.con_id = "calibration",
217	}, {
218		.nvmem_name = "fuse",
219		.cell_name = "sata-calibration",
220		.dev_id = "70020000.sata",
221		.con_id = "calibration",
222	}, {
223		.nvmem_name = "fuse",
224		.cell_name = "tsensor-common",
225		.dev_id = "700e2000.thermal-sensor",
226		.con_id = "common",
227	}, {
228		.nvmem_name = "fuse",
229		.cell_name = "tsensor-realignment",
230		.dev_id = "700e2000.thermal-sensor",
231		.con_id = "realignment",
232	}, {
233		.nvmem_name = "fuse",
234		.cell_name = "tsensor-cpu0",
235		.dev_id = "700e2000.thermal-sensor",
236		.con_id = "cpu0",
237	}, {
238		.nvmem_name = "fuse",
239		.cell_name = "tsensor-cpu1",
240		.dev_id = "700e2000.thermal-sensor",
241		.con_id = "cpu1",
242	}, {
243		.nvmem_name = "fuse",
244		.cell_name = "tsensor-cpu2",
245		.dev_id = "700e2000.thermal-sensor",
246		.con_id = "cpu2",
247	}, {
248		.nvmem_name = "fuse",
249		.cell_name = "tsensor-cpu3",
250		.dev_id = "700e2000.thermal-sensor",
251		.con_id = "cpu3",
252	}, {
253		.nvmem_name = "fuse",
254		.cell_name = "tsensor-mem0",
255		.dev_id = "700e2000.thermal-sensor",
256		.con_id = "mem0",
257	}, {
258		.nvmem_name = "fuse",
259		.cell_name = "tsensor-mem1",
260		.dev_id = "700e2000.thermal-sensor",
261		.con_id = "mem1",
262	}, {
263		.nvmem_name = "fuse",
264		.cell_name = "tsensor-gpu",
265		.dev_id = "700e2000.thermal-sensor",
266		.con_id = "gpu",
267	}, {
268		.nvmem_name = "fuse",
269		.cell_name = "tsensor-pllx",
270		.dev_id = "700e2000.thermal-sensor",
271		.con_id = "pllx",
272	},
273};
274
275static const struct tegra_fuse_info tegra124_fuse_info = {
276	.read = tegra30_fuse_read,
277	.size = 0x300,
278	.spare = 0x200,
279};
280
281const struct tegra_fuse_soc tegra124_fuse_soc = {
282	.init = tegra30_fuse_init,
283	.speedo_init = tegra124_init_speedo_data,
284	.info = &tegra124_fuse_info,
285	.lookups = tegra124_fuse_lookups,
286	.num_lookups = ARRAY_SIZE(tegra124_fuse_lookups),
287	.cells = tegra124_fuse_cells,
288	.num_cells = ARRAY_SIZE(tegra124_fuse_cells),
289	.soc_attr_group = &tegra_soc_attr_group,
290	.clk_suspend_on = true,
291};
292#endif
293
294#if defined(CONFIG_ARCH_TEGRA_210_SOC)
295static const struct nvmem_cell_info tegra210_fuse_cells[] = {
296	{
297		.name = "tsensor-cpu1",
298		.offset = 0x084,
299		.bytes = 4,
300		.bit_offset = 0,
301		.nbits = 32,
302	}, {
303		.name = "tsensor-cpu2",
304		.offset = 0x088,
305		.bytes = 4,
306		.bit_offset = 0,
307		.nbits = 32,
308	}, {
309		.name = "tsensor-cpu0",
310		.offset = 0x098,
311		.bytes = 4,
312		.bit_offset = 0,
313		.nbits = 32,
314	}, {
315		.name = "xusb-pad-calibration",
316		.offset = 0x0f0,
317		.bytes = 4,
318		.bit_offset = 0,
319		.nbits = 32,
320	}, {
321		.name = "tsensor-cpu3",
322		.offset = 0x12c,
323		.bytes = 4,
324		.bit_offset = 0,
325		.nbits = 32,
326	}, {
327		.name = "sata-calibration",
328		.offset = 0x124,
329		.bytes = 4,
330		.bit_offset = 0,
331		.nbits = 32,
332	}, {
333		.name = "tsensor-gpu",
334		.offset = 0x154,
335		.bytes = 4,
336		.bit_offset = 0,
337		.nbits = 32,
338	}, {
339		.name = "tsensor-mem0",
340		.offset = 0x158,
341		.bytes = 4,
342		.bit_offset = 0,
343		.nbits = 32,
344	}, {
345		.name = "tsensor-mem1",
346		.offset = 0x15c,
347		.bytes = 4,
348		.bit_offset = 0,
349		.nbits = 32,
350	}, {
351		.name = "tsensor-pllx",
352		.offset = 0x160,
353		.bytes = 4,
354		.bit_offset = 0,
355		.nbits = 32,
356	}, {
357		.name = "tsensor-common",
358		.offset = 0x180,
359		.bytes = 4,
360		.bit_offset = 0,
361		.nbits = 32,
362	}, {
363		.name = "gpu-calibration",
364		.offset = 0x204,
365		.bytes = 4,
366		.bit_offset = 0,
367		.nbits = 32,
368	}, {
369		.name = "xusb-pad-calibration-ext",
370		.offset = 0x250,
371		.bytes = 4,
372		.bit_offset = 0,
373		.nbits = 32,
374	},
375};
376
377static const struct nvmem_cell_lookup tegra210_fuse_lookups[] = {
378	{
379		.nvmem_name = "fuse",
380		.cell_name = "tsensor-cpu1",
381		.dev_id = "700e2000.thermal-sensor",
382		.con_id = "cpu1",
383	}, {
384		.nvmem_name = "fuse",
385		.cell_name = "tsensor-cpu2",
386		.dev_id = "700e2000.thermal-sensor",
387		.con_id = "cpu2",
388	}, {
389		.nvmem_name = "fuse",
390		.cell_name = "tsensor-cpu0",
391		.dev_id = "700e2000.thermal-sensor",
392		.con_id = "cpu0",
393	}, {
394		.nvmem_name = "fuse",
395		.cell_name = "xusb-pad-calibration",
396		.dev_id = "7009f000.padctl",
397		.con_id = "calibration",
398	}, {
399		.nvmem_name = "fuse",
400		.cell_name = "tsensor-cpu3",
401		.dev_id = "700e2000.thermal-sensor",
402		.con_id = "cpu3",
403	}, {
404		.nvmem_name = "fuse",
405		.cell_name = "sata-calibration",
406		.dev_id = "70020000.sata",
407		.con_id = "calibration",
408	}, {
409		.nvmem_name = "fuse",
410		.cell_name = "tsensor-gpu",
411		.dev_id = "700e2000.thermal-sensor",
412		.con_id = "gpu",
413	}, {
414		.nvmem_name = "fuse",
415		.cell_name = "tsensor-mem0",
416		.dev_id = "700e2000.thermal-sensor",
417		.con_id = "mem0",
418	}, {
419		.nvmem_name = "fuse",
420		.cell_name = "tsensor-mem1",
421		.dev_id = "700e2000.thermal-sensor",
422		.con_id = "mem1",
423	}, {
424		.nvmem_name = "fuse",
425		.cell_name = "tsensor-pllx",
426		.dev_id = "700e2000.thermal-sensor",
427		.con_id = "pllx",
428	}, {
429		.nvmem_name = "fuse",
430		.cell_name = "tsensor-common",
431		.dev_id = "700e2000.thermal-sensor",
432		.con_id = "common",
433	}, {
434		.nvmem_name = "fuse",
435		.cell_name = "gpu-calibration",
436		.dev_id = "57000000.gpu",
437		.con_id = "calibration",
438	}, {
439		.nvmem_name = "fuse",
440		.cell_name = "xusb-pad-calibration-ext",
441		.dev_id = "7009f000.padctl",
442		.con_id = "calibration-ext",
443	},
444};
445
446static const struct tegra_fuse_info tegra210_fuse_info = {
447	.read = tegra30_fuse_read,
448	.size = 0x300,
449	.spare = 0x280,
450};
451
452const struct tegra_fuse_soc tegra210_fuse_soc = {
453	.init = tegra30_fuse_init,
454	.speedo_init = tegra210_init_speedo_data,
455	.info = &tegra210_fuse_info,
456	.lookups = tegra210_fuse_lookups,
457	.cells = tegra210_fuse_cells,
458	.num_cells = ARRAY_SIZE(tegra210_fuse_cells),
459	.num_lookups = ARRAY_SIZE(tegra210_fuse_lookups),
460	.soc_attr_group = &tegra_soc_attr_group,
461	.clk_suspend_on = false,
462};
463#endif
464
465#if defined(CONFIG_ARCH_TEGRA_186_SOC)
466static const struct nvmem_cell_info tegra186_fuse_cells[] = {
467	{
468		.name = "xusb-pad-calibration",
469		.offset = 0x0f0,
470		.bytes = 4,
471		.bit_offset = 0,
472		.nbits = 32,
473	}, {
474		.name = "xusb-pad-calibration-ext",
475		.offset = 0x250,
476		.bytes = 4,
477		.bit_offset = 0,
478		.nbits = 32,
479	},
480};
481
482static const struct nvmem_cell_lookup tegra186_fuse_lookups[] = {
483	{
484		.nvmem_name = "fuse",
485		.cell_name = "xusb-pad-calibration",
486		.dev_id = "3520000.padctl",
487		.con_id = "calibration",
488	}, {
489		.nvmem_name = "fuse",
490		.cell_name = "xusb-pad-calibration-ext",
491		.dev_id = "3520000.padctl",
492		.con_id = "calibration-ext",
493	},
494};
495
496static const struct nvmem_keepout tegra186_fuse_keepouts[] = {
497	{ .start = 0x01c, .end = 0x0f0 },
498	{ .start = 0x138, .end = 0x198 },
499	{ .start = 0x1d8, .end = 0x250 },
500	{ .start = 0x280, .end = 0x290 },
501	{ .start = 0x340, .end = 0x344 }
502};
503
504static const struct tegra_fuse_info tegra186_fuse_info = {
505	.read = tegra30_fuse_read,
506	.size = 0x478,
507	.spare = 0x280,
508};
509
510const struct tegra_fuse_soc tegra186_fuse_soc = {
511	.init = tegra30_fuse_init,
512	.info = &tegra186_fuse_info,
513	.lookups = tegra186_fuse_lookups,
514	.num_lookups = ARRAY_SIZE(tegra186_fuse_lookups),
515	.cells = tegra186_fuse_cells,
516	.num_cells = ARRAY_SIZE(tegra186_fuse_cells),
517	.keepouts = tegra186_fuse_keepouts,
518	.num_keepouts = ARRAY_SIZE(tegra186_fuse_keepouts),
519	.soc_attr_group = &tegra_soc_attr_group,
520	.clk_suspend_on = false,
521};
522#endif
523
524#if defined(CONFIG_ARCH_TEGRA_194_SOC)
525static const struct nvmem_cell_info tegra194_fuse_cells[] = {
526	{
527		.name = "xusb-pad-calibration",
528		.offset = 0x0f0,
529		.bytes = 4,
530		.bit_offset = 0,
531		.nbits = 32,
532	}, {
533		.name = "gpu-gcplex-config-fuse",
534		.offset = 0x1c8,
535		.bytes = 4,
536		.bit_offset = 0,
537		.nbits = 32,
538	}, {
539		.name = "xusb-pad-calibration-ext",
540		.offset = 0x250,
541		.bytes = 4,
542		.bit_offset = 0,
543		.nbits = 32,
544	}, {
545		.name = "gpu-pdi0",
546		.offset = 0x300,
547		.bytes = 4,
548		.bit_offset = 0,
549		.nbits = 32,
550	}, {
551		.name = "gpu-pdi1",
552		.offset = 0x304,
553		.bytes = 4,
554		.bit_offset = 0,
555		.nbits = 32,
556	},
557};
558
559static const struct nvmem_cell_lookup tegra194_fuse_lookups[] = {
560	{
561		.nvmem_name = "fuse",
562		.cell_name = "xusb-pad-calibration",
563		.dev_id = "3520000.padctl",
564		.con_id = "calibration",
565	}, {
566		.nvmem_name = "fuse",
567		.cell_name = "xusb-pad-calibration-ext",
568		.dev_id = "3520000.padctl",
569		.con_id = "calibration-ext",
570	}, {
571		.nvmem_name = "fuse",
572		.cell_name = "gpu-gcplex-config-fuse",
573		.dev_id = "17000000.gpu",
574		.con_id = "gcplex-config-fuse",
575	}, {
576		.nvmem_name = "fuse",
577		.cell_name = "gpu-pdi0",
578		.dev_id = "17000000.gpu",
579		.con_id = "pdi0",
580	}, {
581		.nvmem_name = "fuse",
582		.cell_name = "gpu-pdi1",
583		.dev_id = "17000000.gpu",
584		.con_id = "pdi1",
585	},
586};
587
588static const struct nvmem_keepout tegra194_fuse_keepouts[] = {
589	{ .start = 0x01c, .end = 0x0b8 },
590	{ .start = 0x12c, .end = 0x198 },
591	{ .start = 0x1a0, .end = 0x1bc },
592	{ .start = 0x1d8, .end = 0x250 },
593	{ .start = 0x270, .end = 0x290 },
594	{ .start = 0x310, .end = 0x45c }
595};
596
597static const struct tegra_fuse_info tegra194_fuse_info = {
598	.read = tegra30_fuse_read,
599	.size = 0x650,
600	.spare = 0x280,
601};
602
603const struct tegra_fuse_soc tegra194_fuse_soc = {
604	.init = tegra30_fuse_init,
605	.info = &tegra194_fuse_info,
606	.lookups = tegra194_fuse_lookups,
607	.num_lookups = ARRAY_SIZE(tegra194_fuse_lookups),
608	.cells = tegra194_fuse_cells,
609	.num_cells = ARRAY_SIZE(tegra194_fuse_cells),
610	.keepouts = tegra194_fuse_keepouts,
611	.num_keepouts = ARRAY_SIZE(tegra194_fuse_keepouts),
612	.soc_attr_group = &tegra194_soc_attr_group,
613	.clk_suspend_on = false,
614};
615#endif
616
617#if defined(CONFIG_ARCH_TEGRA_234_SOC)
618static const struct nvmem_cell_info tegra234_fuse_cells[] = {
619	{
620		.name = "xusb-pad-calibration",
621		.offset = 0x0f0,
622		.bytes = 4,
623		.bit_offset = 0,
624		.nbits = 32,
625	}, {
626		.name = "xusb-pad-calibration-ext",
627		.offset = 0x250,
628		.bytes = 4,
629		.bit_offset = 0,
630		.nbits = 32,
631	},
632};
633
634static const struct nvmem_cell_lookup tegra234_fuse_lookups[] = {
635	{
636		.nvmem_name = "fuse",
637		.cell_name = "xusb-pad-calibration",
638		.dev_id = "3520000.padctl",
639		.con_id = "calibration",
640	}, {
641		.nvmem_name = "fuse",
642		.cell_name = "xusb-pad-calibration-ext",
643		.dev_id = "3520000.padctl",
644		.con_id = "calibration-ext",
645	},
646};
647
648static const struct nvmem_keepout tegra234_fuse_keepouts[] = {
649	{ .start = 0x01c, .end = 0x0c8 },
650	{ .start = 0x12c, .end = 0x184 },
651	{ .start = 0x190, .end = 0x198 },
652	{ .start = 0x1a0, .end = 0x204 },
653	{ .start = 0x21c, .end = 0x250 },
654	{ .start = 0x25c, .end = 0x2f0 },
655	{ .start = 0x310, .end = 0x3d8 },
656	{ .start = 0x400, .end = 0x4f0 },
657	{ .start = 0x4f8, .end = 0x7e8 },
658	{ .start = 0x8d0, .end = 0x8d8 },
659	{ .start = 0xacc, .end = 0xf00 }
660};
661
662static const struct tegra_fuse_info tegra234_fuse_info = {
663	.read = tegra30_fuse_read,
664	.size = 0xf90,
665	.spare = 0x280,
666};
667
668const struct tegra_fuse_soc tegra234_fuse_soc = {
669	.init = tegra30_fuse_init,
670	.info = &tegra234_fuse_info,
671	.lookups = tegra234_fuse_lookups,
672	.num_lookups = ARRAY_SIZE(tegra234_fuse_lookups),
673	.cells = tegra234_fuse_cells,
674	.num_cells = ARRAY_SIZE(tegra234_fuse_cells),
675	.keepouts = tegra234_fuse_keepouts,
676	.num_keepouts = ARRAY_SIZE(tegra234_fuse_keepouts),
677	.soc_attr_group = &tegra194_soc_attr_group,
678	.clk_suspend_on = false,
679};
680#endif
681