cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fuse-tegra.c (14125B)


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