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