kernel/0126-feat-VE-VE-support-power-management.patch

807 lines
25 KiB
Diff

From 1257c53c7921d1e9e0af718338dd0e77dc16d388 Mon Sep 17 00:00:00 2001
From: zouxiaojun <zouxiaojun@eswincomputing.com>
Date: Thu, 18 Jul 2024 16:24:24 +0800
Subject: [PATCH 126/219] feat(VE): VE support power management
Changelogs:
Add generic & runtime power management for VENC&JENC;
Signed-off-by: zouxiaojun <zouxiaojun@eswincomputing.com>
---
.../staging/media/eswin/venc/vc8000_driver.h | 11 +-
.../media/eswin/venc/vc8000_normal_driver.c | 68 +++--
.../media/eswin/venc/vc8000_vcmd_driver.c | 119 +++++---
.../staging/media/eswin/venc/vc8000e_driver.c | 257 +++++++++++++++++-
4 files changed, 381 insertions(+), 74 deletions(-)
diff --git a/drivers/staging/media/eswin/venc/vc8000_driver.h b/drivers/staging/media/eswin/venc/vc8000_driver.h
index aadd259d1752..2863a47ff0ff 100644
--- a/drivers/staging/media/eswin/venc/vc8000_driver.h
+++ b/drivers/staging/media/eswin/venc/vc8000_driver.h
@@ -71,6 +71,9 @@
#include "vc8000_axife.h"
#endif
+#define ENC_DEV_IDLEWAIT_TIME (msecs_to_jiffies(10000))
+
+#define ENC_CORE_NUM (4)
#undef ptr_t
#define ptr_t PTR_T_KERNEL
@@ -81,16 +84,18 @@ struct dmabuf_cfg {
int dmabuf_fd;
unsigned long iova;
};
+#endif
#ifdef __KERNEL__
-struct dmabuf_priv {
+struct filp_priv {
+#ifdef SUPPORT_DMA_HEAP
struct heap_root root;
struct heap_root root_d1;
+#endif
void *dev;
+ atomic_t core_tasks[ENC_CORE_NUM]; /** for task count of 4 cores*/
};
#endif
-#endif
-
#define ENC_HW_ID1 0x48320100
#define ENC_HW_ID2 0x80006000
diff --git a/drivers/staging/media/eswin/venc/vc8000_normal_driver.c b/drivers/staging/media/eswin/venc/vc8000_normal_driver.c
index 6aae8a725c2d..7ef36c148f81 100644
--- a/drivers/staging/media/eswin/venc/vc8000_normal_driver.c
+++ b/drivers/staging/media/eswin/venc/vc8000_normal_driver.c
@@ -836,7 +836,7 @@ static long hantroenc_ioctl(struct file *filp, unsigned int cmd,
struct dmabuf_cfg dbcfg;
size_t buf_size = 0;
struct heap_mem *hmem, *hmem_d1;
- struct dmabuf_priv *db_priv = (struct dmabuf_priv *)filp->private_data;
+ struct filp_priv *fp_priv = (struct filp_priv *)filp->private_data;
if (copy_from_user(&dbcfg, (void __user *)arg, sizeof(struct dmabuf_cfg)) != 0)
return -EFAULT;
@@ -844,14 +844,14 @@ static long hantroenc_ioctl(struct file *filp, unsigned int cmd,
LOG_DBG("import dmabuf_fd = %d\n", dbcfg.dmabuf_fd);
/* map the pha to dma addr(iova)*/
- hmem = common_dmabuf_heap_import_from_user(&db_priv->root, dbcfg.dmabuf_fd);
+ hmem = common_dmabuf_heap_import_from_user(&fp_priv->root, dbcfg.dmabuf_fd);
if(IS_ERR(hmem)) {
LOG_ERR("dmabuf-heap import from userspace failed\n");
return -ENOMEM;
}
if (venc_pdev_d1) {
- hmem_d1 = common_dmabuf_heap_import_from_user(&db_priv->root_d1, dbcfg.dmabuf_fd);
+ hmem_d1 = common_dmabuf_heap_import_from_user(&fp_priv->root_d1, dbcfg.dmabuf_fd);
if(IS_ERR(hmem_d1)) {
common_dmabuf_heap_release(hmem);
LOG_ERR("dmabuf-heap alloc from userspace failed for d1\n");
@@ -891,7 +891,7 @@ static long hantroenc_ioctl(struct file *filp, unsigned int cmd,
case HANTRO_IOCH_DMA_HEAP_PUT_IOVA: {
struct heap_mem *hmem, *hmem_d1;
unsigned int dmabuf_fd;
- struct dmabuf_priv *db_priv = (struct dmabuf_priv *)filp->private_data;
+ struct filp_priv *fp_priv = (struct filp_priv *)filp->private_data;
if (copy_from_user(&dmabuf_fd, (void __user *)arg, sizeof(int)) != 0)
return -EFAULT;
@@ -899,14 +899,14 @@ static long hantroenc_ioctl(struct file *filp, unsigned int cmd,
LOG_DBG("release dmabuf_fd = %d\n", dmabuf_fd);
/* find the heap_mem */
- hmem = common_dmabuf_lookup_heapobj_by_fd(&db_priv->root, dmabuf_fd);
+ hmem = common_dmabuf_lookup_heapobj_by_fd(&fp_priv->root, dmabuf_fd);
if(IS_ERR(hmem)) {
LOG_ERR("cannot find dmabuf-heap for dmabuf_fd %d\n", dmabuf_fd);
return -ENOMEM;
}
if (venc_pdev_d1) {
- hmem_d1 = common_dmabuf_lookup_heapobj_by_fd(&db_priv->root_d1, dmabuf_fd);
+ hmem_d1 = common_dmabuf_lookup_heapobj_by_fd(&fp_priv->root_d1, dmabuf_fd);
if (IS_ERR(hmem_d1)) {
LOG_ERR("cannot find dmabuf-heap for dmabuf_fd %d on d1\n", dmabuf_fd);
return -EFAULT;
@@ -929,27 +929,21 @@ static long hantroenc_ioctl(struct file *filp, unsigned int cmd,
static int hantroenc_open(struct inode *inode, struct file *filp)
{
int result = 0;
-#ifdef SUPPORT_DMA_HEAP
- struct dmabuf_priv *db_priv;
+ struct filp_priv *fp_priv;
- db_priv = kzalloc(sizeof(struct dmabuf_priv), GFP_KERNEL);
- if (!db_priv) {
+ fp_priv = kzalloc(sizeof(struct filp_priv), GFP_KERNEL);
+ if (!fp_priv) {
pr_err("%s: alloc failed\n", __func__);
return -ENOMEM;
}
-
- common_dmabuf_heap_import_init(&db_priv->root, &venc_pdev->dev);
+#ifdef SUPPORT_DMA_HEAP
+ common_dmabuf_heap_import_init(&fp_priv->root, &venc_pdev->dev);
if (venc_pdev_d1) {
- common_dmabuf_heap_import_init(&db_priv->root_d1, &venc_pdev_d1->dev);
+ common_dmabuf_heap_import_init(&fp_priv->root_d1, &venc_pdev_d1->dev);
}
- db_priv->dev = (void *)hantroenc_data;
-
- filp->private_data = (void *)db_priv;
-#else
- hantroenc_t *dev = hantroenc_data;
-
- filp->private_data = (void *)dev;
#endif
+ fp_priv->dev = (void *)hantroenc_data;
+ filp->private_data = (void *)fp_priv;
LOG_DBG("dev opened\n");
return result;
@@ -957,12 +951,8 @@ static int hantroenc_open(struct inode *inode, struct file *filp)
static int hantroenc_release(struct inode *inode, struct file *filp)
{
-#ifdef SUPPORT_DMA_HEAP
- struct dmabuf_priv *db_priv= (struct dmabuf_priv *)filp->private_data;
- hantroenc_t *dev = (hantroenc_t *)db_priv->dev;
-#else
- hantroenc_t *dev = (hantroenc_t *)filp->private_data;
-#endif
+ struct filp_priv *fp_priv= (struct filp_priv *)filp->private_data;
+ hantroenc_t *dev = (hantroenc_t *)fp_priv->dev;
u32 core_id = 0, i = 0;
#ifdef hantroenc_DEBUG
@@ -993,11 +983,11 @@ static int hantroenc_release(struct inode *inode, struct file *filp)
up(&enc_core_sem);
#ifdef SUPPORT_DMA_HEAP
- common_dmabuf_heap_import_uninit(&db_priv->root);
+ common_dmabuf_heap_import_uninit(&fp_priv->root);
if (venc_pdev_d1) {
- common_dmabuf_heap_import_uninit(&db_priv->root_d1);
+ common_dmabuf_heap_import_uninit(&fp_priv->root_d1);
}
- kfree(db_priv);
+ kfree(fp_priv);
#endif
return 0;
@@ -1382,3 +1372,23 @@ static void dump_regs(unsigned long data)
LOG_DBG("Reg Dump End\n");
}
#endif
+
+int hantroenc_wait_core_idle(u32 core_id)
+{
+#if 0
+ hantroenc_t *dev;
+ // u32 irq_status;
+ CORE_WAIT_OUT out;
+
+ if (core_id >= total_subsys_num) {
+ LOG_ERR("invalid core_id = %u, total_subsys_num = %u\n", core_id, total_subsys_num);
+ return -ERESTARTSYS;
+ }
+ dev = &hantroenc_data[core_id];
+
+ return wait_event_interruptible_timeout(enc_wait_queue
+ , CheckEncAnyIrq(dev, &out), ENC_DEV_IDLEWAIT_TIME);
+#else
+ return 0;
+#endif
+}
diff --git a/drivers/staging/media/eswin/venc/vc8000_vcmd_driver.c b/drivers/staging/media/eswin/venc/vc8000_vcmd_driver.c
index 6442cd2c0a54..9e5e388ef990 100644
--- a/drivers/staging/media/eswin/venc/vc8000_vcmd_driver.c
+++ b/drivers/staging/media/eswin/venc/vc8000_vcmd_driver.c
@@ -255,6 +255,7 @@ static int vcmd_type_core_num[MAX_VCMD_TYPE];
#define WORKING_STATE_IDLE 0
#define WORKING_STATE_WORKING 1
+#define WORKING_STATE_STALL 2
#define CMDBUF_EXE_STATUS_OK 0
#define CMDBUF_EXE_STATUS_CMDERR 1
#define CMDBUF_EXE_STATUS_BUSERR 2
@@ -281,6 +282,10 @@ 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);
+
#ifdef VCMD_DEBUG_INTERNAL
static void printk_vcmd_register_debug(const void *hwregs, char *info);
#endif
@@ -1031,6 +1036,15 @@ static long release_cmdbuf(struct file *filp, u16 cmdbuf_id)
}
//spin_unlock_irqrestore(dev->spinlock, flags);
up(&vcmd_reserve_cmdbuf_sem[module_type]);
+ if (filp) {
+ struct filp_priv *fp_priv = (struct filp_priv *)filp->private_data;
+
+ /** release for the pm*/
+ if (atomic_dec_return(&(fp_priv->core_tasks[dev->core_id])) >= 0) {
+ venc_pm_runtime_put(dev->core_id);
+ }
+ }
+
return 0;
}
@@ -1175,6 +1189,11 @@ 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);
+ if (filp) {
+ struct filp_priv *fp_priv = (struct filp_priv *)filp->private_data;
+ venc_pm_runtime_sync(dev->core_id);
+ atomic_inc(&(fp_priv->core_tasks[dev->core_id]));
+ }
//set ddr address for vcmd registers copy.
if (dev->hw_version_id > HW_ID_1_0_C) {
//read vcmd executing register into ddr memory.
@@ -1339,7 +1358,7 @@ static unsigned int wait_cmdbuf_ready(struct file *filp, u16 cmdbuf_id,
#endif
if (wait_event_interruptible(*dev->wait_queue, check_cmdbuf_irq(dev, cmdbuf_obj, irq_status_ret))) {
- LOG_DBG("vcmd_wait_queue_0 interrupted\n");
+ LOG_ERR("vcmd_wait_queue_0 interrupted\n");
//abort the vcmd
//vcmd_write_register_value((const void *)dev->hwregs,dev->reg_mirror,HWIF_VCMD_START_TRIGGER,0);
return -ERESTARTSYS;
@@ -1596,7 +1615,7 @@ static long hantrovcmd_ioctl(struct file *filp, unsigned int cmd,
struct dmabuf_cfg dbcfg;
size_t buf_size = 0;
struct heap_mem *hmem, *hmem_d1;
- struct dmabuf_priv *db_priv = (struct dmabuf_priv *)filp->private_data;
+ struct filp_priv *fp_priv = (struct filp_priv *)filp->private_data;
if (copy_from_user(&dbcfg, (void __user *)arg, sizeof(struct dmabuf_cfg)) != 0)
return -EFAULT;
@@ -1604,14 +1623,14 @@ static long hantrovcmd_ioctl(struct file *filp, unsigned int cmd,
LOG_DBG("import dmabuf_fd = %d\n", dbcfg.dmabuf_fd);
/* map the pha to dma addr(iova)*/
- hmem = common_dmabuf_heap_import_from_user(&db_priv->root, dbcfg.dmabuf_fd);
+ hmem = common_dmabuf_heap_import_from_user(&fp_priv->root, dbcfg.dmabuf_fd);
if(IS_ERR(hmem)) {
LOG_ERR("dmabuf-heap import from userspace failed\n");
return -ENOMEM;
}
if (venc_pdev_d1) {
- hmem_d1 = common_dmabuf_heap_import_from_user(&db_priv->root_d1, dbcfg.dmabuf_fd);
+ hmem_d1 = common_dmabuf_heap_import_from_user(&fp_priv->root_d1, dbcfg.dmabuf_fd);
if(IS_ERR(hmem_d1)) {
common_dmabuf_heap_release(hmem);
LOG_ERR("dmabuf-heap alloc from userspace failed for d1\n");
@@ -1653,7 +1672,7 @@ static long hantrovcmd_ioctl(struct file *filp, unsigned int cmd,
case HANTRO_IOCH_DMA_HEAP_PUT_IOVA: {
struct heap_mem *hmem, *hmem_d1;
unsigned int dmabuf_fd;
- struct dmabuf_priv *db_priv = (struct dmabuf_priv *)filp->private_data;
+ struct filp_priv *fp_priv = (struct filp_priv *)filp->private_data;
if (copy_from_user(&dmabuf_fd, (void __user *)arg, sizeof(int)) != 0)
return -EFAULT;
@@ -1661,14 +1680,14 @@ static long hantrovcmd_ioctl(struct file *filp, unsigned int cmd,
LOG_DBG("release dmabuf_fd = %d\n", dmabuf_fd);
/* find the heap_mem */
- hmem = common_dmabuf_lookup_heapobj_by_fd(&db_priv->root, dmabuf_fd);
+ hmem = common_dmabuf_lookup_heapobj_by_fd(&fp_priv->root, dmabuf_fd);
if(IS_ERR(hmem)) {
LOG_ERR("cannot find dmabuf-heap for dmabuf_fd %d\n", dmabuf_fd);
return -ENOMEM;
}
if (venc_pdev_d1) {
- hmem_d1 = common_dmabuf_lookup_heapobj_by_fd(&db_priv->root_d1, dmabuf_fd);
+ hmem_d1 = common_dmabuf_lookup_heapobj_by_fd(&fp_priv->root_d1, dmabuf_fd);
if (IS_ERR(hmem_d1)) {
LOG_ERR("cannot find dmabuf-heap for dmabuf_fd %d on d1\n", dmabuf_fd);
return -EFAULT;
@@ -1944,25 +1963,24 @@ static int hantrovcmd_open(struct inode *inode, struct file *filp)
bi_list_node *process_manager_node;
unsigned long flags;
struct process_manager_obj *process_manager_obj = NULL;
-#ifdef SUPPORT_DMA_HEAP
- struct dmabuf_priv *db_priv;
+ struct filp_priv *fp_priv;
- db_priv = kzalloc(sizeof(struct dmabuf_priv), GFP_KERNEL);
- if (!db_priv) {
+ fp_priv = kzalloc(sizeof(struct filp_priv), GFP_KERNEL);
+ if (!fp_priv) {
pr_err("%s: alloc failed\n", __func__);
return -ENOMEM;
}
-
- common_dmabuf_heap_import_init(&db_priv->root, &venc_pdev->dev);
+#ifdef SUPPORT_DMA_HEAP
+ common_dmabuf_heap_import_init(&fp_priv->root, &venc_pdev->dev);
if (venc_pdev_d1) {
- common_dmabuf_heap_import_init(&db_priv->root_d1, &venc_pdev_d1->dev);
+ common_dmabuf_heap_import_init(&fp_priv->root_d1, &venc_pdev_d1->dev);
}
- db_priv->dev = (void *)dev;
-
- filp->private_data = (void *)db_priv;
-#else
- filp->private_data = (void *)dev;
#endif
+ fp_priv->dev = (void*)dev;
+ for (u32 core_id = 0; core_id < ENC_CORE_NUM; core_id ++) {
+ atomic_set(&(fp_priv->core_tasks[core_id]), 0);
+ }
+ filp->private_data = (void *)fp_priv;
process_manager_node = create_process_manager_node();
if (!process_manager_node)
return -1;
@@ -1972,20 +1990,14 @@ static int hantrovcmd_open(struct inode *inode, struct file *filp)
spin_lock_irqsave(&vcmd_process_manager_lock, flags);
bi_list_insert_node_tail(&global_process_manager, process_manager_node);
spin_unlock_irqrestore(&vcmd_process_manager_lock, flags);
-
LOG_DBG("dev opened\n");
return result;
}
static int hantrovcmd_release(struct inode *inode, struct file *filp)
{
-#ifdef SUPPORT_DMA_HEAP
- struct dmabuf_priv *db_priv = (struct dmabuf_priv *)filp->private_data;
- struct hantrovcmd_dev *dev = (struct hantrovcmd_dev *)db_priv->dev;
-#else
- struct hantrovcmd_dev *dev =
- (struct hantrovcmd_dev *)filp->private_data;
-#endif
+ struct filp_priv *fp_priv = (struct filp_priv *)filp->private_data;
+ struct hantrovcmd_dev *dev = (struct hantrovcmd_dev *)fp_priv->dev;
u32 core_id = 0;
u32 release_cmdbuf_num = 0;
bi_list_node *new_cmdbuf_node = NULL;
@@ -2345,23 +2357,28 @@ static int hantrovcmd_release(struct inode *inode, struct file *filp)
free_process_manager_node(process_manager_node);
up(&vcmd_reserve_cmdbuf_sem[dev->vcmd_core_cfg.sub_module_type]);
+ 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);
+ }
+ }
#ifdef SUPPORT_DMA_HEAP
- common_dmabuf_heap_import_uninit(&db_priv->root);
+ common_dmabuf_heap_import_uninit(&fp_priv->root);
if (venc_pdev_d1) {
- common_dmabuf_heap_import_uninit(&db_priv->root_d1);
+ common_dmabuf_heap_import_uninit(&fp_priv->root_d1);
}
- kfree(db_priv);
#endif
-
+ kfree(fp_priv);
return 0;
error:
#ifdef SUPPORT_DMA_HEAP
- common_dmabuf_heap_import_uninit(&db_priv->root);
+ common_dmabuf_heap_import_uninit(&fp_priv->root);
if (venc_pdev_d1) {
- common_dmabuf_heap_import_uninit(&db_priv->root_d1);
+ common_dmabuf_heap_import_uninit(&fp_priv->root_d1);
}
- kfree(db_priv);
+ kfree(fp_priv);
#endif
return -ERESTARTSYS;
@@ -4045,3 +4062,37 @@ int vc8000e_vcmd_cleanup(void)
return 0;
}
+static int check_dev_idle(struct hantrovcmd_dev *dev)
+{
+ /** the devices must not be power down now.*/
+ int idle = 0;
+ u8 vcmd_state = vcmd_get_register_value((const void *)dev->hwregs,
+ dev->reg_mirror, HWIF_VCMD_WORK_STATE);
+
+ if (WORKING_STATE_STALL != vcmd_state
+ && WORKING_STATE_WORKING != vcmd_state) {
+ idle = 1;
+ }
+ LOG_INFO("check_dev_idle, vcmd_state = %u\n", vcmd_state);
+
+ return idle;
+}
+
+int hantrovcmd_wait_core_idle(u32 core_id)
+{
+ struct hantrovcmd_dev *dev = NULL;
+ int ret;
+
+ 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);
+ return -ERESTARTSYS;
+ }
+ dev = &hantrovcmd_data[core_id];
+ LOG_INFO("enc wait core idle, core_id = %u\n", core_id);
+
+ ret = wait_event_interruptible_timeout(*dev->wait_queue, check_dev_idle(dev), ENC_DEV_IDLEWAIT_TIME);
+
+ LOG_INFO("enc wait core idle exit, core_id = %u, ret = %d\n", core_id, ret);
+
+ return ret;
+}
diff --git a/drivers/staging/media/eswin/venc/vc8000e_driver.c b/drivers/staging/media/eswin/venc/vc8000e_driver.c
index c85d919fe750..b66055e26c3b 100644
--- a/drivers/staging/media/eswin/venc/vc8000e_driver.c
+++ b/drivers/staging/media/eswin/venc/vc8000e_driver.c
@@ -7,6 +7,7 @@
#include <linux/of_platform.h>
#include <linux/of_irq.h>
#include <linux/clk.h>
+#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
@@ -48,6 +49,15 @@ typedef struct _venc_clk_rst {
struct clk *mon_pclk;
} venc_clk_rst_t;
+typedef struct {
+ venc_clk_rst_t vcrt;
+
+ u8 numa_id;
+ atomic_t dev_close_gate;
+ atomic_t dev_open_gate;
+ u8 dev_closed;
+} venc_dev_prvdata;
+
SUBSYS_CONFIG vc8000e_subsys_array[4] = {0};
CORE_CONFIG vc8000e_core_array[8] = {0};
@@ -59,12 +69,71 @@ module_param(vcmd_supported, uint, 0);
extern int hantroenc_normal_init(void);
extern void hantroenc_normal_cleanup(void);
+extern int hantroenc_wait_core_idle(u32 core_id);
extern int vc8000e_vcmd_init(void);
extern int vc8000e_vcmd_cleanup(void);
+extern int hantrovcmd_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);
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)
+{
+ struct platform_device *pdev = NULL;
+ u8 numa_id;
+
+ 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);
+ return NULL;
+ }
+ numa_id = numa_id_array[core_id];
+
+ if (0 == numa_id)
+ pdev = venc_pdev;
+ else if (1 == numa_id)
+ pdev = venc_pdev_d1;
+
+ return pdev;
+}
+
+int venc_wait_core_idle(u32 core_id) {
+ if (0 == vcmd_supported) {
+ return hantroenc_wait_core_idle(core_id);
+ } else {
+ return hantrovcmd_wait_core_idle(core_id);
+ }
+}
+
+/** <TODO> the je & ve should be seperated as two devices*/
+int venc_wait_device_idle(struct platform_device *pdev)
+{
+ int ret;
+
+ if (pdev == venc_pdev) {
+ ret = venc_wait_core_idle(0);
+ if (ret <= 0)
+ return ret;
+ ret = venc_wait_core_idle(1);
+ return ret;
+ }
+ else if (pdev == venc_pdev_d1) {
+ ret = venc_wait_core_idle(2);
+ if (ret <= 0)
+ return ret;
+ ret = venc_wait_core_idle(3);
+ return ret;
+ }
+
+ LOG_ERR("Unknown platform device = %p\n", pdev);
+ return 1;
+}
+
static int venc_device_node_scan(unsigned char *compatible)
{
struct property *prop;
@@ -113,7 +182,7 @@ static int venc_device_nodes_check(void)
index++; \
} while (0)
-int venc_trans_device_nodes(struct platform_device *pdev)
+int venc_trans_device_nodes(struct platform_device *pdev, u8 numa_id)
{
static int subsys_id = 0;
static int core_index = 0;
@@ -171,6 +240,8 @@ int venc_trans_device_nodes(struct platform_device *pdev)
if (strstr(core_name, "jpeg"))
hw_type = CORE_VC8000EJ;
+ numa_id_array[subsys_id] = numa_id;
+
VENC_CORE_ARRAY_ASSIGN(core_index, subsys_id, hw_type, venc_addr[0], venc_addr[1], child_irq);
VENC_CORE_ARRAY_ASSIGN(core_index, subsys_id, CORE_AXIFE, axife_addr[0], axife_addr[1], -1);
subsys_id++;
@@ -537,7 +608,8 @@ static int hantro_venc_probe(struct platform_device *pdev)
{
static int pdev_count = 0;
int ret, numa_id, venc_dev_num = 0;
- venc_clk_rst_t *vcrt = devm_kzalloc(&pdev->dev, sizeof(venc_clk_rst_t), GFP_KERNEL);
+ venc_dev_prvdata *prvdata = devm_kzalloc(&pdev->dev, sizeof(venc_dev_prvdata), GFP_KERNEL);
+ venc_clk_rst_t *vcrt = &prvdata->vcrt;
venc_dev_num = venc_device_nodes_check();
if (venc_dev_num <= 0) {
@@ -581,7 +653,7 @@ static int hantro_venc_probe(struct platform_device *pdev)
venc_d1_clk_reset_init();
}
- ret = venc_trans_device_nodes(pdev);
+ ret = venc_trans_device_nodes(pdev, numa_id);
if (ret < 0) {
LOG_ERR("venc: dts parse failed");
return -1;
@@ -613,16 +685,31 @@ static int hantro_venc_probe(struct platform_device *pdev)
LOG_ERR("41bit esdma dev: No suitable DMA available\n");
#endif
+ atomic_set(&prvdata->dev_open_gate, 1);
+ atomic_set(&prvdata->dev_close_gate, 1);
+ prvdata->dev_closed = 1;
+ prvdata->numa_id = numa_id;
+
pdev_count++;
if (venc_dev_num > pdev_count) {
LOG_INFO("VENC: The first core loaded, waiting for another...");
return 0;
}
-
if (vcmd_supported == 0)
- return hantroenc_normal_init();
+ ret = hantroenc_normal_init();
else
- return vc8000e_vcmd_init();
+ ret = vc8000e_vcmd_init();
+
+ if (0 == ret) {
+ if (venc_pdev && venc_pm_enable(venc_pdev) < 0) {
+ LOG_WARN("venc: enable pm for venc_pdev failed\n");
+ }
+ if (venc_pdev_d1 && venc_pm_enable(venc_pdev_d1) < 0) {
+ LOG_WARN("venc: enable pm for venc_pdev_d1 failed\n");
+ }
+ }
+
+ return ret;
}
static int hantro_venc_remove(struct platform_device *pdev)
@@ -630,8 +717,12 @@ 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
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
if (vcmd_supported == 0)
hantroenc_normal_cleanup();
else
@@ -643,14 +734,163 @@ static int hantro_venc_remove(struct platform_device *pdev)
LOG_ERR("venc tbu power down failed\n");
return -1;
}
- vcrt = platform_get_drvdata(pdev);
+ prvdata = platform_get_drvdata(pdev);
+ vcrt = &prvdata->vcrt;
venc_hardware_reset(vcrt);
- venc_clk_disable(vcrt);
+ // venc_clk_disable(vcrt);
#endif
return 0;
}
+int venc_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 venc_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, numa_id = %u\n", 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_INFO("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_INFO("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_INFO("The device is opening\n");
+ atomic_inc(&prvdata->dev_close_gate);
+ return 0;
+ }
+ // if (prvdata->dev_closed == 1) {
+ // ret = 0;
+ // goto end;
+ // }
+
+ /** check the device be idle*/
+ LOG_INFO("venc device closing, waiting device idle\n");
+ ret = venc_wait_device_idle(pdev);
+ LOG_INFO("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_INFO("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_INFO("runtime suspend\n");
+ return venc_dev_close(dev);
+}
+
+static int venc_runtime_resume(struct device *dev) {
+ LOG_INFO("runtime resume\n");
+ return venc_dev_open(dev);
+}
+
+static int venc_suspend(struct device *dev) {
+ LOG_INFO("generic suspend\n");
+ if (pm_runtime_status_suspended(dev)) {
+ LOG_INFO("generic suspend, venc is suspended already\n");
+ return 0;
+ }
+ return venc_dev_close(dev);
+}
+
+static int venc_resume(struct device *dev) {
+ LOG_INFO("generic resume\n");
+ if (pm_runtime_status_suspended(dev)) {
+ LOG_INFO("generic resume, venc is resumed already\n");
+ return 0;
+ }
+ return venc_dev_open(dev);
+}
+
+static const struct dev_pm_ops venc_pm_ops = {
+ SET_RUNTIME_PM_OPS(venc_runtime_suspend, venc_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(venc_suspend, venc_resume)
+};
+
static const struct of_device_id eswin_venc_match[] = {
{ .compatible = "eswin,video-encoder0", },
{ .compatible = "eswin,video-encoder1", },
@@ -662,6 +902,7 @@ static struct platform_driver eswin_venc_driver = {
.driver = {
.name = "Eswinenc",
.of_match_table = eswin_venc_match,
+ .pm = &venc_pm_ops,
},
};
--
2.47.0