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)
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 
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 
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 };
115 #endif
116 
117 #ifdef CONFIG_ARCH_TEGRA_114_SOC
118 static const struct tegra_fuse_info tegra114_fuse_info = {
119 	.read = tegra30_fuse_read,
120 	.size = 0x2a0,
121 	.spare = 0x180,
122 };
123 
124 const struct tegra_fuse_soc tegra114_fuse_soc = {
125 	.init = tegra30_fuse_init,
126 	.speedo_init = tegra114_init_speedo_data,
127 	.info = &tegra114_fuse_info,
128 };
129 #endif
130 
131 #if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC)
132 static const struct nvmem_cell_lookup tegra124_fuse_lookups[] = {
133 	{
134 		.nvmem_name = "fuse",
135 		.cell_name = "xusb-pad-calibration",
136 		.dev_id = "7009f000.padctl",
137 		.con_id = "calibration",
138 	}, {
139 		.nvmem_name = "fuse",
140 		.cell_name = "sata-calibration",
141 		.dev_id = "70020000.sata",
142 		.con_id = "calibration",
143 	}, {
144 		.nvmem_name = "fuse",
145 		.cell_name = "tsensor-common",
146 		.dev_id = "700e2000.thermal-sensor",
147 		.con_id = "common",
148 	}, {
149 		.nvmem_name = "fuse",
150 		.cell_name = "tsensor-realignment",
151 		.dev_id = "700e2000.thermal-sensor",
152 		.con_id = "realignment",
153 	}, {
154 		.nvmem_name = "fuse",
155 		.cell_name = "tsensor-cpu0",
156 		.dev_id = "700e2000.thermal-sensor",
157 		.con_id = "cpu0",
158 	}, {
159 		.nvmem_name = "fuse",
160 		.cell_name = "tsensor-cpu1",
161 		.dev_id = "700e2000.thermal-sensor",
162 		.con_id = "cpu1",
163 	}, {
164 		.nvmem_name = "fuse",
165 		.cell_name = "tsensor-cpu2",
166 		.dev_id = "700e2000.thermal-sensor",
167 		.con_id = "cpu2",
168 	}, {
169 		.nvmem_name = "fuse",
170 		.cell_name = "tsensor-cpu3",
171 		.dev_id = "700e2000.thermal-sensor",
172 		.con_id = "cpu3",
173 	}, {
174 		.nvmem_name = "fuse",
175 		.cell_name = "tsensor-mem0",
176 		.dev_id = "700e2000.thermal-sensor",
177 		.con_id = "mem0",
178 	}, {
179 		.nvmem_name = "fuse",
180 		.cell_name = "tsensor-mem1",
181 		.dev_id = "700e2000.thermal-sensor",
182 		.con_id = "mem1",
183 	}, {
184 		.nvmem_name = "fuse",
185 		.cell_name = "tsensor-gpu",
186 		.dev_id = "700e2000.thermal-sensor",
187 		.con_id = "gpu",
188 	}, {
189 		.nvmem_name = "fuse",
190 		.cell_name = "tsensor-pllx",
191 		.dev_id = "700e2000.thermal-sensor",
192 		.con_id = "pllx",
193 	},
194 };
195 
196 static const struct tegra_fuse_info tegra124_fuse_info = {
197 	.read = tegra30_fuse_read,
198 	.size = 0x300,
199 	.spare = 0x200,
200 };
201 
202 const struct tegra_fuse_soc tegra124_fuse_soc = {
203 	.init = tegra30_fuse_init,
204 	.speedo_init = tegra124_init_speedo_data,
205 	.info = &tegra124_fuse_info,
206 	.lookups = tegra124_fuse_lookups,
207 	.num_lookups = ARRAY_SIZE(tegra124_fuse_lookups),
208 };
209 #endif
210 
211 #if defined(CONFIG_ARCH_TEGRA_210_SOC)
212 static const struct nvmem_cell_lookup tegra210_fuse_lookups[] = {
213 	{
214 		.nvmem_name = "fuse",
215 		.cell_name = "tsensor-cpu1",
216 		.dev_id = "700e2000.thermal-sensor",
217 		.con_id = "cpu1",
218 	}, {
219 		.nvmem_name = "fuse",
220 		.cell_name = "tsensor-cpu2",
221 		.dev_id = "700e2000.thermal-sensor",
222 		.con_id = "cpu2",
223 	}, {
224 		.nvmem_name = "fuse",
225 		.cell_name = "tsensor-cpu0",
226 		.dev_id = "700e2000.thermal-sensor",
227 		.con_id = "cpu0",
228 	}, {
229 		.nvmem_name = "fuse",
230 		.cell_name = "xusb-pad-calibration",
231 		.dev_id = "7009f000.padctl",
232 		.con_id = "calibration",
233 	}, {
234 		.nvmem_name = "fuse",
235 		.cell_name = "tsensor-cpu3",
236 		.dev_id = "700e2000.thermal-sensor",
237 		.con_id = "cpu3",
238 	}, {
239 		.nvmem_name = "fuse",
240 		.cell_name = "sata-calibration",
241 		.dev_id = "70020000.sata",
242 		.con_id = "calibration",
243 	}, {
244 		.nvmem_name = "fuse",
245 		.cell_name = "tsensor-gpu",
246 		.dev_id = "700e2000.thermal-sensor",
247 		.con_id = "gpu",
248 	}, {
249 		.nvmem_name = "fuse",
250 		.cell_name = "tsensor-mem0",
251 		.dev_id = "700e2000.thermal-sensor",
252 		.con_id = "mem0",
253 	}, {
254 		.nvmem_name = "fuse",
255 		.cell_name = "tsensor-mem1",
256 		.dev_id = "700e2000.thermal-sensor",
257 		.con_id = "mem1",
258 	}, {
259 		.nvmem_name = "fuse",
260 		.cell_name = "tsensor-pllx",
261 		.dev_id = "700e2000.thermal-sensor",
262 		.con_id = "pllx",
263 	}, {
264 		.nvmem_name = "fuse",
265 		.cell_name = "tsensor-common",
266 		.dev_id = "700e2000.thermal-sensor",
267 		.con_id = "common",
268 	}, {
269 		.nvmem_name = "fuse",
270 		.cell_name = "gpu-calibration",
271 		.dev_id = "57000000.gpu",
272 		.con_id = "calibration",
273 	}, {
274 		.nvmem_name = "fuse",
275 		.cell_name = "xusb-pad-calibration-ext",
276 		.dev_id = "7009f000.padctl",
277 		.con_id = "calibration-ext",
278 	},
279 };
280 
281 static const struct tegra_fuse_info tegra210_fuse_info = {
282 	.read = tegra30_fuse_read,
283 	.size = 0x300,
284 	.spare = 0x280,
285 };
286 
287 const struct tegra_fuse_soc tegra210_fuse_soc = {
288 	.init = tegra30_fuse_init,
289 	.speedo_init = tegra210_init_speedo_data,
290 	.info = &tegra210_fuse_info,
291 	.lookups = tegra210_fuse_lookups,
292 	.num_lookups = ARRAY_SIZE(tegra210_fuse_lookups),
293 };
294 #endif
295 
296 #if defined(CONFIG_ARCH_TEGRA_186_SOC)
297 static const struct nvmem_cell_lookup tegra186_fuse_lookups[] = {
298 	{
299 		.nvmem_name = "fuse",
300 		.cell_name = "xusb-pad-calibration",
301 		.dev_id = "3520000.padctl",
302 		.con_id = "calibration",
303 	}, {
304 		.nvmem_name = "fuse",
305 		.cell_name = "xusb-pad-calibration-ext",
306 		.dev_id = "3520000.padctl",
307 		.con_id = "calibration-ext",
308 	},
309 };
310 
311 static const struct tegra_fuse_info tegra186_fuse_info = {
312 	.read = tegra30_fuse_read,
313 	.size = 0x300,
314 	.spare = 0x280,
315 };
316 
317 const struct tegra_fuse_soc tegra186_fuse_soc = {
318 	.init = tegra30_fuse_init,
319 	.info = &tegra186_fuse_info,
320 	.lookups = tegra186_fuse_lookups,
321 	.num_lookups = ARRAY_SIZE(tegra186_fuse_lookups),
322 };
323 #endif
324 
325 #if defined(CONFIG_ARCH_TEGRA_194_SOC)
326 static const struct nvmem_cell_lookup tegra194_fuse_lookups[] = {
327 	{
328 		.nvmem_name = "fuse",
329 		.cell_name = "xusb-pad-calibration",
330 		.dev_id = "3520000.padctl",
331 		.con_id = "calibration",
332 	}, {
333 		.nvmem_name = "fuse",
334 		.cell_name = "xusb-pad-calibration-ext",
335 		.dev_id = "3520000.padctl",
336 		.con_id = "calibration-ext",
337 	},
338 };
339 
340 static const struct tegra_fuse_info tegra194_fuse_info = {
341 	.read = tegra30_fuse_read,
342 	.size = 0x300,
343 	.spare = 0x280,
344 };
345 
346 const struct tegra_fuse_soc tegra194_fuse_soc = {
347 	.init = tegra30_fuse_init,
348 	.info = &tegra194_fuse_info,
349 	.lookups = tegra194_fuse_lookups,
350 	.num_lookups = ARRAY_SIZE(tegra194_fuse_lookups),
351 };
352 #endif
353