hc
2024-05-14 bedbef8ad3e75a304af6361af235302bcc61d06b
kernel/drivers/soc/tegra/fuse/fuse-tegra.c
....@@ -1,18 +1,6 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
3
- *
4
- * This program is free software; you can redistribute it and/or modify it
5
- * under the terms and conditions of the GNU General Public License,
6
- * version 2, as published by the Free Software Foundation.
7
- *
8
- * This program is distributed in the hope it will be useful, but WITHOUT
9
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11
- * more details.
12
- *
13
- * You should have received a copy of the GNU General Public License
14
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
15
- *
164 */
175
186 #include <linux/clk.h>
....@@ -20,6 +8,8 @@
208 #include <linux/kobject.h>
219 #include <linux/init.h>
2210 #include <linux/io.h>
11
+#include <linux/nvmem-consumer.h>
12
+#include <linux/nvmem-provider.h>
2313 #include <linux/of.h>
2414 #include <linux/of_address.h>
2515 #include <linux/platform_device.h>
....@@ -43,50 +33,6 @@
4333 [TEGRA_REVISION_A04] = "A04",
4434 };
4535
46
-static u8 fuse_readb(struct tegra_fuse *fuse, unsigned int offset)
47
-{
48
- u32 val;
49
-
50
- val = fuse->read(fuse, round_down(offset, 4));
51
- val >>= (offset % 4) * 8;
52
- val &= 0xff;
53
-
54
- return val;
55
-}
56
-
57
-static ssize_t fuse_read(struct file *fd, struct kobject *kobj,
58
- struct bin_attribute *attr, char *buf,
59
- loff_t pos, size_t size)
60
-{
61
- struct device *dev = kobj_to_dev(kobj);
62
- struct tegra_fuse *fuse = dev_get_drvdata(dev);
63
- int i;
64
-
65
- if (pos < 0 || pos >= attr->size)
66
- return 0;
67
-
68
- if (size > attr->size - pos)
69
- size = attr->size - pos;
70
-
71
- for (i = 0; i < size; i++)
72
- buf[i] = fuse_readb(fuse, pos + i);
73
-
74
- return i;
75
-}
76
-
77
-static struct bin_attribute fuse_bin_attr = {
78
- .attr = { .name = "fuse", .mode = S_IRUGO, },
79
- .read = fuse_read,
80
-};
81
-
82
-static int tegra_fuse_create_sysfs(struct device *dev, unsigned int size,
83
- const struct tegra_fuse_info *info)
84
-{
85
- fuse_bin_attr.size = size;
86
-
87
- return device_create_bin_file(dev, &fuse_bin_attr);
88
-}
89
-
9036 static const struct of_device_id car_match[] __initconst = {
9137 { .compatible = "nvidia,tegra20-car", },
9238 { .compatible = "nvidia,tegra30-car", },
....@@ -103,6 +49,12 @@
10349 };
10450
10551 static const struct of_device_id tegra_fuse_match[] = {
52
+#ifdef CONFIG_ARCH_TEGRA_234_SOC
53
+ { .compatible = "nvidia,tegra234-efuse", .data = &tegra234_fuse_soc },
54
+#endif
55
+#ifdef CONFIG_ARCH_TEGRA_194_SOC
56
+ { .compatible = "nvidia,tegra194-efuse", .data = &tegra194_fuse_soc },
57
+#endif
10658 #ifdef CONFIG_ARCH_TEGRA_186_SOC
10759 { .compatible = "nvidia,tegra186-efuse", .data = &tegra186_fuse_soc },
10860 #endif
....@@ -127,9 +79,111 @@
12779 { /* sentinel */ }
12880 };
12981
82
+static int tegra_fuse_read(void *priv, unsigned int offset, void *value,
83
+ size_t bytes)
84
+{
85
+ unsigned int count = bytes / 4, i;
86
+ struct tegra_fuse *fuse = priv;
87
+ u32 *buffer = value;
88
+
89
+ for (i = 0; i < count; i++)
90
+ buffer[i] = fuse->read(fuse, offset + i * 4);
91
+
92
+ return 0;
93
+}
94
+
95
+static const struct nvmem_cell_info tegra_fuse_cells[] = {
96
+ {
97
+ .name = "tsensor-cpu1",
98
+ .offset = 0x084,
99
+ .bytes = 4,
100
+ .bit_offset = 0,
101
+ .nbits = 32,
102
+ }, {
103
+ .name = "tsensor-cpu2",
104
+ .offset = 0x088,
105
+ .bytes = 4,
106
+ .bit_offset = 0,
107
+ .nbits = 32,
108
+ }, {
109
+ .name = "tsensor-cpu0",
110
+ .offset = 0x098,
111
+ .bytes = 4,
112
+ .bit_offset = 0,
113
+ .nbits = 32,
114
+ }, {
115
+ .name = "xusb-pad-calibration",
116
+ .offset = 0x0f0,
117
+ .bytes = 4,
118
+ .bit_offset = 0,
119
+ .nbits = 32,
120
+ }, {
121
+ .name = "tsensor-cpu3",
122
+ .offset = 0x12c,
123
+ .bytes = 4,
124
+ .bit_offset = 0,
125
+ .nbits = 32,
126
+ }, {
127
+ .name = "sata-calibration",
128
+ .offset = 0x124,
129
+ .bytes = 1,
130
+ .bit_offset = 0,
131
+ .nbits = 2,
132
+ }, {
133
+ .name = "tsensor-gpu",
134
+ .offset = 0x154,
135
+ .bytes = 4,
136
+ .bit_offset = 0,
137
+ .nbits = 32,
138
+ }, {
139
+ .name = "tsensor-mem0",
140
+ .offset = 0x158,
141
+ .bytes = 4,
142
+ .bit_offset = 0,
143
+ .nbits = 32,
144
+ }, {
145
+ .name = "tsensor-mem1",
146
+ .offset = 0x15c,
147
+ .bytes = 4,
148
+ .bit_offset = 0,
149
+ .nbits = 32,
150
+ }, {
151
+ .name = "tsensor-pllx",
152
+ .offset = 0x160,
153
+ .bytes = 4,
154
+ .bit_offset = 0,
155
+ .nbits = 32,
156
+ }, {
157
+ .name = "tsensor-common",
158
+ .offset = 0x180,
159
+ .bytes = 4,
160
+ .bit_offset = 0,
161
+ .nbits = 32,
162
+ }, {
163
+ .name = "tsensor-realignment",
164
+ .offset = 0x1fc,
165
+ .bytes = 4,
166
+ .bit_offset = 0,
167
+ .nbits = 32,
168
+ }, {
169
+ .name = "gpu-calibration",
170
+ .offset = 0x204,
171
+ .bytes = 4,
172
+ .bit_offset = 0,
173
+ .nbits = 32,
174
+ }, {
175
+ .name = "xusb-pad-calibration-ext",
176
+ .offset = 0x250,
177
+ .bytes = 4,
178
+ .bit_offset = 0,
179
+ .nbits = 32,
180
+ },
181
+};
182
+
130183 static int tegra_fuse_probe(struct platform_device *pdev)
131184 {
132185 void __iomem *base = fuse->base;
186
+ struct nvmem_config nvmem;
133187 struct resource *res;
134188 int err;
135189
....@@ -145,8 +199,10 @@
145199
146200 fuse->clk = devm_clk_get(&pdev->dev, "fuse");
147201 if (IS_ERR(fuse->clk)) {
148
- dev_err(&pdev->dev, "failed to get FUSE clock: %ld",
149
- PTR_ERR(fuse->clk));
202
+ if (PTR_ERR(fuse->clk) != -EPROBE_DEFER)
203
+ dev_err(&pdev->dev, "failed to get FUSE clock: %ld",
204
+ PTR_ERR(fuse->clk));
205
+
150206 fuse->base = base;
151207 return PTR_ERR(fuse->clk);
152208 }
....@@ -156,20 +212,42 @@
156212
157213 if (fuse->soc->probe) {
158214 err = fuse->soc->probe(fuse);
159
- if (err < 0) {
160
- fuse->base = base;
161
- return err;
162
- }
215
+ if (err < 0)
216
+ goto restore;
163217 }
164218
165
- if (tegra_fuse_create_sysfs(&pdev->dev, fuse->soc->info->size,
166
- fuse->soc->info))
167
- return -ENODEV;
219
+ memset(&nvmem, 0, sizeof(nvmem));
220
+ nvmem.dev = &pdev->dev;
221
+ nvmem.name = "fuse";
222
+ nvmem.id = -1;
223
+ nvmem.owner = THIS_MODULE;
224
+ nvmem.cells = tegra_fuse_cells;
225
+ nvmem.ncells = ARRAY_SIZE(tegra_fuse_cells);
226
+ nvmem.type = NVMEM_TYPE_OTP;
227
+ nvmem.read_only = true;
228
+ nvmem.root_only = true;
229
+ nvmem.reg_read = tegra_fuse_read;
230
+ nvmem.size = fuse->soc->info->size;
231
+ nvmem.word_size = 4;
232
+ nvmem.stride = 4;
233
+ nvmem.priv = fuse;
234
+
235
+ fuse->nvmem = devm_nvmem_register(&pdev->dev, &nvmem);
236
+ if (IS_ERR(fuse->nvmem)) {
237
+ err = PTR_ERR(fuse->nvmem);
238
+ dev_err(&pdev->dev, "failed to register NVMEM device: %d\n",
239
+ err);
240
+ goto restore;
241
+ }
168242
169243 /* release the early I/O memory mapping */
170244 iounmap(base);
171245
172246 return 0;
247
+
248
+restore:
249
+ fuse->base = base;
250
+ return err;
173251 }
174252
175253 static struct platform_driver tegra_fuse_driver = {
....@@ -196,8 +274,11 @@
196274
197275 int tegra_fuse_readl(unsigned long offset, u32 *value)
198276 {
199
- if (!fuse->read)
277
+ if (!fuse->read || !fuse->clk)
200278 return -EPROBE_DEFER;
279
+
280
+ if (IS_ERR(fuse->clk))
281
+ return PTR_ERR(fuse->clk);
201282
202283 *value = fuse->read(fuse, offset);
203284
....@@ -222,6 +303,60 @@
222303 writel(reg, base + 0x14);
223304 }
224305
306
+static ssize_t major_show(struct device *dev, struct device_attribute *attr,
307
+ char *buf)
308
+{
309
+ return sprintf(buf, "%d\n", tegra_get_major_rev());
310
+}
311
+
312
+static DEVICE_ATTR_RO(major);
313
+
314
+static ssize_t minor_show(struct device *dev, struct device_attribute *attr,
315
+ char *buf)
316
+{
317
+ return sprintf(buf, "%d\n", tegra_get_minor_rev());
318
+}
319
+
320
+static DEVICE_ATTR_RO(minor);
321
+
322
+static struct attribute *tegra_soc_attr[] = {
323
+ &dev_attr_major.attr,
324
+ &dev_attr_minor.attr,
325
+ NULL,
326
+};
327
+
328
+const struct attribute_group tegra_soc_attr_group = {
329
+ .attrs = tegra_soc_attr,
330
+};
331
+
332
+#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
333
+ IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
334
+static ssize_t platform_show(struct device *dev, struct device_attribute *attr,
335
+ char *buf)
336
+{
337
+ /*
338
+ * Displays the value in the 'pre_si_platform' field of the HIDREV
339
+ * register for Tegra194 devices. A value of 0 indicates that the
340
+ * platform type is silicon and all other non-zero values indicate
341
+ * the type of simulation platform is being used.
342
+ */
343
+ return sprintf(buf, "%d\n", tegra_get_platform());
344
+}
345
+
346
+static DEVICE_ATTR_RO(platform);
347
+
348
+static struct attribute *tegra194_soc_attr[] = {
349
+ &dev_attr_major.attr,
350
+ &dev_attr_minor.attr,
351
+ &dev_attr_platform.attr,
352
+ NULL,
353
+};
354
+
355
+const struct attribute_group tegra194_soc_attr_group = {
356
+ .attrs = tegra194_soc_attr,
357
+};
358
+#endif
359
+
225360 struct device * __init tegra_soc_device_register(void)
226361 {
227362 struct soc_device_attribute *attr;
....@@ -232,8 +367,10 @@
232367 return NULL;
233368
234369 attr->family = kasprintf(GFP_KERNEL, "Tegra");
235
- attr->revision = kasprintf(GFP_KERNEL, "%d", tegra_sku_info.revision);
370
+ attr->revision = kasprintf(GFP_KERNEL, "%s",
371
+ tegra_revision_name[tegra_sku_info.revision]);
236372 attr->soc_id = kasprintf(GFP_KERNEL, "%u", tegra_get_chip_id());
373
+ attr->custom_attr_group = fuse->soc->soc_attr_group;
237374
238375 dev = soc_device_register(attr);
239376 if (IS_ERR(dev)) {
....@@ -333,7 +470,7 @@
333470 }
334471 }
335472
336
- fuse->base = ioremap_nocache(regs.start, resource_size(&regs));
473
+ fuse->base = ioremap(regs.start, resource_size(&regs));
337474 if (!fuse->base) {
338475 pr_err("failed to map FUSE registers\n");
339476 return -ENXIO;
....@@ -348,6 +485,15 @@
348485 pr_debug("Tegra CPU Speedo ID %d, SoC Speedo ID %d\n",
349486 tegra_sku_info.cpu_speedo_id, tegra_sku_info.soc_speedo_id);
350487
488
+ if (fuse->soc->lookups) {
489
+ size_t size = sizeof(*fuse->lookups) * fuse->soc->num_lookups;
490
+
491
+ fuse->lookups = kmemdup(fuse->soc->lookups, size, GFP_KERNEL);
492
+ if (!fuse->lookups)
493
+ return -ENOMEM;
494
+
495
+ nvmem_add_cell_lookups(fuse->lookups, fuse->soc->num_lookups);
496
+ }
351497
352498 return 0;
353499 }