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 static u32 tegra30_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset)
41 {
42 	if (WARN_ON(!fuse->base))
43 		return 0;
44 
45 	return readl_relaxed(fuse->base + FUSE_BEGIN + offset);
46 }
47 
48 static u32 tegra30_fuse_read(struct tegra_fuse *fuse, unsigned int offset)
49 {
50 	u32 value;
51 	int err;
52 
53 	err = clk_prepare_enable(fuse->clk);
54 	if (err < 0) {
55 		dev_err(fuse->dev, "failed to enable FUSE clock: %d\n", err);
56 		return 0;
57 	}
58 
59 	value = readl_relaxed(fuse->base + FUSE_BEGIN + offset);
60 
61 	clk_disable_unprepare(fuse->clk);
62 
63 	return value;
64 }
65 
66 static 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 
88 static 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
103 static const struct tegra_fuse_info tegra30_fuse_info = {
104 	.read = tegra30_fuse_read,
105 	.size = 0x2a4,
106 	.spare = 0x144,
107 };
108 
109 const 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 };
114 #endif
115 
116 #ifdef CONFIG_ARCH_TEGRA_114_SOC
117 static const struct tegra_fuse_info tegra114_fuse_info = {
118 	.read = tegra30_fuse_read,
119 	.size = 0x2a0,
120 	.spare = 0x180,
121 };
122 
123 const struct tegra_fuse_soc tegra114_fuse_soc = {
124 	.init = tegra30_fuse_init,
125 	.speedo_init = tegra114_init_speedo_data,
126 	.info = &tegra114_fuse_info,
127 };
128 #endif
129 
130 #if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC)
131 static const struct nvmem_cell_lookup tegra124_fuse_lookups[] = {
132 	{
133 		.nvmem_name = "fuse",
134 		.cell_name = "xusb-pad-calibration",
135 		.dev_id = "7009f000.padctl",
136 		.con_id = "calibration",
137 	}, {
138 		.nvmem_name = "fuse",
139 		.cell_name = "sata-calibration",
140 		.dev_id = "70020000.sata",
141 		.con_id = "calibration",
142 	}, {
143 		.nvmem_name = "fuse",
144 		.cell_name = "tsensor-common",
145 		.dev_id = "700e2000.thermal-sensor",
146 		.con_id = "common",
147 	}, {
148 		.nvmem_name = "fuse",
149 		.cell_name = "tsensor-realignment",
150 		.dev_id = "700e2000.thermal-sensor",
151 		.con_id = "realignment",
152 	}, {
153 		.nvmem_name = "fuse",
154 		.cell_name = "tsensor-cpu0",
155 		.dev_id = "700e2000.thermal-sensor",
156 		.con_id = "cpu0",
157 	}, {
158 		.nvmem_name = "fuse",
159 		.cell_name = "tsensor-cpu1",
160 		.dev_id = "700e2000.thermal-sensor",
161 		.con_id = "cpu1",
162 	}, {
163 		.nvmem_name = "fuse",
164 		.cell_name = "tsensor-cpu2",
165 		.dev_id = "700e2000.thermal-sensor",
166 		.con_id = "cpu2",
167 	}, {
168 		.nvmem_name = "fuse",
169 		.cell_name = "tsensor-cpu3",
170 		.dev_id = "700e2000.thermal-sensor",
171 		.con_id = "cpu3",
172 	}, {
173 		.nvmem_name = "fuse",
174 		.cell_name = "tsensor-mem0",
175 		.dev_id = "700e2000.thermal-sensor",
176 		.con_id = "mem0",
177 	}, {
178 		.nvmem_name = "fuse",
179 		.cell_name = "tsensor-mem1",
180 		.dev_id = "700e2000.thermal-sensor",
181 		.con_id = "mem1",
182 	}, {
183 		.nvmem_name = "fuse",
184 		.cell_name = "tsensor-gpu",
185 		.dev_id = "700e2000.thermal-sensor",
186 		.con_id = "gpu",
187 	}, {
188 		.nvmem_name = "fuse",
189 		.cell_name = "tsensor-pllx",
190 		.dev_id = "700e2000.thermal-sensor",
191 		.con_id = "pllx",
192 	},
193 };
194 
195 static const struct tegra_fuse_info tegra124_fuse_info = {
196 	.read = tegra30_fuse_read,
197 	.size = 0x300,
198 	.spare = 0x200,
199 };
200 
201 const struct tegra_fuse_soc tegra124_fuse_soc = {
202 	.init = tegra30_fuse_init,
203 	.speedo_init = tegra124_init_speedo_data,
204 	.info = &tegra124_fuse_info,
205 	.lookups = tegra124_fuse_lookups,
206 	.num_lookups = ARRAY_SIZE(tegra124_fuse_lookups),
207 };
208 #endif
209 
210 #if defined(CONFIG_ARCH_TEGRA_210_SOC)
211 static const struct nvmem_cell_lookup tegra210_fuse_lookups[] = {
212 	{
213 		.nvmem_name = "fuse",
214 		.cell_name = "tsensor-cpu1",
215 		.dev_id = "700e2000.thermal-sensor",
216 		.con_id = "cpu1",
217 	}, {
218 		.nvmem_name = "fuse",
219 		.cell_name = "tsensor-cpu2",
220 		.dev_id = "700e2000.thermal-sensor",
221 		.con_id = "cpu2",
222 	}, {
223 		.nvmem_name = "fuse",
224 		.cell_name = "tsensor-cpu0",
225 		.dev_id = "700e2000.thermal-sensor",
226 		.con_id = "cpu0",
227 	}, {
228 		.nvmem_name = "fuse",
229 		.cell_name = "xusb-pad-calibration",
230 		.dev_id = "7009f000.padctl",
231 		.con_id = "calibration",
232 	}, {
233 		.nvmem_name = "fuse",
234 		.cell_name = "tsensor-cpu3",
235 		.dev_id = "700e2000.thermal-sensor",
236 		.con_id = "cpu3",
237 	}, {
238 		.nvmem_name = "fuse",
239 		.cell_name = "sata-calibration",
240 		.dev_id = "70020000.sata",
241 		.con_id = "calibration",
242 	}, {
243 		.nvmem_name = "fuse",
244 		.cell_name = "tsensor-gpu",
245 		.dev_id = "700e2000.thermal-sensor",
246 		.con_id = "gpu",
247 	}, {
248 		.nvmem_name = "fuse",
249 		.cell_name = "tsensor-mem0",
250 		.dev_id = "700e2000.thermal-sensor",
251 		.con_id = "mem0",
252 	}, {
253 		.nvmem_name = "fuse",
254 		.cell_name = "tsensor-mem1",
255 		.dev_id = "700e2000.thermal-sensor",
256 		.con_id = "mem1",
257 	}, {
258 		.nvmem_name = "fuse",
259 		.cell_name = "tsensor-pllx",
260 		.dev_id = "700e2000.thermal-sensor",
261 		.con_id = "pllx",
262 	}, {
263 		.nvmem_name = "fuse",
264 		.cell_name = "tsensor-common",
265 		.dev_id = "700e2000.thermal-sensor",
266 		.con_id = "common",
267 	}, {
268 		.nvmem_name = "fuse",
269 		.cell_name = "gpu-calibration",
270 		.dev_id = "57000000.gpu",
271 		.con_id = "calibration",
272 	}, {
273 		.nvmem_name = "fuse",
274 		.cell_name = "xusb-pad-calibration-ext",
275 		.dev_id = "7009f000.padctl",
276 		.con_id = "calibration-ext",
277 	},
278 };
279 
280 static const struct tegra_fuse_info tegra210_fuse_info = {
281 	.read = tegra30_fuse_read,
282 	.size = 0x300,
283 	.spare = 0x280,
284 };
285 
286 const struct tegra_fuse_soc tegra210_fuse_soc = {
287 	.init = tegra30_fuse_init,
288 	.speedo_init = tegra210_init_speedo_data,
289 	.info = &tegra210_fuse_info,
290 	.lookups = tegra210_fuse_lookups,
291 	.num_lookups = ARRAY_SIZE(tegra210_fuse_lookups),
292 };
293 #endif
294 
295 #if defined(CONFIG_ARCH_TEGRA_186_SOC)
296 static const struct nvmem_cell_lookup tegra186_fuse_lookups[] = {
297 	{
298 		.nvmem_name = "fuse",
299 		.cell_name = "xusb-pad-calibration",
300 		.dev_id = "3520000.padctl",
301 		.con_id = "calibration",
302 	}, {
303 		.nvmem_name = "fuse",
304 		.cell_name = "xusb-pad-calibration-ext",
305 		.dev_id = "3520000.padctl",
306 		.con_id = "calibration-ext",
307 	},
308 };
309 
310 static const struct tegra_fuse_info tegra186_fuse_info = {
311 	.read = tegra30_fuse_read,
312 	.size = 0x300,
313 	.spare = 0x280,
314 };
315 
316 const struct tegra_fuse_soc tegra186_fuse_soc = {
317 	.init = tegra30_fuse_init,
318 	.info = &tegra186_fuse_info,
319 	.lookups = tegra186_fuse_lookups,
320 	.num_lookups = ARRAY_SIZE(tegra186_fuse_lookups),
321 };
322 #endif
323