Re: [PATCH v3 10/11] media: vsp1: Support Interlaced display pipelines

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Kieran,

On Thursday, 3 May 2018 12:04:30 EEST Kieran Bingham wrote:
> Hi Reviewers ...
> 
> Comments inline ...
> 
> On 03/05/18 09:44, Kieran Bingham wrote:
> > Calculate the top and bottom fields for the interlaced frames and
> > utilise the extended display list command feature to implement the
> > auto-field operations. This allows the DU to update the VSP2 registers
> > dynamically based upon the currently processing field.
> > 
> > Signed-off-by: Kieran Bingham <kieran.bingham+renesas@xxxxxxxxxxxxxxxx>
> > 
> > ---
> > 
> > v3:
> >  - Pass DL through partition calls to allow autocmd's to be retrieved
> 
> This change itself could actually be folded into the TLB-Optimise series,
> but I posted this in v3 here to show why it is necessary (currently).
> 
> I'll take suggestions on alternative implementations here too ...

I think it would make sense to move this to the tlb-optimise series indeed. 
Provided this change is actually needed, which I will comment on when 
reviewing this series in details :-)

> >  - Document interlaced field in struct vsp1_du_atomic_config
> > 
> > v2:
> >  - fix erroneous BIT value which enabled interlaced
> >  - fix field handling at frame_end interrupt
> >  
> >  drivers/media/platform/vsp1/vsp1_dl.c     | 10 +++-
> >  drivers/media/platform/vsp1/vsp1_drm.c    | 13 +++-
> >  drivers/media/platform/vsp1/vsp1_entity.c |  3 +-
> >  drivers/media/platform/vsp1/vsp1_entity.h |  2 +-
> >  drivers/media/platform/vsp1/vsp1_regs.h   |  1 +-
> >  drivers/media/platform/vsp1/vsp1_rpf.c    | 73 +++++++++++++++++++++++-
> >  drivers/media/platform/vsp1/vsp1_rwpf.h   |  1 +-
> >  drivers/media/platform/vsp1/vsp1_uds.c    |  1 +-
> >  drivers/media/platform/vsp1/vsp1_video.c  |  2 +-
> >  drivers/media/platform/vsp1/vsp1_wpf.c    |  1 +-
> >  include/media/vsp1.h                      |  2 +-
> >  11 files changed, 103 insertions(+), 6 deletions(-)
> > 
> > diff --git a/drivers/media/platform/vsp1/vsp1_dl.c
> > b/drivers/media/platform/vsp1/vsp1_dl.c index 6366a1fc92b9..f3e75cff5ab3
> > 100644
> > --- a/drivers/media/platform/vsp1/vsp1_dl.c
> > +++ b/drivers/media/platform/vsp1/vsp1_dl.c
> > @@ -906,6 +906,8 @@ void vsp1_dl_list_commit(struct vsp1_dl_list *dl, bool
> > internal)
> >   */
> >  unsigned int vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm)
> >  {
> > +	struct vsp1_device *vsp1 = dlm->vsp1;
> > +	u32 status = vsp1_read(vsp1, VI6_STATUS);

In theory it would be nice to read this is early as possible, and thus pass it 
down the call stack to this function, but I suppose that if the interrupt 
handler ends up blocking for more than the duration of one field we'll have 
other problems anyway.

> >  	unsigned int flags = 0;
> >  	
> >  	spin_lock(&dlm->lock);
> > @@ -931,6 +933,14 @@ unsigned int vsp1_dlm_irq_frame_end(struct
> > vsp1_dl_manager *dlm)
> >  		goto done;
> >  	
> >  	/*
> > +	 * Progressive streams report only TOP fields. If we have a BOTTOM
> > +	 * field, we are interlaced, and expect the frame to complete on the
> > +	 * next frame end interrupt.
> > +	 */
> > +	if (status & VI6_STATUS_FLD_STD(dlm->index))
> > +		goto done;
> > +
> > +	/*
> >  	 * The device starts processing the queued display list right after the
> >  	 * frame end interrupt. The display list thus becomes active.
> >  	 */
> > diff --git a/drivers/media/platform/vsp1/vsp1_drm.c
> > b/drivers/media/platform/vsp1/vsp1_drm.c index 7714be7f50af..cc29c9d96bb7
> > 100644
> > --- a/drivers/media/platform/vsp1/vsp1_drm.c
> > +++ b/drivers/media/platform/vsp1/vsp1_drm.c
> > @@ -556,7 +556,7 @@ static void vsp1_du_pipeline_configure(struct
> > vsp1_pipeline *pipe)> 
> >  		vsp1_entity_route_setup(entity, pipe, dlb);
> >  		vsp1_entity_configure_stream(entity, pipe, dlb);
> >  		vsp1_entity_configure_frame(entity, pipe, dl, dlb);
> > -		vsp1_entity_configure_partition(entity, pipe, dlb);
> > +		vsp1_entity_configure_partition(entity, pipe, dl, dlb);
> 
> This change, and other changes to vsp1_entity_configure_partition() could be
> performed in tlb-optimise when the corresponding change is made to
> vsp1_entity_configure_frame()
> 
> >  	}
> >  	
> >  	vsp1_dl_list_commit(dl, drm_pipe->force_brx_release);
> > @@ -811,6 +811,17 @@ int vsp1_du_atomic_update(struct device *dev,
> > unsigned int pipe_index,
> >  		return -EINVAL;
> >  	}
> > 
> > +	if (!(vsp1_feature(vsp1, VSP1_HAS_EXT_DL)) && cfg->interlaced) {
> > +		/*
> > +		 * Interlaced support requires extended display lists to
> > +		 * provide the auto-fld feature with the DU.
> > +		 */
> > +		dev_dbg(vsp1->dev, "Interlaced unsupported on this output\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	rpf->interlaced = cfg->interlaced;
> > +
> >  	rpf->fmtinfo = fmtinfo;
> >  	rpf->format.num_planes = fmtinfo->planes;
> >  	rpf->format.plane_fmt[0].bytesperline = cfg->pitch;

[snip]

> > b/drivers/media/platform/vsp1/vsp1_rpf.c index a948670121a4..c1de22398423
> > 100644
> > --- a/drivers/media/platform/vsp1/vsp1_rpf.c
> > +++ b/drivers/media/platform/vsp1/vsp1_rpf.c
> > @@ -20,6 +20,20 @@
> >  #define RPF_MAX_WIDTH				8190
> >  #define RPF_MAX_HEIGHT				8190
> > 
> > +/* Pre extended display list command data structure */
> > +struct vsp1_extcmd_auto_fld_body {
> > +	u32 top_y0;
> > +	u32 bottom_y0;
> > +	u32 top_c0;
> > +	u32 bottom_c0;
> > +	u32 top_c1;
> > +	u32 bottom_c1;
> > +	u32 reserved0;
> > +	u32 reserved1;
> > +} __packed;
> > +
> > +#define VSP1_DL_EXT_AUTOFLD_INT		BIT(0)
> > +
> >  /* ----------------------------------------------------------------------
> >   * Device Access
> >   */
> > @@ -64,6 +78,14 @@ static void rpf_configure_stream(struct vsp1_entity
> > *entity,
> >  		pstride |= format->plane_fmt[1].bytesperline
> >  			<< VI6_RPF_SRCM_PSTRIDE_C_SHIFT;
> > 
> > +	/*
> > +	 * pstride has both STRIDE_Y and STRIDE_C, but multiplying the whole
> > +	 * of pstride by 2 is conveniently OK here as we are multiplying both
> > +	 * values.
> > +	 */
> > +	if (rpf->interlaced)
> > +		pstride *= 2;
> > +
> >  	vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_PSTRIDE, pstride);
> >  	
> >  	/* Format */
> > @@ -100,6 +122,9 @@ static void rpf_configure_stream(struct vsp1_entity
> > *entity,
> >  		top = compose->top;
> >  	}
> > 
> > +	if (rpf->interlaced)
> > +		top /= 2;
> > +
> >  	vsp1_rpf_write(rpf, dlb, VI6_RPF_LOC,
> >  		       (left << VI6_RPF_LOC_HCOORD_SHIFT) |
> >  		       (top << VI6_RPF_LOC_VCOORD_SHIFT));
> > @@ -169,6 +194,31 @@ static void rpf_configure_stream(struct vsp1_entity
> > *entity,
> >  }
> > 
> > +static void vsp1_rpf_configure_autofld(struct vsp1_rwpf *rpf,
> > +				       struct vsp1_dl_ext_cmd *cmd)
> > +{
> > +	const struct v4l2_pix_format_mplane *format = &rpf->format;
> > +	struct vsp1_extcmd_auto_fld_body *auto_fld = cmd->data;
> > +	u32 offset_y, offset_c;
> > +
> > +	/* Re-index our auto_fld to match the current RPF */
> > +	auto_fld = &auto_fld[rpf->entity.index];
> > +
> > +	auto_fld->top_y0 = rpf->mem.addr[0];
> > +	auto_fld->top_c0 = rpf->mem.addr[1];
> > +	auto_fld->top_c1 = rpf->mem.addr[2];
> > +
> > +	offset_y = format->plane_fmt[0].bytesperline;
> > +	offset_c = format->plane_fmt[1].bytesperline;
> > +
> > +	auto_fld->bottom_y0 = rpf->mem.addr[0] + offset_y;
> > +	auto_fld->bottom_c0 = rpf->mem.addr[1] + offset_c;
> > +	auto_fld->bottom_c1 = rpf->mem.addr[2] + offset_c;
> > +
> > +	cmd->flags |= VSP1_DL_EXT_AUTOFLD_INT;
> > +	cmd->flags |= BIT(16 + rpf->entity.index);
> > +}
> > +
> >  static void rpf_configure_frame(struct vsp1_entity *entity,
> >  				struct vsp1_pipeline *pipe,
> >  				struct vsp1_dl_list *dl,
> > @@ -186,11 +236,13 @@ static void rpf_configure_frame(struct vsp1_entity
> > *entity,
> >  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;
> > +	struct vsp1_dl_ext_cmd *cmd;
> >  	const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
> >  	const struct v4l2_pix_format_mplane *format = &rpf->format;
> >  	struct v4l2_rect crop;
> > @@ -219,6 +271,11 @@ static void rpf_configure_partition(struct
> > vsp1_entity *entity,
> >  		crop.left += pipe->partition->rpf.left;
> >  	}
> > 
> > +	if (rpf->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));
> > @@ -247,11 +304,21 @@ static void rpf_configure_partition(struct
> > vsp1_entity *entity,
> >  	    fmtinfo->swap_uv)
> >  		
> >  		swap(mem.addr[1], mem.addr[2]);
> > 
> > -	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]);
> > +	/*
> > +	 * Interlaced pipelines will use the extended pre-cmd to process
> > +	 * SRCM_ADDR_{Y,C0,C1}
> > +	 */
> > +	if (rpf->interlaced) {
> > +		cmd = vsp1_dlm_get_autofld_cmd(dl);
> > +		vsp1_rpf_configure_autofld(rpf, cmd);
> 
> Technically - if (rpf->interlaced) can only evaluate to true on DRM
> pipelines, which don't use the image partitioning. So it might be possible
> to argue that the vsp1_rpf_configure_autofld() call should be done in
> rpf_configure_frame(). Except I think it's reasonable to consider that the
> addresses and configuration of the frame are still just the 'first and only
> partition' - thus I think it's better to leave this here - and instead
> ensure that the requried DL is passed through.

I agree with you, that makes sense.

> Unless there's a better way to get the cmd object ?

There's none that immediately occurs to me.

> > +	} 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]);
> > +	}
> >  }
> > +
> >  static void rpf_partition(struct vsp1_entity *entity,
> >  			  struct vsp1_pipeline *pipe,
> >  			  struct vsp1_partition *partition,
> > diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h
> > b/drivers/media/platform/vsp1/vsp1_rwpf.h index
> > 70742ecf766f..8d6e42f27908 100644
> > --- a/drivers/media/platform/vsp1/vsp1_rwpf.h
> > +++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
> > @@ -42,6 +42,7 @@ struct vsp1_rwpf {
> >  	struct v4l2_pix_format_mplane format;
> >  	const struct vsp1_format_info *fmtinfo;
> >  	unsigned int brx_input;
> > +	bool interlaced;

kerneldoc might be nice :-)

> > 
> >  	unsigned int alpha;
> > 

[snip]

> > diff --git a/include/media/vsp1.h b/include/media/vsp1.h
> > index 678c24de1ac6..c10883f30980 100644
> > --- a/include/media/vsp1.h
> > +++ b/include/media/vsp1.h
> > @@ -50,6 +50,7 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int
> > pipe_index,> 
> >   * @dst: destination rectangle on the display (integer coordinates)
> >   * @alpha: alpha value (0: fully transparent, 255: fully opaque)
> >   * @zpos: Z position of the plane (from 0 to number of planes minus 1)
> > + * @interlaced: true for interlaced pipelines

Maybe "true if the pipeline outputs an interlaced stream" ?

> >   */
> >  struct vsp1_du_atomic_config {
> >  	u32 pixelformat;
> > 

-- 
Regards,

Laurent Pinchart



_______________________________________________
dri-devel mailing list
dri-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/dri-devel




[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux