From a18340ea37ba4ea1a096c63bab35a61bfaebd219 Mon Sep 17 00:00:00 2001 From: Kartik Date: Sun, 15 Sep 2024 08:20:00 +0000 Subject: [PATCH] NVIDIA: SAUCE: nvmem: Add Tegra efuse driver Add Tegra efuse driver. Signed-off-by: Kartik Signed-off-by: Laxman Dewangan Acked-by: Noah Wager Acked-by: Jacob Martin Signed-off-by: Noah Wager --- drivers/nvmem/Makefile | 2 + drivers/nvmem/tegra-efuse.c | 334 ++++++++++++++++++ drivers/soc/tegra/Makefile | 1 + drivers/soc/tegra/common.c | 2 + drivers/soc/tegra/fuse/Makefile | 1 + drivers/soc/tegra/fuse/fuse-tegra.c | 126 +------ drivers/soc/tegra/fuse/fuse-tegra30.c | 7 - drivers/soc/tegra/fuse/fuse.h | 3 +- .../soc/tegra/fuse/tegra-efuse-nvmem-helper.c | 64 ++++ drivers/soc/tegra/tegra-soc.c | 202 +++++++++++ 10 files changed, 610 insertions(+), 132 deletions(-) create mode 100644 drivers/nvmem/tegra-efuse.c create mode 100644 drivers/soc/tegra/fuse/tegra-efuse-nvmem-helper.c create mode 100644 drivers/soc/tegra/tegra-soc.c diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index cdd01fbf1313..bf541a471c38 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -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 diff --git a/drivers/nvmem/tegra-efuse.c b/drivers/nvmem/tegra-efuse.c new file mode 100644 index 000000000000..cb193bb9d83d --- /dev/null +++ b/drivers/nvmem/tegra-efuse.c @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2013-2023, NVIDIA CORPORATION. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +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"); diff --git a/drivers/soc/tegra/Makefile b/drivers/soc/tegra/Makefile index 77044e37af10..5e1dffcf0583 100644 --- a/drivers/soc/tegra/Makefile +++ b/drivers/soc/tegra/Makefile @@ -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 diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c index dff6d5ef4e46..25a577fd0644 100644 --- a/drivers/soc/tegra/common.c +++ b/drivers/soc/tegra/common.c @@ -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", }, { } }; diff --git a/drivers/soc/tegra/fuse/Makefile b/drivers/soc/tegra/fuse/Makefile index ea8332cc3980..b2c15670761a 100644 --- a/drivers/soc/tegra/fuse/Makefile +++ b/drivers/soc/tegra/fuse/Makefile @@ -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 diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index 98805885158e..acc4ec69cade 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -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 diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c index e94d46372a63..de94553333f7 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra30.c +++ b/drivers/soc/tegra/fuse/fuse-tegra30.c @@ -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 diff --git a/drivers/soc/tegra/fuse/fuse.h b/drivers/soc/tegra/fuse/fuse.h index 90f23be73894..580ce32cc251 100644 --- a/drivers/soc/tegra/fuse/fuse.h +++ b/drivers/soc/tegra/fuse/fuse.h @@ -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); diff --git a/drivers/soc/tegra/fuse/tegra-efuse-nvmem-helper.c b/drivers/soc/tegra/fuse/tegra-efuse-nvmem-helper.c new file mode 100644 index 000000000000..a803301bfa94 --- /dev/null +++ b/drivers/soc/tegra/fuse/tegra-efuse-nvmem-helper.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#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); diff --git a/drivers/soc/tegra/tegra-soc.c b/drivers/soc/tegra/tegra-soc.c new file mode 100644 index 000000000000..e2b0cfe41f0c --- /dev/null +++ b/drivers/soc/tegra/tegra-soc.c @@ -0,0 +1,202 @@ +#include +#include + +#include +#include + +#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);