Example #1
0
int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
			    struct v4l2_subdev_pad_config *cfg,
			    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, cfg, sel->which);
		break;

	case V4L2_SEL_TGT_CROP_BOUNDS:
		format = vsp1_entity_get_pad_format(&rwpf->entity, cfg,
						    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;
}
Example #2
0
int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
			 struct v4l2_subdev_format *fmt)
{
	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 != MEDIA_BUS_FMT_ARGB8888_1X32 &&
	    fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
		fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;

	format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad,
					    fmt->which);

	if (fmt->pad == RWPF_PAD_SOURCE) {
		/* The RWPF performs format conversion but can't scale, only the
		 * format code can be changed on the source pad.
		 */
		format->code = fmt->format.code;
		fmt->format = *format;
		return 0;
	}

	format->code = fmt->format.code;
	format->width = clamp_t(unsigned int, fmt->format.width,
				RWPF_MIN_WIDTH, rwpf->max_width);
	format->height = clamp_t(unsigned int, fmt->format.height,
				 RWPF_MIN_HEIGHT, rwpf->max_height);
	format->field = V4L2_FIELD_NONE;
	format->colorspace = V4L2_COLORSPACE_SRGB;

	fmt->format = *format;

	/* Update the sink crop rectangle. */
	crop = vsp1_rwpf_get_crop(rwpf, cfg, 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, cfg, RWPF_PAD_SOURCE,
					    fmt->which);
	*format = fmt->format;

	return 0;
}
Example #3
0
	 */
	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);
	}

	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, cfg, sel->which);
	*crop = sel->r;

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

	return 0;
}
Example #4
0
static void wpf_configure(struct vsp1_entity *entity,
			  struct vsp1_pipeline *pipe,
			  struct vsp1_dl_list *dl)
{
	struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
	struct vsp1_device *vsp1 = wpf->entity.vsp1;
	const struct v4l2_mbus_framefmt *source_format;
	const struct v4l2_mbus_framefmt *sink_format;
	const struct v4l2_rect *crop;
	unsigned int i;
	u32 outfmt = 0;
	u32 srcrpf = 0;

	/* Cropping */
	crop = vsp1_rwpf_get_crop(wpf, wpf->entity.config);

	vsp1_wpf_write(wpf, dl, 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, dl, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN |
		       (crop->top << VI6_WPF_SZCLIP_OFST_SHIFT) |
		       (crop->height << VI6_WPF_SZCLIP_SIZE_SHIFT));

	/* Format */
	sink_format = vsp1_entity_get_pad_format(&wpf->entity,
						 wpf->entity.config,
						 RWPF_PAD_SINK);
	source_format = vsp1_entity_get_pad_format(&wpf->entity,
						   wpf->entity.config,
						   RWPF_PAD_SOURCE);

	if (!pipe->lif) {
		const struct v4l2_pix_format_mplane *format = &wpf->format;
		const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;

		outfmt = fmtinfo->hwfmt << VI6_WPF_OUTFMT_WRFMT_SHIFT;

		if (fmtinfo->alpha)
			outfmt |= VI6_WPF_OUTFMT_PXA;
		if (fmtinfo->swap_yc)
			outfmt |= VI6_WPF_OUTFMT_SPYCS;
		if (fmtinfo->swap_uv)
			outfmt |= VI6_WPF_OUTFMT_SPUVS;

		/* Destination stride and byte swapping. */
		vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_STRIDE_Y,
			       format->plane_fmt[0].bytesperline);
		if (format->num_planes > 1)
			vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_STRIDE_C,
				       format->plane_fmt[1].bytesperline);

		vsp1_wpf_write(wpf, dl, VI6_WPF_DSWAP, fmtinfo->swap);
	}

	if (sink_format->code != source_format->code)
		outfmt |= VI6_WPF_OUTFMT_CSC;

	outfmt |= wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT;
	vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, outfmt);

	vsp1_dl_list_write(dl, VI6_DPR_WPF_FPORCH(wpf->entity.index),
			   VI6_DPR_WPF_FPORCH_FP_WPFN);

	vsp1_dl_list_write(dl, VI6_WPF_WRBCK_CTRL, 0);

	/* Sources. If the pipeline has a single input and BRU is not used,
	 * configure it as the master layer. Otherwise configure all
	 * inputs as sub-layers and select the virtual RPF as the master
	 * layer.
	 */
	for (i = 0; i < vsp1->info->rpf_count; ++i) {
		struct vsp1_rwpf *input = pipe->inputs[i];

		if (!input)
			continue;

		srcrpf |= (!pipe->bru && pipe->num_inputs == 1)
			? VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index)
			: VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index);
	}

	if (pipe->bru || pipe->num_inputs > 1)
		srcrpf |= VI6_WPF_SRCRPF_VIRACT_MST;

	vsp1_wpf_write(wpf, dl, VI6_WPF_SRCRPF, srcrpf);

	/* Enable interrupts */
	vsp1_dl_list_write(dl, VI6_WPF_IRQ_STA(wpf->entity.index), 0);
	vsp1_dl_list_write(dl, VI6_WPF_IRQ_ENB(wpf->entity.index),
			   VI6_WFP_IRQ_ENB_FREE);
}
Example #5
0
static void rpf_configure_partition(struct vsp1_entity *entity,
				    struct vsp1_pipeline *pipe,
				    struct vsp1_dl_list *dl,
				    struct vsp1_dl_body *dlb)
{
	struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
	struct vsp1_rwpf_memory mem = rpf->mem;
	struct vsp1_device *vsp1 = rpf->entity.vsp1;
	const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
	const struct v4l2_pix_format_mplane *format = &rpf->format;
	struct v4l2_rect crop;

	/*
	 * Source size 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.
	 */
	crop = *vsp1_rwpf_get_crop(rpf, rpf->entity.config);

	/*
	 * Partition Algorithm Control
	 *
	 * The partition algorithm can split this frame into multiple
	 * slices. We must scale our partition window based on the pipe
	 * configuration to match the destination partition window.
	 * To achieve this, we adjust our crop to provide a 'sub-crop'
	 * matching the expected partition window. Only 'left' and
	 * 'width' need to be adjusted.
	 */
	if (pipe->partitions > 1) {
		crop.width = pipe->partition->rpf.width;
		crop.left += pipe->partition->rpf.left;
	}

	if (pipe->interlaced) {
		crop.height = round_down(crop.height / 2, fmtinfo->vsub);
		crop.top = round_down(crop.top / 2, fmtinfo->vsub);
	}

	vsp1_rpf_write(rpf, dlb, VI6_RPF_SRC_BSIZE,
		       (crop.width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
		       (crop.height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
	vsp1_rpf_write(rpf, dlb, VI6_RPF_SRC_ESIZE,
		       (crop.width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
		       (crop.height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));

	mem.addr[0] += crop.top * format->plane_fmt[0].bytesperline
		     + crop.left * fmtinfo->bpp[0] / 8;

	if (format->num_planes > 1) {
		unsigned int offset;

		offset = crop.top * format->plane_fmt[1].bytesperline
		       + crop.left / fmtinfo->hsub
		       * fmtinfo->bpp[1] / 8;
		mem.addr[1] += offset;
		mem.addr[2] += offset;
	}

	/*
	 * On Gen3 hardware the SPUVS bit has no effect on 3-planar
	 * formats. Swap the U and V planes manually in that case.
	 */
	if (vsp1->info->gen == 3 && format->num_planes == 3 &&
	    fmtinfo->swap_uv)
		swap(mem.addr[1], mem.addr[2]);

	/*
	 * Interlaced pipelines will use the extended pre-cmd to process
	 * SRCM_ADDR_{Y,C0,C1}.
	 */
	if (pipe->interlaced) {
		vsp1_rpf_configure_autofld(rpf, dl);
	} else {
		vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_ADDR_Y, mem.addr[0]);
		vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_ADDR_C0, mem.addr[1]);
		vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_ADDR_C1, mem.addr[2]);
	}
}
Example #6
0
	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;
}