blob: 83bd505538411cb7c9ddc5b8739c8dc00b7f3654 [file] [log] [blame]
Svyatoslav Ryheld83721f2023-06-30 10:29:02 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2012-2013
4 * NVIDIA Corporation <www.nvidia.com>
5 *
6 * (C) Copyright 2022
7 * Svyatoslav Ryhel <clamor95@gmail.com>
8 */
9
10#include <common.h>
11#include <linux/delay.h>
12#include <asm/io.h>
13
14#include <asm/arch/tegra.h>
15#include <asm/arch/gp_padctrl.h>
16#include <asm/arch/clock.h>
17#include <asm/arch-tegra/fuse.h>
18
19#include "cpu.h"
20
21#define FUSE_UID_LOW 0x108
22#define FUSE_UID_HIGH 0x10c
23
24#define FUSE_VENDOR_CODE 0x200
25#define FUSE_FAB_CODE 0x204
26#define FUSE_LOT_CODE_0 0x208
27#define FUSE_LOT_CODE_1 0x20c
28#define FUSE_WAFER_ID 0x210
29#define FUSE_X_COORDINATE 0x214
30#define FUSE_Y_COORDINATE 0x218
31
32#define FUSE_VENDOR_CODE_MASK 0xf
33#define FUSE_FAB_CODE_MASK 0x3f
34#define FUSE_WAFER_ID_MASK 0x3f
35#define FUSE_X_COORDINATE_MASK 0x1ff
36#define FUSE_Y_COORDINATE_MASK 0x1ff
37
38static u32 tegra_fuse_readl(unsigned long offset)
39{
40 return readl(NV_PA_FUSE_BASE + offset);
41}
42
43static void tegra_fuse_init(void)
44{
45 u32 reg;
46
47 /*
48 * Performed by downstream and is not
49 * documented by TRM. Whithout setting
50 * this bit fuse region will not work.
51 */
52 reg = readl_relaxed(NV_PA_CLK_RST_BASE + 0x48);
53 reg |= BIT(28);
54 writel(reg, NV_PA_CLK_RST_BASE + 0x48);
55
56 clock_enable(PERIPH_ID_FUSE);
57 udelay(2);
58 reset_set_enable(PERIPH_ID_FUSE, 0);
59}
60
61unsigned long long tegra_chip_uid(void)
62{
63 u64 uid = 0ull;
64 u32 reg;
65 u32 cid;
66 u32 vendor;
67 u32 fab;
68 u32 lot;
69 u32 wafer;
70 u32 x;
71 u32 y;
72 u32 i;
73
74 tegra_fuse_init();
75
76 /* This used to be so much easier in prior chips. Unfortunately, there
77 is no one-stop shopping for the unique id anymore. It must be
78 constructed from various bits of information burned into the fuses
79 during the manufacturing process. The 64-bit unique id is formed
80 by concatenating several bit fields. The notation used for the
81 various fields is <fieldname:size_in_bits> with the UID composed
82 thusly:
83 <CID:4><VENDOR:4><FAB:6><LOT:26><WAFER:6><X:9><Y:9>
84 Where:
85 Field Bits Position Data
86 ------- ---- -------- ----------------------------------------
87 CID 4 60 Chip id
88 VENDOR 4 56 Vendor code
89 FAB 6 50 FAB code
90 LOT 26 24 Lot code (5-digit base-36-coded-decimal,
91 re-encoded to 26 bits binary)
92 WAFER 6 18 Wafer id
93 X 9 9 Wafer X-coordinate
94 Y 9 0 Wafer Y-coordinate
95 ------- ----
96 Total 64
97 */
98
99 switch (tegra_get_chip()) {
100 case CHIPID_TEGRA20:
101 /* T20 has simple calculation */
102 return ((unsigned long long)tegra_fuse_readl(FUSE_UID_HIGH) << 32ull) |
103 (unsigned long long)tegra_fuse_readl(FUSE_UID_LOW);
104 case CHIPID_TEGRA30:
105 /* T30 chip id is 0 */
106 cid = 0;
107 break;
108 case CHIPID_TEGRA114:
109 /* T11x chip id is 1 */
110 cid = 1;
111 break;
112 case CHIPID_TEGRA124:
113 /* T12x chip id is 3 */
114 cid = 3;
115 break;
116 case CHIPID_TEGRA210:
117 /* T210 chip id is 5 */
118 cid = 5;
119 default:
120 return 0;
121 }
122
123 vendor = tegra_fuse_readl(FUSE_VENDOR_CODE) & FUSE_VENDOR_CODE_MASK;
124 fab = tegra_fuse_readl(FUSE_FAB_CODE) & FUSE_FAB_CODE_MASK;
125
126 /* Lot code must be re-encoded from a 5 digit base-36 'BCD' number
127 to a binary number. */
128 lot = 0;
129 reg = tegra_fuse_readl(FUSE_LOT_CODE_0) << 2;
130
131 for (i = 0; i < 5; ++i) {
132 u32 digit = (reg & 0xFC000000) >> 26;
133 lot *= 36;
134 lot += digit;
135 reg <<= 6;
136 }
137
138 wafer = tegra_fuse_readl(FUSE_WAFER_ID) & FUSE_WAFER_ID_MASK;
139 x = tegra_fuse_readl(FUSE_X_COORDINATE) & FUSE_X_COORDINATE_MASK;
140 y = tegra_fuse_readl(FUSE_Y_COORDINATE) & FUSE_Y_COORDINATE_MASK;
141
142 uid = ((unsigned long long)cid << 60ull)
143 | ((unsigned long long)vendor << 56ull)
144 | ((unsigned long long)fab << 50ull)
145 | ((unsigned long long)lot << 24ull)
146 | ((unsigned long long)wafer << 18ull)
147 | ((unsigned long long)x << 9ull)
148 | ((unsigned long long)y << 0ull);
149
150 return uid;
151}