1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2013-2014, 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/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)
tegra30_fuse_read_early(struct tegra_fuse * fuse,unsigned int offset)41 static u32 tegra30_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset)
42 {
43 if (WARN_ON(!fuse->base))
44 return 0;
45
46 return readl_relaxed(fuse->base + FUSE_BEGIN + offset);
47 }
48
tegra30_fuse_read(struct tegra_fuse * fuse,unsigned int offset)49 static u32 tegra30_fuse_read(struct tegra_fuse *fuse, unsigned int offset)
50 {
51 u32 value;
52 int err;
53
54 err = clk_prepare_enable(fuse->clk);
55 if (err < 0) {
56 dev_err(fuse->dev, "failed to enable FUSE clock: %d\n", err);
57 return 0;
58 }
59
60 value = readl_relaxed(fuse->base + FUSE_BEGIN + offset);
61
62 clk_disable_unprepare(fuse->clk);
63
64 return value;
65 }
66
tegra30_fuse_add_randomness(void)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
tegra30_fuse_init(struct tegra_fuse * fuse)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 };
116 #endif
117
118 #ifdef CONFIG_ARCH_TEGRA_114_SOC
119 static const struct tegra_fuse_info tegra114_fuse_info = {
120 .read = tegra30_fuse_read,
121 .size = 0x2a0,
122 .spare = 0x180,
123 };
124
125 const 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 };
131 #endif
132
133 #if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC)
134 static const struct nvmem_cell_lookup tegra124_fuse_lookups[] = {
135 {
136 .nvmem_name = "fuse",
137 .cell_name = "xusb-pad-calibration",
138 .dev_id = "7009f000.padctl",
139 .con_id = "calibration",
140 }, {
141 .nvmem_name = "fuse",
142 .cell_name = "sata-calibration",
143 .dev_id = "70020000.sata",
144 .con_id = "calibration",
145 }, {
146 .nvmem_name = "fuse",
147 .cell_name = "tsensor-common",
148 .dev_id = "700e2000.thermal-sensor",
149 .con_id = "common",
150 }, {
151 .nvmem_name = "fuse",
152 .cell_name = "tsensor-realignment",
153 .dev_id = "700e2000.thermal-sensor",
154 .con_id = "realignment",
155 }, {
156 .nvmem_name = "fuse",
157 .cell_name = "tsensor-cpu0",
158 .dev_id = "700e2000.thermal-sensor",
159 .con_id = "cpu0",
160 }, {
161 .nvmem_name = "fuse",
162 .cell_name = "tsensor-cpu1",
163 .dev_id = "700e2000.thermal-sensor",
164 .con_id = "cpu1",
165 }, {
166 .nvmem_name = "fuse",
167 .cell_name = "tsensor-cpu2",
168 .dev_id = "700e2000.thermal-sensor",
169 .con_id = "cpu2",
170 }, {
171 .nvmem_name = "fuse",
172 .cell_name = "tsensor-cpu3",
173 .dev_id = "700e2000.thermal-sensor",
174 .con_id = "cpu3",
175 }, {
176 .nvmem_name = "fuse",
177 .cell_name = "tsensor-mem0",
178 .dev_id = "700e2000.thermal-sensor",
179 .con_id = "mem0",
180 }, {
181 .nvmem_name = "fuse",
182 .cell_name = "tsensor-mem1",
183 .dev_id = "700e2000.thermal-sensor",
184 .con_id = "mem1",
185 }, {
186 .nvmem_name = "fuse",
187 .cell_name = "tsensor-gpu",
188 .dev_id = "700e2000.thermal-sensor",
189 .con_id = "gpu",
190 }, {
191 .nvmem_name = "fuse",
192 .cell_name = "tsensor-pllx",
193 .dev_id = "700e2000.thermal-sensor",
194 .con_id = "pllx",
195 },
196 };
197
198 static const struct tegra_fuse_info tegra124_fuse_info = {
199 .read = tegra30_fuse_read,
200 .size = 0x300,
201 .spare = 0x200,
202 };
203
204 const struct tegra_fuse_soc tegra124_fuse_soc = {
205 .init = tegra30_fuse_init,
206 .speedo_init = tegra124_init_speedo_data,
207 .info = &tegra124_fuse_info,
208 .lookups = tegra124_fuse_lookups,
209 .num_lookups = ARRAY_SIZE(tegra124_fuse_lookups),
210 .soc_attr_group = &tegra_soc_attr_group,
211 };
212 #endif
213
214 #if defined(CONFIG_ARCH_TEGRA_210_SOC)
215 static const struct nvmem_cell_lookup tegra210_fuse_lookups[] = {
216 {
217 .nvmem_name = "fuse",
218 .cell_name = "tsensor-cpu1",
219 .dev_id = "700e2000.thermal-sensor",
220 .con_id = "cpu1",
221 }, {
222 .nvmem_name = "fuse",
223 .cell_name = "tsensor-cpu2",
224 .dev_id = "700e2000.thermal-sensor",
225 .con_id = "cpu2",
226 }, {
227 .nvmem_name = "fuse",
228 .cell_name = "tsensor-cpu0",
229 .dev_id = "700e2000.thermal-sensor",
230 .con_id = "cpu0",
231 }, {
232 .nvmem_name = "fuse",
233 .cell_name = "xusb-pad-calibration",
234 .dev_id = "7009f000.padctl",
235 .con_id = "calibration",
236 }, {
237 .nvmem_name = "fuse",
238 .cell_name = "tsensor-cpu3",
239 .dev_id = "700e2000.thermal-sensor",
240 .con_id = "cpu3",
241 }, {
242 .nvmem_name = "fuse",
243 .cell_name = "sata-calibration",
244 .dev_id = "70020000.sata",
245 .con_id = "calibration",
246 }, {
247 .nvmem_name = "fuse",
248 .cell_name = "tsensor-gpu",
249 .dev_id = "700e2000.thermal-sensor",
250 .con_id = "gpu",
251 }, {
252 .nvmem_name = "fuse",
253 .cell_name = "tsensor-mem0",
254 .dev_id = "700e2000.thermal-sensor",
255 .con_id = "mem0",
256 }, {
257 .nvmem_name = "fuse",
258 .cell_name = "tsensor-mem1",
259 .dev_id = "700e2000.thermal-sensor",
260 .con_id = "mem1",
261 }, {
262 .nvmem_name = "fuse",
263 .cell_name = "tsensor-pllx",
264 .dev_id = "700e2000.thermal-sensor",
265 .con_id = "pllx",
266 }, {
267 .nvmem_name = "fuse",
268 .cell_name = "tsensor-common",
269 .dev_id = "700e2000.thermal-sensor",
270 .con_id = "common",
271 }, {
272 .nvmem_name = "fuse",
273 .cell_name = "gpu-calibration",
274 .dev_id = "57000000.gpu",
275 .con_id = "calibration",
276 }, {
277 .nvmem_name = "fuse",
278 .cell_name = "xusb-pad-calibration-ext",
279 .dev_id = "7009f000.padctl",
280 .con_id = "calibration-ext",
281 },
282 };
283
284 static const struct tegra_fuse_info tegra210_fuse_info = {
285 .read = tegra30_fuse_read,
286 .size = 0x300,
287 .spare = 0x280,
288 };
289
290 const struct tegra_fuse_soc tegra210_fuse_soc = {
291 .init = tegra30_fuse_init,
292 .speedo_init = tegra210_init_speedo_data,
293 .info = &tegra210_fuse_info,
294 .lookups = tegra210_fuse_lookups,
295 .num_lookups = ARRAY_SIZE(tegra210_fuse_lookups),
296 .soc_attr_group = &tegra_soc_attr_group,
297 };
298 #endif
299
300 #if defined(CONFIG_ARCH_TEGRA_186_SOC)
301 static const struct nvmem_cell_lookup tegra186_fuse_lookups[] = {
302 {
303 .nvmem_name = "fuse",
304 .cell_name = "xusb-pad-calibration",
305 .dev_id = "3520000.padctl",
306 .con_id = "calibration",
307 }, {
308 .nvmem_name = "fuse",
309 .cell_name = "xusb-pad-calibration-ext",
310 .dev_id = "3520000.padctl",
311 .con_id = "calibration-ext",
312 },
313 };
314
315 static const struct tegra_fuse_info tegra186_fuse_info = {
316 .read = tegra30_fuse_read,
317 .size = 0x300,
318 .spare = 0x280,
319 };
320
321 const struct tegra_fuse_soc tegra186_fuse_soc = {
322 .init = tegra30_fuse_init,
323 .info = &tegra186_fuse_info,
324 .lookups = tegra186_fuse_lookups,
325 .num_lookups = ARRAY_SIZE(tegra186_fuse_lookups),
326 .soc_attr_group = &tegra_soc_attr_group,
327 };
328 #endif
329
330 #if defined(CONFIG_ARCH_TEGRA_194_SOC)
331 static const struct nvmem_cell_lookup tegra194_fuse_lookups[] = {
332 {
333 .nvmem_name = "fuse",
334 .cell_name = "xusb-pad-calibration",
335 .dev_id = "3520000.padctl",
336 .con_id = "calibration",
337 }, {
338 .nvmem_name = "fuse",
339 .cell_name = "xusb-pad-calibration-ext",
340 .dev_id = "3520000.padctl",
341 .con_id = "calibration-ext",
342 },
343 };
344
345 static const struct tegra_fuse_info tegra194_fuse_info = {
346 .read = tegra30_fuse_read,
347 .size = 0x300,
348 .spare = 0x280,
349 };
350
351 const struct tegra_fuse_soc tegra194_fuse_soc = {
352 .init = tegra30_fuse_init,
353 .info = &tegra194_fuse_info,
354 .lookups = tegra194_fuse_lookups,
355 .num_lookups = ARRAY_SIZE(tegra194_fuse_lookups),
356 .soc_attr_group = &tegra194_soc_attr_group,
357 };
358 #endif
359
360 #if defined(CONFIG_ARCH_TEGRA_234_SOC)
361 static const struct nvmem_cell_lookup tegra234_fuse_lookups[] = {
362 {
363 .nvmem_name = "fuse",
364 .cell_name = "xusb-pad-calibration",
365 .dev_id = "3520000.padctl",
366 .con_id = "calibration",
367 }, {
368 .nvmem_name = "fuse",
369 .cell_name = "xusb-pad-calibration-ext",
370 .dev_id = "3520000.padctl",
371 .con_id = "calibration-ext",
372 },
373 };
374
375 static const struct tegra_fuse_info tegra234_fuse_info = {
376 .read = tegra30_fuse_read,
377 .size = 0x300,
378 .spare = 0x280,
379 };
380
381 const struct tegra_fuse_soc tegra234_fuse_soc = {
382 .init = tegra30_fuse_init,
383 .info = &tegra234_fuse_info,
384 .lookups = tegra234_fuse_lookups,
385 .num_lookups = ARRAY_SIZE(tegra234_fuse_lookups),
386 .soc_attr_group = &tegra194_soc_attr_group,
387 };
388 #endif
389