From a04b4317f04cddf1b1406b788f189a32609aa1d0 Mon Sep 17 00:00:00 2001 From: zouxiaojun Date: Thu, 18 Jul 2024 16:24:24 +0800 Subject: [PATCH 126/222] feat(VE): VE support power management Changelogs: Add generic & runtime power management for VENC&JENC; Signed-off-by: zouxiaojun --- .../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 #include #include +#include #include #include #include @@ -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; +/** 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); + } +} + +/** 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