[PATCH v5 07/19] media: vsp1: dl: Support one-shot entries in the display list

Brian Starkey Brian.Starkey at arm.com
Fri Feb 22 14:30:03 UTC 2019


Hi Laurent,

On Thu, Feb 21, 2019 at 12:32:00PM +0200, Laurent Pinchart wrote:
> One-shot entries are used as an alternative to committing a complete new
> display list when a couple of registers need to be written for one frame
> and then reset to another value for all subsequent frames. This will be
> used to implement writeback support that will need to enable writeback
> for the duration of a single frame.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas at ideasonboard.com>
> ---
>  drivers/media/platform/vsp1/vsp1_dl.c | 78 +++++++++++++++++++++++++++
>  drivers/media/platform/vsp1/vsp1_dl.h |  3 ++
>  2 files changed, 81 insertions(+)
> 
> diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
> index 886b3a69d329..7b4d252bfde7 100644
> --- a/drivers/media/platform/vsp1/vsp1_dl.c
> +++ b/drivers/media/platform/vsp1/vsp1_dl.c
> @@ -115,6 +115,12 @@ struct vsp1_dl_body {
>  
>  	unsigned int num_entries;
>  	unsigned int max_entries;
> +
> +	unsigned int num_patches;
> +	struct {
> +		struct vsp1_dl_entry *entry;
> +		u32 data;
> +	} patches[2];
>  };
>  
>  /**
> @@ -361,6 +367,7 @@ void vsp1_dl_body_put(struct vsp1_dl_body *dlb)
>  		return;
>  
>  	dlb->num_entries = 0;
> +	dlb->num_patches = 0;
>  
>  	spin_lock_irqsave(&dlb->pool->lock, flags);
>  	list_add_tail(&dlb->free, &dlb->pool->free);
> @@ -388,6 +395,47 @@ void vsp1_dl_body_write(struct vsp1_dl_body *dlb, u32 reg, u32 data)
>  	dlb->num_entries++;
>  }
>  
> +/**
> + * vsp1_dl_body_write_oneshot - Write a register to a display list body for a
> + *	single frame
> + * @dlb: The body
> + * @reg: The register address
> + * @value: The register value
> + * @reset_value: The value to reset the register to at the next vblank
> + *
> + * Display lists in continuous mode are re-used by the hardware for successive
> + * frames until a new display list is committed. Changing the VSP configuration
> + * normally requires creating and committing a new display list. This function
> + * offers an alternative race-free way by writing a @value to the @register in
> + * the display list body for a single frame, specifying in @reset_value the
> + * value to reset the register to one vblank after the display list is
> + * committed.
> + *
> + * The maximum number of one-shot entries is limited to 2 per display list body,
> + * and one-shot entries are counted in the total number of entries specified
> + * when the body is allocated by vsp1_dl_body_alloc().
> + */
> +void vsp1_dl_body_write_oneshot(struct vsp1_dl_body *dlb, u32 reg, u32 value,
> +				u32 reset_value)
> +{
> +	if (WARN_ONCE(dlb->num_entries >= dlb->max_entries,
> +		      "DLB size exceeded (max %u)", dlb->max_entries))
> +		return;
> +
> +	if (WARN_ONCE(dlb->num_patches >= ARRAY_SIZE(dlb->patches),
> +		      "DLB patches size exceeded (max %zu)",
> +		      ARRAY_SIZE(dlb->patches)))
> +		return;
> +
> +	dlb->patches[dlb->num_patches].entry = &dlb->entries[dlb->num_entries];
> +	dlb->patches[dlb->num_patches].data = reset_value;
> +	dlb->num_patches++;
> +
> +	dlb->entries[dlb->num_entries].addr = reg;
> +	dlb->entries[dlb->num_entries].data = value;
> +	dlb->num_entries++;
> +}
> +
>  /* -----------------------------------------------------------------------------
>   * Display List Extended Command Management
>   */
> @@ -652,6 +700,7 @@ static void __vsp1_dl_list_put(struct vsp1_dl_list *dl)
>  	 * has at least one body, thus we reinitialise the entries list.
>  	 */
>  	dl->body0->num_entries = 0;
> +	dl->body0->num_patches = 0;
>  
>  	list_add_tail(&dl->list, &dl->dlm->free);
>  }
> @@ -930,6 +979,35 @@ void vsp1_dl_list_commit(struct vsp1_dl_list *dl, unsigned int dl_flags)
>   * Display List Manager
>   */
>  
> +/**
> + * vsp1_dlm_irq_display_start - Display list handler for the display start
> + *	interrupt
> + * @dlm: the display list manager
> + *
> + * Apply all one-shot patches registered for the active display list.
> + */
> +void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm)
> +{
> +	struct vsp1_dl_body *dlb;
> +	struct vsp1_dl_list *dl;
> +	unsigned int i;
> +
> +	spin_lock(&dlm->lock);
> +
> +	dl = dlm->active;
> +	if (!dl)
> +		goto done;
> +
> +	list_for_each_entry(dlb, &dl->bodies, list) {
> +		for (i = 0; i < dlb->num_patches; ++i)
> +			dlb->patches[i].entry->data = dlb->patches[i].data;
> +		dlb->num_patches = 0;
> +	}
> +
> +done:
> +	spin_unlock(&dlm->lock);
> +}
> +

We've got some HW which doesn't support one-shot writeback, and use a
similar trick to try and disable writeback immediately after the flip.

We ran into issues where the "start" interrupt wouldn't run in time to
make sure the writeback disable was committed before the next frame.
We have to keep track of whether the disable really happened in time,
before we release the output buffer.

Might you have a similar problem here?

Thanks,
-Brian

>  /**
>   * vsp1_dlm_irq_frame_end - Display list handler for the frame end interrupt
>   * @dlm: the display list manager
> diff --git a/drivers/media/platform/vsp1/vsp1_dl.h b/drivers/media/platform/vsp1/vsp1_dl.h
> index e0fdb145e6ed..f845607abc4c 100644
> --- a/drivers/media/platform/vsp1/vsp1_dl.h
> +++ b/drivers/media/platform/vsp1/vsp1_dl.h
> @@ -54,6 +54,7 @@ struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1,
>  					unsigned int prealloc);
>  void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm);
>  void vsp1_dlm_reset(struct vsp1_dl_manager *dlm);
> +void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm);
>  unsigned int vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm);
>  struct vsp1_dl_body *vsp1_dlm_dl_body_get(struct vsp1_dl_manager *dlm);
>  
> @@ -71,6 +72,8 @@ struct vsp1_dl_body *vsp1_dl_body_get(struct vsp1_dl_body_pool *pool);
>  void vsp1_dl_body_put(struct vsp1_dl_body *dlb);
>  
>  void vsp1_dl_body_write(struct vsp1_dl_body *dlb, u32 reg, u32 data);
> +void vsp1_dl_body_write_oneshot(struct vsp1_dl_body *dlb, u32 reg, u32 value,
> +				u32 reset_value);
>  int vsp1_dl_list_add_body(struct vsp1_dl_list *dl, struct vsp1_dl_body *dlb);
>  int vsp1_dl_list_add_chain(struct vsp1_dl_list *head, struct vsp1_dl_list *dl);
>  
> -- 
> Regards,
> 
> Laurent Pinchart
> 


More information about the dri-devel mailing list