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

source code of linux/drivers/soc/tegra/fuse/fuse-tegra30.c