[media] v4l: ti-vpe: make sure VPDMA line stride constraints are met
authorArchit Taneja <archit@ti.com>
Tue, 3 Dec 2013 11:51:13 +0000 (08:51 -0300)
committerMauro Carvalho Chehab <m.chehab@samsung.com>
Tue, 10 Dec 2013 18:49:48 +0000 (16:49 -0200)
When VPDMA fetches or writes to an image buffer, the line stride must be a
multiple of 16 bytes. If it isn't, VPDMA HW will write/fetch until the next
16 byte boundry. This causes VPE to work incorrectly for source or destination
widths which don't satisfy the above alignment requirement.
In order to prevent this, we now make sure that when we set pix format for the
input and output buffers, the VPE source and destination image line strides are
16 byte aligned. Also, the motion vector buffers for the de-interlacer are
allocated in such a way that it ensures the same alignment.

Signed-off-by: Archit Taneja <archit@ti.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
drivers/media/platform/ti-vpe/vpdma.c
drivers/media/platform/ti-vpe/vpdma.h
drivers/media/platform/ti-vpe/vpe.c

index af0a5ffcaa981ce380a329221c55e237539ee5f4..f97253f6699fc9f899e5368d6ee4ebb76b254c73 100644 (file)
@@ -602,7 +602,7 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
        if (fmt->data_type == DATA_TYPE_C420)
                depth = 8;
 
-       stride = (depth * c_rect->width) >> 3;
+       stride = ALIGN((depth * c_rect->width) >> 3, VPDMA_STRIDE_ALIGN);
        dma_addr += (c_rect->left * depth) >> 3;
 
        dtd = list->next;
@@ -655,7 +655,7 @@ void vpdma_add_in_dtd(struct vpdma_desc_list *list, int frame_width,
                depth = 8;
        }
 
-       stride = (depth * c_rect->width) >> 3;
+       stride = ALIGN((depth * c_rect->width) >> 3, VPDMA_STRIDE_ALIGN);
        dma_addr += (c_rect->left * depth) >> 3;
 
        dtd = list->next;
index eaa2a71a5db95d1d21533428e96253e009d1d874..62dd14305e81e28cf1d378b5f4762530360f35e5 100644 (file)
@@ -45,7 +45,10 @@ struct vpdma_data_format {
 };
 
 #define VPDMA_DESC_ALIGN               16      /* 16-byte descriptor alignment */
-
+#define VPDMA_STRIDE_ALIGN             16      /*
+                                                * line stride of source and dest
+                                                * buffers should be 16 byte aligned
+                                                */
 #define VPDMA_DTD_DESC_SIZE            32      /* 8 words */
 #define VPDMA_CFD_CTD_DESC_SIZE                16      /* 4 words */
 
index f949ef57a54c749569be7a910e4e44a8449a7383..669777052a163dc9edb173d4ff6982be27f8b8a5 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
+#include <linux/log2.h>
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-ctrls.h>
 /* required alignments */
 #define S_ALIGN                0       /* multiple of 1 */
 #define H_ALIGN                1       /* multiple of 2 */
-#define W_ALIGN                1       /* multiple of 2 */
-
-/* multiple of 128 bits, line stride, 16 bytes */
-#define L_ALIGN                4
 
 /* flags that indicate a format can be used for capture/output */
 #define VPE_FMT_TYPE_CAPTURE   (1 << 0)
@@ -780,12 +777,21 @@ static int set_srcdst_params(struct vpe_ctx *ctx)
 
        if ((s_q_data->flags & Q_DATA_INTERLACED) &&
                        !(d_q_data->flags & Q_DATA_INTERLACED)) {
+               int bytes_per_line;
                const struct vpdma_data_format *mv =
                        &vpdma_misc_fmts[VPDMA_DATA_FMT_MV];
 
                ctx->deinterlacing = 1;
-               mv_buf_size =
-                       (s_q_data->width * s_q_data->height * mv->depth) >> 3;
+               /*
+                * we make sure that the source image has a 16 byte aligned
+                * stride, we need to do the same for the motion vector buffer
+                * by aligning it's stride to the next 16 byte boundry. this
+                * extra space will not be used by the de-interlacer, but will
+                * ensure that vpdma operates correctly
+                */
+               bytes_per_line = ALIGN((s_q_data->width * mv->depth) >> 3,
+                                       VPDMA_STRIDE_ALIGN);
+               mv_buf_size = bytes_per_line * s_q_data->height;
        } else {
                ctx->deinterlacing = 0;
                mv_buf_size = 0;
@@ -1352,7 +1358,8 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f,
 {
        struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
        struct v4l2_plane_pix_format *plane_fmt;
-       int i;
+       unsigned int w_align;
+       int i, depth, depth_bytes;
 
        if (!fmt || !(fmt->types & type)) {
                vpe_err(ctx->dev, "Fourcc format (0x%08x) invalid.\n",
@@ -1363,7 +1370,31 @@ 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_NONE;
 
-       v4l_bound_align_image(&pix->width, MIN_W, MAX_W, W_ALIGN,
+       depth = fmt->vpdma_fmt[VPE_LUMA]->depth;
+
+       /*
+        * the line stride should 16 byte aligned for VPDMA to work, based on
+        * the bytes per pixel, figure out how much the width should be aligned
+        * to make sure line stride is 16 byte aligned
+        */
+       depth_bytes = depth >> 3;
+
+       if (depth_bytes == 3)
+               /*
+                * if bpp is 3(as in some RGB formats), the pixel width doesn't
+                * really help in ensuring line stride is 16 byte aligned
+                */
+               w_align = 4;
+       else
+               /*
+                * for the remainder bpp(4, 2 and 1), the pixel width alignment
+                * can ensure a line stride alignment of 16 bytes. For example,
+                * if bpp is 2, then the line stride can be 16 byte aligned if
+                * the width is 8 byte aligned
+                */
+               w_align = order_base_2(VPDMA_DESC_ALIGN / depth_bytes);
+
+       v4l_bound_align_image(&pix->width, MIN_W, MAX_W, w_align,
                              &pix->height, MIN_H, MAX_H, H_ALIGN,
                              S_ALIGN);
 
@@ -1383,15 +1414,11 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f,
        }
 
        for (i = 0; i < pix->num_planes; i++) {
-               int depth;
-
                plane_fmt = &pix->plane_fmt[i];
                depth = fmt->vpdma_fmt[i]->depth;
 
                if (i == VPE_LUMA)
-                       plane_fmt->bytesperline =
-                                       round_up((pix->width * depth) >> 3,
-                                               1 << L_ALIGN);
+                       plane_fmt->bytesperline = (pix->width * depth) >> 3;
                else
                        plane_fmt->bytesperline = pix->width;