]> rtime.felk.cvut.cz Git - zynq/linux.git/commitdiff
xilinx: v4l2: dma: Add multiple output support
authorSatish Kumar Nagireddy <satish.nagireddy.nagireddy@xilinx.com>
Sat, 5 May 2018 00:31:24 +0000 (17:31 -0700)
committerMichal Simek <michal.simek@xilinx.com>
Wed, 9 May 2018 08:48:25 +0000 (10:48 +0200)
The current implementation supports single direction
which can be input or output.

The requirement is to support multiple output DMAs, for example

Source -> split -> scaler -> dma0
               |-> scaler -> dma1

This patch walks through the graph starting from each of dma and
enable/disable subdevs only once in case if they are shared between
subgraphs.

Signed-off-by: Satish Kumar Nagireddy <satish.nagireddy.nagireddy@xilinx.com>
Reviewed-by: Hyun Kwon <hyun.kwon@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
drivers/media/platform/xilinx/xilinx-dma.c
drivers/media/platform/xilinx/xilinx-dma.h
drivers/media/platform/xilinx/xilinx-vipp.c
drivers/media/platform/xilinx/xilinx-vipp.h

index a4860a70f8275dff63152e257e78d85abc6a2f1f..2f173f11214b9e9b22ab6257109f6168e479a99b 100644 (file)
@@ -127,21 +127,22 @@ static struct media_pad *xvip_get_entity_sink(struct media_entity *entity,
 
 /**
  * xvip_pipeline_start_stop - Start ot stop streaming on a pipeline
- * @pipe: The pipeline
+ * @xdev: Composite video device
+ * @dma: xvip dma
  * @start: Start (when true) or stop (when false) the pipeline
  *
- * Walk the entities chain starting at the pipeline output video node and start
- * or stop all of them.
+ * Walk the entities chain starting @dma and start or stop all of them
  *
  * Return: 0 if successful, or the return value of the failed video::s_stream
  * operation otherwise.
  */
-static int xvip_pipeline_start_stop(struct xvip_pipeline *pipe, bool start)
+static int xvip_pipeline_start_stop(struct xvip_composite_device *xdev,
+                                   struct xvip_dma *dma, bool start)
 {
-       struct xvip_dma *dma = pipe->output;
        struct media_entity *entity;
        struct media_pad *pad;
        struct v4l2_subdev *subdev;
+       bool is_streaming;
        int ret;
 
        entity = &dma->video.entity;
@@ -162,9 +163,21 @@ static int xvip_pipeline_start_stop(struct xvip_pipeline *pipe, bool start)
                entity = pad->entity;
                subdev = media_entity_to_v4l2_subdev(entity);
 
-               ret = v4l2_subdev_call(subdev, video, s_stream, start);
-               if (start && ret < 0 && ret != -ENOIOCTLCMD)
-                       return ret;
+               is_streaming = xvip_subdev_set_streaming(xdev, subdev, start);
+
+               /*
+                * start or stop the subdev only once in case if they are
+                * shared between sub-graphs
+                */
+               if (start != is_streaming) {
+                       ret = v4l2_subdev_call(subdev, video, s_stream,
+                                              start);
+                       if (start && ret < 0 && ret != -ENOIOCTLCMD) {
+                               dev_err(xdev->dev, "s_stream is failed on subdev\n");
+                               xvip_subdev_set_streaming(xdev, subdev, !start);
+                               return ret;
+                       }
+               }
        }
 
        return 0;
@@ -180,7 +193,8 @@ static int xvip_pipeline_start_stop(struct xvip_pipeline *pipe, bool start)
  * independently, pipelines have a shared stream state that enable or disable
  * all entities in the pipeline. For this reason the pipeline uses a streaming
  * counter that tracks the number of DMA engines that have requested the stream
- * to be enabled.
+ * to be enabled. This will walk the graph starting from each DMA and enable or
+ * disable the entities in the path.
  *
  * When called with the @on argument set to true, this function will increment
  * the pipeline streaming count. If the streaming count reaches the number of
@@ -197,20 +211,31 @@ static int xvip_pipeline_start_stop(struct xvip_pipeline *pipe, bool start)
  */
 static int xvip_pipeline_set_stream(struct xvip_pipeline *pipe, bool on)
 {
+       struct xvip_composite_device *xdev;
+       struct xvip_dma *dma;
        int ret = 0;
 
        mutex_lock(&pipe->lock);
+       xdev = pipe->xdev;
 
        if (on) {
                if (pipe->stream_count == pipe->num_dmas - 1) {
-                       ret = xvip_pipeline_start_stop(pipe, true);
-                       if (ret < 0)
-                               goto done;
+                       /*
+                        * This will iterate the DMAs and the stream-on of
+                        * subdevs may not be sequential due to multiple
+                        * sub-graph path
+                        */
+                       list_for_each_entry(dma, &xdev->dmas, list) {
+                               ret = xvip_pipeline_start_stop(xdev, dma, true);
+                               if (ret < 0)
+                                       goto done;
+                       }
                }
                pipe->stream_count++;
        } else {
                if (--pipe->stream_count == 0)
-                       xvip_pipeline_start_stop(pipe, false);
+                       list_for_each_entry(dma, &xdev->dmas, list)
+                               xvip_pipeline_start_stop(xdev, dma, false);
        }
 
 done:
@@ -248,7 +273,6 @@ static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
                dma = to_xvip_dma(media_entity_to_video_device(entity));
 
                if (dma->pad.flags & MEDIA_PAD_FL_SINK) {
-                       pipe->output = dma;
                        num_outputs++;
                } else {
                        num_inputs++;
@@ -259,11 +283,12 @@ static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
 
        media_graph_walk_cleanup(&graph);
 
-       /* We need exactly one output and zero or one input. */
-       if (num_outputs != 1 || num_inputs > 1)
+       /* We need at least one DMA to proceed */
+       if (num_outputs == 0 && num_inputs == 0)
                return -EPIPE;
 
        pipe->num_dmas = num_inputs + num_outputs;
+       pipe->xdev = start->xdev;
 
        return 0;
 }
@@ -271,7 +296,6 @@ static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
 static void __xvip_pipeline_cleanup(struct xvip_pipeline *pipe)
 {
        pipe->num_dmas = 0;
-       pipe->output = NULL;
 }
 
 /**
@@ -608,7 +632,9 @@ static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count)
        dma_async_issue_pending(dma->dma);
 
        /* Start the pipeline. */
-       xvip_pipeline_set_stream(pipe, true);
+       ret = xvip_pipeline_set_stream(pipe, true);
+       if (ret < 0)
+               goto error_stop;
 
        return 0;
 
index 33039f5ebaa9e847b0f8e1d277695f6777c1547c..a9c921f63d14083075d7078c1e295ece1b7dcbb8 100644 (file)
@@ -35,7 +35,7 @@ struct xvip_video_format;
  * @use_count: number of DMA engines using the pipeline
  * @stream_count: number of DMA engines currently streaming
  * @num_dmas: number of DMA engines in the pipeline
- * @output: DMA engine at the output of the pipeline
+ * @xdev: Composite device the pipe belongs to
  */
 struct xvip_pipeline {
        struct media_pipeline pipe;
@@ -45,7 +45,7 @@ struct xvip_pipeline {
        unsigned int stream_count;
 
        unsigned int num_dmas;
-       struct xvip_dma *output;
+       struct xvip_composite_device *xdev;
 };
 
 static inline struct xvip_pipeline *to_xvip_pipeline(struct media_entity *e)
index cf8a9805f84cc7ae47a417c7259f882f8ae97091..6a1f424aa7c00bfa0e97a90ba8658b49c0c81519 100644 (file)
@@ -46,6 +46,7 @@ module_param_named(is_mplane, xvip_is_mplane, bool, 0444);
  * @entity: media entity, from the corresponding V4L2 subdev
  * @asd: subdev asynchronous registration information
  * @subdev: V4L2 subdev
+ * @streaming: status of the V4L2 subdev if streaming or not
  */
 struct xvip_graph_entity {
        struct list_head list;
@@ -54,6 +55,7 @@ struct xvip_graph_entity {
 
        struct v4l2_async_subdev asd;
        struct v4l2_subdev *subdev;
+       bool streaming;
 };
 
 /* -----------------------------------------------------------------------------
@@ -198,6 +200,35 @@ xvip_graph_find_dma(struct xvip_composite_device *xdev, unsigned int port)
        return NULL;
 }
 
+/**
+ * xvip_subdev_set_streaming - Find and update streaming status of subdev
+ * @xdev: Composite video device
+ * @subdev: V4L2 sub-device
+ * @enable: enable/disable streaming status
+ *
+ * Walk the xvip graph entities list and find if subdev is present. Returns
+ * streaming status of subdev and update the status as requested
+ *
+ * Return: streaming status (true or false) if successful or warn_on if subdev
+ * is not present and return false
+ */
+bool xvip_subdev_set_streaming(struct xvip_composite_device *xdev,
+                              struct v4l2_subdev *subdev, bool enable)
+{
+       struct xvip_graph_entity *entity;
+
+       list_for_each_entry(entity, &xdev->entities, list)
+               if (entity->node == subdev->dev->of_node) {
+                       bool status = entity->streaming;
+
+                       entity->streaming = enable;
+                       return status;
+               }
+
+       WARN(1, "Should never get here\n");
+       return false;
+}
+
 static int xvip_graph_build_dma(struct xvip_composite_device *xdev)
 {
        u32 link_flags = MEDIA_LNK_FL_ENABLED;
index faf6b6e80b3ba9c6ede82cb7d6d4040f6cd8ecb4..39a3538beef75983ee40faa0516c42c3e9a247c8 100644 (file)
@@ -46,4 +46,7 @@ struct xvip_composite_device {
        u32 v4l2_caps;
 };
 
+bool xvip_subdev_set_streaming(struct xvip_composite_device *xdev,
+                              struct v4l2_subdev *subdev, bool enable);
+
 #endif /* __XILINX_VIPP_H__ */