NVIDIA: SAUCE: nvmem: Add Tegra efuse driver

Add Tegra efuse driver.

Signed-off-by: Kartik <kkartik@nvidia.com>
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Acked-by: Noah Wager <noah.wager@canonical.com>
Acked-by: Jacob Martin <jacob.martin@canonical.com>
Signed-off-by: Noah Wager <noah.wager@canonical.com>
This commit is contained in:
Kartik
2024-09-15 08:20:00 +00:00
committed by Noah Wager
parent 9324fc230d
commit a18340ea37
10 changed files with 610 additions and 132 deletions
+2
View File
@@ -83,3 +83,5 @@ obj-$(CONFIG_NVMEM_ZYNQMP) += nvmem_zynqmp_nvmem.o
nvmem_zynqmp_nvmem-y := zynqmp_nvmem.o
obj-$(CONFIG_NVMEM_QORIQ_EFUSE) += nvmem-qoriq-efuse.o
nvmem-qoriq-efuse-y := qoriq-efuse.o
obj-y += nvmem-tegra-efuse.o
nvmem-tegra-efuse-y := tegra-efuse.o
+334
View File
@@ -0,0 +1,334 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013-2023, NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/device.h>
#include <linux/io.h>
#include <linux/nvmem-consumer.h>
#include <linux/nvmem-provider.h>
#include <linux/of.h>
#include <linux/platform_device.h>
struct tegra_efuse_soc {
int size;
const struct nvmem_cell_lookup *lookups;
unsigned int num_lookups;
const struct nvmem_cell_info *cells;
unsigned int num_cells;
const struct nvmem_keepout *keepouts;
unsigned int num_keepouts;
};
struct tegra_efuse {
void __iomem *base;
struct nvmem_device *nvmem;
const struct tegra_efuse_soc *soc;
};
static int tegra_efuse_readl(struct tegra_efuse *efuse, unsigned int offset)
{
return readl_relaxed(efuse->base + offset);
}
static int tegra_efuse_read(void *priv, unsigned int offset, void *value, size_t bytes)
{
unsigned int count = bytes / 4, i;
struct tegra_efuse *efuse = priv;
u32 *buffer = value;
for (i = 0; i < count; i++)
buffer[i] = tegra_efuse_readl(efuse, offset + i * 4);
return 0;
}
static int tegra_efuse_probe(struct platform_device *pdev)
{
struct tegra_efuse *efuse;
struct nvmem_config nvmem;
struct resource *res;
int id;
id = of_alias_get_id(pdev->dev.of_node, "efuse");
if (id < 0)
return dev_err_probe(&pdev->dev, id, "failed to get alias id\n");
efuse = devm_kzalloc(&pdev->dev, sizeof(*efuse), GFP_KERNEL);
if (!efuse)
return -ENOMEM;
efuse->soc = device_get_match_data(&pdev->dev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
efuse->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(efuse->base))
return PTR_ERR(efuse->base);
platform_set_drvdata(pdev, efuse);
memset(&nvmem, 0, sizeof(nvmem));
nvmem.name = "efuse";
nvmem.dev = &pdev->dev;
nvmem.id = id;
nvmem.owner = THIS_MODULE;
nvmem.cells = efuse->soc->cells;
nvmem.ncells = efuse->soc->num_cells;
nvmem.keepout = efuse->soc->keepouts;
nvmem.nkeepout = efuse->soc->num_keepouts;
nvmem.type = NVMEM_TYPE_OTP;
nvmem.read_only = true;
nvmem.root_only = false;
nvmem.reg_read = tegra_efuse_read;
nvmem.size = efuse->soc->size;
nvmem.word_size = 4;
nvmem.stride = 4;
nvmem.priv = efuse;
efuse->nvmem = devm_nvmem_register(&pdev->dev, &nvmem);
if (IS_ERR(efuse->nvmem))
return dev_err_probe(&pdev->dev, PTR_ERR(efuse->nvmem),
"failed to register NVMEM device\n");
return 0;
}
static int tegra_efuse_remove(struct platform_device *pdev)
{
return 0;
}
static const struct nvmem_cell_info tegra264_efuse_cells[] = {
{
.name = "tsensor-cpu1",
.offset = 0x084,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
},
};
static const struct nvmem_cell_lookup tegra264_efuse_lookups[] = {
/* Sample Node */
{
.nvmem_name = "efuse0",
.cell_name = "tensor-cpu1",
.dev_id = "700e2000.thermal-sensor",
.con_id = "cpu1",
},
};
static const struct nvmem_keepout tegra264_efuse_keepouts[] = {
{ .start = 0x00038, .end = 0x00050 },
{ .start = 0x00054, .end = 0x0005c },
{ .start = 0x00060, .end = 0x00064 },
{ .start = 0x00080, .end = 0x00088 },
{ .start = 0x000a4, .end = 0x00100 },
{ .start = 0x0042c, .end = 0x00434 },
{ .start = 0x00450, .end = 0x00454 },
{ .start = 0x00594, .end = 0x0059c },
{ .start = 0x0088c, .end = 0x00890 },
{ .start = 0x008a0, .end = 0x008a8 },
{ .start = 0x008dc, .end = 0x008e4 },
{ .start = 0x009d8, .end = 0x009dc },
{ .start = 0x00a6c, .end = 0x00a70 },
{ .start = 0x00a74, .end = 0x00a7c },
{ .start = 0x00af4, .end = 0x00af8 },
{ .start = 0x00b14, .end = 0x00b20 },
{ .start = 0x00b44, .end = 0x00b4c },
{ .start = 0x00b50, .end = 0x00b58 },
{ .start = 0x00b5c, .end = 0x00b64 },
{ .start = 0x00b68, .end = 0x00b70 },
{ .start = 0x00bcc, .end = 0x00bd0 },
{ .start = 0x00c0c, .end = 0x00c18 },
{ .start = 0x00d80, .end = 0x00d8c },
{ .start = 0x00eac, .end = 0x00eb4 },
{ .start = 0x00eb8, .end = 0x00ebc },
{ .start = 0x00f0c, .end = 0x00f10 },
{ .start = 0x010d0, .end = 0x02000 },
{ .start = 0x0201c, .end = 0x10164 },
{ .start = 0x10184, .end = 0x101a0 },
{ .start = 0x101a4, .end = 0x1029c },
{ .start = 0x102a0, .end = 0x102cc },
{ .start = 0x102d0, .end = 0x10408 },
{ .start = 0x10410, .end = 0x1065c },
{ .start = 0x1067c, .end = 0x107b0 },
{ .start = 0x107b4, .end = 0x11108 },
{ .start = 0x1110c, .end = 0x11118 },
{ .start = 0x11120, .end = 0x111b8 },
{ .start = 0x111c4, .end = 0x111c8 },
{ .start = 0x111e8, .end = 0x111ec },
{ .start = 0x111f0, .end = 0x11224 },
{ .start = 0x11228, .end = 0x11268 },
{ .start = 0x1126c, .end = 0x112b8 },
{ .start = 0x112bc, .end = 0x112e4 },
{ .start = 0x112e8, .end = 0x112ec },
{ .start = 0x112f0, .end = 0x1131c },
{ .start = 0x11350, .end = 0x1143c },
{ .start = 0x11440, .end = 0x114c8 },
{ .start = 0x114d0, .end = 0x11520 },
{ .start = 0x11530, .end = 0x11540 },
{ .start = 0x11544, .end = 0x11568 },
{ .start = 0x1156c, .end = 0x115a8 },
{ .start = 0x115ac, .end = 0x116cc },
{ .start = 0x116d0, .end = 0x116dc },
{ .start = 0x116e0, .end = 0x117b4 },
{ .start = 0x117bc, .end = 0x11840 },
{ .start = 0x11844, .end = 0x118b8 },
{ .start = 0x118bc, .end = 0x11910 },
{ .start = 0x11914, .end = 0x11950 },
{ .start = 0x11958, .end = 0x119a0 },
{ .start = 0x119ac, .end = 0x11c48 },
{ .start = 0x11c50, .end = 0x11c5c },
{ .start = 0x11c60, .end = 0x11cf8 },
{ .start = 0x11cfc, .end = 0x11d18 },
{ .start = 0x11d40, .end = 0x12100 },
{ .start = 0x12104, .end = 0x12110 },
{ .start = 0x12114, .end = 0x121fc },
{ .start = 0x1221c, .end = 0x12220 },
{ .start = 0x12224, .end = 0x12244 },
{ .start = 0x1224c, .end = 0x12400 },
{ .start = 0x12408, .end = 0x1246c },
{ .start = 0x12470, .end = 0x127ac },
{ .start = 0x127b0, .end = 0x12d60 },
{ .start = 0x12d64, .end = 0x12e94 },
{ .start = 0x12ea4, .end = 0x13104 },
{ .start = 0x13108, .end = 0x1310c },
{ .start = 0x13110, .end = 0x13114 },
{ .start = 0x13118, .end = 0x13120 },
{ .start = 0x13164, .end = 0x13184 },
{ .start = 0x131a0, .end = 0x131a4 },
{ .start = 0x131b8, .end = 0x131c4 },
{ .start = 0x131c8, .end = 0x131e8 },
{ .start = 0x131ec, .end = 0x131f0 },
{ .start = 0x131fc, .end = 0x1321c },
{ .start = 0x13220, .end = 0x13228 },
{ .start = 0x13244, .end = 0x1324c },
{ .start = 0x13268, .end = 0x1326c },
{ .start = 0x1329c, .end = 0x132a0 },
{ .start = 0x132ac, .end = 0x132c0 },
{ .start = 0x132cc, .end = 0x132d0 },
{ .start = 0x132e4, .end = 0x132e8 },
{ .start = 0x132ec, .end = 0x132f0 },
{ .start = 0x1331c, .end = 0x13350 },
{ .start = 0x133f0, .end = 0x13410 },
{ .start = 0x1342c, .end = 0x13434 },
{ .start = 0x1343c, .end = 0x13444 },
{ .start = 0x13450, .end = 0x13454 },
{ .start = 0x1346c, .end = 0x13470 },
{ .start = 0x134ac, .end = 0x134b0 },
{ .start = 0x134c8, .end = 0x134d0 },
{ .start = 0x13520, .end = 0x13530 },
{ .start = 0x13540, .end = 0x13544 },
{ .start = 0x13568, .end = 0x13570 },
{ .start = 0x13594, .end = 0x1359c },
{ .start = 0x135a8, .end = 0x135ac },
{ .start = 0x13644, .end = 0x1364c },
{ .start = 0x1365c, .end = 0x1367c },
{ .start = 0x136cc, .end = 0x136e0 },
{ .start = 0x136e4, .end = 0x13708 },
{ .start = 0x1370c, .end = 0x13720 },
{ .start = 0x137ac, .end = 0x137bc },
{ .start = 0x137c0, .end = 0x137c8 },
{ .start = 0x13814, .end = 0x13818 },
{ .start = 0x13824, .end = 0x13828 },
{ .start = 0x1382c, .end = 0x13830 },
{ .start = 0x13834, .end = 0x1383c },
{ .start = 0x13840, .end = 0x13844 },
{ .start = 0x13854, .end = 0x13858 },
{ .start = 0x13860, .end = 0x13884 },
{ .start = 0x1388c, .end = 0x13890 },
{ .start = 0x138a0, .end = 0x138a8 },
{ .start = 0x138b8, .end = 0x138bc },
{ .start = 0x138dc, .end = 0x138e4 },
{ .start = 0x138ec, .end = 0x138f0 },
{ .start = 0x13900, .end = 0x13918 },
{ .start = 0x13920, .end = 0x13928 },
{ .start = 0x13930, .end = 0x13958 },
{ .start = 0x139a0, .end = 0x139b0 },
{ .start = 0x139d0, .end = 0x139dc },
{ .start = 0x13a6c, .end = 0x13a70 },
{ .start = 0x13a74, .end = 0x13a7c },
{ .start = 0x13af4, .end = 0x13af8 },
{ .start = 0x13b14, .end = 0x13b20 },
{ .start = 0x13b44, .end = 0x13b4c },
{ .start = 0x13b50, .end = 0x13b58 },
{ .start = 0x13b5c, .end = 0x13b64 },
{ .start = 0x13b68, .end = 0x13b70 },
{ .start = 0x13bcc, .end = 0x13bd8 },
{ .start = 0x13c0c, .end = 0x13c18 },
{ .start = 0x13c48, .end = 0x13c50 },
{ .start = 0x13c5c, .end = 0x13c60 },
{ .start = 0x13cf8, .end = 0x13cfc },
{ .start = 0x13d18, .end = 0x13d40 },
{ .start = 0x13d60, .end = 0x13d64 },
{ .start = 0x13d74, .end = 0x13d8c },
{ .start = 0x13e94, .end = 0x13ea4 },
{ .start = 0x13eac, .end = 0x13eb4 },
{ .start = 0x13eb8, .end = 0x13ebc },
{ .start = 0x13ef4, .end = 0x13f04 },
{ .start = 0x13f0c, .end = 0x13f10 },
{ .start = 0x13fb8, .end = 0x1470c },
{ .start = 0x14720, .end = 0x147c0 },
{ .start = 0x147c8, .end = 0x14824 },
{ .start = 0x14828, .end = 0x1482c },
{ .start = 0x14830, .end = 0x14834 },
{ .start = 0x1483c, .end = 0x14870 },
{ .start = 0x14874, .end = 0x148ec },
{ .start = 0x148f0, .end = 0x14900 },
{ .start = 0x14910, .end = 0x14914 },
{ .start = 0x14918, .end = 0x149ac },
{ .start = 0x149b0, .end = 0x14bd0 },
{ .start = 0x14bd8, .end = 0x152bc },
{ .start = 0x152c0, .end = 0x156d4 },
{ .start = 0x156d8, .end = 0x15814 },
{ .start = 0x15818, .end = 0x15860 },
{ .start = 0x15870, .end = 0x15920 },
{ .start = 0x15924, .end = 0x15930 },
{ .start = 0x15940, .end = 0x159d0 },
{ .start = 0x159d8, .end = 0x15d74 },
{ .start = 0x15d80, .end = 0x15ef4 },
{ .start = 0x15efc, .end = 0x162ac },
{ .start = 0x162b8, .end = 0x166d0 },
{ .start = 0x166d4, .end = 0x166d8 },
{ .start = 0x166dc, .end = 0x166e4 },
{ .start = 0x166ec, .end = 0x16854 },
{ .start = 0x16858, .end = 0x16874 },
{ .start = 0x16884, .end = 0x16924 },
{ .start = 0x16928, .end = 0x16940 },
{ .start = 0x16950, .end = 0x16efc },
{ .start = 0x16f04, .end = 0x17000 },
{ .start = 0x17008, .end = 0x1f000 },
{ .start = 0x1f010, .end = 0x1f014 },
{ .start = 0x1f024, .end = 0x1f030 },
{ .start = 0x1f04c, .end = 0x1f050 },
};
static const struct tegra_efuse_soc tegra264_efuse_soc = {
.cells = tegra264_efuse_cells,
.num_cells = ARRAY_SIZE(tegra264_efuse_cells),
.lookups = tegra264_efuse_lookups,
.num_lookups = ARRAY_SIZE(tegra264_efuse_lookups),
.keepouts = tegra264_efuse_keepouts,
.num_keepouts = ARRAY_SIZE(tegra264_efuse_keepouts),
.size = 0x1f094,
};
static const struct of_device_id tegra_efuse_of_match[] = {
{ .compatible = "nvidia,tegra264-efuse", .data = &tegra264_efuse_soc },
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, tegra_efuse_of_match);
static struct platform_driver tegra_efuse_driver = {
.driver = {
.name = "tegra-efuse",
.of_match_table = tegra_efuse_of_match,
},
.probe = tegra_efuse_probe,
.remove = tegra_efuse_remove,
};
module_platform_driver(tegra_efuse_driver);
MODULE_LICENSE("GPL v2");
+1
View File
@@ -3,6 +3,7 @@ obj-y += fuse/
obj-y += cbb/
obj-y += common.o
obj-y += tegra-soc.o
obj-$(CONFIG_SOC_TEGRA_FLOWCTRL) += flowctrl.o
obj-$(CONFIG_SOC_TEGRA_PMC) += pmc.o
obj-$(CONFIG_SOC_TEGRA_PMC) += tegra264-pmc.o
+2
View File
@@ -22,6 +22,8 @@ static const struct of_device_id tegra_machine_match[] = {
{ .compatible = "nvidia,tegra124", },
{ .compatible = "nvidia,tegra132", },
{ .compatible = "nvidia,tegra210", },
{ .compatible = "nvidia,tegra234", },
{ .compatible = "nvidia,tegra264", },
{ }
};
+1
View File
@@ -2,6 +2,7 @@
obj-y += fuse-tegra.o
obj-y += fuse-tegra30.o
obj-y += tegra-apbmisc.o
obj-y += tegra-efuse-nvmem-helper.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += fuse-tegra20.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += speedo-tegra20.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += speedo-tegra30.o
+3 -123
View File
@@ -35,19 +35,6 @@ static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
[TEGRA_REVISION_A04] = "A04",
};
static const char *tegra_platform_name[TEGRA_PLATFORM_MAX] = {
[TEGRA_PLATFORM_SILICON] = "Silicon",
[TEGRA_PLATFORM_QT] = "QT",
[TEGRA_PLATFORM_SYSTEM_FPGA] = "System FPGA",
[TEGRA_PLATFORM_UNIT_FPGA] = "Unit FPGA",
[TEGRA_PLATFORM_ASIM_QT] = "Asim QT",
[TEGRA_PLATFORM_ASIM_LINSIM] = "Asim Linsim",
[TEGRA_PLATFORM_DSIM_ASIM_LINSIM] = "Dsim Asim Linsim",
[TEGRA_PLATFORM_VERIFICATION_SIMULATION] = "Verification Simulation",
[TEGRA_PLATFORM_VDK] = "VDK",
[TEGRA_PLATFORM_VSP] = "VSP",
};
static const struct of_device_id car_match[] __initconst = {
{ .compatible = "nvidia,tegra20-car", },
{ .compatible = "nvidia,tegra30-car", },
@@ -278,6 +265,9 @@ u32 __init tegra_fuse_read_early(unsigned int offset)
int tegra_fuse_readl(unsigned long offset, u32 *value)
{
if (tegra_get_chip_id() == TEGRA264)
return tegra_efuse_nvmem_readl(offset + 0x100, value);
if (!fuse->read || !fuse->clk)
return -EPROBE_DEFER;
@@ -307,92 +297,6 @@ static void tegra_enable_fuse_clk(void __iomem *base)
writel(reg, base + 0x14);
}
static ssize_t major_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%d\n", tegra_get_major_rev());
}
static DEVICE_ATTR_RO(major);
static ssize_t minor_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%d\n", tegra_get_minor_rev());
}
static DEVICE_ATTR_RO(minor);
static struct attribute *tegra_soc_attr[] = {
&dev_attr_major.attr,
&dev_attr_minor.attr,
NULL,
};
const struct attribute_group tegra_soc_attr_group = {
.attrs = tegra_soc_attr,
};
#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
static ssize_t platform_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
/*
* Displays the value in the 'pre_si_platform' field of the HIDREV
* register for Tegra194 devices. A value of 0 indicates that the
* platform type is silicon and all other non-zero values indicate
* the type of simulation platform is being used.
*/
return sprintf(buf, "%d\n", tegra_get_platform());
}
static DEVICE_ATTR_RO(platform);
static struct attribute *tegra194_soc_attr[] = {
&dev_attr_major.attr,
&dev_attr_minor.attr,
&dev_attr_platform.attr,
NULL,
};
const struct attribute_group tegra194_soc_attr_group = {
.attrs = tegra194_soc_attr,
};
#endif
struct device * __init tegra_soc_device_register(void)
{
struct soc_device_attribute *attr;
struct soc_device *dev;
attr = kzalloc(sizeof(*attr), GFP_KERNEL);
if (!attr)
return NULL;
attr->family = kasprintf(GFP_KERNEL, "Tegra");
if (tegra_is_silicon())
attr->revision = kasprintf(GFP_KERNEL, "%s %s",
tegra_platform_name[tegra_sku_info.platform],
tegra_revision_name[tegra_sku_info.revision]);
else
attr->revision = kasprintf(GFP_KERNEL, "%s",
tegra_platform_name[tegra_sku_info.platform]);
attr->soc_id = kasprintf(GFP_KERNEL, "%u", tegra_get_chip_id());
attr->custom_attr_group = fuse->soc->soc_attr_group;
dev = soc_device_register(attr);
if (IS_ERR(dev)) {
kfree(attr->soc_id);
kfree(attr->revision);
kfree(attr->family);
kfree(attr);
return ERR_CAST(dev);
}
return soc_device_to_device(dev);
}
static int __init tegra_init_fuse(void)
{
const struct of_device_id *match;
@@ -506,27 +410,3 @@ static int __init tegra_init_fuse(void)
return 0;
}
early_initcall(tegra_init_fuse);
#ifdef CONFIG_ARM64
static int __init tegra_init_soc(void)
{
struct device_node *np;
struct device *soc;
/* make sure we're running on Tegra */
np = of_find_matching_node(NULL, tegra_fuse_match);
if (!np)
return 0;
of_node_put(np);
soc = tegra_soc_device_register();
if (IS_ERR(soc)) {
pr_err("failed to register SoC device: %ld\n", PTR_ERR(soc));
return PTR_ERR(soc);
}
return 0;
}
device_initcall(tegra_init_soc);
#endif
-7
View File
@@ -110,7 +110,6 @@ const struct tegra_fuse_soc tegra30_fuse_soc = {
.init = tegra30_fuse_init,
.speedo_init = tegra30_init_speedo_data,
.info = &tegra30_fuse_info,
.soc_attr_group = &tegra_soc_attr_group,
.clk_suspend_on = false,
};
#endif
@@ -126,7 +125,6 @@ const struct tegra_fuse_soc tegra114_fuse_soc = {
.init = tegra30_fuse_init,
.speedo_init = tegra114_init_speedo_data,
.info = &tegra114_fuse_info,
.soc_attr_group = &tegra_soc_attr_group,
.clk_suspend_on = false,
};
#endif
@@ -286,7 +284,6 @@ const struct tegra_fuse_soc tegra124_fuse_soc = {
.num_lookups = ARRAY_SIZE(tegra124_fuse_lookups),
.cells = tegra124_fuse_cells,
.num_cells = ARRAY_SIZE(tegra124_fuse_cells),
.soc_attr_group = &tegra_soc_attr_group,
.clk_suspend_on = true,
};
#endif
@@ -457,7 +454,6 @@ const struct tegra_fuse_soc tegra210_fuse_soc = {
.cells = tegra210_fuse_cells,
.num_cells = ARRAY_SIZE(tegra210_fuse_cells),
.num_lookups = ARRAY_SIZE(tegra210_fuse_lookups),
.soc_attr_group = &tegra_soc_attr_group,
.clk_suspend_on = false,
};
#endif
@@ -516,7 +512,6 @@ const struct tegra_fuse_soc tegra186_fuse_soc = {
.num_cells = ARRAY_SIZE(tegra186_fuse_cells),
.keepouts = tegra186_fuse_keepouts,
.num_keepouts = ARRAY_SIZE(tegra186_fuse_keepouts),
.soc_attr_group = &tegra_soc_attr_group,
.clk_suspend_on = false,
};
#endif
@@ -609,7 +604,6 @@ const struct tegra_fuse_soc tegra194_fuse_soc = {
.num_cells = ARRAY_SIZE(tegra194_fuse_cells),
.keepouts = tegra194_fuse_keepouts,
.num_keepouts = ARRAY_SIZE(tegra194_fuse_keepouts),
.soc_attr_group = &tegra194_soc_attr_group,
.clk_suspend_on = false,
};
#endif
@@ -674,7 +668,6 @@ const struct tegra_fuse_soc tegra234_fuse_soc = {
.num_cells = ARRAY_SIZE(tegra234_fuse_cells),
.keepouts = tegra234_fuse_keepouts,
.num_keepouts = ARRAY_SIZE(tegra234_fuse_keepouts),
.soc_attr_group = &tegra194_soc_attr_group,
.clk_suspend_on = false,
};
#endif
+1 -2
View File
@@ -37,8 +37,6 @@ struct tegra_fuse_soc {
const struct nvmem_keepout *keepouts;
unsigned int num_keepouts;
const struct attribute_group *soc_attr_group;
bool clk_suspend_on;
};
@@ -72,6 +70,7 @@ void tegra_init_apbmisc(void);
u32 __init tegra_fuse_read_spare(unsigned int spare);
u32 __init tegra_fuse_read_early(unsigned int offset);
int tegra_efuse_nvmem_readl(unsigned long offset, u32 *value);
u8 tegra_get_major_rev(void);
u8 tegra_get_minor_rev(void);
@@ -0,0 +1,64 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/device.h>
#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <soc/tegra/fuse.h>
#include "fuse.h"
struct tegra_efuse_nvmem_helper {
struct device *dev;
struct nvmem_device *ndev;
} efuse_helper;
int tegra_efuse_nvmem_readl(unsigned long offset, u32 *value)
{
int num_bytes_read;
if (IS_ERR_OR_NULL(efuse_helper.ndev))
return -EPROBE_DEFER;
num_bytes_read = nvmem_device_read(efuse_helper.ndev, offset, 4, value);
if (num_bytes_read < 0)
return num_bytes_read;
return 0;
}
static int tegra_efuse_nvmem_helper_probe(struct platform_device *pdev)
{
efuse_helper.dev = &pdev->dev;
efuse_helper.ndev = devm_nvmem_device_get(&pdev->dev, "efuse");
if (IS_ERR(efuse_helper.ndev))
return dev_err_probe(&pdev->dev, PTR_ERR(efuse_helper.ndev),
"failed to get alias id\n");
return 0;
}
static int tegra_efuse_nvmem_helper_remove(struct platform_device *pdev)
{
return 0;
}
static const struct of_device_id tegra_efuse_nvmem_helper_match[] = {
{ .compatible = "nvidia,efuse-nvmem-helper", },
{ /* Sentinel. */ }
};
MODULE_DEVICE_TABLE(of, tegra_efuse_nvmem_helper_match);
static struct platform_driver tegra_efuse_nvmem_helper_driver = {
.driver = {
.name = "tegra-efuse-nvmem-helper",
.of_match_table = tegra_efuse_nvmem_helper_match,
},
.probe = tegra_efuse_nvmem_helper_probe,
.remove = tegra_efuse_nvmem_helper_remove,
};
module_platform_driver(tegra_efuse_nvmem_helper_driver);
+202
View File
@@ -0,0 +1,202 @@
#include <linux/init.h>
#include <linux/sys_soc.h>
#include <soc/tegra/common.h>
#include <soc/tegra/fuse.h>
#define TEGRA_SOC_MAJOR_REV_SHIFT 4
#define TEGRA_SOC_MAJOR_REV_MASK 0xf
#define TEGRA_SOC_ID_SHIFT 8
#define TEGRA_SOC_ID_MASK 0xff
#define TEGRA_SOC_MINOR_REV_SHIFT 16
#define TEGRA_SOC_MINOR_REV_MASK 0xf
#define TEGRA_SOC_PLATFORM_SHIFT 20
#define TEGRA_SOC_PLATFORM_MASK 0xf
enum tegra_soc_revision {
TEGRA_SOC_REVISION_0 = 0,
TEGRA_SOC_REVISION_1,
TEGRA_SOC_REVISION_2,
TEGRA_SOC_REVISION_3,
TEGRA_SOC_REVISION_4,
TEGRA_SOC_REVISION_5,
TEGRA_SOC_REVISION_6,
TEGRA_SOC_REVISION_7,
TEGRA_SOC_REVISION_8,
TEGRA_SOC_REVISION_9,
TEGRA_SOC_REVISION_10,
TEGRA_SOC_REVISION_11,
TEGRA_SOC_REVISION_12,
TEGRA_SOC_REVISION_13,
TEGRA_SOC_REVISION_14,
TEGRA_SOC_REVISION_15,
TEGRA_SOC_REVISION_MAX,
};
enum tegra_soc_platform {
TEGRA_SOC_PLATFORM_SILICON = 0,
TEGRA_SOC_PLATFORM_QT,
TEGRA_SOC_PLATFORM_SYSTEM_FPGA,
TEGRA_SOC_PLATFORM_UNIT_FPGA,
TEGRA_SOC_PLATFORM_ASIM_QT,
TEGRA_SOC_PLATFORM_ASIM_LINSIM,
TEGRA_SOC_PLATFORM_DSIM_ASIM_LINSIM,
TEGRA_SOC_PLATFORM_VERIFICATION_SIMULATION,
TEGRA_SOC_PLATFORM_VDK,
TEGRA_SOC_PLATFORM_VSP,
TEGRA_SOC_PLATFORM_MAX,
};
static const char *tegra_soc_revision_name[TEGRA_SOC_REVISION_MAX] = {
[TEGRA_SOC_REVISION_0] = "unknown",
[TEGRA_SOC_REVISION_1] = "A01",
[TEGRA_SOC_REVISION_2] = "A02",
[TEGRA_SOC_REVISION_3] = "A03",
[TEGRA_SOC_REVISION_4] = "unknown",
[TEGRA_SOC_REVISION_5] = "B01",
[TEGRA_SOC_REVISION_6] = "B02",
[TEGRA_SOC_REVISION_7] = "B03",
[TEGRA_SOC_REVISION_8] = "unknown",
[TEGRA_SOC_REVISION_9] = "C01",
[TEGRA_SOC_REVISION_10] = "C02",
[TEGRA_SOC_REVISION_11] = "C03",
[TEGRA_SOC_REVISION_12] = "unknown",
[TEGRA_SOC_REVISION_13] = "D01",
[TEGRA_SOC_REVISION_14] = "D02",
[TEGRA_SOC_REVISION_15] = "D03",
};
static const char *tegra_soc_platform_name[TEGRA_SOC_PLATFORM_MAX] = {
[TEGRA_SOC_PLATFORM_SILICON] = "Silicon",
[TEGRA_SOC_PLATFORM_QT] = "QT",
[TEGRA_SOC_PLATFORM_SYSTEM_FPGA] = "System FPGA",
[TEGRA_SOC_PLATFORM_UNIT_FPGA] = "Unit FPGA",
[TEGRA_SOC_PLATFORM_ASIM_QT] = "Asim QT",
[TEGRA_SOC_PLATFORM_ASIM_LINSIM] = "Asim Linsim",
[TEGRA_SOC_PLATFORM_DSIM_ASIM_LINSIM] = "Dsim Asim Linsim",
[TEGRA_SOC_PLATFORM_VERIFICATION_SIMULATION] = "Verification Simulation",
[TEGRA_SOC_PLATFORM_VDK] = "VDK",
[TEGRA_SOC_PLATFORM_VSP] = "VSP",
};
static ssize_t major_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
int major_rev;
major_rev = (tegra_read_chipid() >> TEGRA_SOC_MAJOR_REV_SHIFT) & TEGRA_SOC_MAJOR_REV_MASK;
return sprintf(buf, "%d\n", major_rev);
}
static DEVICE_ATTR_RO(major);
static ssize_t minor_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
int minor_rev;
minor_rev = (tegra_read_chipid() >> TEGRA_SOC_MINOR_REV_SHIFT) & TEGRA_SOC_MINOR_REV_SHIFT;
return sprintf(buf, "%d\n", minor_rev);
}
static DEVICE_ATTR_RO(minor);
static ssize_t platform_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%d\n", tegra_get_platform());
}
static DEVICE_ATTR_RO(platform);
static struct attribute *tegra_soc_custom_attr[] = {
&dev_attr_major.attr,
&dev_attr_minor.attr,
&dev_attr_platform.attr,
NULL,
};
const struct attribute_group tegra_soc_custom_attr_group = {
.attrs = tegra_soc_custom_attr,
};
static struct soc_device_attribute *tegra_soc_attr;
static struct soc_device *tegra_soc_dev;
static int __init tegra_soc_init(void)
{
u32 miscreg = 0;
u8 platform;
u8 revision;
u32 soc_id;
/* Return if not running on Tegra. */
if (!soc_is_tegra())
return 0;
miscreg = tegra_read_chipid();
if (!miscreg)
return -EPROBE_DEFER;
platform = (miscreg >> TEGRA_SOC_PLATFORM_SHIFT) & TEGRA_SOC_PLATFORM_MASK;
revision = (miscreg >> TEGRA_SOC_MINOR_REV_SHIFT) & TEGRA_SOC_MINOR_REV_MASK;
/*
* FIXME: From Tegra234 onwards the SOC_ID consists of CHIP_ID + Major revision.
* So, soc_id should be (miscreg >> 4) & 0xfff, but most of the userspace
* applications and tests are written with an assumption that SOC_ID = CHIP_ID.
* This causes failures while identifying platforms from those userspace
* applications.
*
* For now, keep soc_id as (miscreg >> 8) & 0xff, until the userspace
* applications are patched.
*/
soc_id = (miscreg >> TEGRA_SOC_ID_SHIFT) & TEGRA_SOC_ID_MASK;
tegra_soc_attr = kzalloc(sizeof(*tegra_soc_attr), GFP_KERNEL);
if (!tegra_soc_attr)
return -EINVAL;
tegra_soc_attr->family = kasprintf(GFP_KERNEL, "Tegra");
if (tegra_is_silicon())
tegra_soc_attr->revision = kasprintf(GFP_KERNEL, "%s %s",
tegra_soc_platform_name[platform],
tegra_soc_revision_name[revision]);
else
tegra_soc_attr->revision = kasprintf(GFP_KERNEL, "%s",
tegra_soc_platform_name[platform]);
/*
* FIXME: Use hex value for SOC_ID as it is the most widely used notation
* for identifying chips.
*
* Fixing this would require patching all the userspace applications
* relying on SOC_ID.
*/
tegra_soc_attr->soc_id = kasprintf(GFP_KERNEL, "%u", soc_id);
tegra_soc_attr->custom_attr_group = &tegra_soc_custom_attr_group;
tegra_soc_dev = soc_device_register(tegra_soc_attr);
if (IS_ERR(tegra_soc_dev)) {
kfree(tegra_soc_attr->soc_id);
kfree(tegra_soc_attr->revision);
kfree(tegra_soc_attr->family);
kfree(tegra_soc_attr);
return PTR_ERR(tegra_soc_dev);
}
return 0;
}
device_initcall(tegra_soc_init);
static void __exit tegra_soc_exit(void)
{
soc_device_unregister(tegra_soc_dev);
kfree(tegra_soc_attr->soc_id);
kfree(tegra_soc_attr->revision);
kfree(tegra_soc_attr->family);
kfree(tegra_soc_attr);
}
module_exit(tegra_soc_exit);