1584 lines
49 KiB
Diff
1584 lines
49 KiB
Diff
From 6e2d06ee741e9b2b073ec0ccd91ee5289ca904ae Mon Sep 17 00:00:00 2001
|
|
From: zouxiaojun <zouxiaojun@eswincomputing.com>
|
|
Date: Mon, 29 Jul 2024 17:05:54 +0800
|
|
Subject: [PATCH 157/219] fix(enc):fix hang issue of ve roi
|
|
|
|
Changelogs:
|
|
A certain timeout cycles might lead hw bug, causing ve to get stuck when
|
|
encoding next frame. It need to restart vcmd and ve core while met the following two
|
|
conditions:
|
|
1. The hw bug is detected when the vcmd JMP interrupt callback;
|
|
2. The encoding tasks are timeout;
|
|
|
|
Signed-off-by: zouxiaojun <zouxiaojun@eswincomputing.com>
|
|
---
|
|
.../dts/eswin/eswin-win2030-die0-soc.dtsi | 3 +-
|
|
.../dts/eswin/eswin-win2030-die1-soc.dtsi | 3 +-
|
|
drivers/staging/media/eswin/venc/Makefile | 1 +
|
|
.../media/eswin/venc/vc8000_vcmd_driver.c | 594 ++++++++++++++++--
|
|
.../staging/media/eswin/venc/vc8000e_driver.c | 392 ++++++++----
|
|
5 files changed, 820 insertions(+), 173 deletions(-)
|
|
|
|
diff --git a/arch/riscv/boot/dts/eswin/eswin-win2030-die0-soc.dtsi b/arch/riscv/boot/dts/eswin/eswin-win2030-die0-soc.dtsi
|
|
index 13a40780a619..2785eb640b3a 100644
|
|
--- a/arch/riscv/boot/dts/eswin/eswin-win2030-die0-soc.dtsi
|
|
+++ b/arch/riscv/boot/dts/eswin/eswin-win2030-die0-soc.dtsi
|
|
@@ -1027,19 +1027,20 @@ venc0: video-encoder@50110000 {
|
|
iommus = <&smmu0 WIN2030_SID_VENC>;
|
|
vccsr-reg = <0x0 0x501c0000 0x0 0x1000>;
|
|
numa-node-id = <0>;
|
|
- tbus = <WIN2030_TBUID_VENC>, <WIN2030_TBUID_JENC>;
|
|
dma-noncoherent;
|
|
|
|
venc_0: venc0@50110000 {
|
|
core-name = "video-enc0";
|
|
base-addr = <0x50110000>;
|
|
interrupts = <229>;
|
|
+ tbus = <WIN2030_TBUID_VENC>;
|
|
};
|
|
|
|
jenc_0: jenc0@50130000 {
|
|
core-name = "jpeg-enc0";
|
|
base-addr = <0x50130000>;
|
|
interrupts = <232>;
|
|
+ tbus = <WIN2030_TBUID_JENC>;
|
|
};
|
|
};
|
|
|
|
diff --git a/arch/riscv/boot/dts/eswin/eswin-win2030-die1-soc.dtsi b/arch/riscv/boot/dts/eswin/eswin-win2030-die1-soc.dtsi
|
|
index be08ead18fa8..9883a0b1a8bf 100644
|
|
--- a/arch/riscv/boot/dts/eswin/eswin-win2030-die1-soc.dtsi
|
|
+++ b/arch/riscv/boot/dts/eswin/eswin-win2030-die1-soc.dtsi
|
|
@@ -438,19 +438,20 @@ venc1: video-encoder@70110000 {
|
|
iommus = <&smmu1 WIN2030_SID_VENC>;
|
|
vccsr-reg = <0x0 0x701c0000 0x0 0x1000>;
|
|
numa-node-id = <1>;
|
|
- tbus = <WIN2030_TBUID_VENC>, <WIN2030_TBUID_JENC>;
|
|
dma-noncoherent;
|
|
|
|
venc_1: venc0@70110000 {
|
|
core-name = "video-enc0";
|
|
base-addr = <0x70110000>;
|
|
interrupts = <229>;
|
|
+ tbus = <WIN2030_TBUID_VENC>;
|
|
};
|
|
|
|
jenc_1: jenc0@70130000 {
|
|
core-name = "jpeg-enc0";
|
|
base-addr = <0x70130000>;
|
|
interrupts = <232>;
|
|
+ tbus = <WIN2030_TBUID_JENC>;
|
|
};
|
|
};
|
|
/*mailbox between u84 & scpu*/
|
|
diff --git a/drivers/staging/media/eswin/venc/Makefile b/drivers/staging/media/eswin/venc/Makefile
|
|
index c14e399e3393..745450bf20c6 100644
|
|
--- a/drivers/staging/media/eswin/venc/Makefile
|
|
+++ b/drivers/staging/media/eswin/venc/Makefile
|
|
@@ -1,6 +1,7 @@
|
|
# SPDX-License-Identifier: GPL-2.0-only
|
|
ccflags-y += -DSUPPORT_DMA_HEAP
|
|
ccflags-y += -DHANTROAXIFE_SUPPORT -DHANTROVCMD_ENABLE_IP_SUPPORT
|
|
+ccflags-y += -DSUPPORT_WATCHDOG
|
|
es_venc-objs := vc8000_axife.o vc8000_normal_driver.o vc8000_vcmd_driver.o vc8000e_driver.o bidirect_list.o vcmdswhwregisters.o
|
|
|
|
obj-$(CONFIG_VIDEO_ESWIN_VENC) += es_venc.o
|
|
diff --git a/drivers/staging/media/eswin/venc/vc8000_vcmd_driver.c b/drivers/staging/media/eswin/venc/vc8000_vcmd_driver.c
|
|
index 33137277dda6..d08a8effc7f2 100644
|
|
--- a/drivers/staging/media/eswin/venc/vc8000_vcmd_driver.c
|
|
+++ b/drivers/staging/media/eswin/venc/vc8000_vcmd_driver.c
|
|
@@ -93,6 +93,7 @@
|
|
#include <linux/vmalloc.h>
|
|
#include <linux/timer.h>
|
|
#include <linux/delay.h>
|
|
+#include <linux/kthread.h>
|
|
|
|
/* device tree access */
|
|
#include <linux/of.h>
|
|
@@ -123,6 +124,7 @@
|
|
|
|
#define MAX_VCMD_NUMBER (MAX_VCMD_TYPE * MAX_SAME_MODULE_TYPE_CORE_NUMBER) //
|
|
|
|
+#define HW_WORK_STATE_IDLE 0
|
|
#define HW_WORK_STATE_PEND 3
|
|
|
|
#define MAX_CMDBUF_INT_NUMBER 1
|
|
@@ -130,6 +132,12 @@
|
|
#define MAX_PROCESS_CORE_NUMBER (4 * 8)
|
|
#define PROCESS_MAX_SUM_OF_IMAGE_SIZE (4096 * 2160 * MAX_SAME_MODULE_TYPE_CORE_NUMBER * MAX_PROCESS_CORE_NUMBER)
|
|
|
|
+/** the wait time for the vcmd task list(in milliseconds):
|
|
+ * 200x frame encoding time + 1000ms
|
|
+ * = size*200*1000/800000000 + 1000
|
|
+*/
|
|
+#define ENC_VCMD_WAIT_TIME(size) (size/4000 + 1000)
|
|
+
|
|
#define MAX_SAME_MODULE_TYPE_CORE_NUMBER 4
|
|
|
|
|
|
@@ -226,6 +234,13 @@ struct hantrovcmd_dev {
|
|
|
|
unsigned int mmu_vcmd_reg_mem_busAddress; //start mmu mapping address of vcmd registers memory of CMDBUF.
|
|
u32 vcmd_reg_mem_size; // size of vcmd registers memory of CMDBUF.
|
|
+
|
|
+ // watchdog
|
|
+ struct timer_list watchdog_timer;
|
|
+ u8 watchdog_active;
|
|
+ u8 watchdog_triggered;
|
|
+ u32 vce_hang;
|
|
+ u32 restart_cmdbuf_id;
|
|
};
|
|
|
|
/*
|
|
@@ -283,11 +298,14 @@ static void create_kernel_process_manager(void);
|
|
static irqreturn_t hantrovcmd_isr(int irq, void *dev_id);
|
|
|
|
/** pm runtime sync & put*/
|
|
-extern int venc_pm_runtime_sync(u32 core_id);
|
|
-extern int venc_pm_runtime_put(u32 core_id);
|
|
+extern int enc_pm_runtime_sync(u32 core_id);
|
|
+extern int enc_pm_runtime_put(u32 core_id);
|
|
+/** system reset*/
|
|
+extern int enc_reset_system(u32 core_id);
|
|
|
|
#ifdef VCMD_DEBUG_INTERNAL
|
|
static void printk_vcmd_register_debug(const void *hwregs, char *info);
|
|
+static void PrintInstr(u32 i, u32 instr, u32 *size);
|
|
#endif
|
|
|
|
/*********************local variable declaration*****************/
|
|
@@ -300,7 +318,10 @@ int venc_vcmd_core_num = 0;
|
|
static struct hantrovcmd_dev *hantrovcmd_data;
|
|
|
|
static int software_triger_abort;
|
|
-
|
|
+// kernel thread
|
|
+struct task_struct *kthread;
|
|
+u8 stop_kthread;
|
|
+wait_queue_head_t kthread_waitq;
|
|
|
|
#ifdef IRQ_SIMULATION
|
|
struct timer_manager {
|
|
@@ -325,6 +346,409 @@ static wait_queue_head_t wait_queue_vcmd[MAX_VCMD_NUMBER];
|
|
|
|
static wait_queue_head_t abort_queue_vcmd[MAX_VCMD_NUMBER];
|
|
|
|
+/**
|
|
+ * @brief hook function for system-driver to do further process
|
|
+ * for abort vcmd failed.
|
|
+ */
|
|
+static void hook_vcmd_abort_failed(struct hantrovcmd_dev *dev)
|
|
+{
|
|
+ /** wait_event_xxx could not be interrupt by pm suspend*/
|
|
+ LOG_ERR("dev[%d]: vcmd abort failed, need to do further process\n", dev->core_id);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief wait jobs count that need to be finished from dev list
|
|
+ */
|
|
+static u32 dev_wait_job_exetime(struct hantrovcmd_dev *dev)
|
|
+{
|
|
+ struct cmdbuf_obj *obj;
|
|
+ bi_list_node *node = dev->list_manager.head;
|
|
+ u32 exttime = 0;
|
|
+
|
|
+ while (node) {
|
|
+ obj = (struct cmdbuf_obj *)node->data;
|
|
+ if (obj->cmdbuf_run_done == 0) {
|
|
+ exttime += obj->executing_time;
|
|
+ if (obj->has_end_cmdbuf == 1 || obj->no_normal_int_cmdbuf == 0) {
|
|
+ return exttime;
|
|
+ }
|
|
+ }
|
|
+ node = node->next;
|
|
+ }
|
|
+
|
|
+ return exttime;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * check if hang after receive JMP interrupt
|
|
+ */
|
|
+static int check_vce_hang(struct hantrovcmd_dev *dev, u32 cmdbuf_id)
|
|
+{
|
|
+ u32 *status_virt;
|
|
+
|
|
+ if (dev->vcmd_core_cfg.sub_module_type != VCMD_TYPE_ENCODER)
|
|
+ return 0;
|
|
+
|
|
+ status_virt = vcmd_status_buf_mem_pool.virtualAddress + \
|
|
+ cmdbuf_id*CMDBUF_MAX_SIZE / 4 + \
|
|
+ (dev->vcmd_core_cfg.submodule_main_addr / 2 / 4 + 0);
|
|
+
|
|
+ if (*(status_virt + 217) != *(status_virt + 218)) {
|
|
+ LOG_INFO("check vce hang, cmdbuf_id=%u, swreg217=0x%08x, swreg218=0x%08x\n"
|
|
+ , cmdbuf_id, status_virt[217], status_virt[218]);
|
|
+
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief abort vcmd
|
|
+ */
|
|
+static int vcmd_abort(struct hantrovcmd_dev *dev)
|
|
+{
|
|
+ unsigned long flags;
|
|
+ u32 state;
|
|
+ u8 pend_state;
|
|
+
|
|
+ state = vcmd_get_register_value((const void *)dev->hwregs,
|
|
+ dev->reg_mirror, HWIF_VCMD_WORK_STATE);
|
|
+ pend_state = (state == HW_WORK_STATE_PEND) ? 1 : 0;
|
|
+ LOG_INFO("vcmd_abort, start vcmd aborting, vcmd state = %u, vce_hang = %u, working_state = %u\n"
|
|
+ , state, dev->vce_hang, dev->working_state);
|
|
+ spin_lock_irqsave(dev->spinlock, flags);
|
|
+ if (state == HW_WORK_STATE_IDLE) {
|
|
+ dev->vce_hang = 0;
|
|
+ spin_unlock_irqrestore(dev->spinlock, flags);
|
|
+ return 0;
|
|
+ }
|
|
+ if (dev->vce_hang)
|
|
+ vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_ABORT_MODE, 0x1);
|
|
+ else
|
|
+ vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_ABORT_MODE, 0x0);
|
|
+
|
|
+ software_triger_abort = 1;
|
|
+ vcmd_write_register_value((const void *)dev->hwregs,
|
|
+ dev->reg_mirror,
|
|
+ HWIF_VCMD_START_TRIGGER, 0);
|
|
+ spin_unlock_irqrestore(dev->spinlock, flags);
|
|
+
|
|
+#ifdef VCMD_POLLING_ISR
|
|
+ int loop_cnt = 0;
|
|
+
|
|
+ do {
|
|
+ state = vcmd_get_register_value((const void *)dev->hwregs,
|
|
+ dev->reg_mirror, HWIF_VCMD_WORK_STATE);
|
|
+ if (state == HW_WORK_STATE_IDLE) {
|
|
+ if (pend_state)
|
|
+ hantrovcmd_isr(0, dev);
|
|
+ //aborted
|
|
+ break;
|
|
+ }
|
|
+ mdelay(10); // wait 10ms
|
|
+ } while (++loop_cnt < 100);
|
|
+
|
|
+ if (loop_cnt < 100) {
|
|
+ mdelay(10);
|
|
+ software_triger_abort = 0;
|
|
+ return 0;
|
|
+ }
|
|
+ software_triger_abort = 0;
|
|
+ LOG_ERR("%s, can't go to IDLE, need to re-power sub-system!\n", __func__);
|
|
+ return -1;
|
|
+#else
|
|
+ if (wait_event_interruptible(*dev->wait_abort_queue,
|
|
+ (dev->working_state == WORKING_STATE_IDLE))) {
|
|
+ software_triger_abort = 0;
|
|
+ LOG_ERR("vcmd_abort: wait_abort_queue is signaled!!! software_triger_abort_ = 0\n");
|
|
+ return -ERESTARTSYS;
|
|
+ }
|
|
+ LOG_INFO("vcmd_abort, vcmd abort completed, state = %u, software_triger_abort_ = 0\n"
|
|
+ , dev->working_state);
|
|
+
|
|
+ software_triger_abort = 0;
|
|
+ return 0;
|
|
+#endif
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief stop vcmd when hang
|
|
+*/
|
|
+static int stop_vcmd(struct hantrovcmd_dev *dev)
|
|
+{
|
|
+ int ret = 0;
|
|
+
|
|
+ // abort vcmd of vce immediately
|
|
+ ret = vcmd_abort(dev);
|
|
+ if (ret < 0)
|
|
+ hook_vcmd_abort_failed(dev);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief reset system after vce vcmd abort
|
|
+ */
|
|
+static void reset_system(struct hantrovcmd_dev *dev)
|
|
+{
|
|
+ LOG_INFO("reset vce system, working_state = %u!\n", dev->working_state);
|
|
+ if (dev->working_state == HW_WORK_STATE_IDLE) {
|
|
+ int ret = enc_reset_system(dev->core_id);
|
|
+ LOG_INFO("reset vce system completed! ret = %d\n", ret);
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ * restart vcmd for re-encode
|
|
+ */
|
|
+static void restart_vcmd(struct hantrovcmd_dev *dev)
|
|
+{
|
|
+ bi_list_node *restart_node = NULL;
|
|
+
|
|
+ LOG_INFO("restart_vcmd, restart_cmdbuf_id = %u\n", dev->restart_cmdbuf_id);
|
|
+ /* restart VCE vcmd */
|
|
+ if (dev->restart_cmdbuf_id != 0XFFFF) {
|
|
+ unsigned long flags = 0;
|
|
+
|
|
+ spin_lock_irqsave(dev->spinlock, flags);
|
|
+ restart_node = global_cmdbuf_node[dev->restart_cmdbuf_id];
|
|
+ if (restart_node == NULL)
|
|
+ restart_node = dev->list_manager.head;
|
|
+ while (restart_node &&
|
|
+ ((struct cmdbuf_obj *)restart_node->data)->cmdbuf_run_done)
|
|
+ restart_node = restart_node->next;
|
|
+ if (restart_node) {
|
|
+ LOG_INFO("restart_vcmd, restart_node cmdbuf_id = %u, cmdbuf_run_done = %u"
|
|
+ , ((struct cmdbuf_obj *)restart_node->data)->cmdbuf_id
|
|
+ , ((struct cmdbuf_obj *)restart_node->data)->cmdbuf_run_done);
|
|
+ } else {
|
|
+ LOG_INFO("restart_vcmd, no restart_node found, make vcmd idle\n");
|
|
+ }
|
|
+ LOG_INFO("restart_vcmd, sw_cmdbuf_rdy_num = %u, working_state = %u\n"
|
|
+ , dev->sw_cmdbuf_rdy_num, dev->working_state);
|
|
+ if (dev->sw_cmdbuf_rdy_num == 0)
|
|
+ vcmd_link_cmdbuf(dev, restart_node);
|
|
+ if (dev->sw_cmdbuf_rdy_num != 0)
|
|
+ vcmd_start(dev, restart_node);
|
|
+ dev->restart_cmdbuf_id = 0xFFFF;
|
|
+
|
|
+ spin_unlock_irqrestore(dev->spinlock, flags);
|
|
+ LOG_INFO("restart_vcmd, restart vcmd completed\n");
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ * vce hang process
|
|
+ */
|
|
+static void vce_hang_process(struct hantrovcmd_dev *dev)
|
|
+{
|
|
+ int ret = 0;
|
|
+ LOG_INFO("vce hang process start\n");
|
|
+ /* abort VCE vcmd */
|
|
+ ret = stop_vcmd(dev);
|
|
+ if (ret == 0) {
|
|
+ /* do system reset */
|
|
+ reset_system(dev);
|
|
+ /* re-encode */
|
|
+ restart_vcmd(dev);
|
|
+ } else {
|
|
+ LOG_ERR("vce hang process failed, failed to stop vcmd\n");
|
|
+ }
|
|
+ LOG_INFO("vce hang process completed\n");
|
|
+}
|
|
+
|
|
+#ifdef SUPPORT_WATCHDOG
|
|
+/**
|
|
+ * @brief process when watchdog triggered.
|
|
+ */
|
|
+static void _vcmd_watchdog_process(struct hantrovcmd_dev *dev)
|
|
+{
|
|
+ if (dev->vce_hang)
|
|
+ vce_hang_process(dev);
|
|
+}
|
|
+#endif
|
|
+
|
|
+/**
|
|
+ * @brief To check dev's actions which need kthread to process
|
|
+ * @return int: 0: no actions; 1: have actions
|
|
+ */
|
|
+static int _vcmd_kthread_actions(struct hantrovcmd_dev **dev)
|
|
+{
|
|
+ int ret = 0, i;
|
|
+
|
|
+ if (stop_kthread == 1) {
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < venc_vcmd_core_num; i++) {
|
|
+ *dev = &hantrovcmd_data[i];
|
|
+ if ((*dev)->vce_hang
|
|
+#ifdef SUPPORT_WATCHDOG
|
|
+ || (*dev)->watchdog_triggered == 1
|
|
+#endif
|
|
+ ) {
|
|
+ ret = 1;
|
|
+ break;
|
|
+ } else {
|
|
+ ret = 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief vcmd kernel thread main function
|
|
+ */
|
|
+static int _vcmd_kthread_fn(void *data)
|
|
+{
|
|
+ struct hantrovcmd_dev *dev = NULL;
|
|
+
|
|
+ LOG_INFO("vcmd kthread enter\n");
|
|
+ while (!kthread_should_stop()) {
|
|
+ dev = NULL;
|
|
+ if (wait_event_interruptible(kthread_waitq,
|
|
+ _vcmd_kthread_actions(&dev))) {
|
|
+ /** wait_event_xxx could not be interrupt by pm suspend*/
|
|
+ LOG_ERR("wait kthread_waitq, signaled!!!\n");
|
|
+ return -ERESTARTSYS;
|
|
+ }
|
|
+ if (dev == NULL)
|
|
+ continue;
|
|
+
|
|
+ if (dev->vce_hang) {
|
|
+ vce_hang_process(dev);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+#ifdef SUPPORT_WATCHDOG
|
|
+ if (dev->watchdog_triggered == 1) {
|
|
+ if (dev->vcmd_core_cfg.sub_module_type == VCMD_TYPE_ENCODER)
|
|
+ dev->vce_hang = 1;
|
|
+ else
|
|
+ LOG_ERR("Non-VE module is also timeout, module_type = %u, core_id = %u\n"
|
|
+ , dev->vcmd_core_cfg.sub_module_type, dev->core_id);
|
|
+ dev->watchdog_triggered = 0;
|
|
+ _vcmd_watchdog_process(dev);
|
|
+
|
|
+ continue;
|
|
+ }
|
|
+#endif
|
|
+ }
|
|
+ LOG_INFO("vcmd kthread exit\n");
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief wake up vcmd kernel thread
|
|
+ */
|
|
+static void _vcmd_kthread_wakeup(void)
|
|
+{
|
|
+
|
|
+ if (IS_ERR(kthread))
|
|
+ return;
|
|
+
|
|
+ wake_up_interruptible_all(&kthread_waitq);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief create kernel thread for vcmd driver
|
|
+ */
|
|
+static void _vcmd_kthread_create(void)
|
|
+{
|
|
+ stop_kthread = 0;
|
|
+ init_waitqueue_head(&kthread_waitq);
|
|
+ kthread =
|
|
+ kthread_run(_vcmd_kthread_fn, NULL, "vcmd_kthread");
|
|
+ if (IS_ERR(kthread)) {
|
|
+ LOG_ERR("create vcmd kthread failed!\n");
|
|
+ return;
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief stop kernel thread vcmd driver
|
|
+ */
|
|
+static void _vcmd_kthread_stop(void)
|
|
+{
|
|
+ if (!IS_ERR(kthread)) {
|
|
+ stop_kthread = 1;
|
|
+ kthread_stop(kthread);
|
|
+ kthread = NULL;
|
|
+ }
|
|
+}
|
|
+
|
|
+#ifdef SUPPORT_WATCHDOG
|
|
+/**
|
|
+ * @brief timer callback function of watchdog
|
|
+ */
|
|
+#if (KERNEL_VERSION(4, 14, 0) > LINUX_VERSION_CODE)
|
|
+static void _vcmd_watchdog_cb(unsigned long arg)
|
|
+#else
|
|
+static void _vcmd_watchdog_cb(struct timer_list *timer)
|
|
+#endif
|
|
+{
|
|
+#if (KERNEL_VERSION(4, 14, 0) > LINUX_VERSION_CODE)
|
|
+ struct timer_list * timer = (struct timer_list *)arg;
|
|
+#endif
|
|
+ struct hantrovcmd_dev *dev;
|
|
+
|
|
+ LOG_INFO("vcmd watchdog triggered\n");
|
|
+ dev = container_of(timer, struct hantrovcmd_dev, watchdog_timer);
|
|
+ dev->watchdog_triggered = 1;
|
|
+ _vcmd_kthread_wakeup();
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief init vcmd watchdog
|
|
+ */
|
|
+static void _vcmd_watchdog_start(struct hantrovcmd_dev *dev)
|
|
+{
|
|
+ struct timer_list *timer = &dev->watchdog_timer;
|
|
+
|
|
+#if (KERNEL_VERSION(4, 14, 0) > LINUX_VERSION_CODE)
|
|
+ init_timer(timer);
|
|
+ timer->function = _vcmd_watchdog_cb;
|
|
+ timer->data = (unsigned long)timer;
|
|
+#else
|
|
+ timer_setup(timer, _vcmd_watchdog_cb, 0);
|
|
+#endif
|
|
+ dev->watchdog_active = 1;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * stop vcmd watchdog
|
|
+ */
|
|
+static void _vcmd_watchdog_stop(struct hantrovcmd_dev *dev){
|
|
+ if (dev->watchdog_active) {
|
|
+ del_timer(&dev->watchdog_timer);
|
|
+ dev->watchdog_active = 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ * feed and start vcmd watchdog
|
|
+ */
|
|
+static void _vcmd_watchdog_feed(struct hantrovcmd_dev *dev){
|
|
+ u32 exetime = dev_wait_job_exetime(dev);
|
|
+
|
|
+ if (exetime == 0) {
|
|
+ if (dev->watchdog_active)
|
|
+ _vcmd_watchdog_stop(dev);
|
|
+ } else {
|
|
+ unsigned long expires = ENC_VCMD_WAIT_TIME(exetime);
|
|
+
|
|
+ if (dev->watchdog_active == 0) {
|
|
+ _vcmd_watchdog_start(dev);
|
|
+ }
|
|
+ mod_timer(&dev->watchdog_timer,
|
|
+ (jiffies + msecs_to_jiffies(expires)));
|
|
+ }
|
|
+}
|
|
+#endif //SUPPORT_WATCHDOG
|
|
+
|
|
#ifdef VCMD_DEBUG_INTERNAL
|
|
static void PrintInstr(u32 i, u32 instr, u32 *size)
|
|
{
|
|
@@ -991,13 +1415,13 @@ static long release_cmdbuf(struct file *filp, u16 cmdbuf_id)
|
|
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
|
|
if (!new_cmdbuf_node) {
|
|
//should not happen
|
|
- LOG_ERR("vcmd: ERROR cmdbuf_id !!\n");
|
|
+ LOG_ERR("vcmd: ERROR cmdbuf_id = %u !!\n", cmdbuf_id);
|
|
return -1;
|
|
}
|
|
cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
|
|
if (cmdbuf_obj->filp != filp) {
|
|
//should not happen
|
|
- LOG_ERR("vcmd: ERROR cmdbuf_id !!\n");
|
|
+ LOG_ERR("vcmd: ERROR cmdbuf_id = %u !!\n", cmdbuf_id);
|
|
return -1;
|
|
}
|
|
module_type = cmdbuf_obj->module_type;
|
|
@@ -1013,7 +1437,7 @@ static long release_cmdbuf(struct file *filp, u16 cmdbuf_id)
|
|
while (1) {
|
|
//remove current node
|
|
cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
|
|
- if (cmdbuf_obj->cmdbuf_need_remove == 1) {
|
|
+ if (cmdbuf_obj->cmdbuf_need_remove == 1 && cmdbuf_obj->cmdbuf_run_done) {
|
|
new_cmdbuf_node = remove_cmdbuf_node_from_list(
|
|
list, new_cmdbuf_node);
|
|
if (new_cmdbuf_node) {
|
|
@@ -1041,7 +1465,7 @@ static long release_cmdbuf(struct file *filp, u16 cmdbuf_id)
|
|
|
|
/** release for the pm*/
|
|
if (atomic_dec_return(&(fp_priv->core_tasks[dev->core_id])) >= 0) {
|
|
- venc_pm_runtime_put(dev->core_id);
|
|
+ enc_pm_runtime_put(dev->core_id);
|
|
}
|
|
}
|
|
|
|
@@ -1127,13 +1551,13 @@ static long link_and_run_cmdbuf(struct file *filp,
|
|
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
|
|
if (!new_cmdbuf_node) {
|
|
//should not happen
|
|
- LOG_ERR("vcmd: ERROR cmdbuf_id !!\n");
|
|
+ LOG_ERR("vcmd: ERROR cmdbuf_id = %u !!\n", cmdbuf_id);
|
|
return -1;
|
|
}
|
|
cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
|
|
if (cmdbuf_obj->filp != filp) {
|
|
//should not happen
|
|
- LOG_ERR("vcmd: ERROR cmdbuf_id !!\n");
|
|
+ LOG_ERR("vcmd: ERROR cmdbuf_id = %u !!\n", cmdbuf_id);
|
|
return -1;
|
|
}
|
|
cmdbuf_obj->cmdbuf_data_loaded = 1;
|
|
@@ -1188,10 +1612,10 @@ static long link_and_run_cmdbuf(struct file *filp,
|
|
|
|
dev = &hantrovcmd_data[cmdbuf_obj->core_id];
|
|
input_para->core_id = cmdbuf_obj->core_id;
|
|
- LOG_TRACE("Venc Allocate cmd buffer [%d] to core [%d]\n", cmdbuf_id, input_para->core_id);
|
|
+ LOG_TRACE("Venc Allocate cmd buffer [%d] to core [%d], filp = %p\n", cmdbuf_id, input_para->core_id, filp);
|
|
if (filp) {
|
|
struct filp_priv *fp_priv = (struct filp_priv *)filp->private_data;
|
|
- venc_pm_runtime_sync(dev->core_id);
|
|
+ enc_pm_runtime_sync(dev->core_id);
|
|
atomic_inc(&(fp_priv->core_tasks[dev->core_id]));
|
|
}
|
|
//set ddr address for vcmd registers copy.
|
|
@@ -1236,7 +1660,8 @@ static long link_and_run_cmdbuf(struct file *filp,
|
|
spin_lock_irqsave(dev->spinlock, flags);
|
|
last_cmdbuf_node = find_last_linked_cmdbuf(new_cmdbuf_node);
|
|
record_last_cmdbuf_rdy_num = dev->sw_cmdbuf_rdy_num;
|
|
- LOG_DBG("dev->sw_cmdbuf_rdy_num = %d before vcmd_link_cmdbuf\n", dev->sw_cmdbuf_rdy_num);
|
|
+ LOG_DBG("dev->sw_cmdbuf_rdy_num = %d before vcmd_link_cmdbuf, last cmdbuf_id = %u\n"
|
|
+ , dev->sw_cmdbuf_rdy_num, ((struct cmdbuf_obj *)last_cmdbuf_node->data)->cmdbuf_id);
|
|
vcmd_link_cmdbuf(dev, last_cmdbuf_node);
|
|
LOG_DBG("dev->sw_cmdbuf_rdy_num = %d after vcmd_link_cmdbuf\n", dev->sw_cmdbuf_rdy_num);
|
|
if (dev->working_state == WORKING_STATE_IDLE) {
|
|
@@ -1250,10 +1675,13 @@ static long link_and_run_cmdbuf(struct file *filp,
|
|
((struct cmdbuf_obj *)last_cmdbuf_node->data)->cmdbuf_id,
|
|
((struct cmdbuf_obj *)last_cmdbuf_node->data)->cmdbuf_run_done);
|
|
}
|
|
- vcmd_start(dev, last_cmdbuf_node);
|
|
+ LOG_INFO("link_and_run_cmdbuf, cmdbuf_id = %u, restart_cmdbuf_id = %u\n"
|
|
+ , cmdbuf_id, dev->restart_cmdbuf_id);
|
|
+ if (dev->restart_cmdbuf_id == 0XFFFF)
|
|
+ vcmd_start(dev, last_cmdbuf_node);
|
|
} else {
|
|
//just update cmdbuf ready number
|
|
- LOG_DBG("dev state = %d, cmdbuf rdy num updated %d -> %d\n",
|
|
+ LOG_DBG("link_and_run_cmdbuf, dev state = %d, cmdbuf rdy num updated %d -> %d\n",
|
|
dev->working_state, record_last_cmdbuf_rdy_num,
|
|
dev->sw_cmdbuf_rdy_num);
|
|
if (record_last_cmdbuf_rdy_num != dev->sw_cmdbuf_rdy_num)
|
|
@@ -1261,6 +1689,9 @@ static long link_and_run_cmdbuf(struct file *filp,
|
|
dev->reg_mirror,
|
|
HWIF_VCMD_RDY_CMDBUF_COUNT,
|
|
dev->sw_cmdbuf_rdy_num);
|
|
+#ifdef SUPPORT_WATCHDOG
|
|
+ _vcmd_watchdog_feed(dev);
|
|
+#endif
|
|
}
|
|
spin_unlock_irqrestore(dev->spinlock, flags);
|
|
|
|
@@ -1316,17 +1747,16 @@ static unsigned int wait_cmdbuf_ready(struct file *filp, u16 cmdbuf_id,
|
|
bi_list_node *new_cmdbuf_node = NULL;
|
|
struct hantrovcmd_dev *dev = NULL;
|
|
|
|
- LOG_DBG("%s\n", __func__);
|
|
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
|
|
if (!new_cmdbuf_node) {
|
|
//should not happen
|
|
- LOG_ERR("vcmd: ERROR cmdbuf_id !!\n");
|
|
+ LOG_ERR("vcmd: ERROR cmdbuf_id = %u !!\n", cmdbuf_id);
|
|
return -1;
|
|
}
|
|
cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
|
|
if (cmdbuf_obj->filp != filp) {
|
|
//should not happen
|
|
- LOG_ERR("vcmd: ERROR cmdbuf_id !!\n");
|
|
+ LOG_ERR("vcmd: ERROR cmdbuf_id = %u !!\n", cmdbuf_id);
|
|
return -1;
|
|
}
|
|
dev = &hantrovcmd_data[cmdbuf_obj->core_id];
|
|
@@ -2018,8 +2448,6 @@ static int hantrovcmd_release(struct inode *inode, struct file *filp)
|
|
|
|
if (dev->hw_version_id >= HW_ID_1_2_1) {
|
|
for (core_id = 0; core_id < venc_vcmd_core_num; core_id++) {
|
|
- if (!(&dev[core_id]))
|
|
- continue;
|
|
spin_lock_irqsave(dev[core_id].spinlock, flags);
|
|
new_cmdbuf_node = dev[core_id].list_manager.head;
|
|
while (1) {
|
|
@@ -2079,10 +2507,11 @@ static int hantrovcmd_release(struct inode *inode, struct file *filp)
|
|
dev[core_id].reg_mirror, HWIF_VCMD_WORK_STATE)) {
|
|
loop_count++;
|
|
if (!(loop_count % 10)) {
|
|
+ u32 irq_status = vcmd_read_reg(
|
|
+ (const void *)dev[core_id].hwregs,
|
|
+ VCMD_REGISTER_INT_STATUS_OFFSET);
|
|
LOG_ERR("vcmd: expected idle state, but irq status = 0x%0x\n",
|
|
- vcmd_read_reg(
|
|
- (const void *)dev[core_id].hwregs,
|
|
- VCMD_REGISTER_INT_STATUS_OFFSET));
|
|
+ irq_status);
|
|
LOG_ERR("vcmd: vcmd current status is %d\n",
|
|
vcmd_get_register_value((const void *)dev[core_id].hwregs,
|
|
dev[core_id].reg_mirror, HWIF_VCMD_WORK_STATE));
|
|
@@ -2255,11 +2684,17 @@ static int hantrovcmd_release(struct inode *inode, struct file *filp)
|
|
dev[core_id].reg_mirror, HWIF_VCMD_START_TRIGGER));
|
|
LOG_DBG("dev state from %d -> WORKING.\n", dev[core_id].working_state);
|
|
dev[core_id].working_state = WORKING_STATE_WORKING;
|
|
+#ifdef SUPPORT_WATCHDOG
|
|
+ _vcmd_watchdog_feed(&dev[core_id]);
|
|
+#endif
|
|
#ifdef VCMD_DEBUG_INTERNAL
|
|
printk_vcmd_register_debug((const void *)dev[core_id].hwregs, "after restart");
|
|
#endif
|
|
} else {
|
|
- LOG_DBG("No more command buffer to be restarted!\n");
|
|
+// #ifdef SUPPORT_WATCHDOG
|
|
+// _vcmd_watchdog_stop(&dev[core_id]);
|
|
+// #endif
|
|
+ LOG_DBG("No more command buffer to be restarted, core_id = %u!\n", core_id);
|
|
}
|
|
spin_unlock_irqrestore(dev[core_id].spinlock, flags);
|
|
// VCMD aborted but not restarted, nedd to wake up
|
|
@@ -2268,8 +2703,6 @@ static int hantrovcmd_release(struct inode *inode, struct file *filp)
|
|
}
|
|
} else {
|
|
for (core_id = 0; core_id < venc_vcmd_core_num; core_id++) {
|
|
- if ((&dev[core_id]) == NULL)
|
|
- continue;
|
|
spin_lock_irqsave(dev[core_id].spinlock, flags);
|
|
new_cmdbuf_node = dev[core_id].list_manager.head;
|
|
while (1) {
|
|
@@ -2360,7 +2793,7 @@ static int hantrovcmd_release(struct inode *inode, struct file *filp)
|
|
for (u32 core_id = 0; core_id < ENC_CORE_NUM; core_id ++) {
|
|
/** clear the tasks for pm*/
|
|
while (atomic_dec_return(&(fp_priv->core_tasks[core_id])) >= 0) {
|
|
- venc_pm_runtime_put(core_id);
|
|
+ enc_pm_runtime_put(core_id);
|
|
}
|
|
}
|
|
#ifdef SUPPORT_DMA_HEAP
|
|
@@ -2780,6 +3213,13 @@ static void vcmd_start(struct hantrovcmd_dev *dev,
|
|
dev->reg_mirror[0x60 / 4]);
|
|
vcmd_write_reg((const void *)dev->hwregs, 0x64, 0xffffffff); //not interrupt cpu
|
|
|
|
+ //init HWIF_VCMD_EXE_CMDBUF_COUNT
|
|
+ if (!vcmd_get_register_value((const void *)dev->hwregs,
|
|
+ dev->reg_mirror,
|
|
+ HWIF_VCMD_START_TRIGGER))
|
|
+ vcmd_write_register_value((const void *)dev->hwregs,
|
|
+ dev->reg_mirror,
|
|
+ HWIF_VCMD_EXE_CMDBUF_COUNT, 0);
|
|
dev->working_state = WORKING_STATE_WORKING;
|
|
|
|
if (dev->hw_version_id >= HW_ID_1_2_1)
|
|
@@ -2794,10 +3234,21 @@ static void vcmd_start(struct hantrovcmd_dev *dev,
|
|
dev->reg_mirror[0x40 / 4]);
|
|
vcmd_write_reg((const void *)dev->hwregs, 0x40,
|
|
dev->reg_mirror[0x40 / 4]);
|
|
+ LOG_INFO("vcmd start completed\n");
|
|
+#ifdef SUPPORT_WATCHDOG
|
|
+ _vcmd_watchdog_feed(dev);
|
|
+#endif
|
|
#ifdef VCMD_DEBUG_INTERNAL
|
|
printk_vcmd_register_debug(dev->hwregs, "vcmd_start exits ");
|
|
#endif
|
|
}
|
|
+#ifdef SUPPORT_WATCHDOG
|
|
+ else {
|
|
+ LOG_INFO("no linked cmdbuf, first_linked_cmdbuf_node = %u, sw_cmdbuf_rdy_num = %u, core_id = %u\n"
|
|
+ , first_linked_cmdbuf_node!=NULL, dev->sw_cmdbuf_rdy_num, dev->core_id);
|
|
+ _vcmd_watchdog_stop(dev);
|
|
+ }
|
|
+#endif
|
|
}
|
|
|
|
}
|
|
@@ -3125,9 +3576,9 @@ int vcmd_mem_init(void)
|
|
}
|
|
}
|
|
|
|
- LOG_DBG("Init: vcmd_buf_mem_pool.busAddress=0x%llx.\n",
|
|
+ LOG_INFO("Init: vcmd_buf_mem_pool.busAddress=0x%llx.\n",
|
|
(unsigned long long)vcmd_buf_mem_pool.busAddress);
|
|
- LOG_DBG("Init: vcmd_buf_mem_pool.phy_address=0x%llx.\n",
|
|
+ LOG_INFO("Init: vcmd_buf_mem_pool.phy_address=0x%llx.\n",
|
|
(unsigned long long)vcmd_buf_mem_pool.phy_address);
|
|
LOG_DBG("Init: vcmd_buf_mem_pool.virtualAddress=0x%llx.\n",
|
|
(unsigned long long)vcmd_buf_mem_pool.virtualAddress);
|
|
@@ -3151,9 +3602,9 @@ int vcmd_mem_init(void)
|
|
}
|
|
}
|
|
|
|
- LOG_DBG("Init: vcmd_status_buf_mem_pool.busAddress=0x%llx.\n",
|
|
+ LOG_INFO("Init: vcmd_status_buf_mem_pool.busAddress=0x%llx.\n",
|
|
(unsigned long long)vcmd_status_buf_mem_pool.busAddress);
|
|
- LOG_DBG("Init: vcmd_status_buf_mem_pool.phy_address=0x%llx.\n",
|
|
+ LOG_INFO("Init: vcmd_status_buf_mem_pool.phy_address=0x%llx.\n",
|
|
(unsigned long long)vcmd_status_buf_mem_pool.phy_address);
|
|
LOG_DBG("Init: vcmd_status_buf_mem_pool.virtualAddress=0x%llx.\n",
|
|
(unsigned long long)vcmd_status_buf_mem_pool.virtualAddress);
|
|
@@ -3177,9 +3628,9 @@ int vcmd_mem_init(void)
|
|
}
|
|
}
|
|
|
|
- LOG_DBG("Init: vcmd_registers_mem_pool.busAddress=0x%llx.\n",
|
|
+ LOG_INFO("Init: vcmd_registers_mem_pool.busAddress=0x%llx.\n",
|
|
(unsigned long long)vcmd_registers_mem_pool.busAddress);
|
|
- LOG_DBG("Init: vcmd_registers_mem_pool.phy_address=0x%llx.\n",
|
|
+ LOG_INFO("Init: vcmd_registers_mem_pool.phy_address=0x%llx.\n",
|
|
(unsigned long long)vcmd_registers_mem_pool.phy_address);
|
|
LOG_DBG("Init: vcmd_registers_mem_pool.virtualAddress=0x%llx.\n",
|
|
(unsigned long long)vcmd_registers_mem_pool.virtualAddress);
|
|
@@ -3269,6 +3720,12 @@ int hantroenc_vcmd_init(void)
|
|
vcmd_registers_mem_pool.virtualAddress + i * VCMD_REGISTER_SIZE / 4;
|
|
hantrovcmd_data[i].vcmd_reg_mem_size = VCMD_REGISTER_SIZE;
|
|
memset(hantrovcmd_data[i].vcmd_reg_mem_virtualAddress, 0, VCMD_REGISTER_SIZE);
|
|
+#ifdef SUPPORT_WATCHDOG
|
|
+ hantrovcmd_data[i].watchdog_active = 0;
|
|
+ hantrovcmd_data[i].watchdog_triggered = 0;
|
|
+#endif
|
|
+ hantrovcmd_data[i].vce_hang = 0;
|
|
+ hantrovcmd_data[i].restart_cmdbuf_id = 0XFFFF;
|
|
}
|
|
|
|
result = register_chrdev(hantrovcmd_major, DRIVER_NAME, &hantrovcmd_fops);
|
|
@@ -3358,6 +3815,8 @@ int hantroenc_vcmd_init(void)
|
|
read_main_module_all_registers(i);
|
|
}
|
|
|
|
+ _vcmd_kthread_create();
|
|
+
|
|
return 0;
|
|
err:
|
|
unregister_chrdev(hantrovcmd_major, DRIVER_NAME);
|
|
@@ -3379,6 +3838,8 @@ void hantroenc_vcmd_exit(void)
|
|
int i = 0;
|
|
u32 result;
|
|
|
|
+ _vcmd_kthread_stop();
|
|
+
|
|
for (i = 0; i < venc_vcmd_core_num; i++) {
|
|
if (!hantrovcmd_data[i].hwregs)
|
|
continue;
|
|
@@ -3515,6 +3976,7 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
|
|
unsigned long flags;
|
|
bi_list_node *new_cmdbuf_node = NULL;
|
|
bi_list_node *base_cmdbuf_node = NULL;
|
|
+ bi_list_node* curr_cmdbuf_node=NULL;
|
|
struct cmdbuf_obj *cmdbuf_obj = NULL;
|
|
size_t exe_cmdbuf_busAddress;
|
|
u32 cmdbuf_processed_num = 0;
|
|
@@ -3599,6 +4061,8 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
|
|
|
|
if (dev->hw_version_id < HW_ID_1_1_1) {
|
|
if (vcmd_get_register_mirror_value(dev->reg_mirror, HWIF_VCMD_IRQ_RESET)) {
|
|
+ LOG_DBG("VCMD_IRQ_RESET, working state from %u to idle, cmdbuf_id = %u\n"
|
|
+ , dev->working_state, cmdbuf_id);
|
|
//reset error,all cmdbuf that is not done will be run again.
|
|
new_cmdbuf_node = dev->list_manager.head;
|
|
dev->working_state = WORKING_STATE_IDLE;
|
|
@@ -3625,13 +4089,20 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
|
|
}
|
|
|
|
if (vcmd_get_register_mirror_value(dev->reg_mirror, HWIF_VCMD_IRQ_ABORT)) {
|
|
+ u8 restart_curr_node = 0;
|
|
+
|
|
+ LOG_INFO("VCMD_IRQ_ABORT, working state from %u to idle, cmdbuf_id = %u, core_id = %u\n"
|
|
+ , dev->working_state, cmdbuf_id, dev->core_id);
|
|
+#ifdef SUPPORT_WATCHDOG
|
|
+ _vcmd_watchdog_stop(dev);
|
|
+#endif
|
|
//abort error,don't need to reset
|
|
new_cmdbuf_node = dev->list_manager.head;
|
|
dev->working_state = WORKING_STATE_IDLE;
|
|
if (dev->hw_version_id > HW_ID_1_0_C) {
|
|
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
|
|
if (!new_cmdbuf_node) {
|
|
- LOG_ERR("vcmd_isr error cmdbuf_id !!\n");
|
|
+ LOG_ERR("vcmd_isr abort error cmdbuf_id = %u !!\n", cmdbuf_id);
|
|
spin_unlock_irqrestore(dev->spinlock, flags);
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -3655,7 +4126,7 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
|
|
new_cmdbuf_node = new_cmdbuf_node->next;
|
|
}
|
|
}
|
|
- base_cmdbuf_node = new_cmdbuf_node;
|
|
+ curr_cmdbuf_node = new_cmdbuf_node;
|
|
// this cmdbuf and cmdbufs prior to itself, run_done = 1
|
|
while (1) {
|
|
if (!new_cmdbuf_node)
|
|
@@ -3665,13 +4136,38 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
|
|
cmdbuf_obj->cmdbuf_run_done = 1;
|
|
cmdbuf_obj->executing_status = CMDBUF_EXE_STATUS_OK;
|
|
cmdbuf_processed_num++;
|
|
+ if (dev->vce_hang && new_cmdbuf_node == curr_cmdbuf_node) {
|
|
+ restart_curr_node = 1;
|
|
+ cmdbuf_obj->cmdbuf_run_done = 0;
|
|
+ LOG_INFO("VCMD_IRQ_ABORT, cmdbuf_id=%u, vce hang, cmdbuf_run_done = 0\n"
|
|
+ , cmdbuf_obj->cmdbuf_id);
|
|
+ }
|
|
} else
|
|
break;
|
|
new_cmdbuf_node = new_cmdbuf_node->previous;
|
|
}
|
|
- base_cmdbuf_node = base_cmdbuf_node->next;
|
|
+ base_cmdbuf_node = curr_cmdbuf_node->next;
|
|
+ if (dev->vce_hang) {
|
|
+ /**
|
|
+ * if abort previous cmdbuf of hang, restart from next cmdbuf
|
|
+ * if abort cmdbuf of hang, restart current cmdbuf
|
|
+ */
|
|
+ dev->vce_hang = 0;
|
|
+ // LOG_INFO("%s:%d, vcmd aborted, vce_hang reset = %u\n", __FUNCTION__, __LINE__, dev->vce_hang);
|
|
+ if (restart_curr_node == 1) {
|
|
+ restart_curr_node = 0;
|
|
+ base_cmdbuf_node=curr_cmdbuf_node;
|
|
+ }
|
|
+ }
|
|
+ if (base_cmdbuf_node && base_cmdbuf_node->data)
|
|
+ dev->restart_cmdbuf_id =
|
|
+ ((struct cmdbuf_obj*)base_cmdbuf_node->data)->cmdbuf_id;
|
|
+ else
|
|
+ dev->restart_cmdbuf_id =
|
|
+ ((struct cmdbuf_obj*)curr_cmdbuf_node->data)->cmdbuf_id;
|
|
+ LOG_INFO("VCMD_IRQ_ABORT, restart_cmdbuf_id = %u\n", dev->restart_cmdbuf_id);
|
|
vcmd_delink_cmdbuf(dev, base_cmdbuf_node);
|
|
- if (software_triger_abort == 0) {
|
|
+ if (software_triger_abort == 0 && dev->restart_cmdbuf_id == 0xFFFF) {
|
|
//for QCFE
|
|
vcmd_link_cmdbuf(dev, base_cmdbuf_node);
|
|
if (dev->sw_cmdbuf_rdy_num != 0) {
|
|
@@ -3688,13 +4184,15 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
|
|
return IRQ_HANDLED;
|
|
}
|
|
if (vcmd_get_register_mirror_value(dev->reg_mirror, HWIF_VCMD_IRQ_BUSERR)) {
|
|
+ LOG_DBG("VCMD_IRQ_BUSERR, working state from %u to idle, cmdbuf_id = %u\n"
|
|
+ , dev->working_state, cmdbuf_id);
|
|
//bus error, don't need to reset where to record status?
|
|
new_cmdbuf_node = dev->list_manager.head;
|
|
dev->working_state = WORKING_STATE_IDLE;
|
|
if (dev->hw_version_id > HW_ID_1_0_C) {
|
|
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
|
|
if (!new_cmdbuf_node) {
|
|
- LOG_ERR("vcmd_isr error cmdbuf_id !!\n");
|
|
+ LOG_ERR("VCMD_IRQ_BUSERR, cmdbuf_id = %u !!\n", cmdbuf_id);
|
|
spin_unlock_irqrestore(dev->spinlock, flags);
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -3755,11 +4253,13 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
|
|
if (vcmd_get_register_mirror_value(dev->reg_mirror, HWIF_VCMD_IRQ_TIMEOUT)) {
|
|
//time out,need to reset
|
|
new_cmdbuf_node = dev->list_manager.head;
|
|
+ LOG_DBG("VCMD_IRQ_TIMEOUT, working state from %u to idle, cmdbuf_id = %u\n"
|
|
+ , dev->working_state, cmdbuf_id);
|
|
dev->working_state = WORKING_STATE_IDLE;
|
|
if (dev->hw_version_id > HW_ID_1_0_C) {
|
|
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
|
|
if (!new_cmdbuf_node) {
|
|
- LOG_ERR("vcmd_isr error cmdbuf_id !!\n");
|
|
+ LOG_ERR("vcmd_isr timeout error cmdbuf_id = %u !!\n", cmdbuf_id);
|
|
spin_unlock_irqrestore(dev->spinlock, flags);
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -3816,11 +4316,13 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
|
|
if (vcmd_get_register_mirror_value(dev->reg_mirror, HWIF_VCMD_IRQ_CMDERR)) {
|
|
//command error,don't need to reset
|
|
new_cmdbuf_node = dev->list_manager.head;
|
|
+ LOG_DBG("VCMD_IRQ_CMDERR, working state from %u to idle, cmdbuf_id = %u\n"
|
|
+ , dev->working_state, cmdbuf_id);
|
|
dev->working_state = WORKING_STATE_IDLE;
|
|
if (dev->hw_version_id > HW_ID_1_0_C) {
|
|
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
|
|
if (!new_cmdbuf_node) {
|
|
- LOG_ERR("vcmd_isr error cmdbuf_id !!\n");
|
|
+ LOG_ERR("vcmd_isr cmderr error cmdbuf_id = %u !!\n", cmdbuf_id);
|
|
spin_unlock_irqrestore(dev->spinlock, flags);
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -3885,11 +4387,13 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
|
|
HWIF_VCMD_IRQ_ENDCMD)) {
|
|
//end command interrupt
|
|
new_cmdbuf_node = dev->list_manager.head;
|
|
+ LOG_DBG("VCMD_IRQ_ENDCMD, working state from %u to idle, cmdbuf_id = %u\n"
|
|
+ , dev->working_state, cmdbuf_id);
|
|
dev->working_state = WORKING_STATE_IDLE;
|
|
if (dev->hw_version_id > HW_ID_1_0_C) {
|
|
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
|
|
if (!new_cmdbuf_node) {
|
|
- LOG_ERR("vcmd_isr error cmdbuf_id !!\n");
|
|
+ LOG_ERR("vcmd_isr endcmd error cmdbuf_id = %u !!\n", cmdbuf_id);
|
|
spin_unlock_irqrestore(dev->spinlock, flags);
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -3966,9 +4470,17 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
|
|
break;
|
|
new_cmdbuf_node = new_cmdbuf_node->previous;
|
|
}
|
|
+#ifdef SUPPORT_WATCHDOG
|
|
+ _vcmd_watchdog_feed(dev);
|
|
+#endif
|
|
+ if (dev->vce_hang == 0) {
|
|
+ dev->vce_hang = check_vce_hang(dev, cmdbuf_id);
|
|
+ if (dev->vce_hang) {
|
|
+ _vcmd_kthread_wakeup();
|
|
+ }
|
|
+ }
|
|
handled++;
|
|
}
|
|
-
|
|
spin_unlock_irqrestore(dev->spinlock, flags);
|
|
if (cmdbuf_processed_num)
|
|
wake_up_interruptible_all(dev->wait_queue);
|
|
diff --git a/drivers/staging/media/eswin/venc/vc8000e_driver.c b/drivers/staging/media/eswin/venc/vc8000e_driver.c
|
|
index 5ed832b39132..97743c8172cd 100644
|
|
--- a/drivers/staging/media/eswin/venc/vc8000e_driver.c
|
|
+++ b/drivers/staging/media/eswin/venc/vc8000e_driver.c
|
|
@@ -29,6 +29,9 @@
|
|
#define MCPU_SP0_DYMN_CSR_EN_BIT 3
|
|
#define MCPU_SP0_DYMN_CSR_GNT_BIT 3
|
|
|
|
+#define CORE_NAME_VE ("video-enc0")
|
|
+#define CORE_NAME_JE ("jpeg-enc0")
|
|
+
|
|
typedef struct _venc_clk_rst {
|
|
struct reset_control *rstc_cfg;
|
|
struct reset_control *rstc_axi;
|
|
@@ -77,16 +80,17 @@ extern int vc8000e_vcmd_wait_core_idle(u32 core_id);
|
|
static int venc_dev_open(struct device *dev);
|
|
static int venc_dev_close(struct device *dev);
|
|
static int venc_pm_enable(struct platform_device *pdev);
|
|
+static void enc_pm_disable(struct platform_device *pdev);
|
|
|
|
extern VCMD_CONFIG vc8000e_vcmd_core_array[];
|
|
extern int venc_vcmd_core_num;
|
|
|
|
/** <TODO> the je & ve should be seperated as two devices*/
|
|
static u8 numa_id_array[4] = {0};
|
|
-struct platform_device *venc_get_platform_device(u32 core_id)
|
|
+static struct platform_device *venc_get_platform_device(u32 core_id)
|
|
{
|
|
struct platform_device *pdev = NULL;
|
|
- u8 numa_id;
|
|
+ u8 numa_id = 0xff;
|
|
|
|
if (core_id >= venc_vcmd_core_num) {
|
|
LOG_ERR("invalid core_id = %u, venc_vcmd_core_num = %u\n", core_id, venc_vcmd_core_num);
|
|
@@ -102,7 +106,7 @@ struct platform_device *venc_get_platform_device(u32 core_id)
|
|
return pdev;
|
|
}
|
|
|
|
-int venc_wait_core_idle(u32 core_id) {
|
|
+static int venc_wait_core_idle(u32 core_id) {
|
|
if (0 == vcmd_supported) {
|
|
return hantroenc_wait_core_idle(core_id);
|
|
} else {
|
|
@@ -111,9 +115,9 @@ int venc_wait_core_idle(u32 core_id) {
|
|
}
|
|
|
|
/** <TODO> the je & ve should be seperated as two devices*/
|
|
-int venc_wait_device_idle(struct platform_device *pdev)
|
|
+static int venc_wait_device_idle(struct platform_device *pdev)
|
|
{
|
|
- int ret;
|
|
+ int ret = 0;
|
|
|
|
if (pdev == venc_pdev) {
|
|
ret = venc_wait_core_idle(0);
|
|
@@ -136,8 +140,8 @@ int venc_wait_device_idle(struct platform_device *pdev)
|
|
|
|
static int venc_device_node_scan(unsigned char *compatible)
|
|
{
|
|
- struct property *prop;
|
|
- struct device_node *np;
|
|
+ struct property *prop = NULL;
|
|
+ struct device_node *np = NULL;
|
|
|
|
np = of_find_compatible_node(NULL, NULL, compatible);
|
|
if (!np) {
|
|
@@ -161,7 +165,7 @@ static int venc_device_node_scan(unsigned char *compatible)
|
|
|
|
static int venc_device_nodes_check(void)
|
|
{
|
|
- int i, venc_dev_num = 0;
|
|
+ int i = 0, venc_dev_num = 0;
|
|
unsigned char compatible[32] = {0};
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
@@ -182,7 +186,7 @@ static int venc_device_nodes_check(void)
|
|
index++; \
|
|
} while (0)
|
|
|
|
-int venc_trans_device_nodes(struct platform_device *pdev, u8 numa_id)
|
|
+static int venc_trans_device_nodes(struct platform_device *pdev, u8 numa_id)
|
|
{
|
|
static int subsys_id = 0;
|
|
static int core_index = 0;
|
|
@@ -299,7 +303,7 @@ static int venc_sys_reset_init(struct platform_device *pdev, venc_clk_rst_t *vcr
|
|
|
|
static int venc_sys_reset_release(venc_clk_rst_t *vcrt)
|
|
{
|
|
- int ret;
|
|
+ int ret = 0;
|
|
|
|
ret = reset_control_deassert(vcrt->rstc_cfg);
|
|
WARN_ON(0 != ret);
|
|
@@ -327,7 +331,7 @@ static int venc_sys_reset_release(venc_clk_rst_t *vcrt)
|
|
|
|
static int venc_sys_clk_init(struct platform_device *pdev, venc_clk_rst_t *vcrt)
|
|
{
|
|
- int ret;
|
|
+ int ret = 0;
|
|
|
|
vcrt->aclk = devm_clk_get(&pdev->dev, "aclk");
|
|
if (IS_ERR(vcrt->aclk)) {
|
|
@@ -404,8 +408,8 @@ static int venc_sys_clk_init(struct platform_device *pdev, venc_clk_rst_t *vcrt)
|
|
|
|
static int venc_sys_clk_enable(venc_clk_rst_t *vcrt)
|
|
{
|
|
- int ret;
|
|
- long rate;
|
|
+ int ret = 0;
|
|
+ long rate = 0;
|
|
|
|
ret = clk_set_parent(vcrt->vc_mux, vcrt->spll2_fout1);
|
|
if (ret < 0) {
|
|
@@ -524,7 +528,7 @@ static int venc_hardware_reset(venc_clk_rst_t *vcrt)
|
|
return 0;
|
|
}
|
|
|
|
-static int venc_smmu_dynm_sid_init(struct platform_device *pdev)
|
|
+static int venc_smmu_dynm_sid_init(struct platform_device *pdev, u16 module_type)
|
|
{
|
|
int ret;
|
|
unsigned int reg_val, vccsr_addr[4] = {0};
|
|
@@ -532,6 +536,11 @@ static int venc_smmu_dynm_sid_init(struct platform_device *pdev)
|
|
struct regmap *regmap;
|
|
void __iomem *venc_csr_reg = NULL;
|
|
|
|
+ if (VCMD_TYPE_ENCODER != module_type && VCMD_TYPE_JPEG_ENCODER != module_type)
|
|
+ {
|
|
+ LOG_ERR("Unknown module type %u, while smmu sid init\n", module_type);
|
|
+ return -1;
|
|
+ }
|
|
regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "eswin,syscfg");
|
|
if (IS_ERR(regmap)) {
|
|
dev_err(&pdev->dev, "No syscfg phandle specified\n");
|
|
@@ -561,10 +570,13 @@ static int venc_smmu_dynm_sid_init(struct platform_device *pdev)
|
|
return -1;
|
|
}
|
|
|
|
- writel(WIN2030_SID_VENC, (venc_csr_reg + VENC_MMU_AWSSID_OFF));
|
|
- writel(WIN2030_SID_VENC, (venc_csr_reg + VENC_MMU_ARSSID_OFF));
|
|
- writel(WIN2030_SID_JENC, (venc_csr_reg + JENC_MMU_AWSSID_OFF));
|
|
- writel(WIN2030_SID_JENC, (venc_csr_reg + JENC_MMU_ARSSID_OFF));
|
|
+ if (VCMD_TYPE_ENCODER == module_type) {
|
|
+ writel(WIN2030_SID_VENC, (venc_csr_reg + VENC_MMU_AWSSID_OFF));
|
|
+ writel(WIN2030_SID_VENC, (venc_csr_reg + VENC_MMU_ARSSID_OFF));
|
|
+ } else {
|
|
+ writel(WIN2030_SID_JENC, (venc_csr_reg + JENC_MMU_AWSSID_OFF));
|
|
+ writel(WIN2030_SID_JENC, (venc_csr_reg + JENC_MMU_ARSSID_OFF));
|
|
+ }
|
|
|
|
regmap_read(regmap, dynm_csr_en_off, ®_val);
|
|
reg_val |= (1 << MCPU_SP0_DYMN_CSR_EN_BIT);
|
|
@@ -585,10 +597,10 @@ static int venc_smmu_dynm_sid_init(struct platform_device *pdev)
|
|
|
|
return 0;
|
|
}
|
|
-#endif
|
|
+#endif /** end of SUPPORT_DMA_HEAP*/
|
|
|
|
/* Temporary using this func to do crg init for d1 */
|
|
-int venc_d1_clk_reset_init(void)
|
|
+static int venc_d1_clk_reset_init(void)
|
|
{
|
|
void __iomem *d1_crg_reg = NULL;
|
|
|
|
@@ -604,6 +616,211 @@ int venc_d1_clk_reset_init(void)
|
|
return 0;
|
|
}
|
|
|
|
+static int enc_reset_core(struct device *dev, u16 module_type)
|
|
+{
|
|
+ venc_dev_prvdata *prvdata = dev_get_drvdata(dev);
|
|
+ venc_clk_rst_t *vcrt = &prvdata->vcrt;
|
|
+ int ret = 0;
|
|
+
|
|
+ if (VCMD_TYPE_ENCODER == module_type) {
|
|
+ ret = reset_control_reset(vcrt->rstc_ve_cfg);
|
|
+ WARN_ON(0 != ret);
|
|
+ ret = reset_control_reset(vcrt->rstc_ve_axi);
|
|
+ WARN_ON(0 != ret);
|
|
+ } else if (VCMD_TYPE_JPEG_ENCODER == module_type) {
|
|
+ ret = reset_control_reset(vcrt->rstc_je_cfg);
|
|
+ WARN_ON(0 != ret);
|
|
+ ret = reset_control_reset(vcrt->rstc_je_axi);
|
|
+ WARN_ON(0 != ret);
|
|
+ } else {
|
|
+ LOG_ERR("Unknown module type %u, while core reset\n", module_type);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int enc_tbu_power(struct device *dev, u16 mod_type, bool powerUp)
|
|
+{
|
|
+ struct device_node *chi = NULL;
|
|
+ char *core_name_tag = "";
|
|
+
|
|
+ if (VCMD_TYPE_ENCODER == mod_type)
|
|
+ core_name_tag = CORE_NAME_VE;
|
|
+ else
|
|
+ core_name_tag = CORE_NAME_JE;
|
|
+ for_each_child_of_node(dev->of_node, chi) {
|
|
+ const char *core_name;
|
|
+ if (of_property_read_string(chi, "core-name", &core_name)) {
|
|
+ LOG_ERR("Sub dev core not found, mod_type = %u\n", mod_type);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (!strcmp(core_name, core_name_tag)) {
|
|
+ LOG_INFO("ve tbu power on = %u, mod_type = %u\n", powerUp, mod_type);
|
|
+ win2030_tbu_power_by_dev_and_node(dev, chi, powerUp);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int venc_pm_enable(struct platform_device *pdev) {
|
|
+ /** enable runtime PM */
|
|
+ WARN_ON(pm_runtime_enabled(&pdev->dev));
|
|
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
|
|
+ pm_runtime_use_autosuspend(&pdev->dev);
|
|
+ pm_runtime_set_active(&pdev->dev);
|
|
+ pm_runtime_enable(&pdev->dev);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void enc_pm_disable(struct platform_device *pdev) {
|
|
+ pm_runtime_disable(&pdev->dev);
|
|
+}
|
|
+
|
|
+static int venc_dev_open(struct device *dev)
|
|
+{
|
|
+ venc_dev_prvdata *prvdata = dev_get_drvdata(dev);
|
|
+ venc_clk_rst_t *vcrt = &prvdata->vcrt;
|
|
+ int ret = -1;
|
|
+
|
|
+ if (atomic_dec_return(&prvdata->dev_open_gate) < 0) {
|
|
+ LOG_DBG("The device is opening\n");
|
|
+ atomic_inc(&prvdata->dev_open_gate);
|
|
+ return 0;
|
|
+ }
|
|
+ ret = venc_sys_clk_enable(vcrt);
|
|
+ if (ret) {
|
|
+ LOG_ERR("open device, venc enable clock failed\n");
|
|
+ goto end;
|
|
+ }
|
|
+ ret = enc_tbu_power(dev, VCMD_TYPE_ENCODER, true);
|
|
+ if (ret != 0) {
|
|
+ LOG_ERR("ve: open device, tbu power up failed\n");
|
|
+ goto end;
|
|
+ }
|
|
+ ret = enc_tbu_power(dev, VCMD_TYPE_JPEG_ENCODER, true);
|
|
+ if (ret != 0) {
|
|
+ LOG_ERR("je: open device, tbu power up failed\n");
|
|
+ goto end;
|
|
+ }
|
|
+ prvdata->dev_closed = 0;
|
|
+
|
|
+end:
|
|
+ LOG_DBG("dev open, numa_id = %u, ret = %d\n", prvdata->numa_id, ret);
|
|
+ atomic_inc(&prvdata->dev_open_gate);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int venc_dev_close(struct device *dev)
|
|
+{
|
|
+ struct platform_device *pdev = container_of(dev, struct platform_device, dev);
|
|
+ venc_dev_prvdata *prvdata = dev_get_drvdata(dev);
|
|
+ venc_clk_rst_t *vcrt = &prvdata->vcrt;
|
|
+ int ret;
|
|
+
|
|
+ if (atomic_dec_return(&prvdata->dev_close_gate) < 0) {
|
|
+ LOG_DBG("The device is closing\n");
|
|
+ atomic_inc(&prvdata->dev_close_gate);
|
|
+ return 0;
|
|
+ }
|
|
+ /** check the device be idle*/
|
|
+ ret = venc_wait_device_idle(pdev);
|
|
+ if (0 == ret) {
|
|
+ /** timeout*/
|
|
+ LOG_ERR("Timeout for venc_suspend\n");
|
|
+ ret = -ETIMEDOUT;
|
|
+ goto end;
|
|
+ } else if (ret < 0) {
|
|
+ LOG_ERR("Interrupt triggered while venc_suspend\n");
|
|
+ ret = -ERESTARTSYS;
|
|
+ goto end;
|
|
+ }
|
|
+ ret = enc_tbu_power(dev, VCMD_TYPE_ENCODER, false);
|
|
+ if (ret != 0) {
|
|
+ LOG_ERR("ve: close device, tbu power down failed\n");
|
|
+ goto end;
|
|
+ }
|
|
+ ret = enc_tbu_power(dev, VCMD_TYPE_JPEG_ENCODER, false);
|
|
+ if (ret != 0) {
|
|
+ LOG_ERR("je: close device, tbu power down failed\n");
|
|
+ goto end;
|
|
+ }
|
|
+ ret = venc_clk_disable(vcrt);
|
|
+ if (ret) {
|
|
+ LOG_ERR("close device, venc disable clock failed\n");
|
|
+ goto end;
|
|
+ }
|
|
+ prvdata->dev_closed = 1;
|
|
+
|
|
+end:
|
|
+ LOG_DBG("dev closed, numa_id = %u, ret = %d\n", prvdata->numa_id, ret);
|
|
+ atomic_inc(&prvdata->dev_close_gate);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/** interface functions might be called by others files*/
|
|
+int enc_pm_runtime_sync(u32 core_id) {
|
|
+ struct platform_device *pdev = venc_get_platform_device(core_id);
|
|
+
|
|
+ if (!pdev) {
|
|
+ LOG_ERR("get platform device failed for pm sync, core_id = %u\n", core_id);
|
|
+ }
|
|
+
|
|
+ return pm_runtime_get_sync(&pdev->dev);
|
|
+}
|
|
+
|
|
+int enc_pm_runtime_put(u32 core_id) {
|
|
+ struct platform_device *pdev = venc_get_platform_device(core_id);
|
|
+
|
|
+ if (!pdev) {
|
|
+ LOG_ERR("get platform device failed for pm put, core_id = %u\n", core_id);
|
|
+ }
|
|
+
|
|
+ return pm_runtime_put(&pdev->dev);
|
|
+}
|
|
+
|
|
+int enc_reset_system(u32 core_id) {
|
|
+ struct platform_device *pdev = venc_get_platform_device(core_id);
|
|
+ int ret = 0;
|
|
+ u16 mod_type = vc8000e_vcmd_core_array[core_id].sub_module_type;
|
|
+
|
|
+ if (!pdev) {
|
|
+ LOG_ERR("get platform device failed for reset system, core_id = %u\n", core_id);
|
|
+ return -1;
|
|
+ }
|
|
+ if (VCMD_TYPE_ENCODER != mod_type && VCMD_TYPE_JPEG_ENCODER != mod_type) {
|
|
+ LOG_ERR("Unsupported module type %u, while reset system\n", mod_type);
|
|
+ return -1;
|
|
+ }
|
|
+ /** enc tbu power down*/
|
|
+ ret = enc_tbu_power(&pdev->dev, mod_type, false);
|
|
+ if (ret != 0) {
|
|
+ LOG_ERR("mod_type=%u: reset system tbu power down failed\n", mod_type);
|
|
+ return -1;
|
|
+ }
|
|
+ /** enc core reset*/
|
|
+ ret = enc_reset_core(&pdev->dev, mod_type);
|
|
+ if (ret != 0) {
|
|
+ LOG_ERR("mod_type=%u: core reset failed\n", mod_type);
|
|
+ return -1;
|
|
+ }
|
|
+ /** enc tbu power up*/
|
|
+ ret = enc_tbu_power(&pdev->dev, mod_type, true);
|
|
+ if (ret != 0) {
|
|
+ LOG_ERR("mod_type=%u: reset system tbu power up failed\n", mod_type);
|
|
+ return -1;
|
|
+ }
|
|
+#ifdef SUPPORT_DMA_HEAP
|
|
+ venc_smmu_dynm_sid_init(pdev, mod_type);
|
|
+#endif
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+/** end of interface functions*/
|
|
+
|
|
static int hantro_venc_probe(struct platform_device *pdev)
|
|
{
|
|
static int pdev_count = 0;
|
|
@@ -617,7 +834,7 @@ static int hantro_venc_probe(struct platform_device *pdev)
|
|
return -1;
|
|
}
|
|
|
|
- platform_set_drvdata(pdev, (void *)vcrt);
|
|
+ platform_set_drvdata(pdev, (void *)prvdata);
|
|
|
|
if(of_property_read_u32(pdev->dev.of_node, "numa-node-id", &numa_id)) {
|
|
numa_id = 0;
|
|
@@ -665,15 +882,24 @@ static int hantro_venc_probe(struct platform_device *pdev)
|
|
venc_pdev_d1 = pdev;
|
|
|
|
#ifdef SUPPORT_DMA_HEAP
|
|
- ret = win2030_tbu_power(&pdev->dev, true);
|
|
+ ret = enc_tbu_power(&pdev->dev, VCMD_TYPE_ENCODER, true);
|
|
if (ret != 0) {
|
|
- LOG_ERR("venc: tbu power up failed\n");
|
|
+ LOG_ERR("ve: tbu power up failed\n");
|
|
return -1;
|
|
}
|
|
-
|
|
- ret = venc_smmu_dynm_sid_init(pdev);
|
|
+ ret = enc_tbu_power(&pdev->dev, VCMD_TYPE_JPEG_ENCODER, true);
|
|
+ if (ret != 0) {
|
|
+ LOG_ERR("je: tbu power up failed\n");
|
|
+ return -1;
|
|
+ }
|
|
+ ret = venc_smmu_dynm_sid_init(pdev, VCMD_TYPE_ENCODER);
|
|
+ if (ret < 0) {
|
|
+ LOG_ERR("ve: dynamic smmu sid set failed");
|
|
+ return -1;
|
|
+ }
|
|
+ ret = venc_smmu_dynm_sid_init(pdev, VCMD_TYPE_JPEG_ENCODER);
|
|
if (ret < 0) {
|
|
- LOG_ERR("venc: dynamic smmu sid set failed");
|
|
+ LOG_ERR("je: dynamic smmu sid set failed");
|
|
return -1;
|
|
}
|
|
|
|
@@ -717,27 +943,28 @@ static int hantro_venc_remove(struct platform_device *pdev)
|
|
#ifdef SUPPORT_DMA_HEAP
|
|
int ret;
|
|
venc_clk_rst_t *vcrt;
|
|
- venc_dev_prvdata *prvdata;
|
|
#endif
|
|
+ venc_dev_prvdata *prvdata = platform_get_drvdata(pdev);
|
|
|
|
- pm_runtime_dont_use_autosuspend(&pdev->dev);
|
|
- pm_runtime_disable(&pdev->dev);
|
|
-
|
|
+ enc_pm_disable(pdev);
|
|
if (vcmd_supported == 0)
|
|
hantroenc_normal_cleanup();
|
|
else
|
|
vc8000e_vcmd_cleanup();
|
|
|
|
#ifdef SUPPORT_DMA_HEAP
|
|
- ret = win2030_tbu_power(&pdev->dev, false);
|
|
- if (ret) {
|
|
- LOG_ERR("venc tbu power down failed\n");
|
|
+ ret = enc_tbu_power(&pdev->dev, VCMD_TYPE_ENCODER, false);
|
|
+ if (ret != 0) {
|
|
+ LOG_ERR("ve: tbu power down failed\n");
|
|
+ return -1;
|
|
+ }
|
|
+ ret = enc_tbu_power(&pdev->dev, VCMD_TYPE_JPEG_ENCODER, false);
|
|
+ if (ret != 0) {
|
|
+ LOG_ERR("je: tbu power down failed\n");
|
|
return -1;
|
|
}
|
|
- prvdata = platform_get_drvdata(pdev);
|
|
vcrt = &prvdata->vcrt;
|
|
venc_hardware_reset(vcrt);
|
|
- // venc_clk_disable(vcrt);
|
|
#endif
|
|
|
|
return 0;
|
|
@@ -763,101 +990,6 @@ int venc_pm_runtime_put(u32 core_id) {
|
|
return pm_runtime_put(&pdev->dev);
|
|
}
|
|
|
|
-static int venc_pm_enable(struct platform_device *pdev) {
|
|
- /** enable runtime PM */
|
|
- WARN_ON(pm_runtime_enabled(&pdev->dev));
|
|
- pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
|
|
- pm_runtime_use_autosuspend(&pdev->dev);
|
|
- pm_runtime_set_active(&pdev->dev);
|
|
- pm_runtime_enable(&pdev->dev);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int venc_dev_open(struct device *dev)
|
|
-{
|
|
- venc_dev_prvdata *prvdata = dev_get_drvdata(dev);
|
|
- venc_clk_rst_t *vcrt = &prvdata->vcrt;
|
|
- int ret = -1;
|
|
-
|
|
- if (atomic_dec_return(&prvdata->dev_open_gate) < 0) {
|
|
- LOG_DBG("The device is opening\n");
|
|
- atomic_inc(&prvdata->dev_open_gate);
|
|
- return 0;
|
|
- }
|
|
- // if (prvdata->dev_closed == 0) {
|
|
- // ret = 0;
|
|
- // goto end;
|
|
- // }
|
|
- ret = venc_sys_clk_enable(vcrt);
|
|
- if (ret) {
|
|
- LOG_ERR("open device, venc enable clock failed\n");
|
|
- goto end;
|
|
- }
|
|
- ret = win2030_tbu_power(dev, true);
|
|
- if (ret) {
|
|
- LOG_ERR("open device, tbu power on failed\n");
|
|
- goto end;
|
|
- }
|
|
- prvdata->dev_closed = 0;
|
|
-
|
|
-end:
|
|
- LOG_DBG("dev open, numa_id = %u, ret = %d\n", prvdata->numa_id, ret);
|
|
- atomic_inc(&prvdata->dev_open_gate);
|
|
- return ret;
|
|
-}
|
|
-
|
|
-static int venc_dev_close(struct device *dev)
|
|
-{
|
|
- struct platform_device *pdev = container_of(dev, struct platform_device, dev);
|
|
- venc_dev_prvdata *prvdata = dev_get_drvdata(dev);
|
|
- venc_clk_rst_t *vcrt = &prvdata->vcrt;
|
|
- int ret;
|
|
-
|
|
- if (atomic_dec_return(&prvdata->dev_close_gate) < 0) {
|
|
- LOG_DBG("The device is closing\n");
|
|
- atomic_inc(&prvdata->dev_close_gate);
|
|
- return 0;
|
|
- }
|
|
- // if (prvdata->dev_closed == 1) {
|
|
- // ret = 0;
|
|
- // goto end;
|
|
- // }
|
|
-
|
|
- /** check the device be idle*/
|
|
- LOG_DBG("venc device closing, waiting device idle\n");
|
|
- ret = venc_wait_device_idle(pdev);
|
|
- LOG_DBG("enc device closing, waiting device idle ret=%d\n", ret);
|
|
- if (0 == ret) {
|
|
- /** timeout*/
|
|
- LOG_ERR("Timeout for venc_suspend\n");
|
|
- ret = -ETIMEDOUT;
|
|
- goto end;
|
|
- } else if (ret < 0) {
|
|
- LOG_ERR("Interrupt triggered while venc_suspend\n");
|
|
- ret = -ERESTARTSYS;
|
|
- goto end;
|
|
- }
|
|
-
|
|
- /** close the venc device*/
|
|
- ret = win2030_tbu_power(dev, false);
|
|
- if (ret) {
|
|
- LOG_ERR("close device, tbu power down failed\n");
|
|
- goto end;
|
|
- }
|
|
- ret = venc_clk_disable(vcrt);
|
|
- if (ret) {
|
|
- LOG_ERR("close device, venc disable clock failed\n");
|
|
- goto end;
|
|
- }
|
|
- prvdata->dev_closed = 1;
|
|
-
|
|
-end:
|
|
- LOG_DBG("dev closed, numa_id = %u, ret = %d\n", prvdata->numa_id, ret);
|
|
- atomic_inc(&prvdata->dev_close_gate);
|
|
- return ret;
|
|
-}
|
|
-
|
|
static int venc_runtime_suspend(struct device *dev) {
|
|
LOG_DBG("runtime suspend\n");
|
|
return venc_dev_close(dev);
|
|
--
|
|
2.47.0
|
|
|