Skip to contentSkip to conversation

v4l: ti-vpe: Some VPE fixes and enhancements

PATCH Superseded Archit Taneja 4 participants 88 messages Mar 3, 2014 – Mar 14, 2014 Media (V4L/DVB)

lore
Share & tools
lore
#0 lore raw

cover v4l: ti-vpe: Some VPE fixes and enhancements

This patch set mainly consists of minor fixes for the VPE driver. These fixes ensure the following:

- The VPE module can be inserted and removed successively.
- Make sure that smaller resolutions like qcif work correctly.
- Prevent race condition between firmware loading and an open call to the v4l2 device.
- Prevent the possibility of output m2m queue not having sufficient 'ready' buffers.
- Some VPDMA data descriptor fields weren't understood correctly before. They are now used correctly.

The rest of the patches add some minor features like DMA buf support and cropping.

Reference branch:

[email protected]:boddob/linux.git vpe_for_315

Archit Taneja (7):
v4l: ti-vpe: Make sure in job_ready that we have the needed number of
dst_bufs
v4l: ti-vpe: register video device only when firmware is loaded
v4l: ti-vpe: Use video_device_release_empty
v4l: ti-vpe: Allow DMABUF buffer type support
v4l: ti-vpe: Allow usage of smaller images
v4l: ti-vpe: Fix some params in VPE data descriptors
v4l: ti-vpe: Add crop support in VPE driver

 drivers/media/platform/ti-vpe/vpdma.c |  58 ++++++++---
 drivers/media/platform/ti-vpe/vpdma.h |  16 +--
 drivers/media/platform/ti-vpe/vpe.c   | 180 +++++++++++++++++++++++++++-------
 3 files changed, 198 insertions(+), 56 deletions(-)
Signature · 1 line
1.8.3.2
#1 lore raw

PATCH 1/7 v4l: ti-vpe: Make sure in job_ready that we have the needed number of dst_bufs

VPE has a ctrl parameter which decides how many mem to mem transactions the active job from the job queue can perform.

The driver's job_ready() made sure that the number of ready source buffers are sufficient for the job to execute successfully. But it didn't make sure if there are sufficient ready destination buffers in the capture queue for the VPE output.

If the time taken by VPE to process a single frame is really slow, then it's possible that we don't need to imply such a restriction on the dst queue, but really fast transactions(small resolution, no de-interlacing) may cause us to hit the condition where we don't have any free buffers for the VPE to write on.

Add the extra check in job_ready() to make sure we have the sufficient amount of destination buffers.

---
 drivers/media/platform/ti-vpe/vpe.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/media/platform/ti-vpe/vpe.c +3 -0
index 1296c53..623e59e 100644
@@ -887,6 +887,9 @@ static int job_ready(void *priv)
 	if (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) < needed)
 		return 0;
 
+	if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < needed)
+		return 0;
+
 	return 1;
 }
 
Signature · 1 line
1.8.3.2
#2 lore raw

PATCH 2/7 v4l: ti-vpe: register video device only when firmware is loaded

In reply to Archit Taneja

vpe fops(vpe_open in particular) should be called only when VPDMA firmware is loaded. File operations on the video device are possible the moment it is registered.

Currently, we register the video device for VPE at driver probe, after calling a vpdma helper to initialize VPDMA and load firmware. This function is non-blocking(it calls request_firmware_nowait()), and doesn't ensure that the firmware is actually loaded when it returns.

We remove the device registration from vpe probe, and move it to a callback provided by the vpe driver to the vpdma library, through vpdma_create().

The ready field in vpdma_data is no longer needed since we always have firmware loaded before the device is registered.

A minor problem with this approach is that if the video_register_device fails(which doesn't really happen), the vpe platform device would be registered. however, there won't be any v4l2 device corresponding to it.

---
 drivers/media/platform/ti-vpe/vpdma.c |  8 +++--
 drivers/media/platform/ti-vpe/vpdma.h |  7 +++--
 drivers/media/platform/ti-vpe/vpe.c   | 55 ++++++++++++++++++++---------------
 3 files changed, 41 insertions(+), 29 deletions(-)
drivers/media/platform/ti-vpe/vpdma.c +5 -3
index e8175e7..73dd38e 100644
@@ -781,7 +781,7 @@ static void vpdma_firmware_cb(const struct firmware *f, void *context)
 	/* already initialized */
 	if (read_field_reg(vpdma, VPDMA_LIST_ATTR, VPDMA_LIST_RDY_MASK,
 			VPDMA_LIST_RDY_SHFT)) {
-		vpdma->ready = true;
+		vpdma->cb(vpdma->pdev);
 		return;
 	}
 
@@ -811,7 +811,7 @@ static void vpdma_firmware_cb(const struct firmware *f, void *context)
 		goto free_buf;
 	}
 
-	vpdma->ready = true;
+	vpdma->cb(vpdma->pdev);
 
 free_buf:
 	vpdma_unmap_desc_buf(vpdma, &fw_dma_buf);
@@ -839,7 +839,8 @@ static int vpdma_load_firmware(struct vpdma_data *vpdma)
 	return 0;
 }
 
-struct vpdma_data *vpdma_create(struct platform_device *pdev)
+struct vpdma_data *vpdma_create(struct platform_device *pdev,
+		void (*cb)(struct platform_device *pdev))
 {
 	struct resource *res;
 	struct vpdma_data *vpdma;
@@ -854,6 +855,7 @@ struct vpdma_data *vpdma_create(struct platform_device *pdev)
 	}
 
 	vpdma->pdev = pdev;
+	vpdma->cb = cb;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpdma");
 	if (res == NULL) {
drivers/media/platform/ti-vpe/vpdma.h +4 -3
index cf40f11..bf5f8bb 100644
@@ -35,8 +35,8 @@ struct vpdma_data {
 
 	struct platform_device	*pdev;
 
-	/* tells whether vpdma firmware is loaded or not */
-	bool ready;
+	/* callback to VPE driver when the firmware is loaded */
+	void (*cb)(struct platform_device *pdev);
 };
 
 enum vpdma_data_format_type {
@@ -208,6 +208,7 @@ void vpdma_set_frame_start_event(struct vpdma_data *vpdma,
 void vpdma_dump_regs(struct vpdma_data *vpdma);
 
 /* initialize vpdma, passed with VPE's platform device pointer */
-struct vpdma_data *vpdma_create(struct platform_device *pdev);
+struct vpdma_data *vpdma_create(struct platform_device *pdev,
+		void (*cb)(struct platform_device *pdev));
 
 #endif
drivers/media/platform/ti-vpe/vpe.c +32 -23

81 lines not on this page · raw message

Signature · 1 line
1.8.3.2
#3 lore raw

PATCH 3/7 v4l: ti-vpe: Use video_device_release_empty

In reply to Archit Taneja

The video_device struct is currently embedded in the driver data struct vpe_dev. A vpe_dev instance is allocated by the driver, and the memory for the vfd is a part of this struct.

The v4l2 core, however, manages the removal of the vfd region, through the video_device's .release() op, which currently is the helper video_device_release. This causes memory corruption, and leads to issues when we try to re-insert the vpe module.

Use the video_device_release_empty helper function instead

---
 drivers/media/platform/ti-vpe/vpe.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/platform/ti-vpe/vpe.c +1 -1
index 4243687..bb275f4 100644
@@ -1998,7 +1998,7 @@ static struct video_device vpe_videodev = {
 	.fops		= &vpe_fops,
 	.ioctl_ops	= &vpe_ioctl_ops,
 	.minor		= -1,
-	.release	= video_device_release,
+	.release	= video_device_release_empty,
 	.vfl_dir	= VFL_DIR_M2M,
 };
 
Signature · 1 line
1.8.3.2
#4 lore raw

PATCH 4/7 v4l: ti-vpe: Allow DMABUF buffer type support

In reply to Archit Taneja

For OMAP and DRA7x, we generally allocate video and graphics buffers through omapdrm since the corresponding omap-gem driver provides DMM-Tiler backed contiguous buffers. omapdrm is a dma-buf exporter. These buffers are used by other drivers in the video pipeline.

Add VB2_DMABUF flag to the io_modes of the vb2 output and capture queues. This allows the driver to import dma shared buffers.

---
 drivers/media/platform/ti-vpe/vpe.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/media/platform/ti-vpe/vpe.c +2 -2
index bb275f4..915029b 100644
@@ -1768,7 +1768,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
 
 	memset(src_vq, 0, sizeof(*src_vq));
 	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
-	src_vq->io_modes = VB2_MMAP;
+	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
 	src_vq->drv_priv = ctx;
 	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 	src_vq->ops = &vpe_qops;
@@ -1781,7 +1781,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
 
 	memset(dst_vq, 0, sizeof(*dst_vq));
 	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-	dst_vq->io_modes = VB2_MMAP;
+	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
 	dst_vq->drv_priv = ctx;
 	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 	dst_vq->ops = &vpe_qops;
Signature · 1 line
1.8.3.2
#5 lore raw

PATCH 5/7 v4l: ti-vpe: Allow usage of smaller images

In reply to Archit Taneja

The minimum width and height for VPE input/output was kept as 128 pixels. VPE doesn't have a constraint on the image height, it requires the image width to be atleast 16 bytes.

Change the minimum supported dimensions to 32x32. This allows us to de-interlace qcif content. A smaller image size than 32x32 didn't make much sense, so stopped at this.

---
 drivers/media/platform/ti-vpe/vpe.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/media/platform/ti-vpe/vpe.c +2 -2
index 915029b..3a610a6 100644
@@ -49,8 +49,8 @@
 #define VPE_MODULE_NAME "vpe"
 
 /* minimum and maximum frame sizes */
-#define MIN_W		128
-#define MIN_H		128
+#define MIN_W		32
+#define MIN_H		32
 #define MAX_W		1920
 #define MAX_H		1080
 
Signature · 1 line
1.8.3.2
#6 lore raw

RE: [PATCH 5/7] v4l: ti-vpe: Allow usage of smaller images

Hi Archit,

Quoted 6 lines

From: Archit Taneja [mailto:[email protected]]
Sent: Monday, March 03, 2014 8:33 AM

The minimum width and height for VPE input/output was kept as 128 pixels. VPE doesn't have a constraint on the image height, it requires the image width to be atleast 16 bytes.

"16 bytes" - shouldn't it be pixels? (also "at least" :) ) I can correct it when applying the patch if the above is the case.

Quoted 5 lines

Change the minimum supported dimensions to 32x32. This allows us to de- interlace qcif content. A smaller image size than 32x32 didn't make much sense, so stopped at this.

Best wishes,

Signature · 2 lines
Kamil Debski
Samsung R&D Institute Poland
Quoted 22 lines
---
 drivers/media/platform/ti-vpe/vpe.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/media/platform/ti-vpe/vpe.c +2 -3
index 915029b..3a610a6 100644
@@ -49,8 +49,8 @@
 #define VPE_MODULE_NAME "vpe"
 
 /* minimum and maximum frame sizes */
-#define MIN_W		128
-#define MIN_H		128
+#define MIN_W		32
+#define MIN_H		32
 #define MAX_W		1920
 #define MAX_H		1080
 
--

1.8.3.2

#7 lore raw

Re: [PATCH 5/7] v4l: ti-vpe: Allow usage of smaller images

Hi,

Quoted 11 lines · Kamil Debski

Hi Archit,

Quoted 6 lines

From: Archit Taneja [mailto:[email protected]]
Sent: Monday, March 03, 2014 8:33 AM

The minimum width and height for VPE input/output was kept as 128 pixels. VPE doesn't have a constraint on the image height, it requires the image width to be atleast 16 bytes.

"16 bytes" - shouldn't it be pixels? (also "at least" :) ) I can correct it when applying the patch if the above is the case.

VPDMA IP requires the line stride of the input/output images to be at least 16 bytes in total.

This can safely result in a minimum width of 16 pixels(NV12 has the least bpp with 1 byte per pixel). But we don't really have any need to support such small image resolutions. So I picked up 32x32 as the minimum size, and tested VPE with that.

Thanks,
Archit

#8 lore raw

PATCH 6/7 v4l: ti-vpe: Fix some params in VPE data descriptors

In reply to Archit Taneja

Some parameters of the VPE descriptors were understood incorrectly. They are now fixed. The fixes are explained as follows:

- When adding an inbound data descriptor to the VPDMA descriptor list, we intend to use c_rect as the cropped region fetched by VPDMA. Therefore, c_rect->width shouldn't be used to calculate the line stride, the original image width should be used for that. We add a 'width' argument which gives the buffer width in memory.

- frame_width and frame_height describe the complete width and height of the client to which the channel is connected. If there are multiple channels fetching data and providing to the same client, the above 2 arguments should be the width and height of the region covered by all the channels. In the case where there is only one channel providing pixel data to the client (like in VPE), frame_width and frame_height should be the cropped width and cropped height respectively. The calculation of these params is done in the vpe driver now.

- start_h and start_v is also used in the case of multiple channels to describe where each channel should start filling pixel data. We don't use this in VPE, and pass 0s to the vpdma_add_in_dtd() helper.

- Some minor changes are made to the vpdma_add_out_dtd() helper. The c_rect param is removed since cropping isn't possible for outbound data, and 'width' is added to calculate the line stride.

---
 drivers/media/platform/ti-vpe/vpdma.c | 50 ++++++++++++++++++++++++++---------
 drivers/media/platform/ti-vpe/vpdma.h |  9 ++++---
 drivers/media/platform/ti-vpe/vpe.c   | 16 +++++++----
 3 files changed, 53 insertions(+), 22 deletions(-)
drivers/media/platform/ti-vpe/vpdma.c +37 -13
index 73dd38e..7248f16 100644
@@ -614,8 +614,15 @@ static void dump_dtd(struct vpdma_dtd *dtd)
 /*
  * append an outbound data transfer descriptor to the given descriptor list,
  * this sets up a 'client to memory' VPDMA transfer for the given VPDMA channel
+ *
+ * @list: vpdma desc list to which we add this decriptor
+ * @width: width of the image in pixels in memory
+ * @fmt: vpdma data format of the buffer
+ * dma_addr: dma address as seen by VPDMA
+ * chan: VPDMA channel
+ * flags: VPDMA flags to configure some descriptor fileds
  */
-void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
+void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width,
 		const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
 		enum vpdma_channel chan, u32 flags)
 {
@@ -633,8 +640,7 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
 			fmt->data_type == DATA_TYPE_C420)
 		depth = 8;
 
-	stride = ALIGN((depth * c_rect->width) >> 3, VPDMA_STRIDE_ALIGN);
-	dma_addr += (c_rect->left * depth) >> 3;
+	stride = ALIGN((depth * width) >> 3, VPDMA_STRIDE_ALIGN);
 
 	dtd = list->next;
 	WARN_ON((void *)(dtd + 1) > (list->buf.addr + list->buf.size));
@@ -664,31 +670,48 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
 /*
  * append an inbound data transfer descriptor to the given descriptor list,
  * this sets up a 'memory to client' VPDMA transfer for the given VPDMA channel
+ *
+ * @list: vpdma desc list to which we add this decriptor
+ * @width: width of the image in pixels in memory(not the cropped width)
+ * @c_rect: crop params of input image
+ * @fmt: vpdma data format of the buffer
+ * dma_addr: dma address as seen by VPDMA
+ * chan: VPDMA channel
+ * field: top or bottom field info of the input image
+ * flags: VPDMA flags to configure some descriptor fileds
+ * frame_width/height: the complete width/height of the image presented to the
+ *			client (this makes sense when multiple channels are
+ *			connected to the same client, forming a larger frame)
+ * start_h, start_v: position where the given channel starts providing pixel
+ *			data to the client (makes sense when multiple channels
+ *			contribute to the client)
  */
-void vpdma_add_in_dtd(struct vpdma_desc_list *list, int frame_width,
-		int frame_height, struct v4l2_rect *c_rect,
+void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width,
+		const struct v4l2_rect *c_rect,
 		const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
-		enum vpdma_channel chan, int field, u32 flags)
+		enum vpdma_channel chan, int field, u32 flags, int frame_width,
+		int frame_height, int start_h, int start_v)
 {
 	int priority = 0;
 	int notify = 1;
 	int depth = fmt->depth;
 	int channel, next_chan;
+	struct v4l2_rect rect = *c_rect;
 	int stride;
-	int height = c_rect->height;
 	struct vpdma_dtd *dtd;
 
 	channel = next_chan = chan_info[chan].num;
 
 	if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV &&
 			fmt->data_type == DATA_TYPE_C420) {
-		height >>= 1;
-		frame_height >>= 1;
+		rect.height >>= 1;
+		rect.top >>= 1;
 		depth = 8;
 	}
 
-	stride = ALIGN((depth * c_rect->width) >> 3, VPDMA_STRIDE_ALIGN);
-	dma_addr += (c_rect->left * depth) >> 3;
+	stride = ALIGN((depth * width) >> 3, VPDMA_STRIDE_ALIGN);
+
+	dma_addr += rect.top * stride + (rect.left * depth >> 3);
 
 	dtd = list->next;
 	WARN_ON((void *)(dtd + 1) > (list->buf.addr + list->buf.size));
@@ -701,13 +724,14 @@ void vpdma_add_in_dtd(struct vpdma_desc_list *list, int frame_width,
 					!!(flags & VPDMA_DATA_ODD_LINE_SKIP),
 					stride);
 
-	dtd->xfer_length_height = dtd_xfer_length_height(c_rect->width, height);
+	dtd->xfer_length_height = dtd_xfer_length_height(rect.width,
+					rect.height);
 	dtd->start_addr = (u32) dma_addr;
 	dtd->pkt_ctl = dtd_pkt_ctl(!!(flags & VPDMA_DATA_MODE_TILED),
 				DTD_DIR_IN, channel, priority, next_chan);
 	dtd->frame_width_height = dtd_frame_width_height(frame_width,
 					frame_height);
-	dtd->start_h_v = dtd_start_h_v(c_rect->left, c_rect->top);
+	dtd->start_h_v = dtd_start_h_v(start_h, start_v);
 	dtd->client_attr0 = 0;
 	dtd->client_attr1 = 0;
 
drivers/media/platform/ti-vpe/vpdma.h +5 -4
index bf5f8bb..850c8d5 100644
@@ -186,13 +186,14 @@ void vpdma_add_cfd_adb(struct vpdma_desc_list *list, int client,
 		struct vpdma_buf *adb);
 void vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list,
 		enum vpdma_channel chan);
-void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
+void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width,
 		const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
 		enum vpdma_channel chan, u32 flags);
-void vpdma_add_in_dtd(struct vpdma_desc_list *list, int frame_width,
-		int frame_height, struct v4l2_rect *c_rect,
+void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width,
+		const struct v4l2_rect *c_rect,
 		const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
-		enum vpdma_channel chan, int field, u32 flags);
+		enum vpdma_channel chan, int field, u32 flags, int frame_width,
+		int frame_height, int start_h, int start_v);
 
 /* vpdma list interrupt management */
 void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int list_num,
drivers/media/platform/ti-vpe/vpe.c +11 -5
index 3a610a6..6acdcd8 100644
@@ -986,7 +986,6 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port)
 	struct vpe_q_data *q_data = &ctx->q_data[Q_DATA_DST];
 	const struct vpe_port_data *p_data = &port_data[port];
 	struct vb2_buffer *vb = ctx->dst_vb;
-	struct v4l2_rect *c_rect = &q_data->c_rect;
 	struct vpe_fmt *fmt = q_data->fmt;
 	const struct vpdma_data_format *vpdma_fmt;
 	int mv_buf_selector = !ctx->src_mv_buf_selector;
@@ -1015,7 +1014,7 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port)
 	if (q_data->flags & Q_DATA_MODE_TILED)
 		flags |= VPDMA_DATA_MODE_TILED;
 
-	vpdma_add_out_dtd(&ctx->desc_list, c_rect, vpdma_fmt, dma_addr,
+	vpdma_add_out_dtd(&ctx->desc_list, q_data->width, vpdma_fmt, dma_addr,
 		p_data->channel, flags);
 }
 
@@ -1024,11 +1023,11 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port)
 	struct vpe_q_data *q_data = &ctx->q_data[Q_DATA_SRC];
 	const struct vpe_port_data *p_data = &port_data[port];
 	struct vb2_buffer *vb = ctx->src_vbs[p_data->vb_index];
-	struct v4l2_rect *c_rect = &q_data->c_rect;
 	struct vpe_fmt *fmt = q_data->fmt;
 	const struct vpdma_data_format *vpdma_fmt;
 	int mv_buf_selector = ctx->src_mv_buf_selector;
 	int field = vb->v4l2_buf.field == V4L2_FIELD_BOTTOM;
+	int frame_width, frame_height;
 	dma_addr_t dma_addr;
 	u32 flags = 0;
 
@@ -1055,8 +1054,15 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port)
 	if (q_data->flags & Q_DATA_MODE_TILED)
 		flags |= VPDMA_DATA_MODE_TILED;
 
-	vpdma_add_in_dtd(&ctx->desc_list, q_data->width, q_data->height,
-		c_rect, vpdma_fmt, dma_addr, p_data->channel, field, flags);
+	frame_width = q_data->c_rect.width;
+	frame_height = q_data->c_rect.height;
+
+	if (p_data->vb_part && fmt->fourcc == V4L2_PIX_FMT_NV12)
+		frame_height /= 2;
+
+	vpdma_add_in_dtd(&ctx->desc_list, q_data->width, &q_data->c_rect,
+		vpdma_fmt, dma_addr, p_data->channel, field, flags, frame_width,
+		frame_height, 0, 0);
 }
 
 /*
Signature · 1 line
1.8.3.2
#9 lore raw

PATCH 7/7 v4l: ti-vpe: Add crop support in VPE driver

In reply to Archit Taneja

Add crop ioctl ops. For VPE, cropping only makes sense with the input to VPE, or the V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE buffer type.

For the CAPTURE type, a S_CROP ioctl results in setting the crop region as the whole image itself, hence making crop dimensions same as the pix dimensions.

Setting the crop successfully should result in re-configuration of those registers which are affected when either source or destination dimensions change, set_srcdst_params() is called for this purpose.

Some standard crop parameter checks are done in __vpe_try_crop().

---
 drivers/media/platform/ti-vpe/vpe.c | 96 +++++++++++++++++++++++++++++++++++++
 1 file changed, 96 insertions(+)
drivers/media/platform/ti-vpe/vpe.c +96 -0
index 6acdcd8..c6778f4 100644
@@ -1585,6 +1585,98 @@ static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	return set_srcdst_params(ctx);
 }
 
+static int __vpe_try_crop(struct vpe_ctx *ctx, struct v4l2_crop *cr)
+{
+	struct vpe_q_data *q_data;
+
+	q_data = get_q_data(ctx, cr->type);
+	if (!q_data)
+		return -EINVAL;
+
+	/* we don't support crop on capture plane */
+	if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		cr->c.top = cr->c.left = 0;
+		cr->c.width = q_data->width;
+		cr->c.height = q_data->height;
+		return 0;
+	}
+
+	if (cr->c.top < 0 || cr->c.left < 0) {
+		vpe_err(ctx->dev, "negative values for top and left\n");
+		cr->c.top = cr->c.left = 0;
+	}
+
+	v4l_bound_align_image(&cr->c.width, MIN_W, q_data->width, 1,
+		&cr->c.height, MIN_H, q_data->height, H_ALIGN, S_ALIGN);
+
+	/* adjust left/top if cropping rectangle is out of bounds */
+	if (cr->c.left + cr->c.width > q_data->width)
+		cr->c.left = q_data->width - cr->c.width;
+	if (cr->c.top + cr->c.height > q_data->height)
+		cr->c.top = q_data->height - cr->c.height;
+
+	return 0;
+}
+
+static int vpe_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cr)
+{
+	struct vpe_ctx *ctx = file2ctx(file);
+	struct vpe_q_data *q_data;
+
+	q_data = get_q_data(ctx, cr->type);
+	if (!q_data)
+		return -EINVAL;
+
+	cr->bounds.left = 0;
+	cr->bounds.top = 0;
+	cr->bounds.width = q_data->width;
+	cr->bounds.height = q_data->height;
+	cr->defrect = cr->bounds;
+
+	return 0;
+}
+
+static int vpe_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+{
+	struct vpe_ctx *ctx = file2ctx(file);
+	struct vpe_q_data *q_data;
+
+	q_data = get_q_data(ctx, cr->type);
+	if (!q_data)
+		return -EINVAL;
+
+	cr->c = q_data->c_rect;
+
+	return 0;
+}
+
+static int vpe_s_crop(struct file *file, void *priv,
+		const struct v4l2_crop *crop)
+{
+	struct vpe_ctx *ctx = file2ctx(file);
+	struct vpe_q_data *q_data;
+	struct v4l2_crop cr = *crop;
+	int ret;
+
+	ret = __vpe_try_crop(ctx, &cr);
+	if (ret)
+		return ret;
+
+	q_data = get_q_data(ctx, cr.type);
+
+	if ((q_data->c_rect.left == cr.c.left) &&
+			(q_data->c_rect.top == cr.c.top) &&
+			(q_data->c_rect.width == cr.c.width) &&
+			(q_data->c_rect.height == cr.c.height)) {
+		vpe_dbg(ctx->dev, "requested crop values are already set\n");
+		return 0;
+	}
+
+	q_data->c_rect = cr.c;
+
+	return set_srcdst_params(ctx);
+}
+
 static int vpe_reqbufs(struct file *file, void *priv,
 		       struct v4l2_requestbuffers *reqbufs)
 {
@@ -1672,6 +1764,10 @@ static const struct v4l2_ioctl_ops vpe_ioctl_ops = {
 	.vidioc_try_fmt_vid_out_mplane	= vpe_try_fmt,
 	.vidioc_s_fmt_vid_out_mplane	= vpe_s_fmt,
 
+	.vidioc_cropcap			= vpe_cropcap,
+	.vidioc_g_crop			= vpe_g_crop,
+	.vidioc_s_crop			= vpe_s_crop,
+
 	.vidioc_reqbufs		= vpe_reqbufs,
 	.vidioc_querybuf	= vpe_querybuf,
 
Signature · 1 line
1.8.3.2
#10 lore raw

Re: [PATCH 7/7] v4l: ti-vpe: Add crop support in VPE driver

Hi Archit!

Quoted 11 lines · Archit Taneja

Add crop ioctl ops. For VPE, cropping only makes sense with the input to VPE, or the V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE buffer type.

For the CAPTURE type, a S_CROP ioctl results in setting the crop region as the whole image itself, hence making crop dimensions same as the pix dimensions.

Setting the crop successfully should result in re-configuration of those registers which are affected when either source or destination dimensions change, set_srcdst_params() is called for this purpose.

Some standard crop parameter checks are done in __vpe_try_crop().

Please use the selection ops instead: if you implement cropping with those then you'll support both the selection API and the old cropping API will be implemented by the v4l2 core using the selection ops. Two for the price of one...

Regards,

Hans

Quoted 121 lines
---
 drivers/media/platform/ti-vpe/vpe.c | 96 +++++++++++++++++++++++++++++++++++++
 1 file changed, 96 insertions(+)
drivers/media/platform/ti-vpe/vpe.c +96 -0
index 6acdcd8..c6778f4 100644
@@ -1585,6 +1585,98 @@ static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	return set_srcdst_params(ctx);
 }
 
+static int __vpe_try_crop(struct vpe_ctx *ctx, struct v4l2_crop *cr)
+{
+	struct vpe_q_data *q_data;
+
+	q_data = get_q_data(ctx, cr->type);
+	if (!q_data)
+		return -EINVAL;
+
+	/* we don't support crop on capture plane */
+	if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		cr->c.top = cr->c.left = 0;
+		cr->c.width = q_data->width;
+		cr->c.height = q_data->height;
+		return 0;
+	}
+
+	if (cr->c.top < 0 || cr->c.left < 0) {
+		vpe_err(ctx->dev, "negative values for top and left\n");
+		cr->c.top = cr->c.left = 0;
+	}
+
+	v4l_bound_align_image(&cr->c.width, MIN_W, q_data->width, 1,
+		&cr->c.height, MIN_H, q_data->height, H_ALIGN, S_ALIGN);
+
+	/* adjust left/top if cropping rectangle is out of bounds */
+	if (cr->c.left + cr->c.width > q_data->width)
+		cr->c.left = q_data->width - cr->c.width;
+	if (cr->c.top + cr->c.height > q_data->height)
+		cr->c.top = q_data->height - cr->c.height;
+
+	return 0;
+}
+
+static int vpe_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cr)
+{
+	struct vpe_ctx *ctx = file2ctx(file);
+	struct vpe_q_data *q_data;
+
+	q_data = get_q_data(ctx, cr->type);
+	if (!q_data)
+		return -EINVAL;
+
+	cr->bounds.left = 0;
+	cr->bounds.top = 0;
+	cr->bounds.width = q_data->width;
+	cr->bounds.height = q_data->height;
+	cr->defrect = cr->bounds;
+
+	return 0;
+}
+
+static int vpe_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+{
+	struct vpe_ctx *ctx = file2ctx(file);
+	struct vpe_q_data *q_data;
+
+	q_data = get_q_data(ctx, cr->type);
+	if (!q_data)
+		return -EINVAL;
+
+	cr->c = q_data->c_rect;
+
+	return 0;
+}
+
+static int vpe_s_crop(struct file *file, void *priv,
+		const struct v4l2_crop *crop)
+{
+	struct vpe_ctx *ctx = file2ctx(file);
+	struct vpe_q_data *q_data;
+	struct v4l2_crop cr = *crop;
+	int ret;
+
+	ret = __vpe_try_crop(ctx, &cr);
+	if (ret)
+		return ret;
+
+	q_data = get_q_data(ctx, cr.type);
+
+	if ((q_data->c_rect.left == cr.c.left) &&
+			(q_data->c_rect.top == cr.c.top) &&
+			(q_data->c_rect.width == cr.c.width) &&
+			(q_data->c_rect.height == cr.c.height)) {
+		vpe_dbg(ctx->dev, "requested crop values are already set\n");
+		return 0;
+	}
+
+	q_data->c_rect = cr.c;
+
+	return set_srcdst_params(ctx);
+}
+
 static int vpe_reqbufs(struct file *file, void *priv,
 		       struct v4l2_requestbuffers *reqbufs)
 {
@@ -1672,6 +1764,10 @@ static const struct v4l2_ioctl_ops vpe_ioctl_ops = {
 	.vidioc_try_fmt_vid_out_mplane	= vpe_try_fmt,
 	.vidioc_s_fmt_vid_out_mplane	= vpe_s_fmt,
 
+	.vidioc_cropcap			= vpe_cropcap,
+	.vidioc_g_crop			= vpe_g_crop,
+	.vidioc_s_crop			= vpe_s_crop,
+
 	.vidioc_reqbufs		= vpe_reqbufs,
 	.vidioc_querybuf	= vpe_querybuf,
 
#11 lore raw

Re: [PATCH 7/7] v4l: ti-vpe: Add crop support in VPE driver

Hi,

Quoted 13 lines · Hans Verkuil

Hi Archit!

Quoted 10 lines · Archit Taneja

Add crop ioctl ops. For VPE, cropping only makes sense with the input to VPE, or the V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE buffer type.

For the CAPTURE type, a S_CROP ioctl results in setting the crop region as the whole image itself, hence making crop dimensions same as the pix dimensions.

Setting the crop successfully should result in re-configuration of those registers which are affected when either source or destination dimensions change, set_srcdst_params() is called for this purpose.

Quoted 5 lines
Quoted 1 line

Some standard crop parameter checks are done in __vpe_try_crop().

Please use the selection ops instead: if you implement cropping with those then you'll support both the selection API and the old cropping API will be implemented by the v4l2 core using the selection ops. Two for the price of one...

<snip>

Thanks for the feedback. I'll use selection ops here.

Archit

#12 lore raw

RE: [PATCH 7/7] v4l: ti-vpe: Add crop support in VPE driver

Hi Archit,

Quoted 26 lines

From: Archit Taneja [mailto:[email protected]]
Sent: Monday, March 03, 2014 9:26 AM

Hi,

Quoted 4 lines · Hans Verkuil

Hi Archit!

Quoted 1 line · Archit Taneja

Add crop ioctl ops. For VPE, cropping only makes sense with the

input

Quoted 4 lines
Quoted 4 lines

to VPE, or the V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE buffer type.

For the CAPTURE type, a S_CROP ioctl results in setting the crop region as the whole image itself, hence making crop dimensions same

as the pix dimensions.

Quoted 10 lines
Quoted 6 lines

Setting the crop successfully should result in re-configuration of those registers which are affected when either source or destination dimensions change, set_srcdst_params() is called for this purpose.

Some standard crop parameter checks are done in __vpe_try_crop().

Please use the selection ops instead: if you implement cropping with those then you'll support both the selection API and the old cropping API will be implemented by the v4l2 core using the selection ops. Two

Quoted 7 lines

for the price of one...

<snip>

Thanks for the feedback. I'll use selection ops here.

From your reply I understand that you will send a v2 of these patches,

right?
If so, please correct the typos I mentioned in the patch 5/7.

Also, it is quite late for v3.15. I did already send a pull request to Mauro,
However I have one patch pending. Could you tell me when are you planning to post v2 of these patches? I want to decide whether should I wait for your patchset or should I send the second pull request with the pending patch as soon as possible.

Best wishes,

Signature · 2 lines
Kamil Debski
Samsung R&D Institute Poland
#13 lore raw

Re: [PATCH 7/7] v4l: ti-vpe: Add crop support in VPE driver

Hi,

Quoted 38 lines · Kamil Debski

Hi Archit,

Quoted 23 lines

From: Archit Taneja [mailto:[email protected]]
Sent: Monday, March 03, 2014 9:26 AM

Hi,

Quoted 4 lines · Hans Verkuil

Hi Archit!

Quoted 1 line · Archit Taneja

Add crop ioctl ops. For VPE, cropping only makes sense with the

input

Quoted 4 lines
Quoted 4 lines

to VPE, or the V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE buffer type.

For the CAPTURE type, a S_CROP ioctl results in setting the crop region as the whole image itself, hence making crop dimensions same

as the pix dimensions.

Quoted 7 lines
Quoted 6 lines

Setting the crop successfully should result in re-configuration of those registers which are affected when either source or destination dimensions change, set_srcdst_params() is called for this purpose.

Some standard crop parameter checks are done in __vpe_try_crop().

Quoted 8 lines
Quoted 3 lines

Please use the selection ops instead: if you implement cropping with those then you'll support both the selection API and the old cropping API will be implemented by the v4l2 core using the selection ops. Two

for the price of one...

<snip>

Thanks for the feedback. I'll use selection ops here.

From your reply I understand that you will send a v2 of these patches,
right?
If so, please correct the typos I mentioned in the patch 5/7.

Quoted 6 lines

Also, it is quite late for v3.15. I did already send a pull request to Mauro,
However I have one patch pending. Could you tell me when are you planning to post v2 of these patches? I want to decide whether should I wait for your patchset or should I send the second pull request with the pending patch as soon as possible.

I'll post a v2 of this set by tomorrow(India time). I have worked on a patch which converts it to selection ioctls, but I need to test it, and get some comments on whether I have implemented the selection ops correctly.

Thanks,
Archit

#14 lore raw

Re: [PATCH 7/7] v4l: ti-vpe: Add crop support in VPE driver

In reply to Hans Verkuil

Hi Hans,

Quoted 13 lines · Hans Verkuil

Hi Archit!

Quoted 10 lines · Archit Taneja

Add crop ioctl ops. For VPE, cropping only makes sense with the input to VPE, or the V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE buffer type.

For the CAPTURE type, a S_CROP ioctl results in setting the crop region as the whole image itself, hence making crop dimensions same as the pix dimensions.

Setting the crop successfully should result in re-configuration of those registers which are affected when either source or destination dimensions change, set_srcdst_params() is called for this purpose.

Quoted 5 lines
Quoted 1 line

Some standard crop parameter checks are done in __vpe_try_crop().

Please use the selection ops instead: if you implement cropping with those then you'll support both the selection API and the old cropping API will be implemented by the v4l2 core using the selection ops. Two for the price of one...

When using selection API, I was finding issues using the older cropping API. The v4l_s_crop() ioctl func assumes that "crop means compose for output devices". However, for a m2m device. It probably makes sense to provide the following configuration:

for V4L2_BUF_TYPE_VIDEO_OUTPUT (input to the mem to mem HW), use CROP target(to crop the input buffer)

and, for V4L2_BUF_TYPE_VIDEO_CAPTURE(output of the mem to mem HW), use COMPOSE target(to place the HW output into a larger region)

Don't you think forcing OUTPUT devices to 'COMPOSE' for older cropping API is a bit limiting?

Thanks,
Archit

#15 lore raw

Re: [PATCH 7/7] v4l: ti-vpe: Add crop support in VPE driver

Quoted 28 lines · Archit Taneja

Hi Hans,

Quoted 13 lines · Hans Verkuil

Hi Archit!

Quoted 10 lines · Archit Taneja

Add crop ioctl ops. For VPE, cropping only makes sense with the input to VPE, or the V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE buffer type.

For the CAPTURE type, a S_CROP ioctl results in setting the crop region as the whole image itself, hence making crop dimensions same as the pix dimensions.

Setting the crop successfully should result in re-configuration of those registers which are affected when either source or destination dimensions change, set_srcdst_params() is called for this purpose.

Quoted 5 lines
Quoted 1 line

Some standard crop parameter checks are done in __vpe_try_crop().

Please use the selection ops instead: if you implement cropping with those then you'll support both the selection API and the old cropping API will be implemented by the v4l2 core using the selection ops. Two for the price of one...

When using selection API, I was finding issues using the older cropping API. The v4l_s_crop() ioctl func assumes that "crop means compose for output devices". However, for a m2m device. It probably makes sense to provide the following configuration:

Quoted 8 lines

for V4L2_BUF_TYPE_VIDEO_OUTPUT (input to the mem to mem HW), use CROP target(to crop the input buffer)

and, for V4L2_BUF_TYPE_VIDEO_CAPTURE(output of the mem to mem HW), use COMPOSE target(to place the HW output into a larger region)

Don't you think forcing OUTPUT devices to 'COMPOSE' for older cropping API is a bit limiting?

Yes, and that's why the selection API was created to work around that limitation :-)

The old cropping API was insufficiently flexible for modern devices, so we came up with this replacement.

Another reason why you have to implement the selection API: it's the only way to implement your functionality.

Regards,

Hans

#16 lore raw

Re: [PATCH 7/7] v4l: ti-vpe: Add crop support in VPE driver

Hi,

Quoted 38 lines · Hans Verkuil
Quoted 28 lines · Archit Taneja

Hi Hans,

Quoted 13 lines · Hans Verkuil

Hi Archit!

Quoted 10 lines · Archit Taneja

Add crop ioctl ops. For VPE, cropping only makes sense with the input to VPE, or the V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE buffer type.

For the CAPTURE type, a S_CROP ioctl results in setting the crop region as the whole image itself, hence making crop dimensions same as the pix dimensions.

Setting the crop successfully should result in re-configuration of those registers which are affected when either source or destination dimensions change, set_srcdst_params() is called for this purpose.

Quoted 5 lines
Quoted 1 line

Some standard crop parameter checks are done in __vpe_try_crop().

Please use the selection ops instead: if you implement cropping with those then you'll support both the selection API and the old cropping API will be implemented by the v4l2 core using the selection ops. Two for the price of one...

When using selection API, I was finding issues using the older cropping API. The v4l_s_crop() ioctl func assumes that "crop means compose for output devices". However, for a m2m device. It probably makes sense to provide the following configuration:

Quoted 8 lines

for V4L2_BUF_TYPE_VIDEO_OUTPUT (input to the mem to mem HW), use CROP target(to crop the input buffer)

and, for V4L2_BUF_TYPE_VIDEO_CAPTURE(output of the mem to mem HW), use COMPOSE target(to place the HW output into a larger region)

Don't you think forcing OUTPUT devices to 'COMPOSE' for older cropping API is a bit limiting?

Quoted 8 lines

Yes, and that's why the selection API was created to work around that limitation :-)

The old cropping API was insufficiently flexible for modern devices, so we came up with this replacement.

Another reason why you have to implement the selection API: it's the only way to implement your functionality.

Okay, I'll go ahead with the selection API then :)

Archit

#17 lore raw

v2 cover v4l: ti-vpe: Some VPE fixes and enhancements

In reply to Archit Taneja

This patch set mainly consists of minor fixes for the VPE driver. These fixes ensure the following:

- The VPE module can be inserted and removed successively.
- Make sure that smaller resolutions like qcif work correctly.
- Prevent race condition between firmware loading and an open call to the v4l2 device.
- Prevent the possibility of output m2m queue not having sufficient 'ready' buffers.
- Some VPDMA data descriptor fields weren't understood correctly before. They are now used correctly.

The rest of the patches add some minor features like DMA buf support and cropping/composing.

Reference branch:

[email protected]:boddob/linux.git vpe_for_315

Changes in v2:

- selection API used instead of older cropping API.
- Typo fix.
- Some changes in patch 6/7 to support composing on the capture side of VPE.

Archit Taneja (7):
v4l: ti-vpe: Make sure in job_ready that we have the needed number of
dst_bufs
v4l: ti-vpe: register video device only when firmware is loaded
v4l: ti-vpe: Use video_device_release_empty
v4l: ti-vpe: Allow DMABUF buffer type support
v4l: ti-vpe: Allow usage of smaller images
v4l: ti-vpe: Fix some params in VPE data descriptors
v4l: ti-vpe: Add selection API in VPE driver

 drivers/media/platform/ti-vpe/vpdma.c |  68 +++++++---
 drivers/media/platform/ti-vpe/vpdma.h |  17 +--
 drivers/media/platform/ti-vpe/vpe.c   | 228 +++++++++++++++++++++++++++++-----
 3 files changed, 255 insertions(+), 58 deletions(-)
Signature · 1 line
1.8.3.2
#18 lore raw

PATCH v2 1/7 v4l: ti-vpe: Make sure in job_ready that we have the needed number of dst_bufs

VPE has a ctrl parameter which decides how many mem to mem transactions the active job from the job queue can perform.

The driver's job_ready() made sure that the number of ready source buffers are sufficient for the job to execute successfully. But it didn't make sure if there are sufficient ready destination buffers in the capture queue for the VPE output.

If the time taken by VPE to process a single frame is really slow, then it's possible that we don't need to imply such a restriction on the dst queue, but really fast transactions(small resolution, no de-interlacing) may cause us to hit the condition where we don't have any free buffers for the VPE to write on.

Add the extra check in job_ready() to make sure we have the sufficient amount of destination buffers.

---
 drivers/media/platform/ti-vpe/vpe.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/media/platform/ti-vpe/vpe.c +3 -0
index 1296c53..623e59e 100644
@@ -887,6 +887,9 @@ static int job_ready(void *priv)
 	if (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) < needed)
 		return 0;
 
+	if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < needed)
+		return 0;
+
 	return 1;
 }
 
Signature · 1 line
1.8.3.2
#19 lore raw

PATCH v2 2/7 v4l: ti-vpe: register video device only when firmware is loaded

In reply to Archit Taneja

vpe fops(vpe_open in particular) should be called only when VPDMA firmware is loaded. File operations on the video device are possible the moment it is registered.

Currently, we register the video device for VPE at driver probe, after calling a vpdma helper to initialize VPDMA and load firmware. This function is non-blocking(it calls request_firmware_nowait()), and doesn't ensure that the firmware is actually loaded when it returns.

We remove the device registration from vpe probe, and move it to a callback provided by the vpe driver to the vpdma library, through vpdma_create().

The ready field in vpdma_data is no longer needed since we always have firmware loaded before the device is registered.

A minor problem with this approach is that if the video_register_device fails(which doesn't really happen), the vpe platform device would be registered. however, there won't be any v4l2 device corresponding to it.

---
 drivers/media/platform/ti-vpe/vpdma.c |  8 +++--
 drivers/media/platform/ti-vpe/vpdma.h |  7 +++--
 drivers/media/platform/ti-vpe/vpe.c   | 55 ++++++++++++++++++++---------------
 3 files changed, 41 insertions(+), 29 deletions(-)
drivers/media/platform/ti-vpe/vpdma.c +5 -3
index e8175e7..73dd38e 100644
@@ -781,7 +781,7 @@ static void vpdma_firmware_cb(const struct firmware *f, void *context)
 	/* already initialized */
 	if (read_field_reg(vpdma, VPDMA_LIST_ATTR, VPDMA_LIST_RDY_MASK,
 			VPDMA_LIST_RDY_SHFT)) {
-		vpdma->ready = true;
+		vpdma->cb(vpdma->pdev);
 		return;
 	}
 
@@ -811,7 +811,7 @@ static void vpdma_firmware_cb(const struct firmware *f, void *context)
 		goto free_buf;
 	}
 
-	vpdma->ready = true;
+	vpdma->cb(vpdma->pdev);
 
 free_buf:
 	vpdma_unmap_desc_buf(vpdma, &fw_dma_buf);
@@ -839,7 +839,8 @@ static int vpdma_load_firmware(struct vpdma_data *vpdma)
 	return 0;
 }
 
-struct vpdma_data *vpdma_create(struct platform_device *pdev)
+struct vpdma_data *vpdma_create(struct platform_device *pdev,
+		void (*cb)(struct platform_device *pdev))
 {
 	struct resource *res;
 	struct vpdma_data *vpdma;
@@ -854,6 +855,7 @@ struct vpdma_data *vpdma_create(struct platform_device *pdev)
 	}
 
 	vpdma->pdev = pdev;
+	vpdma->cb = cb;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpdma");
 	if (res == NULL) {
drivers/media/platform/ti-vpe/vpdma.h +4 -3
index cf40f11..bf5f8bb 100644
@@ -35,8 +35,8 @@ struct vpdma_data {
 
 	struct platform_device	*pdev;
 
-	/* tells whether vpdma firmware is loaded or not */
-	bool ready;
+	/* callback to VPE driver when the firmware is loaded */
+	void (*cb)(struct platform_device *pdev);
 };
 
 enum vpdma_data_format_type {
@@ -208,6 +208,7 @@ void vpdma_set_frame_start_event(struct vpdma_data *vpdma,
 void vpdma_dump_regs(struct vpdma_data *vpdma);
 
 /* initialize vpdma, passed with VPE's platform device pointer */
-struct vpdma_data *vpdma_create(struct platform_device *pdev);
+struct vpdma_data *vpdma_create(struct platform_device *pdev,
+		void (*cb)(struct platform_device *pdev));
 
 #endif
drivers/media/platform/ti-vpe/vpe.c +32 -23

81 lines not on this page · raw message

Signature · 1 line
1.8.3.2
#20 lore raw

PATCH v2 3/7 v4l: ti-vpe: Use video_device_release_empty

In reply to Archit Taneja

The video_device struct is currently embedded in the driver data struct vpe_dev. A vpe_dev instance is allocated by the driver, and the memory for the vfd is a part of this struct.

The v4l2 core, however, manages the removal of the vfd region, through the video_device's .release() op, which currently is the helper video_device_release. This causes memory corruption, and leads to issues when we try to re-insert the vpe module.

Use the video_device_release_empty helper function instead

---
 drivers/media/platform/ti-vpe/vpe.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/platform/ti-vpe/vpe.c +1 -1
index 4243687..bb275f4 100644
@@ -1998,7 +1998,7 @@ static struct video_device vpe_videodev = {
 	.fops		= &vpe_fops,
 	.ioctl_ops	= &vpe_ioctl_ops,
 	.minor		= -1,
-	.release	= video_device_release,
+	.release	= video_device_release_empty,
 	.vfl_dir	= VFL_DIR_M2M,
 };
 
Signature · 1 line
1.8.3.2
#21 lore raw

PATCH v2 4/7 v4l: ti-vpe: Allow DMABUF buffer type support

In reply to Archit Taneja

For OMAP and DRA7x, we generally allocate video and graphics buffers through omapdrm since the corresponding omap-gem driver provides DMM-Tiler backed contiguous buffers. omapdrm is a dma-buf exporter. These buffers are used by other drivers in the video pipeline.

Add VB2_DMABUF flag to the io_modes of the vb2 output and capture queues. This allows the driver to import dma shared buffers.

---
 drivers/media/platform/ti-vpe/vpe.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/media/platform/ti-vpe/vpe.c +2 -2
index bb275f4..915029b 100644
@@ -1768,7 +1768,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
 
 	memset(src_vq, 0, sizeof(*src_vq));
 	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
-	src_vq->io_modes = VB2_MMAP;
+	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
 	src_vq->drv_priv = ctx;
 	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 	src_vq->ops = &vpe_qops;
@@ -1781,7 +1781,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
 
 	memset(dst_vq, 0, sizeof(*dst_vq));
 	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-	dst_vq->io_modes = VB2_MMAP;
+	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
 	dst_vq->drv_priv = ctx;
 	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 	dst_vq->ops = &vpe_qops;
Signature · 1 line
1.8.3.2
#22 lore raw

PATCH v2 5/7 v4l: ti-vpe: Allow usage of smaller images

In reply to Archit Taneja

The minimum width and height for VPE input/output was kept as 128 pixels. VPE doesn't have a constraint on the image height, it requires the image width to be at least 16 bytes.

Change the minimum supported dimensions to 32x32. This allows us to de-interlace qcif content. A smaller image size than 32x32 didn't make much sense, so stopped at this.

---
 drivers/media/platform/ti-vpe/vpe.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/media/platform/ti-vpe/vpe.c +2 -2
index 915029b..3a610a6 100644
@@ -49,8 +49,8 @@
 #define VPE_MODULE_NAME "vpe"
 
 /* minimum and maximum frame sizes */
-#define MIN_W		128
-#define MIN_H		128
+#define MIN_W		32
+#define MIN_H		32
 #define MAX_W		1920
 #define MAX_H		1080
 
Signature · 1 line
1.8.3.2
#23 lore raw

PATCH v2 6/7 v4l: ti-vpe: Fix some params in VPE data descriptors

In reply to Archit Taneja

Some parameters of the VPE descriptors were understood incorrectly. They are now fixed. The fixes are explained as follows:

- When adding an inbound data descriptor to the VPDMA descriptor list, we intend to use c_rect as the cropped region fetched by VPDMA. Therefore, c_rect->width shouldn't be used to calculate the line stride, the original image width should be used for that. We add a 'width' argument which gives the buffer width in memory.

- frame_width and frame_height describe the complete width and height of the client to which the channel is connected. If there are multiple channels fetching data and providing to the same client, the above 2 arguments should be the width and height of the region covered by all the channels. In the case where there is only one channel providing pixel data to the client (like in VPE), frame_width and frame_height should be the cropped width and cropped height respectively. The calculation of these params is done in the vpe driver now.

- start_h and start_v is also used in the case of multiple channels to describe where each channel should start filling pixel data. We don't use this in VPE, and pass 0s to the vpdma_add_in_dtd() helper.

- Some minor changes are made to the vpdma_add_out_dtd() helper. The c_rect param is used for specifying the 'composition' target, and 'width' is added to calculate the line stride.

---
 drivers/media/platform/ti-vpe/vpdma.c | 60 +++++++++++++++++++++++++++--------
 drivers/media/platform/ti-vpe/vpdma.h | 10 +++---
 drivers/media/platform/ti-vpe/vpe.c   | 18 +++++++----
 3 files changed, 64 insertions(+), 24 deletions(-)
drivers/media/platform/ti-vpe/vpdma.c +46 -14
index 73dd38e..a51a013 100644
@@ -614,8 +614,17 @@ static void dump_dtd(struct vpdma_dtd *dtd)
 /*
  * append an outbound data transfer descriptor to the given descriptor list,
  * this sets up a 'client to memory' VPDMA transfer for the given VPDMA channel
+ *
+ * @list: vpdma desc list to which we add this decriptor
+ * @width: width of the image in pixels in memory
+ * @c_rect: compose params of output image
+ * @fmt: vpdma data format of the buffer
+ * dma_addr: dma address as seen by VPDMA
+ * chan: VPDMA channel
+ * flags: VPDMA flags to configure some descriptor fileds
  */
-void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
+void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width,
+		const struct v4l2_rect *c_rect,
 		const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
 		enum vpdma_channel chan, u32 flags)
 {
@@ -623,6 +632,7 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
 	int field = 0;
 	int notify = 1;
 	int channel, next_chan;
+	struct v4l2_rect rect = *c_rect;
 	int depth = fmt->depth;
 	int stride;
 	struct vpdma_dtd *dtd;
@@ -630,11 +640,15 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
 	channel = next_chan = chan_info[chan].num;
 
 	if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV &&
-			fmt->data_type == DATA_TYPE_C420)
+			fmt->data_type == DATA_TYPE_C420) {
+		rect.height >>= 1;
+		rect.top >>= 1;
 		depth = 8;
+	}
 
-	stride = ALIGN((depth * c_rect->width) >> 3, VPDMA_STRIDE_ALIGN);
-	dma_addr += (c_rect->left * depth) >> 3;
+	stride = ALIGN((depth * width) >> 3, VPDMA_STRIDE_ALIGN);
+
+	dma_addr += rect.top * stride + (rect.left * depth >> 3);
 
 	dtd = list->next;
 	WARN_ON((void *)(dtd + 1) > (list->buf.addr + list->buf.size));
@@ -664,31 +678,48 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
 /*
  * append an inbound data transfer descriptor to the given descriptor list,
  * this sets up a 'memory to client' VPDMA transfer for the given VPDMA channel
+ *
+ * @list: vpdma desc list to which we add this decriptor
+ * @width: width of the image in pixels in memory(not the cropped width)
+ * @c_rect: crop params of input image
+ * @fmt: vpdma data format of the buffer
+ * dma_addr: dma address as seen by VPDMA
+ * chan: VPDMA channel
+ * field: top or bottom field info of the input image
+ * flags: VPDMA flags to configure some descriptor fileds
+ * frame_width/height: the complete width/height of the image presented to the
+ *			client (this makes sense when multiple channels are
+ *			connected to the same client, forming a larger frame)
+ * start_h, start_v: position where the given channel starts providing pixel
+ *			data to the client (makes sense when multiple channels
+ *			contribute to the client)
  */
-void vpdma_add_in_dtd(struct vpdma_desc_list *list, int frame_width,
-		int frame_height, struct v4l2_rect *c_rect,
+void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width,
+		const struct v4l2_rect *c_rect,
 		const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
-		enum vpdma_channel chan, int field, u32 flags)
+		enum vpdma_channel chan, int field, u32 flags, int frame_width,
+		int frame_height, int start_h, int start_v)
 {
 	int priority = 0;
 	int notify = 1;
 	int depth = fmt->depth;
 	int channel, next_chan;
+	struct v4l2_rect rect = *c_rect;
 	int stride;
-	int height = c_rect->height;
 	struct vpdma_dtd *dtd;
 
 	channel = next_chan = chan_info[chan].num;
 
 	if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV &&
 			fmt->data_type == DATA_TYPE_C420) {
-		height >>= 1;
-		frame_height >>= 1;
+		rect.height >>= 1;
+		rect.top >>= 1;
 		depth = 8;
 	}
 
-	stride = ALIGN((depth * c_rect->width) >> 3, VPDMA_STRIDE_ALIGN);
-	dma_addr += (c_rect->left * depth) >> 3;
+	stride = ALIGN((depth * width) >> 3, VPDMA_STRIDE_ALIGN);
+
+	dma_addr += rect.top * stride + (rect.left * depth >> 3);
 
 	dtd = list->next;
 	WARN_ON((void *)(dtd + 1) > (list->buf.addr + list->buf.size));
@@ -701,13 +732,14 @@ void vpdma_add_in_dtd(struct vpdma_desc_list *list, int frame_width,
 					!!(flags & VPDMA_DATA_ODD_LINE_SKIP),
 					stride);
 
-	dtd->xfer_length_height = dtd_xfer_length_height(c_rect->width, height);
+	dtd->xfer_length_height = dtd_xfer_length_height(rect.width,
+					rect.height);
 	dtd->start_addr = (u32) dma_addr;
 	dtd->pkt_ctl = dtd_pkt_ctl(!!(flags & VPDMA_DATA_MODE_TILED),
 				DTD_DIR_IN, channel, priority, next_chan);
 	dtd->frame_width_height = dtd_frame_width_height(frame_width,
 					frame_height);
-	dtd->start_h_v = dtd_start_h_v(c_rect->left, c_rect->top);
+	dtd->start_h_v = dtd_start_h_v(start_h, start_v);
 	dtd->client_attr0 = 0;
 	dtd->client_attr1 = 0;
 
drivers/media/platform/ti-vpe/vpdma.h +6 -4
index bf5f8bb..2bd8fb0 100644
@@ -186,13 +186,15 @@ void vpdma_add_cfd_adb(struct vpdma_desc_list *list, int client,
 		struct vpdma_buf *adb);
 void vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list,
 		enum vpdma_channel chan);
-void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
+void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width,
+		const struct v4l2_rect *c_rect,
 		const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
 		enum vpdma_channel chan, u32 flags);
-void vpdma_add_in_dtd(struct vpdma_desc_list *list, int frame_width,
-		int frame_height, struct v4l2_rect *c_rect,
+void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width,
+		const struct v4l2_rect *c_rect,
 		const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
-		enum vpdma_channel chan, int field, u32 flags);
+		enum vpdma_channel chan, int field, u32 flags, int frame_width,
+		int frame_height, int start_h, int start_v);
 
 /* vpdma list interrupt management */
 void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int list_num,
drivers/media/platform/ti-vpe/vpe.c +12 -6
index 3a610a6..03a6846 100644
@@ -986,7 +986,6 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port)
 	struct vpe_q_data *q_data = &ctx->q_data[Q_DATA_DST];
 	const struct vpe_port_data *p_data = &port_data[port];
 	struct vb2_buffer *vb = ctx->dst_vb;
-	struct v4l2_rect *c_rect = &q_data->c_rect;
 	struct vpe_fmt *fmt = q_data->fmt;
 	const struct vpdma_data_format *vpdma_fmt;
 	int mv_buf_selector = !ctx->src_mv_buf_selector;
@@ -1015,8 +1014,8 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port)
 	if (q_data->flags & Q_DATA_MODE_TILED)
 		flags |= VPDMA_DATA_MODE_TILED;
 
-	vpdma_add_out_dtd(&ctx->desc_list, c_rect, vpdma_fmt, dma_addr,
-		p_data->channel, flags);
+	vpdma_add_out_dtd(&ctx->desc_list, q_data->width, &q_data->c_rect,
+		vpdma_fmt, dma_addr, p_data->channel, flags);
 }
 
 static void add_in_dtd(struct vpe_ctx *ctx, int port)
@@ -1024,11 +1023,11 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port)
 	struct vpe_q_data *q_data = &ctx->q_data[Q_DATA_SRC];
 	const struct vpe_port_data *p_data = &port_data[port];
 	struct vb2_buffer *vb = ctx->src_vbs[p_data->vb_index];
-	struct v4l2_rect *c_rect = &q_data->c_rect;
 	struct vpe_fmt *fmt = q_data->fmt;
 	const struct vpdma_data_format *vpdma_fmt;
 	int mv_buf_selector = ctx->src_mv_buf_selector;
 	int field = vb->v4l2_buf.field == V4L2_FIELD_BOTTOM;
+	int frame_width, frame_height;
 	dma_addr_t dma_addr;
 	u32 flags = 0;
 
@@ -1055,8 +1054,15 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port)
 	if (q_data->flags & Q_DATA_MODE_TILED)
 		flags |= VPDMA_DATA_MODE_TILED;
 
-	vpdma_add_in_dtd(&ctx->desc_list, q_data->width, q_data->height,
-		c_rect, vpdma_fmt, dma_addr, p_data->channel, field, flags);
+	frame_width = q_data->c_rect.width;
+	frame_height = q_data->c_rect.height;
+
+	if (p_data->vb_part && fmt->fourcc == V4L2_PIX_FMT_NV12)
+		frame_height /= 2;
+
+	vpdma_add_in_dtd(&ctx->desc_list, q_data->width, &q_data->c_rect,
+		vpdma_fmt, dma_addr, p_data->channel, field, flags, frame_width,
+		frame_height, 0, 0);
 }
 
 /*
Signature · 1 line
1.8.3.2
#24 lore raw

PATCH v2 7/7 v4l: ti-vpe: Add selection API in VPE driver

In reply to Archit Taneja

Add selection ioctl ops. For VPE, cropping makes sense only for the input to VPE(or V4L2_BUF_TYPE_VIDEO_OUTPUT/MPLANE buffers) and composing makes sense only for the output of VPE(or V4L2_BUF_TYPE_VIDEO_CAPTURE/MPLANE buffers).

For the CAPTURE type, V4L2_SEL_TGT_COMPOSE results in VPE writing the output in a rectangle within the capture buffer. For the OUTPUT type, V4L2_SEL_TGT_CROP results in selecting a rectangle region within the source buffer.

Setting the crop/compose rectangles should successfully result in re-configuration of registers which are affected when either source or destination dimensions change, set_srcdst_params() is called for this purpose.

---
 drivers/media/platform/ti-vpe/vpe.c | 142 ++++++++++++++++++++++++++++++++++++
 1 file changed, 142 insertions(+)
drivers/media/platform/ti-vpe/vpe.c +142 -0
index 03a6846..b938590 100644
@@ -410,8 +410,10 @@ static struct vpe_q_data *get_q_data(struct vpe_ctx *ctx,
 {
 	switch (type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 		return &ctx->q_data[Q_DATA_SRC];
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 		return &ctx->q_data[Q_DATA_DST];
 	default:
 		BUG();
@@ -1585,6 +1587,143 @@ static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	return set_srcdst_params(ctx);
 }
 
+static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s)
+{
+	struct vpe_q_data *q_data;
+
+	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, s->type);
+	if (!q_data)
+		return -EINVAL;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE:
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		/*
+		 * COMPOSE target is only valid for capture buffer type, for
+		 * output buffer type, assign existing crop parameters to the
+		 * selection rectangle
+		 */
+		if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+			break;
+		} else {
+			s->r = q_data->c_rect;
+			return 0;
+		}
+
+	case V4L2_SEL_TGT_CROP:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		/*
+		 * CROP target is only valid for output buffer type, for capture
+		 * buffer type, assign existing compose parameters to the
+		 * selection rectangle
+		 */
+		if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+			break;
+		} else {
+			s->r = q_data->c_rect;
+			return 0;
+		}
+	default:
+		return -EINVAL;
+	}
+
+	if (s->r.top < 0 || s->r.left < 0) {
+		vpe_err(ctx->dev, "negative values for top and left\n");
+		s->r.top = s->r.left = 0;
+	}
+
+	v4l_bound_align_image(&s->r.width, MIN_W, q_data->width, 1,
+		&s->r.height, MIN_H, q_data->height, H_ALIGN, S_ALIGN);
+
+	/* adjust left/top if cropping rectangle is out of bounds */
+	if (s->r.left + s->r.width > q_data->width)
+		s->r.left = q_data->width - s->r.width;
+	if (s->r.top + s->r.height > q_data->height)
+		s->r.top = q_data->height - s->r.height;
+
+	return 0;
+}
+
+static int vpe_g_selection(struct file *file, void *fh,
+		struct v4l2_selection *s)
+{
+	struct vpe_ctx *ctx = file2ctx(file);
+	struct vpe_q_data *q_data;
+
+	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, s->type);
+	if (!q_data)
+		return -EINVAL;
+
+	switch (s->target) {
+	/* return width and height from S_FMT of the respective buffer type */
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+		s->r.left = 0;
+		s->r.top = 0;
+		s->r.width = q_data->width;
+		s->r.height = q_data->height;
+		return 0;
+
+	/*
+	 * CROP target holds for the output buffer type, and COMPOSE target
+	 * holds for the capture buffer type. We still return the c_rect params
+	 * for both the target types.
+	 */
+	case V4L2_SEL_TGT_COMPOSE:
+	case V4L2_SEL_TGT_CROP:
+		s->r.left = q_data->c_rect.left;
+		s->r.top = q_data->c_rect.top;
+		s->r.width = q_data->c_rect.width;
+		s->r.height = q_data->c_rect.height;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+
+static int vpe_s_selection(struct file *file, void *fh,
+		struct v4l2_selection *s)
+{
+	struct vpe_ctx *ctx = file2ctx(file);
+	struct vpe_q_data *q_data;
+	struct v4l2_selection sel = *s;
+	int ret;
+
+	ret = __vpe_try_selection(ctx, &sel);
+	if (ret)
+		return ret;
+
+	q_data = get_q_data(ctx, sel.type);
+	if (!q_data)
+		return -EINVAL;
+
+	if ((q_data->c_rect.left == sel.r.left) &&
+			(q_data->c_rect.top == sel.r.top) &&
+			(q_data->c_rect.width == sel.r.width) &&
+			(q_data->c_rect.height == sel.r.height)) {
+		vpe_dbg(ctx->dev,
+			"requested crop/compose values are already set\n");
+		return 0;
+	}
+
+	q_data->c_rect = sel.r;
+
+	return set_srcdst_params(ctx);
+}
+
 static int vpe_reqbufs(struct file *file, void *priv,
 		       struct v4l2_requestbuffers *reqbufs)
 {
@@ -1672,6 +1811,9 @@ static const struct v4l2_ioctl_ops vpe_ioctl_ops = {
 	.vidioc_try_fmt_vid_out_mplane	= vpe_try_fmt,
 	.vidioc_s_fmt_vid_out_mplane	= vpe_s_fmt,
 
+	.vidioc_g_selection		= vpe_g_selection,
+	.vidioc_s_selection		= vpe_s_selection,
+
 	.vidioc_reqbufs		= vpe_reqbufs,
 	.vidioc_querybuf	= vpe_querybuf,
 
Signature · 1 line
1.8.3.2
#25 lore raw

Re: [PATCH v2 7/7] v4l: ti-vpe: Add selection API in VPE driver

Hi Archit,

Quoted 22 lines · Archit Taneja

Add selection ioctl ops. For VPE, cropping makes sense only for the input to VPE(or V4L2_BUF_TYPE_VIDEO_OUTPUT/MPLANE buffers) and composing makes sense only for the output of VPE(or V4L2_BUF_TYPE_VIDEO_CAPTURE/MPLANE buffers).

For the CAPTURE type, V4L2_SEL_TGT_COMPOSE results in VPE writing the output in a rectangle within the capture buffer. For the OUTPUT type, V4L2_SEL_TGT_CROP results in selecting a rectangle region within the source buffer.

Setting the crop/compose rectangles should successfully result in re-configuration of registers which are affected when either source or destination dimensions change, set_srcdst_params() is called for this purpose.

---
 drivers/media/platform/ti-vpe/vpe.c | 142 ++++++++++++++++++++++++++++++++++++
 1 file changed, 142 insertions(+)
drivers/media/platform/ti-vpe/vpe.c +0 -0
index 03a6846..b938590 100644

drivers/media/platform/ti-vpe/vpe.c static struct vpe_q_data *get_q_data(struct vpe_ctx *ctx, · line 416

Quoted 7 lines
drivers/media/platform/ti-vpe/vpe.c +2 -0
@@ -410,8 +410,10 @@ static struct vpe_q_data *get_q_data(struct vpe_ctx *ctx,
 {
 	switch (type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 		return &ctx->q_data[Q_DATA_SRC];
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:

I noticed that the querycap implementation is wrong. It reports V4L2_CAP_VIDEO_M2M instead of V4L2_CAP_VIDEO_M2M_MPLANE.

This driver is using the multiplanar formats, so the M2M_MPLANE cap should be set.

This should be a separate patch.

BTW, did you test the driver with the v4l2-compliance tool? The latest version
(http://git.linuxtv.org/v4l-utils.git) has m2m support.

However, if you want to test streaming (the -s option), then you will probably need to base your kernel on this tree:

http://git.linuxtv.org/hverkuil/media_tree.git/shortlog/refs/heads/vb2-part1

That branch contains a pile of fixes for vb2 and without that v4l2-compliance -s will fail a number of tests.

Quoted 21 lines
drivers/media/platform/ti-vpe/vpe.c +14 -0
 		return &ctx->q_data[Q_DATA_DST];
 	default:
 		BUG();
@@ -1585,6 +1587,143 @@ static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	return set_srcdst_params(ctx);
 }
 
+static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s)
+{
+	struct vpe_q_data *q_data;
+
+	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, s->type);
+	if (!q_data)
+		return -EINVAL;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE:

drivers/media/platform/ti-vpe/vpe.c static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) · line 1613

Quoted 10 lines
drivers/media/platform/ti-vpe/vpe.c +10 -0
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		/*
+		 * COMPOSE target is only valid for capture buffer type, for
+		 * output buffer type, assign existing crop parameters to the
+		 * selection rectangle
+		 */
+		if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+			break;
+		} else {

No need for the 'else' keywork here.

Quoted 5 lines
drivers/media/platform/ti-vpe/vpe.c +5 -0
+			s->r = q_data->c_rect;
+			return 0;
+		}
+
+	case V4L2_SEL_TGT_CROP:

drivers/media/platform/ti-vpe/vpe.c static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) · line 1628

Quoted 10 lines
drivers/media/platform/ti-vpe/vpe.c +10 -0
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		/*
+		 * CROP target is only valid for output buffer type, for capture
+		 * buffer type, assign existing compose parameters to the
+		 * selection rectangle
+		 */
+		if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+			break;
+		} else {

Ditto.

Quoted 103 lines
drivers/media/platform/ti-vpe/vpe.c +98 -0
+			s->r = q_data->c_rect;
+			return 0;
+		}
+	default:
+		return -EINVAL;
+	}
+
+	if (s->r.top < 0 || s->r.left < 0) {
+		vpe_err(ctx->dev, "negative values for top and left\n");
+		s->r.top = s->r.left = 0;
+	}
+
+	v4l_bound_align_image(&s->r.width, MIN_W, q_data->width, 1,
+		&s->r.height, MIN_H, q_data->height, H_ALIGN, S_ALIGN);
+
+	/* adjust left/top if cropping rectangle is out of bounds */
+	if (s->r.left + s->r.width > q_data->width)
+		s->r.left = q_data->width - s->r.width;
+	if (s->r.top + s->r.height > q_data->height)
+		s->r.top = q_data->height - s->r.height;
+
+	return 0;
+}
+
+static int vpe_g_selection(struct file *file, void *fh,
+		struct v4l2_selection *s)
+{
+	struct vpe_ctx *ctx = file2ctx(file);
+	struct vpe_q_data *q_data;
+
+	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, s->type);
+	if (!q_data)
+		return -EINVAL;
+
+	switch (s->target) {
+	/* return width and height from S_FMT of the respective buffer type */
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+		s->r.left = 0;
+		s->r.top = 0;
+		s->r.width = q_data->width;
+		s->r.height = q_data->height;
+		return 0;
+
+	/*
+	 * CROP target holds for the output buffer type, and COMPOSE target
+	 * holds for the capture buffer type. We still return the c_rect params
+	 * for both the target types.
+	 */
+	case V4L2_SEL_TGT_COMPOSE:
+	case V4L2_SEL_TGT_CROP:
+		s->r.left = q_data->c_rect.left;
+		s->r.top = q_data->c_rect.top;
+		s->r.width = q_data->c_rect.width;
+		s->r.height = q_data->c_rect.height;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+
+static int vpe_s_selection(struct file *file, void *fh,
+		struct v4l2_selection *s)
+{
+	struct vpe_ctx *ctx = file2ctx(file);
+	struct vpe_q_data *q_data;
+	struct v4l2_selection sel = *s;
+	int ret;
+
+	ret = __vpe_try_selection(ctx, &sel);
+	if (ret)
+		return ret;
+
+	q_data = get_q_data(ctx, sel.type);
+	if (!q_data)
+		return -EINVAL;
+
+	if ((q_data->c_rect.left == sel.r.left) &&
+			(q_data->c_rect.top == sel.r.top) &&
+			(q_data->c_rect.width == sel.r.width) &&
+			(q_data->c_rect.height == sel.r.height)) {
+		vpe_dbg(ctx->dev,
+			"requested crop/compose values are already set\n");
+		return 0;
+	}
+
+	q_data->c_rect = sel.r;
+
+	return set_srcdst_params(ctx);
+}
+
 static int vpe_reqbufs(struct file *file, void *priv,
 		       struct v4l2_requestbuffers *reqbufs)
 {

drivers/media/platform/ti-vpe/vpe.c static const struct v4l2_ioctl_ops vpe_ioctl_ops = { · line 1819

Quoted 9 lines
drivers/media/platform/ti-vpe/vpe.c +3 -0
@@ -1672,6 +1811,9 @@ static const struct v4l2_ioctl_ops vpe_ioctl_ops = {
 	.vidioc_try_fmt_vid_out_mplane	= vpe_try_fmt,
 	.vidioc_s_fmt_vid_out_mplane	= vpe_s_fmt,
 
+	.vidioc_g_selection		= vpe_g_selection,
+	.vidioc_s_selection		= vpe_s_selection,
+
 	.vidioc_reqbufs		= vpe_reqbufs,
 	.vidioc_querybuf	= vpe_querybuf,
 

Regards,

Hans

#26 lore raw

Re: [PATCH v2 7/7] v4l: ti-vpe: Add selection API in VPE driver

Hi,

Quoted 36 lines · Hans Verkuil

Hi Archit,

Quoted 22 lines · Archit Taneja

Add selection ioctl ops. For VPE, cropping makes sense only for the input to VPE(or V4L2_BUF_TYPE_VIDEO_OUTPUT/MPLANE buffers) and composing makes sense only for the output of VPE(or V4L2_BUF_TYPE_VIDEO_CAPTURE/MPLANE buffers).

For the CAPTURE type, V4L2_SEL_TGT_COMPOSE results in VPE writing the output in a rectangle within the capture buffer. For the OUTPUT type, V4L2_SEL_TGT_CROP results in selecting a rectangle region within the source buffer.

Setting the crop/compose rectangles should successfully result in re-configuration of registers which are affected when either source or destination dimensions change, set_srcdst_params() is called for this purpose.

---
  drivers/media/platform/ti-vpe/vpe.c | 142 ++++++++++++++++++++++++++++++++++++
  1 file changed, 142 insertions(+)
drivers/media/platform/ti-vpe/vpe.c +0 -0
index 03a6846..b938590 100644

drivers/media/platform/ti-vpe/vpe.c static struct vpe_q_data *get_q_data(struct vpe_ctx *ctx, · line 416

Quoted 7 lines
drivers/media/platform/ti-vpe/vpe.c +2 -0
@@ -410,8 +410,10 @@ static struct vpe_q_data *get_q_data(struct vpe_ctx *ctx,
  {
  	switch (type) {
  	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
  		return &ctx->q_data[Q_DATA_SRC];
  	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:

I noticed that the querycap implementation is wrong. It reports V4L2_CAP_VIDEO_M2M instead of V4L2_CAP_VIDEO_M2M_MPLANE.

Quoted 4 lines

This driver is using the multiplanar formats, so the M2M_MPLANE cap should be set.

This should be a separate patch.

Thanks for pointing this out, I'll make a patch for that.

Quoted 4 lines

BTW, did you test the driver with the v4l2-compliance tool? The latest version
(http://git.linuxtv.org/v4l-utils.git) has m2m support.

I haven't tested it with this yet.

Quoted 4 lines

However, if you want to test streaming (the -s option), then you will probably need to base your kernel on this tree:

http://git.linuxtv.org/hverkuil/media_tree.git/shortlog/refs/heads/vb2-part1

I can give it a try. It'll probably take a bit more time to try this out. I'll need to port some minor DRA7x stuff.

Kamil,

Do you think you have some more time for the m2m pull request?

Quoted 47 lines

That branch contains a pile of fixes for vb2 and without that v4l2-compliance -s will fail a number of tests.

Quoted 21 lines
drivers/media/platform/ti-vpe/vpe.c +14 -0
  		return &ctx->q_data[Q_DATA_DST];
  	default:
  		BUG();
@@ -1585,6 +1587,143 @@ static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
  	return set_srcdst_params(ctx);
  }
 
+static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s)
+{
+	struct vpe_q_data *q_data;
+
+	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, s->type);
+	if (!q_data)
+		return -EINVAL;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE:

drivers/media/platform/ti-vpe/vpe.c static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) · line 1613

Quoted 10 lines
drivers/media/platform/ti-vpe/vpe.c +10 -0
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		/*
+		 * COMPOSE target is only valid for capture buffer type, for
+		 * output buffer type, assign existing crop parameters to the
+		 * selection rectangle
+		 */
+		if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+			break;
+		} else {

No need for the 'else' keywork here.

Quoted 9 lines
drivers/media/platform/ti-vpe/vpe.c +9 -0
+			s->r = q_data->c_rect;
+			return 0;
+		}
+
+	case V4L2_SEL_TGT_CROP:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		/*
+		 * CROP target is only valid for output buffer type, for capture
Quoted 8 lines

drivers/media/platform/ti-vpe/vpe.c static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) · line 1628

Quoted 6 lines
drivers/media/platform/ti-vpe/vpe.c +6 -0
+		 * buffer type, assign existing compose parameters to the
+		 * selection rectangle
+		 */
+		if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+			break;
+		} else {

Ditto.

Thanks. I'll fix these.

I had a minor question about the selection API:

Are the V4L2_SET_TGT_CROP/COMPOSE_DEFAULT and the corresponding 'BOUNDS' targets supposed to be used with VIDIOC_S_SELECTION? If so, what's the expect behaviour?

Thanks,
Archit

#27 lore raw

Re: [PATCH v2 7/7] v4l: ti-vpe: Add selection API in VPE driver

Quoted 5 lines · Archit Taneja

I had a minor question about the selection API:

Are the V4L2_SET_TGT_CROP/COMPOSE_DEFAULT and the corresponding 'BOUNDS' targets supposed to be used with VIDIOC_S_SELECTION? If so, what's the expect behaviour?

No, those are read only in practice. So only used with G_SELECTION, never with S_SELECTION.

Regards,

Hans

#28 lore raw

Re: [PATCH v2 7/7] v4l: ti-vpe: Add selection API in VPE driver

Hi Hans,

Quoted 9 lines · Hans Verkuil
Quoted 5 lines · Archit Taneja

I had a minor question about the selection API:

Are the V4L2_SET_TGT_CROP/COMPOSE_DEFAULT and the corresponding 'BOUNDS' targets supposed to be used with VIDIOC_S_SELECTION? If so, what's the expect behaviour?

No, those are read only in practice. So only used with G_SELECTION, never with S_SELECTION.

<snip>

I tried the v4l2-compliance thing. It's awesome! And a bit annoying too when it comes to fixing little things needed for compliance :). But it's required, and I hope to fix these eventually.

After a few small fixes in the driver, I get the results as below. I am debugging the cause of try_fmt and s_fmt failures. I'm not sure why the streaming test fails with MMAP, the logs of my driver show that a successful mem2mem transaction happened.

I tried this on the 'vb2-part1' branch as you suggested.

Do you think I can go ahead with posting the v3 patch set for 3.15, and work on fixing the compliance issue for the -rc fixes?

Thanks,
Archit

# ./utils/v4l2-compliance/v4l2-compliance  -v --streaming=10
root@localhost:~/source_trees/v4l-utils# Driver Info:
        Driver name   : vpe
        Card type     : vpe
        Bus info      : platform:vpe
        Driver version: 3.14.0
        Capabilities  : 0x84004000
                Video Memory-to-Memory Multiplanar
                Streaming
                Device Capabilities
        Device Caps   : 0x04004000
                Video Memory-to-Memory Multiplanar
                Streaming

Compliance test for device /dev/video0 (not using libv4l2):

Required ioctls:
test VIDIOC_QUERYCAP: OK

Allow for multiple opens:
test second video open: OK
test VIDIOC_QUERYCAP: OK
test VIDIOC_G/S_PRIORITY: OK

Debug ioctls:
test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported) test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
test VIDIOC_G/S_TUNER: OK (Not Supported) test VIDIOC_G/S_FREQUENCY: OK (Not Supported) test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported) test VIDIOC_ENUMAUDIO: OK (Not Supported) test VIDIOC_G/S/ENUMINPUT: OK (Not Supported) test VIDIOC_G/S_AUDIO: OK (Not Supported)
Inputs: 0 Audio Inputs: 0 Tuners: 0

Output ioctls:
test VIDIOC_G/S_MODULATOR: OK (Not Supported) test VIDIOC_G/S_FREQUENCY: OK (Not Supported) test VIDIOC_ENUMAUDOUT: OK (Not Supported) test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported) test VIDIOC_G/S_AUDOUT: OK (Not Supported)
Outputs: 0 Audio Outputs: 0 Modulators: 0

Control ioctls:
info: checking v4l2_queryctrl of control 'User
Controls' (0x00980001)
info: checking v4l2_queryctrl of control 'Buffers Per
Transaction' (0x00981950)
info: checking v4l2_queryctrl of control 'Buffers Per
Transaction' (0x08000000)
test VIDIOC_QUERYCTRL/MENU: OK
info: checking control 'User Controls' (0x00980001)
info: checking control 'Buffers Per Transaction'
(0x00981950)
test VIDIOC_G/S_CTRL: OK
info: checking extended control 'User Controls'
(0x00980001)
info: checking extended control 'Buffers Per
Transaction' (0x00981950)
test VIDIOC_G/S/TRY_EXT_CTRLS: OK
info: checking control event 'User Controls' (0x00980001)
info: checking control event 'Buffers Per Transaction'
(0x00981950)
test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK
test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
Standard Controls: 1 Private Controls: 1

Input/Output configuration ioctls:
test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported) test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported) test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)

Format ioctls:
info: found 8 formats for buftype 9
info: found 4 formats for buftype 10
test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK test VIDIOC_G/S_PARM: OK (Not Supported)
test VIDIOC_G_FBUF: OK (Not Supported)
test VIDIOC_G_FMT: OK
fail: v4l2-test-formats.cpp(614): Video Capture
Multiplanar: TRY_FMT(G_FMT) != G_FMT
test VIDIOC_TRY_FMT: FAIL
warn: v4l2-test-formats.cpp(834): S_FMT cannot handle
an invalid pixelformat.
warn: v4l2-test-formats.cpp(835): This may or may not
be a problem. For more information see:

                warn: v4l2-test-formats.cpp(836): 
http://www.mail-archive.com/[email protected]/msg56550.html
                fail: v4l2-test-formats.cpp(420): pix_mp.reserved not 
zeroed
                fail: v4l2-test-formats.cpp(851): Video Capture 

Multiplanar is valid, but no S_FMT was implemented
test VIDIOC_S_FMT: FAIL
test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)

Codec ioctls:
test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported) test VIDIOC_G_ENC_INDEX: OK (Not Supported) test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Buffer ioctls:
info: test buftype Video Capture Multiplanar
warn: v4l2-test-buffers.cpp(403): VIDIOC_CREATE_BUFS
not supported
info: test buftype Video Output Multiplanar
warn: v4l2-test-buffers.cpp(403): VIDIOC_CREATE_BUFS
not supported
test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
test VIDIOC_EXPBUF: OK (Not Supported)
test read/write: OK (Not Supported)
Video Capture Multiplanar (polling):
Buffer: 0 Sequence: 0 Field: Top Timestamp: 113.178208s
fail: v4l2-test-buffers.cpp(222): buf.field !=
cur_fmt.fmt.pix.field

                fail: v4l2-test-buffers.cpp(630): checkQueryBuf(node, 
buf, bufs.type, bufs.memory, buf.index, Dequeued, last_seq)
                fail: v4l2-test-buffers.cpp(1038): captureBufs(node, 

bufs, m2m_bufs, frame_count, true)
test MMAP: FAIL
test USERPTR: OK (Not Supported)
test DMABUF: Cannot test, specify --expbuf-device

Total: 40, Succeeded: 37, Failed: 3, Warnings: 5

[1]+ Exit 1 ./utils/v4l2-compliance/v4l2-compliance -v --streaming=10

#29 lore raw

Re: [PATCH v2 7/7] v4l: ti-vpe: Add selection API in VPE driver

Quoted 24 lines · Archit Taneja

Hi Hans,

Quoted 9 lines · Hans Verkuil
Quoted 5 lines · Archit Taneja

I had a minor question about the selection API:

Are the V4L2_SET_TGT_CROP/COMPOSE_DEFAULT and the corresponding 'BOUNDS' targets supposed to be used with VIDIOC_S_SELECTION? If so, what's the expect behaviour?

No, those are read only in practice. So only used with G_SELECTION, never with S_SELECTION.

<snip>

I tried the v4l2-compliance thing. It's awesome! And a bit annoying too when it comes to fixing little things needed for compliance :). But it's required, and I hope to fix these eventually.

After a few small fixes in the driver, I get the results as below. I am debugging the cause of try_fmt and s_fmt failures. I'm not sure why the streaming test fails with MMAP, the logs of my driver show that a successful mem2mem transaction happened.

Quoted 4 lines

I tried this on the 'vb2-part1' branch as you suggested.

Do you think I can go ahead with posting the v3 patch set for 3.15, and work on fixing the compliance issue for the -rc fixes?

It's fine to upstream this in staging, but while not all compliance errors are fixed it can't go to drivers/media. I'm tightening the screws on that since v4l2-compliance is getting to be such a powerful tool for ensuring the driver complies.

Quoted 92 lines

Thanks,
Archit

# ./utils/v4l2-compliance/v4l2-compliance  -v --streaming=10
root@localhost:~/source_trees/v4l-utils# Driver Info:
         Driver name   : vpe
         Card type     : vpe
         Bus info      : platform:vpe
         Driver version: 3.14.0
         Capabilities  : 0x84004000
                 Video Memory-to-Memory Multiplanar
                 Streaming
                 Device Capabilities
         Device Caps   : 0x04004000
                 Video Memory-to-Memory Multiplanar
                 Streaming

Compliance test for device /dev/video0 (not using libv4l2):

Required ioctls:
test VIDIOC_QUERYCAP: OK

Allow for multiple opens:
test second video open: OK
test VIDIOC_QUERYCAP: OK
test VIDIOC_G/S_PRIORITY: OK

Debug ioctls:
test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported) test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
test VIDIOC_G/S_TUNER: OK (Not Supported) test VIDIOC_G/S_FREQUENCY: OK (Not Supported) test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported) test VIDIOC_ENUMAUDIO: OK (Not Supported) test VIDIOC_G/S/ENUMINPUT: OK (Not Supported) test VIDIOC_G/S_AUDIO: OK (Not Supported)
Inputs: 0 Audio Inputs: 0 Tuners: 0

Output ioctls:
test VIDIOC_G/S_MODULATOR: OK (Not Supported) test VIDIOC_G/S_FREQUENCY: OK (Not Supported) test VIDIOC_ENUMAUDOUT: OK (Not Supported) test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported) test VIDIOC_G/S_AUDOUT: OK (Not Supported)
Outputs: 0 Audio Outputs: 0 Modulators: 0

Control ioctls:
info: checking v4l2_queryctrl of control 'User
Controls' (0x00980001)
info: checking v4l2_queryctrl of control 'Buffers Per
Transaction' (0x00981950)
info: checking v4l2_queryctrl of control 'Buffers Per
Transaction' (0x08000000)
test VIDIOC_QUERYCTRL/MENU: OK
info: checking control 'User Controls' (0x00980001)
info: checking control 'Buffers Per Transaction'
(0x00981950)
test VIDIOC_G/S_CTRL: OK
info: checking extended control 'User Controls'
(0x00980001)
info: checking extended control 'Buffers Per
Transaction' (0x00981950)
test VIDIOC_G/S/TRY_EXT_CTRLS: OK
info: checking control event 'User Controls' (0x00980001)
info: checking control event 'Buffers Per Transaction'
(0x00981950)
test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK
test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
Standard Controls: 1 Private Controls: 1

Input/Output configuration ioctls:
test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported) test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported) test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)

Format ioctls:
info: found 8 formats for buftype 9
info: found 4 formats for buftype 10
test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK test VIDIOC_G/S_PARM: OK (Not Supported)
test VIDIOC_G_FBUF: OK (Not Supported)
test VIDIOC_G_FMT: OK
fail: v4l2-test-formats.cpp(614): Video Capture
Multiplanar: TRY_FMT(G_FMT) != G_FMT
test VIDIOC_TRY_FMT: FAIL
warn: v4l2-test-formats.cpp(834): S_FMT cannot handle
an invalid pixelformat.
warn: v4l2-test-formats.cpp(835): This may or may not
be a problem. For more information see:

Quoted 4 lines
                 warn: v4l2-test-formats.cpp(836): 
http://www.mail-archive.com/[email protected]/msg56550.html
                 fail: v4l2-test-formats.cpp(420): pix_mp.reserved not 

zeroed

This is easy enough to fix.

Quoted 2 lines
                 fail: v4l2-test-formats.cpp(851): Video Capture 

Multiplanar is valid, but no S_FMT was implemented

For the FMT things: run with -T: that gives nice traces. You can also set the debug flag: echo 2 >/sys/class/video4linux/video0/debug to see all ioctls in more detail.

Quoted 8 lines

test VIDIOC_S_FMT: FAIL
test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)

Codec ioctls:
test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported) test VIDIOC_G_ENC_INDEX: OK (Not Supported) test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Quoted 14 lines

Buffer ioctls:
info: test buftype Video Capture Multiplanar
warn: v4l2-test-buffers.cpp(403): VIDIOC_CREATE_BUFS
not supported
info: test buftype Video Output Multiplanar
warn: v4l2-test-buffers.cpp(403): VIDIOC_CREATE_BUFS
not supported
test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
test VIDIOC_EXPBUF: OK (Not Supported)
test read/write: OK (Not Supported)
Video Capture Multiplanar (polling):
Buffer: 0 Sequence: 0 Field: Top Timestamp: 113.178208s
fail: v4l2-test-buffers.cpp(222): buf.field !=
cur_fmt.fmt.pix.field

Definitely needs to be fixed, you probably just don't set the field at all.

Quoted 8 lines
                 fail: v4l2-test-buffers.cpp(630): checkQueryBuf(node, 
buf, bufs.type, bufs.memory, buf.index, Dequeued, last_seq)
                 fail: v4l2-test-buffers.cpp(1038): captureBufs(node, 

bufs, m2m_bufs, frame_count, true)
test MMAP: FAIL
test USERPTR: OK (Not Supported)
test DMABUF: Cannot test, specify --expbuf-device

Quoted 4 lines

Total: 40, Succeeded: 37, Failed: 3, Warnings: 5

[1]+ Exit 1 ./utils/v4l2-compliance/v4l2-compliance -v
--streaming=10

Regards,

Hans

#30 lore raw

Re: [PATCH v2 7/7] v4l: ti-vpe: Add selection API in VPE driver

Hi,

Quoted 9 lines · Hans Verkuil
Quoted 3 lines

Do you think I can go ahead with posting the v3 patch set for 3.15, and work on fixing the compliance issue for the -rc fixes?

It's fine to upstream this in staging, but while not all compliance errors are fixed it can't go to drivers/media. I'm tightening the screws on that since v4l2-compliance is getting to be such a powerful tool for ensuring the driver complies.

But the vpe driver is already in drivers/media. How do I push these patches if the vpe drivers is not in staging?

<snip>

Quoted 11 lines
Quoted 10 lines

Multiplanar: TRY_FMT(G_FMT) != G_FMT
test VIDIOC_TRY_FMT: FAIL
warn: v4l2-test-formats.cpp(834): S_FMT cannot handle
an invalid pixelformat.
warn: v4l2-test-formats.cpp(835): This may or may not
be a problem. For more information see:

                  warn: v4l2-test-formats.cpp(836):
http://www.mail-archive.com/[email protected]/msg56550.html
                  fail: v4l2-test-formats.cpp(420): pix_mp.reserved not

zeroed

Quoted 8 lines

This is easy enough to fix.

Quoted 2 lines
                  fail: v4l2-test-formats.cpp(851): Video Capture

Multiplanar is valid, but no S_FMT was implemented

For the FMT things: run with -T: that gives nice traces. You can also set the debug flag: echo 2 >/sys/class/video4linux/video0/debug to see all ioctls in more detail.

Thanks for the tip, will try this.

Quoted 24 lines
Quoted 9 lines

test VIDIOC_S_FMT: FAIL
test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)

Codec ioctls:
test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported) test VIDIOC_G_ENC_INDEX: OK (Not Supported) test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Quoted 14 lines

Buffer ioctls:
info: test buftype Video Capture Multiplanar
warn: v4l2-test-buffers.cpp(403): VIDIOC_CREATE_BUFS
not supported
info: test buftype Video Output Multiplanar
warn: v4l2-test-buffers.cpp(403): VIDIOC_CREATE_BUFS
not supported
test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
test VIDIOC_EXPBUF: OK (Not Supported)
test read/write: OK (Not Supported)
Video Capture Multiplanar (polling):
Buffer: 0 Sequence: 0 Field: Top Timestamp: 113.178208s
fail: v4l2-test-buffers.cpp(222): buf.field !=
cur_fmt.fmt.pix.field

Quoted 1 line

Definitely needs to be fixed, you probably just don't set the field at all.

The VPE output is always progressive. But yes, I should still set the field parameter to something.

Thanks,
Archit

#31 lore raw

Re: [PATCH v2 7/7] v4l: ti-vpe: Add selection API in VPE driver

Quoted 7 lines · Archit Taneja

Hi,

Quoted 4 lines · Hans Verkuil
Quoted 3 lines

Do you think I can go ahead with posting the v3 patch set for 3.15, and work on fixing the compliance issue for the -rc fixes?

Quoted 8 lines
Quoted 5 lines

It's fine to upstream this in staging, but while not all compliance errors are fixed it can't go to drivers/media. I'm tightening the screws on that since v4l2-compliance is getting to be such a powerful tool for ensuring the driver complies.

But the vpe driver is already in drivers/media. How do I push these patches if the vpe drivers is not in staging?

Oops, sorry. I got confused with Benoit's AM437x ti-vpfe patch :-)

Disregard what I said, it's OK to upstream it. But if you could just spend some hours fixing the problems, that would really be best.

Quoted 49 lines

<snip>

Quoted 11 lines
Quoted 10 lines

Multiplanar: TRY_FMT(G_FMT) != G_FMT
test VIDIOC_TRY_FMT: FAIL
warn: v4l2-test-formats.cpp(834): S_FMT cannot handle
an invalid pixelformat.
warn: v4l2-test-formats.cpp(835): This may or may not
be a problem. For more information see:

                  warn: v4l2-test-formats.cpp(836):
http://www.mail-archive.com/[email protected]/msg56550.html
                  fail: v4l2-test-formats.cpp(420): pix_mp.reserved not

zeroed

Quoted 8 lines

This is easy enough to fix.

Quoted 2 lines
                  fail: v4l2-test-formats.cpp(851): Video Capture

Multiplanar is valid, but no S_FMT was implemented

For the FMT things: run with -T: that gives nice traces. You can also set the debug flag: echo 2 >/sys/class/video4linux/video0/debug to see all ioctls in more detail.

Thanks for the tip, will try this.

Quoted 24 lines
Quoted 23 lines

test VIDIOC_S_FMT: FAIL
test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)

Codec ioctls:
test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported) test VIDIOC_G_ENC_INDEX: OK (Not Supported) test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Buffer ioctls:
info: test buftype Video Capture Multiplanar
warn: v4l2-test-buffers.cpp(403): VIDIOC_CREATE_BUFS
not supported
info: test buftype Video Output Multiplanar
warn: v4l2-test-buffers.cpp(403): VIDIOC_CREATE_BUFS
not supported
test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
test VIDIOC_EXPBUF: OK (Not Supported)
test read/write: OK (Not Supported)
Video Capture Multiplanar (polling):
Buffer: 0 Sequence: 0 Field: Top Timestamp: 113.178208s
fail: v4l2-test-buffers.cpp(222): buf.field !=
cur_fmt.fmt.pix.field

Quoted 4 lines
Quoted 1 line

Definitely needs to be fixed, you probably just don't set the field at all.

The VPE output is always progressive. But yes, I should still set the field parameter to something.

V4L2_FIELD_NONE is the correct field setting for that.

Regards,

Hans

Quoted 9 lines

Thanks,
Archit

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

#32 lore raw

Re: [PATCH v2 7/7] v4l: ti-vpe: Add selection API in VPE driver

Quoted 14 lines · Hans Verkuil
Quoted 13 lines · Archit Taneja

Hi,

Quoted 9 lines · Hans Verkuil
Quoted 3 lines

Do you think I can go ahead with posting the v3 patch set for 3.15, and work on fixing the compliance issue for the -rc fixes?

It's fine to upstream this in staging, but while not all compliance errors are fixed it can't go to drivers/media. I'm tightening the screws on that since v4l2-compliance is getting to be such a powerful tool for ensuring the driver complies.

Quoted 7 lines
Quoted 2 lines

But the vpe driver is already in drivers/media. How do I push these patches if the vpe drivers is not in staging?

Oops, sorry. I got confused with Benoit's AM437x ti-vpfe patch :-)

Disregard what I said, it's OK to upstream it. But if you could just spend some hours fixing the problems, that would really be best.

Sure, I'll try to fix these issues and then post a v3.

Quoted 50 lines
Quoted 50 lines

<snip>

Quoted 11 lines
Quoted 10 lines

Multiplanar: TRY_FMT(G_FMT) != G_FMT
test VIDIOC_TRY_FMT: FAIL
warn: v4l2-test-formats.cpp(834): S_FMT cannot handle
an invalid pixelformat.
warn: v4l2-test-formats.cpp(835): This may or may not
be a problem. For more information see:

                   warn: v4l2-test-formats.cpp(836):
http://www.mail-archive.com/[email protected]/msg56550.html
                   fail: v4l2-test-formats.cpp(420): pix_mp.reserved not

zeroed

Quoted 8 lines

This is easy enough to fix.

Quoted 2 lines
                   fail: v4l2-test-formats.cpp(851): Video Capture

Multiplanar is valid, but no S_FMT was implemented

For the FMT things: run with -T: that gives nice traces. You can also set the debug flag: echo 2 >/sys/class/video4linux/video0/debug to see all ioctls in more detail.

Thanks for the tip, will try this.

Quoted 24 lines
Quoted 23 lines

test VIDIOC_S_FMT: FAIL
test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)

Codec ioctls:
test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported) test VIDIOC_G_ENC_INDEX: OK (Not Supported) test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Buffer ioctls:
info: test buftype Video Capture Multiplanar
warn: v4l2-test-buffers.cpp(403): VIDIOC_CREATE_BUFS
not supported
info: test buftype Video Output Multiplanar
warn: v4l2-test-buffers.cpp(403): VIDIOC_CREATE_BUFS
not supported
test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
test VIDIOC_EXPBUF: OK (Not Supported)
test read/write: OK (Not Supported)
Video Capture Multiplanar (polling):
Buffer: 0 Sequence: 0 Field: Top Timestamp: 113.178208s
fail: v4l2-test-buffers.cpp(222): buf.field !=
cur_fmt.fmt.pix.field

Quoted 6 lines
Quoted 4 lines
Quoted 1 line

Definitely needs to be fixed, you probably just don't set the field at all.

The VPE output is always progressive. But yes, I should still set the field parameter to something.

V4L2_FIELD_NONE is the correct field setting for that.

I checked the driver, it isn't setting it to V4L2_FIELD_NONE. Will fix this.

Archit

#33 lore raw

Re: [PATCH v2 7/7] v4l: ti-vpe: Add selection API in VPE driver

Hi Hans,

Quoted 9 lines · Archit Taneja
Quoted 6 lines · Hans Verkuil

On 03/07/2014 02:22 PM, Archit Taneja wrote:

Disregard what I said, it's OK to upstream it. But if you could just spend
some hours fixing the problems, that would really be best.

Sure, I'll try to fix these issues and then post a v3.

I fixed most of the compliance errors. There were some things I needed to change in .utils/v4l2-compliance/v4l2-test-buffers.cpp'. I added those with some questions in the comments:

utils/v4l2-compliance/v4l2-test-buffers.cpp +18 -4
index 6576d11..532a5b6 100644
@@ -219,7 +219,13 @@ static int checkQueryBuf(struct node *node, const struct v4l2_buffer &buf,
 		fail_on_test(!(buf.flags & (V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR)));
 		if (node->is_video) {
 			fail_on_test(buf.field == V4L2_FIELD_ALTERNATE);
-			fail_on_test(buf.field == V4L2_FIELD_ANY);
+			/*
+			 * the OUTPUT buffers are queued with V4L2_FIELD_ANY
+			 * field type by the application. Is it the driver's
+			 * job to change this to NONE in buf_prepare?
+			 */
+
+			/* fail_on_test(buf.field == V4L2_FIELD_ANY); */
 			if (cur_fmt.fmt.pix.field == V4L2_FIELD_ALTERNATE) {
 				fail_on_test(buf.field != V4L2_FIELD_BOTTOM &&
 						buf.field != V4L2_FIELD_TOP);
@@ -651,9 +657,17 @@ static int captureBufs(struct node *node, const struct v4l2_requestbuffers &bufs
 			} else if (node->is_m2m && timestamp == V4L2_BUF_FLAG_TIMESTAMP_COPY) {
 				fail_on_test(buffer_info.find(buf.timestamp) == buffer_info.end());
 				struct v4l2_buffer &orig_buf = buffer_info[buf.timestamp];
-				fail_on_test(buf.field != orig_buf.field);
-				fail_on_test((buf.flags & valid_output_flags) !=
-					     (orig_buf.flags & valid_output_flags));
+				/* same issue as as in checkQueryBuf */
+				/* fail_on_test(buf.field != orig_buf.field); */
+
+				/*
+				 * the queued buffers are filled with flags like
+				 * V4L2_BUF_FLAG_KEYFRAME, these are lost when
+				 * the captured buffers are dequed. How do we
+				 * fix this?
+				 */
+				/*fail_on_test((buf.flags & valid_output_flags) !=
+					     (orig_buf.flags & valid_output_flags)); */
 				if (buf.flags & V4L2_BUF_FLAG_TIMECODE)
 					fail_on_test(memcmp(&buf.timecode, &orig_buf.timecode,
 								sizeof(buf.timecode)));

Thanks,
Archit

#34 lore raw

Re: [PATCH v2 7/7] v4l: ti-vpe: Add selection API in VPE driver

Quoted 23 lines · Archit Taneja

Hi Hans,

Quoted 9 lines · Archit Taneja
Quoted 6 lines · Hans Verkuil

On 03/07/2014 02:22 PM, Archit Taneja wrote:

Disregard what I said, it's OK to upstream it. But if you could just spend
some hours fixing the problems, that would really be best.

Sure, I'll try to fix these issues and then post a v3.

I fixed most of the compliance errors. There were some things I needed to change in .utils/v4l2-compliance/v4l2-test-buffers.cpp'. I added those with some questions in the comments:

utils/v4l2-compliance/v4l2-test-buffers.cpp +0 -0
index 6576d11..532a5b6 100644

utils/v4l2-compliance/v4l2-test-buffers.cpp static int checkQueryBuf(struct node *node, const · line 226

Quoted 9 lines
utils/v4l2-compliance/v4l2-test-buffers.cpp +4 -1
@@ -219,7 +219,13 @@ static int checkQueryBuf(struct node *node, const 
 struct v4l2_buffer &buf,
  		fail_on_test(!(buf.flags & (V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR)));
  		if (node->is_video) {
  			fail_on_test(buf.field == V4L2_FIELD_ALTERNATE);
-			fail_on_test(buf.field == V4L2_FIELD_ANY);
+			/*
+			 * the OUTPUT buffers are queued with V4L2_FIELD_ANY
+			 * field type by the application. Is it the driver's
+			 * job to change this to NONE in buf_prepare?

Yes, it is. Applications may pass in FIELD_ANY, but the driver must never return it, it should always be replaced by what the driver actually uses.

Quoted 12 lines
utils/v4l2-compliance/v4l2-test-buffers.cpp +3 -0
+			 */
+
+			/* fail_on_test(buf.field == V4L2_FIELD_ANY); */
  			if (cur_fmt.fmt.pix.field == V4L2_FIELD_ALTERNATE) {
  				fail_on_test(buf.field != V4L2_FIELD_BOTTOM &&
  						buf.field != V4L2_FIELD_TOP);
utils/v4l2-compliance/v4l2-test-buffers.cpp +0 -0
@@ -651,9 +657,17 @@ static int captureBufs(struct node *node, const 

struct v4l2_requestbuffers &bufs
} else if (node->is_m2m && timestamp == V4L2_BUF_FLAG_TIMESTAMP_COPY) {
fail_on_test(buffer_info.find(buf.timestamp) == buffer_info.end()); struct v4l2_buffer &orig_buf = buffer_info[buf.timestamp];

utils/v4l2-compliance/v4l2-test-buffers.cpp +0 -1
-				fail_on_test(buf.field != orig_buf.field);

utils/v4l2-compliance/v4l2-test-buffers.cpp static int captureBufs(struct node *node, const struct v4l2_requestbuffers &bufs · line 667

Quoted 10 lines
utils/v4l2-compliance/v4l2-test-buffers.cpp +8 -2
-				fail_on_test((buf.flags & valid_output_flags) !=
-					     (orig_buf.flags & valid_output_flags));
+				/* same issue as as in checkQueryBuf */
+				/* fail_on_test(buf.field != orig_buf.field); */
+
+				/*
+				 * the queued buffers are filled with flags like
+				 * V4L2_BUF_FLAG_KEYFRAME, these are lost when
+				 * the captured buffers are dequed. How do we
+				 * fix this?

Well, the driver has to copy them :-)

Note that v4l2-compliance assumes that there is a 1 to 1 mapping between buffers coming into the codec and buffers coming out of the codec. If that's not the case, then copying such flags does not make any sense. On the other hand, in that case using V4L2_BUF_FLAG_TIMESTAMP_COPY probably makes no sense either.

Regards,

Hans

Quoted 11 lines
utils/v4l2-compliance/v4l2-test-buffers.cpp +3 -0
+				 */
+				/*fail_on_test((buf.flags & valid_output_flags) !=
+					     (orig_buf.flags & valid_output_flags)); */
  				if (buf.flags & V4L2_BUF_FLAG_TIMECODE)
  					fail_on_test(memcmp(&buf.timecode, &orig_buf.timecode,
  								sizeof(buf.timecode)));

Thanks,
Archit

#35 lore raw

RE: [PATCH v2 7/7] v4l: ti-vpe: Add selection API in VPE driver

In reply to Archit Taneja

Hi Archit,

Quoted 71 lines

From: Archit Taneja [mailto:[email protected]]
Sent: Tuesday, March 04, 2014 12:25 PM

Hi,

Quoted 6 lines · Hans Verkuil

Hi Archit,

Quoted 3 lines · Archit Taneja

Add selection ioctl ops. For VPE, cropping makes sense only for the input to VPE(or V4L2_BUF_TYPE_VIDEO_OUTPUT/MPLANE buffers) and composing makes sense only for the output of VPE(or

V4L2_BUF_TYPE_VIDEO_CAPTURE/MPLANE buffers).

Quoted 2 lines
Quoted 2 lines

For the CAPTURE type, V4L2_SEL_TGT_COMPOSE results in VPE writing

the

Quoted 1 line
Quoted 1 line

output in a rectangle within the capture buffer. For the OUTPUT

type,

Quoted 1 line
Quoted 1 line

V4L2_SEL_TGT_CROP results in selecting a rectangle region within the

source buffer.

Quoted 4 lines
Quoted 4 lines

Setting the crop/compose rectangles should successfully result in re-configuration of registers which are affected when either source or destination dimensions change, set_srcdst_params() is called for

this purpose.

Quoted 4 lines
Quoted 4 lines
---
  drivers/media/platform/ti-vpe/vpe.c | 142

++++++++++++++++++++++++++++++++++++

Quoted 8 lines

drivers/media/platform/ti-vpe/vpe.c static struct vpe_q_data *get_q_data(struct

Quoted 8 lines
  1 file changed, 142 insertions(+)
drivers/media/platform/ti-vpe/vpe.c +0 -0
index 03a6846..b938590 100644
@@ -410,8 +410,10 @@ static struct vpe_q_data *get_q_data(struct

vpe_ctx *ctx,

Quoted 11 lines

drivers/media/platform/ti-vpe/vpe.c static struct vpe_q_data *get_q_data(struct vpe_ctx *ctx, · line 416

Quoted 7 lines
drivers/media/platform/ti-vpe/vpe.c +2 -0
  {
  	switch (type) {
  	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
  		return &ctx->q_data[Q_DATA_SRC];
  	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:

I noticed that the querycap implementation is wrong. It reports V4L2_CAP_VIDEO_M2M instead of V4L2_CAP_VIDEO_M2M_MPLANE.

Quoted 4 lines

This driver is using the multiplanar formats, so the M2M_MPLANE cap should be set.

This should be a separate patch.

Thanks for pointing this out, I'll make a patch for that.

Quoted 2 lines

BTW, did you test the driver with the v4l2-compliance tool? The

latest

Quoted 3 lines

version
(http://git.linuxtv.org/v4l-utils.git) has m2m support.

I haven't tested it with this yet.

Quoted 4 lines

However, if you want to test streaming (the -s option), then you will probably need to base your kernel on this tree:

http://git.linuxtv.org/hverkuil/media_tree.git/shortlog/refs/heads/vb2

Quoted 8 lines
Quoted 1 line

-part1

I can give it a try. It'll probably take a bit more time to try this out. I'll need to port some minor DRA7x stuff.

Kamil,

Do you think you have some more time for the m2m pull request?

Yes, I would like to send the final pull request at the beginning of the coming week.

Quoted 65 lines
Quoted 8 lines

That branch contains a pile of fixes for vb2 and without that v4l2-compliance -s will fail a number of tests.

drivers/media/platform/ti-vpe/vpe.c static int vpe_s_fmt(struct file *file, void

Quoted 4 lines
drivers/media/platform/ti-vpe/vpe.c +0 -0
  		return &ctx->q_data[Q_DATA_DST];
  	default:
  		BUG();
@@ -1585,6 +1587,143 @@ static int vpe_s_fmt(struct file *file, void

*priv, struct v4l2_format *f)

Quoted 13 lines
Quoted 13 lines
drivers/media/platform/ti-vpe/vpe.c +10 -0
  	return set_srcdst_params(ctx);
  }
 
+static int __vpe_try_selection(struct vpe_ctx *ctx, struct
+v4l2_selection *s) {
+	struct vpe_q_data *q_data;
+
+	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, s->type);
+	if (!q_data)
Quoted 8 lines

drivers/media/platform/ti-vpe/vpe.c static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f)

Quoted 8 lines
drivers/media/platform/ti-vpe/vpe.c +8 -0
+		return -EINVAL;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE:
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		/*
+		 * COMPOSE target is only valid for capture buffer type,

for

Quoted 1 line

drivers/media/platform/ti-vpe/vpe.c static int vpe_s_fmt(struct file *file, void · line 1608

Quoted 1 line
drivers/media/platform/ti-vpe/vpe.c +1 -0
+		 * output buffer type, assign existing crop parameters to

the

Quoted 8 lines

drivers/media/platform/ti-vpe/vpe.c static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) · line 1613

Quoted 5 lines
drivers/media/platform/ti-vpe/vpe.c +5 -0
+		 * selection rectangle
+		 */
+		if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+			break;
+		} else {

No need for the 'else' keywork here.

Quoted 9 lines

drivers/media/platform/ti-vpe/vpe.c static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f)

Quoted 9 lines
drivers/media/platform/ti-vpe/vpe.c +9 -0
+			s->r = q_data->c_rect;
+			return 0;
+		}
+
+	case V4L2_SEL_TGT_CROP:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		/*
+		 * CROP target is only valid for output buffer type, for

capture

Quoted 8 lines

drivers/media/platform/ti-vpe/vpe.c static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) · line 1628

Quoted 6 lines
drivers/media/platform/ti-vpe/vpe.c +6 -0
+		 * buffer type, assign existing compose parameters to the
+		 * selection rectangle
+		 */
+		if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+			break;
+		} else {

Ditto.

Thanks. I'll fix these.

I had a minor question about the selection API:

Quoted 7 lines

Are the V4L2_SET_TGT_CROP/COMPOSE_DEFAULT and the corresponding 'BOUNDS'
targets supposed to be used with VIDIOC_S_SELECTION? If so, what's the expect behaviour?

Thanks,
Archit

Best wishes,

Signature · 2 lines
Kamil Debski
Samsung R&D Institute Poland
#36 lore raw

v3 cover v4l: ti-vpe: Some VPE fixes and enhancements

In reply to Archit Taneja

This patch set mainly consists of minor fixes for the VPE driver. These fixes ensure the following:

- The VPE module can be inserted and removed successively.
- Make sure that smaller resolutions like qcif work correctly.
- Prevent race condition between firmware loading and an open call to the v4l2 device.
- Prevent the possibility of output m2m queue not having sufficient 'ready' buffers.
- Some VPDMA data descriptor fields weren't understood correctly before. They are now used correctly.

The rest of the patches add some minor features like DMA buf support and cropping/composing.

Reference branch:

[email protected]:boddob/linux.git vpe_for_315

Changes in v3:

- improvements in selection API patch.
- querycap fixes for v4l2 compliance.
- v4l2_buffer 'field' and flags' fixes for compliance.
- fixes in try_fmt vpe_open for compliance.
- rename a IOMEM resource for better DT compatibility.

Changes in v2:

- selection API used instead of older cropping API.
- Typo fix.
- Some changes in patch 6/7 to support composing on the capture side of VPE.

Archit Taneja (14):
v4l: ti-vpe: Make sure in job_ready that we have the needed number of
dst_bufs
v4l: ti-vpe: register video device only when firmware is loaded
v4l: ti-vpe: Use video_device_release_empty
v4l: ti-vpe: Allow DMABUF buffer type support
v4l: ti-vpe: Allow usage of smaller images
v4l: ti-vpe: Fix some params in VPE data descriptors
v4l: ti-vpe: Add selection API in VPE driver
v4l: ti-vpe: Rename csc memory resource name
v4l: ti-vpe: report correct capabilities in querycap
v4l: ti-vpe: Use correct bus_info name for the device in querycap
v4l: ti-vpe: Fix initial configuration queue data
v4l: ti-vpe: zero out reserved fields in try_fmt
v4l: ti-vpe: Set correct field parameter for output and capture
buffers
v4l: ti-vpe: retain v4l2_buffer flags for captured buffers

 drivers/media/platform/ti-vpe/csc.c   |   2 +-
 drivers/media/platform/ti-vpe/vpdma.c |  68 ++++++---
 drivers/media/platform/ti-vpe/vpdma.h |  17 ++-
 drivers/media/platform/ti-vpe/vpe.c   | 263 ++++++++++++++++++++++++++++------
 4 files changed, 281 insertions(+), 69 deletions(-)
Signature · 1 line
1.8.3.2
#37 lore raw

PATCH v3 1/14 v4l: ti-vpe: Make sure in job_ready that we have the needed number of dst_bufs

VPE has a ctrl parameter which decides how many mem to mem transactions the active job from the job queue can perform.

The driver's job_ready() made sure that the number of ready source buffers are sufficient for the job to execute successfully. But it didn't make sure if there are sufficient ready destination buffers in the capture queue for the VPE output.

If the time taken by VPE to process a single frame is really slow, then it's possible that we don't need to imply such a restriction on the dst queue, but really fast transactions(small resolution, no de-interlacing) may cause us to hit the condition where we don't have any free buffers for the VPE to write on.

Add the extra check in job_ready() to make sure we have the sufficient amount of destination buffers.

---
 drivers/media/platform/ti-vpe/vpe.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/media/platform/ti-vpe/vpe.c +3 -0
index 7a77a5b..f3143ac 100644
@@ -887,6 +887,9 @@ static int job_ready(void *priv)
 	if (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) < needed)
 		return 0;
 
+	if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < needed)
+		return 0;
+
 	return 1;
 }
 
Signature · 1 line
1.8.3.2
Acked-by on v3 1/14
#38 lore raw

RE: [PATCH v3 01/14] v4l: ti-vpe: Make sure in job_ready that we have the needed number of dst_bufs

Hi,

Quoted 17 lines

From: Archit Taneja [mailto:[email protected]]
Sent: Tuesday, March 11, 2014 9:34 AM

VPE has a ctrl parameter which decides how many mem to mem transactions the active job from the job queue can perform.

The driver's job_ready() made sure that the number of ready source buffers are sufficient for the job to execute successfully. But it didn't make sure if there are sufficient ready destination buffers in the capture queue for the VPE output.

If the time taken by VPE to process a single frame is really slow, then it's possible that we don't need to imply such a restriction on the dst queue, but really fast transactions(small resolution, no de-interlacing) may cause us to hit the condition where we don't have any free buffers for the VPE to write on.

Quoted 4 lines

Add the extra check in job_ready() to make sure we have the sufficient amount of destination buffers.

Best wishes,

Signature · 2 lines
Kamil Debski
Samsung R&D Institute Poland
Quoted 21 lines
---
 drivers/media/platform/ti-vpe/vpe.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/media/platform/ti-vpe/vpe.c +3 -1
index 7a77a5b..f3143ac 100644
@@ -887,6 +887,9 @@ static int job_ready(void *priv)
 	if (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) < needed)
 		return 0;
 
+	if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < needed)
+		return 0;
+
 	return 1;
 }
 
--

1.8.3.2

#39 lore raw

PATCH v3 2/14 v4l: ti-vpe: register video device only when firmware is loaded

In reply to Archit Taneja

vpe fops(vpe_open in particular) should be called only when VPDMA firmware is loaded. File operations on the video device are possible the moment it is registered.

Currently, we register the video device for VPE at driver probe, after calling a vpdma helper to initialize VPDMA and load firmware. This function is non-blocking(it calls request_firmware_nowait()), and doesn't ensure that the firmware is actually loaded when it returns.

We remove the device registration from vpe probe, and move it to a callback provided by the vpe driver to the vpdma library, through vpdma_create().

The ready field in vpdma_data is no longer needed since we always have firmware loaded before the device is registered.

A minor problem with this approach is that if the video_register_device fails(which doesn't really happen), the vpe platform device would be registered. however, there won't be any v4l2 device corresponding to it.

---
 drivers/media/platform/ti-vpe/vpdma.c |  8 +++--
 drivers/media/platform/ti-vpe/vpdma.h |  7 +++--
 drivers/media/platform/ti-vpe/vpe.c   | 55 ++++++++++++++++++++---------------
 3 files changed, 41 insertions(+), 29 deletions(-)
drivers/media/platform/ti-vpe/vpdma.c +5 -3
index e8175e7..73dd38e 100644
@@ -781,7 +781,7 @@ static void vpdma_firmware_cb(const struct firmware *f, void *context)
 	/* already initialized */
 	if (read_field_reg(vpdma, VPDMA_LIST_ATTR, VPDMA_LIST_RDY_MASK,
 			VPDMA_LIST_RDY_SHFT)) {
-		vpdma->ready = true;
+		vpdma->cb(vpdma->pdev);
 		return;
 	}
 
@@ -811,7 +811,7 @@ static void vpdma_firmware_cb(const struct firmware *f, void *context)
 		goto free_buf;
 	}
 
-	vpdma->ready = true;
+	vpdma->cb(vpdma->pdev);
 
 free_buf:
 	vpdma_unmap_desc_buf(vpdma, &fw_dma_buf);
@@ -839,7 +839,8 @@ static int vpdma_load_firmware(struct vpdma_data *vpdma)
 	return 0;
 }
 
-struct vpdma_data *vpdma_create(struct platform_device *pdev)
+struct vpdma_data *vpdma_create(struct platform_device *pdev,
+		void (*cb)(struct platform_device *pdev))
 {
 	struct resource *res;
 	struct vpdma_data *vpdma;
@@ -854,6 +855,7 @@ struct vpdma_data *vpdma_create(struct platform_device *pdev)
 	}
 
 	vpdma->pdev = pdev;
+	vpdma->cb = cb;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpdma");
 	if (res == NULL) {
drivers/media/platform/ti-vpe/vpdma.h +4 -3
index cf40f11..bf5f8bb 100644
@@ -35,8 +35,8 @@ struct vpdma_data {
 
 	struct platform_device	*pdev;
 
-	/* tells whether vpdma firmware is loaded or not */
-	bool ready;
+	/* callback to VPE driver when the firmware is loaded */
+	void (*cb)(struct platform_device *pdev);
 };
 
 enum vpdma_data_format_type {
@@ -208,6 +208,7 @@ void vpdma_set_frame_start_event(struct vpdma_data *vpdma,
 void vpdma_dump_regs(struct vpdma_data *vpdma);
 
 /* initialize vpdma, passed with VPE's platform device pointer */
-struct vpdma_data *vpdma_create(struct platform_device *pdev);
+struct vpdma_data *vpdma_create(struct platform_device *pdev,
+		void (*cb)(struct platform_device *pdev));
 
 #endif
drivers/media/platform/ti-vpe/vpe.c +32 -23

81 lines not on this page · raw message

Signature · 1 line
1.8.3.2
#40 lore raw

RE: [PATCH v3 02/14] v4l: ti-vpe: register video device only when firmware is loaded

Hi Archit,

Quoted 16 lines

From: Archit Taneja [mailto:[email protected]]
Sent: Tuesday, March 11, 2014 9:34 AM

vpe fops(vpe_open in particular) should be called only when VPDMA firmware is loaded. File operations on the video device are possible the moment it is registered.

Currently, we register the video device for VPE at driver probe, after calling a vpdma helper to initialize VPDMA and load firmware. This function is non-blocking(it calls request_firmware_nowait()), and doesn't ensure that the firmware is actually loaded when it returns.

We remove the device registration from vpe probe, and move it to a callback provided by the vpe driver to the vpdma library, through vpdma_create().

Quoted 7 lines

The ready field in vpdma_data is no longer needed since we always have firmware loaded before the device is registered.

A minor problem with this approach is that if the video_register_device fails(which doesn't really happen), the vpe platform device would be registered.
however, there won't be any v4l2 device corresponding to it.

Could you explain to me one thing. request_firmware cannot be used in probe, thus you are using request_firmware_nowait. Why cannot the firmware be
loaded on open with a regular request_firmware that is waiting?

This patch seems to swap one problem for another. The possibility that open fails (because firmware is not yet loaded) is swapped for a vague possibility
that video_register_device.

Best wishes,

Signature · 2 lines
Kamil Debski
Samsung R&D Institute Poland
Quoted 168 lines
---
 drivers/media/platform/ti-vpe/vpdma.c |  8 +++--
drivers/media/platform/ti-vpe/vpdma.h |  7 +++--
 drivers/media/platform/ti-vpe/vpe.c   | 55 ++++++++++++++++++++-------
--------
 3 files changed, 41 insertions(+), 29 deletions(-)
drivers/media/platform/ti-vpe/vpdma.c +2 -2
index e8175e7..73dd38e 100644
@@ -781,7 +781,7 @@ static void vpdma_firmware_cb(const struct firmware
 *f, void *context)
 	/* already initialized */
 	if (read_field_reg(vpdma, VPDMA_LIST_ATTR, VPDMA_LIST_RDY_MASK,
 			VPDMA_LIST_RDY_SHFT)) {
-		vpdma->ready = true;
+		vpdma->cb(vpdma->pdev);
 		return;
 	}
@@ -811,7 +811,7 @@ static void vpdma_firmware_cb(const struct firmware
 *f, void *context)
 		goto free_buf;
 	}
 
-	vpdma->ready = true;
+	vpdma->cb(vpdma->pdev);
 
 free_buf:

vpdma_unmap_desc_buf(vpdma, &fw_dma_buf); @@ -839,7 +839,8 @@
static int vpdma_load_firmware(struct vpdma_data *vpdma)

drivers/media/platform/ti-vpe/vpdma.c +3 -1
 	return 0;
 }
 
-struct vpdma_data *vpdma_create(struct platform_device *pdev)
+struct vpdma_data *vpdma_create(struct platform_device *pdev,
+		void (*cb)(struct platform_device *pdev))
 {
 	struct resource *res;
 	struct vpdma_data *vpdma;
@@ -854,6 +855,7 @@ struct vpdma_data *vpdma_create(struct
 platform_device *pdev)
 	}
 
 	vpdma->pdev = pdev;
+	vpdma->cb = cb;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpdma");
drivers/media/platform/ti-vpe/vpdma.c +0 -0
 	if (res == NULL) {
drivers/media/platform/ti-vpe/vpdma.h +4 -2
index cf40f11..bf5f8bb 100644
@@ -35,8 +35,8 @@ struct vpdma_data {
 
 	struct platform_device	*pdev;
 
-	/* tells whether vpdma firmware is loaded or not */
-	bool ready;
+	/* callback to VPE driver when the firmware is loaded */
+	void (*cb)(struct platform_device *pdev);
 };
 
 enum vpdma_data_format_type {
@@ -208,6 +208,7 @@ void vpdma_set_frame_start_event(struct vpdma_data
 *vpdma,  void vpdma_dump_regs(struct vpdma_data *vpdma);
 
 /* initialize vpdma, passed with VPE's platform device pointer */ -
 struct vpdma_data *vpdma_create(struct platform_device *pdev);
+struct vpdma_data *vpdma_create(struct platform_device *pdev,
+		void (*cb)(struct platform_device *pdev));
 
 #endif
drivers/media/platform/ti-vpe/vpe.c +30 -6
index f3143ac..f1eae67 100644
@@ -1817,11 +1817,6 @@ static int vpe_open(struct file *file)
 
 	vpe_dbg(dev, "vpe_open\n");
 
-	if (!dev->vpdma->ready) {
-		vpe_err(dev, "vpdma firmware not loaded\n");
-		return -ENODEV;
-	}
-
 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
@@ -2039,10 +2034,40 @@ static void vpe_runtime_put(struct
 platform_device *pdev)
 	WARN_ON(r < 0 && r != -ENOSYS);
 }
 
+static void vpe_fw_cb(struct platform_device *pdev) {
+	struct vpe_dev *dev = platform_get_drvdata(pdev);
+	struct video_device *vfd;
+	int ret;
+
+	vfd = &dev->vfd;
+	*vfd = vpe_videodev;
+	vfd->lock = &dev->dev_mutex;
+	vfd->v4l2_dev = &dev->v4l2_dev;
+
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+	if (ret) {
+		vpe_err(dev, "Failed to register video device\n");
+
+		vpe_set_clock_enable(dev, 0);
+		vpe_runtime_put(pdev);
+		pm_runtime_disable(&pdev->dev);
+		v4l2_m2m_release(dev->m2m_dev);
+		vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+		v4l2_device_unregister(&dev->v4l2_dev);
+
+		return;
+	}
+
+	video_set_drvdata(vfd, dev);
+	snprintf(vfd->name, sizeof(vfd->name), "%s", vpe_videodev.name);
+	dev_info(dev->v4l2_dev.dev, "Device registered as /dev/video%d\n",
+		vfd->num);
+}
+
 static int vpe_probe(struct platform_device *pdev)  {
 	struct vpe_dev *dev;
-	struct video_device *vfd;
 	int ret, irq, func;
 
 	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); @@ -

2123,28 +2148,12 @@ static int vpe_probe(struct platform_device *pdev)

drivers/media/platform/ti-vpe/vpe.c +1 -18
 		goto runtime_put;
 	}
 
-	dev->vpdma = vpdma_create(pdev);
+	dev->vpdma = vpdma_create(pdev, vpe_fw_cb);
 	if (IS_ERR(dev->vpdma)) {
 		ret = PTR_ERR(dev->vpdma);
 		goto runtime_put;
 	}
 
-	vfd = &dev->vfd;
-	*vfd = vpe_videodev;
-	vfd->lock = &dev->dev_mutex;
-	vfd->v4l2_dev = &dev->v4l2_dev;
-
-	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
-	if (ret) {
-		vpe_err(dev, "Failed to register video device\n");
-		goto runtime_put;
-	}
-
-	video_set_drvdata(vfd, dev);
-	snprintf(vfd->name, sizeof(vfd->name), "%s", vpe_videodev.name);
-	dev_info(dev->v4l2_dev.dev, "Device registered as /dev/video%d\n",
-		vfd->num);
-
 	return 0;
 
 runtime_put:
--

1.8.3.2

#41 lore raw

Re: [PATCH v3 02/14] v4l: ti-vpe: register video device only when firmware is loaded

Hi Kamil,

Quoted 26 lines · Kamil Debski

Hi Archit,

Quoted 16 lines

From: Archit Taneja [mailto:[email protected]]
Sent: Tuesday, March 11, 2014 9:34 AM

vpe fops(vpe_open in particular) should be called only when VPDMA firmware is loaded. File operations on the video device are possible the moment it is registered.

Currently, we register the video device for VPE at driver probe, after calling a vpdma helper to initialize VPDMA and load firmware. This function is non-blocking(it calls request_firmware_nowait()), and doesn't ensure that the firmware is actually loaded when it returns.

We remove the device registration from vpe probe, and move it to a callback provided by the vpe driver to the vpdma library, through vpdma_create().

Quoted 7 lines

The ready field in vpdma_data is no longer needed since we always have firmware loaded before the device is registered.

A minor problem with this approach is that if the video_register_device fails(which doesn't really happen), the vpe platform device would be registered.
however, there won't be any v4l2 device corresponding to it.

Quoted 4 lines

Could you explain to me one thing. request_firmware cannot be used in probe, thus you are using request_firmware_nowait. Why cannot the firmware be
loaded on open with a regular request_firmware that is waiting?

I totally agree with you here. Placing the firmware in open() would probably make more sense.

The reason I didn't place it in open() is because I didn't want to release firmware in a corresponding close(), and be in a situation where the firmware is loaded multiple times in the driver's lifetime.

There are some reasons for doing this. First, it will require more testing with respect to whether the firmware is loaded correctly successive times :), the second is that loading firmware might probably take a bit of time, and we don't want to make applications too slow(I haven't measured the time taken, so I don't have a strong case for this either)

Quoted 5 lines

This patch seems to swap one problem for another. The possibility that open fails (because firmware is not yet loaded) is swapped for a vague possibility
that video_register_device.

The driver will work fine in most cases even without this patch(apart from the possibility mentioned as above).

We could discard this patch from this series, and I can work on a patch which moves firmware loading to the vpe_open() call, and hence solving the issue in the right manner. Does that sound fine?

Thanks,
Archit

#42 lore raw

RE: [PATCH v3 02/14] v4l: ti-vpe: register video device only when firmware is loaded

Hi,

Quoted 38 lines

From: Archit Taneja [mailto:[email protected]]
Sent: Thursday, March 13, 2014 1:09 PM

Hi Kamil,

Quoted 13 lines · Kamil Debski

Hi Archit,

Quoted 11 lines

From: Archit Taneja [mailto:[email protected]]
Sent: Tuesday, March 11, 2014 9:34 AM

vpe fops(vpe_open in particular) should be called only when VPDMA firmware is loaded. File operations on the video device are possible the moment it is registered.

Currently, we register the video device for VPE at driver probe, after calling a vpdma helper to initialize VPDMA and load firmware. This function is non-blocking(it calls request_firmware_nowait()), and doesn't ensure that the firmware is actually loaded when it

returns.

Quoted 13 lines
Quoted 5 lines

We remove the device registration from vpe probe, and move it to a callback provided by the vpe driver to the vpdma library, through vpdma_create().

Quoted 7 lines

The ready field in vpdma_data is no longer needed since we always have firmware loaded before the device is registered.

A minor problem with this approach is that if the video_register_device fails(which doesn't really happen), the vpe platform device would be registered.
however, there won't be any v4l2 device corresponding to it.

Quoted 4 lines

Could you explain to me one thing. request_firmware cannot be used in probe, thus you are using request_firmware_nowait. Why cannot the firmware be loaded on open with a regular request_firmware that is waiting?

Quoted 6 lines

I totally agree with you here. Placing the firmware in open() would probably make more sense.

The reason I didn't place it in open() is because I didn't want to release firmware in a corresponding close(), and be in a situation where the firmware is loaded multiple times in the driver's lifetime.

Would it be possible to load firmware in open and release it in remove? I know that this would disturb the symmetry between open-release and probe-remove. But this could work.

Quoted 12 lines

There are some reasons for doing this. First, it will require more testing with respect to whether the firmware is loaded correctly successive times :), the second is that loading firmware might probably take a bit of time, and we don't want to make applications too slow(I haven't measured the time taken, so I don't have a strong case for this either)

Quoted 2 lines

This patch seems to swap one problem for another. The possibility

that

Quoted 1 line

open fails (because firmware is not yet loaded) is swapped for a

vague

Quoted 8 lines
Quoted 1 line

possibility that video_register_device.

The driver will work fine in most cases even without this patch(apart from the possibility mentioned as above).

We could discard this patch from this series, and I can work on a patch which moves firmware loading to the vpe_open() call, and hence solving the issue in the right manner. Does that sound fine?

I agree, this should be a good solution.

Quoted 3 lines

Thanks,
Archit

Best wishes,

Signature · 2 lines
Kamil Debski
Samsung R&D Institute Poland
#43 lore raw

Re: [PATCH v3 02/14] v4l: ti-vpe: register video device only when firmware is loaded

Hi,

Quoted 43 lines · Kamil Debski

Hi,

Quoted 41 lines

From: Archit Taneja [mailto:[email protected]]
Sent: Thursday, March 13, 2014 1:09 PM

Hi Kamil,

Quoted 13 lines · Kamil Debski

Hi Archit,

Quoted 11 lines

From: Archit Taneja [mailto:[email protected]]
Sent: Tuesday, March 11, 2014 9:34 AM

vpe fops(vpe_open in particular) should be called only when VPDMA firmware is loaded. File operations on the video device are possible the moment it is registered.

Currently, we register the video device for VPE at driver probe, after calling a vpdma helper to initialize VPDMA and load firmware. This function is non-blocking(it calls request_firmware_nowait()), and doesn't ensure that the firmware is actually loaded when it

returns.

Quoted 13 lines
Quoted 5 lines

We remove the device registration from vpe probe, and move it to a callback provided by the vpe driver to the vpdma library, through vpdma_create().

Quoted 7 lines

The ready field in vpdma_data is no longer needed since we always have firmware loaded before the device is registered.

A minor problem with this approach is that if the video_register_device fails(which doesn't really happen), the vpe platform device would be registered.
however, there won't be any v4l2 device corresponding to it.

Quoted 4 lines

Could you explain to me one thing. request_firmware cannot be used in probe, thus you are using request_firmware_nowait. Why cannot the firmware be loaded on open with a regular request_firmware that is waiting?

I totally agree with you here. Placing the firmware in open() would probably make more sense.

Quoted 7 lines
Quoted 3 lines

The reason I didn't place it in open() is because I didn't want to release firmware in a corresponding close(), and be in a situation where the firmware is loaded multiple times in the driver's lifetime.

Would it be possible to load firmware in open and release it in remove? I know that this would disturb the symmetry between open-release and probe-remove. But this could work.

That might work.

Currently, the driver doesn't do any clock management, it just enables the clocks in probe, and disables them in remove. I need to check how the firmware is dependent on clocks. We could make a better decision about where to release the firmware with that information.

Archit

#44 lore raw

PATCH v3 3/14 v4l: ti-vpe: Use video_device_release_empty

In reply to Archit Taneja

The video_device struct is currently embedded in the driver data struct vpe_dev. A vpe_dev instance is allocated by the driver, and the memory for the vfd is a part of this struct.

The v4l2 core, however, manages the removal of the vfd region, through the video_device's .release() op, which currently is the helper video_device_release. This causes memory corruption, and leads to issues when we try to re-insert the vpe module.

Use the video_device_release_empty helper function instead

---
 drivers/media/platform/ti-vpe/vpe.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/platform/ti-vpe/vpe.c +1 -1
index f1eae67..0363df6 100644
@@ -2000,7 +2000,7 @@ static struct video_device vpe_videodev = {
 	.fops		= &vpe_fops,
 	.ioctl_ops	= &vpe_ioctl_ops,
 	.minor		= -1,
-	.release	= video_device_release,
+	.release	= video_device_release_empty,
 	.vfl_dir	= VFL_DIR_M2M,
 };
 
Signature · 1 line
1.8.3.2
Reviewed-by on v3 3/14
#45 lore raw

Re: [PATCH v3 03/14] v4l: ti-vpe: Use video_device_release_empty

Quoted 4 lines · Archit Taneja

The video_device struct is currently embedded in the driver data struct vpe_dev. A vpe_dev instance is allocated by the driver, and the memory for the vfd is a part of this struct.

Quoted 8 lines

The v4l2 core, however, manages the removal of the vfd region, through the video_device's .release() op, which currently is the helper video_device_release. This causes memory corruption, and leads to issues when we try to re-insert the vpe module.

Use the video_device_release_empty helper function instead

Quoted 18 lines
---
 drivers/media/platform/ti-vpe/vpe.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/platform/ti-vpe/vpe.c +1 -1
index f1eae67..0363df6 100644
@@ -2000,7 +2000,7 @@ static struct video_device vpe_videodev = {
 	.fops		= &vpe_fops,
 	.ioctl_ops	= &vpe_ioctl_ops,
 	.minor		= -1,
-	.release	= video_device_release,
+	.release	= video_device_release_empty,
 	.vfl_dir	= VFL_DIR_M2M,
 };
 
#46 lore raw

PATCH v3 4/14 v4l: ti-vpe: Allow DMABUF buffer type support

In reply to Archit Taneja

For OMAP and DRA7x, we generally allocate video and graphics buffers through omapdrm since the corresponding omap-gem driver provides DMM-Tiler backed contiguous buffers. omapdrm is a dma-buf exporter. These buffers are used by other drivers in the video pipeline.

Add VB2_DMABUF flag to the io_modes of the vb2 output and capture queues. This allows the driver to import dma shared buffers.

---
 drivers/media/platform/ti-vpe/vpe.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/media/platform/ti-vpe/vpe.c +2 -2
index 0363df6..0e7573a 100644
@@ -1770,7 +1770,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
 
 	memset(src_vq, 0, sizeof(*src_vq));
 	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
-	src_vq->io_modes = VB2_MMAP;
+	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
 	src_vq->drv_priv = ctx;
 	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 	src_vq->ops = &vpe_qops;
@@ -1783,7 +1783,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
 
 	memset(dst_vq, 0, sizeof(*dst_vq));
 	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-	dst_vq->io_modes = VB2_MMAP;
+	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
 	dst_vq->drv_priv = ctx;
 	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 	dst_vq->ops = &vpe_qops;
Signature · 1 line
1.8.3.2
Reviewed-by on v3 4/14
#47 lore raw

Re: [PATCH v3 04/14] v4l: ti-vpe: Allow DMABUF buffer type support

Quoted 9 lines · Archit Taneja

For OMAP and DRA7x, we generally allocate video and graphics buffers through omapdrm since the corresponding omap-gem driver provides DMM-Tiler backed contiguous buffers. omapdrm is a dma-buf exporter. These buffers are used by other drivers in the video pipeline.

Add VB2_DMABUF flag to the io_modes of the vb2 output and capture queues. This allows the driver to import dma shared buffers.

Quoted 27 lines
---
 drivers/media/platform/ti-vpe/vpe.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/media/platform/ti-vpe/vpe.c +2 -2
index 0363df6..0e7573a 100644
@@ -1770,7 +1770,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
 
 	memset(src_vq, 0, sizeof(*src_vq));
 	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
-	src_vq->io_modes = VB2_MMAP;
+	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
 	src_vq->drv_priv = ctx;
 	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 	src_vq->ops = &vpe_qops;
@@ -1783,7 +1783,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
 
 	memset(dst_vq, 0, sizeof(*dst_vq));
 	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-	dst_vq->io_modes = VB2_MMAP;
+	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
 	dst_vq->drv_priv = ctx;
 	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 	dst_vq->ops = &vpe_qops;
#48 lore raw

PATCH v3 5/14 v4l: ti-vpe: Allow usage of smaller images

In reply to Archit Taneja

The minimum width and height for VPE input/output was kept as 128 pixels. VPE doesn't have a constraint on the image height, it requires the image width to be at least 16 bytes.

Change the minimum supported dimensions to 32x32. This allows us to de-interlace qcif content. A smaller image size than 32x32 didn't make much sense, so stopped at this.

---
 drivers/media/platform/ti-vpe/vpe.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/media/platform/ti-vpe/vpe.c +2 -2
index 0e7573a..dbdc338 100644
@@ -49,8 +49,8 @@
 #define VPE_MODULE_NAME "vpe"
 
 /* minimum and maximum frame sizes */
-#define MIN_W		128
-#define MIN_H		128
+#define MIN_W		32
+#define MIN_H		32
 #define MAX_W		1920
 #define MAX_H		1080
 
Signature · 1 line
1.8.3.2
Reviewed-by on v3 5/14
#49 lore raw

Re: [PATCH v3 05/14] v4l: ti-vpe: Allow usage of smaller images

Quoted 9 lines · Archit Taneja

The minimum width and height for VPE input/output was kept as 128 pixels. VPE doesn't have a constraint on the image height, it requires the image width to be at least 16 bytes.

Change the minimum supported dimensions to 32x32. This allows us to de-interlace qcif content. A smaller image size than 32x32 didn't make much sense, so stopped at this.

Quoted 20 lines
---
 drivers/media/platform/ti-vpe/vpe.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/media/platform/ti-vpe/vpe.c +2 -2
index 0e7573a..dbdc338 100644
@@ -49,8 +49,8 @@
 #define VPE_MODULE_NAME "vpe"
 
 /* minimum and maximum frame sizes */
-#define MIN_W		128
-#define MIN_H		128
+#define MIN_W		32
+#define MIN_H		32
 #define MAX_W		1920
 #define MAX_H		1080
 
#50 lore raw

PATCH v3 6/14 v4l: ti-vpe: Fix some params in VPE data descriptors

In reply to Archit Taneja

Some parameters of the VPE descriptors were understood incorrectly. They are now fixed. The fixes are explained as follows:

- When adding an inbound data descriptor to the VPDMA descriptor list, we intend to use c_rect as the cropped region fetched by VPDMA. Therefore, c_rect->width shouldn't be used to calculate the line stride, the original image width should be used for that. We add a 'width' argument which gives the buffer width in memory.

- frame_width and frame_height describe the complete width and height of the client to which the channel is connected. If there are multiple channels fetching data and providing to the same client, the above 2 arguments should be the width and height of the region covered by all the channels. In the case where there is only one channel providing pixel data to the client (like in VPE), frame_width and frame_height should be the cropped width and cropped height respectively. The calculation of these params is done in the vpe driver now.

- start_h and start_v is also used in the case of multiple channels to describe where each channel should start filling pixel data. We don't use this in VPE, and pass 0s to the vpdma_add_in_dtd() helper.

- Some minor changes are made to the vpdma_add_out_dtd() helper. The c_rect param is used for specifying the 'composition' target, and 'width' is added to calculate the line stride.

---
 drivers/media/platform/ti-vpe/vpdma.c | 60 +++++++++++++++++++++++++++--------
 drivers/media/platform/ti-vpe/vpdma.h | 10 +++---
 drivers/media/platform/ti-vpe/vpe.c   | 18 +++++++----
 3 files changed, 64 insertions(+), 24 deletions(-)
drivers/media/platform/ti-vpe/vpdma.c +46 -14
index 73dd38e..a51a013 100644
@@ -614,8 +614,17 @@ static void dump_dtd(struct vpdma_dtd *dtd)
 /*
  * append an outbound data transfer descriptor to the given descriptor list,
  * this sets up a 'client to memory' VPDMA transfer for the given VPDMA channel
+ *
+ * @list: vpdma desc list to which we add this decriptor
+ * @width: width of the image in pixels in memory
+ * @c_rect: compose params of output image
+ * @fmt: vpdma data format of the buffer
+ * dma_addr: dma address as seen by VPDMA
+ * chan: VPDMA channel
+ * flags: VPDMA flags to configure some descriptor fileds
  */
-void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
+void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width,
+		const struct v4l2_rect *c_rect,
 		const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
 		enum vpdma_channel chan, u32 flags)
 {
@@ -623,6 +632,7 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
 	int field = 0;
 	int notify = 1;
 	int channel, next_chan;
+	struct v4l2_rect rect = *c_rect;
 	int depth = fmt->depth;
 	int stride;
 	struct vpdma_dtd *dtd;
@@ -630,11 +640,15 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
 	channel = next_chan = chan_info[chan].num;
 
 	if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV &&
-			fmt->data_type == DATA_TYPE_C420)
+			fmt->data_type == DATA_TYPE_C420) {
+		rect.height >>= 1;
+		rect.top >>= 1;
 		depth = 8;
+	}
 
-	stride = ALIGN((depth * c_rect->width) >> 3, VPDMA_STRIDE_ALIGN);
-	dma_addr += (c_rect->left * depth) >> 3;
+	stride = ALIGN((depth * width) >> 3, VPDMA_STRIDE_ALIGN);
+
+	dma_addr += rect.top * stride + (rect.left * depth >> 3);
 
 	dtd = list->next;
 	WARN_ON((void *)(dtd + 1) > (list->buf.addr + list->buf.size));
@@ -664,31 +678,48 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
 /*
  * append an inbound data transfer descriptor to the given descriptor list,
  * this sets up a 'memory to client' VPDMA transfer for the given VPDMA channel
+ *
+ * @list: vpdma desc list to which we add this decriptor
+ * @width: width of the image in pixels in memory(not the cropped width)
+ * @c_rect: crop params of input image
+ * @fmt: vpdma data format of the buffer
+ * dma_addr: dma address as seen by VPDMA
+ * chan: VPDMA channel
+ * field: top or bottom field info of the input image
+ * flags: VPDMA flags to configure some descriptor fileds
+ * frame_width/height: the complete width/height of the image presented to the
+ *			client (this makes sense when multiple channels are
+ *			connected to the same client, forming a larger frame)
+ * start_h, start_v: position where the given channel starts providing pixel
+ *			data to the client (makes sense when multiple channels
+ *			contribute to the client)
  */
-void vpdma_add_in_dtd(struct vpdma_desc_list *list, int frame_width,
-		int frame_height, struct v4l2_rect *c_rect,
+void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width,
+		const struct v4l2_rect *c_rect,
 		const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
-		enum vpdma_channel chan, int field, u32 flags)
+		enum vpdma_channel chan, int field, u32 flags, int frame_width,
+		int frame_height, int start_h, int start_v)
 {
 	int priority = 0;
 	int notify = 1;
 	int depth = fmt->depth;
 	int channel, next_chan;
+	struct v4l2_rect rect = *c_rect;
 	int stride;
-	int height = c_rect->height;
 	struct vpdma_dtd *dtd;
 
 	channel = next_chan = chan_info[chan].num;
 
 	if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV &&
 			fmt->data_type == DATA_TYPE_C420) {
-		height >>= 1;
-		frame_height >>= 1;
+		rect.height >>= 1;
+		rect.top >>= 1;
 		depth = 8;
 	}
 
-	stride = ALIGN((depth * c_rect->width) >> 3, VPDMA_STRIDE_ALIGN);
-	dma_addr += (c_rect->left * depth) >> 3;
+	stride = ALIGN((depth * width) >> 3, VPDMA_STRIDE_ALIGN);
+
+	dma_addr += rect.top * stride + (rect.left * depth >> 3);
 
 	dtd = list->next;
 	WARN_ON((void *)(dtd + 1) > (list->buf.addr + list->buf.size));
@@ -701,13 +732,14 @@ void vpdma_add_in_dtd(struct vpdma_desc_list *list, int frame_width,
 					!!(flags & VPDMA_DATA_ODD_LINE_SKIP),
 					stride);
 
-	dtd->xfer_length_height = dtd_xfer_length_height(c_rect->width, height);
+	dtd->xfer_length_height = dtd_xfer_length_height(rect.width,
+					rect.height);
 	dtd->start_addr = (u32) dma_addr;
 	dtd->pkt_ctl = dtd_pkt_ctl(!!(flags & VPDMA_DATA_MODE_TILED),
 				DTD_DIR_IN, channel, priority, next_chan);
 	dtd->frame_width_height = dtd_frame_width_height(frame_width,
 					frame_height);
-	dtd->start_h_v = dtd_start_h_v(c_rect->left, c_rect->top);
+	dtd->start_h_v = dtd_start_h_v(start_h, start_v);
 	dtd->client_attr0 = 0;
 	dtd->client_attr1 = 0;
 
drivers/media/platform/ti-vpe/vpdma.h +6 -4
index bf5f8bb..2bd8fb0 100644
@@ -186,13 +186,15 @@ void vpdma_add_cfd_adb(struct vpdma_desc_list *list, int client,
 		struct vpdma_buf *adb);
 void vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list,
 		enum vpdma_channel chan);
-void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
+void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width,
+		const struct v4l2_rect *c_rect,
 		const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
 		enum vpdma_channel chan, u32 flags);
-void vpdma_add_in_dtd(struct vpdma_desc_list *list, int frame_width,
-		int frame_height, struct v4l2_rect *c_rect,
+void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width,
+		const struct v4l2_rect *c_rect,
 		const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
-		enum vpdma_channel chan, int field, u32 flags);
+		enum vpdma_channel chan, int field, u32 flags, int frame_width,
+		int frame_height, int start_h, int start_v);
 
 /* vpdma list interrupt management */
 void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int list_num,
drivers/media/platform/ti-vpe/vpe.c +12 -6
index dbdc338..ece9b96 100644
@@ -986,7 +986,6 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port)
 	struct vpe_q_data *q_data = &ctx->q_data[Q_DATA_DST];
 	const struct vpe_port_data *p_data = &port_data[port];
 	struct vb2_buffer *vb = ctx->dst_vb;
-	struct v4l2_rect *c_rect = &q_data->c_rect;
 	struct vpe_fmt *fmt = q_data->fmt;
 	const struct vpdma_data_format *vpdma_fmt;
 	int mv_buf_selector = !ctx->src_mv_buf_selector;
@@ -1015,8 +1014,8 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port)
 	if (q_data->flags & Q_DATA_MODE_TILED)
 		flags |= VPDMA_DATA_MODE_TILED;
 
-	vpdma_add_out_dtd(&ctx->desc_list, c_rect, vpdma_fmt, dma_addr,
-		p_data->channel, flags);
+	vpdma_add_out_dtd(&ctx->desc_list, q_data->width, &q_data->c_rect,
+		vpdma_fmt, dma_addr, p_data->channel, flags);
 }
 
 static void add_in_dtd(struct vpe_ctx *ctx, int port)
@@ -1024,11 +1023,11 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port)
 	struct vpe_q_data *q_data = &ctx->q_data[Q_DATA_SRC];
 	const struct vpe_port_data *p_data = &port_data[port];
 	struct vb2_buffer *vb = ctx->src_vbs[p_data->vb_index];
-	struct v4l2_rect *c_rect = &q_data->c_rect;
 	struct vpe_fmt *fmt = q_data->fmt;
 	const struct vpdma_data_format *vpdma_fmt;
 	int mv_buf_selector = ctx->src_mv_buf_selector;
 	int field = vb->v4l2_buf.field == V4L2_FIELD_BOTTOM;
+	int frame_width, frame_height;
 	dma_addr_t dma_addr;
 	u32 flags = 0;
 
@@ -1055,8 +1054,15 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port)
 	if (q_data->flags & Q_DATA_MODE_TILED)
 		flags |= VPDMA_DATA_MODE_TILED;
 
-	vpdma_add_in_dtd(&ctx->desc_list, q_data->width, q_data->height,
-		c_rect, vpdma_fmt, dma_addr, p_data->channel, field, flags);
+	frame_width = q_data->c_rect.width;
+	frame_height = q_data->c_rect.height;
+
+	if (p_data->vb_part && fmt->fourcc == V4L2_PIX_FMT_NV12)
+		frame_height /= 2;
+
+	vpdma_add_in_dtd(&ctx->desc_list, q_data->width, &q_data->c_rect,
+		vpdma_fmt, dma_addr, p_data->channel, field, flags, frame_width,
+		frame_height, 0, 0);
 }
 
 /*
Signature · 1 line
1.8.3.2
#51 lore raw

PATCH v3 7/14 v4l: ti-vpe: Add selection API in VPE driver

In reply to Archit Taneja

Add selection ioctl ops. For VPE, cropping makes sense only for the input to VPE(or V4L2_BUF_TYPE_VIDEO_OUTPUT/MPLANE buffers) and composing makes sense only for the output of VPE(or V4L2_BUF_TYPE_VIDEO_CAPTURE/MPLANE buffers).

For the CAPTURE type, V4L2_SEL_TGT_COMPOSE results in VPE writing the output in a rectangle within the capture buffer. For the OUTPUT type, V4L2_SEL_TGT_CROP results in selecting a rectangle region within the source buffer.

Setting the crop/compose rectangles should successfully result in re-configuration of registers which are affected when either source or destination dimensions change, set_srcdst_params() is called for this purpose.

---
 drivers/media/platform/ti-vpe/vpe.c | 141 ++++++++++++++++++++++++++++++++++++
 1 file changed, 141 insertions(+)
drivers/media/platform/ti-vpe/vpe.c +141 -0
index ece9b96..4abb85c 100644
@@ -410,8 +410,10 @@ static struct vpe_q_data *get_q_data(struct vpe_ctx *ctx,
 {
 	switch (type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 		return &ctx->q_data[Q_DATA_SRC];
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 		return &ctx->q_data[Q_DATA_DST];
 	default:
 		BUG();
@@ -1587,6 +1589,142 @@ static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	return set_srcdst_params(ctx);
 }
 
+static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s)
+{
+	struct vpe_q_data *q_data;
+
+	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, s->type);
+	if (!q_data)
+		return -EINVAL;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE:
+		/*
+		 * COMPOSE target is only valid for capture buffer type, for
+		 * output buffer type, assign existing crop parameters to the
+		 * selection rectangle
+		 */
+		if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			break;
+
+		s->r = q_data->c_rect;
+		return 0;
+
+	case V4L2_SEL_TGT_CROP:
+		/*
+		 * CROP target is only valid for output buffer type, for capture
+		 * buffer type, assign existing compose parameters to the
+		 * selection rectangle
+		 */
+		if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+			break;
+
+		s->r = q_data->c_rect;
+		return 0;
+
+	/*
+	 * bound and default crop/compose targets are invalid targets to
+	 * try/set
+	 */
+	default:
+		return -EINVAL;
+	}
+
+	if (s->r.top < 0 || s->r.left < 0) {
+		vpe_err(ctx->dev, "negative values for top and left\n");
+		s->r.top = s->r.left = 0;
+	}
+
+	v4l_bound_align_image(&s->r.width, MIN_W, q_data->width, 1,
+		&s->r.height, MIN_H, q_data->height, H_ALIGN, S_ALIGN);
+
+	/* adjust left/top if cropping rectangle is out of bounds */
+	if (s->r.left + s->r.width > q_data->width)
+		s->r.left = q_data->width - s->r.width;
+	if (s->r.top + s->r.height > q_data->height)
+		s->r.top = q_data->height - s->r.height;
+
+	return 0;
+}
+
+static int vpe_g_selection(struct file *file, void *fh,
+		struct v4l2_selection *s)
+{
+	struct vpe_ctx *ctx = file2ctx(file);
+	struct vpe_q_data *q_data;
+
+	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, s->type);
+	if (!q_data)
+		return -EINVAL;
+
+	switch (s->target) {
+	/* return width and height from S_FMT of the respective buffer type */
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+		s->r.left = 0;
+		s->r.top = 0;
+		s->r.width = q_data->width;
+		s->r.height = q_data->height;
+		return 0;
+
+	/*
+	 * CROP target holds for the output buffer type, and COMPOSE target
+	 * holds for the capture buffer type. We still return the c_rect params
+	 * for both the target types.
+	 */
+	case V4L2_SEL_TGT_COMPOSE:
+	case V4L2_SEL_TGT_CROP:
+		s->r.left = q_data->c_rect.left;
+		s->r.top = q_data->c_rect.top;
+		s->r.width = q_data->c_rect.width;
+		s->r.height = q_data->c_rect.height;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+
+static int vpe_s_selection(struct file *file, void *fh,
+		struct v4l2_selection *s)
+{
+	struct vpe_ctx *ctx = file2ctx(file);
+	struct vpe_q_data *q_data;
+	struct v4l2_selection sel = *s;
+	int ret;
+
+	ret = __vpe_try_selection(ctx, &sel);
+	if (ret)
+		return ret;
+
+	q_data = get_q_data(ctx, sel.type);
+	if (!q_data)
+		return -EINVAL;
+
+	if ((q_data->c_rect.left == sel.r.left) &&
+			(q_data->c_rect.top == sel.r.top) &&
+			(q_data->c_rect.width == sel.r.width) &&
+			(q_data->c_rect.height == sel.r.height)) {
+		vpe_dbg(ctx->dev,
+			"requested crop/compose values are already set\n");
+		return 0;
+	}
+
+	q_data->c_rect = sel.r;
+
+	return set_srcdst_params(ctx);
+}
+
 static int vpe_reqbufs(struct file *file, void *priv,
 		       struct v4l2_requestbuffers *reqbufs)
 {
@@ -1674,6 +1812,9 @@ static const struct v4l2_ioctl_ops vpe_ioctl_ops = {
 	.vidioc_try_fmt_vid_out_mplane	= vpe_try_fmt,
 	.vidioc_s_fmt_vid_out_mplane	= vpe_s_fmt,
 
+	.vidioc_g_selection		= vpe_g_selection,
+	.vidioc_s_selection		= vpe_s_selection,
+
 	.vidioc_reqbufs		= vpe_reqbufs,
 	.vidioc_querybuf	= vpe_querybuf,
 
Signature · 1 line
1.8.3.2
#52 lore raw

Re: [PATCH v3 07/14] v4l: ti-vpe: Add selection API in VPE driver

Hi Archit,

A few small comments below...

Quoted 47 lines · Archit Taneja

Add selection ioctl ops. For VPE, cropping makes sense only for the input to VPE(or V4L2_BUF_TYPE_VIDEO_OUTPUT/MPLANE buffers) and composing makes sense only for the output of VPE(or V4L2_BUF_TYPE_VIDEO_CAPTURE/MPLANE buffers).

For the CAPTURE type, V4L2_SEL_TGT_COMPOSE results in VPE writing the output in a rectangle within the capture buffer. For the OUTPUT type, V4L2_SEL_TGT_CROP results in selecting a rectangle region within the source buffer.

Setting the crop/compose rectangles should successfully result in re-configuration of registers which are affected when either source or destination dimensions change, set_srcdst_params() is called for this purpose.

---
 drivers/media/platform/ti-vpe/vpe.c | 141 ++++++++++++++++++++++++++++++++++++
 1 file changed, 141 insertions(+)
drivers/media/platform/ti-vpe/vpe.c +13 -0
index ece9b96..4abb85c 100644
@@ -410,8 +410,10 @@ static struct vpe_q_data *get_q_data(struct vpe_ctx *ctx,
 {
 	switch (type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 		return &ctx->q_data[Q_DATA_SRC];
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 		return &ctx->q_data[Q_DATA_DST];
 	default:
 		BUG();
@@ -1587,6 +1589,142 @@ static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	return set_srcdst_params(ctx);
 }
 
+static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s)
+{
+	struct vpe_q_data *q_data;
+
+	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, s->type);
+	if (!q_data)
+		return -EINVAL;

drivers/media/platform/ti-vpe/vpe.c static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) · line 1612

Quoted 10 lines
drivers/media/platform/ti-vpe/vpe.c +10 -0
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE:
+		/*
+		 * COMPOSE target is only valid for capture buffer type, for
+		 * output buffer type, assign existing crop parameters to the
+		 * selection rectangle
+		 */
+		if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			break;

Shouldn't this return -EINVAL?

drivers/media/platform/ti-vpe/vpe.c static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) · line 1624

Quoted 12 lines
drivers/media/platform/ti-vpe/vpe.c +12 -0
+
+		s->r = q_data->c_rect;
+		return 0;
+
+	case V4L2_SEL_TGT_CROP:
+		/*
+		 * CROP target is only valid for output buffer type, for capture
+		 * buffer type, assign existing compose parameters to the
+		 * selection rectangle
+		 */
+		if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+			break;

Ditto.

Quoted 43 lines
drivers/media/platform/ti-vpe/vpe.c +43 -0
+
+		s->r = q_data->c_rect;
+		return 0;
+
+	/*
+	 * bound and default crop/compose targets are invalid targets to
+	 * try/set
+	 */
+	default:
+		return -EINVAL;
+	}
+
+	if (s->r.top < 0 || s->r.left < 0) {
+		vpe_err(ctx->dev, "negative values for top and left\n");
+		s->r.top = s->r.left = 0;
+	}
+
+	v4l_bound_align_image(&s->r.width, MIN_W, q_data->width, 1,
+		&s->r.height, MIN_H, q_data->height, H_ALIGN, S_ALIGN);
+
+	/* adjust left/top if cropping rectangle is out of bounds */
+	if (s->r.left + s->r.width > q_data->width)
+		s->r.left = q_data->width - s->r.width;
+	if (s->r.top + s->r.height > q_data->height)
+		s->r.top = q_data->height - s->r.height;
+
+	return 0;
+}
+
+static int vpe_g_selection(struct file *file, void *fh,
+		struct v4l2_selection *s)
+{
+	struct vpe_ctx *ctx = file2ctx(file);
+	struct vpe_q_data *q_data;
+
+	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, s->type);
+	if (!q_data)
+		return -EINVAL;
+

drivers/media/platform/ti-vpe/vpe.c static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) · line 1677

Quoted 10 lines
drivers/media/platform/ti-vpe/vpe.c +10 -0
+	switch (s->target) {
+	/* return width and height from S_FMT of the respective buffer type */
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+		s->r.left = 0;
+		s->r.top = 0;
+		s->r.width = q_data->width;
+		s->r.height = q_data->height;

The crop targets only make sense for type OUTPUT and the compose only for type CAPTURE. Add some checks for that.

Quoted 64 lines
drivers/media/platform/ti-vpe/vpe.c +53 -0
+		return 0;
+
+	/*
+	 * CROP target holds for the output buffer type, and COMPOSE target
+	 * holds for the capture buffer type. We still return the c_rect params
+	 * for both the target types.
+	 */
+	case V4L2_SEL_TGT_COMPOSE:
+	case V4L2_SEL_TGT_CROP:
+		s->r.left = q_data->c_rect.left;
+		s->r.top = q_data->c_rect.top;
+		s->r.width = q_data->c_rect.width;
+		s->r.height = q_data->c_rect.height;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+
+static int vpe_s_selection(struct file *file, void *fh,
+		struct v4l2_selection *s)
+{
+	struct vpe_ctx *ctx = file2ctx(file);
+	struct vpe_q_data *q_data;
+	struct v4l2_selection sel = *s;
+	int ret;
+
+	ret = __vpe_try_selection(ctx, &sel);
+	if (ret)
+		return ret;
+
+	q_data = get_q_data(ctx, sel.type);
+	if (!q_data)
+		return -EINVAL;
+
+	if ((q_data->c_rect.left == sel.r.left) &&
+			(q_data->c_rect.top == sel.r.top) &&
+			(q_data->c_rect.width == sel.r.width) &&
+			(q_data->c_rect.height == sel.r.height)) {
+		vpe_dbg(ctx->dev,
+			"requested crop/compose values are already set\n");
+		return 0;
+	}
+
+	q_data->c_rect = sel.r;
+
+	return set_srcdst_params(ctx);
+}
+
 static int vpe_reqbufs(struct file *file, void *priv,
 		       struct v4l2_requestbuffers *reqbufs)
 {
@@ -1674,6 +1812,9 @@ static const struct v4l2_ioctl_ops vpe_ioctl_ops = {
 	.vidioc_try_fmt_vid_out_mplane	= vpe_try_fmt,
 	.vidioc_s_fmt_vid_out_mplane	= vpe_s_fmt,
 
+	.vidioc_g_selection		= vpe_g_selection,
+	.vidioc_s_selection		= vpe_s_selection,
+
 	.vidioc_reqbufs		= vpe_reqbufs,
 	.vidioc_querybuf	= vpe_querybuf,
 
#53 lore raw

Re: [PATCH v3 07/14] v4l: ti-vpe: Add selection API in VPE driver

Quoted 56 lines · Hans Verkuil

Hi Archit,

A few small comments below...

Quoted 51 lines · Archit Taneja

Add selection ioctl ops. For VPE, cropping makes sense only for the input to VPE(or V4L2_BUF_TYPE_VIDEO_OUTPUT/MPLANE buffers) and composing makes sense only for the output of VPE(or V4L2_BUF_TYPE_VIDEO_CAPTURE/MPLANE buffers).

For the CAPTURE type, V4L2_SEL_TGT_COMPOSE results in VPE writing the output in a rectangle within the capture buffer. For the OUTPUT type, V4L2_SEL_TGT_CROP results in selecting a rectangle region within the source buffer.

Setting the crop/compose rectangles should successfully result in re-configuration of registers which are affected when either source or destination dimensions change, set_srcdst_params() is called for this purpose.

---
  drivers/media/platform/ti-vpe/vpe.c | 141 ++++++++++++++++++++++++++++++++++++
  1 file changed, 141 insertions(+)
drivers/media/platform/ti-vpe/vpe.c +17 -0
index ece9b96..4abb85c 100644
@@ -410,8 +410,10 @@ static struct vpe_q_data *get_q_data(struct vpe_ctx *ctx,
  {
  	switch (type) {
  	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
  		return &ctx->q_data[Q_DATA_SRC];
  	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
  		return &ctx->q_data[Q_DATA_DST];
  	default:
  		BUG();
@@ -1587,6 +1589,142 @@ static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
  	return set_srcdst_params(ctx);
  }
 
+static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s)
+{
+	struct vpe_q_data *q_data;
+
+	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, s->type);
+	if (!q_data)
+		return -EINVAL;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE:
+		/*
Quoted 8 lines

drivers/media/platform/ti-vpe/vpe.c static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) · line 1612

Quoted 6 lines
drivers/media/platform/ti-vpe/vpe.c +6 -0
+		 * COMPOSE target is only valid for capture buffer type, for
+		 * output buffer type, assign existing crop parameters to the
+		 * selection rectangle
+		 */
+		if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			break;

Shouldn't this return -EINVAL?

compose only makes sense for CAPTURE. So, it breaks and performs the calculations after the switch statement.

Quoted 4 lines

drivers/media/platform/ti-vpe/vpe.c static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) · line 1615

Quoted 4 lines
drivers/media/platform/ti-vpe/vpe.c +3 -0
+
+		s->r = q_data->c_rect;
+		return 0;

The above 2 lines are called for if we try to set compose for OUTPUT. I don't return an error here, just keep the size as the original rect size, and return 0.

I'll replace these 2 lines with 'return -EINVAL;'

Quoted 60 lines

drivers/media/platform/ti-vpe/vpe.c static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) · line 1624

Quoted 9 lines
drivers/media/platform/ti-vpe/vpe.c +9 -0
+
+	case V4L2_SEL_TGT_CROP:
+		/*
+		 * CROP target is only valid for output buffer type, for capture
+		 * buffer type, assign existing compose parameters to the
+		 * selection rectangle
+		 */
+		if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+			break;

Ditto.

Quoted 48 lines
drivers/media/platform/ti-vpe/vpe.c +48 -0
+
+		s->r = q_data->c_rect;
+		return 0;
+
+	/*
+	 * bound and default crop/compose targets are invalid targets to
+	 * try/set
+	 */
+	default:
+		return -EINVAL;
+	}
+
+	if (s->r.top < 0 || s->r.left < 0) {
+		vpe_err(ctx->dev, "negative values for top and left\n");
+		s->r.top = s->r.left = 0;
+	}
+
+	v4l_bound_align_image(&s->r.width, MIN_W, q_data->width, 1,
+		&s->r.height, MIN_H, q_data->height, H_ALIGN, S_ALIGN);
+
+	/* adjust left/top if cropping rectangle is out of bounds */
+	if (s->r.left + s->r.width > q_data->width)
+		s->r.left = q_data->width - s->r.width;
+	if (s->r.top + s->r.height > q_data->height)
+		s->r.top = q_data->height - s->r.height;
+
+	return 0;
+}
+
+static int vpe_g_selection(struct file *file, void *fh,
+		struct v4l2_selection *s)
+{
+	struct vpe_ctx *ctx = file2ctx(file);
+	struct vpe_q_data *q_data;
+
+	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, s->type);
+	if (!q_data)
+		return -EINVAL;
+
+	switch (s->target) {
+	/* return width and height from S_FMT of the respective buffer type */
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
Quoted 8 lines

drivers/media/platform/ti-vpe/vpe.c static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) · line 1677

Quoted 5 lines
drivers/media/platform/ti-vpe/vpe.c +5 -0
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+		s->r.left = 0;
+		s->r.top = 0;
+		s->r.width = q_data->width;
+		s->r.height = q_data->height;

The crop targets only make sense for type OUTPUT and the compose only for type CAPTURE. Add some checks for that.

I return the image size for G_FMT irrespective of what combination of crop/compose CAPTURE/OUTPUT it is. I suppose it is better to return an error if the user tries to configure a wrong combination.

Thanks,
Archit

#54 lore raw

Re: [PATCH v3 07/14] v4l: ti-vpe: Add selection API in VPE driver

Quoted 66 lines · Archit Taneja
Quoted 56 lines · Hans Verkuil

Hi Archit,

A few small comments below...

Quoted 51 lines · Archit Taneja

Add selection ioctl ops. For VPE, cropping makes sense only for the input to VPE(or V4L2_BUF_TYPE_VIDEO_OUTPUT/MPLANE buffers) and composing makes sense only for the output of VPE(or V4L2_BUF_TYPE_VIDEO_CAPTURE/MPLANE buffers).

For the CAPTURE type, V4L2_SEL_TGT_COMPOSE results in VPE writing the output in a rectangle within the capture buffer. For the OUTPUT type, V4L2_SEL_TGT_CROP results in selecting a rectangle region within the source buffer.

Setting the crop/compose rectangles should successfully result in re-configuration of registers which are affected when either source or destination dimensions change, set_srcdst_params() is called for this purpose.

---
  drivers/media/platform/ti-vpe/vpe.c | 141 ++++++++++++++++++++++++++++++++++++
  1 file changed, 141 insertions(+)
drivers/media/platform/ti-vpe/vpe.c +17 -0
index ece9b96..4abb85c 100644
@@ -410,8 +410,10 @@ static struct vpe_q_data *get_q_data(struct vpe_ctx *ctx,
  {
      switch (type) {
      case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+    case V4L2_BUF_TYPE_VIDEO_OUTPUT:
          return &ctx->q_data[Q_DATA_SRC];
      case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+    case V4L2_BUF_TYPE_VIDEO_CAPTURE:
          return &ctx->q_data[Q_DATA_DST];
      default:
          BUG();
@@ -1587,6 +1589,142 @@ static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
      return set_srcdst_params(ctx);
  }
 
+static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s)
+{
+    struct vpe_q_data *q_data;
+
+    if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+        (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+        return -EINVAL;
+
+    q_data = get_q_data(ctx, s->type);
+    if (!q_data)
+        return -EINVAL;
+
+    switch (s->target) {
+    case V4L2_SEL_TGT_COMPOSE:
+        /*
Quoted 8 lines

drivers/media/platform/ti-vpe/vpe.c static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) · line 1612

Quoted 6 lines
drivers/media/platform/ti-vpe/vpe.c +6 -0
+         * COMPOSE target is only valid for capture buffer type, for
+         * output buffer type, assign existing crop parameters to the
+         * selection rectangle
+         */
+        if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+            break;

Shouldn't this return -EINVAL?

Quoted 1 line

compose only makes sense for CAPTURE. So, it breaks and performs the calculations after the switch statement.

It's so easy to get confused here.

Quoted 9 lines
Quoted 5 lines

drivers/media/platform/ti-vpe/vpe.c static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) · line 1615

Quoted 5 lines
drivers/media/platform/ti-vpe/vpe.c +3 -0
+
+        s->r = q_data->c_rect;
+        return 0;

The above 2 lines are called for if we try to set compose for OUTPUT. I don't return an error here, just keep the size as the original rect size, and return 0.

I'll replace these 2 lines with 'return -EINVAL;'

Yes, that makes more sense.

Quoted 70 lines
Quoted 61 lines

drivers/media/platform/ti-vpe/vpe.c static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) · line 1624

Quoted 10 lines
drivers/media/platform/ti-vpe/vpe.c +9 -0
+
+    case V4L2_SEL_TGT_CROP:
+        /*
+         * CROP target is only valid for output buffer type, for capture
+         * buffer type, assign existing compose parameters to the
+         * selection rectangle
+         */
+        if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+            break;

Ditto.

Quoted 48 lines
drivers/media/platform/ti-vpe/vpe.c +48 -0
+
+        s->r = q_data->c_rect;
+        return 0;
+
+    /*
+     * bound and default crop/compose targets are invalid targets to
+     * try/set
+     */
+    default:
+        return -EINVAL;
+    }
+
+    if (s->r.top < 0 || s->r.left < 0) {
+        vpe_err(ctx->dev, "negative values for top and left\n");
+        s->r.top = s->r.left = 0;
+    }
+
+    v4l_bound_align_image(&s->r.width, MIN_W, q_data->width, 1,
+        &s->r.height, MIN_H, q_data->height, H_ALIGN, S_ALIGN);
+
+    /* adjust left/top if cropping rectangle is out of bounds */
+    if (s->r.left + s->r.width > q_data->width)
+        s->r.left = q_data->width - s->r.width;
+    if (s->r.top + s->r.height > q_data->height)
+        s->r.top = q_data->height - s->r.height;
+
+    return 0;
+}
+
+static int vpe_g_selection(struct file *file, void *fh,
+        struct v4l2_selection *s)
+{
+    struct vpe_ctx *ctx = file2ctx(file);
+    struct vpe_q_data *q_data;
+
+    if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+        (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+        return -EINVAL;
+
+    q_data = get_q_data(ctx, s->type);
+    if (!q_data)
+        return -EINVAL;
+
+    switch (s->target) {
+    /* return width and height from S_FMT of the respective buffer type */
+    case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+    case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+    case V4L2_SEL_TGT_CROP_BOUNDS:
Quoted 8 lines

drivers/media/platform/ti-vpe/vpe.c static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) · line 1677

Quoted 5 lines
drivers/media/platform/ti-vpe/vpe.c +5 -0
+    case V4L2_SEL_TGT_CROP_DEFAULT:
+        s->r.left = 0;
+        s->r.top = 0;
+        s->r.width = q_data->width;
+        s->r.height = q_data->height;

The crop targets only make sense for type OUTPUT and the compose only for type CAPTURE. Add some checks for that.

Quoted 3 lines

I return the image size for G_FMT irrespective of what combination of crop/compose CAPTURE/OUTPUT it is. I suppose it is better to return an error if the user tries to configure a wrong combination.

Yes. If for no other reason that I plan on adding crop/compose/scaling support to v4l2-compliance soon, and this will probably be one of the tests.

Quoted 8 lines

Thanks,
Archit

Signature · 3 lines
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#55 lore raw

Re: [PATCH v3 07/14] v4l: ti-vpe: Add selection API in VPE driver

Quoted 7 lines · Hans Verkuil
Quoted 6 lines · Archit Taneja
Quoted 5 lines · Hans Verkuil

Hi Archit,

A few small comments below...

On 03/11/14 09:33, Archit Taneja wrote:

<snip>

Quoted 2 lines

Yes. If for no other reason that I plan on adding crop/compose/scaling support to v4l2-compliance soon, and this will probably be one of the tests.

Thanks, will update. Thanks for reviewing of the series.

Archit

Quoted 10 lines
Quoted 9 lines

Thanks,
Archit

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

#56 lore raw

PATCH v3 8/14 v4l: ti-vpe: Rename csc memory resource name

In reply to Archit Taneja

Rename the memory block resource "vpe_csc" to "csc" since it also exists within the VIP IP block. This would make the name more generic, and both VPE and VIP DT nodes in the future can use it.

---
 drivers/media/platform/ti-vpe/csc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/platform/ti-vpe/csc.c +1 -1
index acfea50..0333339 100644
@@ -180,7 +180,7 @@ struct csc_data *csc_create(struct platform_device *pdev)
 	csc->pdev = pdev;
 
 	csc->res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-			"vpe_csc");
+			"csc");
 	if (csc->res == NULL) {
 		dev_err(&pdev->dev, "missing platform resources data\n");
 		return ERR_PTR(-ENODEV);
Signature · 1 line
1.8.3.2
#57 lore raw

PATCH v3 9/14 v4l: ti-vpe: report correct capabilities in querycap

In reply to Archit Taneja

querycap currently returns V4L2_CAP_VIDEO_M2M as a capability, this should be V4L2_CAP_VIDEO_M2M_MPLANE instead, as the driver supports multiplanar formats.

---
 drivers/media/platform/ti-vpe/vpe.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/platform/ti-vpe/vpe.c +1 -1
index 4abb85c..46b9d44 100644
@@ -1347,7 +1347,7 @@ static int vpe_querycap(struct file *file, void *priv,
 	strncpy(cap->driver, VPE_MODULE_NAME, sizeof(cap->driver) - 1);
 	strncpy(cap->card, VPE_MODULE_NAME, sizeof(cap->card) - 1);
 	strlcpy(cap->bus_info, VPE_MODULE_NAME, sizeof(cap->bus_info));
-	cap->device_caps  = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
+	cap->device_caps  = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
 	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
 }
Signature · 1 line
1.8.3.2
Reviewed-by on v3 9/14
#58 lore raw

Re: [PATCH v3 09/14] v4l: ti-vpe: report correct capabilities in querycap

Quoted 4 lines · Archit Taneja

querycap currently returns V4L2_CAP_VIDEO_M2M as a capability, this should be V4L2_CAP_VIDEO_M2M_MPLANE instead, as the driver supports multiplanar formats.

Quoted 18 lines
---
 drivers/media/platform/ti-vpe/vpe.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/platform/ti-vpe/vpe.c +1 -1
index 4abb85c..46b9d44 100644
@@ -1347,7 +1347,7 @@ static int vpe_querycap(struct file *file, void *priv,
 	strncpy(cap->driver, VPE_MODULE_NAME, sizeof(cap->driver) - 1);
 	strncpy(cap->card, VPE_MODULE_NAME, sizeof(cap->card) - 1);
 	strlcpy(cap->bus_info, VPE_MODULE_NAME, sizeof(cap->bus_info));
-	cap->device_caps  = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
+	cap->device_caps  = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
 	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
 }
#59 lore raw

PATCH v3 10/14 v4l: ti-vpe: Use correct bus_info name for the device in querycap

In reply to Archit Taneja

The bus_info parameter in v4l2_capabilities expects a 'platform_' prefix. This wasn't done in the driver and hence was breaking compliance. Update the bus_info parameter accordingly.

---
 drivers/media/platform/ti-vpe/vpe.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/media/platform/ti-vpe/vpe.c +2 -1
index 46b9d44..5591d04 100644
@@ -1346,7 +1346,8 @@ static int vpe_querycap(struct file *file, void *priv,
 {
 	strncpy(cap->driver, VPE_MODULE_NAME, sizeof(cap->driver) - 1);
 	strncpy(cap->card, VPE_MODULE_NAME, sizeof(cap->card) - 1);
-	strlcpy(cap->bus_info, VPE_MODULE_NAME, sizeof(cap->bus_info));
+	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+		VPE_MODULE_NAME);
 	cap->device_caps  = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
 	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
Signature · 1 line
1.8.3.2
Reviewed-by on v3 10/14
#60 lore raw

Re: [PATCH v3 10/14] v4l: ti-vpe: Use correct bus_info name for the device in querycap

Quoted 5 lines · Archit Taneja

The bus_info parameter in v4l2_capabilities expects a 'platform_' prefix. This wasn't done in the driver and hence was breaking compliance. Update the bus_info parameter accordingly.

Quoted 19 lines
---
 drivers/media/platform/ti-vpe/vpe.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/media/platform/ti-vpe/vpe.c +2 -1
index 46b9d44..5591d04 100644
@@ -1346,7 +1346,8 @@ static int vpe_querycap(struct file *file, void *priv,
 {
 	strncpy(cap->driver, VPE_MODULE_NAME, sizeof(cap->driver) - 1);
 	strncpy(cap->card, VPE_MODULE_NAME, sizeof(cap->card) - 1);
-	strlcpy(cap->bus_info, VPE_MODULE_NAME, sizeof(cap->bus_info));
+	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+		VPE_MODULE_NAME);
 	cap->device_caps  = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
 	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
#61 lore raw

PATCH v3 11/14 v4l: ti-vpe: Fix initial configuration queue data

In reply to Archit Taneja

The vpe output and capture queues are initially configured to default values in vpe_open(). A G_FMT before any S_FMTs will result in these values being populated.

The colorspace and bytesperline parameter of this initial configuration are incorrect. This breaks compliance when as we get 'TRY_FMT(G_FMT) != G_FMT'.

Fix the initial queue configuration such that it wouldn't need to be fixed by try_fmt.

---
 drivers/media/platform/ti-vpe/vpe.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/media/platform/ti-vpe/vpe.c +4 -2
index 5591d04..85d1122 100644
@@ -2012,9 +2012,11 @@ static int vpe_open(struct file *file)
 	s_q_data->fmt = &vpe_formats[2];
 	s_q_data->width = 1920;
 	s_q_data->height = 1080;
-	s_q_data->sizeimage[VPE_LUMA] = (s_q_data->width * s_q_data->height *
+	s_q_data->bytesperline[VPE_LUMA] = (s_q_data->width *
 			s_q_data->fmt->vpdma_fmt[VPE_LUMA]->depth) >> 3;
-	s_q_data->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	s_q_data->sizeimage[VPE_LUMA] = (s_q_data->bytesperline[VPE_LUMA] *
+			s_q_data->height);
+	s_q_data->colorspace = V4L2_COLORSPACE_REC709;
 	s_q_data->field = V4L2_FIELD_NONE;
 	s_q_data->c_rect.left = 0;
 	s_q_data->c_rect.top = 0;
Signature · 1 line
1.8.3.2
Reviewed-by on v3 11/14
#62 lore raw

Re: [PATCH v3 11/14] v4l: ti-vpe: Fix initial configuration queue data

Quoted 11 lines · Archit Taneja

The vpe output and capture queues are initially configured to default values in vpe_open(). A G_FMT before any S_FMTs will result in these values being populated.

The colorspace and bytesperline parameter of this initial configuration are incorrect. This breaks compliance when as we get 'TRY_FMT(G_FMT) != G_FMT'.

Fix the initial queue configuration such that it wouldn't need to be fixed by try_fmt.

Quoted 23 lines
---
 drivers/media/platform/ti-vpe/vpe.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/media/platform/ti-vpe/vpe.c +4 -2
index 5591d04..85d1122 100644
@@ -2012,9 +2012,11 @@ static int vpe_open(struct file *file)
 	s_q_data->fmt = &vpe_formats[2];
 	s_q_data->width = 1920;
 	s_q_data->height = 1080;
-	s_q_data->sizeimage[VPE_LUMA] = (s_q_data->width * s_q_data->height *
+	s_q_data->bytesperline[VPE_LUMA] = (s_q_data->width *
 			s_q_data->fmt->vpdma_fmt[VPE_LUMA]->depth) >> 3;
-	s_q_data->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	s_q_data->sizeimage[VPE_LUMA] = (s_q_data->bytesperline[VPE_LUMA] *
+			s_q_data->height);
+	s_q_data->colorspace = V4L2_COLORSPACE_REC709;
 	s_q_data->field = V4L2_FIELD_NONE;
 	s_q_data->c_rect.left = 0;
 	s_q_data->c_rect.top = 0;
#63 lore raw

PATCH v3 12/14 v4l: ti-vpe: zero out reserved fields in try_fmt

In reply to Archit Taneja

Zero out the reserved formats in v4l2_pix_format_mplane and v4l2_plane_pix_format members of the returned v4l2_format pointer when passed through TRY_FMT ioctl.

This ensures that the user doesn't interpret the non-zero fields as some data passed by the driver, and ensures compliance.

---
 drivers/media/platform/ti-vpe/vpe.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/media/platform/ti-vpe/vpe.c +3 -0
index 85d1122..970408a 100644
@@ -1488,6 +1488,7 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f,
 		}
 	}
 
+	memset(pix->reserved, 0, sizeof(pix->reserved));
 	for (i = 0; i < pix->num_planes; i++) {
 		plane_fmt = &pix->plane_fmt[i];
 		depth = fmt->vpdma_fmt[i]->depth;
@@ -1499,6 +1500,8 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f,
 
 		plane_fmt->sizeimage =
 				(pix->height * pix->width * depth) >> 3;
+
+		memset(plane_fmt->reserved, 0, sizeof(plane_fmt->reserved));
 	}
 
 	return 0;
Signature · 1 line
1.8.3.2
Reviewed-by on v3 12/14
#64 lore raw

Re: [PATCH v3 12/14] v4l: ti-vpe: zero out reserved fields in try_fmt

Quoted 8 lines · Archit Taneja

Zero out the reserved formats in v4l2_pix_format_mplane and v4l2_plane_pix_format members of the returned v4l2_format pointer when passed through TRY_FMT ioctl.

This ensures that the user doesn't interpret the non-zero fields as some data passed by the driver, and ensures compliance.

Quoted 26 lines
---
 drivers/media/platform/ti-vpe/vpe.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/media/platform/ti-vpe/vpe.c +3 -0
index 85d1122..970408a 100644
@@ -1488,6 +1488,7 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f,
 		}
 	}
 
+	memset(pix->reserved, 0, sizeof(pix->reserved));
 	for (i = 0; i < pix->num_planes; i++) {
 		plane_fmt = &pix->plane_fmt[i];
 		depth = fmt->vpdma_fmt[i]->depth;
@@ -1499,6 +1500,8 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f,
 
 		plane_fmt->sizeimage =
 				(pix->height * pix->width * depth) >> 3;
+
+		memset(plane_fmt->reserved, 0, sizeof(plane_fmt->reserved));
 	}
 
 	return 0;
#65 lore raw

PATCH v3 13/14 v4l: ti-vpe: Set correct field parameter for output and capture buffers

In reply to Archit Taneja

The vpe driver wasn't setting the correct field parameter for dequed CAPTURE type buffers for the case where the captured output is progressive.

Set the field to V4L2_FIELD_NONE for the completed destination buffers when the captured output is progressive.

For OUTPUT type buffers, a queued buffer's field is forced to V4L2_FIELD_NONE if the pixel format(configured through s_fmt for the buffer type V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE specifies) the field type isn't interlaced. If the pixel format specified was V4L2_FIELD_ALTERNATE, and the queued buffer's field isn't V4L2_FIELD_TOP or V4L2_FIELD_BOTTOM, the vb2 buf_prepare op returns an error.

This ensures compliance, and that the dequeued output and captured buffers contain the field type that the driver used internally.

---
 drivers/media/platform/ti-vpe/vpe.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)
drivers/media/platform/ti-vpe/vpe.c +12 -1
index 970408a..c884910 100644
@@ -1296,10 +1296,10 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data)
 		d_buf->timecode = s_buf->timecode;
 	}
 	d_buf->sequence = ctx->sequence;
-	d_buf->field = ctx->field;
 
 	d_q_data = &ctx->q_data[Q_DATA_DST];
 	if (d_q_data->flags & Q_DATA_INTERLACED) {
+		d_buf->field = ctx->field;
 		if (ctx->field == V4L2_FIELD_BOTTOM) {
 			ctx->sequence++;
 			ctx->field = V4L2_FIELD_TOP;
@@ -1308,6 +1308,7 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data)
 			ctx->field = V4L2_FIELD_BOTTOM;
 		}
 	} else {
+		d_buf->field = V4L2_FIELD_NONE;
 		ctx->sequence++;
 	}
 
@@ -1871,6 +1872,16 @@ static int vpe_buf_prepare(struct vb2_buffer *vb)
 	q_data = get_q_data(ctx, vb->vb2_queue->type);
 	num_planes = q_data->fmt->coplanar ? 2 : 1;
 
+	if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		if (!(q_data->flags & Q_DATA_INTERLACED)) {
+			vb->v4l2_buf.field = V4L2_FIELD_NONE;
+		} else {
+			if (vb->v4l2_buf.field != V4L2_FIELD_TOP ||
+					vb->v4l2_buf.field != V4L2_FIELD_BOTTOM)
+				return -EINVAL;
+		}
+	}
+
 	for (i = 0; i < num_planes; i++) {
 		if (vb2_plane_size(vb, i) < q_data->sizeimage[i]) {
 			vpe_err(ctx->dev,
Signature · 1 line
1.8.3.2
Reviewed-by on v3 13/14
#66 lore raw

Re: [PATCH v3 13/14] v4l: ti-vpe: Set correct field parameter for output and capture buffers

Quoted 13 lines · Archit Taneja

The vpe driver wasn't setting the correct field parameter for dequed CAPTURE type buffers for the case where the captured output is progressive.

Set the field to V4L2_FIELD_NONE for the completed destination buffers when the captured output is progressive.

For OUTPUT type buffers, a queued buffer's field is forced to V4L2_FIELD_NONE if the pixel format(configured through s_fmt for the buffer type V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE specifies) the field type isn't interlaced. If the pixel format specified was V4L2_FIELD_ALTERNATE, and the queued buffer's field isn't V4L2_FIELD_TOP or V4L2_FIELD_BOTTOM, the vb2 buf_prepare op returns an error.

Quoted 4 lines

This ensures compliance, and that the dequeued output and captured buffers contain the field type that the driver used internally.

Quoted 46 lines
---
 drivers/media/platform/ti-vpe/vpe.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)
drivers/media/platform/ti-vpe/vpe.c +12 -1
index 970408a..c884910 100644
@@ -1296,10 +1296,10 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data)
 		d_buf->timecode = s_buf->timecode;
 	}
 	d_buf->sequence = ctx->sequence;
-	d_buf->field = ctx->field;
 
 	d_q_data = &ctx->q_data[Q_DATA_DST];
 	if (d_q_data->flags & Q_DATA_INTERLACED) {
+		d_buf->field = ctx->field;
 		if (ctx->field == V4L2_FIELD_BOTTOM) {
 			ctx->sequence++;
 			ctx->field = V4L2_FIELD_TOP;
@@ -1308,6 +1308,7 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data)
 			ctx->field = V4L2_FIELD_BOTTOM;
 		}
 	} else {
+		d_buf->field = V4L2_FIELD_NONE;
 		ctx->sequence++;
 	}
 
@@ -1871,6 +1872,16 @@ static int vpe_buf_prepare(struct vb2_buffer *vb)
 	q_data = get_q_data(ctx, vb->vb2_queue->type);
 	num_planes = q_data->fmt->coplanar ? 2 : 1;
 
+	if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		if (!(q_data->flags & Q_DATA_INTERLACED)) {
+			vb->v4l2_buf.field = V4L2_FIELD_NONE;
+		} else {
+			if (vb->v4l2_buf.field != V4L2_FIELD_TOP ||
+					vb->v4l2_buf.field != V4L2_FIELD_BOTTOM)
+				return -EINVAL;
+		}
+	}
+
 	for (i = 0; i < num_planes; i++) {
 		if (vb2_plane_size(vb, i) < q_data->sizeimage[i]) {
 			vpe_err(ctx->dev,
#67 lore raw

PATCH v3 14/14 v4l: ti-vpe: retain v4l2_buffer flags for captured buffers

In reply to Archit Taneja

The dequed CAPTURE_MPLANE type buffers don't contain the flags that the originally queued OUTPUT_MPLANE type buffers have. This breaks compliance.

Copy the source v4l2_buffer flags to the destination v4l2_buffer flags before they are dequed.

---
 drivers/media/platform/ti-vpe/vpe.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/media/platform/ti-vpe/vpe.c +4 -5
index c884910..f7759e8 100644
@@ -1288,13 +1288,12 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data)
 	s_buf = &s_vb->v4l2_buf;
 	d_buf = &d_vb->v4l2_buf;
 
+	d_buf->flags = s_buf->flags;
+
 	d_buf->timestamp = s_buf->timestamp;
-	d_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
-	d_buf->flags |= s_buf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
-	if (s_buf->flags & V4L2_BUF_FLAG_TIMECODE) {
-		d_buf->flags |= V4L2_BUF_FLAG_TIMECODE;
+	if (s_buf->flags & V4L2_BUF_FLAG_TIMECODE)
 		d_buf->timecode = s_buf->timecode;
-	}
+
 	d_buf->sequence = ctx->sequence;
 
 	d_q_data = &ctx->q_data[Q_DATA_DST];
Signature · 1 line
1.8.3.2
Reviewed-by on v3 14/14
#68 lore raw

Re: [PATCH v3 14/14] v4l: ti-vpe: retain v4l2_buffer flags for captured buffers

Quoted 7 lines · Archit Taneja

The dequed CAPTURE_MPLANE type buffers don't contain the flags that the originally queued OUTPUT_MPLANE type buffers have. This breaks compliance.

Copy the source v4l2_buffer flags to the destination v4l2_buffer flags before they are dequed.

Quoted 27 lines
---
 drivers/media/platform/ti-vpe/vpe.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/media/platform/ti-vpe/vpe.c +4 -5
index c884910..f7759e8 100644
@@ -1288,13 +1288,12 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data)
 	s_buf = &s_vb->v4l2_buf;
 	d_buf = &d_vb->v4l2_buf;
 
+	d_buf->flags = s_buf->flags;
+
 	d_buf->timestamp = s_buf->timestamp;
-	d_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
-	d_buf->flags |= s_buf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
-	if (s_buf->flags & V4L2_BUF_FLAG_TIMECODE) {
-		d_buf->flags |= V4L2_BUF_FLAG_TIMECODE;
+	if (s_buf->flags & V4L2_BUF_FLAG_TIMECODE)
 		d_buf->timecode = s_buf->timecode;
-	}
+
 	d_buf->sequence = ctx->sequence;
 
 	d_q_data = &ctx->q_data[Q_DATA_DST];
#69 lore raw

v4 cover v4l: ti-vpe: Some VPE fixes and enhancements

In reply to Archit Taneja

This patch set mainly consists of minor fixes for the VPE driver. These fixes ensure the following:

- The VPE module can be inserted and removed successively.
- Make sure that smaller resolutions like qcif work correctly.
- Prevent race condition between firmware loading and an open call to the v4l2 device.
- Prevent the possibility of output m2m queue not having sufficient 'ready' buffers.
- Some VPDMA data descriptor fields weren't understood correctly before. They are now used correctly.

The rest of the patches add some minor features like DMA buf support and cropping/composing.

Reference branch:

[email protected]:boddob/linux.git vpe_for_315

Changes in v4:

- More legible code for selection API
- Stricter checking for target type vs crop type in g_selection
- Minor fix in patch 13/14, there was a logical bug in buf_prepare when checking validity of top and bottom fields.

Changes in v3:

- improvements in selection API patch.
- querycap fixes for v4l2 compliance.
- v4l2_buffer 'field' and flags' fixes for compliance.
- fixes in try_fmt vpe_open for compliance.
- rename a IOMEM resource for better DT compatibility.

Changes in v2:

- selection API used instead of older cropping API.
- Typo fix.
- Some changes in patch 6/7 to support composing on the capture side of VPE.

Archit Taneja (14):
v4l: ti-vpe: Make sure in job_ready that we have the needed number of
dst_bufs
v4l: ti-vpe: register video device only when firmware is loaded
v4l: ti-vpe: Use video_device_release_empty
v4l: ti-vpe: Allow DMABUF buffer type support
v4l: ti-vpe: Allow usage of smaller images
v4l: ti-vpe: Fix some params in VPE data descriptors
v4l: ti-vpe: Add selection API in VPE driver
v4l: ti-vpe: Rename csc memory resource name
v4l: ti-vpe: report correct capabilities in querycap
v4l: ti-vpe: Use correct bus_info name for the device in querycap
v4l: ti-vpe: Fix initial configuration queue data
v4l: ti-vpe: zero out reserved fields in try_fmt
v4l: ti-vpe: Set correct field parameter for output and capture
buffers
v4l: ti-vpe: retain v4l2_buffer flags for captured buffers

 drivers/media/platform/ti-vpe/csc.c   |   2 +-
 drivers/media/platform/ti-vpe/vpdma.c |  68 ++++++---
 drivers/media/platform/ti-vpe/vpdma.h |  17 ++-
 drivers/media/platform/ti-vpe/vpe.c   | 272 ++++++++++++++++++++++++++++------
 4 files changed, 290 insertions(+), 69 deletions(-)
Signature · 1 line
1.8.3.2
#70 lore raw

PATCH v4 1/14 v4l: ti-vpe: Make sure in job_ready that we have the needed number of dst_bufs

VPE has a ctrl parameter which decides how many mem to mem transactions the active job from the job queue can perform.

The driver's job_ready() made sure that the number of ready source buffers are sufficient for the job to execute successfully. But it didn't make sure if there are sufficient ready destination buffers in the capture queue for the VPE output.

If the time taken by VPE to process a single frame is really slow, then it's possible that we don't need to imply such a restriction on the dst queue, but really fast transactions(small resolution, no de-interlacing) may cause us to hit the condition where we don't have any free buffers for the VPE to write on.

Add the extra check in job_ready() to make sure we have the sufficient amount of destination buffers.

---
 drivers/media/platform/ti-vpe/vpe.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/media/platform/ti-vpe/vpe.c +3 -0
index 7a77a5b..f3143ac 100644
@@ -887,6 +887,9 @@ static int job_ready(void *priv)
 	if (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) < needed)
 		return 0;
 
+	if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < needed)
+		return 0;
+
 	return 1;
 }
 
Signature · 1 line
1.8.3.2
Acked-by on v4 1/14
#71 lore raw

RE: [PATCH v4 01/14] v4l: ti-vpe: Make sure in job_ready that we have the needed number of dst_bufs

Quoted 17 lines

From: Archit Taneja [mailto:[email protected]]
Sent: Thursday, March 13, 2014 12:44 PM

VPE has a ctrl parameter which decides how many mem to mem transactions the active job from the job queue can perform.

The driver's job_ready() made sure that the number of ready source buffers are sufficient for the job to execute successfully. But it didn't make sure if there are sufficient ready destination buffers in the capture queue for the VPE output.

If the time taken by VPE to process a single frame is really slow, then it's possible that we don't need to imply such a restriction on the dst queue, but really fast transactions(small resolution, no de-interlacing) may cause us to hit the condition where we don't have any free buffers for the VPE to write on.

Quoted 4 lines

Add the extra check in job_ready() to make sure we have the sufficient amount of destination buffers.

Quoted 21 lines
---
 drivers/media/platform/ti-vpe/vpe.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/media/platform/ti-vpe/vpe.c +3 -1
index 7a77a5b..f3143ac 100644
@@ -887,6 +887,9 @@ static int job_ready(void *priv)
 	if (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) < needed)
 		return 0;
 
+	if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < needed)
+		return 0;
+
 	return 1;
 }
 
--

1.8.3.2

#72 lore raw

PATCH v4 2/14 v4l: ti-vpe: register video device only when firmware is loaded

In reply to Archit Taneja

vpe fops(vpe_open in particular) should be called only when VPDMA firmware is loaded. File operations on the video device are possible the moment it is registered.

Currently, we register the video device for VPE at driver probe, after calling a vpdma helper to initialize VPDMA and load firmware. This function is non-blocking(it calls request_firmware_nowait()), and doesn't ensure that the firmware is actually loaded when it returns.

We remove the device registration from vpe probe, and move it to a callback provided by the vpe driver to the vpdma library, through vpdma_create().

The ready field in vpdma_data is no longer needed since we always have firmware loaded before the device is registered.

A minor problem with this approach is that if the video_register_device fails(which doesn't really happen), the vpe platform device would be registered. however, there won't be any v4l2 device corresponding to it.

---
 drivers/media/platform/ti-vpe/vpdma.c |  8 +++--
 drivers/media/platform/ti-vpe/vpdma.h |  7 +++--
 drivers/media/platform/ti-vpe/vpe.c   | 55 ++++++++++++++++++++---------------
 3 files changed, 41 insertions(+), 29 deletions(-)
drivers/media/platform/ti-vpe/vpdma.c +5 -3
index e8175e7..73dd38e 100644
@@ -781,7 +781,7 @@ static void vpdma_firmware_cb(const struct firmware *f, void *context)
 	/* already initialized */
 	if (read_field_reg(vpdma, VPDMA_LIST_ATTR, VPDMA_LIST_RDY_MASK,
 			VPDMA_LIST_RDY_SHFT)) {
-		vpdma->ready = true;
+		vpdma->cb(vpdma->pdev);
 		return;
 	}
 
@@ -811,7 +811,7 @@ static void vpdma_firmware_cb(const struct firmware *f, void *context)
 		goto free_buf;
 	}
 
-	vpdma->ready = true;
+	vpdma->cb(vpdma->pdev);
 
 free_buf:
 	vpdma_unmap_desc_buf(vpdma, &fw_dma_buf);
@@ -839,7 +839,8 @@ static int vpdma_load_firmware(struct vpdma_data *vpdma)
 	return 0;
 }
 
-struct vpdma_data *vpdma_create(struct platform_device *pdev)
+struct vpdma_data *vpdma_create(struct platform_device *pdev,
+		void (*cb)(struct platform_device *pdev))
 {
 	struct resource *res;
 	struct vpdma_data *vpdma;
@@ -854,6 +855,7 @@ struct vpdma_data *vpdma_create(struct platform_device *pdev)
 	}
 
 	vpdma->pdev = pdev;
+	vpdma->cb = cb;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpdma");
 	if (res == NULL) {
drivers/media/platform/ti-vpe/vpdma.h +4 -3
index cf40f11..bf5f8bb 100644
@@ -35,8 +35,8 @@ struct vpdma_data {
 
 	struct platform_device	*pdev;
 
-	/* tells whether vpdma firmware is loaded or not */
-	bool ready;
+	/* callback to VPE driver when the firmware is loaded */
+	void (*cb)(struct platform_device *pdev);
 };
 
 enum vpdma_data_format_type {
@@ -208,6 +208,7 @@ void vpdma_set_frame_start_event(struct vpdma_data *vpdma,
 void vpdma_dump_regs(struct vpdma_data *vpdma);
 
 /* initialize vpdma, passed with VPE's platform device pointer */
-struct vpdma_data *vpdma_create(struct platform_device *pdev);
+struct vpdma_data *vpdma_create(struct platform_device *pdev,
+		void (*cb)(struct platform_device *pdev));
 
 #endif
drivers/media/platform/ti-vpe/vpe.c +32 -23

81 lines not on this page · raw message

Signature · 1 line
1.8.3.2
#73 lore raw

PATCH v4 3/14 v4l: ti-vpe: Use video_device_release_empty

In reply to Archit Taneja

The video_device struct is currently embedded in the driver data struct vpe_dev. A vpe_dev instance is allocated by the driver, and the memory for the vfd is a part of this struct.

The v4l2 core, however, manages the removal of the vfd region, through the video_device's .release() op, which currently is the helper video_device_release. This causes memory corruption, and leads to issues when we try to re-insert the vpe module.

Use the video_device_release_empty helper function instead.

---
 drivers/media/platform/ti-vpe/vpe.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/platform/ti-vpe/vpe.c +1 -1
index f1eae67..0363df6 100644
@@ -2000,7 +2000,7 @@ static struct video_device vpe_videodev = {
 	.fops		= &vpe_fops,
 	.ioctl_ops	= &vpe_ioctl_ops,
 	.minor		= -1,
-	.release	= video_device_release,
+	.release	= video_device_release_empty,
 	.vfl_dir	= VFL_DIR_M2M,
 };
 
Signature · 1 line
1.8.3.2
#74 lore raw

PATCH v4 4/14 v4l: ti-vpe: Allow DMABUF buffer type support

In reply to Archit Taneja

For OMAP and DRA7x, we generally allocate video and graphics buffers through omapdrm since the corresponding omap-gem driver provides DMM-Tiler backed contiguous buffers. omapdrm is a dma-buf exporter. These buffers are used by other drivers in the video pipeline.

Add VB2_DMABUF flag to the io_modes of the vb2 output and capture queues. This allows the driver to import dma shared buffers.

---
 drivers/media/platform/ti-vpe/vpe.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/media/platform/ti-vpe/vpe.c +2 -2
index 0363df6..0e7573a 100644
@@ -1770,7 +1770,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
 
 	memset(src_vq, 0, sizeof(*src_vq));
 	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
-	src_vq->io_modes = VB2_MMAP;
+	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
 	src_vq->drv_priv = ctx;
 	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 	src_vq->ops = &vpe_qops;
@@ -1783,7 +1783,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
 
 	memset(dst_vq, 0, sizeof(*dst_vq));
 	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-	dst_vq->io_modes = VB2_MMAP;
+	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
 	dst_vq->drv_priv = ctx;
 	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 	dst_vq->ops = &vpe_qops;
Signature · 1 line
1.8.3.2
#75 lore raw

PATCH v4 5/14 v4l: ti-vpe: Allow usage of smaller images

In reply to Archit Taneja

The minimum width and height for VPE input/output was kept as 128 pixels. VPE doesn't have a constraint on the image height, it requires the image width to be at least 16 bytes.

Change the minimum supported dimensions to 32x32. This allows us to de-interlace qcif content. A smaller image size than 32x32 didn't make much sense, so stopped at this.

---
 drivers/media/platform/ti-vpe/vpe.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/media/platform/ti-vpe/vpe.c +2 -2
index 0e7573a..dbdc338 100644
@@ -49,8 +49,8 @@
 #define VPE_MODULE_NAME "vpe"
 
 /* minimum and maximum frame sizes */
-#define MIN_W		128
-#define MIN_H		128
+#define MIN_W		32
+#define MIN_H		32
 #define MAX_W		1920
 #define MAX_H		1080
 
Signature · 1 line
1.8.3.2
#76 lore raw

PATCH v4 6/14 v4l: ti-vpe: Fix some params in VPE data descriptors

In reply to Archit Taneja

Some parameters of the VPE descriptors were understood incorrectly. They are now fixed. The fixes are explained as follows:

- When adding an inbound data descriptor to the VPDMA descriptor list, we intend to use c_rect as the cropped region fetched by VPDMA. Therefore, c_rect->width shouldn't be used to calculate the line stride, the original image width should be used for that. We add a 'width' argument which gives the buffer width in memory.

- frame_width and frame_height describe the complete width and height of the client to which the channel is connected. If there are multiple channels fetching data and providing to the same client, the above 2 arguments should be the width and height of the region covered by all the channels. In the case where there is only one channel providing pixel data to the client (like in VPE), frame_width and frame_height should be the cropped width and cropped height respectively. The calculation of these params is done in the vpe driver now.

- start_h and start_v is also used in the case of multiple channels to describe where each channel should start filling pixel data. We don't use this in VPE, and pass 0s to the vpdma_add_in_dtd() helper.

- Some minor changes are made to the vpdma_add_out_dtd() helper. The c_rect param is used for specifying the 'composition' target, and 'width' is added to calculate the line stride.

---
 drivers/media/platform/ti-vpe/vpdma.c | 60 +++++++++++++++++++++++++++--------
 drivers/media/platform/ti-vpe/vpdma.h | 10 +++---
 drivers/media/platform/ti-vpe/vpe.c   | 18 +++++++----
 3 files changed, 64 insertions(+), 24 deletions(-)
drivers/media/platform/ti-vpe/vpdma.c +46 -14
index 73dd38e..a51a013 100644
@@ -614,8 +614,17 @@ static void dump_dtd(struct vpdma_dtd *dtd)
 /*
  * append an outbound data transfer descriptor to the given descriptor list,
  * this sets up a 'client to memory' VPDMA transfer for the given VPDMA channel
+ *
+ * @list: vpdma desc list to which we add this decriptor
+ * @width: width of the image in pixels in memory
+ * @c_rect: compose params of output image
+ * @fmt: vpdma data format of the buffer
+ * dma_addr: dma address as seen by VPDMA
+ * chan: VPDMA channel
+ * flags: VPDMA flags to configure some descriptor fileds
  */
-void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
+void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width,
+		const struct v4l2_rect *c_rect,
 		const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
 		enum vpdma_channel chan, u32 flags)
 {
@@ -623,6 +632,7 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
 	int field = 0;
 	int notify = 1;
 	int channel, next_chan;
+	struct v4l2_rect rect = *c_rect;
 	int depth = fmt->depth;
 	int stride;
 	struct vpdma_dtd *dtd;
@@ -630,11 +640,15 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
 	channel = next_chan = chan_info[chan].num;
 
 	if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV &&
-			fmt->data_type == DATA_TYPE_C420)
+			fmt->data_type == DATA_TYPE_C420) {
+		rect.height >>= 1;
+		rect.top >>= 1;
 		depth = 8;
+	}
 
-	stride = ALIGN((depth * c_rect->width) >> 3, VPDMA_STRIDE_ALIGN);
-	dma_addr += (c_rect->left * depth) >> 3;
+	stride = ALIGN((depth * width) >> 3, VPDMA_STRIDE_ALIGN);
+
+	dma_addr += rect.top * stride + (rect.left * depth >> 3);
 
 	dtd = list->next;
 	WARN_ON((void *)(dtd + 1) > (list->buf.addr + list->buf.size));
@@ -664,31 +678,48 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
 /*
  * append an inbound data transfer descriptor to the given descriptor list,
  * this sets up a 'memory to client' VPDMA transfer for the given VPDMA channel
+ *
+ * @list: vpdma desc list to which we add this decriptor
+ * @width: width of the image in pixels in memory(not the cropped width)
+ * @c_rect: crop params of input image
+ * @fmt: vpdma data format of the buffer
+ * dma_addr: dma address as seen by VPDMA
+ * chan: VPDMA channel
+ * field: top or bottom field info of the input image
+ * flags: VPDMA flags to configure some descriptor fileds
+ * frame_width/height: the complete width/height of the image presented to the
+ *			client (this makes sense when multiple channels are
+ *			connected to the same client, forming a larger frame)
+ * start_h, start_v: position where the given channel starts providing pixel
+ *			data to the client (makes sense when multiple channels
+ *			contribute to the client)
  */
-void vpdma_add_in_dtd(struct vpdma_desc_list *list, int frame_width,
-		int frame_height, struct v4l2_rect *c_rect,
+void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width,
+		const struct v4l2_rect *c_rect,
 		const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
-		enum vpdma_channel chan, int field, u32 flags)
+		enum vpdma_channel chan, int field, u32 flags, int frame_width,
+		int frame_height, int start_h, int start_v)
 {
 	int priority = 0;
 	int notify = 1;
 	int depth = fmt->depth;
 	int channel, next_chan;
+	struct v4l2_rect rect = *c_rect;
 	int stride;
-	int height = c_rect->height;
 	struct vpdma_dtd *dtd;
 
 	channel = next_chan = chan_info[chan].num;
 
 	if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV &&
 			fmt->data_type == DATA_TYPE_C420) {
-		height >>= 1;
-		frame_height >>= 1;
+		rect.height >>= 1;
+		rect.top >>= 1;
 		depth = 8;
 	}
 
-	stride = ALIGN((depth * c_rect->width) >> 3, VPDMA_STRIDE_ALIGN);
-	dma_addr += (c_rect->left * depth) >> 3;
+	stride = ALIGN((depth * width) >> 3, VPDMA_STRIDE_ALIGN);
+
+	dma_addr += rect.top * stride + (rect.left * depth >> 3);
 
 	dtd = list->next;
 	WARN_ON((void *)(dtd + 1) > (list->buf.addr + list->buf.size));
@@ -701,13 +732,14 @@ void vpdma_add_in_dtd(struct vpdma_desc_list *list, int frame_width,
 					!!(flags & VPDMA_DATA_ODD_LINE_SKIP),
 					stride);
 
-	dtd->xfer_length_height = dtd_xfer_length_height(c_rect->width, height);
+	dtd->xfer_length_height = dtd_xfer_length_height(rect.width,
+					rect.height);
 	dtd->start_addr = (u32) dma_addr;
 	dtd->pkt_ctl = dtd_pkt_ctl(!!(flags & VPDMA_DATA_MODE_TILED),
 				DTD_DIR_IN, channel, priority, next_chan);
 	dtd->frame_width_height = dtd_frame_width_height(frame_width,
 					frame_height);
-	dtd->start_h_v = dtd_start_h_v(c_rect->left, c_rect->top);
+	dtd->start_h_v = dtd_start_h_v(start_h, start_v);
 	dtd->client_attr0 = 0;
 	dtd->client_attr1 = 0;
 
drivers/media/platform/ti-vpe/vpdma.h +6 -4
index bf5f8bb..2bd8fb0 100644
@@ -186,13 +186,15 @@ void vpdma_add_cfd_adb(struct vpdma_desc_list *list, int client,
 		struct vpdma_buf *adb);
 void vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list,
 		enum vpdma_channel chan);
-void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
+void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width,
+		const struct v4l2_rect *c_rect,
 		const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
 		enum vpdma_channel chan, u32 flags);
-void vpdma_add_in_dtd(struct vpdma_desc_list *list, int frame_width,
-		int frame_height, struct v4l2_rect *c_rect,
+void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width,
+		const struct v4l2_rect *c_rect,
 		const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
-		enum vpdma_channel chan, int field, u32 flags);
+		enum vpdma_channel chan, int field, u32 flags, int frame_width,
+		int frame_height, int start_h, int start_v);
 
 /* vpdma list interrupt management */
 void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int list_num,
drivers/media/platform/ti-vpe/vpe.c +12 -6
index dbdc338..ece9b96 100644
@@ -986,7 +986,6 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port)
 	struct vpe_q_data *q_data = &ctx->q_data[Q_DATA_DST];
 	const struct vpe_port_data *p_data = &port_data[port];
 	struct vb2_buffer *vb = ctx->dst_vb;
-	struct v4l2_rect *c_rect = &q_data->c_rect;
 	struct vpe_fmt *fmt = q_data->fmt;
 	const struct vpdma_data_format *vpdma_fmt;
 	int mv_buf_selector = !ctx->src_mv_buf_selector;
@@ -1015,8 +1014,8 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port)
 	if (q_data->flags & Q_DATA_MODE_TILED)
 		flags |= VPDMA_DATA_MODE_TILED;
 
-	vpdma_add_out_dtd(&ctx->desc_list, c_rect, vpdma_fmt, dma_addr,
-		p_data->channel, flags);
+	vpdma_add_out_dtd(&ctx->desc_list, q_data->width, &q_data->c_rect,
+		vpdma_fmt, dma_addr, p_data->channel, flags);
 }
 
 static void add_in_dtd(struct vpe_ctx *ctx, int port)
@@ -1024,11 +1023,11 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port)
 	struct vpe_q_data *q_data = &ctx->q_data[Q_DATA_SRC];
 	const struct vpe_port_data *p_data = &port_data[port];
 	struct vb2_buffer *vb = ctx->src_vbs[p_data->vb_index];
-	struct v4l2_rect *c_rect = &q_data->c_rect;
 	struct vpe_fmt *fmt = q_data->fmt;
 	const struct vpdma_data_format *vpdma_fmt;
 	int mv_buf_selector = ctx->src_mv_buf_selector;
 	int field = vb->v4l2_buf.field == V4L2_FIELD_BOTTOM;
+	int frame_width, frame_height;
 	dma_addr_t dma_addr;
 	u32 flags = 0;
 
@@ -1055,8 +1054,15 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port)
 	if (q_data->flags & Q_DATA_MODE_TILED)
 		flags |= VPDMA_DATA_MODE_TILED;
 
-	vpdma_add_in_dtd(&ctx->desc_list, q_data->width, q_data->height,
-		c_rect, vpdma_fmt, dma_addr, p_data->channel, field, flags);
+	frame_width = q_data->c_rect.width;
+	frame_height = q_data->c_rect.height;
+
+	if (p_data->vb_part && fmt->fourcc == V4L2_PIX_FMT_NV12)
+		frame_height /= 2;
+
+	vpdma_add_in_dtd(&ctx->desc_list, q_data->width, &q_data->c_rect,
+		vpdma_fmt, dma_addr, p_data->channel, field, flags, frame_width,
+		frame_height, 0, 0);
 }
 
 /*
Signature · 1 line
1.8.3.2
Acked-by on v4 6/14
#77 lore raw

RE: [PATCH v4 06/14] v4l: ti-vpe: Fix some params in VPE data descriptors

Hi,

Quoted 42 lines

From: Archit Taneja [mailto:[email protected]]
Sent: Thursday, March 13, 2014 12:44 PM
To: [email protected]; [email protected]
Cc: [email protected]; [email protected]; Archit Taneja
Subject: [PATCH v4 06/14] v4l: ti-vpe: Fix some params in VPE data descriptors

Some parameters of the VPE descriptors were understood incorrectly. They are now fixed. The fixes are explained as follows:

- When adding an inbound data descriptor to the VPDMA descriptor list, we intend
to use c_rect as the cropped region fetched by VPDMA. Therefore,
c_rect->width
shouldn't be used to calculate the line stride, the original image
width
should be used for that. We add a 'width' argument which gives the
buffer
width in memory.

- frame_width and frame_height describe the complete width and height of the
client to which the channel is connected. If there are multiple
channels
fetching data and providing to the same client, the above 2 arguments
should
be the width and height of the region covered by all the channels. In
the case
where there is only one channel providing pixel data to the client (like in VPE), frame_width and frame_height should be the cropped
width and
cropped height respectively. The calculation of these params is done
in the
vpe driver now.

- start_h and start_v is also used in the case of multiple channels to describe
where each channel should start filling pixel data. We don't use this
in VPE,
and pass 0s to the vpdma_add_in_dtd() helper.

Quoted 5 lines

- Some minor changes are made to the vpdma_add_out_dtd() helper. The c_rect
param is used for specifying the 'composition' target, and 'width'
is added
to calculate the line stride.

This patch looks ok. Passes checkpatch and compiles. I can't say much more as I have limited knowledge of the internals of VPE and don't have the hardware.

Quoted 1 line

Best wishes,

Signature · 2 lines
Kamil Debski
Samsung R&D Institute Poland
Quoted 76 lines
---
 drivers/media/platform/ti-vpe/vpdma.c | 60
+++++++++++++++++++++++++++--------
 drivers/media/platform/ti-vpe/vpdma.h | 10 +++---
 drivers/media/platform/ti-vpe/vpe.c   | 18 +++++++----
 3 files changed, 64 insertions(+), 24 deletions(-)
drivers/media/platform/ti-vpe/vpdma.c +0 -0
index 73dd38e..a51a013 100644
@@ -614,8 +614,17 @@ static void dump_dtd(struct vpdma_dtd *dtd)
 /*
  * append an outbound data transfer descriptor to the given descriptor
 list,
  * this sets up a 'client to memory' VPDMA transfer for the given

VPDMA channel
+ *
+ * @list: vpdma desc list to which we add this decriptor
+ * @width: width of the image in pixels in memory
+ * @c_rect: compose params of output image
+ * @fmt: vpdma data format of the buffer
+ * dma_addr: dma address as seen by VPDMA
+ * chan: VPDMA channel
+ * flags: VPDMA flags to configure some descriptor fileds */
-void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,

drivers/media/platform/ti-vpe/vpdma.c +3 -0
+void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width,
+		const struct v4l2_rect *c_rect,
 		const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
 		enum vpdma_channel chan, u32 flags)
 {
@@ -623,6 +632,7 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list,
 struct v4l2_rect *c_rect,
 	int field = 0;
 	int notify = 1;
 	int channel, next_chan;
+	struct v4l2_rect rect = *c_rect;
 	int depth = fmt->depth;
 	int stride;
drivers/media/platform/ti-vpe/vpdma.c +7 -3
 	struct vpdma_dtd *dtd;
@@ -630,11 +640,15 @@ void vpdma_add_out_dtd(struct vpdma_desc_list
 *list, struct v4l2_rect *c_rect,
 	channel = next_chan = chan_info[chan].num;
 
 	if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV &&
-			fmt->data_type == DATA_TYPE_C420)
+			fmt->data_type == DATA_TYPE_C420) {
+		rect.height >>= 1;
+		rect.top >>= 1;
 		depth = 8;
+	}
 
-	stride = ALIGN((depth * c_rect->width) >> 3, VPDMA_STRIDE_ALIGN);
-	dma_addr += (c_rect->left * depth) >> 3;
+	stride = ALIGN((depth * width) >> 3, VPDMA_STRIDE_ALIGN);
+
+	dma_addr += rect.top * stride + (rect.left * depth >> 3);
 
 	dtd = list->next;
drivers/media/platform/ti-vpe/vpdma.c +0 -0
 	WARN_ON((void *)(dtd + 1) > (list->buf.addr + list->buf.size));
@@ -664,31 +678,48 @@ void vpdma_add_out_dtd(struct vpdma_desc_list
 *list, struct v4l2_rect *c_rect,
 /*
  * append an inbound data transfer descriptor to the given descriptor
 list,
  * this sets up a 'memory to client' VPDMA transfer for the given

VPDMA channel
+ *
+ * @list: vpdma desc list to which we add this decriptor
+ * @width: width of the image in pixels in memory(not the cropped
+ width)
+ * @c_rect: crop params of input image
+ * @fmt: vpdma data format of the buffer

Quoted 8 lines

+ * dma_addr: dma address as seen by VPDMA
+ * chan: VPDMA channel
+ * field: top or bottom field info of the input image
+ * flags: VPDMA flags to configure some descriptor fileds
+ * frame_width/height: the complete width/height of the image presented to the
+ * client (this makes sense when multiple channels are
+ * connected to the same client, forming a larger

frame)

Quoted 45 lines

+ * start_h, start_v: position where the given channel starts providing pixel
+ * data to the client (makes sense when multiple
channels
+ * contribute to the client)
*/

drivers/media/platform/ti-vpe/vpdma.c +3 -3
-void vpdma_add_in_dtd(struct vpdma_desc_list *list, int frame_width,
-		int frame_height, struct v4l2_rect *c_rect,
+void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width,
+		const struct v4l2_rect *c_rect,
 		const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
-		enum vpdma_channel chan, int field, u32 flags)
+		enum vpdma_channel chan, int field, u32 flags, int

frame_width,

drivers/media/platform/ti-vpe/vpdma.c +7 -5
+		int frame_height, int start_h, int start_v)
 {
 	int priority = 0;
 	int notify = 1;
 	int depth = fmt->depth;
 	int channel, next_chan;
+	struct v4l2_rect rect = *c_rect;
 	int stride;
-	int height = c_rect->height;
 	struct vpdma_dtd *dtd;
 
 	channel = next_chan = chan_info[chan].num;
 
 	if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV &&
 			fmt->data_type == DATA_TYPE_C420) {
-		height >>= 1;
-		frame_height >>= 1;
+		rect.height >>= 1;
+		rect.top >>= 1;
 		depth = 8;
 	}
 
-	stride = ALIGN((depth * c_rect->width) >> 3, VPDMA_STRIDE_ALIGN);
-	dma_addr += (c_rect->left * depth) >> 3;
+	stride = ALIGN((depth * width) >> 3, VPDMA_STRIDE_ALIGN);
+
+	dma_addr += rect.top * stride + (rect.left * depth >> 3);
 
 	dtd = list->next;
 	WARN_ON((void *)(dtd + 1) > (list->buf.addr + list->buf.size));

drivers/media/platform/ti-vpe/vpdma.c void vpdma_add_in_dtd(struct vpdma_desc_list · line 733

Quoted 2 lines
drivers/media/platform/ti-vpe/vpdma.c +0 -0
@@ -701,13 +732,14 @@ void vpdma_add_in_dtd(struct vpdma_desc_list
 *list, int frame_width,
 					!!(flags &

VPDMA_DATA_ODD_LINE_SKIP),

Quoted 104 lines
drivers/media/platform/ti-vpe/vpdma.c +3 -2
 					stride);
 
-	dtd->xfer_length_height = dtd_xfer_length_height(c_rect->width,
 height);
+	dtd->xfer_length_height = dtd_xfer_length_height(rect.width,
+					rect.height);
 	dtd->start_addr = (u32) dma_addr;
 	dtd->pkt_ctl = dtd_pkt_ctl(!!(flags & VPDMA_DATA_MODE_TILED),
 				DTD_DIR_IN, channel, priority, next_chan);
 	dtd->frame_width_height = dtd_frame_width_height(frame_width,
 					frame_height);
-	dtd->start_h_v = dtd_start_h_v(c_rect->left, c_rect->top);
+	dtd->start_h_v = dtd_start_h_v(start_h, start_v);
 	dtd->client_attr0 = 0;
drivers/media/platform/ti-vpe/vpdma.c +0 -0
 	dtd->client_attr1 = 0;
drivers/media/platform/ti-vpe/vpdma.h +6 -4
index bf5f8bb..2bd8fb0 100644
@@ -186,13 +186,15 @@ void vpdma_add_cfd_adb(struct vpdma_desc_list
 *list, int client,
 		struct vpdma_buf *adb);
 void vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list,
 		enum vpdma_channel chan);
-void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect
 *c_rect,
+void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width,
+		const struct v4l2_rect *c_rect,
 		const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
 		enum vpdma_channel chan, u32 flags);
-void vpdma_add_in_dtd(struct vpdma_desc_list *list, int frame_width,
-		int frame_height, struct v4l2_rect *c_rect,
+void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width,
+		const struct v4l2_rect *c_rect,
 		const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
-		enum vpdma_channel chan, int field, u32 flags);
+		enum vpdma_channel chan, int field, u32 flags, int
 frame_width,
+		int frame_height, int start_h, int start_v);

/* vpdma list interrupt management */
void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int
list_num, diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c
index dbdc338..ece9b96 100644

drivers/media/platform/ti-vpe/vpe.c +0 -1
@@ -986,7 +986,6 @@ static void add_out_dtd(struct vpe_ctx *ctx, int
 port)
 	struct vpe_q_data *q_data = &ctx->q_data[Q_DATA_DST];
 	const struct vpe_port_data *p_data = &port_data[port];
 	struct vb2_buffer *vb = ctx->dst_vb;
-	struct v4l2_rect *c_rect = &q_data->c_rect;
 	struct vpe_fmt *fmt = q_data->fmt;
 	const struct vpdma_data_format *vpdma_fmt;
drivers/media/platform/ti-vpe/vpe.c +14 -5
 	int mv_buf_selector = !ctx->src_mv_buf_selector; @@ -1015,8
+1014,8 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port)
 	if (q_data->flags & Q_DATA_MODE_TILED)
 		flags |= VPDMA_DATA_MODE_TILED;
 
-	vpdma_add_out_dtd(&ctx->desc_list, c_rect, vpdma_fmt, dma_addr,
-		p_data->channel, flags);
+	vpdma_add_out_dtd(&ctx->desc_list, q_data->width, &q_data->c_rect,
+		vpdma_fmt, dma_addr, p_data->channel, flags);
 }
 
 static void add_in_dtd(struct vpe_ctx *ctx, int port) @@ -1024,11
+1023,11 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port)
 	struct vpe_q_data *q_data = &ctx->q_data[Q_DATA_SRC];
 	const struct vpe_port_data *p_data = &port_data[port];
 	struct vb2_buffer *vb = ctx->src_vbs[p_data->vb_index];
-	struct v4l2_rect *c_rect = &q_data->c_rect;
 	struct vpe_fmt *fmt = q_data->fmt;
 	const struct vpdma_data_format *vpdma_fmt;
 	int mv_buf_selector = ctx->src_mv_buf_selector;
 	int field = vb->v4l2_buf.field == V4L2_FIELD_BOTTOM;
+	int frame_width, frame_height;
 	dma_addr_t dma_addr;
 	u32 flags = 0;
@@ -1055,8 +1054,15 @@ static void add_in_dtd(struct vpe_ctx *ctx, int
 port)
 	if (q_data->flags & Q_DATA_MODE_TILED)
 		flags |= VPDMA_DATA_MODE_TILED;
 
-	vpdma_add_in_dtd(&ctx->desc_list, q_data->width, q_data->height,
-		c_rect, vpdma_fmt, dma_addr, p_data->channel, field, flags);
+	frame_width = q_data->c_rect.width;
+	frame_height = q_data->c_rect.height;
+
+	if (p_data->vb_part && fmt->fourcc == V4L2_PIX_FMT_NV12)
+		frame_height /= 2;
+
+	vpdma_add_in_dtd(&ctx->desc_list, q_data->width, &q_data->c_rect,
+		vpdma_fmt, dma_addr, p_data->channel, field, flags,
 frame_width,
+		frame_height, 0, 0);
 }

/*
--
1.8.3.2

#78 lore raw

PATCH v4 7/14 v4l: ti-vpe: Add selection API in VPE driver

In reply to Archit Taneja

Add selection ioctl ops. For VPE, cropping makes sense only for the input to VPE(or V4L2_BUF_TYPE_VIDEO_OUTPUT/MPLANE buffers) and composing makes sense only for the output of VPE(or V4L2_BUF_TYPE_VIDEO_CAPTURE/MPLANE buffers).

For the CAPTURE type, V4L2_SEL_TGT_COMPOSE results in VPE writing the output in a rectangle within the capture buffer. For the OUTPUT type, V4L2_SEL_TGT_CROP results in selecting a rectangle region within the source buffer.

Setting the crop/compose rectangles should successfully result in re-configuration of registers which are affected when either source or destination dimensions change, set_srcdst_params() is called for this purpose.

---
 drivers/media/platform/ti-vpe/vpe.c | 150 ++++++++++++++++++++++++++++++++++++
 1 file changed, 150 insertions(+)
drivers/media/platform/ti-vpe/vpe.c +150 -0
index ece9b96..f3f1c10 100644
@@ -410,8 +410,10 @@ static struct vpe_q_data *get_q_data(struct vpe_ctx *ctx,
 {
 	switch (type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 		return &ctx->q_data[Q_DATA_SRC];
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 		return &ctx->q_data[Q_DATA_DST];
 	default:
 		BUG();
@@ -1587,6 +1589,151 @@ static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	return set_srcdst_params(ctx);
 }
 
+static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s)
+{
+	struct vpe_q_data *q_data;
+
+	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, s->type);
+	if (!q_data)
+		return -EINVAL;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE:
+		/*
+		 * COMPOSE target is only valid for capture buffer type, return
+		 * error for output buffer type
+		 */
+		if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+			return -EINVAL;
+		break;
+	case V4L2_SEL_TGT_CROP:
+		/*
+		 * CROP target is only valid for output buffer type, return
+		 * error for capture buffer type
+		 */
+		if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+		break;
+	/*
+	 * bound and default crop/compose targets are invalid targets to
+	 * try/set
+	 */
+	default:
+		return -EINVAL;
+	}
+
+	if (s->r.top < 0 || s->r.left < 0) {
+		vpe_err(ctx->dev, "negative values for top and left\n");
+		s->r.top = s->r.left = 0;
+	}
+
+	v4l_bound_align_image(&s->r.width, MIN_W, q_data->width, 1,
+		&s->r.height, MIN_H, q_data->height, H_ALIGN, S_ALIGN);
+
+	/* adjust left/top if cropping rectangle is out of bounds */
+	if (s->r.left + s->r.width > q_data->width)
+		s->r.left = q_data->width - s->r.width;
+	if (s->r.top + s->r.height > q_data->height)
+		s->r.top = q_data->height - s->r.height;
+
+	return 0;
+}
+
+static int vpe_g_selection(struct file *file, void *fh,
+		struct v4l2_selection *s)
+{
+	struct vpe_ctx *ctx = file2ctx(file);
+	struct vpe_q_data *q_data;
+	bool use_c_rect = false;
+
+	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, s->type);
+	if (!q_data)
+		return -EINVAL;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+			return -EINVAL;
+		break;
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+		if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+		break;
+	case V4L2_SEL_TGT_COMPOSE:
+		if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+			return -EINVAL;
+		use_c_rect = true;
+		break;
+	case V4L2_SEL_TGT_CROP:
+		if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+		use_c_rect = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (use_c_rect) {
+		/*
+		 * for CROP/COMPOSE target type, return c_rect params from the
+		 * respective buffer type
+		 */
+		s->r = q_data->c_rect;
+	} else {
+		/*
+		 * for DEFAULT/BOUNDS target type, return width and height from
+		 * S_FMT of the respective buffer type
+		 */
+		s->r.left = 0;
+		s->r.top = 0;
+		s->r.width = q_data->width;
+		s->r.height = q_data->height;
+	}
+
+	return 0;
+}
+
+
+static int vpe_s_selection(struct file *file, void *fh,
+		struct v4l2_selection *s)
+{
+	struct vpe_ctx *ctx = file2ctx(file);
+	struct vpe_q_data *q_data;
+	struct v4l2_selection sel = *s;
+	int ret;
+
+	ret = __vpe_try_selection(ctx, &sel);
+	if (ret)
+		return ret;
+
+	q_data = get_q_data(ctx, sel.type);
+	if (!q_data)
+		return -EINVAL;
+
+	if ((q_data->c_rect.left == sel.r.left) &&
+			(q_data->c_rect.top == sel.r.top) &&
+			(q_data->c_rect.width == sel.r.width) &&
+			(q_data->c_rect.height == sel.r.height)) {
+		vpe_dbg(ctx->dev,
+			"requested crop/compose values are already set\n");
+		return 0;
+	}
+
+	q_data->c_rect = sel.r;
+
+	return set_srcdst_params(ctx);
+}
+
 static int vpe_reqbufs(struct file *file, void *priv,
 		       struct v4l2_requestbuffers *reqbufs)
 {
@@ -1674,6 +1821,9 @@ static const struct v4l2_ioctl_ops vpe_ioctl_ops = {
 	.vidioc_try_fmt_vid_out_mplane	= vpe_try_fmt,
 	.vidioc_s_fmt_vid_out_mplane	= vpe_s_fmt,
 
+	.vidioc_g_selection		= vpe_g_selection,
+	.vidioc_s_selection		= vpe_s_selection,
+
 	.vidioc_reqbufs		= vpe_reqbufs,
 	.vidioc_querybuf	= vpe_querybuf,
 
Signature · 1 line
1.8.3.2
#79 lore raw

PATCH v4 8/14 v4l: ti-vpe: Rename csc memory resource name

In reply to Archit Taneja

Rename the memory block resource "vpe_csc" to "csc" since it also exists within the VIP IP block. This would make the name more generic, and both VPE and VIP DT nodes in the future can use it.

---
 drivers/media/platform/ti-vpe/csc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/platform/ti-vpe/csc.c +1 -1
index acfea50..0333339 100644
@@ -180,7 +180,7 @@ struct csc_data *csc_create(struct platform_device *pdev)
 	csc->pdev = pdev;
 
 	csc->res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-			"vpe_csc");
+			"csc");
 	if (csc->res == NULL) {
 		dev_err(&pdev->dev, "missing platform resources data\n");
 		return ERR_PTR(-ENODEV);
Signature · 1 line
1.8.3.2
#80 lore raw

RE: [PATCH v4 08/14] v4l: ti-vpe: Rename csc memory resource name

Hi,

Quoted 6 lines

From: Archit Taneja [mailto:[email protected]]
Sent: Thursday, March 13, 2014 12:44 PM

Rename the memory block resource "vpe_csc" to "csc" since it also exists within the VIP IP block. This would make the name more generic, and both VPE and VIP DT nodes in the future can use it.

I understand that this is not yet used in any public dts files. Right?

Best wishes,

Signature · 2 lines
Kamil Debski
Samsung R&D Institute Poland
Quoted 23 lines
---
 drivers/media/platform/ti-vpe/csc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/platform/ti-vpe/csc.c +1 -1
index acfea50..0333339 100644
@@ -180,7 +180,7 @@ struct csc_data *csc_create(struct platform_device
 *pdev)
 	csc->pdev = pdev;
 
 	csc->res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-			"vpe_csc");
+			"csc");
 	if (csc->res == NULL) {
 		dev_err(&pdev->dev, "missing platform resources data\n");

return ERR_PTR(-ENODEV);
--
1.8.3.2

#81 lore raw

Re: [PATCH v4 08/14] v4l: ti-vpe: Rename csc memory resource name

Hi Kamil,

Quoted 5 lines · Kamil Debski

Hi,

Quoted 3 lines

From: Archit Taneja [mailto:[email protected]]
Sent: Thursday, March 13, 2014 12:44 PM

Quoted 8 lines
Quoted 3 lines

Rename the memory block resource "vpe_csc" to "csc" since it also exists within the VIP IP block. This would make the name more generic, and both VPE and VIP DT nodes in the future can use it.

I understand that this is not yet used in any public dts files. Right?

Best wishes,

Yes, a VPE DT node doesn't exist in any public dts files yet. So it's safe to change the name.

It should eventually come in dra7.dtsi. There is a dependency on a crossbar IP module, which provides us with an IRQ line for VPE going to the GIC. Once that is merged, I can add the VPE DT node.

Thanks,
Archit

#82 lore raw

PATCH v4 9/14 v4l: ti-vpe: report correct capabilities in querycap

In reply to Archit Taneja

querycap currently returns V4L2_CAP_VIDEO_M2M as a capability, this should be V4L2_CAP_VIDEO_M2M_MPLANE instead, as the driver supports multiplanar formats.

---
 drivers/media/platform/ti-vpe/vpe.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/platform/ti-vpe/vpe.c +1 -1
index f3f1c10..c066eb8 100644
@@ -1347,7 +1347,7 @@ static int vpe_querycap(struct file *file, void *priv,
 	strncpy(cap->driver, VPE_MODULE_NAME, sizeof(cap->driver) - 1);
 	strncpy(cap->card, VPE_MODULE_NAME, sizeof(cap->card) - 1);
 	strlcpy(cap->bus_info, VPE_MODULE_NAME, sizeof(cap->bus_info));
-	cap->device_caps  = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
+	cap->device_caps  = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
 	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
 }
Signature · 1 line
1.8.3.2
#83 lore raw

PATCH v4 10/14 v4l: ti-vpe: Use correct bus_info name for the device in querycap

In reply to Archit Taneja

The bus_info parameter in v4l2_capabilities expects a 'platform_' prefix. This wasn't done in the driver and hence was breaking compliance. Update the bus_info parameter accordingly.

---
 drivers/media/platform/ti-vpe/vpe.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/media/platform/ti-vpe/vpe.c +2 -1
index c066eb8..3a312ea 100644
@@ -1346,7 +1346,8 @@ static int vpe_querycap(struct file *file, void *priv,
 {
 	strncpy(cap->driver, VPE_MODULE_NAME, sizeof(cap->driver) - 1);
 	strncpy(cap->card, VPE_MODULE_NAME, sizeof(cap->card) - 1);
-	strlcpy(cap->bus_info, VPE_MODULE_NAME, sizeof(cap->bus_info));
+	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+		VPE_MODULE_NAME);
 	cap->device_caps  = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
 	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
Signature · 1 line
1.8.3.2
#84 lore raw

PATCH v4 11/14 v4l: ti-vpe: Fix initial configuration queue data

In reply to Archit Taneja

The vpe output and capture queues are initially configured to default values in vpe_open(). A G_FMT before any S_FMTs will result in these values being populated.

The colorspace and bytesperline parameter of this initial configuration are incorrect. This breaks compliance when as we get 'TRY_FMT(G_FMT) != G_FMT'.

Fix the initial queue configuration such that it wouldn't need to be fixed by try_fmt.

---
 drivers/media/platform/ti-vpe/vpe.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/media/platform/ti-vpe/vpe.c +4 -2
index 3a312ea..d7befb9 100644
@@ -2021,9 +2021,11 @@ static int vpe_open(struct file *file)
 	s_q_data->fmt = &vpe_formats[2];
 	s_q_data->width = 1920;
 	s_q_data->height = 1080;
-	s_q_data->sizeimage[VPE_LUMA] = (s_q_data->width * s_q_data->height *
+	s_q_data->bytesperline[VPE_LUMA] = (s_q_data->width *
 			s_q_data->fmt->vpdma_fmt[VPE_LUMA]->depth) >> 3;
-	s_q_data->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	s_q_data->sizeimage[VPE_LUMA] = (s_q_data->bytesperline[VPE_LUMA] *
+			s_q_data->height);
+	s_q_data->colorspace = V4L2_COLORSPACE_REC709;
 	s_q_data->field = V4L2_FIELD_NONE;
 	s_q_data->c_rect.left = 0;
 	s_q_data->c_rect.top = 0;
Signature · 1 line
1.8.3.2
#85 lore raw

PATCH v4 12/14 v4l: ti-vpe: zero out reserved fields in try_fmt

In reply to Archit Taneja

Zero out the reserved formats in v4l2_pix_format_mplane and v4l2_plane_pix_format members of the returned v4l2_format pointer when passed through TRY_FMT ioctl.

This ensures that the user doesn't interpret the non-zero fields as some data passed by the driver, and ensures compliance.

---
 drivers/media/platform/ti-vpe/vpe.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/media/platform/ti-vpe/vpe.c +3 -0
index d7befb9..c0ae847 100644
@@ -1488,6 +1488,7 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f,
 		}
 	}
 
+	memset(pix->reserved, 0, sizeof(pix->reserved));
 	for (i = 0; i < pix->num_planes; i++) {
 		plane_fmt = &pix->plane_fmt[i];
 		depth = fmt->vpdma_fmt[i]->depth;
@@ -1499,6 +1500,8 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f,
 
 		plane_fmt->sizeimage =
 				(pix->height * pix->width * depth) >> 3;
+
+		memset(plane_fmt->reserved, 0, sizeof(plane_fmt->reserved));
 	}
 
 	return 0;
Signature · 1 line
1.8.3.2
#86 lore raw

PATCH v4 13/14 v4l: ti-vpe: Set correct field parameter for output and capture buffers

In reply to Archit Taneja

The vpe driver wasn't setting the correct field parameter for dequed CAPTURE type buffers for the case where the captured output is progressive.

Set the field to V4L2_FIELD_NONE for the completed destination buffers when the captured output is progressive.

For OUTPUT type buffers, a queued buffer's field is forced to V4L2_FIELD_NONE if the pixel format(configured through s_fmt for the buffer type V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE specifies) the field type isn't interlaced. If the pixel format specified was V4L2_FIELD_ALTERNATE, and the queued buffer's field isn't V4L2_FIELD_TOP or V4L2_FIELD_BOTTOM, the vb2 buf_prepare op returns an error.

This ensures compliance, and that the dequeued output and captured buffers contain the field type that the driver used internally.

---
 drivers/media/platform/ti-vpe/vpe.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)
drivers/media/platform/ti-vpe/vpe.c +12 -1
index c0ae847..362d5be 100644
@@ -1296,10 +1296,10 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data)
 		d_buf->timecode = s_buf->timecode;
 	}
 	d_buf->sequence = ctx->sequence;
-	d_buf->field = ctx->field;
 
 	d_q_data = &ctx->q_data[Q_DATA_DST];
 	if (d_q_data->flags & Q_DATA_INTERLACED) {
+		d_buf->field = ctx->field;
 		if (ctx->field == V4L2_FIELD_BOTTOM) {
 			ctx->sequence++;
 			ctx->field = V4L2_FIELD_TOP;
@@ -1308,6 +1308,7 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data)
 			ctx->field = V4L2_FIELD_BOTTOM;
 		}
 	} else {
+		d_buf->field = V4L2_FIELD_NONE;
 		ctx->sequence++;
 	}
 
@@ -1880,6 +1881,16 @@ static int vpe_buf_prepare(struct vb2_buffer *vb)
 	q_data = get_q_data(ctx, vb->vb2_queue->type);
 	num_planes = q_data->fmt->coplanar ? 2 : 1;
 
+	if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		if (!(q_data->flags & Q_DATA_INTERLACED)) {
+			vb->v4l2_buf.field = V4L2_FIELD_NONE;
+		} else {
+			if (vb->v4l2_buf.field != V4L2_FIELD_TOP &&
+					vb->v4l2_buf.field != V4L2_FIELD_BOTTOM)
+				return -EINVAL;
+		}
+	}
+
 	for (i = 0; i < num_planes; i++) {
 		if (vb2_plane_size(vb, i) < q_data->sizeimage[i]) {
 			vpe_err(ctx->dev,
Signature · 1 line
1.8.3.2
#87 lore raw

PATCH v4 14/14 v4l: ti-vpe: retain v4l2_buffer flags for captured buffers

In reply to Archit Taneja

The dequed CAPTURE_MPLANE type buffers don't contain the flags that the originally queued OUTPUT_MPLANE type buffers have. This breaks compliance.

Copy the source v4l2_buffer flags to the destination v4l2_buffer flags before they are dequed.

---
 drivers/media/platform/ti-vpe/vpe.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/media/platform/ti-vpe/vpe.c +4 -5
index 362d5be..972f43f 100644
@@ -1288,13 +1288,12 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data)
 	s_buf = &s_vb->v4l2_buf;
 	d_buf = &d_vb->v4l2_buf;
 
+	d_buf->flags = s_buf->flags;
+
 	d_buf->timestamp = s_buf->timestamp;
-	d_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
-	d_buf->flags |= s_buf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
-	if (s_buf->flags & V4L2_BUF_FLAG_TIMECODE) {
-		d_buf->flags |= V4L2_BUF_FLAG_TIMECODE;
+	if (s_buf->flags & V4L2_BUF_FLAG_TIMECODE)
 		d_buf->timecode = s_buf->timecode;
-	}
+
 	d_buf->sequence = ctx->sequence;
 
 	d_q_data = &ctx->q_data[Q_DATA_DST];
Signature · 1 line
1.8.3.2