diff mbox

[v2,3/3] v4l: vivi: add 2- and 3-planar YCbCr422

Message ID 1268146183-2018-4-git-send-email-p.osciak@samsung.com (mailing list archive)
State RFC
Headers show

Commit Message

Pawel Osciak March 9, 2010, 2:49 p.m. UTC
None
diff mbox

Patch

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 */