From bfb97da0507f48a5bfdcc3d7dcbc64aaeafa3025 Mon Sep 17 00:00:00 2001 From: Ding Wei Date: Tue, 22 Mar 2022 17:42:33 +0800 Subject: [PATCH] rockchip: video: mpp: Add soft reset+disable_irq before power off Change-Id: I62feeae483092bbd12edb185c956acc00b27b1c3 Signed-off-by: Ding Wei Signed-off-by: Wu Liangqing --- drivers/video/rockchip/mpp/mpp_common.c | 9 +-- drivers/video/rockchip/mpp/mpp_common.h | 1 + drivers/video/rockchip/mpp/mpp_iommu.c | 2 + drivers/video/rockchip/mpp/mpp_iommu.h | 2 + drivers/video/rockchip/mpp/mpp_rkvdec2.c | 74 +++++++++++++++++++++++- 5 files changed, 81 insertions(+), 7 deletions(-) diff --git a/drivers/video/rockchip/mpp/mpp_common.c b/drivers/video/rockchip/mpp/mpp_common.c index 772f33993f1c..bd16124b3238 100644 --- a/drivers/video/rockchip/mpp/mpp_common.c +++ b/drivers/video/rockchip/mpp/mpp_common.c @@ -2077,7 +2077,6 @@ int mpp_dev_probe(struct mpp_dev *mpp, goto failed; } - pm_runtime_get_sync(dev); /* * TODO: here or at the device itself, some device does not * have the iommu, maybe in the device is better. @@ -2090,7 +2089,7 @@ int mpp_dev_probe(struct mpp_dev *mpp, if (mpp->hw_ops->init) { ret = mpp->hw_ops->init(mpp); if (ret) - goto failed_init; + goto failed; } /* set iommu fault handler */ if (mpp->iommu_info) @@ -2099,19 +2098,17 @@ int mpp_dev_probe(struct mpp_dev *mpp, /* read hardware id */ if (hw_info->reg_id >= 0) { + pm_runtime_get_sync(dev); if (mpp->hw_ops->clk_on) mpp->hw_ops->clk_on(mpp); hw_info->hw_id = mpp_read(mpp, hw_info->reg_id); if (mpp->hw_ops->clk_off) mpp->hw_ops->clk_off(mpp); + pm_runtime_put_sync(dev); } - pm_runtime_put_sync(dev); - return ret; -failed_init: - pm_runtime_put_sync(dev); failed: mpp_detach_workqueue(mpp); device_init_wakeup(dev, false); diff --git a/drivers/video/rockchip/mpp/mpp_common.h b/drivers/video/rockchip/mpp/mpp_common.h index 6bcb83096206..655bbb69eace 100644 --- a/drivers/video/rockchip/mpp/mpp_common.h +++ b/drivers/video/rockchip/mpp/mpp_common.h @@ -333,6 +333,7 @@ struct mpp_dev { u32 msgs_cap; int irq; + bool is_irq_startup; u32 irq_status; void __iomem *reg_base; diff --git a/drivers/video/rockchip/mpp/mpp_iommu.c b/drivers/video/rockchip/mpp/mpp_iommu.c index 60e4b0007aab..b221f2eeace0 100644 --- a/drivers/video/rockchip/mpp/mpp_iommu.c +++ b/drivers/video/rockchip/mpp/mpp_iommu.c @@ -441,6 +441,8 @@ mpp_iommu_probe(struct device *dev) info->pdev = pdev; info->group = group; info->domain = domain; + info->irq = platform_get_irq(pdev, 0); + info->got_irq = (info->irq < 0) ? false : true; return info; diff --git a/drivers/video/rockchip/mpp/mpp_iommu.h b/drivers/video/rockchip/mpp/mpp_iommu.h index 0be63b2a8502..e9b57da39eb9 100644 --- a/drivers/video/rockchip/mpp/mpp_iommu.h +++ b/drivers/video/rockchip/mpp/mpp_iommu.h @@ -74,6 +74,8 @@ struct mpp_iommu_info { struct mpp_rk_iommu *iommu; iommu_fault_handler_t hdl; u32 av1d_iommu; + int irq; + int got_irq; }; struct mpp_dma_session * diff --git a/drivers/video/rockchip/mpp/mpp_rkvdec2.c b/drivers/video/rockchip/mpp/mpp_rkvdec2.c index 504029219108..be514e09fe9e 100644 --- a/drivers/video/rockchip/mpp/mpp_rkvdec2.c +++ b/drivers/video/rockchip/mpp/mpp_rkvdec2.c @@ -960,6 +960,9 @@ static int rkvdec2_ccu_probe(struct platform_device *pdev) device_init_wakeup(dev, true); pm_runtime_enable(dev); + /* power domain autosuspend delay 2s */ + pm_runtime_set_autosuspend_delay(dev, 2000); + pm_runtime_use_autosuspend(dev); ccu->aclk_info.clk = devm_clk_get(dev, "aclk_ccu"); if (!ccu->aclk_info.clk) @@ -1088,7 +1091,7 @@ static int rkvdec2_core_probe(struct platform_device *pdev) mpp = &dec->mpp; platform_set_drvdata(pdev, mpp); - + mpp->is_irq_startup = false; if (dev->of_node) { struct device_node *np = pdev->dev.of_node; const struct of_device_id *match; @@ -1110,6 +1113,9 @@ static int rkvdec2_core_probe(struct platform_device *pdev) dev_err(dev, "attach ccu failed\n"); return ret; } + /* power domain autosuspend delay 2s */ + pm_runtime_set_autosuspend_delay(dev, 2000); + pm_runtime_use_autosuspend(dev); /* alloc rcb buffer */ rkvdec2_alloc_rcbbuf(pdev, dec); @@ -1129,6 +1135,9 @@ static int rkvdec2_core_probe(struct platform_device *pdev) dev_err(dev, "register interrupter runtime failed\n"); return -EINVAL; } + /*make sure mpp->irq is startup then can be en/disable*/ + mpp->is_irq_startup = true; + mpp->session_max_buffers = RKVDEC_SESSION_MAX_BUFFERS; rkvdec2_procfs_init(mpp); @@ -1264,6 +1273,68 @@ static void rkvdec2_shutdown(struct platform_device *pdev) mpp_dev_shutdown(pdev); } +static int __maybe_unused rkvdec2_runtime_suspend(struct device *dev) +{ + if (strstr(dev_name(dev), "ccu")) { + struct rkvdec2_ccu *ccu = dev_get_drvdata(dev); + + mpp_clk_safe_disable(ccu->aclk_info.clk); + } else { + u32 val; + struct mpp_dev *mpp = dev_get_drvdata(dev); + + /* soft reset */ + mpp_write(mpp, RKVDEC_REG_IMPORTANT_BASE, RKVDEC_SOFTREST_EN); + udelay(5); + val = mpp_read(mpp, RKVDEC_REG_INT_EN); + if (!(val & RKVDEC_SOFT_RESET_READY)) + mpp_err("soft reset fail, int %08x\n", val); + mpp_write(mpp, RKVDEC_REG_INT_EN, 0); + + if (mpp->is_irq_startup) { + /* disable core irq */ + disable_irq(mpp->irq); + if (mpp->iommu_info && mpp->iommu_info->got_irq) + /* disable mmu irq */ + disable_irq(mpp->iommu_info->irq); + } + + if (mpp->hw_ops->clk_off) + mpp->hw_ops->clk_off(mpp); + } + + return 0; +} + +static int __maybe_unused rkvdec2_runtime_resume(struct device *dev) +{ + if (strstr(dev_name(dev), "ccu")) { + struct rkvdec2_ccu *ccu = dev_get_drvdata(dev); + + mpp_clk_safe_enable(ccu->aclk_info.clk); + } else { + struct mpp_dev *mpp = dev_get_drvdata(dev); + + if (mpp->hw_ops->clk_on) + mpp->hw_ops->clk_on(mpp); + if (mpp->is_irq_startup) { + /* enable core irq */ + enable_irq(mpp->irq); + /* enable mmu irq */ + if (mpp->iommu_info && mpp->iommu_info->got_irq) + enable_irq(mpp->iommu_info->irq); + } + + } + + return 0; +} + +static const struct dev_pm_ops rkvdec2_pm_ops = { + SET_RUNTIME_PM_OPS(rkvdec2_runtime_suspend, rkvdec2_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) +}; + struct platform_driver rockchip_rkvdec2_driver = { .probe = rkvdec2_probe, .remove = rkvdec2_remove, @@ -1271,6 +1342,7 @@ struct platform_driver rockchip_rkvdec2_driver = { .driver = { .name = RKVDEC_DRIVER_NAME, .of_match_table = of_match_ptr(mpp_rkvdec2_dt_match), + .pm = &rkvdec2_pm_ops, }, }; EXPORT_SYMBOL(rockchip_rkvdec2_driver);