In order to reuse the FIMC-LITE module on Exynos4 and Exynos5 SoC introduce a set of callbacks for the media pipeline control from within FIMC/FIMC-LITE video node. It lets us avoid symbol dependencies between FIMC-LITE and the whole media device driver, which simplifies the initialization sequences and doesn't introduce issues preventing common kernel image for exynos4 and exynos5 SoCs. Signed-off-by: Sylwester Nawrocki <s.nawrocki@xxxxxxxxxxx> Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx> --- drivers/media/platform/s5p-fimc/fimc-capture.c | 21 ++++++++++++--------- drivers/media/platform/s5p-fimc/fimc-core.h | 1 + drivers/media/platform/s5p-fimc/fimc-lite.c | 22 ++++++++++++++-------- drivers/media/platform/s5p-fimc/fimc-lite.h | 2 ++ drivers/media/platform/s5p-fimc/fimc-mdevice.c | 26 ++++++++++++++++++-------- drivers/media/platform/s5p-fimc/fimc-mdevice.h | 6 ------ include/media/s5p_fimc.h | 18 ++++++++++++++++++ 7 files changed, 65 insertions(+), 31 deletions(-) diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c index 4092388..ab1fa9d 100644 --- a/drivers/media/platform/s5p-fimc/fimc-capture.c +++ b/drivers/media/platform/s5p-fimc/fimc-capture.c @@ -118,7 +118,8 @@ static int fimc_capture_state_cleanup(struct fimc_dev *fimc, bool suspend) spin_unlock_irqrestore(&fimc->slock, flags); if (streaming) - return fimc_pipeline_s_stream(&fimc->pipeline, 0); + return fimc_pipeline_call(fimc, set_stream, + &fimc->pipeline, 0); else return 0; } @@ -264,7 +265,8 @@ static int start_streaming(struct vb2_queue *q, unsigned int count) fimc_activate_capture(ctx); if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state)) - fimc_pipeline_s_stream(&fimc->pipeline, 1); + fimc_pipeline_call(fimc, set_stream, + &fimc->pipeline, 1); } return 0; @@ -288,7 +290,7 @@ int fimc_capture_suspend(struct fimc_dev *fimc) int ret = fimc_stop_capture(fimc, suspend); if (ret) return ret; - return fimc_pipeline_shutdown(&fimc->pipeline); + return fimc_pipeline_call(fimc, shutdown, &fimc->pipeline); } static void buffer_queue(struct vb2_buffer *vb); @@ -304,8 +306,8 @@ int fimc_capture_resume(struct fimc_dev *fimc) INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q); vid_cap->buf_index = 0; - fimc_pipeline_initialize(&fimc->pipeline, &vid_cap->vfd.entity, - false); + fimc_pipeline_call(fimc, initialize, &fimc->pipeline, + &vid_cap->vfd.entity, false); fimc_capture_hw_init(fimc); clear_bit(ST_CAPT_SUSPENDED, &fimc->state); @@ -422,7 +424,8 @@ static void buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&fimc->slock, flags); if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state)) - fimc_pipeline_s_stream(&fimc->pipeline, 1); + fimc_pipeline_call(fimc, set_stream, + &fimc->pipeline, 1); return; } spin_unlock_irqrestore(&fimc->slock, flags); @@ -502,8 +505,8 @@ static int fimc_capture_open(struct file *file) } if (++fimc->vid_cap.refcnt == 1) { - ret = fimc_pipeline_initialize(&fimc->pipeline, - &fimc->vid_cap.vfd.entity, true); + ret = fimc_pipeline_call(fimc, initialize, &fimc->pipeline, + &fimc->vid_cap.vfd.entity, true); if (!ret && !fimc->vid_cap.user_subdev_api) ret = fimc_capture_set_default_format(fimc); @@ -536,7 +539,7 @@ static int fimc_capture_close(struct file *file) if (--fimc->vid_cap.refcnt == 0) { clear_bit(ST_CAPT_BUSY, &fimc->state); fimc_stop_capture(fimc, false); - fimc_pipeline_shutdown(&fimc->pipeline); + fimc_pipeline_call(fimc, shutdown, &fimc->pipeline); clear_bit(ST_CAPT_SUSPENDED, &fimc->state); } diff --git a/drivers/media/platform/s5p-fimc/fimc-core.h b/drivers/media/platform/s5p-fimc/fimc-core.h index d3a3a00..6180546 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.h +++ b/drivers/media/platform/s5p-fimc/fimc-core.h @@ -440,6 +440,7 @@ struct fimc_dev { unsigned long state; struct vb2_alloc_ctx *alloc_ctx; struct fimc_pipeline pipeline; + const struct fimc_pipeline_ops *pipeline_ops; }; /** diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.c b/drivers/media/platform/s5p-fimc/fimc-lite.c index 9289008..5e99713 100644 --- a/drivers/media/platform/s5p-fimc/fimc-lite.c +++ b/drivers/media/platform/s5p-fimc/fimc-lite.c @@ -28,11 +28,14 @@ #include <media/v4l2-mem2mem.h> #include <media/videobuf2-core.h> #include <media/videobuf2-dma-contig.h> +#include <media/s5p_fimc.h> #include "fimc-mdevice.h" #include "fimc-core.h" +#include "fimc-lite.h" #include "fimc-lite-reg.h" + static int debug; module_param(debug, int, 0644); @@ -193,7 +196,7 @@ static int fimc_lite_reinit(struct fimc_lite *fimc, bool suspend) if (!streaming) return 0; - return fimc_pipeline_s_stream(&fimc->pipeline, 0); + return fimc_pipeline_call(fimc, set_stream, &fimc->pipeline, 0); } static int fimc_lite_stop_capture(struct fimc_lite *fimc, bool suspend) @@ -307,7 +310,8 @@ static int start_streaming(struct vb2_queue *q, unsigned int count) flite_hw_capture_start(fimc); if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state)) - fimc_pipeline_s_stream(&fimc->pipeline, 1); + fimc_pipeline_call(fimc, set_stream, + &fimc->pipeline, 1); } if (debug > 0) flite_hw_dump_regs(fimc, __func__); @@ -411,7 +415,8 @@ static void buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&fimc->slock, flags); if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state)) - fimc_pipeline_s_stream(&fimc->pipeline, 1); + fimc_pipeline_call(fimc, set_stream, + &fimc->pipeline, 1); return; } spin_unlock_irqrestore(&fimc->slock, flags); @@ -466,8 +471,8 @@ static int fimc_lite_open(struct file *file) goto done; if (++fimc->ref_count == 1 && fimc->out_path == FIMC_IO_DMA) { - ret = fimc_pipeline_initialize(&fimc->pipeline, - &fimc->vfd.entity, true); + ret = fimc_pipeline_call(fimc, initialize, &fimc->pipeline, + &fimc->vfd.entity, true); if (ret < 0) { pm_runtime_put_sync(&fimc->pdev->dev); fimc->ref_count--; @@ -493,7 +498,7 @@ static int fimc_lite_close(struct file *file) if (--fimc->ref_count == 0 && fimc->out_path == FIMC_IO_DMA) { clear_bit(ST_FLITE_IN_USE, &fimc->state); fimc_lite_stop_capture(fimc, false); - fimc_pipeline_shutdown(&fimc->pipeline); + fimc_pipeline_call(fimc, shutdown, &fimc->pipeline); clear_bit(ST_FLITE_SUSPENDED, &fimc->state); } @@ -1505,7 +1510,8 @@ static int fimc_lite_resume(struct device *dev) return 0; INIT_LIST_HEAD(&fimc->active_buf_q); - fimc_pipeline_initialize(&fimc->pipeline, &fimc->vfd.entity, false); + fimc_pipeline_call(fimc, initialize, &fimc->pipeline, + &fimc->vfd.entity, false); fimc_lite_hw_init(fimc); clear_bit(ST_FLITE_SUSPENDED, &fimc->state); @@ -1531,7 +1537,7 @@ static int fimc_lite_suspend(struct device *dev) if (ret < 0 || !fimc_lite_active(fimc)) return ret; - return fimc_pipeline_shutdown(&fimc->pipeline); + return fimc_pipeline_call(fimc, shutdown, &fimc->pipeline); } #endif /* CONFIG_PM_SLEEP */ diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.h b/drivers/media/platform/s5p-fimc/fimc-lite.h index 9944dd3..b04bf3b 100644 --- a/drivers/media/platform/s5p-fimc/fimc-lite.h +++ b/drivers/media/platform/s5p-fimc/fimc-lite.h @@ -108,6 +108,7 @@ struct flite_buffer { * @test_pattern: test pattern controls * @index: FIMC-LITE platform device index * @pipeline: video capture pipeline data structure + * @pipeline_ops: media pipeline ops for the video node driver * @slock: spinlock protecting this data structure and the hw registers * @lock: mutex serializing video device and the subdev operations * @clock: FIMC-LITE gate clock @@ -142,6 +143,7 @@ struct fimc_lite { struct v4l2_ctrl *test_pattern; u32 index; struct fimc_pipeline pipeline; + const struct fimc_pipeline_ops *pipeline_ops; struct mutex lock; spinlock_t slock; diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index 3c76bd9..d97d190 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c @@ -23,6 +23,7 @@ #include <linux/slab.h> #include <media/v4l2-ctrls.h> #include <media/media-device.h> +#include <media/s5p_fimc.h> #include "fimc-core.h" #include "fimc-lite.h" @@ -38,7 +39,8 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd, * * Caller holds the graph mutex. */ -void fimc_pipeline_prepare(struct fimc_pipeline *p, struct media_entity *me) +static void fimc_pipeline_prepare(struct fimc_pipeline *p, + struct media_entity *me) { struct media_pad *pad = &me->pads[0]; struct v4l2_subdev *sd; @@ -114,7 +116,7 @@ static int __subdev_set_power(struct v4l2_subdev *sd, int on) * * Needs to be called with the graph mutex held. */ -int fimc_pipeline_s_power(struct fimc_pipeline *p, bool state) +static int fimc_pipeline_s_power(struct fimc_pipeline *p, bool state) { unsigned int i; int ret; @@ -159,8 +161,8 @@ static int __fimc_pipeline_initialize(struct fimc_pipeline *p, return fimc_pipeline_s_power(p, 1); } -int fimc_pipeline_initialize(struct fimc_pipeline *p, struct media_entity *me, - bool prep) +static int fimc_pipeline_initialize(struct fimc_pipeline *p, + struct media_entity *me, bool prep) { int ret; @@ -170,7 +172,6 @@ int fimc_pipeline_initialize(struct fimc_pipeline *p, struct media_entity *me, return ret; } -EXPORT_SYMBOL_GPL(fimc_pipeline_initialize); /** * __fimc_pipeline_shutdown - disable the sensor clock and pipeline power @@ -191,7 +192,7 @@ static int __fimc_pipeline_shutdown(struct fimc_pipeline *p) return ret == -ENXIO ? 0 : ret; } -int fimc_pipeline_shutdown(struct fimc_pipeline *p) +static int fimc_pipeline_shutdown(struct fimc_pipeline *p) { struct media_entity *me; int ret; @@ -206,7 +207,6 @@ int fimc_pipeline_shutdown(struct fimc_pipeline *p) return ret; } -EXPORT_SYMBOL_GPL(fimc_pipeline_shutdown); /** * fimc_pipeline_s_stream - invoke s_stream on pipeline subdevs @@ -232,7 +232,13 @@ int fimc_pipeline_s_stream(struct fimc_pipeline *p, bool on) return 0; } -EXPORT_SYMBOL_GPL(fimc_pipeline_s_stream); + +/* Media pipeline operations for the FIMC/FIMC-LITE video device driver */ +static const struct fimc_pipeline_ops fimc_pipeline_ops = { + .initialize = fimc_pipeline_initialize, + .shutdown = fimc_pipeline_shutdown, + .set_stream = fimc_pipeline_s_stream, +}; /* * Sensor subdevice helper functions @@ -347,6 +353,7 @@ static int fimc_register_callback(struct device *dev, void *p) if (fimc->pdev->id < 0 || fimc->pdev->id >= FIMC_MAX_DEVS) return 0; + fimc->pipeline_ops = &fimc_pipeline_ops; fmd->fimc[fimc->pdev->id] = fimc; sd->grp_id = FIMC_GROUP_ID; @@ -372,6 +379,7 @@ static int fimc_lite_register_callback(struct device *dev, void *p) if (fimc->index >= FIMC_LITE_MAX_DEVS) return 0; + fimc->pipeline_ops = &fimc_pipeline_ops; fmd->fimc_lite[fimc->index] = fimc; sd->grp_id = FLITE_GROUP_ID; @@ -473,12 +481,14 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd) if (fmd->fimc[i] == NULL) continue; v4l2_device_unregister_subdev(&fmd->fimc[i]->vid_cap.subdev); + fmd->fimc[i]->pipeline_ops = NULL; fmd->fimc[i] = NULL; } for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) { if (fmd->fimc_lite[i] == NULL) continue; v4l2_device_unregister_subdev(&fmd->fimc_lite[i]->subdev); + fmd->fimc[i]->pipeline_ops = NULL; fmd->fimc_lite[i] = NULL; } for (i = 0; i < CSIS_MAX_ENTITIES; i++) { diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.h b/drivers/media/platform/s5p-fimc/fimc-mdevice.h index d310d9c..0135386 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.h +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.h @@ -108,11 +108,5 @@ static inline void fimc_md_graph_unlock(struct fimc_dev *fimc) } int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on); -void fimc_pipeline_prepare(struct fimc_pipeline *p, struct media_entity *me); -int fimc_pipeline_initialize(struct fimc_pipeline *p, struct media_entity *me, - bool resume); -int fimc_pipeline_shutdown(struct fimc_pipeline *p); -int fimc_pipeline_s_power(struct fimc_pipeline *p, bool state); -int fimc_pipeline_s_stream(struct fimc_pipeline *p, bool state); #endif diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h index 8587aaf..6ea4017 100644 --- a/include/media/s5p_fimc.h +++ b/include/media/s5p_fimc.h @@ -12,6 +12,8 @@ #ifndef S5P_FIMC_H_ #define S5P_FIMC_H_ +#include <media/media-entity.h> + enum cam_bus_type { FIMC_ITU_601 = 1, FIMC_ITU_656, @@ -80,4 +82,20 @@ struct fimc_pipeline { struct media_pipeline *m_pipeline; }; +/* + * Media pipeline operations to be called from within the fimc(-lite) + * video node when it is the last entity of the pipeline. Implemented + * by a corresponding media device driver. + */ +struct fimc_pipeline_ops { + int (*initialize)(struct fimc_pipeline *p, struct media_entity *me, + bool resume); + int (*shutdown)(struct fimc_pipeline *p); + int (*set_stream)(struct fimc_pipeline *p, bool state); +}; + +#define fimc_pipeline_call(f, op, p, args...) \ + (!(f) ? -ENODEV : (((f)->pipeline_ops && (f)->pipeline_ops->op) ? \ + (f)->pipeline_ops->op((p), ##args) : -ENOIOCTLCMD)) + #endif /* S5P_FIMC_H_ */ -- 1.7.11.3 -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html