Add example 2- and 3- planar YCbCr422 formats for multi-plane
format testing.

Signed-off-by: Pawel Osciak <p.osc...@samsung.com>
Reviewed-by: Kyungmin Park <kyungmin.p...@samsung.com>
---
 drivers/media/video/vivi.c |  179 +++++++++++++++++++++++++++++++++++---------
 include/linux/videodev2.h  |    3 +
 2 files changed, 147 insertions(+), 35 deletions(-)

diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 37632a0..bc1ec0d 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -132,6 +132,9 @@ struct vivi_fmt {
        char  *name;
        u32   fourcc;          /* v4l2 format id */
        int   depth;
+       unsigned int num_planes;
+       unsigned int plane_w_shr;
+       unsigned int plane_h_shr;
 };
 
 static struct vivi_fmt formats[] = {
@@ -139,31 +142,53 @@ static struct vivi_fmt formats[] = {
                .name     = "4:2:2, packed, YUYV",
                .fourcc   = V4L2_PIX_FMT_YUYV,
                .depth    = 16,
+               .num_planes = 1,
        },
        {
                .name     = "4:2:2, packed, UYVY",
                .fourcc   = V4L2_PIX_FMT_UYVY,
                .depth    = 16,
+               .num_planes = 1,
        },
        {
                .name     = "RGB565 (LE)",
                .fourcc   = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
                .depth    = 16,
+               .num_planes = 1,
        },
        {
                .name     = "RGB565 (BE)",
                .fourcc   = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
                .depth    = 16,
+               .num_planes = 1,
        },
        {
                .name     = "RGB555 (LE)",
                .fourcc   = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
                .depth    = 16,
+               .num_planes = 1,
        },
        {
                .name     = "RGB555 (BE)",
                .fourcc   = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
                .depth    = 16,
+               .num_planes = 1,
+       },
+       {
+               .name           = "YUV 4:2:2, 3-planar",
+               .fourcc         = V4L2_PIX_FMT_YUV422PM,
+               .depth          = 16,
+               .num_planes     = 3,
+               .plane_w_shr    = 1,
+               .plane_h_shr    = 0,
+       },
+       {
+               .name           = "YUV 4:2:2, 2-planar",
+               .fourcc         = V4L2_PIX_FMT_NV16M,
+               .depth          = 16,
+               .num_planes     = 2,
+               .plane_w_shr    = 1,
+               .plane_h_shr    = 0,
        },
 };
 
@@ -361,6 +386,8 @@ static void precalculate_bars(struct vivi_fh *fh)
                switch (fh->fmt->fourcc) {
                case V4L2_PIX_FMT_YUYV:
                case V4L2_PIX_FMT_UYVY:
+               case V4L2_PIX_FMT_YUV422PM:
+               case V4L2_PIX_FMT_NV16M:
                        is_yuv = 1;
                        break;
                case V4L2_PIX_FMT_RGB565:
@@ -410,6 +437,8 @@ static void gen_twopix(struct vivi_fh *fh, unsigned char 
*buf, int colorpos)
 
                switch (fh->fmt->fourcc) {
                case V4L2_PIX_FMT_YUYV:
+               case V4L2_PIX_FMT_YUV422PM:
+               case V4L2_PIX_FMT_NV16M:
                        switch (color) {
                        case 0:
                        case 2:
@@ -558,30 +587,58 @@ end:
 static void vivi_fillbuff(struct vivi_fh *fh, struct vivi_buffer *buf)
 {
        struct vivi_dev *dev = fh->dev;
-       int h , pos = 0;
+       int i, x, h, curr_plane = 0, pos = 0;
        int hmax  = buf->vb.height;
        int wmax  = buf->vb.width;
        struct timeval ts;
-       char *tmpbuf;
-       void *vbuf = videobuf_to_vmalloc(&buf->vb);
+       char *tmpbuf, *p_tmpbuf;
+       char *vbuf[VIDEO_MAX_PLANES];
+
+       for (i = 0; i < fh->fmt->num_planes; ++i) {
+               vbuf[i] = videobuf_plane_to_vmalloc(&buf->vb, i);
+               if (!vbuf[i]) {
+                       dprintk(dev, 1, "Failed acquiring vaddr for a plane\n");
+                       return;
+               }
+       }
 
-       if (!vbuf)
-               return;
+       if (fh->fmt->num_planes > 1) {
+               tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
+               if (!tmpbuf)
+                       return;
+
+               for (h = 0; h < hmax; h++) {
+                       gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count,
+                                dev->timestr);
+                       p_tmpbuf = tmpbuf;
+
+                       for (x = 0; x < wmax; ++x) {
+                               *(vbuf[0]++) = *p_tmpbuf++;
+                               *(vbuf[curr_plane + 1]++) = *p_tmpbuf++;
+                               if (V4L2_PIX_FMT_YUV422PM == fh->fmt->fourcc)
+                                       curr_plane = !curr_plane;
+                       }
+               }
 
-       tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
-       if (!tmpbuf)
-               return;
+               dev->mv_count++;
 
-       for (h = 0; h < hmax; h++) {
-               gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count,
-                        dev->timestr);
-               memcpy(vbuf + pos, tmpbuf, wmax * 2);
-               pos += wmax*2;
-       }
+               kfree(tmpbuf);
+       } else {
+               tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
+               if (!tmpbuf)
+                       return;
+
+               for (h = 0; h < hmax; h++) {
+                       gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count,
+                                dev->timestr);
+                       memcpy(vbuf[0] + pos, tmpbuf, wmax * 2);
+                       pos += wmax*2;
+               }
 
-       dev->mv_count++;
+               dev->mv_count++;
 
-       kfree(tmpbuf);
+               kfree(tmpbuf);
+       }
 
        /* Updates stream time */
 
@@ -708,8 +765,6 @@ static int vivi_start_thread(struct vivi_fh *fh)
        dma_q->frame = 0;
        dma_q->ini_jiffies = jiffies;
 
-       dprintk(dev, 1, "%s\n", __func__);
-
        dma_q->kthread = kthread_run(vivi_thread, fh, "vivi");
 
        if (IS_ERR(dma_q->kthread)) {
@@ -719,7 +774,6 @@ static int vivi_start_thread(struct vivi_fh *fh)
        /* Wakes thread */
        wake_up_interruptible(&dma_q->wq);
 
-       dprintk(dev, 1, "returning from %s\n", __func__);
        return 0;
 }
 
@@ -738,22 +792,66 @@ static void vivi_stop_thread(struct vivi_dmaqueue  *dma_q)
 /* ------------------------------------------------------------------
        Videobuf operations
    ------------------------------------------------------------------*/
-static int
-buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int 
*size)
+static unsigned long get_plane_size(struct vivi_fh *fh, unsigned int plane)
 {
-       struct vivi_fh  *fh = vq->priv_data;
-       struct vivi_dev *dev  = fh->dev;
+       unsigned long plane_size = 0;
+
+       if (plane >= fh->fmt->num_planes)
+               return 0;
+
+       if (1 == fh->fmt->num_planes) {
+               plane_size = fh->width * fh->height * 2;
+       } else {
+               if (0 == plane) {
+                       plane_size = fh->width * fh->height;
+               } else {
+                       plane_size = (fh->width >> 1) * fh->height;
+                       if (2 == fh->fmt->num_planes)
+                               plane_size *= 2;
+               }
+       }
+
+       return plane_size;
+}
+static int buffer_negotiate(struct videobuf_queue *vq, unsigned int *buf_count,
+                           unsigned int *plane_count)
+{
+       struct vivi_fh *fh      = vq->priv_data;
+       struct vivi_dev *dev    = fh->dev;
+       unsigned int buf_size   = 0;
+       unsigned int i;
+
+       *plane_count = fh->fmt->num_planes;
+
+       if (0 == *buf_count)
+               *buf_count = 32;
+
+       for (i = 0; i < fh->fmt->num_planes; ++i)
+               buf_size += get_plane_size(fh, i);
+
+       while (buf_size * *buf_count > vid_limit * 1024 * 1024)
+               (*buf_count)--;
+
+       dprintk(dev, 1, "%s, buffer count=%d, plane count=%d\n",
+                       __func__, *buf_count, *plane_count);
 
-       *size = fh->width*fh->height*2;
+       return 0;
+}
 
-       if (0 == *count)
-               *count = 32;
+static int buffer_setup_plane(struct videobuf_queue *vq, unsigned int plane,
+                             unsigned int *plane_size)
+{
+       struct vivi_fh *fh      = vq->priv_data;
+       struct vivi_dev *dev    = fh->dev;
 
-       while (*size * *count > vid_limit * 1024 * 1024)
-               (*count)--;
+       if (plane >= fh->fmt->num_planes) {
+               dprintk(dev, 1, "%s, invalid plane=%d\n", __func__, plane);
+               return -EINVAL;
+       }
 
-       dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__,
-               *count, *size);
+       *plane_size = get_plane_size(fh, plane);
+       dprintk(dev, 1, "%s, plane=%d, size=%d\n",
+               __func__, plane, *plane_size);
 
        return 0;
 }
@@ -783,6 +881,7 @@ buffer_prepare(struct videobuf_queue *vq, struct 
videobuf_buffer *vb,
        struct vivi_dev    *dev = fh->dev;
        struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
        int rc;
+       unsigned int i;
 
        dprintk(dev, 1, "%s, field=%d\n", __func__, field);
 
@@ -792,9 +891,17 @@ buffer_prepare(struct videobuf_queue *vq, struct 
videobuf_buffer *vb,
            fh->height < 32 || fh->height > norm_maxh())
                return -EINVAL;
 
-       buf->vb.size = fh->width*fh->height*2;
-       if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
-               return -EINVAL;
+       for (i = 0; i < fh->fmt->num_planes; ++i) {
+               buf->vb.planes[i].size = get_plane_size(fh, i);
+
+               if (0 != buf->vb.planes[i].baddr
+                   && buf->vb.planes[i].bsize < buf->vb.planes[i].size) {
+                       dprintk(dev, 1, "%s, invalid plane %u size: (%d<%lu)\n",
+                               __func__, i, buf->vb.planes[i].bsize,
+                               buf->vb.planes[i].size);
+                       return -EINVAL;
+               }
+       }
 
        /* These properties only change when queue is idle, see s_fmt */
        buf->fmt       = fh->fmt;
@@ -846,7 +953,8 @@ static void buffer_release(struct videobuf_queue *vq,
 }
 
 static struct videobuf_queue_ops vivi_video_qops = {
-       .buf_setup      = buffer_setup,
+       .buf_negotiate  = buffer_negotiate,
+       .buf_setup_plane = buffer_setup_plane,
        .buf_prepare    = buffer_prepare,
        .buf_queue      = buffer_queue,
        .buf_release    = buffer_release,
@@ -948,8 +1056,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void 
*priv,
 {
        struct vivi_fh *fh = priv;
        struct videobuf_queue *q = &fh->vb_vidq;
+       int ret;
 
-       int ret = vidioc_try_fmt_vid_cap(file, fh, f);
+       ret = vidioc_try_fmt_vid_cap(file, fh, f);
        if (ret < 0)
                return ret;
 
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index bf3f33d..fbce9d7 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -314,6 +314,8 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_UYVY    v4l2_fourcc('U', 'Y', 'V', 'Y') /* 16  YUV 4:2:2  
   */
 #define V4L2_PIX_FMT_VYUY    v4l2_fourcc('V', 'Y', 'U', 'Y') /* 16  YUV 4:2:2  
   */
 #define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4', '2', '2', 'P') /* 16  YVU422 
planar */
+#define V4L2_PIX_FMT_YUV422PM v4l2_fourcc('4', '2', '2', 'M') /* 16 YUV422 
multiplane */
+
 #define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4', '1', '1', 'P') /* 16  YVU411 
planar */
 #define V4L2_PIX_FMT_Y41P    v4l2_fourcc('Y', '4', '1', 'P') /* 12  YUV 4:1:1  
   */
 #define V4L2_PIX_FMT_YUV444  v4l2_fourcc('Y', '4', '4', '4') /* 16  xxxxyyyy 
uuuuvvvv */
@@ -329,6 +331,7 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_NV12    v4l2_fourcc('N', 'V', '1', '2') /* 12  Y/CbCr 
4:2:0  */
 #define V4L2_PIX_FMT_NV21    v4l2_fourcc('N', 'V', '2', '1') /* 12  Y/CrCb 
4:2:0  */
 #define V4L2_PIX_FMT_NV16    v4l2_fourcc('N', 'V', '1', '6') /* 16  Y/CbCr 
4:2:2  */
+#define V4L2_PIX_FMT_NV16M   v4l2_fourcc('N', 'M', '1', '6') /* 16  Y/CbCr 
multiplane 4:2:2 */
 #define V4L2_PIX_FMT_NV61    v4l2_fourcc('N', 'V', '6', '1') /* 16  Y/CrCb 
4:2:2  */
 
 /* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */
-- 
1.7.0.31.g1df487

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to