1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2013-2023, NVIDIA CORPORATION. All rights reserved. |
4 | */ |
5 | |
6 | #include <linux/clk.h> |
7 | #include <linux/device.h> |
8 | #include <linux/kobject.h> |
9 | #include <linux/init.h> |
10 | #include <linux/io.h> |
11 | #include <linux/nvmem-consumer.h> |
12 | #include <linux/nvmem-provider.h> |
13 | #include <linux/of.h> |
14 | #include <linux/of_address.h> |
15 | #include <linux/platform_device.h> |
16 | #include <linux/pm_runtime.h> |
17 | #include <linux/reset.h> |
18 | #include <linux/slab.h> |
19 | #include <linux/sys_soc.h> |
20 | |
21 | #include <soc/tegra/common.h> |
22 | #include <soc/tegra/fuse.h> |
23 | |
24 | #include "fuse.h" |
25 | |
26 | struct tegra_sku_info tegra_sku_info; |
27 | EXPORT_SYMBOL(tegra_sku_info); |
28 | |
29 | static const char *tegra_revision_name[TEGRA_REVISION_MAX] = { |
30 | [TEGRA_REVISION_UNKNOWN] = "unknown" , |
31 | [TEGRA_REVISION_A01] = "A01" , |
32 | [TEGRA_REVISION_A02] = "A02" , |
33 | [TEGRA_REVISION_A03] = "A03" , |
34 | [TEGRA_REVISION_A03p] = "A03 prime" , |
35 | [TEGRA_REVISION_A04] = "A04" , |
36 | }; |
37 | |
38 | static const char *tegra_platform_name[TEGRA_PLATFORM_MAX] = { |
39 | [TEGRA_PLATFORM_SILICON] = "Silicon" , |
40 | [TEGRA_PLATFORM_QT] = "QT" , |
41 | [TEGRA_PLATFORM_SYSTEM_FPGA] = "System FPGA" , |
42 | [TEGRA_PLATFORM_UNIT_FPGA] = "Unit FPGA" , |
43 | [TEGRA_PLATFORM_ASIM_QT] = "Asim QT" , |
44 | [TEGRA_PLATFORM_ASIM_LINSIM] = "Asim Linsim" , |
45 | [TEGRA_PLATFORM_DSIM_ASIM_LINSIM] = "Dsim Asim Linsim" , |
46 | [TEGRA_PLATFORM_VERIFICATION_SIMULATION] = "Verification Simulation" , |
47 | [TEGRA_PLATFORM_VDK] = "VDK" , |
48 | [TEGRA_PLATFORM_VSP] = "VSP" , |
49 | }; |
50 | |
51 | static const struct of_device_id car_match[] __initconst = { |
52 | { .compatible = "nvidia,tegra20-car" , }, |
53 | { .compatible = "nvidia,tegra30-car" , }, |
54 | { .compatible = "nvidia,tegra114-car" , }, |
55 | { .compatible = "nvidia,tegra124-car" , }, |
56 | { .compatible = "nvidia,tegra132-car" , }, |
57 | { .compatible = "nvidia,tegra210-car" , }, |
58 | {}, |
59 | }; |
60 | |
61 | static struct tegra_fuse *fuse = &(struct tegra_fuse) { |
62 | .base = NULL, |
63 | .soc = NULL, |
64 | }; |
65 | |
66 | static const struct of_device_id tegra_fuse_match[] = { |
67 | #ifdef CONFIG_ARCH_TEGRA_234_SOC |
68 | { .compatible = "nvidia,tegra234-efuse" , .data = &tegra234_fuse_soc }, |
69 | #endif |
70 | #ifdef CONFIG_ARCH_TEGRA_194_SOC |
71 | { .compatible = "nvidia,tegra194-efuse" , .data = &tegra194_fuse_soc }, |
72 | #endif |
73 | #ifdef CONFIG_ARCH_TEGRA_186_SOC |
74 | { .compatible = "nvidia,tegra186-efuse" , .data = &tegra186_fuse_soc }, |
75 | #endif |
76 | #ifdef CONFIG_ARCH_TEGRA_210_SOC |
77 | { .compatible = "nvidia,tegra210-efuse" , .data = &tegra210_fuse_soc }, |
78 | #endif |
79 | #ifdef CONFIG_ARCH_TEGRA_132_SOC |
80 | { .compatible = "nvidia,tegra132-efuse" , .data = &tegra124_fuse_soc }, |
81 | #endif |
82 | #ifdef CONFIG_ARCH_TEGRA_124_SOC |
83 | { .compatible = "nvidia,tegra124-efuse" , .data = &tegra124_fuse_soc }, |
84 | #endif |
85 | #ifdef CONFIG_ARCH_TEGRA_114_SOC |
86 | { .compatible = "nvidia,tegra114-efuse" , .data = &tegra114_fuse_soc }, |
87 | #endif |
88 | #ifdef CONFIG_ARCH_TEGRA_3x_SOC |
89 | { .compatible = "nvidia,tegra30-efuse" , .data = &tegra30_fuse_soc }, |
90 | #endif |
91 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC |
92 | { .compatible = "nvidia,tegra20-efuse" , .data = &tegra20_fuse_soc }, |
93 | #endif |
94 | { /* sentinel */ } |
95 | }; |
96 | |
97 | static int tegra_fuse_read(void *priv, unsigned int offset, void *value, |
98 | size_t bytes) |
99 | { |
100 | unsigned int count = bytes / 4, i; |
101 | struct tegra_fuse *fuse = priv; |
102 | u32 *buffer = value; |
103 | |
104 | for (i = 0; i < count; i++) |
105 | buffer[i] = fuse->read(fuse, offset + i * 4); |
106 | |
107 | return 0; |
108 | } |
109 | |
110 | static void tegra_fuse_restore(void *base) |
111 | { |
112 | fuse->base = (void __iomem *)base; |
113 | fuse->clk = NULL; |
114 | } |
115 | |
116 | static int tegra_fuse_probe(struct platform_device *pdev) |
117 | { |
118 | void __iomem *base = fuse->base; |
119 | struct nvmem_config nvmem; |
120 | struct resource *res; |
121 | int err; |
122 | |
123 | err = devm_add_action(&pdev->dev, tegra_fuse_restore, (void __force *)base); |
124 | if (err) |
125 | return err; |
126 | |
127 | /* take over the memory region from the early initialization */ |
128 | fuse->base = devm_platform_get_and_ioremap_resource(pdev, index: 0, res: &res); |
129 | if (IS_ERR(ptr: fuse->base)) |
130 | return PTR_ERR(ptr: fuse->base); |
131 | fuse->phys = res->start; |
132 | |
133 | fuse->clk = devm_clk_get(dev: &pdev->dev, id: "fuse" ); |
134 | if (IS_ERR(ptr: fuse->clk)) { |
135 | if (PTR_ERR(ptr: fuse->clk) != -EPROBE_DEFER) |
136 | dev_err(&pdev->dev, "failed to get FUSE clock: %ld" , |
137 | PTR_ERR(fuse->clk)); |
138 | |
139 | return PTR_ERR(ptr: fuse->clk); |
140 | } |
141 | |
142 | platform_set_drvdata(pdev, data: fuse); |
143 | fuse->dev = &pdev->dev; |
144 | |
145 | err = devm_pm_runtime_enable(dev: &pdev->dev); |
146 | if (err) |
147 | return err; |
148 | |
149 | if (fuse->soc->probe) { |
150 | err = fuse->soc->probe(fuse); |
151 | if (err < 0) |
152 | return err; |
153 | } |
154 | |
155 | memset(&nvmem, 0, sizeof(nvmem)); |
156 | nvmem.dev = &pdev->dev; |
157 | nvmem.name = "fuse" ; |
158 | nvmem.id = -1; |
159 | nvmem.owner = THIS_MODULE; |
160 | nvmem.cells = fuse->soc->cells; |
161 | nvmem.ncells = fuse->soc->num_cells; |
162 | nvmem.keepout = fuse->soc->keepouts; |
163 | nvmem.nkeepout = fuse->soc->num_keepouts; |
164 | nvmem.type = NVMEM_TYPE_OTP; |
165 | nvmem.read_only = true; |
166 | nvmem.root_only = false; |
167 | nvmem.reg_read = tegra_fuse_read; |
168 | nvmem.size = fuse->soc->info->size; |
169 | nvmem.word_size = 4; |
170 | nvmem.stride = 4; |
171 | nvmem.priv = fuse; |
172 | |
173 | fuse->nvmem = devm_nvmem_register(dev: &pdev->dev, cfg: &nvmem); |
174 | if (IS_ERR(ptr: fuse->nvmem)) { |
175 | err = PTR_ERR(ptr: fuse->nvmem); |
176 | dev_err(&pdev->dev, "failed to register NVMEM device: %d\n" , |
177 | err); |
178 | return err; |
179 | } |
180 | |
181 | fuse->rst = devm_reset_control_get_optional(dev: &pdev->dev, id: "fuse" ); |
182 | if (IS_ERR(ptr: fuse->rst)) { |
183 | err = PTR_ERR(ptr: fuse->rst); |
184 | dev_err(&pdev->dev, "failed to get FUSE reset: %pe\n" , |
185 | fuse->rst); |
186 | return err; |
187 | } |
188 | |
189 | /* |
190 | * FUSE clock is enabled at a boot time, hence this resume/suspend |
191 | * disables the clock besides the h/w resetting. |
192 | */ |
193 | err = pm_runtime_resume_and_get(dev: &pdev->dev); |
194 | if (err) |
195 | return err; |
196 | |
197 | err = reset_control_reset(rstc: fuse->rst); |
198 | pm_runtime_put(dev: &pdev->dev); |
199 | |
200 | if (err < 0) { |
201 | dev_err(&pdev->dev, "failed to reset FUSE: %d\n" , err); |
202 | return err; |
203 | } |
204 | |
205 | /* release the early I/O memory mapping */ |
206 | iounmap(addr: base); |
207 | |
208 | return 0; |
209 | } |
210 | |
211 | static int __maybe_unused tegra_fuse_runtime_resume(struct device *dev) |
212 | { |
213 | int err; |
214 | |
215 | err = clk_prepare_enable(clk: fuse->clk); |
216 | if (err < 0) { |
217 | dev_err(dev, "failed to enable FUSE clock: %d\n" , err); |
218 | return err; |
219 | } |
220 | |
221 | return 0; |
222 | } |
223 | |
224 | static int __maybe_unused tegra_fuse_runtime_suspend(struct device *dev) |
225 | { |
226 | clk_disable_unprepare(clk: fuse->clk); |
227 | |
228 | return 0; |
229 | } |
230 | |
231 | static int __maybe_unused tegra_fuse_suspend(struct device *dev) |
232 | { |
233 | int ret; |
234 | |
235 | /* |
236 | * Critical for RAM re-repair operation, which must occur on resume |
237 | * from LP1 system suspend and as part of CCPLEX cluster switching. |
238 | */ |
239 | if (fuse->soc->clk_suspend_on) |
240 | ret = pm_runtime_resume_and_get(dev); |
241 | else |
242 | ret = pm_runtime_force_suspend(dev); |
243 | |
244 | return ret; |
245 | } |
246 | |
247 | static int __maybe_unused tegra_fuse_resume(struct device *dev) |
248 | { |
249 | int ret = 0; |
250 | |
251 | if (fuse->soc->clk_suspend_on) |
252 | pm_runtime_put(dev); |
253 | else |
254 | ret = pm_runtime_force_resume(dev); |
255 | |
256 | return ret; |
257 | } |
258 | |
259 | static const struct dev_pm_ops tegra_fuse_pm = { |
260 | SET_RUNTIME_PM_OPS(tegra_fuse_runtime_suspend, tegra_fuse_runtime_resume, |
261 | NULL) |
262 | SET_SYSTEM_SLEEP_PM_OPS(tegra_fuse_suspend, tegra_fuse_resume) |
263 | }; |
264 | |
265 | static struct platform_driver tegra_fuse_driver = { |
266 | .driver = { |
267 | .name = "tegra-fuse" , |
268 | .of_match_table = tegra_fuse_match, |
269 | .pm = &tegra_fuse_pm, |
270 | .suppress_bind_attrs = true, |
271 | }, |
272 | .probe = tegra_fuse_probe, |
273 | }; |
274 | builtin_platform_driver(tegra_fuse_driver); |
275 | |
276 | u32 __init tegra_fuse_read_spare(unsigned int spare) |
277 | { |
278 | unsigned int offset = fuse->soc->info->spare + spare * 4; |
279 | |
280 | return fuse->read_early(fuse, offset) & 1; |
281 | } |
282 | |
283 | u32 __init tegra_fuse_read_early(unsigned int offset) |
284 | { |
285 | return fuse->read_early(fuse, offset); |
286 | } |
287 | |
288 | int tegra_fuse_readl(unsigned long offset, u32 *value) |
289 | { |
290 | if (!fuse->read || !fuse->clk) |
291 | return -EPROBE_DEFER; |
292 | |
293 | if (IS_ERR(ptr: fuse->clk)) |
294 | return PTR_ERR(ptr: fuse->clk); |
295 | |
296 | *value = fuse->read(fuse, offset); |
297 | |
298 | return 0; |
299 | } |
300 | EXPORT_SYMBOL(tegra_fuse_readl); |
301 | |
302 | static void tegra_enable_fuse_clk(void __iomem *base) |
303 | { |
304 | u32 reg; |
305 | |
306 | reg = readl_relaxed(base + 0x48); |
307 | reg |= 1 << 28; |
308 | writel(val: reg, addr: base + 0x48); |
309 | |
310 | /* |
311 | * Enable FUSE clock. This needs to be hardcoded because the clock |
312 | * subsystem is not active during early boot. |
313 | */ |
314 | reg = readl(addr: base + 0x14); |
315 | reg |= 1 << 7; |
316 | writel(val: reg, addr: base + 0x14); |
317 | } |
318 | |
319 | static ssize_t major_show(struct device *dev, struct device_attribute *attr, |
320 | char *buf) |
321 | { |
322 | return sprintf(buf, fmt: "%d\n" , tegra_get_major_rev()); |
323 | } |
324 | |
325 | static DEVICE_ATTR_RO(major); |
326 | |
327 | static ssize_t minor_show(struct device *dev, struct device_attribute *attr, |
328 | char *buf) |
329 | { |
330 | return sprintf(buf, fmt: "%d\n" , tegra_get_minor_rev()); |
331 | } |
332 | |
333 | static DEVICE_ATTR_RO(minor); |
334 | |
335 | static struct attribute *tegra_soc_attr[] = { |
336 | &dev_attr_major.attr, |
337 | &dev_attr_minor.attr, |
338 | NULL, |
339 | }; |
340 | |
341 | const struct attribute_group tegra_soc_attr_group = { |
342 | .attrs = tegra_soc_attr, |
343 | }; |
344 | |
345 | #if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \ |
346 | IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) |
347 | static ssize_t platform_show(struct device *dev, struct device_attribute *attr, |
348 | char *buf) |
349 | { |
350 | /* |
351 | * Displays the value in the 'pre_si_platform' field of the HIDREV |
352 | * register for Tegra194 devices. A value of 0 indicates that the |
353 | * platform type is silicon and all other non-zero values indicate |
354 | * the type of simulation platform is being used. |
355 | */ |
356 | return sprintf(buf, "%d\n" , tegra_get_platform()); |
357 | } |
358 | |
359 | static DEVICE_ATTR_RO(platform); |
360 | |
361 | static struct attribute *tegra194_soc_attr[] = { |
362 | &dev_attr_major.attr, |
363 | &dev_attr_minor.attr, |
364 | &dev_attr_platform.attr, |
365 | NULL, |
366 | }; |
367 | |
368 | const struct attribute_group tegra194_soc_attr_group = { |
369 | .attrs = tegra194_soc_attr, |
370 | }; |
371 | #endif |
372 | |
373 | struct device * __init tegra_soc_device_register(void) |
374 | { |
375 | struct soc_device_attribute *attr; |
376 | struct soc_device *dev; |
377 | |
378 | attr = kzalloc(size: sizeof(*attr), GFP_KERNEL); |
379 | if (!attr) |
380 | return NULL; |
381 | |
382 | attr->family = kasprintf(GFP_KERNEL, fmt: "Tegra" ); |
383 | if (tegra_is_silicon()) |
384 | attr->revision = kasprintf(GFP_KERNEL, fmt: "%s %s" , |
385 | tegra_platform_name[tegra_sku_info.platform], |
386 | tegra_revision_name[tegra_sku_info.revision]); |
387 | else |
388 | attr->revision = kasprintf(GFP_KERNEL, fmt: "%s" , |
389 | tegra_platform_name[tegra_sku_info.platform]); |
390 | attr->soc_id = kasprintf(GFP_KERNEL, fmt: "%u" , tegra_get_chip_id()); |
391 | attr->custom_attr_group = fuse->soc->soc_attr_group; |
392 | |
393 | dev = soc_device_register(soc_plat_dev_attr: attr); |
394 | if (IS_ERR(ptr: dev)) { |
395 | kfree(objp: attr->soc_id); |
396 | kfree(objp: attr->revision); |
397 | kfree(objp: attr->family); |
398 | kfree(objp: attr); |
399 | return ERR_CAST(ptr: dev); |
400 | } |
401 | |
402 | return soc_device_to_device(soc: dev); |
403 | } |
404 | |
405 | static int __init tegra_init_fuse(void) |
406 | { |
407 | const struct of_device_id *match; |
408 | struct device_node *np; |
409 | struct resource regs; |
410 | |
411 | tegra_init_apbmisc(); |
412 | |
413 | np = of_find_matching_node_and_match(NULL, matches: tegra_fuse_match, match: &match); |
414 | if (!np) { |
415 | /* |
416 | * Fall back to legacy initialization for 32-bit ARM only. All |
417 | * 64-bit ARM device tree files for Tegra are required to have |
418 | * a FUSE node. |
419 | * |
420 | * This is for backwards-compatibility with old device trees |
421 | * that didn't contain a FUSE node. |
422 | */ |
423 | if (IS_ENABLED(CONFIG_ARM) && soc_is_tegra()) { |
424 | u8 chip = tegra_get_chip_id(); |
425 | |
426 | regs.start = 0x7000f800; |
427 | regs.end = 0x7000fbff; |
428 | regs.flags = IORESOURCE_MEM; |
429 | |
430 | switch (chip) { |
431 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC |
432 | case TEGRA20: |
433 | fuse->soc = &tegra20_fuse_soc; |
434 | break; |
435 | #endif |
436 | |
437 | #ifdef CONFIG_ARCH_TEGRA_3x_SOC |
438 | case TEGRA30: |
439 | fuse->soc = &tegra30_fuse_soc; |
440 | break; |
441 | #endif |
442 | |
443 | #ifdef CONFIG_ARCH_TEGRA_114_SOC |
444 | case TEGRA114: |
445 | fuse->soc = &tegra114_fuse_soc; |
446 | break; |
447 | #endif |
448 | |
449 | #ifdef CONFIG_ARCH_TEGRA_124_SOC |
450 | case TEGRA124: |
451 | fuse->soc = &tegra124_fuse_soc; |
452 | break; |
453 | #endif |
454 | |
455 | default: |
456 | pr_warn("Unsupported SoC: %02x\n" , chip); |
457 | break; |
458 | } |
459 | } else { |
460 | /* |
461 | * At this point we're not running on Tegra, so play |
462 | * nice with multi-platform kernels. |
463 | */ |
464 | return 0; |
465 | } |
466 | } else { |
467 | /* |
468 | * Extract information from the device tree if we've found a |
469 | * matching node. |
470 | */ |
471 | if (of_address_to_resource(dev: np, index: 0, r: ®s) < 0) { |
472 | pr_err("failed to get FUSE register\n" ); |
473 | return -ENXIO; |
474 | } |
475 | |
476 | fuse->soc = match->data; |
477 | } |
478 | |
479 | np = of_find_matching_node(NULL, matches: car_match); |
480 | if (np) { |
481 | void __iomem *base = of_iomap(node: np, index: 0); |
482 | of_node_put(node: np); |
483 | if (base) { |
484 | tegra_enable_fuse_clk(base); |
485 | iounmap(addr: base); |
486 | } else { |
487 | pr_err("failed to map clock registers\n" ); |
488 | return -ENXIO; |
489 | } |
490 | } |
491 | |
492 | fuse->base = ioremap(offset: regs.start, size: resource_size(res: ®s)); |
493 | if (!fuse->base) { |
494 | pr_err("failed to map FUSE registers\n" ); |
495 | return -ENXIO; |
496 | } |
497 | |
498 | fuse->soc->init(fuse); |
499 | |
500 | pr_info("Tegra Revision: %s SKU: %d CPU Process: %d SoC Process: %d\n" , |
501 | tegra_revision_name[tegra_sku_info.revision], |
502 | tegra_sku_info.sku_id, tegra_sku_info.cpu_process_id, |
503 | tegra_sku_info.soc_process_id); |
504 | pr_debug("Tegra CPU Speedo ID %d, SoC Speedo ID %d\n" , |
505 | tegra_sku_info.cpu_speedo_id, tegra_sku_info.soc_speedo_id); |
506 | |
507 | if (fuse->soc->lookups) { |
508 | size_t size = sizeof(*fuse->lookups) * fuse->soc->num_lookups; |
509 | |
510 | fuse->lookups = kmemdup(p: fuse->soc->lookups, size, GFP_KERNEL); |
511 | if (fuse->lookups) |
512 | nvmem_add_cell_lookups(entries: fuse->lookups, nentries: fuse->soc->num_lookups); |
513 | } |
514 | |
515 | return 0; |
516 | } |
517 | early_initcall(tegra_init_fuse); |
518 | |
519 | #ifdef CONFIG_ARM64 |
520 | static int __init tegra_init_soc(void) |
521 | { |
522 | struct device_node *np; |
523 | struct device *soc; |
524 | |
525 | /* make sure we're running on Tegra */ |
526 | np = of_find_matching_node(NULL, tegra_fuse_match); |
527 | if (!np) |
528 | return 0; |
529 | |
530 | of_node_put(np); |
531 | |
532 | soc = tegra_soc_device_register(); |
533 | if (IS_ERR(soc)) { |
534 | pr_err("failed to register SoC device: %ld\n" , PTR_ERR(soc)); |
535 | return PTR_ERR(soc); |
536 | } |
537 | |
538 | return 0; |
539 | } |
540 | device_initcall(tegra_init_soc); |
541 | #endif |
542 | |