driver: rknpu: Update rknpu driver, version: 0.6.4

* Add support for rk3588/rk3588s

Signed-off-by: Felix Zeng <felix.zeng@rock-chips.com>
Change-Id: I292cca4037367d21e88f05bb8a8b7cac93c2f91e
This commit is contained in:
Felix Zeng
2021-11-17 14:58:59 +08:00
committed by Tao Huang
parent 43d1db61b0
commit 3d588e4c36
9 changed files with 588 additions and 179 deletions

View File

@@ -20,10 +20,10 @@
#define DRIVER_NAME "rknpu"
#define DRIVER_DESC "RKNPU driver"
#define DRIVER_DATE "20210824"
#define DRIVER_DATE "20211227"
#define DRIVER_MAJOR 0
#define DRIVER_MINOR 5
#define DRIVER_PATCHLEVEL 0
#define DRIVER_MINOR 6
#define DRIVER_PATCHLEVEL 4
#define LOG_TAG "RKNPU"
@@ -42,10 +42,28 @@
DRM_DEV_DEBUG_DRIVER(dev, LOG_TAG ": " fmt, ##args)
#define LOG_DEV_ERROR(dev, fmt, args...) dev_err(dev, LOG_TAG ": " fmt, ##args)
struct npu_reset_data {
const char *srst_a_name;
const char *srst_h_name;
};
struct rknpu_config {
__u32 bw_priority_addr;
__u32 bw_priority_length;
__u64 dma_mask;
__u32 pc_data_extra_amount;
__u32 bw_enable;
const struct npu_irqs_data *irqs;
const struct npu_reset_data *resets;
int num_irqs;
int num_resets;
};
struct rknpu_subcore_data {
struct list_head todo_list;
wait_queue_head_t job_done_wq;
struct rknpu_job *job;
uint64_t task_num;
};
/**
@@ -56,22 +74,20 @@ struct rknpu_config {
* @drm_dev: DRM device instance
*/
struct rknpu_device {
void __iomem *base;
void __iomem *base[RKNPU_MAX_CORES];
struct device *dev;
struct device *fake_dev;
struct drm_device *drm_dev;
atomic_t sequence;
spinlock_t lock;
spinlock_t irq_lock;
struct list_head todo_list;
wait_queue_head_t job_done_wq;
struct rknpu_subcore_data subcore_datas[RKNPU_MAX_CORES];
const struct rknpu_config *config;
void __iomem *bw_priority_base;
struct rknpu_job *job;
struct rknpu_fence_context *fence_ctx;
bool iommu_en;
struct reset_control *srst_a;
struct reset_control *srst_h;
struct reset_control *srst_a[RKNPU_MAX_CORES];
struct reset_control *srst_h[RKNPU_MAX_CORES];
struct clk_bulk_data *clks;
int num_clks;
struct regulator *vdd;

View File

@@ -15,9 +15,7 @@ struct rknpu_fence_context {
spinlock_t spinlock;
};
struct rknpu_fence_context *rknpu_fence_context_alloc(void);
void rknpu_fence_context_free(struct rknpu_fence_context *fence_ctx);
int rknpu_fence_context_alloc(struct rknpu_device *rknpu_dev);
int rknpu_fence_alloc(struct rknpu_job *job);

View File

@@ -14,8 +14,6 @@
#define __user
#endif
#define RKNPU_PC_DATA_EXTRA_AMOUNT 4
#define RKNPU_OFFSET_VERSION 0x0
#define RKNPU_OFFSET_PC_OP_EN 0x8
#define RKNPU_OFFSET_PC_DATA_ADDR 0x10
@@ -27,6 +25,7 @@
#define RKNPU_OFFSET_INT_MASK 0x20
#define RKNPU_OFFSET_INT_CLEAR 0x24
#define RKNPU_OFFSET_INT_STATUS 0x28
#define RKNPU_OFFSET_INT_RAW_STATUS 0x2c
#define RKNPU_OFFSET_CLR_ALL_RW_AMOUNT 0x8010
#define RKNPU_OFFSET_DT_WR_AMOUNT 0x8034
@@ -91,9 +90,11 @@ enum e_rknpu_job_mode {
RKNPU_JOB_BLOCK = 0 << 1,
RKNPU_JOB_NONBLOCK = 1 << 1,
RKNPU_JOB_PINGPONG = 1 << 2,
RKNPU_JOB_FENCE = 1 << 3,
RKNPU_JOB_FENCE_IN = 1 << 3,
RKNPU_JOB_FENCE_OUT = 1 << 4,
RKNPU_JOB_MASK = RKNPU_JOB_PC | RKNPU_JOB_NONBLOCK |
RKNPU_JOB_PINGPONG | RKNPU_JOB_FENCE
RKNPU_JOB_PINGPONG | RKNPU_JOB_FENCE_IN |
RKNPU_JOB_FENCE_OUT
};
/* action definitions */
@@ -206,6 +207,19 @@ struct rknpu_task {
__u64 regcmd_data;
} __packed;
/**
* struct rknpu_subcore_task structure for subcore task index
*
* @task_start: task start index
* @task_number: task number
*
*/
struct rknpu_subcore_task {
__u32 task_start;
__u32 task_number;
__u32 task_end;
};
/**
* struct rknpu_submit structure for job submit
*
@@ -219,7 +233,7 @@ struct rknpu_task {
* @regcfg_obj_addr: address of register config object
* @user_data: (optional) user data
* @sequence: submit sequence
* @core_id: core id of rknpu
* @core_mask: core mask of rknpu
* @fence_fd: dma fence fd
*
*/
@@ -234,8 +248,9 @@ struct rknpu_submit {
__u64 regcfg_obj_addr;
__u64 user_data;
__u64 sequence;
__u32 core_id;
__u32 core_mask;
__s32 fence_fd;
struct rknpu_subcore_task subcore_task[5];
};
/**

View File

@@ -14,12 +14,19 @@
#include "rknpu_ioctl.h"
#define RKNPU_MAX_CORES 3
#define RKNPU_JOB_DONE (1 << 0)
#define RKNPU_JOB_ASYNC (1 << 1)
#define RKNPU_CORE_AUTO_MASK 0x00
#define RKNPU_CORE0_MASK 0x01
#define RKNPU_CORE1_MASK 0x02
#define RKNPU_CORE2_MASK 0x04
struct rknpu_job {
struct rknpu_device *rknpu_dev;
struct list_head head;
struct list_head head[RKNPU_MAX_CORES];
struct work_struct cleanup_work;
unsigned int flags;
int ret;
@@ -27,14 +34,18 @@ struct rknpu_job {
bool args_owner;
struct rknpu_task *first_task;
struct rknpu_task *last_task;
uint32_t int_mask;
uint32_t int_status;
uint32_t int_mask[RKNPU_MAX_CORES];
uint32_t int_status[RKNPU_MAX_CORES];
struct dma_fence *fence;
spinlock_t fence_lock;
ktime_t timestamp;
uint32_t use_core_num;
uint32_t run_count;
uint32_t interrupt_count;
};
irqreturn_t rknpu_irq_handler(int irq, void *data);
irqreturn_t rknpu_core0_irq_handler(int irq, void *data);
irqreturn_t rknpu_core1_irq_handler(int irq, void *data);
irqreturn_t rknpu_core2_irq_handler(int irq, void *data);
int rknpu_submit_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);

View File

@@ -36,9 +36,11 @@
#include <drm/drm_file.h>
#include <drm/drm_drv.h>
#ifndef FPGA_PLATFORM
#include <soc/rockchip/rockchip_opp_select.h>
#include <soc/rockchip/rockchip_system_monitor.h>
#include <soc/rockchip/rockchip_ipa.h>
#endif
#include "rknpu_ioctl.h"
#include "rknpu_reset.h"
@@ -56,10 +58,52 @@ module_param(bypass_soft_reset, int, 0644);
MODULE_PARM_DESC(bypass_soft_reset,
"bypass RKNPU soft reset if set it to 1, disabled by default");
struct npu_irqs_data {
const char *name;
irqreturn_t (*irq_hdl)(int irq, void *ctx);
};
static const struct npu_irqs_data rk356x_npu_irqs[] = {
{ "npu0_irq", rknpu_core0_irq_handler }
};
static const struct npu_irqs_data rk3588_npu_irqs[] = {
{ "npu0_irq", rknpu_core0_irq_handler },
{ "npu1_irq", rknpu_core1_irq_handler },
{ "npu2_irq", rknpu_core2_irq_handler }
};
static const struct npu_reset_data rk356x_npu_resets[] = { { "srst_a",
"srst_h" } };
static const struct npu_reset_data rk3588_npu_resets[] = {
{ "srst_a0", "srst_h0" },
{ "srst_a1", "srst_h1" },
{ "srst_a2", "srst_h2" }
};
static const struct rknpu_config rk356x_rknpu_config = {
.bw_priority_addr = 0xfe180008,
.bw_priority_length = 0x10,
.dma_mask = DMA_BIT_MASK(32),
.pc_data_extra_amount = 4,
.bw_enable = 1,
.irqs = rk356x_npu_irqs,
.resets = rk356x_npu_resets,
.num_irqs = ARRAY_SIZE(rk356x_npu_irqs),
.num_resets = ARRAY_SIZE(rk356x_npu_resets)
};
static const struct rknpu_config rk3588_rknpu_config = {
.bw_priority_addr = 0x0,
.bw_priority_length = 0x0,
.dma_mask = DMA_BIT_MASK(40),
.pc_data_extra_amount = 2,
.bw_enable = 0,
.irqs = rk3588_npu_irqs,
.resets = rk3588_npu_resets,
.num_irqs = ARRAY_SIZE(rk3588_npu_irqs),
.num_resets = ARRAY_SIZE(rk3588_npu_resets)
};
/* driver probe and init */
@@ -72,6 +116,10 @@ static const struct of_device_id rknpu_of_match[] = {
.compatible = "rockchip,rk3568-rknpu",
.data = &rk356x_rknpu_config,
},
{
.compatible = "rockchip,rk3588-rknpu",
.data = &rk3588_rknpu_config,
},
{},
};
@@ -350,6 +398,7 @@ static int rknpu_power_on(struct rknpu_device *rknpu_dev)
struct device *dev = rknpu_dev->dev;
int ret = -EINVAL;
#ifndef FPGA_PLATFORM
ret = regulator_enable(rknpu_dev->vdd);
if (ret) {
LOG_DEV_ERROR(
@@ -357,6 +406,7 @@ static int rknpu_power_on(struct rknpu_device *rknpu_dev)
ret);
return ret;
}
#endif
ret = clk_bulk_prepare_enable(rknpu_dev->num_clks, rknpu_dev->clks);
if (ret) {
@@ -428,11 +478,14 @@ static int rknpu_power_off(struct rknpu_device *rknpu_dev)
clk_bulk_disable_unprepare(rknpu_dev->num_clks, rknpu_dev->clks);
#ifndef FPGA_PLATFORM
regulator_disable(rknpu_dev->vdd);
#endif
return 0;
}
#ifndef FPGA_PLATFORM
static struct monitor_dev_profile npu_mdevp = {
.type = MONITOR_TPYE_DEV,
.low_temp_adjust = rockchip_monitor_dev_low_temp_adjust,
@@ -677,6 +730,57 @@ static int rknpu_devfreq_init(struct rknpu_device *rknpu_dev)
out:
return 0;
}
#endif
static int rknpu_register_irq(struct platform_device *pdev,
struct rknpu_device *rknpu_dev)
{
const struct rknpu_config *config = rknpu_dev->config;
struct device *dev = &pdev->dev;
struct resource *res;
int i, ret, irq;
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
config->irqs[0].name);
if (res) {
/* there are irq names in dts */
for (i = 0; i < config->num_irqs; i++) {
irq = platform_get_irq_byname(pdev,
config->irqs[i].name);
if (irq < 0) {
LOG_DEV_ERROR(dev, "no npu %s in dts\n",
config->irqs[i].name);
return irq;
}
ret = devm_request_irq(dev, irq,
config->irqs[i].irq_hdl,
IRQF_SHARED, dev_name(dev),
rknpu_dev);
if (ret < 0) {
LOG_DEV_ERROR(dev, "request %s failed: %d\n",
config->irqs[i].name, ret);
return ret;
}
}
} else {
/* no irq names in dts */
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
LOG_DEV_ERROR(dev, "no npu irq in dts\n");
return irq;
}
ret = devm_request_irq(dev, irq, rknpu_core0_irq_handler,
IRQF_SHARED, dev_name(dev), rknpu_dev);
if (ret < 0) {
LOG_DEV_ERROR(dev, "request irq failed: %d\n", ret);
return ret;
}
}
return 0;
}
static int rknpu_probe(struct platform_device *pdev)
{
@@ -686,7 +790,7 @@ static int rknpu_probe(struct platform_device *pdev)
struct device *virt_dev = NULL;
const struct of_device_id *match = NULL;
const struct rknpu_config *config = NULL;
int ret = -EINVAL;
int ret = -EINVAL, i = 0;
if (!pdev->dev.of_node) {
LOG_DEV_ERROR(dev, "rknpu device-tree data is missing!\n");
@@ -729,11 +833,8 @@ static int rknpu_probe(struct platform_device *pdev)
rknpu_reset_get(rknpu_dev);
rknpu_dev->num_clks = devm_clk_bulk_get_all(dev, &rknpu_dev->clks);
if (rknpu_dev->num_clks < 1) {
LOG_DEV_ERROR(dev, "failed to get clk source for rknpu\n");
return -ENODEV;
}
#ifndef FPGA_PLATFORM
rknpu_dev->vdd = devm_regulator_get_optional(dev, "rknpu");
if (IS_ERR(rknpu_dev->vdd)) {
if (PTR_ERR(rknpu_dev->vdd) != -ENODEV) {
@@ -746,73 +847,68 @@ static int rknpu_probe(struct platform_device *pdev)
}
rknpu_dev->vdd = NULL;
}
#endif
spin_lock_init(&rknpu_dev->lock);
spin_lock_init(&rknpu_dev->irq_lock);
INIT_LIST_HEAD(&rknpu_dev->todo_list);
init_waitqueue_head(&rknpu_dev->job_done_wq);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
LOG_DEV_ERROR(dev, "failed to get memory resource for rknpu\n");
return -ENXIO;
}
rknpu_dev->base = devm_ioremap_resource(dev, res);
if (PTR_ERR(rknpu_dev->base) == -EBUSY) {
rknpu_dev->base =
devm_ioremap(dev, res->start, resource_size(res));
}
if (IS_ERR(rknpu_dev->base)) {
LOG_DEV_ERROR(dev, "failed to remap register for rknpu\n");
return PTR_ERR(rknpu_dev->base);
}
rknpu_dev->bw_priority_base = devm_ioremap(
dev, config->bw_priority_addr, config->bw_priority_length);
if (IS_ERR(rknpu_dev->bw_priority_base)) {
LOG_DEV_ERROR(
rknpu_dev->dev,
"failed to remap bw priority register for rknpu\n");
rknpu_dev->bw_priority_base = NULL;
}
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
LOG_DEV_ERROR(dev,
"failed to get interrupt resource for rknpu\n");
return -ENXIO;
}
if (!rknpu_dev->bypass_irq_handler) {
ret = devm_request_irq(dev, res->start, rknpu_irq_handler,
IRQF_SHARED, dev_name(dev), rknpu_dev);
if (ret) {
LOG_DEV_ERROR(dev, "failed to request irq for rknpu\n");
return ret;
for (i = 0; i < config->num_irqs; i++) {
INIT_LIST_HEAD(&rknpu_dev->subcore_datas[i].todo_list);
init_waitqueue_head(&rknpu_dev->subcore_datas[i].job_done_wq);
rknpu_dev->subcore_datas[i].task_num = 0;
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
if (!res) {
LOG_DEV_ERROR(
dev,
"failed to get memory resource for rknpu\n");
return -ENXIO;
}
rknpu_dev->base[i] = devm_ioremap_resource(dev, res);
if (PTR_ERR(rknpu_dev->base[i]) == -EBUSY) {
rknpu_dev->base[i] = devm_ioremap(dev, res->start,
resource_size(res));
}
if (IS_ERR(rknpu_dev->base[i])) {
LOG_DEV_ERROR(dev,
"failed to remap register for rknpu\n");
return PTR_ERR(rknpu_dev->base[i]);
}
} else {
LOG_DEV_WARN(dev, "bypass irq handler!\n");
}
if (config->bw_priority_length > 0) {
rknpu_dev->bw_priority_base =
devm_ioremap(dev, config->bw_priority_addr,
config->bw_priority_length);
if (IS_ERR(rknpu_dev->bw_priority_base)) {
LOG_DEV_ERROR(
rknpu_dev->dev,
"failed to remap bw priority register for rknpu\n");
rknpu_dev->bw_priority_base = NULL;
}
}
if (!rknpu_dev->bypass_irq_handler)
rknpu_register_irq(pdev, rknpu_dev);
ret = rknpu_drm_probe(rknpu_dev);
if (ret) {
LOG_DEV_ERROR(dev, "failed to probe device for rknpu\n");
return ret;
}
rknpu_dev->fence_ctx = rknpu_fence_context_alloc();
if (IS_ERR(rknpu_dev->fence_ctx)) {
ret = rknpu_fence_context_alloc(rknpu_dev);
if (ret) {
LOG_DEV_ERROR(dev,
"failed to allocate fence context for rknpu\n");
ret = PTR_ERR(rknpu_dev->fence_ctx);
goto err_remove_drm;
}
platform_set_drvdata(pdev, rknpu_dev);
#ifndef FPGA_PLATFORM
rknpu_devfreq_init(rknpu_dev);
#endif
pm_runtime_enable(dev);
@@ -832,12 +928,10 @@ static int rknpu_probe(struct platform_device *pdev)
ret = rknpu_power_on(rknpu_dev);
if (ret)
goto err_free_fence_context;
goto err_remove_drm;
return 0;
err_free_fence_context:
rknpu_fence_context_free(rknpu_dev->fence_ctx);
err_remove_drm:
rknpu_drm_remove(rknpu_dev);
@@ -847,14 +941,15 @@ err_remove_drm:
static int rknpu_remove(struct platform_device *pdev)
{
struct rknpu_device *rknpu_dev = platform_get_drvdata(pdev);
int i = 0;
WARN_ON(rknpu_dev->job);
WARN_ON(!list_empty(&rknpu_dev->todo_list));
for (i = 0; i < rknpu_dev->config->num_irqs; i++) {
WARN_ON(rknpu_dev->subcore_datas[i].job);
WARN_ON(!list_empty(&rknpu_dev->subcore_datas[i].todo_list));
}
rknpu_drm_remove(rknpu_dev);
rknpu_fence_context_free(rknpu_dev->fence_ctx);
rknpu_power_off(rknpu_dev);
if (rknpu_dev->multiple_domains) {

View File

@@ -24,24 +24,21 @@ static const struct dma_fence_ops rknpu_fence_ops = {
.get_timeline_name = rknpu_fence_get_name,
};
struct rknpu_fence_context *rknpu_fence_context_alloc(void)
int rknpu_fence_context_alloc(struct rknpu_device *rknpu_dev)
{
struct rknpu_fence_context *fence_ctx = NULL;
fence_ctx = kzalloc(sizeof(*fence_ctx), GFP_KERNEL);
fence_ctx =
devm_kzalloc(rknpu_dev->dev, sizeof(*fence_ctx), GFP_KERNEL);
if (!fence_ctx)
return ERR_PTR(-ENOMEM);
return -ENOMEM;
fence_ctx->context = dma_fence_context_alloc(1);
spin_lock_init(&fence_ctx->spinlock);
return fence_ctx;
}
rknpu_dev->fence_ctx = fence_ctx;
void rknpu_fence_context_free(struct rknpu_fence_context *fence_ctx)
{
if (!IS_ERR(fence_ctx))
kfree(fence_ctx);
return 0;
}
int rknpu_fence_alloc(struct rknpu_job *job)
@@ -53,7 +50,7 @@ int rknpu_fence_alloc(struct rknpu_job *job)
if (!fence)
return -ENOMEM;
dma_fence_init(fence, &rknpu_fence_ops, &job->fence_lock,
dma_fence_init(fence, &rknpu_fence_ops, &fence_ctx->spinlock,
fence_ctx->context, ++fence_ctx->seqno);
job->fence = fence;

View File

@@ -130,9 +130,6 @@ static int rknpu_gem_alloc_buf(struct rknpu_gem_object *rknpu_obj)
#endif
#ifdef DMA_ATTR_SYS_CACHE_ONLY
rknpu_obj->dma_attrs |= DMA_ATTR_SYS_CACHE_ONLY;
#elif DMA_ATTR_FORCE_COHERENT
// force coherent
rknpu_obj->dma_attrs |= DMA_ATTR_FORCE_COHERENT;
#endif
} else if (rknpu_obj->flags & RKNPU_MEM_WRITE_COMBINE) {
rknpu_obj->dma_attrs |= DMA_ATTR_WRITE_COMBINE;
@@ -459,7 +456,7 @@ int rknpu_gem_create_ioctl(struct drm_device *dev, void *data,
// rknpu_gem_object_get(&rknpu_obj->base);
args->size = rknpu_obj->size;
args->obj_addr = (__u64)rknpu_obj;
args->obj_addr = (__u64)(uintptr_t)rknpu_obj;
args->dma_addr = rknpu_obj->dma_addr;
return 0;
@@ -920,7 +917,7 @@ int rknpu_gem_sync_ioctl(struct drm_device *dev, void *data,
unsigned long len = 0;
int i;
rknpu_obj = (struct rknpu_gem_object *)args->obj_addr;
rknpu_obj = (struct rknpu_gem_object *)(uintptr_t)args->obj_addr;
if (!rknpu_obj)
return -EINVAL;

View File

@@ -6,6 +6,8 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/sync_file.h>
#include <linux/io.h>
#include "rknpu_ioctl.h"
#include "rknpu_drv.h"
@@ -17,8 +19,41 @@
#define _REG_READ(base, offset) readl(base + (offset))
#define _REG_WRITE(base, value, offset) writel(value, base + (offset))
#define REG_READ(offset) _REG_READ(rknpu_dev->base, offset)
#define REG_WRITE(value, offset) _REG_WRITE(rknpu_dev->base, value, offset)
#define REG_READ(offset) _REG_READ(rknpu_core_base, offset)
#define REG_WRITE(value, offset) _REG_WRITE(rknpu_core_base, value, offset)
static int rknpu_core_index(int core_mask)
{
int index = 0;
if (core_mask & RKNPU_CORE0_MASK)
index = 0;
else if (core_mask & RKNPU_CORE1_MASK)
index = 1;
else if (core_mask & RKNPU_CORE2_MASK)
index = 2;
return index;
}
static int rknpu_core_mask(int core_index)
{
int core_mask[3] = { RKNPU_CORE0_MASK, RKNPU_CORE1_MASK,
RKNPU_CORE2_MASK };
return core_mask[core_index];
}
static int rknn_get_task_number(struct rknpu_job *job, int core_index)
{
int task_num = job->args->task_number;
if (job->use_core_num == 2)
task_num = job->args->subcore_task[core_index].task_number;
else if (job->use_core_num == 3)
task_num = job->args->subcore_task[core_index + 2].task_number;
return task_num;
}
static void rknpu_job_free(struct rknpu_job *job)
{
@@ -27,7 +62,8 @@ static void rknpu_job_free(struct rknpu_job *job)
if (job->fence)
dma_fence_put(job->fence);
task_obj = (struct rknpu_gem_object *)job->args->task_obj_addr;
task_obj =
(struct rknpu_gem_object *)(uintptr_t)job->args->task_obj_addr;
if (task_obj)
rknpu_gem_object_put(&task_obj->base);
@@ -58,14 +94,22 @@ static inline struct rknpu_job *rknpu_job_alloc(struct rknpu_device *rknpu_dev,
struct rknpu_job *job = NULL;
struct rknpu_gem_object *task_obj = NULL;
if (rknpu_dev->config->num_irqs == 1)
args->core_mask = RKNPU_CORE0_MASK;
job = kzalloc(sizeof(*job), GFP_KERNEL);
if (!job)
return NULL;
job->timestamp = ktime_get();
job->rknpu_dev = rknpu_dev;
job->use_core_num = (args->core_mask & RKNPU_CORE0_MASK) +
((args->core_mask & RKNPU_CORE1_MASK) >> 1) +
((args->core_mask & RKNPU_CORE2_MASK) >> 2);
job->run_count = job->use_core_num;
job->interrupt_count = job->use_core_num;
task_obj = (struct rknpu_gem_object *)args->task_obj_addr;
task_obj = (struct rknpu_gem_object *)(uintptr_t)args->task_obj_addr;
if (task_obj)
rknpu_gem_object_get(&task_obj->base);
@@ -93,9 +137,13 @@ static inline int rknpu_job_wait(struct rknpu_job *job)
struct rknpu_device *rknpu_dev = job->rknpu_dev;
struct rknpu_submit *args = job->args;
struct rknpu_task *last_task = NULL;
struct rknpu_subcore_data *subcore_data = NULL;
void __iomem *rknpu_core_base = NULL;
int core_index = rknpu_core_index(job->args->core_mask);
int ret = -EINVAL;
ret = wait_event_interruptible_timeout(rknpu_dev->job_done_wq,
subcore_data = &rknpu_dev->subcore_datas[core_index];
ret = wait_event_interruptible_timeout(subcore_data->job_done_wq,
job->flags & RKNPU_JOB_DONE,
msecs_to_jiffies(args->timeout));
@@ -103,10 +151,11 @@ static inline int rknpu_job_wait(struct rknpu_job *job)
if (!last_task)
return -EINVAL;
last_task->int_status = job->int_status;
last_task->int_status = job->int_status[core_index];
if (ret <= 0) {
args->task_counter = 0;
rknpu_core_base = rknpu_dev->base[core_index];
if (args->flags & RKNPU_JOB_PC) {
uint32_t task_status =
REG_READ(RKNPU_OFFSET_PC_TASK_STATUS);
@@ -120,25 +169,48 @@ static inline int rknpu_job_wait(struct rknpu_job *job)
return 0;
}
static inline int rknpu_job_commit_pc(struct rknpu_job *job)
static inline int rknpu_job_commit_pc(struct rknpu_job *job, int core_index)
{
struct rknpu_device *rknpu_dev = job->rknpu_dev;
struct rknpu_submit *args = job->args;
struct rknpu_gem_object *task_obj =
(struct rknpu_gem_object *)args->task_obj_addr;
(struct rknpu_gem_object *)(uintptr_t)args->task_obj_addr;
struct rknpu_task *task_base = NULL;
struct rknpu_task *first_task = NULL;
struct rknpu_task *last_task = NULL;
void __iomem *rknpu_core_base = rknpu_dev->base[core_index];
int task_start = args->task_start;
int task_end = args->task_start + args->task_number - 1;
int task_number = args->task_number;
int task_pp_en = args->flags & RKNPU_JOB_PINGPONG ? 1 : 0;
int i = 0;
for (i = 0; i < rknpu_dev->config->num_irqs; i++) {
if (i == core_index) {
REG_WRITE((0xe + 0x10000000 * i), 0x1004);
REG_WRITE((0xe + 0x10000000 * i), 0x3004);
}
}
if (!task_obj)
return -EINVAL;
if ((task_start + 1) * sizeof(*task_base) > task_obj->size ||
(task_end + 1) * sizeof(*task_base) > task_obj->size)
return -EINVAL;
if (job->use_core_num == 1) {
task_start = args->subcore_task[core_index].task_start;
task_end = args->subcore_task[core_index].task_start +
args->subcore_task[core_index].task_end - 1;
task_number = args->subcore_task[core_index].task_number;
} else if (job->use_core_num == 2) {
task_start = args->subcore_task[core_index].task_start;
task_end = args->subcore_task[core_index].task_start +
args->subcore_task[core_index].task_end - 1;
task_number = args->subcore_task[core_index].task_number;
} else if (job->use_core_num == 3) {
task_start = args->subcore_task[core_index + 2].task_start;
task_end = args->subcore_task[core_index + 2].task_start +
args->subcore_task[core_index + 2].task_end - 1;
task_number = args->subcore_task[core_index + 2].task_number;
}
task_base = task_obj->kv_addr;
@@ -147,21 +219,22 @@ static inline int rknpu_job_commit_pc(struct rknpu_job *job)
REG_WRITE(first_task->regcmd_data, RKNPU_OFFSET_PC_DATA_ADDR);
REG_WRITE(first_task->regcfg_amount + RKNPU_PC_DATA_EXTRA_AMOUNT - 1,
REG_WRITE(first_task->regcfg_amount +
rknpu_dev->config->pc_data_extra_amount - 1,
RKNPU_OFFSET_PC_DATA_AMOUNT);
REG_WRITE(last_task->int_mask, RKNPU_OFFSET_INT_MASK);
REG_WRITE(first_task->int_mask, RKNPU_OFFSET_INT_CLEAR);
REG_WRITE(((0x6 | task_pp_en) << 12) | args->task_number,
REG_WRITE(((0x6 | task_pp_en) << 12) | task_number,
RKNPU_OFFSET_PC_TASK_CONTROL);
REG_WRITE(0x0, RKNPU_OFFSET_PC_DMA_BASE_ADDR);
job->first_task = first_task;
job->last_task = last_task;
job->int_mask = last_task->int_mask;
job->int_mask[core_index] = last_task->int_mask;
REG_WRITE(0x1, RKNPU_OFFSET_PC_OP_EN);
REG_WRITE(0x0, RKNPU_OFFSET_PC_OP_EN);
@@ -169,10 +242,11 @@ static inline int rknpu_job_commit_pc(struct rknpu_job *job)
return 0;
}
static int rknpu_job_commit(struct rknpu_job *job)
static int rknpu_job_commit(struct rknpu_job *job, int core_index)
{
struct rknpu_device *rknpu_dev = job->rknpu_dev;
struct rknpu_submit *args = job->args;
void __iomem *rknpu_core_base = rknpu_dev->base[core_index];
// switch to slave mode
REG_WRITE(0x1, RKNPU_OFFSET_PC_DATA_ADDR);
@@ -180,49 +254,73 @@ static int rknpu_job_commit(struct rknpu_job *job)
if (!(args->flags & RKNPU_JOB_PC))
return -EINVAL;
return rknpu_job_commit_pc(job);
return rknpu_job_commit_pc(job, core_index);
}
static void rknpu_job_next(struct rknpu_device *rknpu_dev)
static void rknpu_job_next(struct rknpu_device *rknpu_dev, int core_index)
{
struct rknpu_job *job = NULL;
struct rknpu_subcore_data *subcore_data = NULL;
unsigned long flags;
subcore_data = &rknpu_dev->subcore_datas[core_index];
spin_lock_irqsave(&rknpu_dev->irq_lock, flags);
if (rknpu_dev->job || list_empty(&rknpu_dev->todo_list)) {
if (subcore_data->job || list_empty(&subcore_data->todo_list)) {
spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags);
return;
}
job = list_first_entry(&rknpu_dev->todo_list, struct rknpu_job, head);
job = list_first_entry(&subcore_data->todo_list, struct rknpu_job,
head[core_index]);
list_del_init(&job->head);
list_del_init(&job->head[core_index]);
rknpu_dev->job = job;
subcore_data->job = job;
job->run_count--;
spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags);
job->ret = rknpu_job_commit(job);
if (job->run_count == 0) {
if (job->args->core_mask & RKNPU_CORE0_MASK)
job->ret = rknpu_job_commit(job, 0);
if (job->args->core_mask & RKNPU_CORE1_MASK)
job->ret = rknpu_job_commit(job, 1);
if (job->args->core_mask & RKNPU_CORE2_MASK)
job->ret = rknpu_job_commit(job, 2);
}
}
static void rknpu_job_done(struct rknpu_job *job, int ret)
static void rknpu_job_done(struct rknpu_job *job, int ret, int core_index)
{
struct rknpu_device *rknpu_dev = job->rknpu_dev;
struct rknpu_subcore_data *subcore_data = NULL;
unsigned long flags;
int task_num = 0;
subcore_data = &rknpu_dev->subcore_datas[core_index];
task_num = rknn_get_task_number(job, core_index);
spin_lock_irqsave(&rknpu_dev->irq_lock, flags);
rknpu_dev->job = NULL;
subcore_data->job = NULL;
subcore_data->task_num = subcore_data->task_num - task_num;
job->interrupt_count--;
spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags);
job->flags |= RKNPU_JOB_DONE;
job->ret = ret;
if (job->interrupt_count == 0) {
job->flags |= RKNPU_JOB_DONE;
job->ret = ret;
if (job->fence)
dma_fence_signal(job->fence);
if (job->fence)
dma_fence_signal(job->fence);
wake_up(&rknpu_dev->job_done_wq);
rknpu_job_next(rknpu_dev);
if (job->use_core_num > 1)
wake_up(&(&rknpu_dev->subcore_datas[0])->job_done_wq);
else
wake_up(&subcore_data->job_done_wq);
}
rknpu_job_next(rknpu_dev, core_index);
if (job->flags & RKNPU_JOB_ASYNC)
schedule_work(&job->cleanup_work);
@@ -231,28 +329,97 @@ static void rknpu_job_done(struct rknpu_job *job, int ret)
static void rknpu_job_schedule(struct rknpu_job *job)
{
struct rknpu_device *rknpu_dev = job->rknpu_dev;
struct rknpu_subcore_data *subcore_data = NULL;
int i = 0, core_index = 0;
unsigned long flags;
int task_num_list[3] = { 0, 1, 2 };
int task_num = 0;
int tmp = 0;
if ((job->args->core_mask & 0x07) == RKNPU_CORE_AUTO_MASK) {
if (rknpu_dev->subcore_datas[0].task_num >
rknpu_dev->subcore_datas[1].task_num) {
tmp = task_num_list[1];
task_num_list[1] = task_num_list[0];
task_num_list[0] = tmp;
}
if (rknpu_dev->subcore_datas[task_num_list[0]].task_num >
rknpu_dev->subcore_datas[2].task_num) {
tmp = task_num_list[2];
task_num_list[2] = task_num_list[1];
task_num_list[1] = task_num_list[0];
task_num_list[0] = tmp;
} else if (rknpu_dev->subcore_datas[task_num_list[1]].task_num >
rknpu_dev->subcore_datas[2].task_num) {
tmp = task_num_list[2];
task_num_list[2] = task_num_list[1];
task_num_list[1] = tmp;
}
if (!rknpu_dev->subcore_datas[task_num_list[0]].job)
core_index = task_num_list[0];
else if (!rknpu_dev->subcore_datas[task_num_list[1]].job)
core_index = task_num_list[1];
else if (!rknpu_dev->subcore_datas[task_num_list[2]].job)
core_index = task_num_list[2];
else
core_index = task_num_list[0];
job->args->core_mask = rknpu_core_mask(core_index);
job->use_core_num = 1;
job->interrupt_count = 1;
job->run_count = 1;
}
spin_lock_irqsave(&rknpu_dev->irq_lock, flags);
list_add_tail(&job->head, &rknpu_dev->todo_list);
for (i = 0; i < rknpu_dev->config->num_irqs; i++) {
if (job->args->core_mask & rknpu_core_mask(i)) {
subcore_data = &rknpu_dev->subcore_datas[i];
task_num = rknn_get_task_number(job, i);
subcore_data->task_num =
subcore_data->task_num + task_num;
list_add_tail(&job->head[i], &subcore_data->todo_list);
}
}
spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags);
rknpu_job_next(rknpu_dev);
for (i = 0; i < rknpu_dev->config->num_irqs; i++) {
if (job->args->core_mask & rknpu_core_mask(i))
rknpu_job_next(rknpu_dev, i);
}
}
static void rknpu_job_abort(struct rknpu_job *job)
{
struct rknpu_device *rknpu_dev = job->rknpu_dev;
struct rknpu_subcore_data *subcore_data = NULL;
int core_index = rknpu_core_index(job->args->core_mask);
void __iomem *rknpu_core_base = rknpu_dev->base[core_index];
unsigned long flags;
int i = 0;
int task_num = 0;
msleep(100);
if (job->ret == -ETIMEDOUT)
if (job->ret == -ETIMEDOUT) {
LOG_ERROR(
"job timeout, irq status: %#x, raw status: %#x, require mask: %#x\n",
REG_READ(RKNPU_OFFSET_INT_STATUS),
REG_READ(RKNPU_OFFSET_INT_RAW_STATUS),
job->int_mask[core_index]);
rknpu_soft_reset(rknpu_dev);
if (job == rknpu_dev->job) {
spin_lock_irqsave(&rknpu_dev->irq_lock, flags);
rknpu_dev->job = NULL;
spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags);
}
for (i = 0; i < rknpu_dev->config->num_irqs; i++) {
if (job->args->core_mask & rknpu_core_mask(i)) {
subcore_data = &rknpu_dev->subcore_datas[i];
if (job == subcore_data->job) {
spin_lock_irqsave(&rknpu_dev->irq_lock, flags);
task_num = rknn_get_task_number(job, i);
subcore_data->job = NULL;
subcore_data->task_num =
subcore_data->task_num - task_num;
spin_unlock_irqrestore(&rknpu_dev->irq_lock,
flags);
}
}
}
rknpu_job_cleanup(job);
@@ -283,10 +450,11 @@ static inline uint32_t rknpu_fuzz_status(uint32_t status)
return fuzz_status;
}
irqreturn_t rknpu_irq_handler(int irq, void *data)
static inline irqreturn_t rknpu_irq_handler(int irq, void *data, int core_index)
{
struct rknpu_device *rknpu_dev = data;
struct rknpu_job *job = rknpu_dev->job;
struct rknpu_job *job = rknpu_dev->subcore_datas[core_index].job;
void __iomem *rknpu_core_base = rknpu_dev->base[core_index];
uint32_t status = 0;
if (!job)
@@ -295,49 +463,81 @@ irqreturn_t rknpu_irq_handler(int irq, void *data)
status = REG_READ(RKNPU_OFFSET_INT_STATUS);
REG_WRITE(RKNPU_INT_CLEAR, RKNPU_OFFSET_INT_CLEAR);
job->int_status = status;
job->int_status[core_index] = status;
if (rknpu_fuzz_status(status) != job->int_mask) {
LOG_DEBUG("irq: status = %#x, mask = %#x\n", status,
job->int_mask);
if (rknpu_fuzz_status(status) != job->int_mask[core_index]) {
LOG_ERROR(
"invalid irq status: %#x, raw status: %#x, require mask: %#x\n",
status, REG_READ(RKNPU_OFFSET_INT_RAW_STATUS),
job->int_mask[core_index]);
return IRQ_HANDLED;
}
rknpu_job_done(job, 0);
rknpu_job_done(job, 0, core_index);
return IRQ_HANDLED;
}
static void rknpu_job_timeout_clean(struct rknpu_device *rknpu_dev)
irqreturn_t rknpu_core0_irq_handler(int irq, void *data)
{
return rknpu_irq_handler(irq, data, 0);
}
irqreturn_t rknpu_core1_irq_handler(int irq, void *data)
{
return rknpu_irq_handler(irq, data, 1);
}
irqreturn_t rknpu_core2_irq_handler(int irq, void *data)
{
return rknpu_irq_handler(irq, data, 2);
}
static void rknpu_job_timeout_clean(struct rknpu_device *rknpu_dev,
int core_mask)
{
struct rknpu_job *job = NULL;
unsigned long flags;
ktime_t now = ktime_get();
struct rknpu_subcore_data *subcore_data = NULL;
int i = 0;
job = rknpu_dev->job;
if (job &&
ktime_to_ms(ktime_sub(now, job->timestamp)) >= job->args->timeout) {
rknpu_soft_reset(rknpu_dev);
for (i = 0; i < rknpu_dev->config->num_irqs; i++) {
if (core_mask & rknpu_core_mask(i)) {
subcore_data = &rknpu_dev->subcore_datas[i];
job = subcore_data->job;
if (job &&
ktime_to_ms(ktime_sub(now, job->timestamp)) >=
job->args->timeout) {
rknpu_soft_reset(rknpu_dev);
spin_lock_irqsave(&rknpu_dev->irq_lock, flags);
rknpu_dev->job = NULL;
spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags);
spin_lock_irqsave(&rknpu_dev->irq_lock, flags);
subcore_data->job = NULL;
spin_unlock_irqrestore(&rknpu_dev->irq_lock,
flags);
do {
schedule_work(&job->cleanup_work);
do {
schedule_work(&job->cleanup_work);
spin_lock_irqsave(&rknpu_dev->irq_lock, flags);
spin_lock_irqsave(&rknpu_dev->irq_lock,
flags);
if (!list_empty(&rknpu_dev->todo_list)) {
job = list_first_entry(&rknpu_dev->todo_list,
struct rknpu_job, head);
list_del_init(&job->head);
} else {
job = NULL;
if (!list_empty(
&subcore_data->todo_list)) {
job = list_first_entry(
&subcore_data->todo_list,
struct rknpu_job,
head[i]);
list_del_init(&job->head[i]);
} else {
job = NULL;
}
spin_unlock_irqrestore(
&rknpu_dev->irq_lock, flags);
} while (job);
}
spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags);
} while (job);
}
}
}
@@ -360,7 +560,38 @@ int rknpu_submit_ioctl(struct drm_device *dev, void *data,
return -ENOMEM;
}
if (args->flags & RKNPU_JOB_FENCE) {
if (args->flags & RKNPU_JOB_FENCE_IN) {
struct dma_fence *in_fence;
in_fence = sync_file_get_fence(args->fence_fd);
if (!in_fence) {
LOG_ERROR("invalid fence in fd, fd = %d\n",
args->fence_fd);
return -EINVAL;
}
args->fence_fd = -1;
/*
* Wait if the fence is from a foreign context, or if the fence
* array contains any fence from a foreign context.
*/
ret = 0;
if (!dma_fence_match_context(in_fence,
rknpu_dev->fence_ctx->context))
ret = dma_fence_wait_timeout(in_fence, true,
args->timeout);
dma_fence_put(in_fence);
if (ret < 0) {
if (ret != -ERESTARTSYS)
LOG_ERROR("Error (%d) waiting for fence!\n",
ret);
return ret;
}
}
if (args->flags & RKNPU_JOB_FENCE_OUT) {
ret = rknpu_fence_alloc(job);
if (ret) {
rknpu_job_free(job);
@@ -372,7 +603,7 @@ int rknpu_submit_ioctl(struct drm_device *dev, void *data,
if (args->flags & RKNPU_JOB_NONBLOCK) {
job->flags |= RKNPU_JOB_ASYNC;
rknpu_job_timeout_clean(rknpu_dev);
rknpu_job_timeout_clean(rknpu_dev, job->args->core_mask);
rknpu_job_schedule(job);
ret = job->ret;
if (ret) {
@@ -397,6 +628,8 @@ int rknpu_submit_ioctl(struct drm_device *dev, void *data,
int rknpu_get_hw_version(struct rknpu_device *rknpu_dev, uint32_t *version)
{
void __iomem *rknpu_core_base = rknpu_dev->base[0];
if (version != NULL)
*version = REG_READ(RKNPU_OFFSET_VERSION);
@@ -408,6 +641,11 @@ int rknpu_get_bw_priority(struct rknpu_device *rknpu_dev, uint32_t *priority,
{
void __iomem *base = rknpu_dev->bw_priority_base;
if (!rknpu_dev->config->bw_enable) {
LOG_WARN("Get bw_priority is not supported on this device!\n");
return 0;
}
if (!base)
return -EINVAL;
@@ -432,6 +670,11 @@ int rknpu_set_bw_priority(struct rknpu_device *rknpu_dev, uint32_t priority,
{
void __iomem *base = rknpu_dev->bw_priority_base;
if (!rknpu_dev->config->bw_enable) {
LOG_WARN("Set bw_priority is not supported on this device!\n");
return 0;
}
if (!base)
return -EINVAL;
@@ -453,6 +696,13 @@ int rknpu_set_bw_priority(struct rknpu_device *rknpu_dev, uint32_t priority,
int rknpu_clear_rw_amount(struct rknpu_device *rknpu_dev)
{
void __iomem *rknpu_core_base = rknpu_dev->base[0];
if (!rknpu_dev->config->bw_enable) {
LOG_WARN("Clear rw_amount is not supported on this device!\n");
return 0;
}
spin_lock(&rknpu_dev->lock);
REG_WRITE(0x80000101, RKNPU_OFFSET_CLR_ALL_RW_AMOUNT);
@@ -466,6 +716,13 @@ int rknpu_clear_rw_amount(struct rknpu_device *rknpu_dev)
int rknpu_get_rw_amount(struct rknpu_device *rknpu_dev, uint32_t *dt_wr,
uint32_t *dt_rd, uint32_t *wd_rd)
{
void __iomem *rknpu_core_base = rknpu_dev->base[0];
if (!rknpu_dev->config->bw_enable) {
LOG_WARN("Get rw_amount is not supported on this device!\n");
return 0;
}
spin_lock(&rknpu_dev->lock);
if (dt_wr != NULL)
@@ -489,6 +746,12 @@ int rknpu_get_total_rw_amount(struct rknpu_device *rknpu_dev, uint32_t *amount)
uint32_t wd_rd = 0;
int ret = -EINVAL;
if (!rknpu_dev->config->bw_enable) {
LOG_WARN(
"Get total_rw_amount is not supported on this device!\n");
return 0;
}
ret = rknpu_get_rw_amount(rknpu_dev, &dt_wr, &dt_rd, &wd_rd);
if (amount != NULL)

View File

@@ -9,6 +9,7 @@
#include "rknpu_reset.h"
#ifndef FPGA_PLATFORM
static inline struct reset_control *rknpu_reset_control_get(struct device *dev,
const char *name)
{
@@ -22,27 +23,38 @@ static inline struct reset_control *rknpu_reset_control_get(struct device *dev,
return rst;
}
#endif
int rknpu_reset_get(struct rknpu_device *rknpu_dev)
{
#ifndef FPGA_PLATFORM
struct reset_control *srst_a = NULL;
struct reset_control *srst_h = NULL;
int i = 0;
srst_a = rknpu_reset_control_get(rknpu_dev->dev, "srst_a");
if (IS_ERR(srst_a))
return PTR_ERR(srst_a);
for (i = 0; i < rknpu_dev->config->num_resets; i++) {
srst_a = rknpu_reset_control_get(
rknpu_dev->dev,
rknpu_dev->config->resets[i].srst_a_name);
if (IS_ERR(srst_a))
return PTR_ERR(srst_a);
rknpu_dev->srst_a = srst_a;
rknpu_dev->srst_a[i] = srst_a;
srst_h = devm_reset_control_get(rknpu_dev->dev, "srst_h");
if (IS_ERR(srst_h))
return PTR_ERR(srst_h);
srst_h = rknpu_reset_control_get(
rknpu_dev->dev,
rknpu_dev->config->resets[i].srst_h_name);
if (IS_ERR(srst_h))
return PTR_ERR(srst_h);
rknpu_dev->srst_h = srst_h;
rknpu_dev->srst_h[i] = srst_h;
}
#endif
return 0;
}
#ifndef FPGA_PLATFORM
static int rknpu_reset_assert(struct reset_control *rst)
{
int ret = -EINVAL;
@@ -74,11 +86,13 @@ static int rknpu_reset_deassert(struct reset_control *rst)
return 0;
}
#endif
int rknpu_soft_reset(struct rknpu_device *rknpu_dev)
{
#ifndef FPGA_PLATFORM
struct iommu_domain *domain = NULL;
int ret = -EINVAL;
int ret = -EINVAL, i = 0;
if (rknpu_dev->bypass_soft_reset) {
LOG_WARN("bypass soft reset\n");
@@ -87,13 +101,15 @@ int rknpu_soft_reset(struct rknpu_device *rknpu_dev)
LOG_INFO("soft reset\n");
ret = rknpu_reset_assert(rknpu_dev->srst_a);
ret |= rknpu_reset_assert(rknpu_dev->srst_h);
for (i = 0; i < rknpu_dev->config->num_resets; i++) {
ret = rknpu_reset_assert(rknpu_dev->srst_a[i]);
ret |= rknpu_reset_assert(rknpu_dev->srst_h[i]);
udelay(10);
udelay(10);
ret |= rknpu_reset_deassert(rknpu_dev->srst_a);
ret |= rknpu_reset_deassert(rknpu_dev->srst_h);
ret |= rknpu_reset_deassert(rknpu_dev->srst_a[i]);
ret |= rknpu_reset_deassert(rknpu_dev->srst_h[i]);
}
if (ret) {
LOG_DEV_ERROR(rknpu_dev->dev,
@@ -108,6 +124,7 @@ int rknpu_soft_reset(struct rknpu_device *rknpu_dev)
iommu_detach_device(domain, rknpu_dev->dev);
iommu_attach_device(domain, rknpu_dev->dev);
}
#endif
return ret;
return 0;
}