diff options
author | Nikhil Devshatwar <nikhil.nd@ti.com> | 2017-05-12 15:09:51 +0530 |
---|---|---|
committer | Nikhil Devshatwar <nikhil.nd@ti.com> | 2018-01-19 15:26:23 +0530 |
commit | ce834862e50ec4c5dff2ea2cf63b5bc6ebdfc6a2 (patch) | |
tree | 09c7fa033f15204ed0f16bac5f54c6a49e9d7bf3 | |
parent | 742f84423d8eb464e85520b16c9424b4498f5665 (diff) | |
download | omap-omapzoom-ce834862e50ec4c5dff2ea2cf63b5bc6ebdfc6a2.tar.gz |
media: ti-vpe: Add support for SEQ_BT
According to V4L2 spec, SEQ_BT indicates order of fields in memory
But TI decoder always puts the frames in memory as top followed by bottom
V4L2 doesn't have a field enum to indicate display order
(top field vs bottom field first) in case of sequential fields SEQ_XX
Because it is assumed that if the bottom field is first, it would be
put in the memory first.
Reuse the SEQ_TB and SEQ_BT enums to indicate the display order.
Driver always assumes fields in top followed by bottom order.
field enum decides which field gets processed first.
Change-Id: I20f9a38c99b8f8a037a178762f4374da5581d50e
Signed-off-by: Nikhil Devshatwar <nikhil.nd@ti.com>
-rw-r--r-- | drivers/media/platform/ti-vpe/vpe.c | 100 |
1 files changed, 66 insertions, 34 deletions
diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index c500b1e8f10d..7dc99cbd3548 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -341,9 +341,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, @@ -1103,31 +1108,52 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port) } else { /* to incorporate interleaved formats */ int plane = fmt->coplanar ? p_data->vb_part : 0; + int height = q_data->height; + dma_addr_t offset; + int bpp; + + if (q_data->flags & Q_IS_SEQ_XX) + height /= 2; + if (plane) + height /= 2; + + bpp = fmt->fourcc == V4L2_PIX_FMT_NV12 ? + 1 : (vpdma_fmt->depth >> 3); + /* Calulate offset for SEQ_TB and SEQ_BT formats */ + offset = q_data->width * height * bpp; vpdma_fmt = fmt->vpdma_fmt[plane]; dma_addr = vb2_dma_addr_plus_data_offset(vb, plane); + /* + * field used in VPDMA desc = 0 (top) / 1 (bottom) + * Use top or bottom field from same vb alternately + * f,f-1,f-2 = TBT (0,1,0) when seq is even + * f,f-1,f-2 = BTB (1,0,1) when seq is odd + */ 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; - - 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; - } + if (ctx->sequence % 2 == 0) + /* Even seq TBT = 010 */ + field = (p_data->vb_index + 0) % 2; + else + /* Odd seq BTB = 101 */ + field = (p_data->vb_index + 1) % 2; + + if (field == 1) + dma_addr += offset; + } + + if (q_data->flags & Q_DATA_INTERLACED_SEQ_BT) { + if (ctx->sequence % 2 == 0) + /* Even seq BTB = 101 */ + field = (p_data->vb_index + 1) % 2; + else + /* Odd seq TBT = 010 */ + field = (p_data->vb_index + 0) % 2; + + if (field == 1) + dma_addr += offset; } if (!dma_addr) { @@ -1186,13 +1212,15 @@ 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 && + if (ctx->deinterlacing && s_q_data->flags & Q_IS_SEQ_XX && 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 - */ + /* When using SEQ_XX type buffers, each buffer has two fields + * ach 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 fielda and REMOVE from queue + * */ ctx->src_vbs[0] = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); WARN_ON(ctx->src_vbs[0] == NULL); } else { @@ -1584,7 +1612,8 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f, } if (pix->field != V4L2_FIELD_NONE && pix->field != V4L2_FIELD_ALTERNATE - && pix->field != V4L2_FIELD_SEQ_TB) + && pix->field != V4L2_FIELD_SEQ_TB + && pix->field != V4L2_FIELD_SEQ_BT) pix->field = V4L2_FIELD_NONE; depth = fmt->vpdma_fmt[VPE_LUMA]->depth; @@ -1620,9 +1649,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; @@ -1714,11 +1743,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", @@ -1791,10 +1822,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; @@ -2098,7 +2129,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; } } |