From: Laurent Pinchart Date: Sat, 31 May 2014 00:45:48 +0000 (-0300) Subject: [media] v4l: vsp1: uds: Fix scaling of alpha layer X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=bdc2df62ae38bbab044078f4d25a7a3d9e2379c9;p=openwrt%2Fstaging%2Fblogic.git [media] v4l: vsp1: uds: Fix scaling of alpha layer Pixel color components can be scaled using either bilinear interpolation or a multitap filter. The multitap filter provides better results, but can't be selected when the alpha layer need to be scaled down by more than 1/2. Disable alpha scaling when the input has a fixed alpha value, and program the UDS to output a fixed alpha value in that case. This ensures the multitap filter will be used whenever possible. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c index 576779f2332b..d14d26b718ef 100644 --- a/drivers/media/platform/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/vsp1/vsp1_rpf.c @@ -46,6 +46,7 @@ static int rpf_s_ctrl(struct v4l2_ctrl *ctrl) { struct vsp1_rwpf *rpf = container_of(ctrl->handler, struct vsp1_rwpf, ctrls); + struct vsp1_pipeline *pipe; if (!vsp1_entity_is_streaming(&rpf->entity)) return 0; @@ -54,6 +55,9 @@ static int rpf_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_ALPHA_COMPONENT: vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET, ctrl->val << VI6_RPF_VRTCOL_SET_LAYA_SHIFT); + + pipe = to_vsp1_pipeline(&rpf->entity.subdev.entity); + vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, ctrl->val); break; } diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c index 0293bdbb4401..de92ef4944b3 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.c +++ b/drivers/media/platform/vsp1/vsp1_uds.c @@ -45,6 +45,11 @@ static inline void vsp1_uds_write(struct vsp1_uds *uds, u32 reg, u32 data) * Scaling Computation */ +void vsp1_uds_set_alpha(struct vsp1_uds *uds, unsigned int alpha) +{ + vsp1_uds_write(uds, VI6_UDS_ALPVAL, alpha << VI6_UDS_ALPVAL_VAL0_SHIFT); +} + /* * uds_output_size - Return the output size for an input size and scaling ratio * @input: input size in pixels @@ -105,49 +110,56 @@ static unsigned int uds_compute_ratio(unsigned int input, unsigned int output) return (input - 1) * 4096 / (output - 1); } -static void uds_compute_ratios(struct vsp1_uds *uds) -{ - struct v4l2_mbus_framefmt *input = &uds->entity.formats[UDS_PAD_SINK]; - struct v4l2_mbus_framefmt *output = - &uds->entity.formats[UDS_PAD_SOURCE]; - - uds->hscale = uds_compute_ratio(input->width, output->width); - uds->vscale = uds_compute_ratio(input->height, output->height); - - dev_dbg(uds->entity.vsp1->dev, "hscale %u vscale %u\n", - uds->hscale, uds->vscale); -} - /* ----------------------------------------------------------------------------- * V4L2 Subdevice Core Operations */ static int uds_s_stream(struct v4l2_subdev *subdev, int enable) { - const struct v4l2_mbus_framefmt *format; struct vsp1_uds *uds = to_uds(subdev); + const struct v4l2_mbus_framefmt *output; + const struct v4l2_mbus_framefmt *input; + unsigned int hscale; + unsigned int vscale; + bool multitap; if (!enable) return 0; - /* Enable multi-tap scaling. */ - vsp1_uds_write(uds, VI6_UDS_CTRL, VI6_UDS_CTRL_AON | VI6_UDS_CTRL_BC); + input = &uds->entity.formats[UDS_PAD_SINK]; + output = &uds->entity.formats[UDS_PAD_SOURCE]; + + hscale = uds_compute_ratio(input->width, output->width); + vscale = uds_compute_ratio(input->height, output->height); + + dev_dbg(uds->entity.vsp1->dev, "hscale %u vscale %u\n", hscale, vscale); + + /* Multi-tap scaling can't be enabled along with alpha scaling when + * scaling down with a factor lower than or equal to 1/2 in either + * direction. + */ + if (uds->scale_alpha && (hscale >= 8192 || vscale >= 8192)) + multitap = false; + else + multitap = true; + + vsp1_uds_write(uds, VI6_UDS_CTRL, + (uds->scale_alpha ? VI6_UDS_CTRL_AON : 0) | + (multitap ? VI6_UDS_CTRL_BC : 0)); vsp1_uds_write(uds, VI6_UDS_PASS_BWIDTH, - (uds_passband_width(uds->hscale) + (uds_passband_width(hscale) << VI6_UDS_PASS_BWIDTH_H_SHIFT) | - (uds_passband_width(uds->vscale) + (uds_passband_width(vscale) << VI6_UDS_PASS_BWIDTH_V_SHIFT)); /* Set the scaling ratios and the output size. */ - format = &uds->entity.formats[UDS_PAD_SOURCE]; - vsp1_uds_write(uds, VI6_UDS_SCALE, - (uds->hscale << VI6_UDS_SCALE_HFRAC_SHIFT) | - (uds->vscale << VI6_UDS_SCALE_VFRAC_SHIFT)); + (hscale << VI6_UDS_SCALE_HFRAC_SHIFT) | + (vscale << VI6_UDS_SCALE_VFRAC_SHIFT)); vsp1_uds_write(uds, VI6_UDS_CLIP_SIZE, - (format->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) | - (format->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT)); + (output->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) | + (output->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT)); return 0; } @@ -280,9 +292,6 @@ static int uds_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, uds_try_format(uds, fh, UDS_PAD_SOURCE, format, fmt->which); } - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) - uds_compute_ratios(uds); - return 0; } diff --git a/drivers/media/platform/vsp1/vsp1_uds.h b/drivers/media/platform/vsp1/vsp1_uds.h index 479d12df1180..031ac0da1b66 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.h +++ b/drivers/media/platform/vsp1/vsp1_uds.h @@ -25,9 +25,7 @@ struct vsp1_device; struct vsp1_uds { struct vsp1_entity entity; - - unsigned int hscale; - unsigned int vscale; + bool scale_alpha; }; static inline struct vsp1_uds *to_uds(struct v4l2_subdev *subdev) @@ -37,4 +35,6 @@ static inline struct vsp1_uds *to_uds(struct v4l2_subdev *subdev) struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index); +void vsp1_uds_set_alpha(struct vsp1_uds *uds, unsigned int alpha); + #endif /* __VSP1_UDS_H__ */ diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index 58fc076197f1..915a20eb003e 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -31,6 +31,7 @@ #include "vsp1_bru.h" #include "vsp1_entity.h" #include "vsp1_rwpf.h" +#include "vsp1_uds.h" #include "vsp1_video.h" #define VSP1_VIDEO_DEF_FORMAT V4L2_PIX_FMT_YUYV @@ -306,13 +307,14 @@ vsp1_video_format_adjust(struct vsp1_video *video, * Pipeline Management */ -static int vsp1_pipeline_validate_branch(struct vsp1_rwpf *input, +static int vsp1_pipeline_validate_branch(struct vsp1_pipeline *pipe, + struct vsp1_rwpf *input, struct vsp1_rwpf *output) { struct vsp1_entity *entity; unsigned int entities = 0; struct media_pad *pad; - bool uds_found = false; + bool bru_found = false; input->location.left = 0; input->location.top = 0; @@ -341,6 +343,8 @@ static int vsp1_pipeline_validate_branch(struct vsp1_rwpf *input, input->location.left = rect->left; input->location.top = rect->top; + + bru_found = true; } /* We've reached the WPF, we're done. */ @@ -355,9 +359,12 @@ static int vsp1_pipeline_validate_branch(struct vsp1_rwpf *input, /* UDS can't be chained. */ if (entity->type == VSP1_ENTITY_UDS) { - if (uds_found) + if (pipe->uds) return -EPIPE; - uds_found = true; + + pipe->uds = entity; + pipe->uds_input = bru_found ? pipe->bru + : &input->entity; } /* Follow the source link. The link setup operations ensure @@ -394,6 +401,7 @@ static void __vsp1_pipeline_cleanup(struct vsp1_pipeline *pipe) pipe->output = NULL; pipe->bru = NULL; pipe->lif = NULL; + pipe->uds = NULL; } static int vsp1_pipeline_validate(struct vsp1_pipeline *pipe, @@ -451,7 +459,7 @@ static int vsp1_pipeline_validate(struct vsp1_pipeline *pipe, * contains no loop and that all branches end at the output WPF. */ for (i = 0; i < pipe->num_inputs; ++i) { - ret = vsp1_pipeline_validate_branch(pipe->inputs[i], + ret = vsp1_pipeline_validate_branch(pipe, pipe->inputs[i], pipe->output); if (ret < 0) goto error; @@ -654,6 +662,47 @@ done: spin_unlock_irqrestore(&pipe->irqlock, flags); } +/* + * Propagate the alpha value through the pipeline. + * + * As the UDS has restricted scaling capabilities when the alpha component needs + * to be scaled, we disable alpha scaling when the UDS input has a fixed alpha + * value. The UDS then outputs a fixed alpha value which needs to be programmed + * from the input RPF alpha. + */ +void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, + struct vsp1_entity *input, + unsigned int alpha) +{ + struct vsp1_entity *entity; + struct media_pad *pad; + + pad = media_entity_remote_pad(&input->pads[RWPF_PAD_SOURCE]); + + while (pad) { + if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + break; + + entity = to_vsp1_entity(media_entity_to_v4l2_subdev(pad->entity)); + + /* The BRU background color has a fixed alpha value set to 255, + * the output alpha value is thus always equal to 255. + */ + if (entity->type == VSP1_ENTITY_BRU) + alpha = 255; + + if (entity->type == VSP1_ENTITY_UDS) { + struct vsp1_uds *uds = to_uds(&entity->subdev); + + vsp1_uds_set_alpha(uds, alpha); + break; + } + + pad = &entity->pads[entity->source_pad]; + pad = media_entity_remote_pad(pad); + } +} + /* ----------------------------------------------------------------------------- * videobuf2 Queue Operations */ @@ -761,6 +810,25 @@ static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count) mutex_lock(&pipe->lock); if (pipe->stream_count == pipe->num_video - 1) { + if (pipe->uds) { + struct vsp1_uds *uds = to_uds(&pipe->uds->subdev); + + /* If a BRU is present in the pipeline before the UDS, + * the alpha component doesn't need to be scaled as the + * BRU output alpha value is fixed to 255. Otherwise we + * need to scale the alpha component only when available + * at the input RPF. + */ + if (pipe->uds_input->type == VSP1_ENTITY_BRU) { + uds->scale_alpha = false; + } else { + struct vsp1_rwpf *rpf = + to_rwpf(&pipe->uds_input->subdev); + + uds->scale_alpha = rpf->video.fmtinfo->alpha; + } + } + list_for_each_entry(entity, &pipe->entities, list_pipe) { vsp1_entity_route_setup(entity); diff --git a/drivers/media/platform/vsp1/vsp1_video.h b/drivers/media/platform/vsp1/vsp1_video.h index 4dad110b2e69..fd2851a82e00 100644 --- a/drivers/media/platform/vsp1/vsp1_video.h +++ b/drivers/media/platform/vsp1/vsp1_video.h @@ -79,6 +79,8 @@ struct vsp1_pipeline { struct vsp1_rwpf *output; struct vsp1_entity *bru; struct vsp1_entity *lif; + struct vsp1_entity *uds; + struct vsp1_entity *uds_input; struct list_head entities; }; @@ -143,4 +145,8 @@ void vsp1_video_cleanup(struct vsp1_video *video); void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe); +void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, + struct vsp1_entity *input, + unsigned int alpha); + #endif /* __VSP1_VIDEO_H__ */