From f03685b25bc13913084c37c472daac4bd038ece3 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Mon, 15 May 2023 06:09:01 +0000 Subject: [PATCH 01/14] cvnas: Remove dummy Makefile for cvnas build Remove dummy makefile for cvnas driver integration from the kernel/nvidia. Bug 4083867 Change-Id: I6ebd811b6efafd5d731fae9105d40bfd479a4c29 Signed-off-by: Laxman Dewangan --- drivers/platform/tegra/cvnas/Makefile | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 drivers/platform/tegra/cvnas/Makefile diff --git a/drivers/platform/tegra/cvnas/Makefile b/drivers/platform/tegra/cvnas/Makefile deleted file mode 100644 index 37a9470b..00000000 --- a/drivers/platform/tegra/cvnas/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. - -# NOTE: Do not change or add anything in this makefile. -# The source code and makefile rules are copied from the -# kernel/nvidia/drivers/platform/tegra/cvnas. This file is -# just place-holder for empty makefile to avoid any build -# issue when copy is not done from command line and building -# the tree independent of source copy. - From 04479abd45eb240702ad41e490510eb38cd4c854 Mon Sep 17 00:00:00 2001 From: Damian Halas Date: Fri, 2 Feb 2018 14:25:05 -0800 Subject: [PATCH 02/14] t19x: cvnas: expose cvsram base and size to kernel Add nvcvnas_get_cvsram_base and nvcvnas_get_cvsram_size, Use them in pva_queue.c and nvhost_buffer.c instead of hardcoded values. JIRA EVLR-2273 Change-Id: I3fbec50a2c57220034b25b3a91569ba4aec319f6 Signed-off-by: Damian Halas Reviewed-on: https://git-master.nvidia.com/r/1651414 Reviewed-by: Puneet Saxena Reviewed-by: Mikko Perttunen Reviewed-by: Nirav Patel --- include/linux/cvnas.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 include/linux/cvnas.h diff --git a/include/linux/cvnas.h b/include/linux/cvnas.h new file mode 100644 index 00000000..a769106b --- /dev/null +++ b/include/linux/cvnas.h @@ -0,0 +1,28 @@ +/* + * include/linux/cvnas.h + * + * Tegra cvnas driver + * + * Copyright (c) 2018, NVIDIA Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#ifndef __LINUX_CVNAS_H +#define __LINUX_CVNAS_H + +int nvcvnas_busy(void); +int nvcvnas_idle(void); +phys_addr_t nvcvnas_get_cvsram_base(void); +size_t nvcvnas_get_cvsram_size(void); + +#endif From 526fd969f6306410cc134eb1d9e4827db51bdc51 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Mon, 20 Dec 2021 21:10:06 +0000 Subject: [PATCH 03/14] platform: tegra: cvnas: Prepare for building as a module Prepare for building the CVNAS driver as a module by adding the necessary Kconfig option. In order to build the driver as an external module, move the source into its own sub-directory and add it own Makefile so that it can be built independently of other drivers. Bug 3459526 Change-Id: I87ce24852c561144313849774d5031821b6c3a47 Signed-off-by: Jon Hunter Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2650490 Reviewed-by: Ketan Patil Reviewed-by: Sachin Nikam --- drivers/platform/tegra/cvnas/Makefile | 11 + drivers/platform/tegra/cvnas/cvnas.c | 843 ++++++++++++++++++++++++++ 2 files changed, 854 insertions(+) create mode 100644 drivers/platform/tegra/cvnas/Makefile create mode 100644 drivers/platform/tegra/cvnas/cvnas.c diff --git a/drivers/platform/tegra/cvnas/Makefile b/drivers/platform/tegra/cvnas/Makefile new file mode 100644 index 00000000..cf5d624b --- /dev/null +++ b/drivers/platform/tegra/cvnas/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Tegra CVNAS Driver. +# +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# + +ccflags-y += -I$(srctree.nvidia)/include +ccflags-y += -Werror + +obj-$(CONFIG_TEGRA_CVNAS) += cvnas.o diff --git a/drivers/platform/tegra/cvnas/cvnas.c b/drivers/platform/tegra/cvnas/cvnas.c new file mode 100644 index 00000000..4a4ceed8 --- /dev/null +++ b/drivers/platform/tegra/cvnas/cvnas.c @@ -0,0 +1,843 @@ +/* + * drivers/platform/tegra/cvnas.c + * + * Copyright (C) 2017-2022, NVIDIA Corporation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifdef pr_fmt +#undef pr_fmt +#endif + +#define pr_fmt(fmt) "cvnas: %s,%d" fmt, __func__, __LINE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if KERNEL_VERSION(4, 15, 0) > LINUX_VERSION_CODE +#include +#endif +#include +#include + +static int cvnas_debug; +module_param(cvnas_debug, int, 0644); +#define CVNOC_MISC_DBG_APERTURE_CONTROL 0x8 +#define CVNOC_MISC_DBG_APERTURE_DISABLE 0x1 + +static bool cvnas_rail; + +#define CVSRAM_MEM_INIT_OFFSET 0x00 +#define CVSRAM_MEM_INIT_START BIT(0) +#define CVSRAM_MEM_INIT_STATUS BIT(1) + +#define CVSRAM_RD_COUNT_OFFSET 0x008 +#define CVSRAM_WR_COUNT_OFFSET 0x00C +#define CVSRAM_STALLED_RD_COUNT_OFFSET 0x010 +#define CVSRAM_STALLED_WR_COUNT_OFFSET 0x014 + +#define CVSRAM_PWR_CTRL_OFFSET 0x018 + +#define CVSRAM_EC_MERR_FORCE_OFFSET 0x83C +#define CVSRAM_EC_MERR_ECC_INJECT 0xFFFFFF + +#define ERRCOLLATOR_MISSIONERR_STATUS 0x840 + +#define CVNAS_EC_MERR_FORCE_OFFSET 0xF134 +#define CVNAS_EC_MERR_ECC_INJECT 0x1FE + +#define MEM_INIT_FCM 0x1 +#define DEV_CVNAS_CLR_RST 0x2 + +#define HSM_CVSRAM_ECC_CORRECT_OFFSET 0x1A8 +#define HSM_CVSRAM_ECC_DED_OFFSET_0 0x180 +#define HSM_CVSRAM_ECC_DED_OFFSET_1 0x184 + +#define HSM_CVSRAM_ECC_CORRECT_MASK 0x0F000000 +#define HSM_CVSRAM_ECC_DED_MASK_0 0x80000000 +#define HSM_CVSRAM_ECC_DED_MASK_1 0x00000007 + +struct cvnas_device { + struct dentry *debugfs_root; + + void __iomem *cvsram_iobase; + void __iomem *cvreg_iobase; + void __iomem *hsm_iobase; + + struct device dma_dev; + + int nslices; + int slice_size; + phys_addr_t cvsram_base; + size_t cvsram_size; + + struct clk *clk; + struct device_attribute *attr; + + struct reset_control *rst; + struct reset_control *rst_fcm; + + bool virt; + + int (*pmops_busy)(void); + int (*pmops_idle)(void); +}; + +static struct platform_device *cvnas_plat_dev; + +static u32 nvcvsram_readl(struct cvnas_device *dev, int sid, u32 reg) +{ + return readl(dev->cvsram_iobase + dev->slice_size * sid + reg); +} + +static void nvcvsram_writel(struct cvnas_device *dev, int sid, u32 val, u32 reg) +{ + writel(val, dev->cvsram_iobase + dev->slice_size * sid + reg); +} + +static u32 nvhsm_readl(struct cvnas_device *dev, u32 reg) +{ + return readl(dev->hsm_iobase + reg); +} + +/* Call at the time we allocate something from CVNAS */ +int nvcvnas_busy(void) +{ + if (!cvnas_plat_dev) { + pr_err("CVNAS Platform Device not found\n"); + return -ENODEV; + } + + return pm_runtime_get_sync(&cvnas_plat_dev->dev); +} +EXPORT_SYMBOL(nvcvnas_busy); + +/* Call after we release a buffer */ +int nvcvnas_idle(void) +{ + if (!cvnas_plat_dev) { + pr_err("CVNAS Platform Device not found\n"); + return -ENODEV; + } + + return pm_runtime_put(&cvnas_plat_dev->dev); +} +EXPORT_SYMBOL(nvcvnas_idle); + + +static int cvsram_perf_counters_show(struct seq_file *s, void *data) +{ + struct cvnas_device *dev = s->private; + int i; + u32 val; + + if (!dev) { + seq_printf(s, "Invalid cvnas device!\n"); + return -EINVAL; + } + + seq_printf(s, "RD: "); + for (i = 0; i < dev->nslices; i++) { + val = nvcvsram_readl(dev, i, CVSRAM_RD_COUNT_OFFSET); + seq_printf(s, "%x ", val); + } + seq_printf(s, "\nWR: "); + for (i = 0; i < dev->nslices; i++) { + val = nvcvsram_readl(dev, i, CVSRAM_WR_COUNT_OFFSET); + seq_printf(s, "%x ", val); + } + seq_printf(s, "\nSRD: "); + for (i = 0; i < dev->nslices; i++) { + val = nvcvsram_readl(dev, i, CVSRAM_STALLED_RD_COUNT_OFFSET); + seq_printf(s, "%x ", val); + } + seq_printf(s, "\nSWR: "); + for (i = 0; i < dev->nslices; i++) { + val = nvcvsram_readl(dev, i, CVSRAM_STALLED_WR_COUNT_OFFSET); + seq_printf(s, "%x ", val); + } + seq_printf(s, "\n"); + return 0; +} + +static int cvsram_perf_counter_open(struct inode *inode, struct file *file) +{ + return single_open(file, cvsram_perf_counters_show, + inode->i_private); +} + +static const struct file_operations cvsram_perf_fops = { + .open = cvsram_perf_counter_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int cvsram_ecc_err_inject(struct seq_file *s, void *data) +{ + struct cvnas_device *dev = (struct cvnas_device *)s->private; + int i; + u32 val; + + if (!dev) { + seq_printf(s, "Invalid cvnas device!\n"); + return -EINVAL; + } + + for (i = 0; i < dev->nslices; i++) { + nvcvsram_writel(dev, i, CVSRAM_EC_MERR_ECC_INJECT, + CVSRAM_EC_MERR_FORCE_OFFSET); + if (cvnas_debug) { + val = nvcvsram_readl(dev, i, + CVSRAM_EC_MERR_FORCE_OFFSET); + seq_printf(s, "CVSRAM_EC_MERR_FORCE_OFFSET_SLICE%d: 0x%x : 0x%x\n", + i, CVSRAM_EC_MERR_FORCE_OFFSET, val); + } + } + + for (i = 0; i < dev->nslices; i++) { + if (cvnas_debug) { + val = nvcvsram_readl(dev, i, + ERRCOLLATOR_MISSIONERR_STATUS); + seq_printf(s, "ERRCOLLATOR_SLICE0_ERRSLICE0_MISSIONERR_STATUS_SLICE%d: 0x%x : 0x%x\n", + i, ERRCOLLATOR_MISSIONERR_STATUS, val); + } + } + + val = nvhsm_readl(dev, HSM_CVSRAM_ECC_CORRECT_OFFSET); + if (val & HSM_CVSRAM_ECC_CORRECT_MASK) { + seq_printf(s, "HSM received ECC corrected SEC error\n"); + } + val = nvhsm_readl(dev, HSM_CVSRAM_ECC_DED_OFFSET_0); + if (val & HSM_CVSRAM_ECC_DED_MASK_0) { + seq_printf(s, "HSM received ECC DED_0 error\n"); + } + val = nvhsm_readl(dev, HSM_CVSRAM_ECC_DED_OFFSET_1); + if (val & HSM_CVSRAM_ECC_DED_MASK_1) { + seq_printf(s, "HSM received ECC DED_1 error\n"); + } + + return 0; +} + +static int cvsram_ecc_err_open(struct inode *inode, struct file *file) +{ + return single_open(file, cvsram_ecc_err_inject, + inode->i_private); +} + +static const struct file_operations cvsram_ecc_err_fops = { + .open = cvsram_ecc_err_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int rd_cvrail(void *data, u64 *val) +{ + *val = cvnas_rail; + return 0; +} + +static int wr_cvrail(void *data, u64 val) +{ + bool cvrail = (bool)val; + int ret = 0; + + if (cvrail) { + ret = nvcvnas_busy(); + cvnas_rail = true; + } else { + ret = nvcvnas_idle(); + cvnas_rail = false; + } + + return ret; +} +DEFINE_SIMPLE_ATTRIBUTE(cvnas_reg_fops, rd_cvrail, wr_cvrail, + "%llu\n"); + +static int nvcvnas_debugfs_init(struct cvnas_device *dev) +{ + struct dentry *root; + + root = debugfs_create_dir("cvnas", NULL); + if (!root) + return PTR_ERR(root); + + debugfs_create_file("cvrail", 0644, + root, dev, &cvnas_reg_fops); + debugfs_create_x64("cvsram_base", S_IRUGO, root, &dev->cvsram_base); + debugfs_create_size_t("cvsram_size", S_IRUGO, root, &dev->cvsram_size); + debugfs_create_file("cvsram_perf_counters", S_IRUGO, root, dev, &cvsram_perf_fops); + debugfs_create_file("inject_cvsram_ecc_error", S_IRUGO, root, dev, &cvsram_ecc_err_fops); + dev->debugfs_root = root; + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int nvcvsram_ecc_setup(struct cvnas_device *dev) +{ + u32 mem_init = 0; + int i; + + /* enable clock if disabled */ + + for (i = 0; i < dev->nslices; i++) { + mem_init = nvcvsram_readl(dev, i, CVSRAM_MEM_INIT_OFFSET); + if (mem_init & CVSRAM_MEM_INIT_STATUS) + return 0; + nvcvsram_writel(dev, i, MEM_INIT_FCM, CVSRAM_MEM_INIT_OFFSET); + } + + for (i = 0; i < dev->nslices; i++) { + while (1) { + usleep_range(100, 200); + mem_init = nvcvsram_readl(dev, i, + CVSRAM_MEM_INIT_OFFSET); + /* FIXME: Use CCF to make sure clock runs + * at fixed frequency and wait for just + * that much time. + */ + if (((mem_init & CVSRAM_MEM_INIT_STATUS) >> 1) & 1) + break; + } + } + + if (mem_init & CVSRAM_MEM_INIT_STATUS) + return 0; + return -EBUSY; +} + +/* Disable CVNOC Debug Aperture */ +static void disable_cvnoc_debug_apert(struct cvnas_device *cvnas_dev) +{ + unsigned long val; + + val = readl(cvnas_dev->cvreg_iobase + CVNOC_MISC_DBG_APERTURE_CONTROL); + val = val | CVNOC_MISC_DBG_APERTURE_DISABLE; + writel(val, cvnas_dev->cvreg_iobase + CVNOC_MISC_DBG_APERTURE_CONTROL); +} + +static int nvcvnas_power_on(struct cvnas_device *cvnas_dev) +{ + u32 fcm_upg_seq[] = + {0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00}; + + int i, j; + int err; + + if (!tegra_platform_is_silicon()) { + pr_err("is not supported on this platform\n"); + return 0; + } + + if (cvnas_dev->virt) + return 0; + + err = clk_prepare_enable(cvnas_dev->clk); + if (err < 0) + goto err_enable_clk; + + err = reset_control_deassert(cvnas_dev->rst); + if (err < 0) + goto err_deassert_reset; + + for (i = 0; i < ARRAY_SIZE(fcm_upg_seq); i++) { + for (j = 0; j < cvnas_dev->nslices; j++) { + nvcvsram_writel(cvnas_dev, j, fcm_upg_seq[i], + CVSRAM_PWR_CTRL_OFFSET); + if (cvnas_debug) { + u32 val = nvcvsram_readl(cvnas_dev, j, + CVSRAM_PWR_CTRL_OFFSET); + pr_info("Set SRAM%d_CVSRAM_PWR_CTRL %x to %x\n", + j, CVSRAM_PWR_CTRL_OFFSET, val); + } + } + } + + err = reset_control_deassert(cvnas_dev->rst_fcm); + if (err < 0) + goto err_deassert_fcm_reset; + + err = nvcvsram_ecc_setup(cvnas_dev); + if (err < 0) { + pr_err("ECC init failed\n"); + goto err_init_ecc; + } + + + if (!tegra_platform_is_sim()) + disable_cvnoc_debug_apert(cvnas_dev); + + return 0; + +err_init_ecc: + reset_control_assert(cvnas_dev->rst_fcm); +err_deassert_fcm_reset: + reset_control_assert(cvnas_dev->rst); +err_deassert_reset: + clk_disable_unprepare(cvnas_dev->clk); +err_enable_clk: + return err; +} +#endif /* CONFIG_PM_SLEEP */ + +static int nvcvnas_power_off(struct cvnas_device *cvnas_dev) +{ + int val, i, j; + u32 fcm_pg_seq[] = + {0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF}; + + if (!tegra_platform_is_silicon()) { + pr_err("is not supported on this platform\n"); + return 0; + } + + if (cvnas_dev->virt) + return 0; + + reset_control_assert(cvnas_dev->rst_fcm); + + /* FCM low power mode */ + for (i = 0; i < ARRAY_SIZE(fcm_pg_seq); i++) { + for (j = 0; j < cvnas_dev->nslices; j++) { + nvcvsram_writel(cvnas_dev, j, fcm_pg_seq[i], + CVSRAM_PWR_CTRL_OFFSET); + if (cvnas_debug) { + val = nvcvsram_readl(cvnas_dev, j, + CVSRAM_PWR_CTRL_OFFSET); + pr_info("Set SRAM%d_CVSRAM_PWR_CTRL %x to %x\n", + j, CVSRAM_PWR_CTRL_OFFSET, val); + } + } + } + + reset_control_assert(cvnas_dev->rst); + clk_disable_unprepare(cvnas_dev->clk); + + return 0; +} + +phys_addr_t nvcvnas_get_cvsram_base(void) +{ + struct cvnas_device *cvnas_dev; + + if (!cvnas_plat_dev) + return 0; + + cvnas_dev = dev_get_drvdata(&cvnas_plat_dev->dev); + return cvnas_dev->cvsram_base; +} +EXPORT_SYMBOL(nvcvnas_get_cvsram_base); + +size_t nvcvnas_get_cvsram_size(void) +{ + struct cvnas_device *cvnas_dev; + + if (!cvnas_plat_dev) + return 0; + + cvnas_dev = dev_get_drvdata(&cvnas_plat_dev->dev); + return cvnas_dev->cvsram_size; +} +EXPORT_SYMBOL(nvcvnas_get_cvsram_size); + +int is_nvcvnas_probed(void) +{ + if (cvnas_plat_dev && dev_get_drvdata(&cvnas_plat_dev->dev)) + return 1; + else + return 0; +} + +int is_nvcvnas_clk_enabled(void) +{ + struct cvnas_device *cvnas_dev = dev_get_drvdata(&cvnas_plat_dev->dev); + + if (cvnas_plat_dev && cvnas_dev) + return __clk_is_enabled(cvnas_dev->clk); + else + return 0; +} +EXPORT_SYMBOL(is_nvcvnas_clk_enabled); + +static ssize_t clk_cap_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct cvnas_device *cvnas = dev_get_drvdata(dev); + unsigned long max_rate; + int ret; + + ret = kstrtoul(buf, 0, &max_rate); + if (ret) + return -EINVAL; + + /* Remove previous freq cap to get correct rounted rate for new cap */ + ret = clk_set_max_rate(cvnas->clk, UINT_MAX); + if (ret < 0) + return ret; + + max_rate = clk_round_rate(cvnas->clk, max_rate); + if (max_rate < 0) + return -EINVAL; + + /* Apply new freq cap */ + ret = clk_set_max_rate(cvnas->clk, max_rate); + if (ret < 0) + return ret; + + return count; +} + +static ssize_t clk_cap_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cvnas_device *cvnas = dev_get_drvdata(dev); + long max_rate; + + max_rate = clk_round_rate(cvnas->clk, UINT_MAX); + if (max_rate < 0) + return max_rate; + + return snprintf(buf, PAGE_SIZE, "%ld\n", max_rate); +} + +static const struct of_device_id nvcvnas_of_ids[] = { + { .compatible = "nvidia,tegra-cvnas", .data = (void *)false, }, + { .compatible = "nvidia,tegra-cvnas-hv", .data = (void *)true, }, + { } +}; +MODULE_DEVICE_TABLE(of, nvcvnas_of_ids); + +static int nvcvnas_probe(struct platform_device *pdev) +{ + struct cvnas_device *cvnas_dev; + int ret; + u32 cvsram_slice_data[2]; + u32 cvsram_reg_data[4]; + const struct of_device_id *match; + +#if KERNEL_VERSION(4, 15, 0) > LINUX_VERSION_CODE + if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA19 && +#else + if (tegra_get_chip_id() == TEGRA194 && +#endif + tegra_get_sku_id() == 0x9E) { + dev_err(&pdev->dev, "CVNAS IP is disabled in SKU.\n"); + return -ENODEV; + } + + cvnas_plat_dev = pdev; + + cvnas_dev = (struct cvnas_device *)kzalloc( + sizeof(*cvnas_dev), GFP_KERNEL); + if (!cvnas_dev) + return -ENOMEM; + + cvnas_dev->attr = + devm_kmalloc(&pdev->dev, sizeof(*cvnas_dev->attr), GFP_KERNEL); + if (!cvnas_dev->attr) { + kfree(cvnas_dev); + return -ENOMEM; + } + + sysfs_attr_init(&cvnas_dev->attr->attr); + cvnas_dev->attr->attr.name = "clk_cap"; + cvnas_dev->attr->attr.mode = 0644; + cvnas_dev->attr->show = clk_cap_show; + cvnas_dev->attr->store = clk_cap_store; + + ret = device_create_file(&pdev->dev, cvnas_dev->attr); + if (ret) { + dev_err(&pdev->dev, "sysfs_create_file failed: %d\n", ret); + goto err_device_create_file; + } + + match = of_match_device(nvcvnas_of_ids, &pdev->dev); + if (match) + cvnas_dev->virt = (bool)match->data; + + cvnas_dev->cvreg_iobase = of_iomap(pdev->dev.of_node, 0); + if (!cvnas_dev->cvreg_iobase) { + dev_err(&pdev->dev, "No cvnas reg property found\n"); + ret = PTR_ERR(cvnas_dev->cvreg_iobase); + goto err_of_iomap; + } + + cvnas_dev->cvsram_iobase = of_iomap(pdev->dev.of_node, 1); + if (!cvnas_dev->cvsram_iobase) { + dev_err(&pdev->dev, "No cvsram reg property found\n"); + ret = PTR_ERR(cvnas_dev->cvsram_iobase); + goto err_cvsram_of_iomap; + } + + cvnas_dev->hsm_iobase = of_iomap(pdev->dev.of_node, 2); + if (!cvnas_dev->hsm_iobase) { + dev_err(&pdev->dev, "No hsm reg property found\n"); + ret = PTR_ERR(cvnas_dev->hsm_iobase); + goto err_hsm_of_iomap; + } + + ret = of_property_read_u32_array(pdev->dev.of_node, + "cvsramslice", cvsram_slice_data, + ARRAY_SIZE(cvsram_slice_data)); + if (ret) { + dev_err(&pdev->dev, "no cvsramslice property found\n"); + goto err_cvsram_get_slice_data; + } + cvnas_dev->nslices = cvsram_slice_data[0]; + cvnas_dev->slice_size = cvsram_slice_data[1]; + + ret = of_property_read_u32_array(pdev->dev.of_node, + "cvsram-reg", cvsram_reg_data, + ARRAY_SIZE(cvsram_reg_data)); + if (ret) { + dev_err(&pdev->dev, "no cvsram-reg property found\n"); + goto err_cvsram_get_reg_data; + } + + cvnas_dev->cvsram_base = ((u64)cvsram_reg_data[0]) << 32; + cvnas_dev->cvsram_base |= cvsram_reg_data[1]; + cvnas_dev->cvsram_size = ((u64)cvsram_reg_data[2]) << 32; + cvnas_dev->cvsram_size |= cvsram_reg_data[3]; + + cvnas_dev->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(cvnas_dev->clk)) { + ret = PTR_ERR(cvnas_dev->clk); + goto err_get_clk; + } + + cvnas_dev->rst = devm_reset_control_get(&pdev->dev, "rst"); + if (IS_ERR(cvnas_dev->rst)) { + ret = PTR_ERR(cvnas_dev->rst); + goto err_get_reset; + } + + cvnas_dev->rst_fcm = devm_reset_control_get(&pdev->dev, "rst_fcm"); + if (IS_ERR(cvnas_dev->rst_fcm)) { + ret = PTR_ERR(cvnas_dev->rst_fcm); + goto err_get_reset_fcm; + } + + pm_runtime_enable(&pdev->dev); + + ret = nvcvnas_debugfs_init(cvnas_dev); + if (ret) { + dev_err(&pdev->dev, "debugfs init failed. ret=%d\n", ret); + goto err_cvnas_debugfs_init; + } + + cvnas_dev->pmops_busy = nvcvnas_busy; + cvnas_dev->pmops_idle = nvcvnas_idle; + + ret = nvmap_register_cvsram_carveout(&cvnas_dev->dma_dev, + cvnas_dev->cvsram_base, cvnas_dev->cvsram_size, + cvnas_dev->pmops_busy, cvnas_dev->pmops_idle); + if (ret) { + dev_err(&pdev->dev, + "nvmap cvsram register failed. ret=%d\n", ret); + goto err_cvsram_nvmap_heap_register; + } + + dev_set_drvdata(&pdev->dev, cvnas_dev); + + /* TODO: Add interrupt handler */ + + return 0; +err_cvsram_nvmap_heap_register: + debugfs_remove(cvnas_dev->debugfs_root); +err_cvnas_debugfs_init: +err_get_reset_fcm: +err_get_reset: +err_get_clk: +err_cvsram_get_reg_data: +err_cvsram_get_slice_data: + iounmap(cvnas_dev->hsm_iobase); +err_hsm_of_iomap: + iounmap(cvnas_dev->cvsram_iobase); +err_cvsram_of_iomap: + iounmap(cvnas_dev->cvreg_iobase); +err_of_iomap: + device_remove_file(&pdev->dev, cvnas_dev->attr); +err_device_create_file: + kfree(cvnas_dev); + return ret; +} + +static int nvcvnas_remove(struct platform_device *pdev) +{ + struct cvnas_device *cvnas_dev; + + cvnas_dev = dev_get_drvdata(&pdev->dev); + if (!cvnas_dev) + return -ENODEV; + + device_remove_file(&pdev->dev, cvnas_dev->attr); + debugfs_remove(cvnas_dev->debugfs_root); + of_reserved_mem_device_release(&pdev->dev); + iounmap(cvnas_dev->cvsram_iobase); + iounmap(cvnas_dev->cvreg_iobase); + kfree(cvnas_dev); + return 0; +} + +static void nvcvnas_shutdown(struct platform_device *pdev) +{ + struct cvnas_device *cvnas_dev; + int ret; + + if (pm_runtime_suspended(&pdev->dev)) + return; + + cvnas_dev = dev_get_drvdata(&pdev->dev); + if (!cvnas_dev) { + dev_err(&pdev->dev, "shutdown fail\n"); + return; + } + + ret = nvcvnas_power_off(cvnas_dev); + if (ret) + dev_err(&pdev->dev, "power off fail\n"); +} + +/* TODO: Add runtime power management */ +#ifdef CONFIG_PM_SLEEP +static int nvcvnas_suspend(struct device *dev) +{ + struct cvnas_device *cvnas_dev; + + cvnas_dev = dev_get_drvdata(dev); + if (!cvnas_dev) + return -ENODEV; + + return nvcvnas_power_off(cvnas_dev); +} + +static int nvcvnas_resume(struct device *dev) +{ + struct cvnas_device *cvnas_dev; + int ret; + + cvnas_dev = dev_get_drvdata(dev); + if (!cvnas_dev) { + dev_err(dev, "empty drvdata!\n"); + return -ENODEV; + } + + ret = nvcvnas_power_on(cvnas_dev); + if (ret) { + dev_err(dev, "cvnas power on failed\n"); + return ret; + } + return 0; +} + +static int nvcvnas_runtime_suspend(struct device *dev) +{ + nvcvnas_suspend(dev); + return 0; +} + +static int nvcvnas_runtime_resume(struct device *dev) +{ + nvcvnas_resume(dev); + return 0; +} + +static const struct dev_pm_ops nvcvnas_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(nvcvnas_runtime_suspend, + nvcvnas_runtime_resume, NULL) +}; + +#define NVCVNAS_PM_OPS (&nvcvnas_pm_ops) +#else +#define NVCVNAS_PM_OPS NULL +#endif + +/* Function to resume CV without using runtime pm. + * CVNOC register setting is required by CBB driver during resume to + * enable reporting CVNOC errors for illegal register accesses. + */ +int nvcvnas_busy_no_rpm(void) +{ +#ifdef CONFIG_PM_SLEEP + if (cvnas_plat_dev && dev_get_drvdata(&cvnas_plat_dev->dev)) + return nvcvnas_resume(&cvnas_plat_dev->dev); + else +#endif + return 0; +} +EXPORT_SYMBOL(nvcvnas_busy_no_rpm); + +/* + * Function to suspend CV without using runtime pm. + */ +int nvcvnas_idle_no_rpm(struct device *dev) +{ +#ifdef CONFIG_PM_SLEEP + if (cvnas_plat_dev && dev_get_drvdata(&cvnas_plat_dev->dev)) + return nvcvnas_suspend(&cvnas_plat_dev->dev); + else +#endif + return 0; +} +EXPORT_SYMBOL(nvcvnas_idle_no_rpm); + +static struct platform_driver nvcvnas_driver = { + .driver = { + .name = "tegra-cvnas", + .owner = THIS_MODULE, + .of_match_table = nvcvnas_of_ids, +#ifdef CONFIG_PM + .pm = NVCVNAS_PM_OPS, +#endif + }, + + .probe = nvcvnas_probe, + .remove = nvcvnas_remove, + .shutdown = nvcvnas_shutdown, +}; + +static int __init nvcvnas_init(void) +{ + int ret; + + ret = platform_driver_register(&nvcvnas_driver); + if (ret) + return ret; + + return 0; +} +module_init(nvcvnas_init); + +static void __exit nvcvnas_exit(void) +{ +} +module_exit(nvcvnas_exit); + +MODULE_LICENSE("GPL v2"); From 344d952e461b2b2c6a8c2f2692b72b55f8219b09 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 21 Dec 2021 10:29:52 +0000 Subject: [PATCH 04/14] platform: tegra: cvnas: Add support for upstream Linux kernels When building the CVNAS driver as an external module against upstream Linux kernels, there are some downstream fuse APIs that are not found. To fix building CVNAS for upstream kernels ... 1. Use the device-tree machine compatibility string instead of the downstream fuse function tegra_get_chip_id(). 2. For the functions tegra_platform_is_silicon() and tegra_platform_is_sim() add implementations in a fuse-helper.h that always assume that platform is silicon and not a simulator. Note this assumption is only applied to upstream kernels and downstream kernel still use the downstream implementation. Long term we need to revisit this. 3. Copy the downstream implementation for function tegra_get_sku_id() to the fuse-helper.h so that this is available for upstream kernels. The functions implemented in fuse-helper.h are only used if the compiler flag CONFIG_TEGRA_FUSE_UPSTREAM is defined. Bug 3459526 Change-Id: I5bbd08ac2560c236f932606ce5ad0e73dc71205a Signed-off-by: Jon Hunter Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2650491 Reviewed-by: Sachin Nikam --- drivers/platform/tegra/cvnas/Makefile | 4 ++++ drivers/platform/tegra/cvnas/cvnas.c | 10 +++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/platform/tegra/cvnas/Makefile b/drivers/platform/tegra/cvnas/Makefile index cf5d624b..df0c1fd3 100644 --- a/drivers/platform/tegra/cvnas/Makefile +++ b/drivers/platform/tegra/cvnas/Makefile @@ -8,4 +8,8 @@ ccflags-y += -I$(srctree.nvidia)/include ccflags-y += -Werror +ifeq ($(CONFIG_TEGRA_FUSE_UPSTREAM),y) +ccflags-y += -DCONFIG_TEGRA_FUSE_UPSTREAM +endif + obj-$(CONFIG_TEGRA_CVNAS) += cvnas.o diff --git a/drivers/platform/tegra/cvnas/cvnas.c b/drivers/platform/tegra/cvnas/cvnas.c index 4a4ceed8..8327645c 100644 --- a/drivers/platform/tegra/cvnas/cvnas.c +++ b/drivers/platform/tegra/cvnas/cvnas.c @@ -39,7 +39,7 @@ #if KERNEL_VERSION(4, 15, 0) > LINUX_VERSION_CODE #include #endif -#include +#include #include static int cvnas_debug; @@ -540,12 +540,8 @@ static int nvcvnas_probe(struct platform_device *pdev) u32 cvsram_reg_data[4]; const struct of_device_id *match; -#if KERNEL_VERSION(4, 15, 0) > LINUX_VERSION_CODE - if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA19 && -#else - if (tegra_get_chip_id() == TEGRA194 && -#endif - tegra_get_sku_id() == 0x9E) { + if (of_machine_is_compatible("nvidia,tegra194") && + tegra_get_sku_id() == 0x9E) { dev_err(&pdev->dev, "CVNAS IP is disabled in SKU.\n"); return -ENODEV; } From 2f44df7fa3bd96f4a4a154fd0f2bbc8c6be13ceb Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 21 Jan 2022 10:52:21 +0000 Subject: [PATCH 05/14] platform: tegra: cvnas: Simplify DT support The compatible string for CVNAS devices has been updated from "nvidia,tegra-cvnas" to "nvidia,tegra194-cvnas" to conform with the upstream policy of stating the actual device it is supported on. The 'nvidia,tegra-cvnas-hv' has been left as-is because this is a special case for virtualisation. The CVNAS driver is only support for Tegra194 devices and so it is not necessary to check the actual device variant, just the device SKU. Finally, instead of populating platform data in the device-tree table we can simply use the compatible string itself to detect if the device support virtualisation. Bug 3459526 Change-Id: I9755e8277892445b3e6772b8fa0b1960a34d90f4 Signed-off-by: Jon Hunter Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2657909 Reviewed-by: Puneet Saxena Reviewed-by: Sachin Nikam --- drivers/platform/tegra/cvnas/cvnas.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/platform/tegra/cvnas/cvnas.c b/drivers/platform/tegra/cvnas/cvnas.c index 8327645c..eae224e3 100644 --- a/drivers/platform/tegra/cvnas/cvnas.c +++ b/drivers/platform/tegra/cvnas/cvnas.c @@ -526,8 +526,8 @@ static ssize_t clk_cap_show(struct device *dev, } static const struct of_device_id nvcvnas_of_ids[] = { - { .compatible = "nvidia,tegra-cvnas", .data = (void *)false, }, - { .compatible = "nvidia,tegra-cvnas-hv", .data = (void *)true, }, + { .compatible = "nvidia,tegra194-cvnas", }, + { .compatible = "nvidia,tegra-cvnas-hv", }, { } }; MODULE_DEVICE_TABLE(of, nvcvnas_of_ids); @@ -538,10 +538,8 @@ static int nvcvnas_probe(struct platform_device *pdev) int ret; u32 cvsram_slice_data[2]; u32 cvsram_reg_data[4]; - const struct of_device_id *match; - if (of_machine_is_compatible("nvidia,tegra194") && - tegra_get_sku_id() == 0x9E) { + if (tegra_get_sku_id() == 0x9E) { dev_err(&pdev->dev, "CVNAS IP is disabled in SKU.\n"); return -ENODEV; } @@ -572,9 +570,8 @@ static int nvcvnas_probe(struct platform_device *pdev) goto err_device_create_file; } - match = of_match_device(nvcvnas_of_ids, &pdev->dev); - if (match) - cvnas_dev->virt = (bool)match->data; + if (of_device_is_compatible(pdev->dev.of_node, "nvidia,tegra-cvnas-hv")) + cvnas_dev->virt = true; cvnas_dev->cvreg_iobase = of_iomap(pdev->dev.of_node, 0); if (!cvnas_dev->cvreg_iobase) { From c920508259451874c48a452302188a1ed4219727 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 15 Feb 2022 10:12:32 +0000 Subject: [PATCH 06/14] platform: tegra: cvnas: Fix function declarations Sparse generates the following warnings for the CVNAS driver ... drivers/platform/tegra/cvnas/cvnas.c:126:5: warning: symbol 'nvcvnas_busy' was not declared. Should it be static? drivers/platform/tegra/cvnas/cvnas.c:138:5: warning: symbol 'nvcvnas_idle' was not declared. Should it be static? drivers/platform/tegra/cvnas/cvnas.c:444:13: warning: symbol 'nvcvnas_get_cvsram_base' was not declared. Should it be static? drivers/platform/tegra/cvnas/cvnas.c:456:8: warning: symbol 'nvcvnas_get_cvsram_size' was not declared. Should it be static? drivers/platform/tegra/cvnas/cvnas.c:468:5: warning: symbol 'is_nvcvnas_probed' was not declared. Should it be static? drivers/platform/tegra/cvnas/cvnas.c:476:5: warning: symbol 'is_nvcvnas_clk_enabled' was not declared. Should it be static? drivers/platform/tegra/cvnas/cvnas.c:779:5: warning: symbol 'nvcvnas_busy_no_rpm' was not declared. Should it be static? drivers/platform/tegra/cvnas/cvnas.c:793:5: warning: symbol 'nvcvnas_idle_no_rpm' was not declared. Should it be static? There are a few problems here which are: 1. The CVNAS driver does not include the 'cvnas.h' header file and so some of the declarations are not found. 2. Some of the CVNAS functions are not declared in the 'cvnas.h' header file and need to be added. 3. The Tegra19x CBB driver is a user of these CVNAS functions, but instead of including the 'cvnas.h' file it defines prototypes for these functions. This is not necessary and so we can remove these prototypes and simply include the 'cvnas.h' header file. 4. The function definition nvcvnas_idle_no_rpm() in the CVNAS driver is incorrect and this function should not have any arguments passed to it and currently does not match the prototype. Bug 3528414 Change-Id: I7945f8c66ceb5ca5b158b7ed1b81a50f19c52bb7 Signed-off-by: Jon Hunter Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2670149 Reviewed-by: Ketan Patil Reviewed-by: Sachin Nikam --- drivers/platform/tegra/cvnas/cvnas.c | 3 ++- include/linux/cvnas.h | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/platform/tegra/cvnas/cvnas.c b/drivers/platform/tegra/cvnas/cvnas.c index eae224e3..c3850d20 100644 --- a/drivers/platform/tegra/cvnas/cvnas.c +++ b/drivers/platform/tegra/cvnas/cvnas.c @@ -21,6 +21,7 @@ #define pr_fmt(fmt) "cvnas: %s,%d" fmt, __func__, __LINE__ #include +#include #include #include #include @@ -790,7 +791,7 @@ EXPORT_SYMBOL(nvcvnas_busy_no_rpm); /* * Function to suspend CV without using runtime pm. */ -int nvcvnas_idle_no_rpm(struct device *dev) +int nvcvnas_idle_no_rpm(void) { #ifdef CONFIG_PM_SLEEP if (cvnas_plat_dev && dev_get_drvdata(&cvnas_plat_dev->dev)) diff --git a/include/linux/cvnas.h b/include/linux/cvnas.h index a769106b..54b2d64f 100644 --- a/include/linux/cvnas.h +++ b/include/linux/cvnas.h @@ -3,7 +3,7 @@ * * Tegra cvnas driver * - * Copyright (c) 2018, NVIDIA Corporation. All rights reserved. + * Copyright (c) 2018-2022, NVIDIA Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,9 +20,15 @@ #ifndef __LINUX_CVNAS_H #define __LINUX_CVNAS_H +#include + int nvcvnas_busy(void); +int nvcvnas_busy_no_rpm(void); int nvcvnas_idle(void); +int nvcvnas_idle_no_rpm(void); +int is_nvcvnas_probed(void); phys_addr_t nvcvnas_get_cvsram_base(void); size_t nvcvnas_get_cvsram_size(void); +int is_nvcvnas_clk_enabled(void); #endif From 584a58b4b1f27195890b2339b540de2039ab07d2 Mon Sep 17 00:00:00 2001 From: Rajkumar Kasirajan Date: Tue, 8 Feb 2022 17:20:49 +0800 Subject: [PATCH 07/14] tegra: cvnas: set capped clock rate to max The CVNAS clock does not support dynamic frequency scaling and it is always expected to run at max rate. When its frequency is capped at runtime via clock_cap sysfs node, forcefully change current rate to capped max rate. Bug 3510538 Change-Id: I133865dbd8cfe58182dca3e6b2b969b99df393b0 Signed-off-by: Rajkumar Kasirajan Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2665653 --- drivers/platform/tegra/cvnas/cvnas.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/platform/tegra/cvnas/cvnas.c b/drivers/platform/tegra/cvnas/cvnas.c index c3850d20..51fdfaa8 100644 --- a/drivers/platform/tegra/cvnas/cvnas.c +++ b/drivers/platform/tegra/cvnas/cvnas.c @@ -490,6 +490,7 @@ static ssize_t clk_cap_store(struct device *dev, { struct cvnas_device *cvnas = dev_get_drvdata(dev); unsigned long max_rate; + long rounded_max_rate; int ret; ret = kstrtoul(buf, 0, &max_rate); @@ -501,12 +502,18 @@ static ssize_t clk_cap_store(struct device *dev, if (ret < 0) return ret; - max_rate = clk_round_rate(cvnas->clk, max_rate); - if (max_rate < 0) + rounded_max_rate = clk_round_rate(cvnas->clk, max_rate); + if (rounded_max_rate < 0) return -EINVAL; /* Apply new freq cap */ - ret = clk_set_max_rate(cvnas->clk, max_rate); + ret = clk_set_max_rate(cvnas->clk, (unsigned long) rounded_max_rate); + if (ret < 0) + return ret; + + /* No dynamic frequency scaling support for CVNAS clock. + * Set current rate to max */ + ret = clk_set_rate(cvnas->clk, (unsigned long) rounded_max_rate); if (ret < 0) return ret; From 3a872813533c0c46d809875d6b9b8d9c973f7b80 Mon Sep 17 00:00:00 2001 From: Ketan Patil Date: Wed, 9 Mar 2022 07:11:19 +0000 Subject: [PATCH 08/14] video: tegra: nvmap: Remove dependency of cvnas Handle dependencies between nvmap and cvnas driver: - nvmap_register_cvsram_carveout function is called by cvnas driver (builtin driver for 5.10) and it's definition is present in nvmap driver (builtin driver for 5.10, but we are trying to make LKM). This is resulting into build issues while making nvmap as LKM for 5.10 - One option to resolve this is by making cvnas driver as LKM for 5.10 But nvhost, nvdla, cbb are not LKM for 5.10 and are calling functions defined in cvnas driver e.g. nvcvnas_get_cvsram_base, hence we can't make cvnas as LKM for 5.10 - Second option is to get rid of the call nvmap_register_cvsram_carveout from cvnas driver. This approach is implemented in this patch. - Export cvnas_dev from cvnas driver, do not call the above function from cvnas driver. During nvmap probe, nvmap itself would call the above function, as cvnas_dev is exported , it's being used in nvmap driver to get base, size etc. information, which is needed as argument to above function, which will register the cvnas carveout in case of 5.10 Bug 200722684 Change-Id: I32e5694386de4a7fef65c3f67ffb9b5066f62ab3 Signed-off-by: Ketan Patil Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2678685 --- drivers/platform/tegra/cvnas/Makefile | 3 +++ drivers/platform/tegra/cvnas/cvnas.c | 35 ++++++--------------------- include/linux/cvnas.h | 27 +++++++++++++++++++++ 3 files changed, 38 insertions(+), 27 deletions(-) diff --git a/drivers/platform/tegra/cvnas/Makefile b/drivers/platform/tegra/cvnas/Makefile index df0c1fd3..0e225fcf 100644 --- a/drivers/platform/tegra/cvnas/Makefile +++ b/drivers/platform/tegra/cvnas/Makefile @@ -13,3 +13,6 @@ ccflags-y += -DCONFIG_TEGRA_FUSE_UPSTREAM endif obj-$(CONFIG_TEGRA_CVNAS) += cvnas.o +ifeq ($(CONFIG_TEGRA_CVNAS),m) +ccflags-y += -DCVNAS_MODULE +endif diff --git a/drivers/platform/tegra/cvnas/cvnas.c b/drivers/platform/tegra/cvnas/cvnas.c index 51fdfaa8..ed85a800 100644 --- a/drivers/platform/tegra/cvnas/cvnas.c +++ b/drivers/platform/tegra/cvnas/cvnas.c @@ -80,31 +80,10 @@ static bool cvnas_rail; #define HSM_CVSRAM_ECC_DED_MASK_0 0x80000000 #define HSM_CVSRAM_ECC_DED_MASK_1 0x00000007 -struct cvnas_device { - struct dentry *debugfs_root; - - void __iomem *cvsram_iobase; - void __iomem *cvreg_iobase; - void __iomem *hsm_iobase; - - struct device dma_dev; - - int nslices; - int slice_size; - phys_addr_t cvsram_base; - size_t cvsram_size; - - struct clk *clk; - struct device_attribute *attr; - - struct reset_control *rst; - struct reset_control *rst_fcm; - - bool virt; - - int (*pmops_busy)(void); - int (*pmops_idle)(void); -}; +struct cvnas_device *cvnas_dev; +#ifndef CVNAS_MODULE +EXPORT_SYMBOL(cvnas_dev); +#endif /* !CVNAS_MODULE */ static struct platform_device *cvnas_plat_dev; @@ -542,7 +521,6 @@ MODULE_DEVICE_TABLE(of, nvcvnas_of_ids); static int nvcvnas_probe(struct platform_device *pdev) { - struct cvnas_device *cvnas_dev; int ret; u32 cvsram_slice_data[2]; u32 cvsram_reg_data[4]; @@ -654,6 +632,7 @@ static int nvcvnas_probe(struct platform_device *pdev) cvnas_dev->pmops_busy = nvcvnas_busy; cvnas_dev->pmops_idle = nvcvnas_idle; +#ifdef CVNAS_MODULE ret = nvmap_register_cvsram_carveout(&cvnas_dev->dma_dev, cvnas_dev->cvsram_base, cvnas_dev->cvsram_size, cvnas_dev->pmops_busy, cvnas_dev->pmops_idle); @@ -662,14 +641,16 @@ static int nvcvnas_probe(struct platform_device *pdev) "nvmap cvsram register failed. ret=%d\n", ret); goto err_cvsram_nvmap_heap_register; } - +#endif /* CVNAS_MODULE */ dev_set_drvdata(&pdev->dev, cvnas_dev); /* TODO: Add interrupt handler */ return 0; +#ifdef CVNAS_MODULE err_cvsram_nvmap_heap_register: debugfs_remove(cvnas_dev->debugfs_root); +#endif /* CVNAS_MODULE */ err_cvnas_debugfs_init: err_get_reset_fcm: err_get_reset: diff --git a/include/linux/cvnas.h b/include/linux/cvnas.h index 54b2d64f..d89bf6be 100644 --- a/include/linux/cvnas.h +++ b/include/linux/cvnas.h @@ -21,6 +21,33 @@ #define __LINUX_CVNAS_H #include +#include + +struct cvnas_device { + struct dentry *debugfs_root; + + void __iomem *cvsram_iobase; + void __iomem *cvreg_iobase; + void __iomem *hsm_iobase; + + struct device dma_dev; + + int nslices; + int slice_size; + phys_addr_t cvsram_base; + size_t cvsram_size; + + struct clk *clk; + struct device_attribute *attr; + + struct reset_control *rst; + struct reset_control *rst_fcm; + + bool virt; + + int (*pmops_busy)(void); + int (*pmops_idle)(void); +}; int nvcvnas_busy(void); int nvcvnas_busy_no_rpm(void); From 242600283f0083f0ba657aa1c00d718d7845ea7a Mon Sep 17 00:00:00 2001 From: Ketan Patil Date: Fri, 29 Apr 2022 03:48:02 +0000 Subject: [PATCH 09/14] video: tegra: nvmap: Do not export cvnas_dev By exporting cvnas_dev all the internal data of the driver is getting exposed to any driver that uses it. This could allow drivers to corrupt this driver data. Hence do not export cvnas_dev, use helper functions to get it's required member elements from nvmap. Bug 200722684 Bug 3528414 Change-Id: I17f6fa1e98c777a7ec9118dbc6f0c6359e949f22 Signed-off-by: Ketan Patil Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2704698 Reviewed-by: Puneet Saxena Reviewed-by: Jonathan Hunter Reviewed-by: Sachin Nikam --- drivers/platform/tegra/cvnas/cvnas.c | 30 ++++++++++++++++++++++++---- include/linux/cvnas.h | 27 ------------------------- 2 files changed, 26 insertions(+), 31 deletions(-) diff --git a/drivers/platform/tegra/cvnas/cvnas.c b/drivers/platform/tegra/cvnas/cvnas.c index ed85a800..d9fce5cb 100644 --- a/drivers/platform/tegra/cvnas/cvnas.c +++ b/drivers/platform/tegra/cvnas/cvnas.c @@ -80,10 +80,31 @@ static bool cvnas_rail; #define HSM_CVSRAM_ECC_DED_MASK_0 0x80000000 #define HSM_CVSRAM_ECC_DED_MASK_1 0x00000007 -struct cvnas_device *cvnas_dev; -#ifndef CVNAS_MODULE -EXPORT_SYMBOL(cvnas_dev); -#endif /* !CVNAS_MODULE */ +struct cvnas_device { + struct dentry *debugfs_root; + + void __iomem *cvsram_iobase; + void __iomem *cvreg_iobase; + void __iomem *hsm_iobase; + + struct device dma_dev; + + int nslices; + int slice_size; + phys_addr_t cvsram_base; + size_t cvsram_size; + + struct clk *clk; + struct device_attribute *attr; + + struct reset_control *rst; + struct reset_control *rst_fcm; + + bool virt; + + int (*pmops_busy)(void); + int (*pmops_idle)(void); +}; static struct platform_device *cvnas_plat_dev; @@ -521,6 +542,7 @@ MODULE_DEVICE_TABLE(of, nvcvnas_of_ids); static int nvcvnas_probe(struct platform_device *pdev) { + struct cvnas_device *cvnas_dev; int ret; u32 cvsram_slice_data[2]; u32 cvsram_reg_data[4]; diff --git a/include/linux/cvnas.h b/include/linux/cvnas.h index d89bf6be..54b2d64f 100644 --- a/include/linux/cvnas.h +++ b/include/linux/cvnas.h @@ -21,33 +21,6 @@ #define __LINUX_CVNAS_H #include -#include - -struct cvnas_device { - struct dentry *debugfs_root; - - void __iomem *cvsram_iobase; - void __iomem *cvreg_iobase; - void __iomem *hsm_iobase; - - struct device dma_dev; - - int nslices; - int slice_size; - phys_addr_t cvsram_base; - size_t cvsram_size; - - struct clk *clk; - struct device_attribute *attr; - - struct reset_control *rst; - struct reset_control *rst_fcm; - - bool virt; - - int (*pmops_busy)(void); - int (*pmops_idle)(void); -}; int nvcvnas_busy(void); int nvcvnas_busy_no_rpm(void); From eda8327741cc8ba34beba10f9e03601bea62468a Mon Sep 17 00:00:00 2001 From: Bharat Nihalani Date: Wed, 4 May 2022 11:31:55 +0530 Subject: [PATCH 10/14] include: Fix cvnas build errors Fix cvnas build errors when CONFIG_TEGRA_CVNAS is disabled. The following build errors are fixed: nvhost_buffer.c:134: undefined reference to `nvcvnas_get_cvsram_base' nvhost_buffer.c:135: undefined reference to `nvcvnas_get_cvsram_size' Bug 3633940 Change-Id: I3f42bb9a0f5d833a70fd05c494fdbbcaab60be1e Signed-off-by: Bharat Nihalani Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2706940 Reviewed-by: Ketan Patil Reviewed-by: Sachin Nikam --- include/linux/cvnas.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/include/linux/cvnas.h b/include/linux/cvnas.h index 54b2d64f..956b993b 100644 --- a/include/linux/cvnas.h +++ b/include/linux/cvnas.h @@ -22,6 +22,7 @@ #include +#if defined(CONFIG_TEGRA_CVNAS) || defined(CVNAS_MODULE) int nvcvnas_busy(void); int nvcvnas_busy_no_rpm(void); int nvcvnas_idle(void); @@ -30,5 +31,15 @@ int is_nvcvnas_probed(void); phys_addr_t nvcvnas_get_cvsram_base(void); size_t nvcvnas_get_cvsram_size(void); int is_nvcvnas_clk_enabled(void); +#else +static inline int nvcvnas_busy(void) { return 0; } +static inline int nvcvnas_busy_no_rpm(void) { return 0; } +static inline int nvcvnas_idle(void) { return 0; } +static inline int nvcvnas_idle_no_rpm(void) { return 0; } +static inline int is_nvcvnas_probed(void) { return 0; } +static inline phys_addr_t nvcvnas_get_cvsram_base(void) { return 0; } +static inline size_t nvcvnas_get_cvsram_size(void) { return 0; } +static inline int is_nvcvnas_clk_enabled(void) { return 0; } +#endif /* CONFIG_TEGRA_CVNAS || CVNAS_MODULE */ -#endif +#endif /* __LINUX_CVNAS_H */ From cb92d33b4e86db0c569a59215a5cc232467f8b68 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 20 May 2022 06:32:17 +0000 Subject: [PATCH 11/14] cvnas: Set config variable when build as OOT module When cvnas driver is build as OOT module, it is required to set the following config. CONFIG_TEGRA_FUSE_UPSTREAM CONFIG_TEGRA_CVNAS Set these config when CONFIG_TEGRA_OOT_MODULE is set. Bug 3583599 Change-Id: I8deffa609cfc7abf6c9efd69405295077649c8b1 Signed-off-by: Laxman Dewangan Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2715735 Reviewed-by: Bitan Biswas --- drivers/platform/tegra/cvnas/Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/platform/tegra/cvnas/Makefile b/drivers/platform/tegra/cvnas/Makefile index 0e225fcf..48ccb0a4 100644 --- a/drivers/platform/tegra/cvnas/Makefile +++ b/drivers/platform/tegra/cvnas/Makefile @@ -8,6 +8,12 @@ ccflags-y += -I$(srctree.nvidia)/include ccflags-y += -Werror +# Set config when build as OOT module. +ifeq ($(CONFIG_TEGRA_OOT_MODULE),m) +CONFIG_TEGRA_FUSE_UPSTREAM := y +CONFIG_TEGRA_CVNAS := m +endif + ifeq ($(CONFIG_TEGRA_FUSE_UPSTREAM),y) ccflags-y += -DCONFIG_TEGRA_FUSE_UPSTREAM endif From 659ad2b6eeec997d91a94dacfb3a205b93d50a53 Mon Sep 17 00:00:00 2001 From: Sagar Gulab Patil Date: Fri, 1 Jul 2022 12:19:14 +0000 Subject: [PATCH 12/14] tegra: cvnas: Fix Cert-C error handling bug In function nvcvnas_probe casting cvsram_slice_data[0] from unsigned int to int without checking its value may result in lost or misinterpreted data. Fix this by changing data type of variable. ID 490074 Bug 3512545 Change-Id: Ia9f141f14a540f9c2c436bf605d4aec8f3489fb5 Signed-off-by: Sagar Gulab Patil Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2738506 Reviewed-by: Sachin Nikam --- drivers/platform/tegra/cvnas/cvnas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/tegra/cvnas/cvnas.c b/drivers/platform/tegra/cvnas/cvnas.c index d9fce5cb..911dadbc 100644 --- a/drivers/platform/tegra/cvnas/cvnas.c +++ b/drivers/platform/tegra/cvnas/cvnas.c @@ -89,7 +89,7 @@ struct cvnas_device { struct device dma_dev; - int nslices; + u32 nslices; int slice_size; phys_addr_t cvsram_base; size_t cvsram_size; From 59f352a819056b46f3aff4c31c9ca212cefc723f Mon Sep 17 00:00:00 2001 From: Sagar Gulab Patil Date: Tue, 19 Jul 2022 06:44:19 +0000 Subject: [PATCH 13/14] tegra: cvnas: Fix Cert-C error handling bug In function nvcvnas_power_off casting nvcvsram_readl from unsigned int to int without checking its value may result in lost or misinterpreted data. Fix this by changing data type of val to u32. CID 427418 Bug 3512545 Change-Id: I8be65b1ca73270a4a0d76380207078da745c7057 Signed-off-by: Sagar Gulab Patil Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2747340 Reviewed-by: Sachin Nikam --- drivers/platform/tegra/cvnas/cvnas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/tegra/cvnas/cvnas.c b/drivers/platform/tegra/cvnas/cvnas.c index 911dadbc..30ec99b7 100644 --- a/drivers/platform/tegra/cvnas/cvnas.c +++ b/drivers/platform/tegra/cvnas/cvnas.c @@ -408,7 +408,7 @@ err_enable_clk: static int nvcvnas_power_off(struct cvnas_device *cvnas_dev) { - int val, i, j; + u32 val, i, j; u32 fcm_pg_seq[] = {0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF}; From 300ceb3ea22a5d12aafd973822450d446577619f Mon Sep 17 00:00:00 2001 From: Ketan Patil Date: Thu, 15 Dec 2022 11:52:41 +0000 Subject: [PATCH 14/14] tegra: cvnas: Fix type casting issue CERT-C is reporting following issue: - Casting cvsram_slice_data[1] from unsigned int to int without checking its value may result in lost or misinterpreted data. Fix this by changing the data type of slice_size. CID 490074 Bug 3745813 Change-Id: Ic52fd016798310b69da69247a6eb2d7a626a4146 Signed-off-by: Ketan Patil Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2828530 Reviewed-by: Sachin Nikam --- drivers/platform/tegra/cvnas/cvnas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/tegra/cvnas/cvnas.c b/drivers/platform/tegra/cvnas/cvnas.c index 30ec99b7..e4e0e8ab 100644 --- a/drivers/platform/tegra/cvnas/cvnas.c +++ b/drivers/platform/tegra/cvnas/cvnas.c @@ -90,7 +90,7 @@ struct cvnas_device { struct device dma_dev; u32 nslices; - int slice_size; + u32 slice_size; phys_addr_t cvsram_base; size_t cvsram_size;