From: changhuang.liang Date: Mon, 26 Sep 2022 09:12:04 +0000 (+0800) Subject: v4l2: VIN driver use pm X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d8b38689abf4a27a1b775ee745e8133fd5994ed9;p=platform%2Fkernel%2Flinux-starfive.git v4l2: VIN driver use pm VIN driver use pm save power, delete turn on pmu multiple times and modify isp clk and reset after turn on pmu. Signed-off-by: changhuang.liang --- diff --git a/drivers/media/platform/starfive/v4l2_driver/stf_isp.c b/drivers/media/platform/starfive/v4l2_driver/stf_isp.c index 6fb75d4..52c0833 100644 --- a/drivers/media/platform/starfive/v4l2_driver/stf_isp.c +++ b/drivers/media/platform/starfive/v4l2_driver/stf_isp.c @@ -400,25 +400,16 @@ free_ctrls: static int isp_set_power(struct v4l2_subdev *sd, int on) { struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd); - struct stf_vin2_dev *vin_dev = isp_dev->stfcamss->vin_dev; st_debug(ST_ISP, "%s, %d\n", __func__, __LINE__); mutex_lock(&isp_dev->power_lock); if (on) { - if (isp_dev->power_count == 0) { - /* Needs to enable vin clock before access ISP. */ - vin_dev->hw_ops->vin_top_clk_init(vin_dev); - vin_dev->hw_ops->vin_clk_enable(vin_dev); - isp_dev->hw_ops->isp_clk_enable(isp_dev); - if (!user_config_isp) - isp_dev->hw_ops->isp_config_set(isp_dev); - } + if (isp_dev->power_count == 0) + st_debug(ST_ISP, "turn on isp\n"); isp_dev->power_count++; } else { if (isp_dev->power_count == 0) goto exit; - if (isp_dev->power_count == 1) - isp_dev->hw_ops->isp_clk_disable(isp_dev); isp_dev->power_count--; } exit: @@ -473,6 +464,9 @@ static int isp_set_stream(struct v4l2_subdev *sd, int enable) mutex_lock(&isp_dev->stream_lock); if (enable) { if (isp_dev->stream_count == 0) { + isp_dev->hw_ops->isp_clk_enable(isp_dev); + if (!user_config_isp) + isp_dev->hw_ops->isp_config_set(isp_dev); interface_type = isp_get_interface_type(&sd->entity); if (interface_type < 0) { st_err(ST_ISP, "%s, pipeline not config\n", __func__); @@ -488,8 +482,10 @@ static int isp_set_stream(struct v4l2_subdev *sd, int enable) } else { if (isp_dev->stream_count == 0) goto exit; - if (isp_dev->stream_count == 1) + if (isp_dev->stream_count == 1) { isp_dev->hw_ops->isp_stream_set(isp_dev, enable); + isp_dev->hw_ops->isp_clk_disable(isp_dev); + } isp_dev->stream_count--; } src_ch.type = V4L2_EVENT_SOURCE_CHANGE, diff --git a/drivers/media/platform/starfive/v4l2_driver/stf_vin.c b/drivers/media/platform/starfive/v4l2_driver/stf_vin.c index 7625aad..ca60869 100644 --- a/drivers/media/platform/starfive/v4l2_driver/stf_vin.c +++ b/drivers/media/platform/starfive/v4l2_driver/stf_vin.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "stfcamss.h" @@ -218,23 +219,6 @@ int stf_vin_subdev_init(struct stfcamss *stfcamss) vin_dev->hw_ops->vin_wr_irq_enable(vin_dev, 1); vin_dev->hw_ops->vin_wr_irq_enable(vin_dev, 0); - /* Reset device */ - /*Do not configure the CLK before powering on the device, - *add vin_power_on() to vin_set_power() 2021 1111 - */ - ret = vin_dev->hw_ops->vin_top_clk_init(vin_dev); - if (ret) { - st_err(ST_VIN, "Failed to reset device\n"); - goto out; - } - - // /* set the sysctl config */ - // ret = vin_dev->hw_ops->vin_config_set(vin_dev); - // if (ret) { - // st_err(ST_VIN, "Failed to config device\n"); - // goto out; - // } - mutex_init(&vin_dev->power_lock); vin_dev->power_count = 0; @@ -283,6 +267,7 @@ static int vin_set_power(struct v4l2_subdev *sd, int on) { struct vin_line *line = v4l2_get_subdevdata(sd); struct stf_vin2_dev *vin_dev = line_to_vin2_dev(line); + struct stfcamss *stfcamss = vin_dev->stfcamss; mutex_lock(&line->power_lock); if (on) { @@ -303,7 +288,7 @@ exit_line: mutex_lock(&vin_dev->power_lock); if (on) { if (vin_dev->power_count == 0) { - //vin_dev->hw_ops->vin_top_clk_init(vin_dev); + pm_runtime_get_sync(stfcamss->dev); vin_dev->hw_ops->vin_clk_enable(vin_dev); vin_dev->hw_ops->vin_config_set(vin_dev); } @@ -316,7 +301,7 @@ exit_line: } if (vin_dev->power_count == 1) { vin_dev->hw_ops->vin_clk_disable(vin_dev); - //vin_dev->hw_ops->vin_top_clk_deinit(vin_dev); + pm_runtime_put_sync(stfcamss->dev); } vin_dev->power_count--; } diff --git a/drivers/media/platform/starfive/v4l2_driver/stf_vin.h b/drivers/media/platform/starfive/v4l2_driver/stf_vin.h index b751afc..5625621 100644 --- a/drivers/media/platform/starfive/v4l2_driver/stf_vin.h +++ b/drivers/media/platform/starfive/v4l2_driver/stf_vin.h @@ -87,8 +87,6 @@ struct vin_line { struct stf_vin2_dev; struct vin_hw_ops { - int (*vin_top_clk_init)(struct stf_vin2_dev *vin_dev); - int (*vin_top_clk_deinit)(struct stf_vin2_dev *vin_dev); int (*vin_clk_enable)(struct stf_vin2_dev *vin_dev); int (*vin_clk_disable)(struct stf_vin2_dev *vin_dev); int (*vin_config_set)(struct stf_vin2_dev *vin_dev); diff --git a/drivers/media/platform/starfive/v4l2_driver/stf_vin_hw_ops.c b/drivers/media/platform/starfive/v4l2_driver/stf_vin_hw_ops.c index 9b06550..aaec27c 100644 --- a/drivers/media/platform/starfive/v4l2_driver/stf_vin_hw_ops.c +++ b/drivers/media/platform/starfive/v4l2_driver/stf_vin_hw_ops.c @@ -7,8 +7,6 @@ #include #include #include -#include -#include static void vin_intr_clear(void __iomem *sysctrl_base) { @@ -213,47 +211,6 @@ static irqreturn_t stf_vin_isp_irq_csiline_handler(int irq, void *priv) return IRQ_HANDLED; } -static int stf_vin_top_clk_init(struct stf_vin2_dev *vin_dev) -{ - struct stfcamss *stfcamss = vin_dev->stfcamss; - int ret; - - pm_runtime_enable(stfcamss->dev); - ret = pm_runtime_get_sync(stfcamss->dev); - if (ret < 0) { - dev_err(stfcamss->dev, - "vin_clk_init: failed to get pm runtime: %d\n", ret); - return ret; - } - - if (!__clk_is_enabled(stfcamss->sys_clk[STFCLK_NOC_BUS_CLK_ISP_AXI].clk)) - clk_prepare_enable(stfcamss->sys_clk[STFCLK_NOC_BUS_CLK_ISP_AXI].clk); - else - st_warn(ST_VIN, "noc_bus_clk_isp_axi already enable\n"); - - clk_prepare_enable(stfcamss->sys_clk[STFCLK_ISPCORE_2X].clk); - clk_prepare_enable(stfcamss->sys_clk[STFCLK_ISP_AXI].clk); - reset_control_deassert(stfcamss->sys_rst[STFRST_ISP_TOP_N].rstc); - reset_control_deassert(stfcamss->sys_rst[STFRST_ISP_TOP_AXI].rstc); - - return 0; -} - -static int stf_vin_top_clk_deinit(struct stf_vin2_dev *vin_dev) -{ - struct stfcamss *stfcamss = vin_dev->stfcamss; - - reset_control_assert(stfcamss->sys_rst[STFRST_ISP_TOP_AXI].rstc); - reset_control_assert(stfcamss->sys_rst[STFRST_ISP_TOP_N].rstc); - clk_disable_unprepare(stfcamss->sys_clk[STFCLK_ISP_AXI].clk); - clk_disable_unprepare(stfcamss->sys_clk[STFCLK_ISPCORE_2X].clk); - - pm_runtime_put_sync(stfcamss->dev); - pm_runtime_disable(stfcamss->dev); - - return 0; -} - static int stf_vin_clk_enable(struct stf_vin2_dev *vin_dev) { struct stfcamss *stfcamss = vin_dev->stfcamss; @@ -451,8 +408,6 @@ void dump_vin_reg(void *__iomem regbase) } struct vin_hw_ops vin_ops = { - .vin_top_clk_init = stf_vin_top_clk_init, - .vin_top_clk_deinit = stf_vin_top_clk_deinit, .vin_clk_enable = stf_vin_clk_enable, .vin_clk_disable = stf_vin_clk_disable, .vin_config_set = stf_vin_config_set, diff --git a/drivers/media/platform/starfive/v4l2_driver/stfcamss.c b/drivers/media/platform/starfive/v4l2_driver/stfcamss.c index f699766..f937285 100644 --- a/drivers/media/platform/starfive/v4l2_driver/stfcamss.c +++ b/drivers/media/platform/starfive/v4l2_driver/stfcamss.c @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -1011,6 +1012,8 @@ static int stfcamss_probe(struct platform_device *pdev) goto err_cam; } + pm_runtime_enable(dev); + stfcamss->nclks = ARRAY_SIZE(stfcamss_clocks); stfcamss->sys_clk = stfcamss_clocks; @@ -1175,6 +1178,7 @@ static int stfcamss_remove(struct platform_device *pdev) stfcamss_unregister_subdevices(stfcamss); v4l2_device_unregister(&stfcamss->v4l2_dev); media_device_cleanup(&stfcamss->media_dev); + pm_runtime_disable(&pdev->dev); kfree(stfcamss); @@ -1188,11 +1192,148 @@ static const struct of_device_id stfcamss_of_match[] = { MODULE_DEVICE_TABLE(of, stfcamss_of_match); +#ifdef CONFIG_PM_SLEEP +static int stfcamss_suspend(struct device *dev) +{ + struct stfcamss *stfcamss = dev_get_drvdata(dev); + struct stf_vin2_dev *vin_dev = stfcamss->vin_dev; + struct media_entity *entity; + struct media_pad *pad; + struct v4l2_subdev *subdev; + struct stfcamss_video *video; + struct video_device *vdev; + int i = 0; + + for (i = 0; i < VIN_LINE_MAX; i++) { + if (vin_dev->line[i].stream_count) { + vin_dev->line[i].stream_count ++; + video = &vin_dev->line[i].video_out; + vdev = &vin_dev->line[i].video_out.vdev; + entity = &vdev->entity; + while (1) { + pad = &entity->pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + + pad = media_entity_remote_pad(pad); + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) + break; + + entity = pad->entity; + subdev = media_entity_to_v4l2_subdev(entity); + + v4l2_subdev_call(subdev, video, s_stream, 0); + } + media_pipeline_stop(&vdev->entity); + video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR); + v4l2_pipeline_pm_put(&vdev->entity); + } + } + + return pm_runtime_force_suspend(dev); +} + +static int stfcamss_resume(struct device *dev) +{ + struct stfcamss *stfcamss = dev_get_drvdata(dev); + struct stf_vin2_dev *vin_dev = stfcamss->vin_dev; + struct media_entity *entity; + struct media_pad *pad; + struct v4l2_subdev *subdev; + struct stfcamss_video *video; + struct video_device *vdev; + int i = 0; + int ret = 0; + + pm_runtime_force_resume(dev); + + for (i = 0; i < VIN_LINE_MAX; i++) { + if (vin_dev->line[i].stream_count) { + vin_dev->line[i].stream_count--; + video = &vin_dev->line[i].video_out; + vdev = &vin_dev->line[i].video_out.vdev; + + ret = v4l2_pipeline_pm_get(&vdev->entity); + if (ret < 0) + goto err; + + ret = media_pipeline_start(&vdev->entity, &video->stfcamss->pipe); + if (ret < 0) + goto err_pm_put; + + entity = &vdev->entity; + while (1) { + pad = &entity->pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + + pad = media_entity_remote_pad(pad); + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) + break; + + entity = pad->entity; + subdev = media_entity_to_v4l2_subdev(entity); + + ret = v4l2_subdev_call(subdev, video, s_stream, 1); + if (ret < 0 && ret != -ENOIOCTLCMD) + goto err_pipeline_stop; + } + } + } + + return 0; + +err_pipeline_stop: + media_pipeline_stop(&vdev->entity); +err_pm_put: + v4l2_pipeline_pm_put(&vdev->entity); +err: + return ret; +} +#endif /* CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM +static int stfcamss_runtime_suspend(struct device *dev) +{ + struct stfcamss *stfcamss = dev_get_drvdata(dev); + + if (!__clk_is_enabled(stfcamss->sys_clk[STFCLK_NOC_BUS_CLK_ISP_AXI].clk)) + clk_prepare_enable(stfcamss->sys_clk[STFCLK_NOC_BUS_CLK_ISP_AXI].clk); + else + st_warn(ST_VIN, "noc_bus_clk_isp_axi already enable\n"); + + reset_control_assert(stfcamss->sys_rst[STFRST_ISP_TOP_AXI].rstc); + reset_control_assert(stfcamss->sys_rst[STFRST_ISP_TOP_N].rstc); + clk_disable_unprepare(stfcamss->sys_clk[STFCLK_ISP_AXI].clk); + clk_disable_unprepare(stfcamss->sys_clk[STFCLK_ISPCORE_2X].clk); + + return 0; +} + +static int stfcamss_runtime_resume(struct device *dev) +{ + struct stfcamss *stfcamss = dev_get_drvdata(dev); + + clk_prepare_enable(stfcamss->sys_clk[STFCLK_ISPCORE_2X].clk); + clk_prepare_enable(stfcamss->sys_clk[STFCLK_ISP_AXI].clk); + reset_control_deassert(stfcamss->sys_rst[STFRST_ISP_TOP_N].rstc); + reset_control_deassert(stfcamss->sys_rst[STFRST_ISP_TOP_AXI].rstc); + + return 0; +} +#endif /* CONFIG_PM */ + +static const struct dev_pm_ops stfcamss_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(stfcamss_suspend, stfcamss_resume) + SET_RUNTIME_PM_OPS(stfcamss_runtime_suspend, stfcamss_runtime_resume, NULL) +}; + static struct platform_driver stfcamss_driver = { .probe = stfcamss_probe, .remove = stfcamss_remove, .driver = { .name = DRV_NAME, + .pm = &stfcamss_pm_ops, .of_match_table = of_match_ptr(stfcamss_of_match), }, };