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.
Signed-off-by: Laurent Pinchart laurent.pinchart+renesas@ideasonboard.com --- drivers/media/platform/vsp1/vsp1_drv.c | 15 +++++++ drivers/media/platform/vsp1/vsp1_pipe.c | 5 +++ drivers/media/platform/vsp1/vsp1_pipe.h | 1 + drivers/media/platform/vsp1/vsp1_rwpf.h | 2 + drivers/media/platform/vsp1/vsp1_wpf.c | 52 ++++++++++++++++++++----- 5 files changed, 66 insertions(+), 9 deletions(-)
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index c650e45bb0ad..22709f6f2a0c 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -63,6 +63,21 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data) vsp1_pipeline_frame_end(wpf->entity.pipe); ret = IRQ_HANDLED; } + + /* + * Process the display start interrupt after the frame end + * interrupt to make sure the display list queue is correctly + * updated when processing the display start. + */ + if (wpf->has_writeback) { + status = vsp1_read(vsp1, VI6_DISP_IRQ_STA(i)); + vsp1_write(vsp1, VI6_DISP_IRQ_STA(i), ~status & mask); + + if (status & VI6_DISP_IRQ_STA_DST) { + vsp1_pipeline_display_start(wpf->entity.pipe); + ret = IRQ_HANDLED; + } + } }
return ret; diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c index 54ff539ffea0..016800c45bc1 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.c +++ b/drivers/media/platform/vsp1/vsp1_pipe.c @@ -309,6 +309,11 @@ bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe) return pipe->buffers_ready == mask; }
+void vsp1_pipeline_display_start(struct vsp1_pipeline *pipe) +{ + vsp1_dlm_irq_display_start(pipe->output->dlm); +} + void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe) { unsigned int flags; diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h index ae646c9ef337..801fca13fc4f 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.h +++ b/drivers/media/platform/vsp1/vsp1_pipe.h @@ -158,6 +158,7 @@ bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe); int vsp1_pipeline_stop(struct vsp1_pipeline *pipe); bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe);
+void vsp1_pipeline_display_start(struct vsp1_pipeline *pipe); void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe);
void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, 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;
struct vsp1_dl_manager *dlm; }; diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index 18c49e3a7875..b8bcc7968f9c 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c @@ -240,6 +240,7 @@ 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; @@ -250,8 +251,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;
@@ -276,8 +278,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)); @@ -288,11 +289,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 @@ -318,9 +317,27 @@ 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. For display pipelines that + * have a writeback buffer, enable the display start interrupt and the + * writeback for one frame and reset the registers to 0 on the next + * vblank. + */ + vsp1_dl_body_write(dlb, VI6_DISP_IRQ_STA(index), 0); + if (wpf->writeback) { + vsp1_dl_body_write_oneshot(dlb, VI6_DISP_IRQ_ENB(index), + VI6_DISP_IRQ_ENB_DSTE, 0); + vsp1_dl_body_write_oneshot(dlb, VI6_WPF_WRBCK_CTRL(index), + VI6_WPF_WRBCK_CTRL_WBMD, 0); + } else { + vsp1_dl_body_write(dlb, VI6_DISP_IRQ_ENB(index), 0); + vsp1_dl_body_write(dlb, VI6_WPF_WRBCK_CTRL(index), 0); + } }
static void wpf_configure_frame(struct vsp1_entity *entity, @@ -390,7 +407,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;
/* @@ -479,6 +500,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, @@ -529,6 +556,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;