Example #1
0
static inline void vsp1_lif_write(struct vsp1_lif *lif, struct vsp1_dl_list *dl,
				  u32 reg, u32 data)
{
	vsp1_dl_list_write(dl, reg, data);
}
Example #2
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 #3
0
static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf,
				  struct vsp1_dl_list *dl, u32 reg, u32 data)
{
	vsp1_dl_list_write(dl, reg + wpf->entity.index * VI6_WPF_OFFSET, data);
}
Example #4
0
static inline void vsp1_hsit_write(struct vsp1_hsit *hsit,
				   struct vsp1_dl_list *dl, u32 reg, u32 data)
{
	vsp1_dl_list_write(dl, reg, data);
}
Example #5
0
static inline void vsp1_clu_write(struct vsp1_clu *clu, struct vsp1_dl_list *dl,
				  u32 reg, u32 data)
{
	vsp1_dl_list_write(dl, reg, data);
}
Example #6
0
static void wpf_configure(struct vsp1_entity *entity,
			  struct vsp1_pipeline *pipe,
			  struct vsp1_dl_list *dl,
			  enum vsp1_entity_params params)
{
	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;
	unsigned int i;
	u32 outfmt = 0;
	u32 srcrpf = 0;

	if (params == VSP1_ENTITY_PARAMS_RUNTIME) {
		const unsigned int mask = BIT(WPF_CTRL_VFLIP)
					| BIT(WPF_CTRL_HFLIP);
		unsigned long flags;

		spin_lock_irqsave(&wpf->flip.lock, flags);
		wpf->flip.active = (wpf->flip.active & ~mask)
				 | (wpf->flip.pending & mask);
		spin_unlock_irqrestore(&wpf->flip.lock, flags);

		outfmt = (wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT) | wpf->outfmt;

		if (wpf->flip.active & BIT(WPF_CTRL_VFLIP))
			outfmt |= VI6_WPF_OUTFMT_FLP;
		if (wpf->flip.active & BIT(WPF_CTRL_HFLIP))
			outfmt |= VI6_WPF_OUTFMT_HFLP;

		vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, outfmt);
		return;
	}

	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 (params == VSP1_ENTITY_PARAMS_PARTITION) {
		const struct v4l2_pix_format_mplane *format = &wpf->format;
		struct vsp1_rwpf_memory mem = wpf->mem;
		unsigned int flip = wpf->flip.active;
		unsigned int width = source_format->width;
		unsigned int height = source_format->height;
		unsigned int offset;

		/*
		 * Cropping. The partition algorithm can split the image into
		 * multiple slices.
		 */
		if (pipe->partitions > 1)
			width = pipe->partition.width;

		vsp1_wpf_write(wpf, dl, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
			       (0 << VI6_WPF_SZCLIP_OFST_SHIFT) |
			       (width << VI6_WPF_SZCLIP_SIZE_SHIFT));
		vsp1_wpf_write(wpf, dl, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN |
			       (0 << VI6_WPF_SZCLIP_OFST_SHIFT) |
			       (height << VI6_WPF_SZCLIP_SIZE_SHIFT));

		if (pipe->lif)
			return;

		/*
		 * Update the memory offsets based on flipping configuration.
		 * The destination addresses point to the locations where the
		 * VSP starts writing to memory, which can be different corners
		 * of the image depending on vertical flipping.
		 */
		if (pipe->partitions > 1) {
			const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;

			/*
			 * Horizontal flipping is handled through a line buffer
			 * and doesn't modify the start address, but still needs
			 * to be handled when image partitioning is in effect to
			 * order the partitions correctly.
			 */
			if (flip & BIT(WPF_CTRL_HFLIP))
				offset = format->width - pipe->partition.left
					- pipe->partition.width;
			else
				offset = pipe->partition.left;

			mem.addr[0] += offset * fmtinfo->bpp[0] / 8;
			if (format->num_planes > 1) {
				mem.addr[1] += offset / fmtinfo->hsub
					     * fmtinfo->bpp[1] / 8;
				mem.addr[2] += offset / fmtinfo->hsub
					     * fmtinfo->bpp[2] / 8;
			}
		}

		if (flip & BIT(WPF_CTRL_VFLIP)) {
			mem.addr[0] += (format->height - 1)
				     * format->plane_fmt[0].bytesperline;

			if (format->num_planes > 1) {
				offset = (format->height / wpf->fmtinfo->vsub - 1)
				       * format->plane_fmt[1].bytesperline;
				mem.addr[1] += offset;
				mem.addr[2] += offset;
			}
		}

		vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, mem.addr[0]);
		vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, mem.addr[1]);
		vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, mem.addr[2]);
		return;
	}

	/* Format */
	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 (vsp1->info->features & VSP1_HAS_WPF_HFLIP &&
		    wpf->entity.index == 0)
			vsp1_wpf_write(wpf, dl, VI6_WPF_ROT_CTRL,
				       VI6_WPF_ROT_CTRL_LN16 |
				       (256 << VI6_WPF_ROT_CTRL_LMEM_WD_SHIFT));
	}

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

	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_DFEE);
}