1.Add vcp ready ipi register driver. 2.Add vcp ready notify work mechanism. 3.Add vcp feature resgiter mechanism.
Signed-off-by: Xiangzhi Tang <[email protected]> --- drivers/remoteproc/mtk_vcp_common.c | 279 ++++++++++++++++++++++ drivers/remoteproc/mtk_vcp_common.h | 56 +++++ drivers/remoteproc/mtk_vcp_rproc.c | 62 ++++- drivers/remoteproc/mtk_vcp_rproc.h | 18 ++ include/linux/remoteproc/mtk_vcp_public.h | 12 + 5 files changed, 425 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/mtk_vcp_common.c b/drivers/remoteproc/mtk_vcp_common.c index 97ea8099912d..f3b506034e95 100644 --- a/drivers/remoteproc/mtk_vcp_common.c +++ b/drivers/remoteproc/mtk_vcp_common.c @@ -24,6 +24,9 @@ #include "mtk_vcp_common.h" #include "mtk_vcp_rproc.h" +static BLOCKING_NOTIFIER_HEAD(mmup_notifier_list); +static BLOCKING_NOTIFIER_HEAD(vcp_notifier_list); + phys_addr_t vcp_get_reserve_mem_phys(struct mtk_vcp_device *vcp, enum vcp_reserve_mem_id id) { @@ -153,6 +156,40 @@ int vcp_reserve_memory_init(struct mtk_vcp_device *vcp) return 0; } +static bool vcp_is_core_ready(struct mtk_vcp_device *vcp, + enum vcp_core_id core_id) +{ + switch (core_id) { + case VCP_ID: + return vcp->vcp_cluster->vcp_ready[VCP_ID]; + case MMUP_ID: + return vcp->vcp_cluster->vcp_ready[MMUP_ID]; + case VCP_CORE_TOTAL: + default: + return vcp->vcp_cluster->vcp_ready[VCP_ID] & + vcp->vcp_cluster->vcp_ready[MMUP_ID]; + } +} + +static enum vcp_core_id get_core_by_feature(struct mtk_vcp_device *vcp, + enum vcp_feature_id id) +{ + for (u32 i = 0; i < NUM_FEATURE_ID; i++) { + if (vcp->platdata->feature_tb[i].feature_id == id) + return vcp->platdata->feature_tb[i].core_id; + } + + return 0; +} + +bool is_vcp_ready(struct mtk_vcp_device *vcp, + enum vcp_feature_id id) +{ + enum vcp_core_id core_id = get_core_by_feature(vcp, id); + + return vcp_is_core_ready(vcp, core_id); +} + int wait_core_hart_shutdown(struct mtk_vcp_device *vcp, enum vcp_core_id core_id) { @@ -215,9 +252,120 @@ int wait_core_hart_shutdown(struct mtk_vcp_device *vcp, return ret; } +void vcp_A_register_notify(struct mtk_vcp_device *vcp, + enum vcp_feature_id id, + struct notifier_block *nb) +{ + enum vcp_core_id core_id = get_core_by_feature(vcp, id); + + switch (core_id) { + case VCP_ID: + blocking_notifier_chain_register(&vcp_notifier_list, nb); + if (vcp_is_core_ready(vcp, VCP_ID)) + nb->notifier_call(nb, VCP_EVENT_READY, NULL); + break; + case MMUP_ID: + blocking_notifier_chain_register(&mmup_notifier_list, nb); + if (vcp_is_core_ready(vcp, MMUP_ID)) + nb->notifier_call(nb, VCP_EVENT_READY, NULL); + break; + default: + dev_err(vcp->dev, "%s(), No Support core id\n", __func__); + break; + } +} + +void vcp_A_unregister_notify(struct mtk_vcp_device *vcp, + enum vcp_feature_id id, + struct notifier_block *nb) +{ + enum vcp_core_id core_id = get_core_by_feature(vcp, id); + + switch (core_id) { + case VCP_ID: + blocking_notifier_chain_unregister(&vcp_notifier_list, nb); + break; + case MMUP_ID: + blocking_notifier_chain_unregister(&mmup_notifier_list, nb); + break; + default: + dev_err(vcp->dev, "%s(), No Support core id\n", __func__); + break; + } +} + +void vcp_extern_notify(enum vcp_core_id core_id, + enum vcp_notify_event notify_status) +{ + switch (core_id) { + case VCP_ID: + blocking_notifier_call_chain(&vcp_notifier_list, notify_status, NULL); + break; + case MMUP_ID: + blocking_notifier_call_chain(&mmup_notifier_list, notify_status, NULL); + break; + default: + break; + } +} + +static void vcp_A_notify_ws(struct work_struct *ws) +{ + struct vcp_work_struct *sws = + container_of(ws, struct vcp_work_struct, work); + struct mtk_vcp_device *vcp = platform_get_drvdata(to_platform_device(sws->dev)); + enum vcp_core_id core_id = sws->flags; + + if (core_id < VCP_CORE_TOTAL) { + mutex_lock(&vcp->vcp_cluster->vcp_ready_mutex); + vcp->vcp_cluster->vcp_ready[core_id] = true; + mutex_unlock(&vcp->vcp_cluster->vcp_ready_mutex); + + vcp_extern_notify(core_id, VCP_EVENT_READY); + + /*clear reset status and unlock wake lock*/ + dev_info(sws->dev, "%s core id %u ready\n", __func__, core_id); + } else { + dev_err(sws->dev, "%s wrong core id %u\n", __func__, core_id); + } +} + +static void vcp_A_set_ready(struct mtk_vcp_device *vcp, + enum vcp_core_id core_id) +{ + if (core_id < VCP_CORE_TOTAL) { + vcp->vcp_cluster->vcp_ready_notify_wk[core_id].flags = core_id; + queue_work(vcp->vcp_cluster->vcp_workqueue, + &vcp->vcp_cluster->vcp_ready_notify_wk[core_id].work); + } +} + +int vcp_A_ready_ipi_handler(u32 id, void *prdata, void *data, u32 len) +{ + struct mtk_vcp_device *vcp = (struct mtk_vcp_device *)prdata; + + switch (id) { + case IPI_IN_VCP_READY_0: + if (!vcp_is_core_ready(vcp, VCP_ID)) + vcp_A_set_ready(vcp, VCP_ID); + break; + case IPI_IN_VCP_READY_1: + if (!vcp_is_core_ready(vcp, MMUP_ID)) + vcp_A_set_ready(vcp, MMUP_ID); + break; + default: + dev_err(vcp->dev, "%s(), No Support ipi id\n", __func__); + break; + } + + return 0; +} + int reset_vcp(struct mtk_vcp_device *vcp) { struct arm_smccc_res res; + bool mmup_status, vcp_status; + int ret; if (vcp->vcp_cluster->core_nums > MMUP_ID) { writel((u32)VCP_PACK_IOVA(vcp->vcp_cluster->share_mem_iova), @@ -228,6 +376,16 @@ int reset_vcp(struct mtk_vcp_device *vcp) arm_smccc_smc(MTK_SIP_TINYSYS_VCP_CONTROL, MTK_TINYSYS_MMUP_KERNEL_OP_RESET_RELEASE, 1, 0, 0, 0, 0, 0, &res); + + ret = read_poll_timeout(vcp_is_core_ready, + mmup_status, mmup_status, + USEC_PER_MSEC, + VCP_READY_TIMEOUT_MS * USEC_PER_MSEC, + false, vcp, MMUP_ID); + if (ret) { + dev_err(vcp->dev, "MMUP_ID bootup timeout. Stop vcp booting\n"); + return ret; + } } writel((u32)VCP_PACK_IOVA(vcp->vcp_cluster->share_mem_iova), @@ -239,6 +397,127 @@ int reset_vcp(struct mtk_vcp_device *vcp) MTK_TINYSYS_VCP_KERNEL_OP_RESET_RELEASE, 1, 0, 0, 0, 0, 0, &res); + ret = read_poll_timeout(vcp_is_core_ready, + vcp_status, vcp_status, + USEC_PER_MSEC, + VCP_READY_TIMEOUT_MS * USEC_PER_MSEC, + false, vcp, VCP_ID); + if (ret) { + dev_err(vcp->dev, "VCP_ID bootup timeout. Stop vcp booting\n"); + return ret; + } + + return ret; +} + +static int vcp_enable_pm_clk(struct mtk_vcp_device *vcp, enum vcp_feature_id id) +{ + struct vcp_slp_ctrl slp_data; + bool suspend_status; + int ret; + + if (vcp->vcp_cluster->feature_enable[id]) { + dev_err(vcp->dev, "%s feature(id=%d) already enabled\n", + __func__, id); + return -EINVAL; + } + + if (id != RTOS_FEATURE_ID) { + slp_data.cmd = SLP_WAKE_LOCK; + slp_data.feature = id; + ret = vcp->ipi_ops->ipi_send_compl(vcp->ipi_dev, IPI_OUT_C_SLEEP_0, + &slp_data, PIN_OUT_C_SIZE_SLEEP_0, 500); + if (ret < 0) { + dev_err(vcp->dev, "%s ipc_send_compl failed. ret %d\n", + __func__, ret); + return ret; + } + } + + return 0; +} + +static int vcp_disable_pm_clk(struct mtk_vcp_device *vcp, enum vcp_feature_id id) +{ + struct vcp_slp_ctrl slp_data; + bool suspend_status; + int ret; + + if (!vcp->vcp_cluster->feature_enable[id]) { + dev_err(vcp->dev, "%s feature(id=%d) already disabled\n", + __func__, id); + return -EINVAL; + } + + if (id != RTOS_FEATURE_ID) { + slp_data.cmd = SLP_WAKE_UNLOCK; + slp_data.feature = id; + ret = vcp->ipi_ops->ipi_send_compl(vcp->ipi_dev, IPI_OUT_C_SLEEP_0, + &slp_data, PIN_OUT_C_SIZE_SLEEP_0, 500); + if (ret < 0) { + dev_err(vcp->dev, "%s ipc_send_compl failed. ret %d\n", + __func__, ret); + return ret; + } + } + + return 0; +} + +int vcp_A_register_feature(struct mtk_vcp_device *vcp, enum vcp_feature_id id) +{ + int ret; + + if (id >= NUM_FEATURE_ID) { + dev_err(vcp->dev, "%s unsupported feature id %d\n", + __func__, id); + return -EINVAL; + } + + mutex_lock(&vcp->vcp_cluster->vcp_feature_mutex); + ret = vcp_enable_pm_clk(vcp, id); + if (ret) + dev_err(vcp->dev, "%s feature(id=%d) register failed\n", + __func__, id); + else + vcp->vcp_cluster->feature_enable[id] = true; + mutex_unlock(&vcp->vcp_cluster->vcp_feature_mutex); + + return ret; +} + +int vcp_A_deregister_feature(struct mtk_vcp_device *vcp, enum vcp_feature_id id) +{ + int ret; + + if (id >= NUM_FEATURE_ID) { + dev_err(vcp->dev, "%s unsupported feature id %d\n", __func__, id); + return -EINVAL; + } + + mutex_lock(&vcp->vcp_cluster->vcp_feature_mutex); + ret = vcp_disable_pm_clk(vcp, id); + if (ret) + dev_err(vcp->dev, "%s feature(id=%d) deregister failed\n", + __func__, id); + else + vcp->vcp_cluster->feature_enable[id] = false; + mutex_unlock(&vcp->vcp_cluster->vcp_feature_mutex); + + return ret; +} + +int vcp_notify_work_init(struct mtk_vcp_device *vcp) +{ + vcp->vcp_cluster->vcp_workqueue = create_singlethread_workqueue("VCP_WQ"); + if (!vcp->vcp_cluster->vcp_workqueue) + return dev_err_probe(vcp->dev, -EINVAL, "vcp_workqueue create fail\n"); + + for (u32 core_id = 0; core_id < VCP_CORE_TOTAL; core_id++) { + vcp->vcp_cluster->vcp_ready_notify_wk[core_id].dev = vcp->dev; + INIT_WORK(&vcp->vcp_cluster->vcp_ready_notify_wk[core_id].work, vcp_A_notify_ws); + } + return 0; } diff --git a/drivers/remoteproc/mtk_vcp_common.h b/drivers/remoteproc/mtk_vcp_common.h index d048757c955a..8b19fcb78a79 100644 --- a/drivers/remoteproc/mtk_vcp_common.h +++ b/drivers/remoteproc/mtk_vcp_common.h @@ -13,10 +13,13 @@ #include <linux/remoteproc/mtk_vcp_public.h> /* VCP timeout definition */ +#define VCP_READY_TIMEOUT_MS 3000 +#define VCP_IPI_DEV_READY_TIMEOUT 1000 #define CORE_HART_SHUTDOWN_TIMEOUT_MS 10 /* VCP platform definition */ #define DMA_MAX_MASK_BIT 33 +#define PIN_OUT_C_SIZE_SLEEP_0 2 /* VCP load image definition */ #define VCM_IMAGE_MAGIC (0x58881688) @@ -90,6 +93,14 @@ enum vcp_core_id { VCP_CORE_TOTAL, }; +enum vcp_slp_cmd { + SLP_WAKE_LOCK = 0, + SLP_WAKE_UNLOCK, + SLP_STATUS_DBG, + SLP_SUSPEND, + SLP_RESUME, +}; + enum mtk_tinysys_vcp_kernel_op { MTK_TINYSYS_VCP_KERNEL_OP_RESET_SET = 0, MTK_TINYSYS_VCP_KERNEL_OP_RESET_RELEASE, @@ -154,6 +165,32 @@ struct vcp_reserve_mblock { size_t size; }; +/** + * struct vcp_slp_ctrl - sleep ctrl data sync with AP and VCP + * + * @feature: Feature id + * @cmd: sleep cmd flag. + */ +struct vcp_slp_ctrl { + u32 feature; + u32 cmd; +}; + +/** + * struct vcp_work_struct - vcp notify work structure. + * + * @work: struct work_struct member + * @dev: struct device member + * @u32 flags: vcp notify work flag + * @id: vcp core id + */ +struct vcp_work_struct { + struct work_struct work; + struct device *dev; + u32 flags; + u32 id; +}; + /** * struct vcp_region_info_st - config vcp image info sync to vcp bootloader. * @@ -201,6 +238,20 @@ struct vcp_region_info_st { u32 coredump_dram_offset; }; +int vcp_A_ready_ipi_handler(u32 id, void *prdata, + void *data, u32 len); +bool is_vcp_ready(struct mtk_vcp_device *vcp, + enum vcp_feature_id id); +int vcp_notify_work_init(struct mtk_vcp_device *vcp); +void vcp_extern_notify(enum vcp_core_id core_id, + enum vcp_notify_event notify_status); +void vcp_A_register_notify(struct mtk_vcp_device *vcp, + enum vcp_feature_id id, + struct notifier_block *nb); +void vcp_A_unregister_notify(struct mtk_vcp_device *vcp, + enum vcp_feature_id id, + struct notifier_block *nb); + int vcp_reserve_memory_init(struct mtk_vcp_device *vcp); phys_addr_t vcp_get_reserve_mem_phys(struct mtk_vcp_device *vcp, enum vcp_reserve_mem_id id); dma_addr_t vcp_get_reserve_mem_iova(struct mtk_vcp_device *vcp, enum vcp_reserve_mem_id id); @@ -213,5 +264,10 @@ int mtk_vcp_load(struct rproc *rproc, const struct firmware *fw); int vcp_wdt_irq_init(struct mtk_vcp_device *vcp); +int vcp_A_register_feature(struct mtk_vcp_device *vcp, + enum vcp_feature_id id); +int vcp_A_deregister_feature(struct mtk_vcp_device *vcp, + enum vcp_feature_id id); + int wait_core_hart_shutdown(struct mtk_vcp_device *vcp, enum vcp_core_id core_id); #endif diff --git a/drivers/remoteproc/mtk_vcp_rproc.c b/drivers/remoteproc/mtk_vcp_rproc.c index 6e0fecef72ce..833a0dc69d9c 100644 --- a/drivers/remoteproc/mtk_vcp_rproc.c +++ b/drivers/remoteproc/mtk_vcp_rproc.c @@ -71,6 +71,30 @@ static int mtk_vcp_start(struct rproc *rproc) { struct mtk_vcp_device *vcp = (struct mtk_vcp_device *)rproc->priv; struct arm_smccc_res res; + int ret; + + ret = vcp->ipi_ops->ipi_register(vcp->ipi_dev, IPI_OUT_C_SLEEP_0, + NULL, NULL, &vcp->vcp_cluster->slp_ipi_ack_data); + if (ret) { + dev_err(vcp->dev, "Failed to register IPI_OUT_C_SLEEP_0\n"); + goto slp_ipi_unregister; + } + + ret = vcp->ipi_ops->ipi_register(vcp->ipi_dev, IPI_IN_VCP_READY_0, + (void *)vcp_A_ready_ipi_handler, + vcp, &vcp->vcp_cluster->msg_vcp_ready0); + if (ret) { + dev_err(vcp->dev, "Failed to register IPI_IN_VCP_READY_0\n"); + goto vcp0_ready_ipi_unregister; + } + + ret = vcp->ipi_ops->ipi_register(vcp->ipi_dev, IPI_IN_VCP_READY_1, + (void *)vcp_A_ready_ipi_handler, + vcp, &vcp->vcp_cluster->msg_vcp_ready1); + if (ret) { + dev_err(vcp->dev, "Failed to register IPI_IN_VCP_READY_1\n"); + goto vcp1_ready_ipi_unregister; + } /* core 0 */ arm_smccc_smc(MTK_SIP_TINYSYS_VCP_CONTROL, @@ -83,10 +107,22 @@ static int mtk_vcp_start(struct rproc *rproc) 1, 0, 0, 0, 0, 0, &res); ret = reset_vcp(vcp); - if (ret) + if (ret) { dev_err(vcp->dev, "bootup fail\n"); - else + } else { dev_info(vcp->dev, "bootup successfully\n"); + if (vcp_A_register_feature(vcp, RTOS_FEATURE_ID) < 0) + vcp_A_deregister_feature(vcp, RTOS_FEATURE_ID); + } + + return ret; + +vcp1_ready_ipi_unregister: + vcp->ipi_ops->ipi_unregister(vcp->ipi_dev, IPI_IN_VCP_READY_1); +vcp0_ready_ipi_unregister: + vcp->ipi_ops->ipi_unregister(vcp->ipi_dev, IPI_IN_VCP_READY_0); +slp_ipi_unregister: + vcp->ipi_ops->ipi_unregister(vcp->ipi_dev, IPI_OUT_C_SLEEP_0); return ret; } @@ -97,6 +133,9 @@ static int mtk_vcp_stop(struct rproc *rproc) vcp_A_deregister_feature(vcp, RTOS_FEATURE_ID); + vcp_extern_notify(VCP_ID, VCP_EVENT_STOP); + vcp_extern_notify(MMUP_ID, VCP_EVENT_STOP); + return 0; } @@ -185,6 +224,8 @@ static struct mtk_vcp_device *vcp_rproc_init(struct platform_device *pdev, rproc->auto_boot = vcp_of_data->platdata.auto_boot; rproc->sysfs_read_only = vcp_of_data->platdata.sysfs_read_only; + mutex_init(&vcp->vcp_cluster->vcp_feature_mutex); + mutex_init(&vcp->vcp_cluster->vcp_ready_mutex); platform_set_drvdata(pdev, vcp); ret = vcp_reserve_memory_init(vcp); @@ -213,6 +254,10 @@ static struct mtk_vcp_device *vcp_rproc_init(struct platform_device *pdev, if (ret) return ERR_PTR(dev_err_probe(dev, ret, "vcp_ipi_mbox_init failed\n")); + ret = vcp_notify_work_init(vcp); + if (ret) + return ERR_PTR(dev_err_probe(dev, ret, "vcp_notify_work_init failed\n")); + pm_runtime_get_sync(dev); return vcp; @@ -287,6 +332,8 @@ static void vcp_device_remove(struct platform_device *pdev) { struct mtk_vcp_device *vcp = platform_get_drvdata(pdev); + flush_workqueue(vcp->vcp_cluster->vcp_workqueue); + destroy_workqueue(vcp->vcp_cluster->vcp_workqueue); pm_runtime_disable(&pdev->dev); rproc_del(vcp->rproc); @@ -297,6 +344,12 @@ static void vcp_device_shutdown(struct platform_device *pdev) struct mtk_vcp_device *vcp = platform_get_drvdata(pdev); int ret; + vcp->vcp_cluster->vcp_ready[VCP_ID] = false; + vcp->vcp_cluster->vcp_ready[MMUP_ID] = false; + + vcp_extern_notify(VCP_ID, VCP_EVENT_STOP); + vcp_extern_notify(MMUP_ID, VCP_EVENT_STOP); + writel(GIPC_VCP_HART0_SHUT, vcp->vcp_cluster->cfg_core + R_GIPC_IN_SET); ret = wait_core_hart_shutdown(vcp, VCP_ID); if (ret) @@ -382,6 +435,11 @@ static struct mtk_vcp_ipi_ops mt8196_vcp_ipi_ops = { static const struct mtk_vcp_of_data mt8196_of_data = { .ops = { + .vcp_is_ready = is_vcp_ready, + .vcp_register_feature = vcp_A_register_feature, + .vcp_deregister_feature = vcp_A_deregister_feature, + .vcp_register_notify = vcp_A_register_notify, + .vcp_unregister_notify = vcp_A_unregister_notify, .vcp_get_mem_phys = vcp_get_reserve_mem_phys, .vcp_get_mem_iova = vcp_get_reserve_mem_iova, .vcp_get_mem_virt = vcp_get_reserve_mem_virt, diff --git a/drivers/remoteproc/mtk_vcp_rproc.h b/drivers/remoteproc/mtk_vcp_rproc.h index ff3e67fc2611..600715b77124 100644 --- a/drivers/remoteproc/mtk_vcp_rproc.h +++ b/drivers/remoteproc/mtk_vcp_rproc.h @@ -19,10 +19,19 @@ * @core_nums: total core numbers get from dtb * @twohart: core weo hart support flag * @sram_offset: core sram memory layout + * @msg_vcp_ready0: core0 ready ipi msg data + * @msg_vcp_ready1: core1 ready ipi msg data + * @slp_ipi_ack_data: sleep ipi msg data + * @feature_enable: feature status count data + * @vcp_ready: vcp core status flag * @share_mem_iova: shared memory iova base * @share_mem_size: shared memory size + * @vcp_feature_mutex: vcp feature register mutex structure + * @vcp_ready_mutex: vcp core ready mutex structure * @vcp_ipidev: struct mtk_ipi_device + * @vcp_workqueue: ready workqueue_struct * @vcp_memory_tb: vcp memory allocated table + * @vcp_ready_notify_wk: vcp_work_struct structure */ struct mtk_vcp_of_cluster { void __iomem *sram_base; @@ -33,10 +42,19 @@ struct mtk_vcp_of_cluster { u32 core_nums; u32 twohart[VCP_CORE_TOTAL]; u32 sram_offset[VCP_CORE_TOTAL]; + u32 msg_vcp_ready0; + u32 msg_vcp_ready1; + u32 slp_ipi_ack_data; + bool feature_enable[NUM_FEATURE_ID]; + bool vcp_ready[VCP_CORE_TOTAL]; dma_addr_t share_mem_iova; size_t share_mem_size; + struct mutex vcp_feature_mutex; + struct mutex vcp_ready_mutex; struct mtk_ipi_device vcp_ipidev; + struct workqueue_struct *vcp_workqueue; struct vcp_reserve_mblock vcp_memory_tb[NUMS_MEM_ID]; + struct vcp_work_struct vcp_ready_notify_wk[VCP_CORE_TOTAL]; }; /** diff --git a/include/linux/remoteproc/mtk_vcp_public.h b/include/linux/remoteproc/mtk_vcp_public.h index 58ba4b8bb023..b9e1d86685fd 100644 --- a/include/linux/remoteproc/mtk_vcp_public.h +++ b/include/linux/remoteproc/mtk_vcp_public.h @@ -100,6 +100,18 @@ struct mtk_vcp_ipi_ops { }; struct mtk_vcp_ops { + bool (*vcp_is_ready)(struct mtk_vcp_device *vcp, + enum vcp_feature_id id); + int (*vcp_register_feature)(struct mtk_vcp_device *vcp, + enum vcp_feature_id id); + int (*vcp_deregister_feature)(struct mtk_vcp_device *vcp, + enum vcp_feature_id id); + void (*vcp_register_notify)(struct mtk_vcp_device *vcp, + enum vcp_feature_id id, + struct notifier_block *nb); + void (*vcp_unregister_notify)(struct mtk_vcp_device *vcp, + enum vcp_feature_id id, + struct notifier_block *nb); phys_addr_t (*vcp_get_mem_phys)(struct mtk_vcp_device *vcp, enum vcp_reserve_mem_id id); dma_addr_t (*vcp_get_mem_iova)(struct mtk_vcp_device *vcp, -- 2.46.0

