[media] s5p-fimc: Rework the video pipeline control functions
authorSylwester Nawrocki <s.nawrocki@samsung.com>
Fri, 27 Apr 2012 12:33:10 +0000 (09:33 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Sun, 20 May 2012 12:22:47 +0000 (09:22 -0300)
There is getting more entities to manage within single video pipeline
in newer SoCs. To simplify code put subdevs' pointer into an array
rather than adding new member in struct fimc_pipeline for each subdev.
This allows to easier handle subdev operations in proper order.

Additionally walk graph in one direction only in fimc_pipeline_prepare()
function to make sure we properly gather only media entities that below
to single data pipeline. This avoids wrong initialization in case where,
for example there are multiple active links from s5p-mipi-csis subdev
output pad.

struct fimc_pipeline declaration is moved to the driver's public header
to allow other drivers to reuse the fimc-lite driver added in subsequent
patches.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/s5p-fimc/fimc-capture.c
drivers/media/video/s5p-fimc/fimc-core.h
drivers/media/video/s5p-fimc/fimc-mdevice.c
drivers/media/video/s5p-fimc/fimc-mdevice.h
include/media/s5p_fimc.h

index 52a5fb469b4509a166cfef38fdb2dc967aff8c71..7c884bb7104f5bc44241374f41ab2b2940c93494 100644 (file)
 static int fimc_init_capture(struct fimc_dev *fimc)
 {
        struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+       struct fimc_pipeline *p = &fimc->pipeline;
        struct fimc_sensor_info *sensor;
        unsigned long flags;
        int ret = 0;
 
-       if (fimc->pipeline.sensor == NULL || ctx == NULL)
+       if (p->subdevs[IDX_SENSOR] == NULL || ctx == NULL)
                return -ENXIO;
        if (ctx->s_frame.fmt == NULL)
                return -EINVAL;
 
-       sensor = v4l2_get_subdev_hostdata(fimc->pipeline.sensor);
+       sensor = v4l2_get_subdev_hostdata(p->subdevs[IDX_SENSOR]);
 
        spin_lock_irqsave(&fimc->slock, flags);
        fimc_prepare_dma_offset(ctx, &ctx->d_frame);
@@ -109,7 +110,7 @@ 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, 0);
+               return fimc_pipeline_s_stream(&fimc->pipeline, 0);
        else
                return 0;
 }
@@ -254,7 +255,7 @@ 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, 1);
+                       fimc_pipeline_s_stream(&fimc->pipeline, 1);
        }
 
        return 0;
@@ -281,7 +282,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);
+       return fimc_pipeline_shutdown(&fimc->pipeline);
 }
 
 static void buffer_queue(struct vb2_buffer *vb);
@@ -297,7 +298,7 @@ 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, &fimc->vid_cap.vfd->entity,
+       fimc_pipeline_initialize(&fimc->pipeline, &vid_cap->vfd->entity,
                                 false);
        fimc_init_capture(fimc);
 
@@ -414,7 +415,7 @@ 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, 1);
+                       fimc_pipeline_s_stream(&fimc->pipeline, 1);
                return;
        }
        spin_unlock_irqrestore(&fimc->slock, flags);
@@ -464,7 +465,7 @@ int fimc_capture_ctrls_create(struct fimc_dev *fimc)
                return ret;
 
        return v4l2_ctrl_add_handler(&vid_cap->ctx->ctrl_handler,
-                                   fimc->pipeline.sensor->ctrl_handler);
+                   fimc->pipeline.subdevs[IDX_SENSOR]->ctrl_handler);
 }
 
 static int fimc_capture_set_default_format(struct fimc_dev *fimc);
@@ -487,7 +488,7 @@ static int fimc_capture_open(struct file *file)
        pm_runtime_get_sync(&fimc->pdev->dev);
 
        if (++fimc->vid_cap.refcnt == 1) {
-               ret = fimc_pipeline_initialize(fimc,
+               ret = fimc_pipeline_initialize(&fimc->pipeline,
                               &fimc->vid_cap.vfd->entity, true);
                if (ret < 0) {
                        dev_err(&fimc->pdev->dev,
@@ -515,7 +516,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);
+               fimc_pipeline_shutdown(&fimc->pipeline);
                clear_bit(ST_CAPT_SUSPENDED, &fimc->state);
        }
 
@@ -736,8 +737,8 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
                                    bool set)
 {
        struct fimc_dev *fimc = ctx->fimc_dev;
-       struct v4l2_subdev *sd = fimc->pipeline.sensor;
-       struct v4l2_subdev *csis = fimc->pipeline.csis;
+       struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
+       struct v4l2_subdev *csis = fimc->pipeline.subdevs[IDX_CSIS];
        struct v4l2_subdev_format sfmt;
        struct v4l2_mbus_framefmt *mf = &sfmt.format;
        struct fimc_fmt *ffmt = NULL;
@@ -945,7 +946,7 @@ static int fimc_cap_enum_input(struct file *file, void *priv,
                               struct v4l2_input *i)
 {
        struct fimc_dev *fimc = video_drvdata(file);
-       struct v4l2_subdev *sd = fimc->pipeline.sensor;
+       struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
 
        if (i->index != 0)
                return -EINVAL;
@@ -1037,7 +1038,8 @@ static int fimc_cap_streamon(struct file *file, void *priv,
        if (fimc_capture_active(fimc))
                return -EBUSY;
 
-       media_entity_pipeline_start(&p->sensor->entity, p->pipe);
+       media_entity_pipeline_start(&p->subdevs[IDX_SENSOR]->entity,
+                                   p->m_pipeline);
 
        if (fimc->vid_cap.user_subdev_api) {
                ret = fimc_pipeline_validate(fimc);
@@ -1051,7 +1053,7 @@ static int fimc_cap_streamoff(struct file *file, void *priv,
                            enum v4l2_buf_type type)
 {
        struct fimc_dev *fimc = video_drvdata(file);
-       struct v4l2_subdev *sd = fimc->pipeline.sensor;
+       struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
        int ret;
 
        ret = vb2_streamoff(&fimc->vid_cap.vbq, type);
index 34fbba4246927b69be7706d00d46a318fd3f3861..8b073979cee8d0b316b7969f052efb12acd49657 100644 (file)
@@ -400,11 +400,6 @@ struct samsung_fimc_driverdata {
        int             num_entities;
 };
 
-struct fimc_pipeline {
-       struct media_pipeline *pipe;
-       struct v4l2_subdev *sensor;
-       struct v4l2_subdev *csis;
-};
 
 struct fimc_ctx;
 
index c319842c762d48754aff8bfc32c549fb07d8f076..212474130dfb1a93ec50a095407a8a5725f61045 100644 (file)
@@ -25,6 +25,7 @@
 #include <media/media-device.h>
 
 #include "fimc-core.h"
+#include "fimc-lite.h"
 #include "fimc-mdevice.h"
 #include "mipi-csis.h"
 
@@ -37,22 +38,43 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd,
  *
  * Caller holds the graph mutex.
  */
-void fimc_pipeline_prepare(struct fimc_dev *fimc, struct media_entity *me)
+void fimc_pipeline_prepare(struct fimc_pipeline *p, struct media_entity *me)
 {
-       struct media_entity_graph graph;
+       struct media_pad *pad = &me->pads[0];
        struct v4l2_subdev *sd;
+       int i;
 
-       media_entity_graph_walk_start(&graph, me);
+       for (i = 0; i < IDX_MAX; i++)
+               p->subdevs[i] = NULL;
 
-       while ((me = media_entity_graph_walk_next(&graph))) {
-               if (media_entity_type(me) != MEDIA_ENT_T_V4L2_SUBDEV)
-                       continue;
-               sd = media_entity_to_v4l2_subdev(me);
+       while (1) {
+               if (!(pad->flags & MEDIA_PAD_FL_SINK))
+                       break;
+
+               /* source pad */
+               pad = media_entity_remote_source(pad);
+               if (pad == NULL ||
+                   media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+                       break;
 
-               if (sd->grp_id == SENSOR_GROUP_ID)
-                       fimc->pipeline.sensor = sd;
-               else if (sd->grp_id == CSIS_GROUP_ID)
-                       fimc->pipeline.csis = sd;
+               sd = media_entity_to_v4l2_subdev(pad->entity);
+
+               switch (sd->grp_id) {
+               case SENSOR_GROUP_ID:
+                       p->subdevs[IDX_SENSOR] = sd;
+                       break;
+               case CSIS_GROUP_ID:
+                       p->subdevs[IDX_CSIS] = sd;
+                       break;
+               case FIMC_GROUP_ID:
+                       /* No need to control FIMC subdev through subdev ops */
+                       break;
+               default:
+                       pr_warn("%s: Unknown subdev grp_id: %#x\n",
+                               __func__, sd->grp_id);
+               }
+               /* sink pad */
+               pad = &sd->entity.pads[0];
        }
 }
 
@@ -85,30 +107,27 @@ static int __subdev_set_power(struct v4l2_subdev *sd, int on)
 /**
  * fimc_pipeline_s_power - change power state of all pipeline subdevs
  * @fimc: fimc device terminating the pipeline
- * @state: 1 to enable power or 0 for power down
+ * @state: true to power on, false to power off
  *
- * Need to be called with the graph mutex held.
+ * Needs to be called with the graph mutex held.
  */
-int fimc_pipeline_s_power(struct fimc_dev *fimc, int state)
+int fimc_pipeline_s_power(struct fimc_pipeline *p, bool state)
 {
-       int ret = 0;
+       unsigned int i;
+       int ret;
 
-       if (fimc->pipeline.sensor == NULL)
+       if (p->subdevs[IDX_SENSOR] == NULL)
                return -ENXIO;
 
-       if (state) {
-               ret = __subdev_set_power(fimc->pipeline.csis, 1);
-               if (ret && ret != -ENXIO)
+       for (i = 0; i < IDX_MAX; i++) {
+               unsigned int idx = state ? (IDX_MAX - 1) - i : i;
+
+               ret = __subdev_set_power(p->subdevs[idx], state);
+               if (ret < 0 && ret != -ENXIO)
                        return ret;
-               return __subdev_set_power(fimc->pipeline.sensor, 1);
        }
 
-       ret = __subdev_set_power(fimc->pipeline.sensor, 0);
-       if (ret)
-               return ret;
-       ret = __subdev_set_power(fimc->pipeline.csis, 0);
-
-       return ret == -ENXIO ? 0 : ret;
+       return 0;
 }
 
 /**
@@ -119,32 +138,36 @@ int fimc_pipeline_s_power(struct fimc_dev *fimc, int state)
  *
  * This function must be called with the graph mutex held.
  */
-static int __fimc_pipeline_initialize(struct fimc_dev *fimc,
+static int __fimc_pipeline_initialize(struct fimc_pipeline *p,
                                      struct media_entity *me, bool prep)
 {
        int ret;
 
        if (prep)
-               fimc_pipeline_prepare(fimc, me);
-       if (fimc->pipeline.sensor == NULL)
+               fimc_pipeline_prepare(p, me);
+
+       if (p->subdevs[IDX_SENSOR] == NULL)
                return -EINVAL;
-       ret = fimc_md_set_camclk(fimc->pipeline.sensor, true);
+
+       ret = fimc_md_set_camclk(p->subdevs[IDX_SENSOR], true);
        if (ret)
                return ret;
-       return fimc_pipeline_s_power(fimc, 1);
+
+       return fimc_pipeline_s_power(p, 1);
 }
 
-int fimc_pipeline_initialize(struct fimc_dev *fimc, struct media_entity *me,
+int fimc_pipeline_initialize(struct fimc_pipeline *p, struct media_entity *me,
                             bool prep)
 {
        int ret;
 
        mutex_lock(&me->parent->graph_mutex);
-       ret =  __fimc_pipeline_initialize(fimc, me, prep);
+       ret =  __fimc_pipeline_initialize(p, me, prep);
        mutex_unlock(&me->parent->graph_mutex);
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(fimc_pipeline_initialize);
 
 /**
  * __fimc_pipeline_shutdown - disable the sensor clock and pipeline power
@@ -154,52 +177,55 @@ int fimc_pipeline_initialize(struct fimc_dev *fimc, struct media_entity *me,
  * sensor clock.
  * Called with the graph mutex held.
  */
-int __fimc_pipeline_shutdown(struct fimc_dev *fimc)
+int __fimc_pipeline_shutdown(struct fimc_pipeline *p)
 {
        int ret = 0;
 
-       if (fimc->pipeline.sensor) {
-               ret = fimc_pipeline_s_power(fimc, 0);
-               fimc_md_set_camclk(fimc->pipeline.sensor, false);
+       if (p->subdevs[IDX_SENSOR]) {
+               ret = fimc_pipeline_s_power(p, 0);
+               fimc_md_set_camclk(p->subdevs[IDX_SENSOR], false);
        }
        return ret == -ENXIO ? 0 : ret;
 }
 
-int fimc_pipeline_shutdown(struct fimc_dev *fimc)
+int fimc_pipeline_shutdown(struct fimc_pipeline *p)
 {
-       struct media_entity *me = &fimc->vid_cap.vfd->entity;
+       struct media_entity *me = &p->subdevs[IDX_SENSOR]->entity;
        int ret;
 
        mutex_lock(&me->parent->graph_mutex);
-       ret = __fimc_pipeline_shutdown(fimc);
+       ret = __fimc_pipeline_shutdown(p);
        mutex_unlock(&me->parent->graph_mutex);
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(fimc_pipeline_shutdown);
 
 /**
  * fimc_pipeline_s_stream - invoke s_stream on pipeline subdevs
- * @fimc: fimc device terminating the pipeline
+ * @pipeline: video pipeline structure
  * @on: passed as the s_stream call argument
  */
-int fimc_pipeline_s_stream(struct fimc_dev *fimc, int on)
+int fimc_pipeline_s_stream(struct fimc_pipeline *p, bool on)
 {
-       struct fimc_pipeline *p = &fimc->pipeline;
-       int ret = 0;
+       int i, ret;
 
-       if (p->sensor == NULL)
+       if (p->subdevs[IDX_SENSOR] == NULL)
                return -ENODEV;
 
-       if ((on && p->csis) || !on)
-               ret = v4l2_subdev_call(on ? p->csis : p->sensor,
-                                      video, s_stream, on);
-       if (ret < 0 && ret != -ENOIOCTLCMD)
-               return ret;
-       if ((!on && p->csis) || on)
-               ret = v4l2_subdev_call(on ? p->sensor : p->csis,
-                                      video, s_stream, on);
-       return ret == -ENOIOCTLCMD ? 0 : ret;
+       for (i = 0; i < IDX_MAX; i++) {
+               unsigned int idx = on ? (IDX_MAX - 1) - i : i;
+
+               ret = v4l2_subdev_call(p->subdevs[idx], video, s_stream, on);
+
+               if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
+                       return ret;
+       }
+
+       return 0;
+
 }
+EXPORT_SYMBOL_GPL(fimc_pipeline_s_stream);
 
 /*
  * Sensor subdevice helper functions
@@ -677,6 +703,7 @@ int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on)
 static int fimc_md_link_notify(struct media_pad *source,
                               struct media_pad *sink, u32 flags)
 {
+       struct fimc_pipeline *pipeline;
        struct v4l2_subdev *sd;
        struct fimc_dev *fimc;
        int ret = 0;
@@ -685,16 +712,26 @@ static int fimc_md_link_notify(struct media_pad *source,
                return 0;
 
        sd = media_entity_to_v4l2_subdev(sink->entity);
-       fimc = v4l2_get_subdevdata(sd);
 
-       if (!(flags & MEDIA_LNK_FL_ENABLED)) {
-               ret = __fimc_pipeline_shutdown(fimc);
-               fimc->pipeline.sensor = NULL;
-               fimc->pipeline.csis = NULL;
+       switch (sd->grp_id) {
+       case FIMC_GROUP_ID:
+               fimc = v4l2_get_subdevdata(sd);
+               pipeline = &fimc->pipeline;
+               break;
+       default:
+               return 0;
+       }
 
-               mutex_lock(&fimc->lock);
-               fimc_ctrls_delete(fimc->vid_cap.ctx);
-               mutex_unlock(&fimc->lock);
+       if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+               ret = __fimc_pipeline_shutdown(pipeline);
+               pipeline->subdevs[IDX_SENSOR] = NULL;
+               pipeline->subdevs[IDX_CSIS] = NULL;
+
+               if (fimc) {
+                       mutex_lock(&fimc->lock);
+                       fimc_ctrls_delete(fimc->vid_cap.ctx);
+                       mutex_unlock(&fimc->lock);
+               }
                return ret;
        }
        /*
@@ -704,7 +741,8 @@ static int fimc_md_link_notify(struct media_pad *source,
         */
        mutex_lock(&fimc->lock);
        if (fimc->vid_cap.refcnt > 0) {
-               ret = __fimc_pipeline_initialize(fimc, source->entity, true);
+                       ret = __fimc_pipeline_initialize(pipeline,
+                                                        source->entity, true);
                if (!ret)
                        ret = fimc_capture_ctrls_create(fimc);
        }
index 4f3b69c682cbf2d8511a09bbd53436eecb4cbfda..c5ac3e64b0d9d77d019f4fa4a4ee25ed4d076865 100644 (file)
@@ -109,11 +109,11 @@ 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_dev *fimc, struct media_entity *me);
-int fimc_pipeline_initialize(struct fimc_dev *fimc, struct media_entity *me,
+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_dev *fimc);
-int fimc_pipeline_s_power(struct fimc_dev *fimc, int state);
-int fimc_pipeline_s_stream(struct fimc_dev *fimc, int state);
+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
index 688fb3f1dc3566913965cd2281d344f40e9c8e59..8587aaf7364678cbb5a816cd194b568699717b4e 100644 (file)
@@ -64,4 +64,20 @@ struct s5p_platform_fimc {
  */
 #define S5P_FIMC_TX_END_NOTIFY _IO('e', 0)
 
+enum fimc_subdev_index {
+       IDX_SENSOR,
+       IDX_CSIS,
+       IDX_FLITE,
+       IDX_FIMC,
+       IDX_MAX,
+};
+
+struct media_pipeline;
+struct v4l2_subdev;
+
+struct fimc_pipeline {
+       struct v4l2_subdev *subdevs[IDX_MAX];
+       struct media_pipeline *m_pipeline;
+};
+
 #endif /* S5P_FIMC_H_ */