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 	.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