mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 20:07:46 +09:00
media: rockchip: vicap add pipe power control and do reset after power on
Signed-off-by: Zefa Chen <zefa.chen@rock-chips.com> Change-Id: Ia5723fd08d4d70feef131976f30e31755c9d2ff3
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user