diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 708b439079a5..884b0f4918d6 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -3177,7 +3177,7 @@ static void rkcif_do_cru_reset(struct rkcif_device *dev) } } -static void rkcif_do_soft_reset(struct rkcif_device *dev) +void rkcif_do_soft_reset(struct rkcif_device *dev) { if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY || dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY || @@ -4803,20 +4803,6 @@ static int rkcif_fh_open(struct file *filp) ret); return ret; } - /* - * Soft reset via CRU. - * Because CRU would reset iommu too, so there's not chance - * to reset cif once we hold buffers after buf queued - */ - if (cifdev->chip_id >= CHIP_RK1808_CIF) { - mutex_lock(&cifdev->stream_lock); - if (!atomic_read(&cifdev->fh_cnt)) - rkcif_soft_reset(cifdev, true); - atomic_inc(&cifdev->fh_cnt); - mutex_unlock(&cifdev->stream_lock); - } else { - rkcif_soft_reset(cifdev, true); - } ret = v4l2_fh_open(filp); if (!ret) { @@ -4840,13 +4826,6 @@ static int rkcif_fh_release(struct file *filp) if (!ret) v4l2_pipeline_pm_put(&vnode->vdev.entity); - mutex_lock(&cifdev->stream_lock); - if (!atomic_dec_return(&cifdev->fh_cnt)) - rkcif_soft_reset(cifdev, true); - else if (atomic_read(&cifdev->fh_cnt) < 0) - atomic_set(&cifdev->fh_cnt, 0); - mutex_unlock(&cifdev->stream_lock); - pm_runtime_put_sync(cifdev->dev); return ret; } diff --git a/drivers/media/platform/rockchip/cif/cif-scale.c b/drivers/media/platform/rockchip/cif/cif-scale.c index bbb2d7ce43f4..534d026f952e 100644 --- a/drivers/media/platform/rockchip/cif/cif-scale.c +++ b/drivers/media/platform/rockchip/cif/cif-scale.c @@ -430,12 +430,6 @@ static int rkcif_scale_fh_open(struct file *file) v4l2_err(&cifdev->v4l2_dev, "Failed to get runtime pm, %d\n", ret); - mutex_lock(&cifdev->stream_lock); - if (!atomic_read(&cifdev->fh_cnt)) - rkcif_soft_reset(cifdev, true); - atomic_inc(&cifdev->fh_cnt); - mutex_unlock(&cifdev->stream_lock); - ret = v4l2_fh_open(file); if (!ret) { ret = v4l2_pipeline_pm_get(&vnode->vdev.entity); diff --git a/drivers/media/platform/rockchip/cif/dev.c b/drivers/media/platform/rockchip/cif/dev.c index c6a5d4de941c..962f61b1bac6 100644 --- a/drivers/media/platform/rockchip/cif/dev.c +++ b/drivers/media/platform/rockchip/cif/dev.c @@ -1116,6 +1116,25 @@ err_stream_off: return ret; } +static int rkcif_pipeline_set_power(struct rkcif_pipeline *p, bool on) +{ + int i, ret; + + /* phy -> sensor */ + for (i = 0; i < p->num_subdevs; i++) { + ret = v4l2_subdev_call(p->subdevs[i], core, s_power, on); + if (on && ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) + goto err_power_off; + } + + return 0; + +err_power_off: + for (--i; i >= 0; --i) + v4l2_subdev_call(p->subdevs[i], core, s_power, false); + return ret; +} + static int rkcif_create_link(struct rkcif_device *dev, struct rkcif_sensor_info *sensor, u32 stream_num, @@ -1569,25 +1588,6 @@ static irqreturn_t rkcif_irq_lite_handler(int irq, struct rkcif_device *cif_dev) return IRQ_HANDLED; } -void rkcif_soft_reset(struct rkcif_device *cif_dev, bool is_rst_iommu) -{ - struct rkcif_hw *hw_dev = cif_dev->hw_dev; - bool can_reset = true; - int i; - - if (!cif_dev->hw_dev) - return; - - for (i = 0; i < hw_dev->dev_num; i++) - if (atomic_read(&hw_dev->cif_dev[i]->pipe.stream_cnt) != 0) { - can_reset = false; - break; - } - - if (can_reset) - rkcif_hw_soft_reset(cif_dev->hw_dev, is_rst_iommu); -} - int rkcif_attach_hw(struct rkcif_device *cif_dev) { struct device_node *np; @@ -1755,7 +1755,7 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int spin_lock_init(&cif_dev->reset_watchdog_timer.csi2_err_lock); atomic_set(&cif_dev->pipe.power_cnt, 0); atomic_set(&cif_dev->pipe.stream_cnt, 0); - atomic_set(&cif_dev->fh_cnt, 0); + atomic_set(&cif_dev->power_cnt, 0); cif_dev->is_start_hdr = false; cif_dev->pipe.open = rkcif_pipeline_open; cif_dev->pipe.close = rkcif_pipeline_close; @@ -1982,9 +1982,9 @@ static int __maybe_unused rkcif_runtime_suspend(struct device *dev) struct rkcif_device *cif_dev = dev_get_drvdata(dev); int ret = 0; - if (atomic_dec_return(&cif_dev->hw_dev->power_cnt)) + if (atomic_dec_return(&cif_dev->power_cnt)) return 0; - + rkcif_pipeline_set_power(&cif_dev->pipe, false); mutex_lock(&cif_dev->hw_dev->dev_lock); ret = pm_runtime_put_sync(cif_dev->hw_dev->dev); mutex_unlock(&cif_dev->hw_dev->dev_lock); @@ -1996,11 +1996,15 @@ static int __maybe_unused rkcif_runtime_resume(struct device *dev) struct rkcif_device *cif_dev = dev_get_drvdata(dev); int ret = 0; - if (atomic_inc_return(&cif_dev->hw_dev->power_cnt) > 1) + if (atomic_inc_return(&cif_dev->power_cnt) > 1) return 0; + ret = rkcif_pipeline_set_power(&cif_dev->pipe, true); + if (ret) + return ret; mutex_lock(&cif_dev->hw_dev->dev_lock); ret = pm_runtime_resume_and_get(cif_dev->hw_dev->dev); mutex_unlock(&cif_dev->hw_dev->dev_lock); + rkcif_do_soft_reset(cif_dev); return (ret > 0) ? 0 : ret; } diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index d1621c76203c..46bcdb428688 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -699,7 +699,7 @@ struct rkcif_device { int num_channels; int chip_id; atomic_t stream_cnt; - atomic_t fh_cnt; + atomic_t power_cnt; struct mutex stream_lock; /* lock between streams */ struct mutex scale_lock; /* lock between scale dev */ enum rkcif_workmode workmode; @@ -776,8 +776,6 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev); void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev); unsigned int rkcif_irq_global(struct rkcif_device *cif_dev); void rkcif_irq_handle_toisp(struct rkcif_device *cif_dev, unsigned int intstat_glb); -void rkcif_soft_reset(struct rkcif_device *cif_dev, - bool is_rst_iommu); int rkcif_register_lvds_subdev(struct rkcif_device *dev); void rkcif_unregister_lvds_subdev(struct rkcif_device *dev); int rkcif_register_dvp_sof_subdev(struct rkcif_device *dev); @@ -802,6 +800,8 @@ int rkcif_set_fmt(struct rkcif_stream *stream, bool try); void rkcif_enable_dma_capture(struct rkcif_stream *stream); +void rkcif_do_soft_reset(struct rkcif_device *dev); + u32 rkcif_mbus_pixelcode_to_v4l2(u32 pixelcode); #endif diff --git a/drivers/media/platform/rockchip/cif/hw.c b/drivers/media/platform/rockchip/cif/hw.c index 3b7de160cbe3..c1bdae98b400 100644 --- a/drivers/media/platform/rockchip/cif/hw.c +++ b/drivers/media/platform/rockchip/cif/hw.c @@ -1238,6 +1238,7 @@ static int rkcif_plat_hw_probe(struct platform_device *pdev) cif_hw->is_dma_contig = true; mutex_init(&cif_hw->dev_lock); spin_lock_init(&cif_hw->group_lock); + atomic_set(&cif_hw->power_cnt, 0); cif_hw->iommu_en = is_iommu_enable(dev); ret = of_reserved_mem_device_init(dev); @@ -1328,6 +1329,8 @@ static int __maybe_unused rkcif_runtime_suspend(struct device *dev) { struct rkcif_hw *cif_hw = dev_get_drvdata(dev); + if (atomic_dec_return(&cif_hw->power_cnt)) + return 0; rkcif_disable_sys_clk(cif_hw); return pinctrl_pm_select_sleep_state(dev); @@ -1338,10 +1341,13 @@ static int __maybe_unused rkcif_runtime_resume(struct device *dev) struct rkcif_hw *cif_hw = dev_get_drvdata(dev); int ret; + if (atomic_inc_return(&cif_hw->power_cnt) > 1) + return 0; ret = pinctrl_pm_select_default_state(dev); if (ret < 0) return ret; rkcif_enable_sys_clk(cif_hw); + rkcif_hw_soft_reset(cif_hw, true); return 0; } diff --git a/drivers/media/platform/rockchip/cif/subdev-itf.c b/drivers/media/platform/rockchip/cif/subdev-itf.c index 0f50fa5e108e..a4c9f97f7f99 100644 --- a/drivers/media/platform/rockchip/cif/subdev-itf.c +++ b/drivers/media/platform/rockchip/cif/subdev-itf.c @@ -560,7 +560,7 @@ static int sditf_s_power(struct v4l2_subdev *sd, int on) if (on) ret = pm_runtime_resume_and_get(cif_dev->dev); else - pm_runtime_put(cif_dev->dev); + pm_runtime_put_sync(cif_dev->dev); } return ret; }