kernel/0157-fix-enc-fix-hang-issue-of-ve-roi.patch
2024-12-19 16:34:44 -05:00

1584 lines
49 KiB
Diff

From 8c1f5edf94a29230ce2cd29fe313569029caad6a 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, &reg_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