From 47b40e9b56a3f1fd6b0336609dd586d24f7c1fd2 Mon Sep 17 00:00:00 2001 From: Arvind M Date: Mon, 11 Nov 2024 14:54:18 +0000 Subject: [PATCH] nvdla: kmd: enable syncpoint emulator dependency - Adds syncpt emulator wrapper class for axi-nvdla.ko module - Fixes minor bugs - The behavior of SHIM write differs between the nvhost syncpoint and nvhost-emu. The DLA KMD accommodates the same. - For the simulator, there is no proper management for loading and unloading the firmware. This will lead to a undefined behavior. This commit fixes the issue through use of refcnt. - The RISCV will be in halted state and will continue from where it left off. Due to a security configuration, the DLA cannot reload the firmware again and again after booting the system. As a WAR, the simulator avoids reloading the IMEM and DMEM. Raised a Bug 4960393 to provide a proper fix and work around is protected using macro BUG_4960393=1 - The FPGA is always considered on. Raised a Bug 4972382 to enable power management and work around to skip the power operation through macro BUG_4972382=1 Bug 4942853 Change-Id: I0bf0262d6fde3b3da47f040c493d915ae6a1f98a Signed-off-by: Arvind M Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3248734 Reviewed-by: Vishal Thoke Reviewed-by: Ken Adams GVS: buildbot_gerritrpt Reviewed-by: Mitch Harwell Reviewed-by: Amit Sharma (SW-TEGRA) --- drivers/video/tegra/host/nvdla/Makefile | 3 + drivers/video/tegra/host/nvdla/axi/Makefile | 7 +- drivers/video/tegra/host/nvdla/dla_queue.c | 2 +- drivers/video/tegra/host/nvdla/nvdla.h | 1 + .../video/tegra/host/nvdla/nvdla_cg_regs.h | 8 +- drivers/video/tegra/host/nvdla/nvdla_debug.c | 2 +- drivers/video/tegra/host/nvdla/nvdla_debug.h | 7 +- drivers/video/tegra/host/nvdla/nvdla_ioctl.c | 2 +- drivers/video/tegra/host/nvdla/nvdla_queue.c | 5 + drivers/video/tegra/host/nvdla/nvdla_t194.h | 2 +- drivers/video/tegra/host/nvdla/nvdla_t234.h | 2 +- drivers/video/tegra/host/nvdla/nvdla_t25x.h | 21 +- .../video/tegra/host/nvdla/nvdla_t264_sim.h | 10 +- .../host/nvdla/port/device/nvdla_device_axi.c | 60 ++-- .../tegra/host/nvdla/port/fw/nvdla_fw_flcn.c | 2 +- .../tegra/host/nvdla/port/fw/nvdla_fw_riscv.c | 64 ++++- .../host/nvdla/port/fw/nvdla_fw_riscv_reg.h | 12 + .../host/nvdla/port/nvdla_host_wrapper.h | 26 ++ .../host/nvdla/port/sync/nvdla_sync_syncpt.c | 2 +- .../nvdla/port/sync/nvdla_sync_syncpt_emu.c | 259 ++++++++++++++++++ 20 files changed, 426 insertions(+), 71 deletions(-) create mode 100644 drivers/video/tegra/host/nvdla/port/nvdla_host_wrapper.h create mode 100644 drivers/video/tegra/host/nvdla/port/sync/nvdla_sync_syncpt_emu.c diff --git a/drivers/video/tegra/host/nvdla/Makefile b/drivers/video/tegra/host/nvdla/Makefile index 1a56b416..99677468 100644 --- a/drivers/video/tegra/host/nvdla/Makefile +++ b/drivers/video/tegra/host/nvdla/Makefile @@ -30,4 +30,7 @@ nvhost-nvdla-objs += dla_channel.o endif obj-m += nvhost-nvdla.o + +ifeq ($(NV_BUILD_CONFIGURATION_EXPOSING_T26X), 1) obj-m += axi/ +endif diff --git a/drivers/video/tegra/host/nvdla/axi/Makefile b/drivers/video/tegra/host/nvdla/axi/Makefile index 4c4e8f6a..8d58f8a8 100644 --- a/drivers/video/tegra/host/nvdla/axi/Makefile +++ b/drivers/video/tegra/host/nvdla/axi/Makefile @@ -15,6 +15,9 @@ ccflags-y += -I$(srctree.nvidia-oot)/drivers/video/tegra/host/nvdla ccflags-y += -I$(srctree.nvidia-oot)/drivers/video/tegra/host/nvdla/port/fw endif +LINUXINCLUDE += -I$(srctree.nvidia-oot)/drivers/gpu/host1x-emu/include +ccflags-y += -DCONFIG_TEGRA_HOST1X_EMU_DBG_SYMBL + # # axi-nvdla.ko # @@ -23,12 +26,14 @@ ccflags-y += -DNVDLA_HAVE_CONFIG_AXI=1 ccflags-y += -DNVDLA_HAVE_CONFIG_SYNCPTFD=0 ccflags-y += -DNVDLA_HAVE_CONFIG_HSIERRINJ=0 ccflags-y += -DBUG_4942853=1 +ccflags-y += -DBUG_4960393=1 +ccflags-y += -DBUG_4972382=1 NVDLA_OBJS := \ $(NVDLA_COMMON_OBJS) \ port/device/nvdla_device_axi.o \ port/fw/nvdla_fw_riscv.o \ - port/sync/nvdla_sync_stub.o + port/sync/nvdla_sync_syncpt_emu.o # Duplicate source file for forcing compilation. NVDLA_OBJS := $(addprefix $(NVDLA_TOP)/,$(NVDLA_OBJS)) diff --git a/drivers/video/tegra/host/nvdla/dla_queue.c b/drivers/video/tegra/host/nvdla/dla_queue.c index 031f3e9a..923dc2f3 100644 --- a/drivers/video/tegra/host/nvdla/dla_queue.c +++ b/drivers/video/tegra/host/nvdla/dla_queue.c @@ -13,7 +13,7 @@ #include #include -#include +#include "port/nvdla_host_wrapper.h" #if IS_ENABLED(CONFIG_TEGRA_NVDLA_CHANNEL) #include "nvhost_job.h" diff --git a/drivers/video/tegra/host/nvdla/nvdla.h b/drivers/video/tegra/host/nvdla/nvdla.h index 7217ae20..7693184c 100644 --- a/drivers/video/tegra/host/nvdla/nvdla.h +++ b/drivers/video/tegra/host/nvdla/nvdla.h @@ -71,6 +71,7 @@ enum { NV_DLA0_CLASS_ID = 0xF3, NV_DLA1_CLASS_ID = 0xF4, NV_DLA0_SIM_CLASS_ID = 0xF5, + NV_DLA1_SIM_CLASS_ID = 0xF6, }; /** diff --git a/drivers/video/tegra/host/nvdla/nvdla_cg_regs.h b/drivers/video/tegra/host/nvdla/nvdla_cg_regs.h index f10d8b5e..62856cc2 100644 --- a/drivers/video/tegra/host/nvdla/nvdla_cg_regs.h +++ b/drivers/video/tegra/host/nvdla/nvdla_cg_regs.h @@ -1,12 +1,12 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2022-2023, NVIDIA Corporation. All rights reserved. +/* SPDX-License-Identifier: LicenseRef-NvidiaProprietary */ +/* SPDX-FileCopyrightText: Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * */ #ifndef __NVHOST_NVDLA_CG_REGS_H__ #define __NVHOST_NVDLA_CG_REGS_H__ -#include +#include "port/nvdla_host_wrapper.h" static struct nvhost_gating_register __attribute__((__unused__)) nvdla_gating_registers[] = { diff --git a/drivers/video/tegra/host/nvdla/nvdla_debug.c b/drivers/video/tegra/host/nvdla/nvdla_debug.c index 3eeb848a..180a99df 100644 --- a/drivers/video/tegra/host/nvdla/nvdla_debug.c +++ b/drivers/video/tegra/host/nvdla/nvdla_debug.c @@ -6,7 +6,7 @@ #include #include -#include +#include "port/nvdla_host_wrapper.h" #include #include #include diff --git a/drivers/video/tegra/host/nvdla/nvdla_debug.h b/drivers/video/tegra/host/nvdla/nvdla_debug.h index 5df9a5b6..64720094 100644 --- a/drivers/video/tegra/host/nvdla/nvdla_debug.h +++ b/drivers/video/tegra/host/nvdla/nvdla_debug.h @@ -1,6 +1,5 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2016-2023, NVIDIA Corporation. All rights reserved. +/* SPDX-License-Identifier: LicenseRef-NvidiaProprietary */ +/* SPDX-FileCopyrightText: Copyright (c) 2016-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * * NVDLA debug utils header */ @@ -10,7 +9,7 @@ #include #include -#include +#include "port/nvdla_host_wrapper.h" #include "nvdla.h" diff --git a/drivers/video/tegra/host/nvdla/nvdla_ioctl.c b/drivers/video/tegra/host/nvdla/nvdla_ioctl.c index 4243af08..cdfa35ed 100644 --- a/drivers/video/tegra/host/nvdla/nvdla_ioctl.c +++ b/drivers/video/tegra/host/nvdla/nvdla_ioctl.c @@ -1354,7 +1354,7 @@ static int nvdla_release(struct inode *inode, struct file *file) } nvdla_buffer_release(priv->buffers); - nvhost_module_remove_client(pdev, priv); + nvdla_module_client_unregister(pdev, priv); kfree(priv); return 0; diff --git a/drivers/video/tegra/host/nvdla/nvdla_queue.c b/drivers/video/tegra/host/nvdla/nvdla_queue.c index 056cc7f4..d0e5d0b6 100644 --- a/drivers/video/tegra/host/nvdla/nvdla_queue.c +++ b/drivers/video/tegra/host/nvdla/nvdla_queue.c @@ -728,8 +728,13 @@ static int nvdla_fill_signal_fence_action(struct nvdla_task *task, /* For postaction also update MSS addr */ syncpt_addr = nvdla_sync_get_address(queue->sync_context); +#if defined(NVDLA_HAVE_CONFIG_AXI) && (NVDLA_HAVE_CONFIG_AXI == 1) + next = add_fence_action(next, ACTION_INCREMENT_SEM, + syncpt_addr, 1); +#else next = add_fence_action(next, ACTION_WRITE_SEM, syncpt_addr, 1); +#endif /* NVDLA_HAVE_CONFIG_AXI */ task->fence_counter = task->fence_counter + 1; diff --git a/drivers/video/tegra/host/nvdla/nvdla_t194.h b/drivers/video/tegra/host/nvdla/nvdla_t194.h index ec02e164..c3909ee9 100644 --- a/drivers/video/tegra/host/nvdla/nvdla_t194.h +++ b/drivers/video/tegra/host/nvdla/nvdla_t194.h @@ -7,7 +7,7 @@ #ifndef __NVHOST_NVDLA_T194_H__ #define __NVHOST_NVDLA_T194_H__ -#include +#include "port/nvdla_host_wrapper.h" #include #include "nvdla.h" diff --git a/drivers/video/tegra/host/nvdla/nvdla_t234.h b/drivers/video/tegra/host/nvdla/nvdla_t234.h index bc932af4..10310d81 100644 --- a/drivers/video/tegra/host/nvdla/nvdla_t234.h +++ b/drivers/video/tegra/host/nvdla/nvdla_t234.h @@ -7,7 +7,7 @@ #ifndef __NVHOST_NVDLA_T234_H__ #define __NVHOST_NVDLA_T234_H__ -#include +#include "port/nvdla_host_wrapper.h" #include #include "nvdla.h" diff --git a/drivers/video/tegra/host/nvdla/nvdla_t25x.h b/drivers/video/tegra/host/nvdla/nvdla_t25x.h index fe0b2764..bf2d74d2 100644 --- a/drivers/video/tegra/host/nvdla/nvdla_t25x.h +++ b/drivers/video/tegra/host/nvdla/nvdla_t25x.h @@ -7,20 +7,19 @@ #ifndef __NVHOST_NVDLA_T25X_H__ #define __NVHOST_NVDLA_T25X_H__ -#include +#include "port/nvdla_host_wrapper.h" #include #include "nvdla.h" #include "dla_t25x_fw_version.h" -/* REVISIT the registers */ -static struct nvhost_gating_register nvdla_t25x_gating_registers[] = { - {} -}; - static struct nvhost_device_data t25x_nvdla0_info = { .devfs_name_family = "nvdla", +#if defined(BUG_4972382) && (BUG_4972382 == 1) + .class = NV_DLA0_SIM_CLASS_ID, +#else .class = NV_DLA0_CLASS_ID, +#endif /* BUG_4972382 */ .clocks = { {"nvdla0", UINT_MAX}, {"nvdla0_flcn", UINT_MAX} @@ -40,8 +39,7 @@ static struct nvhost_device_data t25x_nvdla0_info = { .ctrl_ops = &tegra_nvdla_ctrl_ops, .get_reloc_phys_addr = NULL, .module_irq = 1, - .engine_cg_regs = nvdla_t25x_gating_registers, - .engine_can_cg = true, + .engine_can_cg = false, .can_powergate = true, .icc_id = TEGRA_ICC_DLA_0, .transcfg_addr = 0x0444, @@ -51,7 +49,11 @@ static struct nvhost_device_data t25x_nvdla0_info = { static struct nvhost_device_data t25x_nvdla1_info = { .devfs_name_family = "nvdla", +#if defined(BUG_4972382) && (BUG_4972382 == 1) + .class = NV_DLA1_SIM_CLASS_ID, +#else .class = NV_DLA1_CLASS_ID, +#endif /* BUG_4972382 */ .clocks = { {"nvdla1", UINT_MAX}, {"nvdla1_flcn", UINT_MAX} @@ -71,8 +73,7 @@ static struct nvhost_device_data t25x_nvdla1_info = { .ctrl_ops = &tegra_nvdla_ctrl_ops, .get_reloc_phys_addr = NULL, .module_irq = 1, - .engine_cg_regs = nvdla_t25x_gating_registers, - .engine_can_cg = true, + .engine_can_cg = false, .can_powergate = true, .icc_id = TEGRA_ICC_DLA_1, .transcfg_addr = 0x0444, diff --git a/drivers/video/tegra/host/nvdla/nvdla_t264_sim.h b/drivers/video/tegra/host/nvdla/nvdla_t264_sim.h index 2cf34651..e8a92707 100644 --- a/drivers/video/tegra/host/nvdla/nvdla_t264_sim.h +++ b/drivers/video/tegra/host/nvdla/nvdla_t264_sim.h @@ -7,17 +7,12 @@ #ifndef __NVHOST_NVDLA_T264_SIM_H__ #define __NVHOST_NVDLA_T264_SIM_H__ -#include +#include "port/nvdla_host_wrapper.h" #include #include "nvdla.h" #include "dla_t25x_fw_version.h" -/* REVISIT the registers */ -static struct nvhost_gating_register nvdla_t264_gating_registers[] = { - {} -}; - static struct nvhost_device_data t264_sim_nvdla0_info = { .devfs_name_family = "nvdla", .class = NV_DLA0_SIM_CLASS_ID, @@ -40,8 +35,7 @@ static struct nvhost_device_data t264_sim_nvdla0_info = { .ctrl_ops = &tegra_nvdla_ctrl_ops, .get_reloc_phys_addr = NULL, .module_irq = 1, - .engine_cg_regs = nvdla_t264_gating_registers, - .engine_can_cg = true, + .engine_can_cg = false, .can_powergate = true, .icc_id = TEGRA_ICC_DLA_0, .transcfg_addr = 0x0444, diff --git a/drivers/video/tegra/host/nvdla/port/device/nvdla_device_axi.c b/drivers/video/tegra/host/nvdla/port/device/nvdla_device_axi.c index 1c40e3d1..fa5bbaaf 100644 --- a/drivers/video/tegra/host/nvdla/port/device/nvdla_device_axi.c +++ b/drivers/video/tegra/host/nvdla/port/device/nvdla_device_axi.c @@ -14,13 +14,15 @@ #include #include #include -#include +#include #include #include #include #define NVDLA_NUM_CDEV 1 +static uint32_t s_powerref; + uint32_t nvdla_device_register_read(struct platform_device *pdev, uint32_t reg) { @@ -47,6 +49,13 @@ static int32_t s_nvdla_module_get_platform_resources( struct nvhost_device_data *pdata = platform_get_drvdata(pdev); int32_t i; + pdata->host1x = HOST1X_EMU_EXPORT_CALL(nvhost_get_host1x(pdev)); + if (pdata->host1x == NULL) { + nvdla_dbg_err(pdev, "Failed to get private data\n"); + err = -ENODEV; + goto fail; + } + /* Get resources. */ for (i = 0; i < pdev->num_resources; i++) { void __iomem *regs = NULL; @@ -79,7 +88,8 @@ static int32_t s_nvdla_module_pm_enable(struct platform_device *pdev) struct nvhost_device_data *pdata = platform_get_drvdata(pdev); uint32_t i; - if (pdata->class == NV_DLA0_SIM_CLASS_ID) { + if ((pdata->class == NV_DLA0_SIM_CLASS_ID) || + (pdata->class == NV_DLA1_SIM_CLASS_ID)) { nvdla_dbg_warn(pdev, "skipping PM for simulator\n"); err = 0; goto fail; @@ -149,7 +159,8 @@ static void s_nvdla_module_pm_disable(struct platform_device *pdev) { struct nvhost_device_data *pdata = platform_get_drvdata(pdev); - if (pdata->class == NV_DLA0_SIM_CLASS_ID) { + if ((pdata->class == NV_DLA0_SIM_CLASS_ID) || + (pdata->class == NV_DLA1_SIM_CLASS_ID)) { nvdla_dbg_warn(pdev, "skipping PM for simulator\n"); goto fail; } @@ -306,14 +317,16 @@ int32_t nvdla_module_busy(struct platform_device *pdev) struct nvhost_device_data *pdata = platform_get_drvdata(pdev); - if (pdata->class == NV_DLA0_SIM_CLASS_ID) { + if ((pdata->class == NV_DLA0_SIM_CLASS_ID) || + (pdata->class == NV_DLA1_SIM_CLASS_ID)) { err = 0; nvdla_dbg_warn(pdev, "skipping PM for simulator\n"); nvdla_module_load_regs(pdev, pdata->engine_can_cg); - if (pdata->finalize_poweron) + s_powerref++; + if (pdata->finalize_poweron && (s_powerref == 1U)) err = pdata->finalize_poweron(pdev); goto fail; @@ -342,10 +355,18 @@ void nvdla_module_idle_mult(struct platform_device *pdev, int32_t refs) { struct nvhost_device_data *pdata = platform_get_drvdata(pdev); - if (pdata->class == NV_DLA0_SIM_CLASS_ID) { - nvdla_dbg_warn(pdev, "skipping PM for simulator\n"); + if (refs == 0) + goto fail; - if (pdata->prepare_poweroff) + if ((pdata->class == NV_DLA0_SIM_CLASS_ID) || + (pdata->class == NV_DLA1_SIM_CLASS_ID)) { + nvdla_dbg_warn(pdev, "skipping PM for simulator\n"); + if (s_powerref >= refs) + s_powerref -= refs; + else + s_powerref = 0U; + + if (pdata->prepare_poweroff && (s_powerref == 0U)) pdata->prepare_poweroff(pdev); goto fail; @@ -365,21 +386,8 @@ fail: static void nvdla_module_load_regs(struct platform_device *pdev, bool prod) { - struct nvhost_device_data *pdata = platform_get_drvdata(pdev); - struct nvhost_gating_register *regs = pdata->engine_cg_regs; - - if (!regs) - return; - - while (regs->addr) { - if (prod) - nvdla_device_register_write(pdev, regs->addr, - regs->prod); - else - nvdla_device_register_write(pdev, regs->addr, - regs->disable); - regs++; - } + (void) pdev; + (void) prod; } void nvdla_module_reset(struct platform_device *pdev, bool reboot) @@ -424,7 +432,8 @@ int nvdla_module_runtime_suspend(struct device *dev) } } - if (pdata->class != NV_DLA0_SIM_CLASS_ID) + if ((pdata->class != NV_DLA0_SIM_CLASS_ID) || + (pdata->class == NV_DLA1_SIM_CLASS_ID)) clk_bulk_disable_unprepare(pdata->num_clks, pdata->clks); return 0; @@ -439,7 +448,8 @@ int nvdla_module_runtime_resume(struct device *dev) struct nvhost_device_data *pdata = dev_get_drvdata(dev); int err = 0; - if (pdata->class != NV_DLA0_SIM_CLASS_ID) { + if ((pdata->class != NV_DLA0_SIM_CLASS_ID) || + (pdata->class == NV_DLA1_SIM_CLASS_ID)) { err = clk_bulk_prepare_enable(pdata->num_clks, pdata->clks); if (err < 0) { dev_err(&pdev->dev, "failed to enabled clocks: %d\n", err); diff --git a/drivers/video/tegra/host/nvdla/port/fw/nvdla_fw_flcn.c b/drivers/video/tegra/host/nvdla/port/fw/nvdla_fw_flcn.c index 43453ab7..f5a43385 100644 --- a/drivers/video/tegra/host/nvdla/port/fw/nvdla_fw_flcn.c +++ b/drivers/video/tegra/host/nvdla/port/fw/nvdla_fw_flcn.c @@ -5,6 +5,7 @@ */ #include "../nvdla_fw.h" +#include "../nvdla_host_wrapper.h" #include "../nvdla_device.h" #include "../../dla_os_interface.h" @@ -16,7 +17,6 @@ #include #include #include -#include int32_t nvdla_fw_poweron(struct platform_device *pdev) { diff --git a/drivers/video/tegra/host/nvdla/port/fw/nvdla_fw_riscv.c b/drivers/video/tegra/host/nvdla/port/fw/nvdla_fw_riscv.c index 8be44645..a5571c6b 100644 --- a/drivers/video/tegra/host/nvdla/port/fw/nvdla_fw_riscv.c +++ b/drivers/video/tegra/host/nvdla/port/fw/nvdla_fw_riscv.c @@ -5,6 +5,7 @@ */ #include "../nvdla_fw.h" +#include "../nvdla_host_wrapper.h" #include "nvdla_fw_riscv_reg.h" @@ -17,7 +18,6 @@ #include #include #include -#include #define DLA_UCODE_BIN_HEADER_MAGIC 0x10fe #define DLA_BOOTVECTOR_LO 0x100000 @@ -187,6 +187,17 @@ static uint32_t s_riscv_read(struct riscv *riscv, uint32_t offset) return readl(riscv->regs + offset); } +static int32_t s_riscv_wait_mthdid_idle(struct riscv *riscv) +{ + uint32_t value; + + return readl_poll_timeout(riscv->regs + riscv_mthdid_r(), + value, + (riscv_mthdid_wpend_v(value) == riscv_mthdid_wpend_done_v()), + 10 /* sleep in us */, + 100000 /* timeout in us*/); +} + static int32_t s_riscv_wait_idle(struct riscv *riscv) { uint32_t value; @@ -354,6 +365,7 @@ static int32_t s_riscv_finalize_poweron(struct platform_device *pdev) struct nvhost_device_data *pdata = platform_get_drvdata(pdev); struct riscv *riscv = (struct riscv *) pdata->falcon_data; int err; + bool skip_boot = false; err = s_riscv_load_firmware(riscv, pdata->firmware_name); if (err < 0) { @@ -364,16 +376,33 @@ static int32_t s_riscv_finalize_poweron(struct platform_device *pdev) nvdla_device_register_write(pdev, pdata->transcfg_addr, pdata->transcfg_val); - err = s_riscv_boot(riscv); - if (err < 0) { - nvdla_dbg_err(pdev, "boot err: %d\n", err); - goto unload_firmware; - } +#if defined(BUG_4960393) && (BUG_4960393 == 1) + if ((pdata->class == NV_DLA0_SIM_CLASS_ID) || + (pdata->class == NV_DLA1_SIM_CLASS_ID)) { + uint32_t bcr_ctrl; - err = s_riscv_wait_idle(riscv); - if (err < 0) { - nvdla_dbg_err(pdev, "boot timed out\n"); - goto unload_firmware; + bcr_ctrl = s_riscv_read(riscv, riscv_bcr_ctrl_r()); + if (riscv_bcr_ctrl_valid_v(bcr_ctrl) == + riscv_bcr_ctrl_valid_true_v()) { + dev_warn(riscv->dev, "uC will continue from halt.\n"); + dev_warn(riscv->dev, "Skipping uC boot.\n"); + skip_boot = true; + } + } +#endif /* BUG_4960393 */ + + if (!skip_boot) { + err = s_riscv_boot(riscv); + if (err < 0) { + nvdla_dbg_err(pdev, "boot err: %d\n", err); + goto unload_firmware; + } + + err = s_riscv_wait_idle(riscv); + if (err < 0) { + nvdla_dbg_err(pdev, "boot timed out\n"); + goto unload_firmware; + } } if (pdata->flcn_isr) @@ -555,6 +584,7 @@ int32_t nvdla_fw_send_cmd(struct platform_device *pdev, unsigned long timeout; int ret = 0; struct nvhost_device_data *pdata = platform_get_drvdata(pdev); + struct riscv *riscv = (struct riscv *) pdata->falcon_data; struct nvdla_device *nvdla_dev = pdata->private_data; uint32_t method_id = cmd_data->method_id; uint32_t method_data = cmd_data->method_data; @@ -568,7 +598,8 @@ int32_t nvdla_fw_send_cmd(struct platform_device *pdev, if (!nvdla_dev->available) { nvdla_dbg_err(pdev, "Command failed: device unavailable\n"); mutex_unlock(&nvdla_dev->cmd_lock); - return -EAGAIN; + ret = -EAGAIN; + goto fail; } /* @@ -579,6 +610,13 @@ int32_t nvdla_fw_send_cmd(struct platform_device *pdev, method_id |= (1 << DLA_INT_ON_COMPLETE_SHIFT) | (1 << DLA_INT_ON_ERROR_SHIFT); + ret = s_riscv_wait_mthdid_idle(riscv); + if (ret < 0) { + nvdla_dbg_err(pdev, "mthdid timed out\n"); + mutex_unlock(&nvdla_dev->cmd_lock); + goto fail; + } + nvdla_dev->waiting = 1; nvdla_dbg_reg(pdev, "method_data=[0x%x]", method_data); @@ -598,7 +636,8 @@ int32_t nvdla_fw_send_cmd(struct platform_device *pdev, } if (nvdla_dev->cmd_status != DLA_ERR_NONE) { - nvdla_dbg_err(pdev, "Command %u failed\n", method_id); + nvdla_dbg_err(pdev, "Command %u failed (status:%x)\n", + method_id, nvdla_dev->cmd_status); ret = -EINVAL; goto reset_cmd_status; } @@ -610,6 +649,7 @@ unlock_cmd: mutex_unlock(&nvdla_dev->cmd_lock); reset_waiting_status: nvdla_dev->waiting = 0; +fail: return ret; } diff --git a/drivers/video/tegra/host/nvdla/port/fw/nvdla_fw_riscv_reg.h b/drivers/video/tegra/host/nvdla/port/fw/nvdla_fw_riscv_reg.h index fd3f2612..c8e5cad5 100644 --- a/drivers/video/tegra/host/nvdla/port/fw/nvdla_fw_riscv_reg.h +++ b/drivers/video/tegra/host/nvdla/port/fw/nvdla_fw_riscv_reg.h @@ -50,6 +50,18 @@ static inline uint32_t riscv_mthdid_r(void) return 0x00000068U; } +static inline uint32_t riscv_mthdid_wpend_v(uint32_t r) +{ + /* NV_PNVDLA_FALCON_MTHDID_WPEND (16:16) */ + return ((r >> 0x10) & 0x1); +} + +static inline uint32_t riscv_mthdid_wpend_done_v(void) +{ + /* NV_PNVDLA_FALCON_MTHDID_WPEND_DONE (16:16) */ + return 0x0U; +} + static inline uint32_t riscv_mailbox0_r(void) { /* NV_PNVDLA_FALCON_MAILBOX0 */ diff --git a/drivers/video/tegra/host/nvdla/port/nvdla_host_wrapper.h b/drivers/video/tegra/host/nvdla/port/nvdla_host_wrapper.h new file mode 100644 index 00000000..47e91018 --- /dev/null +++ b/drivers/video/tegra/host/nvdla/port/nvdla_host_wrapper.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: LicenseRef-NvidiaProprietary */ +/* SPDX-FileCopyrightText: Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * + * NVDLA NVHOST-WRAPPER + */ + +#ifndef __NVDLA_HOST_WRAPPER_H__ +#define __NVDLA_HOST_WRAPPER_H__ + +#if defined(NVDLA_HAVE_CONFIG_AXI) && (NVDLA_HAVE_CONFIG_AXI == 1) +#include + +struct nvhost_notification { + struct { /* 0000- */ + __u32 nanoseconds[2]; /* nanoseconds since Jan. 1, 1970 */ + } time_stamp; /* -0007 */ + __u32 info32; /* info returned depends on method 0008-000b */ + __u16 info16; /* info returned depends on method 000c-000d */ + __u16 status; /* user sets bit 15, NV sets status 000e-000f */ +}; + +#else +#include +#endif /* NVDLA_HAVE_CONFIG_AXI */ + +#endif /*__NVDLA_HOST_WRAPPER_H__ */ diff --git a/drivers/video/tegra/host/nvdla/port/sync/nvdla_sync_syncpt.c b/drivers/video/tegra/host/nvdla/port/sync/nvdla_sync_syncpt.c index d5b93803..bb96a441 100644 --- a/drivers/video/tegra/host/nvdla/port/sync/nvdla_sync_syncpt.c +++ b/drivers/video/tegra/host/nvdla/port/sync/nvdla_sync_syncpt.c @@ -5,10 +5,10 @@ */ #include "../nvdla_sync.h" +#include "../nvdla_host_wrapper.h" #include "../../nvdla_debug.h" #include -#include #include #include diff --git a/drivers/video/tegra/host/nvdla/port/sync/nvdla_sync_syncpt_emu.c b/drivers/video/tegra/host/nvdla/port/sync/nvdla_sync_syncpt_emu.c new file mode 100644 index 00000000..78628f80 --- /dev/null +++ b/drivers/video/tegra/host/nvdla/port/sync/nvdla_sync_syncpt_emu.c @@ -0,0 +1,259 @@ +// SPDX-License-Identifier: LicenseRef-NvidiaProprietary +/* SPDX-FileCopyrightText: Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * + * NVDLA syncpoint emulator wrapper implementation + */ + +#include "../nvdla_sync.h" +#include "../nvdla_host_wrapper.h" + +#include "../../nvdla_debug.h" +#include +#include +#include + +struct nvdla_sync_device { + struct platform_device *pdev; +}; + +struct nvdla_sync_context { + struct nvdla_sync_device *device; + uint32_t syncptid; + dma_addr_t address; +}; + +struct nvdla_sync_device *nvdla_sync_device_create_syncpoint( + struct platform_device *pdev) +{ + int32_t err; + struct nvdla_sync_device *device = NULL; + + if (pdev == NULL) + goto fail; + + device = (struct nvdla_sync_device *) + vzalloc(sizeof(struct nvdla_sync_device)); + if (device == NULL) { + nvdla_dbg_err(pdev, "failed to allocate sync device\n"); + goto fail; + } + + err = HOST1X_EMU_EXPORT_CALL(nvhost_syncpt_unit_interface_init(pdev)); + if (err < 0) { + nvdla_dbg_err(pdev, "failed to init syncpt interface. err=%d\n", + err); + goto free_device; + } + + device->pdev = pdev; + + return device; + +free_device: + vfree(device); +fail: + return NULL; +} + +void nvdla_sync_device_destroy(struct nvdla_sync_device *device) +{ + if (device == NULL) + goto done; + + if (device->pdev == NULL) + goto free_device; + + HOST1X_EMU_EXPORT_CALL( + nvhost_syncpt_unit_interface_deinit(device->pdev)); + +free_device: + device->pdev = NULL; + vfree(device); +done: + return; +} + +dma_addr_t nvdla_sync_get_address_by_syncptid( + struct nvdla_sync_device *device, + uint32_t syncptid) +{ + dma_addr_t address = 0ULL; + + if (device != NULL) + address = HOST1X_EMU_EXPORT_CALL( + nvhost_syncpt_address(device->pdev, + syncptid)); + + return address; +} + +struct nvdla_sync_context *nvdla_sync_create(struct nvdla_sync_device *device) +{ + struct nvdla_sync_context *context = NULL; + + if ((device == NULL) || (device->pdev == NULL)) + goto fail; + + context = (struct nvdla_sync_context *) + (vzalloc(sizeof(struct nvdla_sync_context))); + if (context == NULL) { + nvdla_dbg_err(device->pdev, + "Failure to allocate sync context\n"); + goto fail; + } + + context->syncptid = HOST1X_EMU_EXPORT_CALL( + nvhost_get_syncpt_host_managed(device->pdev, 0U, NULL)); + + context->address = HOST1X_EMU_EXPORT_CALL( + nvhost_syncpt_address(device->pdev, context->syncptid)); + context->device = device; + + return context; + +fail: + return NULL; +} + +void nvdla_sync_destroy(struct nvdla_sync_context *context) +{ + if (context == NULL) + goto done; + + if ((context->device == NULL) || (context->device->pdev == NULL)) + goto free_context; + + /* Release the syncpoint ID */ + HOST1X_EMU_EXPORT_CALL(nvhost_syncpt_put_ref_ext(context->device->pdev, + context->syncptid)); + +free_context: + context->device = NULL; + vfree(context); +done: + return; +} + +dma_addr_t nvdla_sync_get_address(struct nvdla_sync_context *context) +{ + dma_addr_t address = 0ULL; + + if (context != NULL) + address = context->address; + + return address; +} + +uint32_t nvdla_sync_increment_max_value(struct nvdla_sync_context *context, + uint32_t increment) +{ + uint32_t maxval = 0U; + + if ((context == NULL) || (context->device == NULL)) + goto fail; + + maxval = HOST1X_EMU_EXPORT_CALL( + nvhost_syncpt_incr_max_ext(context->device->pdev, + context->syncptid, + increment)); + +fail: + return maxval; +} + +uint32_t nvdla_sync_get_max_value(struct nvdla_sync_context *context) +{ + int32_t maxval = 0U; + + if ((context == NULL) || (context->device == NULL)) + goto fail; + + maxval = HOST1X_EMU_EXPORT_CALL( + nvhost_syncpt_read_maxval(context->device->pdev, + context->syncptid)); + +fail: + return maxval; +} + +int32_t nvdla_sync_wait(struct nvdla_sync_context *context, + uint32_t threshold, + uint64_t timeout) +{ + int32_t err = 0; + int wait_complete; + struct nvdla_sync_device *device; + + if ((context == NULL) || (context->device == NULL)) { + err = -EINVAL; + goto fail; + } + + device = context->device; + if (timeout == 0ULL) { + wait_complete = HOST1X_EMU_EXPORT_CALL( + nvhost_syncpt_is_expired_ext(device->pdev, + context->syncptid, + threshold)); + if (wait_complete == 0) { + nvdla_dbg_err(device->pdev, + "Wait on sp[%u] for threshold[%u] timedout\n", + context->syncptid, threshold); + err = -ETIMEDOUT; + goto fail; + } + } else { + nvdla_dbg_err(device->pdev, + "Non-zero timeout[%llu] wait is not supported.\n", + timeout); + err = -EINVAL; + goto fail; + } + +fail: + return err; +} + +int32_t nvdla_sync_signal(struct nvdla_sync_context *context, + uint32_t signal_value) +{ + int err = 0; + + if ((context == NULL) || (context->device == NULL)) { + err = -EINVAL; + goto fail; + } + + HOST1X_EMU_EXPORT_CALL( + nvhost_syncpt_set_min_update(context->device->pdev, + context->syncptid, + signal_value)); + +fail: + return err; +} + +void nvdla_sync_print(struct nvdla_sync_context *context) +{ + struct platform_device *pdev; + + if (((context == NULL) || (context->device == NULL)) || + (context->device->pdev == NULL)) + goto done; + + pdev = context->device->pdev; + nvdla_dbg_info(pdev, "syncptid[%u]\n", context->syncptid); + +done: + return; +} + +uint32_t nvdla_sync_get_syncptid(struct nvdla_sync_context *context) +{ + uint32_t syncptid = 0xFFFFFFFFU; + + if (context != NULL) + syncptid = context->syncptid; + + return syncptid; +}