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+rene...@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;
-- 
Regards,

Laurent Pinchart

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

Reply via email to