diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c index 1d1e9bfef8e9..62ca88e72570 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -20,6 +21,8 @@ #include #include #include +#include +#include #include #include #include @@ -1095,6 +1098,11 @@ static void rkvdec_job_finish(struct rkvdec_ctx *ctx, struct rkvdec_dev *rkvdec = ctx->dev; pm_runtime_put_autosuspend(rkvdec->dev); + + if (result == VB2_BUF_STATE_ERROR && + rkvdec->reset_mask == RESET_NONE) + rkvdec->reset_mask |= RESET_SOFT; + rkvdec_job_finish_no_pm(ctx, result); } @@ -1167,6 +1175,33 @@ static void rkvdec_device_run(void *priv) if (WARN_ON(!desc)) return; + if (rkvdec->reset_mask != RESET_NONE) { + + if (rkvdec->reset_mask & RESET_SOFT) { + writel(RKVDEC_SOFTRST_EN_P, + rkvdec->regs + RKVDEC_REG_INTERRUPT); + udelay(RKVDEC_RESET_DELAY); + if (readl(rkvdec->regs + RKVDEC_REG_INTERRUPT) + & RKVDEC_SOFTRESET_RDY) + dev_info_ratelimited(rkvdec->dev, + "softreset failed\n"); + } + + if (rkvdec->reset_mask & RESET_HARD) { + rockchip_pmu_idle_request(rkvdec->dev, true); + ret = reset_control_assert(rkvdec->rstc); + if (!ret) { + udelay(RKVDEC_RESET_DELAY); + ret = reset_control_deassert(rkvdec->rstc); + } + rockchip_pmu_idle_request(rkvdec->dev, false); + if (ret) + dev_notice_ratelimited(rkvdec->dev, + "hardreset failed\n"); + } + rkvdec->reset_mask = RESET_NONE; + pm_runtime_suspend(rkvdec->dev); + } ret = pm_runtime_resume_and_get(rkvdec->dev); if (ret < 0) { @@ -1451,6 +1486,11 @@ static irqreturn_t rk3399_irq_handler(struct rkvdec_ctx *ctx) rkvdec_iommu_restore(rkvdec); } + if (state == VB2_BUF_STATE_ERROR) { + rkvdec->reset_mask |= (status & RKVDEC_ERR_MASK) ? + RESET_HARD : RESET_SOFT; + } + if (cancel_delayed_work(&rkvdec->watchdog_work)) rkvdec_job_finish(ctx, state); @@ -1606,6 +1646,7 @@ static void rkvdec_watchdog_func(struct work_struct *work) ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev); if (ctx) { dev_err(rkvdec->dev, "Frame processing timed out!\n"); + rkvdec->reset_mask |= RESET_HARD; writel(RKVDEC_IRQ_DIS, rkvdec->regs + RKVDEC_REG_INTERRUPT); rkvdec_job_finish(ctx, VB2_BUF_STATE_ERROR); } @@ -1833,6 +1874,18 @@ static int rkvdec_probe(struct platform_device *pdev) if (!rkvdec->sram_pool && rkvdec->variant->num_rcb_sizes > 0) dev_info(&pdev->dev, "No sram node, RCB will be stored in RAM\n"); + + rkvdec->rstc = devm_reset_control_array_get(&pdev->dev, RESET_CONTROL_OPTIONAL_EXCLUSIVE); + if (IS_ERR(rkvdec->rstc)) { + dev_err(&pdev->dev, + "get resets failed %ld\n", PTR_ERR(rkvdec->rstc)); + return PTR_ERR(rkvdec->rstc); + } else { + dev_dbg(&pdev->dev, + "requested %d resets\n", + reset_control_get_count(&pdev->dev)); + } + pm_runtime_set_autosuspend_delay(&pdev->dev, 100); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); @@ -1869,9 +1922,9 @@ static void rkvdec_remove(struct platform_device *pdev) cancel_delayed_work_sync(&rkvdec->watchdog_work); - rkvdec_v4l2_cleanup(rkvdec); - pm_runtime_disable(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); + pm_runtime_disable(&pdev->dev); + rkvdec_v4l2_cleanup(rkvdec); if (rkvdec->empty_domain) iommu_domain_free(rkvdec->empty_domain);