mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-24 02:01:36 +03:00
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 <am@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3248734
Reviewed-by: Vishal Thoke <vthoke@nvidia.com>
Reviewed-by: Ken Adams <kadams@nvidia.com>
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
Reviewed-by: Mitch Harwell <mharwell@nvidia.com>
Reviewed-by: Amit Sharma (SW-TEGRA) <amisharma@nvidia.com>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#include <linux/nvhost.h>
|
||||
#include "port/nvdla_host_wrapper.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_TEGRA_NVDLA_CHANNEL)
|
||||
#include "nvhost_job.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,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 <linux/nvhost.h>
|
||||
#include "port/nvdla_host_wrapper.h"
|
||||
|
||||
static struct nvhost_gating_register __attribute__((__unused__))
|
||||
nvdla_gating_registers[] = {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/nvhost.h>
|
||||
#include "port/nvdla_host_wrapper.h"
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/version.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 <linux/platform_device.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/nvhost.h>
|
||||
#include "port/nvdla_host_wrapper.h"
|
||||
|
||||
#include "nvdla.h"
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#ifndef __NVHOST_NVDLA_T194_H__
|
||||
#define __NVHOST_NVDLA_T194_H__
|
||||
|
||||
#include <linux/nvhost.h>
|
||||
#include "port/nvdla_host_wrapper.h"
|
||||
#include <linux/platform/tegra/emc_bwmgr.h>
|
||||
|
||||
#include "nvdla.h"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#ifndef __NVHOST_NVDLA_T234_H__
|
||||
#define __NVHOST_NVDLA_T234_H__
|
||||
|
||||
#include <linux/nvhost.h>
|
||||
#include "port/nvdla_host_wrapper.h"
|
||||
#include <dt-bindings/interconnect/tegra_icc_id.h>
|
||||
|
||||
#include "nvdla.h"
|
||||
|
||||
@@ -7,20 +7,19 @@
|
||||
#ifndef __NVHOST_NVDLA_T25X_H__
|
||||
#define __NVHOST_NVDLA_T25X_H__
|
||||
|
||||
#include <linux/nvhost.h>
|
||||
#include "port/nvdla_host_wrapper.h"
|
||||
#include <dt-bindings/interconnect/tegra_icc_id.h>
|
||||
|
||||
#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,
|
||||
|
||||
@@ -7,17 +7,12 @@
|
||||
#ifndef __NVHOST_NVDLA_T264_SIM_H__
|
||||
#define __NVHOST_NVDLA_T264_SIM_H__
|
||||
|
||||
#include <linux/nvhost.h>
|
||||
#include "port/nvdla_host_wrapper.h"
|
||||
#include <dt-bindings/interconnect/tegra_icc_id.h>
|
||||
|
||||
#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,
|
||||
|
||||
@@ -14,13 +14,15 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/nvhost.h>
|
||||
#include <linux/nvhost-emu.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#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);
|
||||
|
||||
@@ -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 <linux/errno.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/nvhost.h>
|
||||
|
||||
int32_t nvdla_fw_poweron(struct platform_device *pdev)
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "../nvdla_fw.h"
|
||||
#include "../nvdla_host_wrapper.h"
|
||||
|
||||
#include "nvdla_fw_riscv_reg.h"
|
||||
|
||||
@@ -17,7 +18,6 @@
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/nvhost.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
26
drivers/video/tegra/host/nvdla/port/nvdla_host_wrapper.h
Normal file
26
drivers/video/tegra/host/nvdla/port/nvdla_host_wrapper.h
Normal file
@@ -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 <linux/nvhost-emu.h>
|
||||
|
||||
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 <linux/nvhost.h>
|
||||
#endif /* NVDLA_HAVE_CONFIG_AXI */
|
||||
|
||||
#endif /*__NVDLA_HOST_WRAPPER_H__ */
|
||||
@@ -5,10 +5,10 @@
|
||||
*/
|
||||
|
||||
#include "../nvdla_sync.h"
|
||||
#include "../nvdla_host_wrapper.h"
|
||||
|
||||
#include "../../nvdla_debug.h"
|
||||
#include <linux/errno.h>
|
||||
#include <linux/nvhost.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
|
||||
259
drivers/video/tegra/host/nvdla/port/sync/nvdla_sync_syncpt_emu.c
Normal file
259
drivers/video/tegra/host/nvdla/port/sync/nvdla_sync_syncpt_emu.c
Normal file
@@ -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 <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user