diff options
Diffstat (limited to 'drivers/media/platform/vsp1/vsp1_wpf.c')
| -rw-r--r-- | drivers/media/platform/vsp1/vsp1_wpf.c | 340 | 
1 files changed, 178 insertions, 162 deletions
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index 8bd6b2f1af15..23c8f706b3f2 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0+  /*   * vsp1_wpf.c  --  R-Car VSP1 Write Pixel Formatter   *   * Copyright (C) 2013-2014 Renesas Electronics Corporation   *   * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version.   */  #include <linux/device.h> @@ -31,9 +27,9 @@   */  static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf, -				  struct vsp1_dl_list *dl, u32 reg, u32 data) +				  struct vsp1_dl_body *dlb, u32 reg, u32 data)  { -	vsp1_dl_list_write(dl, reg + wpf->entity.index * VI6_WPF_OFFSET, data); +	vsp1_dl_body_write(dlb, reg + wpf->entity.index * VI6_WPF_OFFSET, data);  }  /* ----------------------------------------------------------------------------- @@ -236,10 +232,9 @@ static void vsp1_wpf_destroy(struct vsp1_entity *entity)  	vsp1_dlm_destroy(wpf->dlm);  } -static void wpf_configure(struct vsp1_entity *entity, -			  struct vsp1_pipeline *pipe, -			  struct vsp1_dl_list *dl, -			  enum vsp1_entity_params params) +static void wpf_configure_stream(struct vsp1_entity *entity, +				 struct vsp1_pipeline *pipe, +				 struct vsp1_dl_body *dlb)  {  	struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);  	struct vsp1_device *vsp1 = wpf->entity.vsp1; @@ -249,149 +244,12 @@ static void wpf_configure(struct vsp1_entity *entity,  	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; -		const struct vsp1_format_info *fmtinfo = wpf->fmtinfo; -		struct vsp1_rwpf_memory mem = wpf->mem; -		unsigned int flip = wpf->flip.active; -		unsigned int width = sink_format->width; -		unsigned int height = sink_format->height; -		unsigned int offset; - -		/* -		 * Cropping. The partition algorithm can split the image into -		 * multiple slices. -		 */ -		if (pipe->partitions > 1) -			width = pipe->partition->wpf.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 any corner of the -		 * image depending on the combination of flipping and rotation. -		 */ - -		/* -		 * First take the partition left coordinate into account. -		 * Compute the offset to order the partitions correctly on the -		 * output based on whether flipping is enabled. Consider -		 * horizontal flipping when rotation is disabled but vertical -		 * flipping when rotation is enabled, as rotating the image -		 * switches the horizontal and vertical directions. The offset -		 * is applied horizontally or vertically accordingly. -		 */ -		if (flip & BIT(WPF_CTRL_HFLIP) && !wpf->flip.rotate) -			offset = format->width - pipe->partition->wpf.left -				- pipe->partition->wpf.width; -		else if (flip & BIT(WPF_CTRL_VFLIP) && wpf->flip.rotate) -			offset = format->height - pipe->partition->wpf.left -				- pipe->partition->wpf.width; -		else -			offset = pipe->partition->wpf.left; - -		for (i = 0; i < format->num_planes; ++i) { -			unsigned int hsub = i > 0 ? fmtinfo->hsub : 1; -			unsigned int vsub = i > 0 ? fmtinfo->vsub : 1; - -			if (wpf->flip.rotate) -				mem.addr[i] += offset / vsub -					     * format->plane_fmt[i].bytesperline; -			else -				mem.addr[i] += offset / hsub -					     * fmtinfo->bpp[i] / 8; -		} - -		if (flip & BIT(WPF_CTRL_VFLIP)) { -			/* -			 * When rotating the output (after rotation) image -			 * height is equal to the partition width (before -			 * rotation). Otherwise it is equal to the output -			 * image height. -			 */ -			if (wpf->flip.rotate) -				height = pipe->partition->wpf.width; -			else -				height = format->height; - -			mem.addr[0] += (height - 1) -				     * format->plane_fmt[0].bytesperline; - -			if (format->num_planes > 1) { -				offset = (height / fmtinfo->vsub - 1) -				       * format->plane_fmt[1].bytesperline; -				mem.addr[1] += offset; -				mem.addr[2] += offset; -			} -		} - -		if (wpf->flip.rotate && !(flip & BIT(WPF_CTRL_HFLIP))) { -			unsigned int hoffset = max(0, (int)format->width - 16); - -			/* -			 * Compute the output coordinate. The partition -			 * horizontal (left) offset becomes a vertical offset. -			 */ -			for (i = 0; i < format->num_planes; ++i) { -				unsigned int hsub = i > 0 ? fmtinfo->hsub : 1; - -				mem.addr[i] += hoffset / hsub -					     * fmtinfo->bpp[i] / 8; -			} -		} - -		/* -		 * 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]); - -		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; @@ -410,17 +268,17 @@ static void wpf_configure(struct vsp1_entity *entity,  			outfmt |= VI6_WPF_OUTFMT_SPUVS;  		/* Destination stride and byte swapping. */ -		vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_STRIDE_Y, +		vsp1_wpf_write(wpf, dlb, 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, +			vsp1_wpf_write(wpf, dlb, VI6_WPF_DSTM_STRIDE_C,  				       format->plane_fmt[1].bytesperline); -		vsp1_wpf_write(wpf, dl, VI6_WPF_DSWAP, fmtinfo->swap); +		vsp1_wpf_write(wpf, dlb, 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, +			vsp1_wpf_write(wpf, dlb, VI6_WPF_ROT_CTRL,  				       VI6_WPF_ROT_CTRL_LN16 |  				       (256 << VI6_WPF_ROT_CTRL_LMEM_WD_SHIFT));  	} @@ -430,13 +288,13 @@ static void wpf_configure(struct vsp1_entity *entity,  	wpf->outfmt = outfmt; -	vsp1_dl_list_write(dl, VI6_DPR_WPF_FPORCH(wpf->entity.index), +	vsp1_dl_body_write(dlb, VI6_DPR_WPF_FPORCH(wpf->entity.index),  			   VI6_DPR_WPF_FPORCH_FP_WPFN); -	vsp1_dl_list_write(dl, VI6_WPF_WRBCK_CTRL, 0); +	vsp1_dl_body_write(dlb, VI6_WPF_WRBCK_CTRL, 0);  	/* -	 * Sources. If the pipeline has a single input and BRU is not used, +	 * Sources. If the pipeline has a single input and BRx 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. @@ -447,24 +305,180 @@ static void wpf_configure(struct vsp1_entity *entity,  		if (!input)  			continue; -		srcrpf |= (!pipe->bru && pipe->num_inputs == 1) +		srcrpf |= (!pipe->brx && 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) -		srcrpf |= pipe->bru->type == VSP1_ENTITY_BRU +	if (pipe->brx) +		srcrpf |= pipe->brx->type == VSP1_ENTITY_BRU  			? VI6_WPF_SRCRPF_VIRACT_MST  			: VI6_WPF_SRCRPF_VIRACT2_MST; -	vsp1_wpf_write(wpf, dl, VI6_WPF_SRCRPF, srcrpf); +	vsp1_wpf_write(wpf, dlb, 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), +	vsp1_dl_body_write(dlb, VI6_WPF_IRQ_STA(wpf->entity.index), 0); +	vsp1_dl_body_write(dlb, VI6_WPF_IRQ_ENB(wpf->entity.index),  			   VI6_WFP_IRQ_ENB_DFEE);  } +static void wpf_configure_frame(struct vsp1_entity *entity, +				struct vsp1_pipeline *pipe, +				struct vsp1_dl_list *dl, +				struct vsp1_dl_body *dlb) +{ +	const unsigned int mask = BIT(WPF_CTRL_VFLIP) +				| BIT(WPF_CTRL_HFLIP); +	struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev); +	unsigned long flags; +	u32 outfmt; + +	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, dlb, VI6_WPF_OUTFMT, outfmt); +} + +static void wpf_configure_partition(struct vsp1_entity *entity, +				    struct vsp1_pipeline *pipe, +				    struct vsp1_dl_list *dl, +				    struct vsp1_dl_body *dlb) +{ +	struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev); +	struct vsp1_device *vsp1 = wpf->entity.vsp1; +	struct vsp1_rwpf_memory mem = wpf->mem; +	const struct v4l2_mbus_framefmt *sink_format; +	const struct v4l2_pix_format_mplane *format = &wpf->format; +	const struct vsp1_format_info *fmtinfo = wpf->fmtinfo; +	unsigned int width; +	unsigned int height; +	unsigned int offset; +	unsigned int flip; +	unsigned int i; + +	sink_format = vsp1_entity_get_pad_format(&wpf->entity, +						 wpf->entity.config, +						 RWPF_PAD_SINK); +	width = sink_format->width; +	height = sink_format->height; + +	/* +	 * Cropping. The partition algorithm can split the image into +	 * multiple slices. +	 */ +	if (pipe->partitions > 1) +		width = pipe->partition->wpf.width; + +	vsp1_wpf_write(wpf, dlb, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN | +		       (0 << VI6_WPF_SZCLIP_OFST_SHIFT) | +		       (width << VI6_WPF_SZCLIP_SIZE_SHIFT)); +	vsp1_wpf_write(wpf, dlb, 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 any corner of the +	 * image depending on the combination of flipping and rotation. +	 */ + +	/* +	 * First take the partition left coordinate into account. +	 * Compute the offset to order the partitions correctly on the +	 * output based on whether flipping is enabled. Consider +	 * horizontal flipping when rotation is disabled but vertical +	 * flipping when rotation is enabled, as rotating the image +	 * switches the horizontal and vertical directions. The offset +	 * is applied horizontally or vertically accordingly. +	 */ +	flip = wpf->flip.active; + +	if (flip & BIT(WPF_CTRL_HFLIP) && !wpf->flip.rotate) +		offset = format->width - pipe->partition->wpf.left +			- pipe->partition->wpf.width; +	else if (flip & BIT(WPF_CTRL_VFLIP) && wpf->flip.rotate) +		offset = format->height - pipe->partition->wpf.left +			- pipe->partition->wpf.width; +	else +		offset = pipe->partition->wpf.left; + +	for (i = 0; i < format->num_planes; ++i) { +		unsigned int hsub = i > 0 ? fmtinfo->hsub : 1; +		unsigned int vsub = i > 0 ? fmtinfo->vsub : 1; + +		if (wpf->flip.rotate) +			mem.addr[i] += offset / vsub +				     * format->plane_fmt[i].bytesperline; +		else +			mem.addr[i] += offset / hsub +				     * fmtinfo->bpp[i] / 8; +	} + +	if (flip & BIT(WPF_CTRL_VFLIP)) { +		/* +		 * When rotating the output (after rotation) image +		 * height is equal to the partition width (before +		 * rotation). Otherwise it is equal to the output +		 * image height. +		 */ +		if (wpf->flip.rotate) +			height = pipe->partition->wpf.width; +		else +			height = format->height; + +		mem.addr[0] += (height - 1) +			     * format->plane_fmt[0].bytesperline; + +		if (format->num_planes > 1) { +			offset = (height / fmtinfo->vsub - 1) +			       * format->plane_fmt[1].bytesperline; +			mem.addr[1] += offset; +			mem.addr[2] += offset; +		} +	} + +	if (wpf->flip.rotate && !(flip & BIT(WPF_CTRL_HFLIP))) { +		unsigned int hoffset = max(0, (int)format->width - 16); + +		/* +		 * Compute the output coordinate. The partition +		 * horizontal (left) offset becomes a vertical offset. +		 */ +		for (i = 0; i < format->num_planes; ++i) { +			unsigned int hsub = i > 0 ? fmtinfo->hsub : 1; + +			mem.addr[i] += hoffset / hsub +				     * fmtinfo->bpp[i] / 8; +		} +	} + +	/* +	 * 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]); + +	vsp1_wpf_write(wpf, dlb, VI6_WPF_DSTM_ADDR_Y, mem.addr[0]); +	vsp1_wpf_write(wpf, dlb, VI6_WPF_DSTM_ADDR_C0, mem.addr[1]); +	vsp1_wpf_write(wpf, dlb, VI6_WPF_DSTM_ADDR_C1, mem.addr[2]); +} +  static unsigned int wpf_max_width(struct vsp1_entity *entity,  				  struct vsp1_pipeline *pipe)  { @@ -484,7 +498,9 @@ static void wpf_partition(struct vsp1_entity *entity,  static const struct vsp1_entity_operations wpf_entity_ops = {  	.destroy = vsp1_wpf_destroy, -	.configure = wpf_configure, +	.configure_stream = wpf_configure_stream, +	.configure_frame = wpf_configure_frame, +	.configure_partition = wpf_configure_partition,  	.max_width = wpf_max_width,  	.partition = wpf_partition,  };  | 
