From: Satish Kumar Nagireddy Date: Sat, 5 May 2018 00:31:24 +0000 (-0700) Subject: xilinx: v4l2: dma: Add multiple output support X-Git-Tag: xlnx_rebase_v4.14_2018.2~26 X-Git-Url: https://rtime.felk.cvut.cz/gitweb/zynq/linux.git/commitdiff_plain/8581f566883a17a986806ce664fcb3fc701ae3dd xilinx: v4l2: dma: Add multiple output support 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 Reviewed-by: Hyun Kwon Signed-off-by: Michal Simek --- diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index a4860a70f827..2f173f11214b 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -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; diff --git a/drivers/media/platform/xilinx/xilinx-dma.h b/drivers/media/platform/xilinx/xilinx-dma.h index 33039f5ebaa9..a9c921f63d14 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.h +++ b/drivers/media/platform/xilinx/xilinx-dma.h @@ -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) diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c index cf8a9805f84c..6a1f424aa7c0 100644 --- a/drivers/media/platform/xilinx/xilinx-vipp.c +++ b/drivers/media/platform/xilinx/xilinx-vipp.c @@ -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; diff --git a/drivers/media/platform/xilinx/xilinx-vipp.h b/drivers/media/platform/xilinx/xilinx-vipp.h index faf6b6e80b3b..39a3538beef7 100644 --- a/drivers/media/platform/xilinx/xilinx-vipp.h +++ b/drivers/media/platform/xilinx/xilinx-vipp.h @@ -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__ */