| From d501b911bf10e28e5227dda7eb071f0799465eb7 Mon Sep 17 00:00:00 2001 |
| From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> |
| Date: Wed, 7 Sep 2016 09:09:53 -0300 |
| Subject: [PATCH 209/286] [media] v4l: vsp1: Support histogram generators in |
| pipeline configuration |
| |
| Histogram generators are single-pad entities that branch as leaf nodes |
| at any point in the pipeline. Make sure that pipeline traversal and |
| routing configuration support them correctly. |
| |
| Support for the actual HGO and HGT operation will come later. |
| |
| Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> |
| Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com> |
| (cherry picked from commit c8663c8e15c95a351296d9d284b0cad5d373234c) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| --- |
| drivers/media/platform/vsp1/vsp1_drm.c | 2 |
| drivers/media/platform/vsp1/vsp1_drv.c | 4 |
| drivers/media/platform/vsp1/vsp1_entity.c | 124 ++++++++++++++++++++++++++---- |
| drivers/media/platform/vsp1/vsp1_entity.h | 8 + |
| drivers/media/platform/vsp1/vsp1_pipe.c | 6 - |
| drivers/media/platform/vsp1/vsp1_video.c | 18 ++-- |
| 6 files changed, 134 insertions(+), 28 deletions(-) |
| |
| --- a/drivers/media/platform/vsp1/vsp1_drm.c |
| +++ b/drivers/media/platform/vsp1/vsp1_drm.c |
| @@ -496,7 +496,7 @@ void vsp1_du_atomic_flush(struct device |
| } |
| } |
| |
| - vsp1_entity_route_setup(entity, dl); |
| + vsp1_entity_route_setup(entity, pipe, dl); |
| |
| if (entity->ops->configure) { |
| entity->ops->configure(entity, pipe, dl, |
| --- a/drivers/media/platform/vsp1/vsp1_drv.c |
| +++ b/drivers/media/platform/vsp1/vsp1_drv.c |
| @@ -105,7 +105,9 @@ static int vsp1_create_sink_links(struct |
| if (source->type == sink->type) |
| continue; |
| |
| - if (source->type == VSP1_ENTITY_LIF || |
| + if (source->type == VSP1_ENTITY_HGO || |
| + source->type == VSP1_ENTITY_HGT || |
| + source->type == VSP1_ENTITY_LIF || |
| source->type == VSP1_ENTITY_WPF) |
| continue; |
| |
| --- a/drivers/media/platform/vsp1/vsp1_entity.c |
| +++ b/drivers/media/platform/vsp1/vsp1_entity.c |
| @@ -21,6 +21,8 @@ |
| #include "vsp1.h" |
| #include "vsp1_dl.h" |
| #include "vsp1_entity.h" |
| +#include "vsp1_pipe.h" |
| +#include "vsp1_rwpf.h" |
| |
| static inline struct vsp1_entity * |
| media_entity_to_vsp1_entity(struct media_entity *entity) |
| @@ -28,11 +30,14 @@ media_entity_to_vsp1_entity(struct media |
| return container_of(entity, struct vsp1_entity, subdev.entity); |
| } |
| |
| -void vsp1_entity_route_setup(struct vsp1_entity *source, |
| +void vsp1_entity_route_setup(struct vsp1_entity *entity, |
| + struct vsp1_pipeline *pipe, |
| struct vsp1_dl_list *dl) |
| { |
| + struct vsp1_entity *source; |
| struct vsp1_entity *sink; |
| |
| + source = entity; |
| if (source->route->reg == 0) |
| return; |
| |
| @@ -283,25 +288,32 @@ done: |
| * Media Operations |
| */ |
| |
| -int vsp1_entity_link_setup(struct media_entity *entity, |
| - const struct media_pad *local, |
| - const struct media_pad *remote, u32 flags) |
| +static int vsp1_entity_link_setup_source(const struct media_pad *source_pad, |
| + const struct media_pad *sink_pad, |
| + u32 flags) |
| { |
| struct vsp1_entity *source; |
| |
| - if (!(local->flags & MEDIA_PAD_FL_SOURCE)) |
| - return 0; |
| - |
| - source = media_entity_to_vsp1_entity(local->entity); |
| + source = media_entity_to_vsp1_entity(source_pad->entity); |
| |
| if (!source->route) |
| return 0; |
| |
| if (flags & MEDIA_LNK_FL_ENABLED) { |
| - if (source->sink) |
| - return -EBUSY; |
| - source->sink = remote->entity; |
| - source->sink_pad = remote->index; |
| + struct vsp1_entity *sink |
| + = media_entity_to_vsp1_entity(sink_pad->entity); |
| + |
| + /* |
| + * Fan-out is limited to one for the normal data path plus |
| + * optional HGO and HGT. We ignore the HGO and HGT here. |
| + */ |
| + if (sink->type != VSP1_ENTITY_HGO && |
| + sink->type != VSP1_ENTITY_HGT) { |
| + if (source->sink) |
| + return -EBUSY; |
| + source->sink = sink_pad->entity; |
| + source->sink_pad = sink_pad->index; |
| + } |
| } else { |
| source->sink = NULL; |
| source->sink_pad = 0; |
| @@ -310,6 +322,85 @@ int vsp1_entity_link_setup(struct media_ |
| return 0; |
| } |
| |
| +static int vsp1_entity_link_setup_sink(const struct media_pad *source_pad, |
| + const struct media_pad *sink_pad, |
| + u32 flags) |
| +{ |
| + struct vsp1_entity *sink; |
| + |
| + sink = media_entity_to_vsp1_entity(sink_pad->entity); |
| + |
| + if (flags & MEDIA_LNK_FL_ENABLED) { |
| + /* Fan-in is limited to one. */ |
| + if (sink->sources[sink_pad->index]) |
| + return -EBUSY; |
| + |
| + sink->sources[sink_pad->index] = source_pad->entity; |
| + } else { |
| + sink->sources[sink_pad->index] = NULL; |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +int vsp1_entity_link_setup(struct media_entity *entity, |
| + const struct media_pad *local, |
| + const struct media_pad *remote, u32 flags) |
| +{ |
| + if (local->flags & MEDIA_PAD_FL_SOURCE) |
| + return vsp1_entity_link_setup_source(local, remote, flags); |
| + else |
| + return vsp1_entity_link_setup_sink(remote, local, flags); |
| +} |
| + |
| +/** |
| + * vsp1_entity_remote_pad - Find the pad at the remote end of a link |
| + * @pad: Pad at the local end of the link |
| + * |
| + * Search for a remote pad connected to the given pad by iterating over all |
| + * links originating or terminating at that pad until an enabled link is found. |
| + * |
| + * Our link setup implementation guarantees that the output fan-out will not be |
| + * higher than one for the data pipelines, except for the links to the HGO and |
| + * HGT that can be enabled in addition to a regular data link. When traversing |
| + * outgoing links this function ignores HGO and HGT entities and should thus be |
| + * used in place of the generic media_entity_remote_pad() function to traverse |
| + * data pipelines. |
| + * |
| + * Return a pointer to the pad at the remote end of the first found enabled |
| + * link, or NULL if no enabled link has been found. |
| + */ |
| +struct media_pad *vsp1_entity_remote_pad(struct media_pad *pad) |
| +{ |
| + struct media_link *link; |
| + |
| + list_for_each_entry(link, &pad->entity->links, list) { |
| + struct vsp1_entity *entity; |
| + |
| + if (!(link->flags & MEDIA_LNK_FL_ENABLED)) |
| + continue; |
| + |
| + /* If we're the sink the source will never be an HGO or HGT. */ |
| + if (link->sink == pad) |
| + return link->source; |
| + |
| + if (link->source != pad) |
| + continue; |
| + |
| + /* If the sink isn't a subdevice it can't be an HGO or HGT. */ |
| + if (!is_media_entity_v4l2_subdev(link->sink->entity)) |
| + return link->sink; |
| + |
| + entity = media_entity_to_vsp1_entity(link->sink->entity); |
| + if (entity->type != VSP1_ENTITY_HGO && |
| + entity->type != VSP1_ENTITY_HGT) |
| + return link->sink; |
| + } |
| + |
| + return NULL; |
| + |
| +} |
| + |
| /* ----------------------------------------------------------------------------- |
| * Initialization |
| */ |
| @@ -388,7 +479,14 @@ int vsp1_entity_init(struct vsp1_device |
| for (i = 0; i < num_pads - 1; ++i) |
| entity->pads[i].flags = MEDIA_PAD_FL_SINK; |
| |
| - entity->pads[num_pads - 1].flags = MEDIA_PAD_FL_SOURCE; |
| + entity->sources = devm_kcalloc(vsp1->dev, max(num_pads - 1, 1U), |
| + sizeof(*entity->sources), GFP_KERNEL); |
| + if (entity->sources == NULL) |
| + return -ENOMEM; |
| + |
| + /* Single-pad entities only have a sink. */ |
| + entity->pads[num_pads - 1].flags = num_pads > 1 ? MEDIA_PAD_FL_SOURCE |
| + : MEDIA_PAD_FL_SINK; |
| |
| /* Initialize the media entity. */ |
| ret = media_entity_pads_init(&entity->subdev.entity, num_pads, |
| --- a/drivers/media/platform/vsp1/vsp1_entity.h |
| +++ b/drivers/media/platform/vsp1/vsp1_entity.h |
| @@ -25,6 +25,8 @@ struct vsp1_pipeline; |
| enum vsp1_entity_type { |
| VSP1_ENTITY_BRU, |
| VSP1_ENTITY_CLU, |
| + VSP1_ENTITY_HGO, |
| + VSP1_ENTITY_HGT, |
| VSP1_ENTITY_HSI, |
| VSP1_ENTITY_HST, |
| VSP1_ENTITY_LIF, |
| @@ -102,6 +104,7 @@ struct vsp1_entity { |
| struct media_pad *pads; |
| unsigned int source_pad; |
| |
| + struct media_entity **sources; |
| struct media_entity *sink; |
| unsigned int sink_pad; |
| |
| @@ -142,9 +145,12 @@ vsp1_entity_get_pad_selection(struct vsp |
| int vsp1_entity_init_cfg(struct v4l2_subdev *subdev, |
| struct v4l2_subdev_pad_config *cfg); |
| |
| -void vsp1_entity_route_setup(struct vsp1_entity *source, |
| +void vsp1_entity_route_setup(struct vsp1_entity *entity, |
| + struct vsp1_pipeline *pipe, |
| struct vsp1_dl_list *dl); |
| |
| +struct media_pad *vsp1_entity_remote_pad(struct media_pad *pad); |
| + |
| int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev, |
| struct v4l2_subdev_pad_config *cfg, |
| struct v4l2_subdev_format *fmt); |
| --- a/drivers/media/platform/vsp1/vsp1_pipe.c |
| +++ b/drivers/media/platform/vsp1/vsp1_pipe.c |
| @@ -252,6 +252,7 @@ bool vsp1_pipeline_stopped(struct vsp1_p |
| |
| int vsp1_pipeline_stop(struct vsp1_pipeline *pipe) |
| { |
| + struct vsp1_device *vsp1 = pipe->output->entity.vsp1; |
| struct vsp1_entity *entity; |
| unsigned long flags; |
| int ret; |
| @@ -261,8 +262,7 @@ int vsp1_pipeline_stop(struct vsp1_pipel |
| * When using display lists in continuous frame mode the only |
| * way to stop the pipeline is to reset the hardware. |
| */ |
| - ret = vsp1_reset_wpf(pipe->output->entity.vsp1, |
| - pipe->output->entity.index); |
| + ret = vsp1_reset_wpf(vsp1, pipe->output->entity.index); |
| if (ret == 0) { |
| spin_lock_irqsave(&pipe->irqlock, flags); |
| pipe->state = VSP1_PIPELINE_STOPPED; |
| @@ -282,7 +282,7 @@ int vsp1_pipeline_stop(struct vsp1_pipel |
| |
| list_for_each_entry(entity, &pipe->entities, list_pipe) { |
| if (entity->route && entity->route->reg) |
| - vsp1_write(entity->vsp1, entity->route->reg, |
| + vsp1_write(vsp1, entity->route->reg, |
| VI6_DPR_NODE_UNUSED); |
| } |
| |
| --- a/drivers/media/platform/vsp1/vsp1_video.c |
| +++ b/drivers/media/platform/vsp1/vsp1_video.c |
| @@ -486,7 +486,12 @@ static int vsp1_video_pipeline_build_bra |
| if (ret < 0) |
| return ret; |
| |
| - pad = media_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]); |
| + /* |
| + * The main data path doesn't include the HGO or HGT, use |
| + * vsp1_entity_remote_pad() to traverse the graph. |
| + */ |
| + |
| + pad = vsp1_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]); |
| |
| while (1) { |
| if (pad == NULL) { |
| @@ -539,14 +544,9 @@ static int vsp1_video_pipeline_build_bra |
| : &input->entity; |
| } |
| |
| - /* |
| - * Follow the source link. The link setup operations ensure |
| - * that the output fan-out can't be more than one, there is thus |
| - * no need to verify here that only a single source link is |
| - * activated. |
| - */ |
| + /* Follow the source link, ignoring any HGO or HGT. */ |
| pad = &entity->pads[entity->source_pad]; |
| - pad = media_entity_remote_pad(pad); |
| + pad = vsp1_entity_remote_pad(pad); |
| } |
| |
| /* The last entity must be the output WPF. */ |
| @@ -800,7 +800,7 @@ static int vsp1_video_setup_pipeline(str |
| } |
| |
| list_for_each_entry(entity, &pipe->entities, list_pipe) { |
| - vsp1_entity_route_setup(entity, pipe->dl); |
| + vsp1_entity_route_setup(entity, pipe, pipe->dl); |
| |
| if (entity->ops->configure) |
| entity->ops->configure(entity, pipe, pipe->dl, |