From: Nikhil Devshatwar <nikhil...@ti.com>

SEQ_BT indicates the buffer for bottom field needs to be processed
before the top field.

Simplify the field selection logic to support SEQ_BT as well.

Modify the interlace flags to include any of alternate, SEQ_TB, SEQ_BT.
Update other format error checking to consider SEQ_BT.
Replace SEQ_TB with SEQ_XX wherever applicable.

Signed-off-by: Nikhil Devshatwar <nikhil...@ti.com>
Signed-off-by: Benoit Parrot <bpar...@ti.com>
---
 drivers/media/platform/ti-vpe/vpe.c | 73 ++++++++++++++++++-----------
 1 file changed, 46 insertions(+), 27 deletions(-)

diff --git a/drivers/media/platform/ti-vpe/vpe.c 
b/drivers/media/platform/ti-vpe/vpe.c
index 0e9cb0319a92..5d0ec5f7ca25 100644
--- a/drivers/media/platform/ti-vpe/vpe.c
+++ b/drivers/media/platform/ti-vpe/vpe.c
@@ -328,9 +328,14 @@ struct vpe_q_data {
 #define        Q_DATA_MODE_TILED               BIT(1)
 #define        Q_DATA_INTERLACED_ALTERNATE     BIT(2)
 #define        Q_DATA_INTERLACED_SEQ_TB        BIT(3)
+#define        Q_DATA_INTERLACED_SEQ_BT        BIT(4)
+
+#define Q_IS_SEQ_XX            (Q_DATA_INTERLACED_SEQ_TB | \
+                               Q_DATA_INTERLACED_SEQ_BT)
 
 #define Q_IS_INTERLACED                (Q_DATA_INTERLACED_ALTERNATE | \
-                               Q_DATA_INTERLACED_SEQ_TB)
+                               Q_DATA_INTERLACED_SEQ_TB | \
+                               Q_DATA_INTERLACED_SEQ_BT)
 
 enum {
        Q_DATA_SRC = 0,
@@ -1105,24 +1110,31 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port)
                dma_addr += offset;
                stride = q_data->bytesperline[VPE_LUMA];
 
-               if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB) {
-                       /*
-                        * Use top or bottom field from same vb alternately
-                        * f,f-1,f-2 = TBT when seq is even
-                        * f,f-1,f-2 = BTB when seq is odd
-                        */
-                       field = (p_data->vb_index + (ctx->sequence % 2)) % 2;
+               /*
+                * field used in VPDMA desc  = 0 (top) / 1 (bottom)
+                * Use top or bottom field from same vb alternately
+                * For each de-interlacing operation, f,f-1,f-2 should be one
+                * of TBT or BTB
+                */
+               if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB ||
+                   q_data->flags & Q_DATA_INTERLACED_SEQ_BT) {
+                       /* Select initial value based on format */
+                       if (q_data->flags & Q_DATA_INTERLACED_SEQ_BT)
+                               field = 1;
+                       else
+                               field = 0;
+
+                       /* Toggle for each vb_index and each operation */
+                       field = (field + p_data->vb_index + ctx->sequence) % 2;
 
                        if (field) {
-                               /*
-                                * bottom field of a SEQ_TB buffer
-                                * Skip the top field data by
-                                */
                                int height = q_data->height / 2;
                                int bpp = fmt->fourcc == V4L2_PIX_FMT_NV12 ?
                                                1 : (vpdma_fmt->depth >> 3);
+
                                if (plane)
                                        height /= 2;
+
                                dma_addr += q_data->width * height * bpp;
                        }
                }
@@ -1177,12 +1189,14 @@ static void device_run(void *priv)
        struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST];
        struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC];
 
-       if (ctx->deinterlacing && s_q_data->flags & Q_DATA_INTERLACED_SEQ_TB &&
-               ctx->sequence % 2 == 0) {
-               /* When using SEQ_TB buffers, When using it first time,
-                * No need to remove the buffer as the next field is present
-                * in the same buffer. (so that job_ready won't fail)
-                * It will be removed when using bottom field
+       if (ctx->deinterlacing && s_q_data->flags & Q_IS_SEQ_XX &&
+           ctx->sequence % 2 == 0) {
+               /* When using SEQ_XX type buffers, each buffer has two fields
+                * each buffer has two fields (top & bottom)
+                * Removing one buffer is actually getting two fields
+                * Alternate between two operations:-
+                * Even : consume one field but DO NOT REMOVE from queue
+                * Odd : consume other field and REMOVE from queue
                 */
                ctx->src_vbs[0] = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
                WARN_ON(ctx->src_vbs[0] == NULL);
@@ -1573,8 +1587,10 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct 
v4l2_format *f,
                return -EINVAL;
        }
 
-       if (pix->field != V4L2_FIELD_NONE && pix->field != V4L2_FIELD_ALTERNATE
-                       && pix->field != V4L2_FIELD_SEQ_TB)
+       if (pix->field != V4L2_FIELD_NONE &&
+           pix->field != V4L2_FIELD_ALTERNATE &&
+           pix->field != V4L2_FIELD_SEQ_TB &&
+           pix->field != V4L2_FIELD_SEQ_BT)
                pix->field = V4L2_FIELD_NONE;
 
        depth = fmt->vpdma_fmt[VPE_LUMA]->depth;
@@ -1626,9 +1642,9 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct 
v4l2_format *f,
 
        /*
         * For the actual image parameters, we need to consider the field
-        * height of the image for SEQ_TB buffers.
+        * height of the image for SEQ_XX buffers.
         */
-       if (pix->field == V4L2_FIELD_SEQ_TB)
+       if (pix->field == V4L2_FIELD_SEQ_TB || pix->field == V4L2_FIELD_SEQ_BT)
                height = pix->height / 2;
        else
                height = pix->height;
@@ -1734,11 +1750,13 @@ static int __vpe_s_fmt(struct vpe_ctx *ctx, struct 
v4l2_format *f)
                q_data->flags |= Q_DATA_INTERLACED_ALTERNATE;
        else if (q_data->field == V4L2_FIELD_SEQ_TB)
                q_data->flags |= Q_DATA_INTERLACED_SEQ_TB;
+       else if (q_data->field == V4L2_FIELD_SEQ_BT)
+               q_data->flags |= Q_DATA_INTERLACED_SEQ_BT;
        else
                q_data->flags &= ~Q_IS_INTERLACED;
 
-       /* the crop height is halved for the case of SEQ_TB buffers */
-       if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB)
+       /* the crop height is halved for the case of SEQ_XX buffers */
+       if (q_data->flags & Q_IS_SEQ_XX)
                q_data->c_rect.height /= 2;
 
        vpe_dbg(ctx->dev, "Setting format for type %d, wxh: %dx%d, fmt: %d 
bpl_y %d",
@@ -1811,10 +1829,10 @@ static int __vpe_try_selection(struct vpe_ctx *ctx, 
struct v4l2_selection *s)
        }
 
        /*
-        * For SEQ_TB buffers, crop height should be less than the height of
+        * For SEQ_XX buffers, crop height should be less than the height of
         * the field height, not the buffer height
         */
-       if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB)
+       if (q_data->flags & Q_IS_SEQ_XX)
                height = q_data->height / 2;
        else
                height = q_data->height;
@@ -2031,7 +2049,8 @@ static int vpe_buf_prepare(struct vb2_buffer *vb)
                } else {
                        if (vbuf->field != V4L2_FIELD_TOP &&
                            vbuf->field != V4L2_FIELD_BOTTOM &&
-                           vbuf->field != V4L2_FIELD_SEQ_TB)
+                           vbuf->field != V4L2_FIELD_SEQ_TB &&
+                           vbuf->field != V4L2_FIELD_SEQ_BT)
                                return -EINVAL;
                }
        }
-- 
2.17.1

Reply via email to