summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikhil Devshatwar <nikhil.nd@ti.com>2017-05-12 15:09:51 +0530
committerNikhil Devshatwar <nikhil.nd@ti.com>2018-01-19 15:26:23 +0530
commitce834862e50ec4c5dff2ea2cf63b5bc6ebdfc6a2 (patch)
tree09c7fa033f15204ed0f16bac5f54c6a49e9d7bf3
parent742f84423d8eb464e85520b16c9424b4498f5665 (diff)
downloadomap-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.c100
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;
}
}