[PATCH v5 6/8] v4l: xilinx: dma: Add multi-planar support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The current v4l driver supports single plane formats. This patch
adds support to handle multi-planar formats. Driver can handle
both single and multi-planar formats.

Signed-off-by: Satish Kumar Nagireddy <satish.nagireddy.nagireddy@xxxxxxxxxx>
---
Changes in v5:
 - Added default height
 - Corrected sizeimage declaration with u32

Changes in v4:
 - Single plane implementation is removed as multi-plane supports both
 - num_buffers and bpl_factor parameters are removed to have clean
   implementation

 drivers/media/platform/xilinx/xilinx-dma.c  | 150 +++++++++++++++++-----------
 drivers/media/platform/xilinx/xilinx-dma.h  |   4 +-
 drivers/media/platform/xilinx/xilinx-vipp.c |  16 +--
 3 files changed, 104 insertions(+), 66 deletions(-)

diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
index 518d572..2ffc276 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.c
+++ b/drivers/media/platform/xilinx/xilinx-dma.c
@@ -74,8 +74,8 @@ static int xvip_dma_verify_format(struct xvip_dma *dma)
 		return ret == -ENOIOCTLCMD ? -EINVAL : ret;
 
 	if (dma->fmtinfo->code != fmt.format.code ||
-	    dma->format.height != fmt.format.height ||
-	    dma->format.width != fmt.format.width)
+	    dma->format.fmt.pix_mp.width != fmt.format.width ||
+	    dma->format.fmt.pix_mp.height != fmt.format.height)
 		return -EINVAL;
 
 	return 0;
@@ -310,7 +310,8 @@ static void xvip_dma_complete(void *param)
 	buf->buf.field = V4L2_FIELD_NONE;
 	buf->buf.sequence = dma->sequence++;
 	buf->buf.vb2_buf.timestamp = ktime_get_ns();
-	vb2_set_plane_payload(&buf->buf.vb2_buf, 0, dma->format.sizeimage);
+	vb2_set_plane_payload(&buf->buf.vb2_buf, 0,
+			      dma->format.fmt.pix_mp.plane_fmt[0].sizeimage);
 	vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE);
 }
 
@@ -320,13 +321,15 @@ xvip_dma_queue_setup(struct vb2_queue *vq,
 		     unsigned int sizes[], struct device *alloc_devs[])
 {
 	struct xvip_dma *dma = vb2_get_drv_priv(vq);
+	u32 sizeimage;
 
 	/* Make sure the image size is large enough. */
+	sizeimage = dma->format.fmt.pix_mp.plane_fmt[0].sizeimage;
 	if (*nplanes)
-		return sizes[0] < dma->format.sizeimage ? -EINVAL : 0;
+		return sizes[0] < sizeimage ? -EINVAL : 0;
 
 	*nplanes = 1;
-	sizes[0] = dma->format.sizeimage;
+	sizes[0] = sizeimage;
 
 	return 0;
 }
@@ -350,8 +353,9 @@ static void xvip_dma_buffer_queue(struct vb2_buffer *vb)
 	struct dma_async_tx_descriptor *desc;
 	dma_addr_t addr = vb2_dma_contig_plane_dma_addr(vb, 0);
 	u32 flags;
+	struct v4l2_pix_format_mplane *pix_mp = &dma->format.fmt.pix_mp;
 
-	if (dma->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+	if (dma->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 		flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
 		dma->xt.dir = DMA_DEV_TO_MEM;
 		dma->xt.src_sgl = false;
@@ -365,10 +369,11 @@ static void xvip_dma_buffer_queue(struct vb2_buffer *vb)
 		dma->xt.src_start = addr;
 	}
 
-	dma->xt.frame_size = 1;
-	dma->sgl[0].size = dma->format.width * dma->fmtinfo->bpp[0];
-	dma->sgl[0].icg = dma->format.bytesperline - dma->sgl[0].size;
-	dma->xt.numf = dma->format.height;
+	dma->xt.frame_size = dma->fmtinfo->num_planes;
+	dma->sgl[0].size = pix_mp->width * dma->fmtinfo->bpp[0];
+	dma->sgl[0].icg = pix_mp->plane_fmt[0].bytesperline - dma->sgl[0].size;
+	dma->xt.numf = pix_mp->height;
+	dma->sgl[0].dst_icg = 0;
 
 	desc = dmaengine_prep_interleaved_dma(dma->dma, &dma->xt, flags);
 	if (!desc) {
@@ -496,11 +501,12 @@ xvip_dma_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
 
 	cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING
 			  | dma->xdev->v4l2_caps;
+	cap->device_caps = V4L2_CAP_STREAMING;
 
-	if (dma->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+	if (dma->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE_MPLANE;
 	else
-		cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+		cap->device_caps |= V4L2_CAP_VIDEO_OUTPUT_MPLANE;
 
 	strlcpy(cap->driver, "xilinx-vipp", sizeof(cap->driver));
 	strlcpy(cap->card, dma->video.name, sizeof(cap->card));
@@ -524,7 +530,7 @@ xvip_dma_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f)
 	if (f->index > 0)
 		return -EINVAL;
 
-	f->pixelformat = dma->format.pixelformat;
+	f->pixelformat = dma->format.fmt.pix_mp.pixelformat;
 	strlcpy(f->description, dma->fmtinfo->description,
 		sizeof(f->description));
 
@@ -537,13 +543,14 @@ xvip_dma_get_format(struct file *file, void *fh, struct v4l2_format *format)
 	struct v4l2_fh *vfh = file->private_data;
 	struct xvip_dma *dma = to_xvip_dma(vfh->vdev);
 
-	format->fmt.pix = dma->format;
+	format->fmt.pix_mp = dma->format.fmt.pix_mp;
 
 	return 0;
 }
 
 static void
-__xvip_dma_try_format(struct xvip_dma *dma, struct v4l2_pix_format *pix,
+__xvip_dma_try_format(struct xvip_dma *dma,
+		      struct v4l2_format *format,
 		      const struct xvip_video_format **fmtinfo)
 {
 	const struct xvip_video_format *info;
@@ -551,19 +558,20 @@ __xvip_dma_try_format(struct xvip_dma *dma, struct v4l2_pix_format *pix,
 	unsigned int max_width;
 	unsigned int min_bpl;
 	unsigned int max_bpl;
-	unsigned int width;
+	unsigned int width, height;
 	unsigned int align;
 	unsigned int bpl;
+	struct v4l2_pix_format_mplane *pix_mp = &format->fmt.pix_mp;
+	struct v4l2_plane_pix_format *plane_fmt = pix_mp->plane_fmt;
 
 	/* Retrieve format information and select the default format if the
 	 * requested format isn't supported.
 	 */
-	info = xvip_get_format_by_fourcc(pix->pixelformat);
+	info = xvip_get_format_by_fourcc(pix_mp->pixelformat);
 	if (IS_ERR(info))
 		info = xvip_get_format_by_fourcc(XVIP_DMA_DEF_FORMAT);
 
-	pix->pixelformat = info->fourcc;
-	pix->field = V4L2_FIELD_NONE;
+	pix_mp->field = V4L2_FIELD_NONE;
 
 	/* The transfer alignment requirements are expressed in bytes. Compute
 	 * the minimum and maximum values, clamp the requested width and convert
@@ -572,22 +580,41 @@ __xvip_dma_try_format(struct xvip_dma *dma, struct v4l2_pix_format *pix,
 	align = lcm(dma->align, info->bpp[0]);
 	min_width = roundup(XVIP_DMA_MIN_WIDTH, align);
 	max_width = rounddown(XVIP_DMA_MAX_WIDTH, align);
-	width = rounddown(pix->width * info->bpp[0], align);
+	pix_mp->width = clamp(pix_mp->width, min_width, max_width);
+	pix_mp->height = clamp(pix_mp->height, XVIP_DMA_MIN_HEIGHT,
+			       XVIP_DMA_MAX_HEIGHT);
 
-	pix->width = clamp(width, min_width, max_width) / info->bpp[0];
-	pix->height = clamp(pix->height, XVIP_DMA_MIN_HEIGHT,
-			    XVIP_DMA_MAX_HEIGHT);
-
-	/* Clamp the requested bytes per line value. If the maximum bytes per
-	 * line value is zero, the module doesn't support user configurable line
-	 * sizes. Override the requested value with the minimum in that case.
+	/*
+	 * Clamp the requested bytes per line value. If the maximum
+	 * bytes per line value is zero, the module doesn't support
+	 * user configurable line sizes. Override the requested value
+	 * with the minimum in that case.
 	 */
-	min_bpl = pix->width * info->bpp[0];
-	max_bpl = rounddown(XVIP_DMA_MAX_WIDTH, dma->align);
-	bpl = rounddown(pix->bytesperline, dma->align);
-
-	pix->bytesperline = clamp(bpl, min_bpl, max_bpl);
-	pix->sizeimage = pix->bytesperline * pix->height;
+	max_bpl = rounddown(XVIP_DMA_MAX_WIDTH, align);
+	min_bpl = pix_mp->width * info->bpp[0];
+	min_bpl = roundup(min_bpl, align);
+	bpl = roundup(plane_fmt[0].bytesperline, align);
+	plane_fmt[0].bytesperline = clamp(bpl, min_bpl, max_bpl);
+
+	if (info->num_planes == 1) {
+		/* Single plane formats */
+		plane_fmt[0].sizeimage = plane_fmt[0].bytesperline *
+					 pix_mp->height;
+	} else {
+		/*
+		 * Supports Multi plane formats in a contiguous buffer,
+		 * so we need only one buffer
+		 */
+		unsigned int i;
+
+		plane_fmt[0].sizeimage = 0;
+		for (i = 0; i < info->num_planes; i++) {
+			width = plane_fmt[0].bytesperline /
+				(i ? info->hsub : 1);
+			height = pix_mp->height / (i ? info->vsub : 1);
+			plane_fmt[0].sizeimage += width * info->bpp[i] * height;
+		}
+	}
 
 	if (fmtinfo)
 		*fmtinfo = info;
@@ -599,7 +626,7 @@ xvip_dma_try_format(struct file *file, void *fh, struct v4l2_format *format)
 	struct v4l2_fh *vfh = file->private_data;
 	struct xvip_dma *dma = to_xvip_dma(vfh->vdev);
 
-	__xvip_dma_try_format(dma, &format->fmt.pix, NULL);
+	__xvip_dma_try_format(dma, format, NULL);
 	return 0;
 }
 
@@ -610,12 +637,13 @@ xvip_dma_set_format(struct file *file, void *fh, struct v4l2_format *format)
 	struct xvip_dma *dma = to_xvip_dma(vfh->vdev);
 	const struct xvip_video_format *info;
 
-	__xvip_dma_try_format(dma, &format->fmt.pix, &info);
+	__xvip_dma_try_format(dma, format, &info);
 
 	if (vb2_is_busy(&dma->queue))
 		return -EBUSY;
 
-	dma->format = format->fmt.pix;
+	dma->format.fmt.pix_mp = format->fmt.pix_mp;
+
 	dma->fmtinfo = info;
 
 	return 0;
@@ -623,13 +651,14 @@ xvip_dma_set_format(struct file *file, void *fh, struct v4l2_format *format)
 
 static const struct v4l2_ioctl_ops xvip_dma_ioctl_ops = {
 	.vidioc_querycap		= xvip_dma_querycap,
-	.vidioc_enum_fmt_vid_cap	= xvip_dma_enum_format,
-	.vidioc_g_fmt_vid_cap		= xvip_dma_get_format,
-	.vidioc_g_fmt_vid_out		= xvip_dma_get_format,
-	.vidioc_s_fmt_vid_cap		= xvip_dma_set_format,
-	.vidioc_s_fmt_vid_out		= xvip_dma_set_format,
-	.vidioc_try_fmt_vid_cap		= xvip_dma_try_format,
-	.vidioc_try_fmt_vid_out		= xvip_dma_try_format,
+	.vidioc_enum_fmt_vid_cap_mplane	= xvip_dma_enum_format,
+	.vidioc_enum_fmt_vid_out_mplane	= xvip_dma_enum_format,
+	.vidioc_g_fmt_vid_cap_mplane	= xvip_dma_get_format,
+	.vidioc_g_fmt_vid_out_mplane	= xvip_dma_get_format,
+	.vidioc_s_fmt_vid_cap_mplane	= xvip_dma_set_format,
+	.vidioc_s_fmt_vid_out_mplane	= xvip_dma_set_format,
+	.vidioc_try_fmt_vid_cap_mplane	= xvip_dma_try_format,
+	.vidioc_try_fmt_vid_out_mplane	= xvip_dma_try_format,
 	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
 	.vidioc_querybuf		= vb2_ioctl_querybuf,
 	.vidioc_qbuf			= vb2_ioctl_qbuf,
@@ -662,6 +691,7 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma,
 {
 	char name[16];
 	int ret;
+	struct v4l2_pix_format_mplane *pix_mp;
 
 	dma->xdev = xdev;
 	dma->port = port;
@@ -671,17 +701,22 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma,
 	spin_lock_init(&dma->queued_lock);
 
 	dma->fmtinfo = xvip_get_format_by_fourcc(XVIP_DMA_DEF_FORMAT);
-	dma->format.pixelformat = dma->fmtinfo->fourcc;
-	dma->format.colorspace = V4L2_COLORSPACE_SRGB;
-	dma->format.field = V4L2_FIELD_NONE;
-	dma->format.width = XVIP_DMA_DEF_WIDTH;
-	dma->format.height = XVIP_DMA_DEF_HEIGHT;
-	dma->format.bytesperline = dma->format.width * dma->fmtinfo->bpp[0];
-	dma->format.sizeimage = dma->format.bytesperline * dma->format.height;
+	dma->format.type = type;
+
+	pix_mp = &dma->format.fmt.pix_mp;
+	pix_mp->pixelformat = dma->fmtinfo->fourcc;
+	pix_mp->colorspace = V4L2_COLORSPACE_SRGB;
+	pix_mp->field = V4L2_FIELD_NONE;
+	pix_mp->width = XVIP_DMA_DEF_WIDTH;
+	pix_mp->height = XVIP_DMA_DEF_HEIGHT;
+	pix_mp->plane_fmt[0].bytesperline = pix_mp->width *
+					    dma->fmtinfo->bpp[0];
+	pix_mp->plane_fmt[0].sizeimage = pix_mp->plane_fmt[0].bytesperline *
+					 pix_mp->height;
 
 	/* Initialize the media entity... */
-	dma->pad.flags = type == V4L2_BUF_TYPE_VIDEO_CAPTURE
-		       ? MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
+	dma->pad.flags = type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
+			? MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
 
 	ret = media_entity_pads_init(&dma->video.entity, 1, &dma->pad);
 	if (ret < 0)
@@ -693,11 +728,14 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma,
 	dma->video.queue = &dma->queue;
 	snprintf(dma->video.name, sizeof(dma->video.name), "%s %s %u",
 		 xdev->dev->of_node->name,
-		 type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? "output" : "input",
+		 type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
+					? "output" : "input",
 		 port);
+
 	dma->video.vfl_type = VFL_TYPE_GRABBER;
-	dma->video.vfl_dir = type == V4L2_BUF_TYPE_VIDEO_CAPTURE
-			   ? VFL_DIR_RX : VFL_DIR_TX;
+	dma->video.vfl_dir = type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
+				? VFL_DIR_RX : VFL_DIR_TX;
+
 	dma->video.release = video_device_release_empty;
 	dma->video.ioctl_ops = &xvip_dma_ioctl_ops;
 	dma->video.lock = &dma->lock;
diff --git a/drivers/media/platform/xilinx/xilinx-dma.h b/drivers/media/platform/xilinx/xilinx-dma.h
index e95d136..96933ed 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.h
+++ b/drivers/media/platform/xilinx/xilinx-dma.h
@@ -62,7 +62,7 @@ static inline struct xvip_pipeline *to_xvip_pipeline(struct media_entity *e)
  * @pipe: pipeline belonging to the DMA channel
  * @port: composite device DT node port number for the DMA channel
  * @lock: protects the @format, @fmtinfo and @queue fields
- * @format: active V4L2 pixel format
+ * @format: V4L2 format
  * @fmtinfo: format information corresponding to the active @format
  * @queue: vb2 buffers queue
  * @sequence: V4L2 buffers sequence number
@@ -83,7 +83,7 @@ struct xvip_dma {
 	unsigned int port;
 
 	struct mutex lock;
-	struct v4l2_pix_format format;
+	struct v4l2_format format;
 	const struct xvip_video_format *fmtinfo;
 
 	struct vb2_queue queue;
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c
index 6bb28cd..509b50f 100644
--- a/drivers/media/platform/xilinx/xilinx-vipp.c
+++ b/drivers/media/platform/xilinx/xilinx-vipp.c
@@ -433,12 +433,15 @@ static int xvip_graph_dma_init_one(struct xvip_composite_device *xdev,
 	if (ret < 0)
 		return ret;
 
-	if (strcmp(direction, "input") == 0)
-		type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	else if (strcmp(direction, "output") == 0)
-		type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-	else
+	if (strcmp(direction, "input") == 0) {
+		type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+		xdev->v4l2_caps |= V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+	} else if (strcmp(direction, "output") == 0) {
+		type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+		xdev->v4l2_caps |= V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+	} else {
 		return -EINVAL;
+	}
 
 	of_property_read_u32(node, "reg", &index);
 
@@ -454,9 +457,6 @@ static int xvip_graph_dma_init_one(struct xvip_composite_device *xdev,
 
 	list_add_tail(&dma->list, &xdev->dmas);
 
-	xdev->v4l2_caps |= type == V4L2_BUF_TYPE_VIDEO_CAPTURE
-			 ? V4L2_CAP_VIDEO_CAPTURE : V4L2_CAP_VIDEO_OUTPUT;
-
 	return 0;
 }
 
-- 
2.7.4




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux