diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c index 56464875a6c5..ffc1b3ab54e2 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c @@ -201,6 +201,8 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { + unsigned int min_width = RWPF_MIN_WIDTH; + unsigned int min_height = RWPF_MIN_HEIGHT; struct vsp1_rwpf *rwpf = to_rwpf(subdev); struct v4l2_subdev_state *state; struct v4l2_mbus_framefmt *format; @@ -229,18 +231,36 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, format = v4l2_subdev_state_get_format(state, RWPF_PAD_SINK); /* - * Restrict the crop rectangle coordinates to multiples of 2 to avoid - * shifting the color plane. + * For YUV formats, restrict the crop rectangle coordinates to multiples + * of 2 to avoid shifting the color plane. */ if (format->code == MEDIA_BUS_FMT_AYUV8_1X32) { sel->r.left = ALIGN(sel->r.left, 2); sel->r.top = ALIGN(sel->r.top, 2); sel->r.width = round_down(sel->r.width, 2); sel->r.height = round_down(sel->r.height, 2); + + /* + * The RPF doesn't enforces the alignment constraint on the sink + * pad format, which could have an odd size, possibly down to + * 1x1. In that case, the minimum width and height would be + * smaller than the sink pad format, leading to a negative upper + * bound in the left and top clamping. Clamp the minimum width + * and height to the format width and height to avoid this. + * + * In such a situation, odd values for the crop rectangle size + * would be accepted when clamping the width and height below. + * While that would create an invalid hardware configuration, + * the video device enforces proper alignment of the pixel + * format, and the mismatch will then result in link validation + * failure. Incorrect operation of the hardware is not possible. + */ + min_width = min(ALIGN(min_width, 2), format->width); + min_height = min(ALIGN(min_height, 2), format->height); } - sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2); - sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2); + sel->r.left = clamp_t(int, sel->r.left, 0, format->width - min_width); + sel->r.top = clamp_t(int, sel->r.top, 0, format->height - min_height); sel->r.width = min_t(unsigned int, sel->r.width, format->width - sel->r.left); sel->r.height = min_t(unsigned int, sel->r.height,