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:
@@ -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
|
||||
|
||||
@@ -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");
|
||||
@@ -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
|
||||
|
||||
@@ -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", },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
Reference in New Issue
Block a user