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

Commit e5ad37b6 authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab
Browse files

[media] v4l: vsp1: Add cropping support



Implement the get and set selection operations on the RPF and WPF
entities. Only the crop targets are currently available.

Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: default avatarMauro Carvalho Chehab <m.chehab@samsung.com>
parent 3299ba5c
Loading
Loading
Loading
Loading
+25 −9
Original line number Diff line number Diff line
@@ -47,25 +47,36 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
	struct vsp1_rwpf *rpf = to_rwpf(subdev);
	const struct vsp1_format_info *fmtinfo = rpf->video.fmtinfo;
	const struct v4l2_pix_format_mplane *format = &rpf->video.format;
	const struct v4l2_rect *crop = &rpf->crop;
	u32 pstride;
	u32 infmt;

	if (!enable)
		return 0;

	/* Source size and stride. Cropping isn't supported yet. */
	/* Source size, stride and crop offsets.
	 *
	 * The crop offsets correspond to the location of the crop rectangle top
	 * left corner in the plane buffer. Only two offsets are needed, as
	 * planes 2 and 3 always have identical strides.
	 */
	vsp1_rpf_write(rpf, VI6_RPF_SRC_BSIZE,
		       (format->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
		       (format->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
		       (crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
		       (crop->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
	vsp1_rpf_write(rpf, VI6_RPF_SRC_ESIZE,
		       (format->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
		       (format->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));
		       (crop->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
		       (crop->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));

	rpf->offsets[0] = crop->top * format->plane_fmt[0].bytesperline
			+ crop->left * fmtinfo->bpp[0] / 8;
	pstride = format->plane_fmt[0].bytesperline
		<< VI6_RPF_SRCM_PSTRIDE_Y_SHIFT;
	if (format->num_planes > 1)
	if (format->num_planes > 1) {
		rpf->offsets[1] = crop->top * format->plane_fmt[1].bytesperline
				+ crop->left * fmtinfo->bpp[1] / 8;
		pstride |= format->plane_fmt[1].bytesperline
			<< VI6_RPF_SRCM_PSTRIDE_C_SHIFT;
	}

	vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride);

@@ -113,6 +124,8 @@ static struct v4l2_subdev_pad_ops rpf_pad_ops = {
	.enum_frame_size = vsp1_rwpf_enum_frame_size,
	.get_fmt = vsp1_rwpf_get_format,
	.set_fmt = vsp1_rwpf_set_format,
	.get_selection = vsp1_rwpf_get_selection,
	.set_selection = vsp1_rwpf_set_selection,
};

static struct v4l2_subdev_ops rpf_ops = {
@@ -129,11 +142,14 @@ static void rpf_vdev_queue(struct vsp1_video *video,
{
	struct vsp1_rwpf *rpf = container_of(video, struct vsp1_rwpf, video);

	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y, buf->addr[0]);
	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
		       buf->addr[0] + rpf->offsets[0]);
	if (buf->buf.num_planes > 1)
		vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0, buf->addr[1]);
		vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
			       buf->addr[1] + rpf->offsets[1]);
	if (buf->buf.num_planes > 2)
		vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1, buf->addr[2]);
		vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
			       buf->addr[2] + rpf->offsets[1]);
}

static const struct vsp1_video_operations rpf_vdev_ops = {
+96 −0
Original line number Diff line number Diff line
@@ -71,6 +71,19 @@ int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
	return 0;
}

static struct v4l2_rect *
vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_fh *fh, u32 which)
{
	switch (which) {
	case V4L2_SUBDEV_FORMAT_TRY:
		return v4l2_subdev_get_try_crop(fh, RWPF_PAD_SINK);
	case V4L2_SUBDEV_FORMAT_ACTIVE:
		return &rwpf->crop;
	default:
		return NULL;
	}
}

int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
			 struct v4l2_subdev_format *fmt)
{
@@ -87,6 +100,7 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
{
	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
	struct v4l2_mbus_framefmt *format;
	struct v4l2_rect *crop;

	/* Default to YUV if the requested format is not supported. */
	if (fmt->format.code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
@@ -115,6 +129,13 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,

	fmt->format = *format;

	/* Update the sink crop rectangle. */
	crop = vsp1_rwpf_get_crop(rwpf, fh, fmt->which);
	crop->left = 0;
	crop->top = 0;
	crop->width = fmt->format.width;
	crop->height = fmt->format.height;

	/* Propagate the format to the source pad. */
	format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SOURCE,
					    fmt->which);
@@ -122,3 +143,78 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,

	return 0;
}

int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
			    struct v4l2_subdev_fh *fh,
			    struct v4l2_subdev_selection *sel)
{
	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
	struct v4l2_mbus_framefmt *format;

	/* Cropping is implemented on the sink pad. */
	if (sel->pad != RWPF_PAD_SINK)
		return -EINVAL;

	switch (sel->target) {
	case V4L2_SEL_TGT_CROP:
		sel->r = *vsp1_rwpf_get_crop(rwpf, fh, sel->which);
		break;

	case V4L2_SEL_TGT_CROP_BOUNDS:
		format = vsp1_entity_get_pad_format(&rwpf->entity, fh,
						    RWPF_PAD_SINK, sel->which);
		sel->r.left = 0;
		sel->r.top = 0;
		sel->r.width = format->width;
		sel->r.height = format->height;
		break;

	default:
		return -EINVAL;
	}

	return 0;
}

int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
			    struct v4l2_subdev_fh *fh,
			    struct v4l2_subdev_selection *sel)
{
	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
	struct v4l2_mbus_framefmt *format;
	struct v4l2_rect *crop;

	/* Cropping is implemented on the sink pad. */
	if (sel->pad != RWPF_PAD_SINK)
		return -EINVAL;

	if (sel->target != V4L2_SEL_TGT_CROP)
		return -EINVAL;

	/* Make sure the crop rectangle is entirely contained in the image. The
	 * WPF top and left offsets are limited to 255.
	 */
	format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SINK,
					    sel->which);
	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);
	if (rwpf->entity.type == VSP1_ENTITY_WPF) {
		sel->r.left = min_t(unsigned int, sel->r.left, 255);
		sel->r.top = min_t(unsigned int, sel->r.top, 255);
	}
	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,
			      format->height - sel->r.top);

	crop = vsp1_rwpf_get_crop(rwpf, fh, sel->which);
	*crop = sel->r;

	/* Propagate the format to the source pad. */
	format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SOURCE,
					    sel->which);
	format->width = crop->width;
	format->height = crop->height;

	return 0;
}
+10 −0
Original line number Diff line number Diff line
@@ -29,6 +29,10 @@ struct vsp1_rwpf {

	unsigned int max_width;
	unsigned int max_height;

	struct v4l2_rect crop;

	unsigned int offsets[2];
};

static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev)
@@ -49,5 +53,11 @@ int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
			 struct v4l2_subdev_format *fmt);
int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
			 struct v4l2_subdev_format *fmt);
int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
			    struct v4l2_subdev_fh *fh,
			    struct v4l2_subdev_selection *sel);
int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
			    struct v4l2_subdev_fh *fh,
			    struct v4l2_subdev_selection *sel);

#endif /* __VSP1_RWPF_H__ */
+10 −7
Original line number Diff line number Diff line
@@ -48,8 +48,7 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
	struct vsp1_pipeline *pipe =
		to_vsp1_pipeline(&wpf->entity.subdev.entity);
	struct vsp1_device *vsp1 = wpf->entity.vsp1;
	const struct v4l2_mbus_framefmt *format =
		&wpf->entity.formats[RWPF_PAD_SOURCE];
	const struct v4l2_rect *crop = &wpf->crop;
	unsigned int i;
	u32 srcrpf = 0;
	u32 outfmt = 0;
@@ -68,7 +67,7 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)

	vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf);

	/* Destination stride. Cropping isn't supported yet. */
	/* Destination stride. */
	if (!pipe->lif) {
		struct v4l2_pix_format_mplane *format = &wpf->video.format;

@@ -79,10 +78,12 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
				       format->plane_fmt[1].bytesperline);
	}

	vsp1_wpf_write(wpf, VI6_WPF_HSZCLIP,
		       format->width << VI6_WPF_SZCLIP_SIZE_SHIFT);
	vsp1_wpf_write(wpf, VI6_WPF_VSZCLIP,
		       format->height << VI6_WPF_SZCLIP_SIZE_SHIFT);
	vsp1_wpf_write(wpf, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
		       (crop->left << VI6_WPF_SZCLIP_OFST_SHIFT) |
		       (crop->width << VI6_WPF_SZCLIP_SIZE_SHIFT));
	vsp1_wpf_write(wpf, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN |
		       (crop->top << VI6_WPF_SZCLIP_OFST_SHIFT) |
		       (crop->height << VI6_WPF_SZCLIP_SIZE_SHIFT));

	/* Format */
	if (!pipe->lif) {
@@ -130,6 +131,8 @@ static struct v4l2_subdev_pad_ops wpf_pad_ops = {
	.enum_frame_size = vsp1_rwpf_enum_frame_size,
	.get_fmt = vsp1_rwpf_get_format,
	.set_fmt = vsp1_rwpf_set_format,
	.get_selection = vsp1_rwpf_get_selection,
	.set_selection = vsp1_rwpf_set_selection,
};

static struct v4l2_subdev_ops wpf_ops = {