[PATCH v6 08/18] media: vsp1: wpf: Add writeback support

Laurent Pinchart laurent.pinchart at ideasonboard.com
Wed Mar 13 11:15:24 UTC 2019


Hi Kieran,

On Wed, Mar 13, 2019 at 10:59:18AM +0000, Kieran Bingham wrote:
> On 13/03/2019 00:05, Laurent Pinchart wrote:
> > Add support for the writeback feature of the WPF, to enable capturing
> > frames at the WPF output for display pipelines. To enable writeback the
> > vsp1_rwpf structure mem field must be set to the address of the
> > writeback buffer and the writeback field set to true before the WPF
> > .configure_stream() and .configure_partition() are called. The WPF will
> > enable writeback in the display list for a single frame, and writeback
> > will then be automatically disabled.
> 
> This looks good.
> 
> Took some time to go through it while I argue with myself, but I think I
> reached an agreement with me in the end :)
> 
> Reviewed-by: Kieran Bingham <kieran.bingham+renesas at ideasonboard.com>
> 
> > Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas at ideasonboard.com>
> > ---
> >  drivers/media/platform/vsp1/vsp1_rwpf.h |  2 +
> >  drivers/media/platform/vsp1/vsp1_wpf.c  | 73 ++++++++++++++++++++++---
> >  2 files changed, 66 insertions(+), 9 deletions(-)
> > 
> > diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
> > index 70742ecf766f..910990b27617 100644
> > --- a/drivers/media/platform/vsp1/vsp1_rwpf.h
> > +++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
> > @@ -35,6 +35,7 @@ struct vsp1_rwpf {
> >  	struct v4l2_ctrl_handler ctrls;
> >  
> >  	struct vsp1_video *video;
> > +	bool has_writeback;
> >  
> >  	unsigned int max_width;
> >  	unsigned int max_height;
> > @@ -61,6 +62,7 @@ struct vsp1_rwpf {
> >  	} flip;
> >  
> >  	struct vsp1_rwpf_memory mem;
> > +	bool writeback;
> 
> Does this need to be initialised to false somewhere?
> 
> answering my own question;
>  No - because we allocate the "struct vsp1_rwpf *wpf" with devm_kzalloc.
> 
> >  	struct vsp1_dl_manager *dlm;
> >  };
> > diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
> > index fc5c1b0f6633..390ac478336d 100644
> > --- a/drivers/media/platform/vsp1/vsp1_wpf.c
> > +++ b/drivers/media/platform/vsp1/vsp1_wpf.c
> > @@ -232,6 +232,27 @@ static void vsp1_wpf_destroy(struct vsp1_entity *entity)
> >  	vsp1_dlm_destroy(wpf->dlm);
> >  }
> >  
> > +static int wpf_configure_writeback_chain(struct vsp1_rwpf *wpf,
> > +					 struct vsp1_dl_list *dl)
> > +{
> > +	unsigned int index = wpf->entity.index;
> > +	struct vsp1_dl_list *dl_next;
> > +	struct vsp1_dl_body *dlb;
> > +
> > +	dl_next = vsp1_dl_list_get(wpf->dlm);> +	if (!dl_next) {
> > +		dev_err(wpf->entity.vsp1->dev,
> > +			"Failed to obtain a dl list, disabling writeback\n");
> > +		return -ENOMEM;
> > +	}
> > +
> > +	dlb = vsp1_dl_list_get_body0(dl_next);
> > +	vsp1_dl_body_write(dlb, VI6_WPF_WRBCK_CTRL(index), 0);
> > +	vsp1_dl_list_add_chain(dl, dl_next);
> 
> Two thoughts for future consideration.
> 
> 1) There was a patch I had floated to reduce the allocations of the pool
> sizes. This would need to be checked if it's ever reconsidered, as we
> now use an extra DL.
> 
> This is currently allocated as 64 lists in vsp1_wpf_create() with:
> 
>  	wpf->dlm = vsp1_dlm_create(vsp1, index, 64);
> 
> which is actually 65 lists because there's a + 1 in vsp1_dlm_create(),
> so I think we have more than we'll ever need for a display pipeline
> currently.
> 
> 
> 2) I did think we could pre-allocate this write back display list and
> re-use it, by always attaching the same "writeback disable display list"
> to the chain.
> 
> If we do that - we'll have to be careful about the refcounting of the
> chained list as it will automatically be put back on to the dlm->free
> list currently when the frame completes.

Yes, and that's why I haven't done so yet. I think it can be implemented
on top of this series as it's an optimization.

> I think it's probably only a small optimisation to re-use the list
> anyway, so just getting a new one and chaining it is certainly adequate
> for this solution.
> 
> > +
> > +	return 0;
> > +}
> > +
> >  static void wpf_configure_stream(struct vsp1_entity *entity,
> >  				 struct vsp1_pipeline *pipe,
> >  				 struct vsp1_dl_list *dl,
> > @@ -241,9 +262,11 @@ static void wpf_configure_stream(struct vsp1_entity *entity,
> >  	struct vsp1_device *vsp1 = wpf->entity.vsp1;
> >  	const struct v4l2_mbus_framefmt *source_format;
> >  	const struct v4l2_mbus_framefmt *sink_format;
> > +	unsigned int index = wpf->entity.index;
> >  	unsigned int i;
> >  	u32 outfmt = 0;
> >  	u32 srcrpf = 0;
> > +	int ret;
> >  
> >  	sink_format = vsp1_entity_get_pad_format(&wpf->entity,
> >  						 wpf->entity.config,
> > @@ -251,8 +274,9 @@ static void wpf_configure_stream(struct vsp1_entity *entity,
> >  	source_format = vsp1_entity_get_pad_format(&wpf->entity,
> >  						   wpf->entity.config,
> >  						   RWPF_PAD_SOURCE);
> > +
> >  	/* Format */
> > -	if (!pipe->lif) {
> > +	if (!pipe->lif || wpf->writeback) {
> >  		const struct v4l2_pix_format_mplane *format = &wpf->format;
> >  		const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
> >  
> > @@ -277,8 +301,7 @@ static void wpf_configure_stream(struct vsp1_entity *entity,
> >  
> >  		vsp1_wpf_write(wpf, dlb, VI6_WPF_DSWAP, fmtinfo->swap);
> >  
> > -		if (vsp1_feature(vsp1, VSP1_HAS_WPF_HFLIP) &&
> > -		    wpf->entity.index == 0)
> > +		if (vsp1_feature(vsp1, VSP1_HAS_WPF_HFLIP) && index == 0)
> >  			vsp1_wpf_write(wpf, dlb, VI6_WPF_ROT_CTRL,
> >  				       VI6_WPF_ROT_CTRL_LN16 |
> >  				       (256 << VI6_WPF_ROT_CTRL_LMEM_WD_SHIFT));
> > @@ -289,11 +312,9 @@ static void wpf_configure_stream(struct vsp1_entity *entity,
> >  
> >  	wpf->outfmt = outfmt;
> >  
> > -	vsp1_dl_body_write(dlb, VI6_DPR_WPF_FPORCH(wpf->entity.index),
> > +	vsp1_dl_body_write(dlb, VI6_DPR_WPF_FPORCH(index),
> >  			   VI6_DPR_WPF_FPORCH_FP_WPFN);
> >  
> > -	vsp1_dl_body_write(dlb, VI6_WPF_WRBCK_CTRL(wpf->entity.index), 0);
> > -
> >  	/*
> >  	 * Sources. If the pipeline has a single input and BRx is not used,
> >  	 * configure it as the master layer. Otherwise configure all
> > @@ -319,9 +340,26 @@ static void wpf_configure_stream(struct vsp1_entity *entity,
> >  	vsp1_wpf_write(wpf, dlb, VI6_WPF_SRCRPF, srcrpf);
> >  
> >  	/* Enable interrupts. */
> > -	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),
> > +	vsp1_dl_body_write(dlb, VI6_WPF_IRQ_STA(index), 0);
> > +	vsp1_dl_body_write(dlb, VI6_WPF_IRQ_ENB(index),
> >  			   VI6_WFP_IRQ_ENB_DFEE);
> > +
> > +	/*
> > +	 * Configure writeback for display pipelines (the wpf writeback flag is
> > +	 * never set for memory-to-memory pipelines). Start by adding a chained
> > +	 * display list to disable writeback after a single frame, and process
> > +	 * to enable writeback. If the display list allocation fails don't
> > +	 * enable writeback as we wouldn't be able to safely disable it,
> > +	 * resulting in possible memory corruption.
> > +	 */
> > +	if (wpf->writeback) {
> > +		ret = wpf_configure_writeback_chain(wpf, dl);
> > +		if (ret < 0)
> > +			wpf->writeback = false;
> > +	}
> > +
> > +	vsp1_dl_body_write(dlb, VI6_WPF_WRBCK_CTRL(index),
> > +			   wpf->writeback ? VI6_WPF_WRBCK_CTRL_WBMD : 0);
> >  }
> >  
> >  static void wpf_configure_frame(struct vsp1_entity *entity,
> > @@ -391,7 +429,11 @@ static void wpf_configure_partition(struct vsp1_entity *entity,
> >  		       (0 << VI6_WPF_SZCLIP_OFST_SHIFT) |
> >  		       (height << VI6_WPF_SZCLIP_SIZE_SHIFT));
> >  
> > -	if (pipe->lif)
> > +	/*
> > +	 * For display pipelines without writeback enabled there's no memory
> > +	 * address to configure, return now.
> > +	 */
> > +	if (pipe->lif && !wpf->writeback)
> >  		return;
> >  
> >  	/*
> > @@ -480,6 +522,12 @@ static void wpf_configure_partition(struct vsp1_entity *entity,
> >  	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]);
> > +
> > +	/*
> > +	 * Writeback operates in single-shot mode and lasts for a single frame,
> > +	 * reset the writeback flag to false for the next frame.
> > +	 */
> > +	wpf->writeback = false;
> >  }
> >  
> >  static unsigned int wpf_max_width(struct vsp1_entity *entity,
> > @@ -530,6 +578,13 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
> >  		wpf->max_height = WPF_GEN3_MAX_HEIGHT;
> >  	}
> >  
> > +	/*
> > +	 * On Gen3 WPFs with a LIF output can also write to memory for display
> > +	 * writeback.
> > +	 */
> > +	if (vsp1->info->gen > 2 && index < vsp1->info->lif_count)
> > +		wpf->has_writeback = true;
> > +
> >  	wpf->entity.ops = &wpf_entity_ops;
> >  	wpf->entity.type = VSP1_ENTITY_WPF;
> >  	wpf->entity.index = index;

-- 
Regards,

Laurent Pinchart


More information about the dri-devel mailing list