Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 780bf2fe authored by Todor Tomov's avatar Todor Tomov Committed by Mauro Carvalho Chehab
Browse files

media: camss: vfe: Add interface for cropping



Extend selection ioctls to handle cropping configuration.

Signed-off-by: default avatarTodor Tomov <todor.tomov@linaro.org>
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent cce91b14
Loading
Loading
Loading
Loading
+149 −42
Original line number Original line Diff line number Diff line
@@ -1993,6 +1993,26 @@ __vfe_get_compose(struct vfe_line *line,
	return &line->compose;
	return &line->compose;
}
}


/*
 * __vfe_get_crop - Get pointer to crop selection structure
 * @line: VFE line
 * @cfg: V4L2 subdev pad configuration
 * @which: TRY or ACTIVE format
 *
 * Return pointer to TRY or ACTIVE crop rectangle structure
 */
static struct v4l2_rect *
__vfe_get_crop(struct vfe_line *line,
	       struct v4l2_subdev_pad_config *cfg,
	       enum v4l2_subdev_format_whence which)
{
	if (which == V4L2_SUBDEV_FORMAT_TRY)
		return v4l2_subdev_get_try_crop(&line->subdev, cfg,
						MSM_VFE_PAD_SRC);

	return &line->crop;
}

/*
/*
 * vfe_try_format - Handle try format by pad subdev method
 * vfe_try_format - Handle try format by pad subdev method
 * @line: VFE line
 * @line: VFE line
@@ -2041,7 +2061,7 @@ static void vfe_try_format(struct vfe_line *line,
		if (line->id == VFE_LINE_PIX) {
		if (line->id == VFE_LINE_PIX) {
			struct v4l2_rect *rect;
			struct v4l2_rect *rect;


			rect = __vfe_get_compose(line, cfg, which);
			rect = __vfe_get_crop(line, cfg, which);


			fmt->width = rect->width;
			fmt->width = rect->width;
			fmt->height = rect->height;
			fmt->height = rect->height;
@@ -2120,6 +2140,49 @@ static void vfe_try_compose(struct vfe_line *line,
		rect->height = 4;
		rect->height = 4;
}
}


/*
 * vfe_try_crop - Handle try crop selection by pad subdev method
 * @line: VFE line
 * @cfg: V4L2 subdev pad configuration
 * @rect: pointer to v4l2 rect structure
 * @which: wanted subdev format
 */
static void vfe_try_crop(struct vfe_line *line,
			 struct v4l2_subdev_pad_config *cfg,
			 struct v4l2_rect *rect,
			 enum v4l2_subdev_format_whence which)
{
	struct v4l2_rect *compose;

	compose = __vfe_get_compose(line, cfg, which);

	if (rect->width > compose->width)
		rect->width = compose->width;

	if (rect->width + rect->left > compose->width)
		rect->left = compose->width - rect->width;

	if (rect->height > compose->height)
		rect->height = compose->height;

	if (rect->height + rect->top > compose->height)
		rect->top = compose->height - rect->height;

	/* wm in line based mode writes multiple of 16 horizontally */
	rect->left += (rect->width & 0xf) >> 1;
	rect->width &= ~0xf;

	if (rect->width < 16) {
		rect->left = 0;
		rect->width = 16;
	}

	if (rect->height < 4) {
		rect->top = 0;
		rect->height = 4;
	}
}

/*
/*
 * vfe_enum_mbus_code - Handle pixel format enumeration
 * vfe_enum_mbus_code - Handle pixel format enumeration
 * @sd: VFE V4L2 subdevice
 * @sd: VFE V4L2 subdevice
@@ -2284,12 +2347,13 @@ static int vfe_get_selection(struct v4l2_subdev *sd,
{
{
	struct vfe_line *line = v4l2_get_subdevdata(sd);
	struct vfe_line *line = v4l2_get_subdevdata(sd);
	struct v4l2_subdev_format fmt = { 0 };
	struct v4l2_subdev_format fmt = { 0 };
	struct v4l2_rect *compose;
	struct v4l2_rect *rect;
	int ret;
	int ret;


	if (line->id != VFE_LINE_PIX || sel->pad != MSM_VFE_PAD_SINK)
	if (line->id != VFE_LINE_PIX)
		return -EINVAL;
		return -EINVAL;


	if (sel->pad == MSM_VFE_PAD_SINK)
		switch (sel->target) {
		switch (sel->target) {
		case V4L2_SEL_TGT_COMPOSE_BOUNDS:
		case V4L2_SEL_TGT_COMPOSE_BOUNDS:
			fmt.pad = sel->pad;
			fmt.pad = sel->pad;
@@ -2297,17 +2361,40 @@ static int vfe_get_selection(struct v4l2_subdev *sd,
			ret = vfe_get_format(sd, cfg, &fmt);
			ret = vfe_get_format(sd, cfg, &fmt);
			if (ret < 0)
			if (ret < 0)
				return ret;
				return ret;

			sel->r.left = 0;
			sel->r.left = 0;
			sel->r.top = 0;
			sel->r.top = 0;
			sel->r.width = fmt.format.width;
			sel->r.width = fmt.format.width;
			sel->r.height = fmt.format.height;
			sel->r.height = fmt.format.height;
			break;
			break;
		case V4L2_SEL_TGT_COMPOSE:
		case V4L2_SEL_TGT_COMPOSE:
		compose = __vfe_get_compose(line, cfg, sel->which);
			rect = __vfe_get_compose(line, cfg, sel->which);
		if (compose == NULL)
			if (rect == NULL)
				return -EINVAL;

			sel->r = *rect;
			break;
		default:
			return -EINVAL;
		}
	else if (sel->pad == MSM_VFE_PAD_SRC)
		switch (sel->target) {
		case V4L2_SEL_TGT_CROP_BOUNDS:
			rect = __vfe_get_compose(line, cfg, sel->which);
			if (rect == NULL)
				return -EINVAL;

			sel->r.left = rect->left;
			sel->r.top = rect->top;
			sel->r.width = rect->width;
			sel->r.height = rect->height;
			break;
		case V4L2_SEL_TGT_CROP:
			rect = __vfe_get_crop(line, cfg, sel->which);
			if (rect == NULL)
				return -EINVAL;
				return -EINVAL;


		sel->r = *compose;
			sel->r = *rect;
			break;
			break;
		default:
		default:
			return -EINVAL;
			return -EINVAL;
@@ -2329,22 +2416,39 @@ int vfe_set_selection(struct v4l2_subdev *sd,
			     struct v4l2_subdev_selection *sel)
			     struct v4l2_subdev_selection *sel)
{
{
	struct vfe_line *line = v4l2_get_subdevdata(sd);
	struct vfe_line *line = v4l2_get_subdevdata(sd);
	struct v4l2_rect *compose;
	struct v4l2_rect *rect;
	struct v4l2_subdev_format fmt = { 0 };
	int ret;
	int ret;


	if (line->id != VFE_LINE_PIX || sel->pad != MSM_VFE_PAD_SINK)
	if (line->id != VFE_LINE_PIX)
		return -EINVAL;
		return -EINVAL;


	if (sel->target != V4L2_SEL_TGT_COMPOSE)
	if (sel->target == V4L2_SEL_TGT_COMPOSE &&
		return -EINVAL;
		sel->pad == MSM_VFE_PAD_SINK) {
		struct v4l2_subdev_selection crop = { 0 };


	compose = __vfe_get_compose(line, cfg, sel->which);
		rect = __vfe_get_compose(line, cfg, sel->which);
	if (compose == NULL)
		if (rect == NULL)
			return -EINVAL;
			return -EINVAL;


		vfe_try_compose(line, cfg, &sel->r, sel->which);
		vfe_try_compose(line, cfg, &sel->r, sel->which);
	*compose = sel->r;
		*rect = sel->r;

		/* Reset source crop selection */
		crop.which = sel->which;
		crop.pad = MSM_VFE_PAD_SRC;
		crop.target = V4L2_SEL_TGT_CROP;
		crop.r = *rect;
		ret = vfe_set_selection(sd, cfg, &crop);
	} else if (sel->target == V4L2_SEL_TGT_CROP &&
		sel->pad == MSM_VFE_PAD_SRC) {
		struct v4l2_subdev_format fmt = { 0 };

		rect = __vfe_get_crop(line, cfg, sel->which);
		if (rect == NULL)
			return -EINVAL;

		vfe_try_crop(line, cfg, &sel->r, sel->which);
		*rect = sel->r;


		/* Reset source pad format width and height */
		/* Reset source pad format width and height */
		fmt.which = sel->which;
		fmt.which = sel->which;
@@ -2353,9 +2457,12 @@ int vfe_set_selection(struct v4l2_subdev *sd,
		if (ret < 0)
		if (ret < 0)
			return ret;
			return ret;


	fmt.format.width = compose->width;
		fmt.format.width = rect->width;
	fmt.format.height = compose->height;
		fmt.format.height = rect->height;
		ret = vfe_set_format(sd, cfg, &fmt);
		ret = vfe_set_format(sd, cfg, &fmt);
	} else {
		ret = -EINVAL;
	}


	return ret;
	return ret;
}
}
+1 −0
Original line number Original line Diff line number Diff line
@@ -81,6 +81,7 @@ struct vfe_line {
	struct media_pad pads[MSM_VFE_PADS_NUM];
	struct media_pad pads[MSM_VFE_PADS_NUM];
	struct v4l2_mbus_framefmt fmt[MSM_VFE_PADS_NUM];
	struct v4l2_mbus_framefmt fmt[MSM_VFE_PADS_NUM];
	struct v4l2_rect compose;
	struct v4l2_rect compose;
	struct v4l2_rect crop;
	struct camss_video video_out;
	struct camss_video video_out;
	struct vfe_output output;
	struct vfe_output output;
};
};