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:
Arvind M
2024-11-11 14:54:18 +00:00
committed by Jon Hunter
parent 873e573464
commit 47b40e9b56
20 changed files with 426 additions and 71 deletions

View File

@@ -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

View File

@@ -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))

View File

@@ -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"

View File

@@ -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,
};
/**

View File

@@ -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[] = {

View File

@@ -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>

View File

@@ -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"

View File

@@ -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;

View File

@@ -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;

View File

@@ -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"

View File

@@ -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"

View File

@@ -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,

View File

@@ -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,

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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;
}

View File

@@ -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 */

View 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__ */

View File

@@ -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>

View 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;
}