Skip to contentSkip to conversation

Upstream patches for Samsung Exynos s5p-mfc and gsc-m2m

PATCH In review John Sheu 6 participants 12 messages Mar 11, 2014 – Nov 11, 2015

Subsystems (2)
lore
Share & tools
lore

John Sheu

author
#0 lore raw

This patchset upstreams some changes carried in the ChromeOS kernel tree especially regarding the s5p-mfc video encoder and gsc-m2m color converter hardware functionality.

Patch 4 in particular affects the V4L2 interface by allowing VIDIOC_REQBUFS(0) to succeed when the queue is of type V4L2_MEMORY_MMAP, inline with the rest of the queue memory types.

author
#1 lore raw

PATCH 1/4 s5p-mfc: fix encoder crash after VIDIOC_STREAMOFF

VIDIOC_STREAMOFF clears the encoder's destination queue -- routines run from the interrupt handler cannot assume that the queue is non-empty.

---
 drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)
drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +11 -9
index df83cd15..04236229 100644
@@ -772,13 +772,16 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx)
 
 	if (p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) {
 		spin_lock_irqsave(&dev->irqlock, flags);
-		dst_mb = list_entry(ctx->dst_queue.next,
-				struct s5p_mfc_buf, list);
-		list_del(&dst_mb->list);
-		ctx->dst_queue_cnt--;
-		vb2_set_plane_payload(dst_mb->b, 0,
-			s5p_mfc_hw_call(dev->mfc_ops, get_enc_strm_size, dev));
-		vb2_buffer_done(dst_mb->b, VB2_BUF_STATE_DONE);
+		if (!list_empty(&ctx->dst_queue)) {
+			dst_mb = list_entry(ctx->dst_queue.next,
+					struct s5p_mfc_buf, list);
+			list_del(&dst_mb->list);
+			ctx->dst_queue_cnt--;
+			vb2_set_plane_payload(dst_mb->b, 0,
+				s5p_mfc_hw_call(dev->mfc_ops, get_enc_strm_size,
+						dev));
+			vb2_buffer_done(dst_mb->b, VB2_BUF_STATE_DONE);
+		}
 		spin_unlock_irqrestore(&dev->irqlock, flags);
 	}
 
@@ -883,8 +886,7 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
 		mfc_debug(2, "enc src count: %d, enc ref count: %d\n",
 			  ctx->src_queue_cnt, ctx->ref_queue_cnt);
 	}
-	if (strm_size > 0) {
-		/* at least one more dest. buffers exist always  */
+	if ((ctx->dst_queue_cnt > 0) && (strm_size > 0)) {
 		mb_entry = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf,
 									list);
 		list_del(&mb_entry->list);
Signature · 1 line
1.9.0.279.gdc9e3eb
author
#2 lore raw

PATCH 2/4 CHROMIUM: s5p-mfc: support dynamic encoding parameter changes

In reply to John Sheu

Add support for dynamic encoding parameter changes in MFCv6. Parameters set are applied with the next OUTPUT buffer queued to the device with VIDIOC_QBUF.

Supported parameters are:

* GOP size (V4L2_CID_MPEG_VIDEO_GOP_SIZE)
* framerate (from VIDIOC_S_PARM)
* VBR target bitrate (V4L2_CID_MPEG_VIDEO_BITRATE)
* (h264) frame type (V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE)

---
 drivers/media/platform/s5p-mfc/regs-mfc-v6.h    |  4 ++
 drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 31 ++++++--
 drivers/media/platform/s5p-mfc/s5p_mfc_enc.c    | 53 +++++++++++---
 drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 29 ++++----
 drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 94 ++++++++++++++-----------
 5 files changed, 140 insertions(+), 71 deletions(-)
drivers/media/platform/s5p-mfc/regs-mfc-v6.h +4 -0
index 8d0b686d..68128073 100644
@@ -331,6 +331,10 @@
 #define S5P_FIMV_E_MVC_RC_RPARA_VIEW1_V6		0xfd50
 #define S5P_FIMV_E_MVC_INTER_VIEW_PREDICTION_ON_V6	0xfd80
 
+#define S5P_FIMV_E_GOP_CONFIG_CHANGE_SHIFT_V6		0
+#define S5P_FIMV_E_FRAME_RATE_CHANGE_SHIFT_V6		1
+#define S5P_FIMV_E_BIT_RATE_CHANGE_SHIFT_V6		2
+
 /* Codec numbers  */
 #define S5P_FIMV_CODEC_NONE_V6		-1
 
drivers/media/platform/s5p-mfc/s5p_mfc_common.h +25 -6
index 5c28cc3e..90b66d2b 100644
@@ -164,12 +164,35 @@ enum s5p_mfc_decode_arg {
 	MFC_DEC_RES_CHANGE,
 };
 
+
+/**
+ * enum s5p_mfc_encoder_param_change - indicates runtime parameter change
+ */
+enum s5p_mfc_encode_param_change {
+	MFC_ENC_GOP_CONFIG_CHANGE,
+	MFC_ENC_FRAME_RATE_CHANGE,
+	MFC_ENC_BIT_RATE_CHANGE,
+	MFC_ENC_FRAME_INSERTION,
+};
+
 #define MFC_BUF_FLAG_USED	(1 << 0)
 #define MFC_BUF_FLAG_EOS	(1 << 1)
 
 struct s5p_mfc_ctx;
 
 /**
+ * struct s5p_mfc_enc_params - runtime modifiable encoding parameters
+ */
+struct s5p_mfc_runtime_enc_params {
+	u32 params_changed;
+	u16 gop_size;
+	u32 rc_framerate_num;
+	u32 rc_framerate_denom;
+	u32 rc_bitrate;
+	enum v4l2_mpeg_mfc51_video_force_frame_type force_frame_type;
+};
+
+/**
  * struct s5p_mfc_buf - MFC buffer
  */
 struct s5p_mfc_buf {
@@ -183,6 +206,7 @@ struct s5p_mfc_buf {
 		size_t stream;
 	} cookie;
 	int flags;
+	struct s5p_mfc_runtime_enc_params runtime_enc_params;
 };
 
 /**
@@ -429,7 +453,6 @@ struct s5p_mfc_enc_params {
 	u32 mv_h_range;
 	u32 mv_v_range;
 
-	u16 gop_size;
 	enum v4l2_mpeg_video_multi_slice_mode slice_mode;
 	u16 slice_mb;
 	u32 slice_bit;
@@ -440,7 +463,6 @@ struct s5p_mfc_enc_params {
 	u8 pad_cr;
 	int rc_frame;
 	int rc_mb;
-	u32 rc_bitrate;
 	u16 rc_reaction_coeff;
 	u16 vbv_size;
 	u32 vbv_delay;
@@ -450,10 +472,9 @@ struct s5p_mfc_enc_params {
 	int fixed_target_bit;
 
 	u8 num_b_frame;
-	u32 rc_framerate_num;
-	u32 rc_framerate_denom;
 
 	struct {
+		struct s5p_mfc_runtime_enc_params runtime;
 		struct s5p_mfc_h264_enc_params h264;
 		struct s5p_mfc_mpeg4_enc_params mpeg4;
 		struct s5p_mfc_vp8_enc_params vp8;
@@ -634,8 +655,6 @@ struct s5p_mfc_ctx {
 	size_t me_buffer_size;
 	size_t tmv_buffer_size;
 
-	enum v4l2_mpeg_mfc51_video_force_frame_type force_frame_type;
-
 	struct list_head ref_queue;
 	unsigned int ref_queue_cnt;
 
drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +44 -9

92 lines not on this page · raw message

drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +16 -13
index 58ec7bb2..45646729 100644
@@ -688,7 +688,7 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
 	reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL);
 	reg |= (1 << 18);
 	reg &= ~(0xFFFF);
-	reg |= p->gop_size;
+	reg |= p->codec.runtime.gop_size;
 	mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL);
 	mfc_write(dev, 0, S5P_FIMV_ENC_B_RECON_WRITE_ON);
 	/* multi-slice control */
@@ -736,7 +736,7 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
 	mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
 	/* bit rate */
 	if (p->rc_frame)
-		mfc_write(dev, p->rc_bitrate,
+		mfc_write(dev, p->codec.runtime.rc_bitrate,
 			S5P_FIMV_ENC_RC_BIT_RATE);
 	else
 		mfc_write(dev, 0, S5P_FIMV_ENC_RC_BIT_RATE);
@@ -831,9 +831,10 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
 	reg |= p_264->rc_frame_qp;
 	mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
 	/* frame rate */
-	if (p->rc_frame && p->rc_framerate_denom)
-		mfc_write(dev, p->rc_framerate_num * 1000
-			/ p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE);
+	if (p->rc_frame && p->codec.runtime.rc_framerate_denom)
+		mfc_write(dev, p->codec.runtime.rc_framerate_num * 1000
+			/ p->codec.runtime.rc_framerate_denom,
+			S5P_FIMV_ENC_RC_FRAME_RATE);
 	else
 		mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE);
 	/* max & min value of QP */
@@ -950,16 +951,17 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
 	}
 	/* frame rate */
 	if (p->rc_frame) {
-		if (p->rc_framerate_denom > 0) {
-			framerate = p->rc_framerate_num * 1000 /
-						p->rc_framerate_denom;
+		if (p->codec.runtime.rc_framerate_denom > 0) {
+			framerate = p->codec.runtime.rc_framerate_num * 1000 /
+				p->codec.runtime.rc_framerate_denom;
 			mfc_write(dev, framerate,
 				S5P_FIMV_ENC_RC_FRAME_RATE);
 			shm = s5p_mfc_read_info_v5(ctx, RC_VOP_TIMING);
 			shm &= ~(0xFFFFFFFF);
 			shm |= (1 << 31);
-			shm |= ((p->rc_framerate_num & 0x7FFF) << 16);
-			shm |= (p->rc_framerate_denom & 0xFFFF);
+			shm |= ((p->codec.runtime.rc_framerate_num & 0x7FFF)
+				<< 16);
+			shm |= (p->codec.runtime.rc_framerate_denom & 0xFFFF);
 			s5p_mfc_write_info_v5(ctx, shm, RC_VOP_TIMING);
 		}
 	} else {
@@ -1009,9 +1011,10 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
 		s5p_mfc_write_info_v5(ctx, shm, P_B_FRAME_QP);
 	}
 	/* frame rate */
-	if (p->rc_frame && p->rc_framerate_denom)
-		mfc_write(dev, p->rc_framerate_num * 1000
-			/ p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE);
+	if (p->rc_frame && p->codec.runtime.rc_framerate_denom)
+		mfc_write(dev, p->codec.runtime.rc_framerate_num * 1000
+		/ p->codec.runtime.rc_framerate_denom,
+		S5P_FIMV_ENC_RC_FRAME_RATE);
 	else
 		mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE);
 	/* rate control config. */
drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +51 -43

142 lines not on this page · raw message

Signature · 1 line
1.9.0.279.gdc9e3eb
author
#3 lore raw

PATCH 3/4 gsc-m2m: report correct format bytesperline and sizeimage

In reply to John Sheu

Explicitly specify sampling period for subsampled chroma formats, so stride and image size are properly reported through VIDIOC_{S,G}_FMT.

---
 drivers/media/platform/exynos-gsc/gsc-core.c | 154 +++++++++++++++------------
 drivers/media/platform/exynos-gsc/gsc-core.h |  16 +--
 drivers/media/platform/exynos-gsc/gsc-regs.c |  40 +++----
 drivers/media/platform/exynos-gsc/gsc-regs.h |   4 +-
 4 files changed, 116 insertions(+), 98 deletions(-)
drivers/media/platform/exynos-gsc/gsc-core.c +84 -70
index 9d0cc04d..c02addef 100644
@@ -34,167 +34,185 @@ static const struct gsc_fmt gsc_formats[] = {
 	{
 		.name		= "RGB565",
 		.pixelformat	= V4L2_PIX_FMT_RGB565X,
-		.depth		= { 16 },
 		.color		= GSC_RGB,
 		.num_planes	= 1,
 		.num_comp	= 1,
+		.depth		= { 16 },
+		.sampling	= { { 1, 1 } },
 	}, {
 		.name		= "XRGB-8-8-8-8, 32 bpp",
 		.pixelformat	= V4L2_PIX_FMT_RGB32,
-		.depth		= { 32 },
 		.color		= GSC_RGB,
 		.num_planes	= 1,
 		.num_comp	= 1,
+		.depth		= { 32 },
+		.sampling	= { { 1, 1 } },
 	}, {
 		.name		= "YUV 4:2:2 packed, YCbYCr",
 		.pixelformat	= V4L2_PIX_FMT_YUYV,
-		.depth		= { 16 },
 		.color		= GSC_YUV422,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CBCR,
 		.num_planes	= 1,
 		.num_comp	= 1,
+		.depth		= { 16 },
+		.sampling	= { { 1, 1 } },
 		.mbus_code	= V4L2_MBUS_FMT_YUYV8_2X8,
 	}, {
 		.name		= "YUV 4:2:2 packed, CbYCrY",
 		.pixelformat	= V4L2_PIX_FMT_UYVY,
-		.depth		= { 16 },
 		.color		= GSC_YUV422,
 		.yorder		= GSC_LSB_C,
 		.corder		= GSC_CBCR,
 		.num_planes	= 1,
 		.num_comp	= 1,
+		.depth		= { 16 },
+		.sampling	= { { 1, 1 } },
 		.mbus_code	= V4L2_MBUS_FMT_UYVY8_2X8,
 	}, {
 		.name		= "YUV 4:2:2 packed, CrYCbY",
 		.pixelformat	= V4L2_PIX_FMT_VYUY,
-		.depth		= { 16 },
 		.color		= GSC_YUV422,
 		.yorder		= GSC_LSB_C,
 		.corder		= GSC_CRCB,
 		.num_planes	= 1,
 		.num_comp	= 1,
+		.depth		= { 16 },
+		.sampling	= { { 1, 1 } },
 		.mbus_code	= V4L2_MBUS_FMT_VYUY8_2X8,
 	}, {
 		.name		= "YUV 4:2:2 packed, YCrYCb",
 		.pixelformat	= V4L2_PIX_FMT_YVYU,
-		.depth		= { 16 },
 		.color		= GSC_YUV422,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CRCB,
 		.num_planes	= 1,
 		.num_comp	= 1,
+		.depth		= { 16 },
+		.sampling	= { { 1, 1 } },
 		.mbus_code	= V4L2_MBUS_FMT_YVYU8_2X8,
 	}, {
 		.name		= "YUV 4:4:4 planar, YCbYCr",
 		.pixelformat	= V4L2_PIX_FMT_YUV32,
-		.depth		= { 32 },
 		.color		= GSC_YUV444,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CBCR,
 		.num_planes	= 1,
 		.num_comp	= 1,
+		.depth		= { 32 },
+		.sampling	= { { 1, 1 } },
 	}, {
 		.name		= "YUV 4:2:2 planar, Y/Cb/Cr",
 		.pixelformat	= V4L2_PIX_FMT_YUV422P,
-		.depth		= { 16 },
 		.color		= GSC_YUV422,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CBCR,
 		.num_planes	= 1,
 		.num_comp	= 3,
+		.depth		= { 8, 8, 8 },
+		.sampling	= { { 1, 1 }, { 2, 1 }, { 2, 1 } },
 	}, {
 		.name		= "YUV 4:2:2 planar, Y/CbCr",
 		.pixelformat	= V4L2_PIX_FMT_NV16,
-		.depth		= { 16 },
 		.color		= GSC_YUV422,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CBCR,
 		.num_planes	= 1,
 		.num_comp	= 2,
+		.depth		= { 8, 16 },
+		.sampling	= { { 1, 1 }, { 2, 1 } },
 	}, {
 		.name		= "YUV 4:2:2 planar, Y/CrCb",
 		.pixelformat	= V4L2_PIX_FMT_NV61,
-		.depth		= { 16 },
 		.color		= GSC_YUV422,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CRCB,
 		.num_planes	= 1,
 		.num_comp	= 2,
+		.depth		= { 8, 16 },
+		.sampling	= { { 1, 1 }, { 2, 1 } },
 	}, {
 		.name		= "YUV 4:2:0 planar, YCbCr",
 		.pixelformat	= V4L2_PIX_FMT_YUV420,
-		.depth		= { 12 },
 		.color		= GSC_YUV420,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CBCR,
 		.num_planes	= 1,
 		.num_comp	= 3,
+		.depth		= { 8, 8, 8 },
+		.sampling	= { { 1, 1 }, { 2, 2 }, { 2, 2 } },
 	}, {
 		.name		= "YUV 4:2:0 planar, YCrCb",
 		.pixelformat	= V4L2_PIX_FMT_YVU420,
-		.depth		= { 12 },
 		.color		= GSC_YUV420,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CRCB,
 		.num_planes	= 1,
 		.num_comp	= 3,
-
+		.depth		= { 8, 8, 8 },
+		.sampling	= { { 1, 1 }, { 2, 2 }, { 2, 2 } },
 	}, {
 		.name		= "YUV 4:2:0 planar, Y/CbCr",
 		.pixelformat	= V4L2_PIX_FMT_NV12,
-		.depth		= { 12 },
 		.color		= GSC_YUV420,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CBCR,
 		.num_planes	= 1,
 		.num_comp	= 2,
+		.depth		= { 8, 16 },
+		.sampling	= { { 1, 1 }, { 2, 2 } },
 	}, {
 		.name		= "YUV 4:2:0 planar, Y/CrCb",
 		.pixelformat	= V4L2_PIX_FMT_NV21,
-		.depth		= { 12 },
 		.color		= GSC_YUV420,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CRCB,
 		.num_planes	= 1,
 		.num_comp	= 2,
+		.depth		= { 8, 16 },
+		.sampling	= { { 1, 1 }, { 2, 2 } },
 	}, {
-		.name		= "YUV 4:2:0 non-contig. 2p, Y/CbCr",
+		.name		= "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr",
 		.pixelformat	= V4L2_PIX_FMT_NV12M,
-		.depth		= { 8, 4 },
 		.color		= GSC_YUV420,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CBCR,
 		.num_planes	= 2,
 		.num_comp	= 2,
+		.depth		= { 8, 16 },
+		.sampling	= { { 1, 1 }, { 2, 2 } },
 	}, {
-		.name		= "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr",
+		.name		= "YUV 4:2:0 non-contiguous 3-planar, Y/Cb/Cr",
 		.pixelformat	= V4L2_PIX_FMT_YUV420M,
-		.depth		= { 8, 2, 2 },
 		.color		= GSC_YUV420,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CBCR,
 		.num_planes	= 3,
 		.num_comp	= 3,
+		.depth		= { 8, 8, 8 },
+		.sampling	= { { 1, 1 }, { 2, 2 }, { 2, 2 } },
 	}, {
-		.name		= "YUV 4:2:0 non-contig. 3p, Y/Cr/Cb",
+		.name		= "YUV 4:2:0 non-contiguous 3-planar, Y/Cr/Cb",
 		.pixelformat	= V4L2_PIX_FMT_YVU420M,
-		.depth		= { 8, 2, 2 },
 		.color		= GSC_YUV420,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CRCB,
 		.num_planes	= 3,
 		.num_comp	= 3,
+		.depth		= { 8, 8, 8 },
+		.sampling	= { { 1, 1 }, { 2, 2 }, { 2, 2 } },
 	}, {
-		.name		= "YUV 4:2:0 n.c. 2p, Y/CbCr tiled",
+		.name		=
+			"YUV 4:2:0 non-contiguous 2-planar, Y/CbCr, tiled",
 		.pixelformat	= V4L2_PIX_FMT_NV12MT_16X16,
-		.depth		= { 8, 4 },
 		.color		= GSC_YUV420,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CBCR,
 		.num_planes	= 2,
 		.num_comp	= 2,
-	}
+		.depth		= { 8, 16 },
+		.sampling	= { { 1, 1 }, { 2, 2 } },
+	},
 };
 
 const struct gsc_fmt *get_format(int index)
@@ -384,6 +402,14 @@ void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame *frm)
 			f_chk_addr, f_chk_len, s_chk_addr, s_chk_len);
 }
 
+static void get_format_size(__u32 width, __u32 height,
+			    const struct gsc_fmt *fmt, int plane,
+			    __u16 *bytesperline, __u32 *sizeimage) {
+	__u16 bpl = ((width * fmt->depth[plane]) / fmt->sampling[plane][0]) / 8;
+	*bytesperline = bpl;
+	*sizeimage = (height * bpl) / fmt->sampling[plane][0];
+}
+
 int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)
 {
 	struct gsc_dev *gsc = ctx->gsc_dev;
@@ -448,14 +474,16 @@ int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)
 	else /* SD */
 		pix_mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
 
-
+	/* V4L2 specifies for contiguous planar formats that bytesperline and
+	   sizeimage are set to values appropriate for the first plane. */
 	for (i = 0; i < pix_mp->num_planes; ++i) {
-		int bpl = (pix_mp->width * fmt->depth[i]) >> 3;
-		pix_mp->plane_fmt[i].bytesperline = bpl;
-		pix_mp->plane_fmt[i].sizeimage = bpl * pix_mp->height;
+		get_format_size(pix_mp->width, pix_mp->height, fmt, i,
+				&pix_mp->plane_fmt[i].bytesperline,
+				&pix_mp->plane_fmt[i].sizeimage);
 
 		pr_debug("[%d]: bpl: %d, sizeimage: %d",
-				i, bpl, pix_mp->plane_fmt[i].sizeimage);
+				i, pix_mp->plane_fmt[i].bytesperline,
+				pix_mp->plane_fmt[i].sizeimage);
 	}
 
 	return 0;
@@ -465,26 +493,27 @@ int gsc_g_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)
 {
 	struct gsc_frame *frame;
 	struct v4l2_pix_format_mplane *pix_mp;
+	const struct gsc_fmt *fmt;
 	int i;
 
 	frame = ctx_get_frame(ctx, f->type);
 	if (IS_ERR(frame))
 		return PTR_ERR(frame);
+	fmt = frame->fmt;
 
 	pix_mp = &f->fmt.pix_mp;
 
 	pix_mp->width		= frame->f_width;
 	pix_mp->height		= frame->f_height;
 	pix_mp->field		= V4L2_FIELD_NONE;
-	pix_mp->pixelformat	= frame->fmt->pixelformat;
+	pix_mp->pixelformat	= fmt->pixelformat;
 	pix_mp->colorspace	= V4L2_COLORSPACE_REC709;
-	pix_mp->num_planes	= frame->fmt->num_planes;
+	pix_mp->num_planes	= fmt->num_planes;
 
 	for (i = 0; i < pix_mp->num_planes; ++i) {
-		pix_mp->plane_fmt[i].bytesperline = (frame->f_width *
-			frame->fmt->depth[i]) / 8;
-		pix_mp->plane_fmt[i].sizeimage =
-			 pix_mp->plane_fmt[i].bytesperline * frame->f_height;
+		get_format_size(pix_mp->width, pix_mp->height, fmt, i,
+				&pix_mp->plane_fmt[i].bytesperline,
+				&pix_mp->plane_fmt[i].sizeimage);
 	}
 
 	return 0;
@@ -794,11 +823,12 @@ void gsc_ctrls_delete(struct gsc_ctx *ctx)
 	}
 }
 
-/* The color format (num_comp, num_planes) must be already configured. */
+/* The color format (num_planes, num_comp) must be already configured. */
 int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb,
 			struct gsc_frame *frame, struct gsc_addr *addr)
 {
 	int ret = 0;
+	const struct gsc_fmt *fmt = frame->fmt;
 	u32 pix_size;
 
 	if ((vb == NULL) || (frame == NULL))
@@ -810,46 +840,30 @@ int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb,
 		frame->fmt->num_planes, frame->fmt->num_comp, pix_size);
 
 	addr->y = vb2_dma_contig_plane_dma_addr(vb, 0);
-
-	if (frame->fmt->num_planes == 1) {
-		switch (frame->fmt->num_comp) {
-		case 1:
-			addr->cb = 0;
-			addr->cr = 0;
-			break;
-		case 2:
-			/* decompose Y into Y/Cb */
-			addr->cb = (dma_addr_t)(addr->y + pix_size);
-			addr->cr = 0;
-			break;
-		case 3:
-			/* decompose Y into Y/Cb/Cr */
-			addr->cb = (dma_addr_t)(addr->y + pix_size);
-			if (GSC_YUV420 == frame->fmt->color)
-				addr->cr = (dma_addr_t)(addr->cb
-						+ (pix_size >> 2));
-			else /* 422 */
-				addr->cr = (dma_addr_t)(addr->cb
-						+ (pix_size >> 1));
-			break;
-		default:
-			pr_err("Invalid the number of color planes");
-			return -EINVAL;
+	addr->cb = 0;
+	addr->cr = 0;
+
+	if (fmt->num_planes == 1) {
+		if (fmt->num_comp >= 2) {
+			addr->cb = (dma_addr_t)(addr->y +
+				((pix_size * fmt->depth[0]) /
+				(fmt->sampling[0][0] *
+				 fmt->sampling[0][1]) / 8));
+		}
+		if (fmt->num_comp >= 3) {
+			addr->cr = (dma_addr_t)(addr->cb +
+				((pix_size * fmt->depth[1]) /
+				(fmt->sampling[1][0] *
+				 fmt->sampling[1][1]) / 8));
 		}
 	} else {
-		if (frame->fmt->num_planes >= 2)
+		if (fmt->num_comp >= 2)
 			addr->cb = vb2_dma_contig_plane_dma_addr(vb, 1);
-
-		if (frame->fmt->num_planes == 3)
+		if (fmt->num_comp == 3)
 			addr->cr = vb2_dma_contig_plane_dma_addr(vb, 2);
 	}
 
-	if ((frame->fmt->pixelformat == V4L2_PIX_FMT_VYUY) ||
-		(frame->fmt->pixelformat == V4L2_PIX_FMT_YVYU) ||
-		(frame->fmt->pixelformat == V4L2_PIX_FMT_NV61) ||
-		(frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420) ||
-		(frame->fmt->pixelformat == V4L2_PIX_FMT_NV21) ||
-		(frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420M))
+	if (fmt->corder == GSC_CRCB)
 		swap(addr->cb, addr->cr);
 
 	pr_debug("ADDR: y= 0x%X  cb= 0x%X cr= 0x%X ret= %d",
drivers/media/platform/exynos-gsc/gsc-core.h +8 -8
index ef0a6564..8fb07e0d 100644
@@ -106,27 +106,27 @@ enum gsc_yuv_fmt {
 	container_of((__ctrl)->handler, struct gsc_ctx, ctrl_handler)
 /**
  * struct gsc_fmt - the driver's internal color format data
- * @mbus_code: Media Bus pixel code, -1 if not applicable
  * @name: format description
  * @pixelformat: the fourcc code for this format, 0 if not applicable
  * @yorder: Y/C order
  * @corder: Chrominance order control
  * @num_planes: number of physically non-contiguous data planes
- * @nr_comp: number of physically contiguous data planes
- * @depth: per plane driver's private 'number of bits per pixel'
- * @flags: flags indicating which operation mode format applies to
+ * @num_comp: number of physically contiguous data planes
+ * @depth: bit depth of each component
+ * @sampling: sampling frequency of each components, X and Y
+ * @mbus_code: Media Bus pixel code, -1 if not applicable
  */
 struct gsc_fmt {
-	enum v4l2_mbus_pixelcode mbus_code;
 	char	*name;
 	u32	pixelformat;
 	u32	color;
 	u32	yorder;
 	u32	corder;
-	u16	num_planes;
-	u16	num_comp;
+	u8	num_planes;
+	u8	num_comp;
 	u8	depth[VIDEO_MAX_PLANES];
-	u32	flags;
+	u8	sampling[VIDEO_MAX_PLANES][2];
+	enum v4l2_mbus_pixelcode mbus_code;
 };
 
 /**
drivers/media/platform/exynos-gsc/gsc-regs.c +22 -18
index e22d147a..a8d6c90b 100644
@@ -167,6 +167,7 @@ void gsc_hw_set_in_image_format(struct gsc_ctx *ctx)
 {
 	struct gsc_dev *dev = ctx->gsc_dev;
 	struct gsc_frame *frame = &ctx->s_frame;
+	const struct gsc_fmt *fmt = frame->fmt;
 	u32 i, depth = 0;
 	u32 cfg;
 
@@ -176,21 +177,22 @@ void gsc_hw_set_in_image_format(struct gsc_ctx *ctx)
 		 GSC_IN_TILE_TYPE_MASK | GSC_IN_TILE_MODE);
 	writel(cfg, dev->regs + GSC_IN_CON);
 
-	if (is_rgb(frame->fmt->color)) {
+	if (is_rgb(fmt->color)) {
 		gsc_hw_set_in_image_rgb(ctx);
 		return;
 	}
-	for (i = 0; i < frame->fmt->num_planes; i++)
-		depth += frame->fmt->depth[i];
+	for (i = 0; i < fmt->num_comp; i++)
+		depth += fmt->depth[i] /
+			(fmt->sampling[i][0] * fmt->sampling[i][1]);
 
-	switch (frame->fmt->num_comp) {
+	switch (fmt->num_comp) {
 	case 1:
 		cfg |= GSC_IN_YUV422_1P;
-		if (frame->fmt->yorder == GSC_LSB_Y)
+		if (fmt->yorder == GSC_LSB_Y)
 			cfg |= GSC_IN_YUV422_1P_ORDER_LSB_Y;
 		else
-			cfg |= GSC_IN_YUV422_1P_OEDER_LSB_C;
-		if (frame->fmt->corder == GSC_CBCR)
+			cfg |= GSC_IN_YUV422_1P_ORDER_LSB_C;
+		if (fmt->corder == GSC_CBCR)
 			cfg |= GSC_IN_CHROMA_ORDER_CBCR;
 		else
 			cfg |= GSC_IN_CHROMA_ORDER_CRCB;
@@ -200,7 +202,7 @@ void gsc_hw_set_in_image_format(struct gsc_ctx *ctx)
 			cfg |= GSC_IN_YUV420_2P;
 		else
 			cfg |= GSC_IN_YUV422_2P;
-		if (frame->fmt->corder == GSC_CBCR)
+		if (fmt->corder == GSC_CBCR)
 			cfg |= GSC_IN_CHROMA_ORDER_CBCR;
 		else
 			cfg |= GSC_IN_CHROMA_ORDER_CRCB;
@@ -213,7 +215,7 @@ void gsc_hw_set_in_image_format(struct gsc_ctx *ctx)
 		break;
 	}
 
-	if (is_tiled(frame->fmt))
+	if (is_tiled(fmt))
 		cfg |= GSC_IN_TILE_C_16x8 | GSC_IN_TILE_MODE;
 
 	writel(cfg, dev->regs + GSC_IN_CON);
@@ -287,6 +289,7 @@ void gsc_hw_set_out_image_format(struct gsc_ctx *ctx)
 {
 	struct gsc_dev *dev = ctx->gsc_dev;
 	struct gsc_frame *frame = &ctx->d_frame;
+	const struct gsc_fmt *fmt = frame->fmt;
 	u32 i, depth = 0;
 	u32 cfg;
 
@@ -296,7 +299,7 @@ void gsc_hw_set_out_image_format(struct gsc_ctx *ctx)
 		 GSC_OUT_TILE_TYPE_MASK | GSC_OUT_TILE_MODE);
 	writel(cfg, dev->regs + GSC_OUT_CON);
 
-	if (is_rgb(frame->fmt->color)) {
+	if (is_rgb(fmt->color)) {
 		gsc_hw_set_out_image_rgb(ctx);
 		return;
 	}
@@ -306,17 +309,18 @@ void gsc_hw_set_out_image_format(struct gsc_ctx *ctx)
 		goto end_set;
 	}
 
-	for (i = 0; i < frame->fmt->num_planes; i++)
-		depth += frame->fmt->depth[i];
+	for (i = 0; i < fmt->num_comp; i++)
+		depth += fmt->depth[i] /
+			(fmt->sampling[i][0] * fmt->sampling[i][1]);
 
-	switch (frame->fmt->num_comp) {
+	switch (fmt->num_comp) {
 	case 1:
 		cfg |= GSC_OUT_YUV422_1P;
-		if (frame->fmt->yorder == GSC_LSB_Y)
+		if (fmt->yorder == GSC_LSB_Y)
 			cfg |= GSC_OUT_YUV422_1P_ORDER_LSB_Y;
 		else
-			cfg |= GSC_OUT_YUV422_1P_OEDER_LSB_C;
-		if (frame->fmt->corder == GSC_CBCR)
+			cfg |= GSC_OUT_YUV422_1P_ORDER_LSB_C;
+		if (fmt->corder == GSC_CBCR)
 			cfg |= GSC_OUT_CHROMA_ORDER_CBCR;
 		else
 			cfg |= GSC_OUT_CHROMA_ORDER_CRCB;
@@ -326,7 +330,7 @@ void gsc_hw_set_out_image_format(struct gsc_ctx *ctx)
 			cfg |= GSC_OUT_YUV420_2P;
 		else
 			cfg |= GSC_OUT_YUV422_2P;
-		if (frame->fmt->corder == GSC_CBCR)
+		if (fmt->corder == GSC_CBCR)
 			cfg |= GSC_OUT_CHROMA_ORDER_CBCR;
 		else
 			cfg |= GSC_OUT_CHROMA_ORDER_CRCB;
@@ -336,7 +340,7 @@ void gsc_hw_set_out_image_format(struct gsc_ctx *ctx)
 		break;
 	}
 
-	if (is_tiled(frame->fmt))
+	if (is_tiled(fmt))
 		cfg |= GSC_OUT_TILE_C_16x8 | GSC_OUT_TILE_MODE;
 
 end_set:
drivers/media/platform/exynos-gsc/gsc-regs.h +2 -2
index 4678f9a6..b03401dc 100644
@@ -46,7 +46,7 @@
 #define GSC_IN_RGB_SD_WIDE		(0 << 14)
 #define GSC_IN_YUV422_1P_ORDER_MASK	(1 << 13)
 #define GSC_IN_YUV422_1P_ORDER_LSB_Y	(0 << 13)
-#define GSC_IN_YUV422_1P_OEDER_LSB_C	(1 << 13)
+#define GSC_IN_YUV422_1P_ORDER_LSB_C	(1 << 13)
 #define GSC_IN_CHROMA_ORDER_MASK	(1 << 12)
 #define GSC_IN_CHROMA_ORDER_CBCR	(0 << 12)
 #define GSC_IN_CHROMA_ORDER_CRCB	(1 << 12)
@@ -91,7 +91,7 @@
 #define GSC_OUT_RGB_SD_NARROW		(0 << 10)
 #define GSC_OUT_YUV422_1P_ORDER_MASK	(1 << 9)
 #define GSC_OUT_YUV422_1P_ORDER_LSB_Y	(0 << 9)
-#define GSC_OUT_YUV422_1P_OEDER_LSB_C	(1 << 9)
+#define GSC_OUT_YUV422_1P_ORDER_LSB_C	(1 << 9)
 #define GSC_OUT_CHROMA_ORDER_MASK	(1 << 8)
 #define GSC_OUT_CHROMA_ORDER_CBCR	(0 << 8)
 #define GSC_OUT_CHROMA_ORDER_CRCB	(1 << 8)
Signature · 1 line
1.9.0.279.gdc9e3eb
#4 lore raw

RE: [PATCH 3/4] gsc-m2m: report correct format bytesperline and sizeimage

Hi Shaik, Sungchun,

Exynos-gsc has no maintainers mentioned in the MAINTAINERS file. I see your activity in the development of this driver. Do you have any comments on this patch?

Best wishes,

Signature · 2 lines
Kamil Debski
Samsung R&D Institute Poland
Quoted 174 lines

-----Original Message-----
From: John Sheu [mailto:[email protected]]
Sent: Tuesday, March 11, 2014 11:52 PM
To: [email protected]
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; John Sheu
Subject: [PATCH 3/4] gsc-m2m: report correct format bytesperline and sizeimage

Explicitly specify sampling period for subsampled chroma formats, so stride and image size are properly reported through VIDIOC_{S,G}_FMT.

---
 drivers/media/platform/exynos-gsc/gsc-core.c | 154 +++++++++++++++----
--------  drivers/media/platform/exynos-gsc/gsc-core.h |  16 +--
drivers/media/platform/exynos-gsc/gsc-regs.c |  40 +++----
 drivers/media/platform/exynos-gsc/gsc-regs.h |   4 +-
 4 files changed, 116 insertions(+), 98 deletions(-)
drivers/media/platform/exynos-gsc/gsc-core.c +26 -15
index 9d0cc04d..c02addef 100644
@@ -34,167 +34,185 @@ static const struct gsc_fmt gsc_formats[] = {
 	{
 		.name		= "RGB565",
 		.pixelformat	= V4L2_PIX_FMT_RGB565X,
-		.depth		= { 16 },
 		.color		= GSC_RGB,
 		.num_planes	= 1,
 		.num_comp	= 1,
+		.depth		= { 16 },
+		.sampling	= { { 1, 1 } },
 	}, {
 		.name		= "XRGB-8-8-8-8, 32 bpp",
 		.pixelformat	= V4L2_PIX_FMT_RGB32,
-		.depth		= { 32 },
 		.color		= GSC_RGB,
 		.num_planes	= 1,
 		.num_comp	= 1,
+		.depth		= { 32 },
+		.sampling	= { { 1, 1 } },
 	}, {
 		.name		= "YUV 4:2:2 packed, YCbYCr",
 		.pixelformat	= V4L2_PIX_FMT_YUYV,
-		.depth		= { 16 },
 		.color		= GSC_YUV422,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CBCR,
 		.num_planes	= 1,
 		.num_comp	= 1,
+		.depth		= { 16 },
+		.sampling	= { { 1, 1 } },
 		.mbus_code	= V4L2_MBUS_FMT_YUYV8_2X8,
 	}, {
 		.name		= "YUV 4:2:2 packed, CbYCrY",
 		.pixelformat	= V4L2_PIX_FMT_UYVY,
-		.depth		= { 16 },
 		.color		= GSC_YUV422,
 		.yorder		= GSC_LSB_C,
 		.corder		= GSC_CBCR,
 		.num_planes	= 1,
 		.num_comp	= 1,
+		.depth		= { 16 },
+		.sampling	= { { 1, 1 } },
 		.mbus_code	= V4L2_MBUS_FMT_UYVY8_2X8,
 	}, {
 		.name		= "YUV 4:2:2 packed, CrYCbY",
 		.pixelformat	= V4L2_PIX_FMT_VYUY,
-		.depth		= { 16 },
 		.color		= GSC_YUV422,
 		.yorder		= GSC_LSB_C,
 		.corder		= GSC_CRCB,
 		.num_planes	= 1,
 		.num_comp	= 1,
+		.depth		= { 16 },
+		.sampling	= { { 1, 1 } },
 		.mbus_code	= V4L2_MBUS_FMT_VYUY8_2X8,
 	}, {
 		.name		= "YUV 4:2:2 packed, YCrYCb",
 		.pixelformat	= V4L2_PIX_FMT_YVYU,
-		.depth		= { 16 },
 		.color		= GSC_YUV422,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CRCB,
 		.num_planes	= 1,
 		.num_comp	= 1,
+		.depth		= { 16 },
+		.sampling	= { { 1, 1 } },
 		.mbus_code	= V4L2_MBUS_FMT_YVYU8_2X8,
 	}, {
 		.name		= "YUV 4:4:4 planar, YCbYCr",
 		.pixelformat	= V4L2_PIX_FMT_YUV32,
-		.depth		= { 32 },
 		.color		= GSC_YUV444,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CBCR,
 		.num_planes	= 1,
 		.num_comp	= 1,
+		.depth		= { 32 },
+		.sampling	= { { 1, 1 } },
 	}, {
 		.name		= "YUV 4:2:2 planar, Y/Cb/Cr",
 		.pixelformat	= V4L2_PIX_FMT_YUV422P,
-		.depth		= { 16 },
 		.color		= GSC_YUV422,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CBCR,
 		.num_planes	= 1,
 		.num_comp	= 3,
+		.depth		= { 8, 8, 8 },
+		.sampling	= { { 1, 1 }, { 2, 1 }, { 2, 1 } },
 	}, {
 		.name		= "YUV 4:2:2 planar, Y/CbCr",
 		.pixelformat	= V4L2_PIX_FMT_NV16,
-		.depth		= { 16 },
 		.color		= GSC_YUV422,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CBCR,
 		.num_planes	= 1,
 		.num_comp	= 2,
+		.depth		= { 8, 16 },
+		.sampling	= { { 1, 1 }, { 2, 1 } },
 	}, {
 		.name		= "YUV 4:2:2 planar, Y/CrCb",
 		.pixelformat	= V4L2_PIX_FMT_NV61,
-		.depth		= { 16 },
 		.color		= GSC_YUV422,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CRCB,
 		.num_planes	= 1,
 		.num_comp	= 2,
+		.depth		= { 8, 16 },
+		.sampling	= { { 1, 1 }, { 2, 1 } },
 	}, {
 		.name		= "YUV 4:2:0 planar, YCbCr",
 		.pixelformat	= V4L2_PIX_FMT_YUV420,
-		.depth		= { 12 },
 		.color		= GSC_YUV420,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CBCR,
 		.num_planes	= 1,
 		.num_comp	= 3,
+		.depth		= { 8, 8, 8 },
+		.sampling	= { { 1, 1 }, { 2, 2 }, { 2, 2 } },
 	}, {
 		.name		= "YUV 4:2:0 planar, YCrCb",
 		.pixelformat	= V4L2_PIX_FMT_YVU420,
-		.depth		= { 12 },
 		.color		= GSC_YUV420,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CRCB,
 		.num_planes	= 1,
 		.num_comp	= 3,
-
+		.depth		= { 8, 8, 8 },
+		.sampling	= { { 1, 1 }, { 2, 2 }, { 2, 2 } },
 	}, {
 		.name		= "YUV 4:2:0 planar, Y/CbCr",
 		.pixelformat	= V4L2_PIX_FMT_NV12,
-		.depth		= { 12 },
 		.color		= GSC_YUV420,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CBCR,
 		.num_planes	= 1,
 		.num_comp	= 2,
+		.depth		= { 8, 16 },
+		.sampling	= { { 1, 1 }, { 2, 2 } },
 	}, {
 		.name		= "YUV 4:2:0 planar, Y/CrCb",
 		.pixelformat	= V4L2_PIX_FMT_NV21,
-		.depth		= { 12 },

drivers/media/platform/exynos-gsc/gsc-core.c static const struct gsc_fmt gsc_formats[] = { · line 175

Quoted 10 lines
drivers/media/platform/exynos-gsc/gsc-core.c +3 -1
 		.color		= GSC_YUV420,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CRCB,
 		.num_planes	= 1,
 		.num_comp	= 2,
+		.depth		= { 8, 16 },
+		.sampling	= { { 1, 1 }, { 2, 2 } },
 	}, {
-		.name		= "YUV 4:2:0 non-contig. 2p, Y/CbCr",
+		.name		= "YUV 4:2:0 non-contiguous 2-planar,

Y/CbCr",

drivers/media/platform/exynos-gsc/gsc-core.c static const struct gsc_fmt gsc_formats[] = {

Quoted 12 lines
drivers/media/platform/exynos-gsc/gsc-core.c +3 -2
 		.pixelformat	= V4L2_PIX_FMT_NV12M,
-		.depth		= { 8, 4 },
 		.color		= GSC_YUV420,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CBCR,
 		.num_planes	= 2,
 		.num_comp	= 2,
+		.depth		= { 8, 16 },
+		.sampling	= { { 1, 1 }, { 2, 2 } },
 	}, {
-		.name		= "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr",
+		.name		= "YUV 4:2:0 non-contiguous 3-planar,

Y/Cb/Cr",

drivers/media/platform/exynos-gsc/gsc-core.c static const struct gsc_fmt gsc_formats[] = {

Quoted 12 lines
drivers/media/platform/exynos-gsc/gsc-core.c +3 -2
 		.pixelformat	= V4L2_PIX_FMT_YUV420M,
-		.depth		= { 8, 2, 2 },
 		.color		= GSC_YUV420,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CBCR,
 		.num_planes	= 3,
 		.num_comp	= 3,
+		.depth		= { 8, 8, 8 },
+		.sampling	= { { 1, 1 }, { 2, 2 }, { 2, 2 } },
 	}, {
-		.name		= "YUV 4:2:0 non-contig. 3p, Y/Cr/Cb",
+		.name		= "YUV 4:2:0 non-contiguous 3-planar,

Y/Cr/Cb",

Quoted 375 lines
drivers/media/platform/exynos-gsc/gsc-core.c +7 -4
 		.pixelformat	= V4L2_PIX_FMT_YVU420M,
-		.depth		= { 8, 2, 2 },
 		.color		= GSC_YUV420,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CRCB,
 		.num_planes	= 3,
 		.num_comp	= 3,
+		.depth		= { 8, 8, 8 },
+		.sampling	= { { 1, 1 }, { 2, 2 }, { 2, 2 } },
 	}, {
-		.name		= "YUV 4:2:0 n.c. 2p, Y/CbCr tiled",
+		.name		=
+			"YUV 4:2:0 non-contiguous 2-planar, Y/CbCr, tiled",
 		.pixelformat	= V4L2_PIX_FMT_NV12MT_16X16,
-		.depth		= { 8, 4 },
 		.color		= GSC_YUV420,
 		.yorder		= GSC_LSB_Y,
 		.corder		= GSC_CBCR,
 		.num_planes	= 2,
 		.num_comp	= 2,
-	}
+		.depth		= { 8, 16 },
+		.sampling	= { { 1, 1 }, { 2, 2 } },
+	},
 };
 
 const struct gsc_fmt *get_format(int index) @@ -384,6 +402,14 @@ void

gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame *frm)

drivers/media/platform/exynos-gsc/gsc-core.c +4 -0
 			f_chk_addr, f_chk_len, s_chk_addr, s_chk_len);  }
 
+static void get_format_size(__u32 width, __u32 height,
+			    const struct gsc_fmt *fmt, int plane,
+			    __u16 *bytesperline, __u32 *sizeimage) {
+	__u16 bpl = ((width * fmt->depth[plane]) / fmt-
Quoted 1 line

sampling[plane][0]) / 8;

drivers/media/platform/exynos-gsc/gsc-core.c +4 -1
+	*bytesperline = bpl;
+	*sizeimage = (height * bpl) / fmt->sampling[plane][0]; }
+
 int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)  {
 	struct gsc_dev *gsc = ctx->gsc_dev;
@@ -448,14 +474,16 @@ int gsc_try_fmt_mplane(struct gsc_ctx *ctx,
 struct v4l2_format *f)
 	else /* SD */
 		pix_mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
 
-
+	/* V4L2 specifies for contiguous planar formats that bytesperline

and

drivers/media/platform/exynos-gsc/gsc-core.c +1 -0
+	   sizeimage are set to values appropriate for the first plane.

*/

drivers/media/platform/exynos-gsc/gsc-core.c +12 -10
 	for (i = 0; i < pix_mp->num_planes; ++i) {
-		int bpl = (pix_mp->width * fmt->depth[i]) >> 3;
-		pix_mp->plane_fmt[i].bytesperline = bpl;
-		pix_mp->plane_fmt[i].sizeimage = bpl * pix_mp->height;
+		get_format_size(pix_mp->width, pix_mp->height, fmt, i,
+				&pix_mp->plane_fmt[i].bytesperline,
+				&pix_mp->plane_fmt[i].sizeimage);
 
 		pr_debug("[%d]: bpl: %d, sizeimage: %d",
-				i, bpl, pix_mp->plane_fmt[i].sizeimage);
+				i, pix_mp->plane_fmt[i].bytesperline,
+				pix_mp->plane_fmt[i].sizeimage);
 	}
 
 	return 0;
@@ -465,26 +493,27 @@ int gsc_g_fmt_mplane(struct gsc_ctx *ctx, struct
 v4l2_format *f)  {
 	struct gsc_frame *frame;
 	struct v4l2_pix_format_mplane *pix_mp;
+	const struct gsc_fmt *fmt;
 	int i;
 
 	frame = ctx_get_frame(ctx, f->type);
 	if (IS_ERR(frame))
 		return PTR_ERR(frame);
+	fmt = frame->fmt;
 
 	pix_mp = &f->fmt.pix_mp;
 
 	pix_mp->width		= frame->f_width;
 	pix_mp->height		= frame->f_height;
 	pix_mp->field		= V4L2_FIELD_NONE;
-	pix_mp->pixelformat	= frame->fmt->pixelformat;
+	pix_mp->pixelformat	= fmt->pixelformat;
 	pix_mp->colorspace	= V4L2_COLORSPACE_REC709;
-	pix_mp->num_planes	= frame->fmt->num_planes;
+	pix_mp->num_planes	= fmt->num_planes;
 
 	for (i = 0; i < pix_mp->num_planes; ++i) {
-		pix_mp->plane_fmt[i].bytesperline = (frame->f_width *
-			frame->fmt->depth[i]) / 8;
-		pix_mp->plane_fmt[i].sizeimage =
-			 pix_mp->plane_fmt[i].bytesperline * frame-
 f_height;
+		get_format_size(pix_mp->width, pix_mp->height, fmt, i,
+				&pix_mp->plane_fmt[i].bytesperline,
+				&pix_mp->plane_fmt[i].sizeimage);
 	}
 
drivers/media/platform/exynos-gsc/gsc-core.c +21 -35
 	return 0;
@@ -794,11 +823,12 @@ void gsc_ctrls_delete(struct gsc_ctx *ctx)
 	}
 }
 
-/* The color format (num_comp, num_planes) must be already configured.
 */
+/* The color format (num_planes, num_comp) must be already configured.
+*/
 int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb,
 			struct gsc_frame *frame, struct gsc_addr *addr)  {
 	int ret = 0;
+	const struct gsc_fmt *fmt = frame->fmt;
 	u32 pix_size;
 
 	if ((vb == NULL) || (frame == NULL))
@@ -810,46 +840,30 @@ int gsc_prepare_addr(struct gsc_ctx *ctx, struct
 vb2_buffer *vb,
 		frame->fmt->num_planes, frame->fmt->num_comp, pix_size);
 
 	addr->y = vb2_dma_contig_plane_dma_addr(vb, 0);
-
-	if (frame->fmt->num_planes == 1) {
-		switch (frame->fmt->num_comp) {
-		case 1:
-			addr->cb = 0;
-			addr->cr = 0;
-			break;
-		case 2:
-			/* decompose Y into Y/Cb */
-			addr->cb = (dma_addr_t)(addr->y + pix_size);
-			addr->cr = 0;
-			break;
-		case 3:
-			/* decompose Y into Y/Cb/Cr */
-			addr->cb = (dma_addr_t)(addr->y + pix_size);
-			if (GSC_YUV420 == frame->fmt->color)
-				addr->cr = (dma_addr_t)(addr->cb
-						+ (pix_size >> 2));
-			else /* 422 */
-				addr->cr = (dma_addr_t)(addr->cb
-						+ (pix_size >> 1));
-			break;
-		default:
-			pr_err("Invalid the number of color planes");
-			return -EINVAL;
+	addr->cb = 0;
+	addr->cr = 0;
+
+	if (fmt->num_planes == 1) {
+		if (fmt->num_comp >= 2) {
+			addr->cb = (dma_addr_t)(addr->y +
+				((pix_size * fmt->depth[0]) /
+				(fmt->sampling[0][0] *
+				 fmt->sampling[0][1]) / 8));
+		}
+		if (fmt->num_comp >= 3) {
+			addr->cr = (dma_addr_t)(addr->cb +
+				((pix_size * fmt->depth[1]) /
+				(fmt->sampling[1][0] *
+				 fmt->sampling[1][1]) / 8));
 		}
 	} else {
-		if (frame->fmt->num_planes >= 2)
+		if (fmt->num_comp >= 2)
 			addr->cb = vb2_dma_contig_plane_dma_addr(vb, 1);
-
-		if (frame->fmt->num_planes == 3)
+		if (fmt->num_comp == 3)
 			addr->cr = vb2_dma_contig_plane_dma_addr(vb, 2);
 	}
 
-	if ((frame->fmt->pixelformat == V4L2_PIX_FMT_VYUY) ||
-		(frame->fmt->pixelformat == V4L2_PIX_FMT_YVYU) ||
-		(frame->fmt->pixelformat == V4L2_PIX_FMT_NV61) ||
-		(frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420) ||
-		(frame->fmt->pixelformat == V4L2_PIX_FMT_NV21) ||
-		(frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420M))
+	if (fmt->corder == GSC_CRCB)
 		swap(addr->cb, addr->cr);
 

pr_debug("ADDR: y= 0x%X cb= 0x%X cr= 0x%X ret= %d", diff --git
a/drivers/media/platform/exynos-gsc/gsc-core.h b/drivers/media/platform/exynos-gsc/gsc-core.h
index ef0a6564..8fb07e0d 100644

drivers/media/platform/exynos-gsc/gsc-core.h +8 -8
@@ -106,27 +106,27 @@ enum gsc_yuv_fmt {
 	container_of((__ctrl)->handler, struct gsc_ctx, ctrl_handler)
 /**
  * struct gsc_fmt - the driver's internal color format data
- * @mbus_code: Media Bus pixel code, -1 if not applicable
  * @name: format description
  * @pixelformat: the fourcc code for this format, 0 if not applicable
  * @yorder: Y/C order
  * @corder: Chrominance order control
  * @num_planes: number of physically non-contiguous data planes
- * @nr_comp: number of physically contiguous data planes
- * @depth: per plane driver's private 'number of bits per pixel'
- * @flags: flags indicating which operation mode format applies to
+ * @num_comp: number of physically contiguous data planes
+ * @depth: bit depth of each component
+ * @sampling: sampling frequency of each components, X and Y
+ * @mbus_code: Media Bus pixel code, -1 if not applicable
  */
 struct gsc_fmt {
-	enum v4l2_mbus_pixelcode mbus_code;
 	char	*name;
 	u32	pixelformat;
 	u32	color;
 	u32	yorder;
 	u32	corder;
-	u16	num_planes;
-	u16	num_comp;
+	u8	num_planes;
+	u8	num_comp;
 	u8	depth[VIDEO_MAX_PLANES];
-	u32	flags;
+	u8	sampling[VIDEO_MAX_PLANES][2];
+	enum v4l2_mbus_pixelcode mbus_code;
 };
 
 /**
drivers/media/platform/exynos-gsc/gsc-regs.c +9 -7
index e22d147a..a8d6c90b 100644
@@ -167,6 +167,7 @@ void gsc_hw_set_in_image_format(struct gsc_ctx
 *ctx)  {
 	struct gsc_dev *dev = ctx->gsc_dev;
 	struct gsc_frame *frame = &ctx->s_frame;
+	const struct gsc_fmt *fmt = frame->fmt;
 	u32 i, depth = 0;
 	u32 cfg;
 
@@ -176,21 +177,22 @@ void gsc_hw_set_in_image_format(struct gsc_ctx
 *ctx)
 		 GSC_IN_TILE_TYPE_MASK | GSC_IN_TILE_MODE);
 	writel(cfg, dev->regs + GSC_IN_CON);
 
-	if (is_rgb(frame->fmt->color)) {
+	if (is_rgb(fmt->color)) {
 		gsc_hw_set_in_image_rgb(ctx);
 		return;
 	}
-	for (i = 0; i < frame->fmt->num_planes; i++)
-		depth += frame->fmt->depth[i];
+	for (i = 0; i < fmt->num_comp; i++)
+		depth += fmt->depth[i] /
+			(fmt->sampling[i][0] * fmt->sampling[i][1]);
 
-	switch (frame->fmt->num_comp) {
+	switch (fmt->num_comp) {
 	case 1:
 		cfg |= GSC_IN_YUV422_1P;
-		if (frame->fmt->yorder == GSC_LSB_Y)
+		if (fmt->yorder == GSC_LSB_Y)
 			cfg |= GSC_IN_YUV422_1P_ORDER_LSB_Y;
 		else
-			cfg |= GSC_IN_YUV422_1P_OEDER_LSB_C;
-		if (frame->fmt->corder == GSC_CBCR)
+			cfg |= GSC_IN_YUV422_1P_ORDER_LSB_C;
+		if (fmt->corder == GSC_CBCR)
 			cfg |= GSC_IN_CHROMA_ORDER_CBCR;
 		else
drivers/media/platform/exynos-gsc/gsc-regs.c +1 -1
 			cfg |= GSC_IN_CHROMA_ORDER_CRCB;
@@ -200,7 +202,7 @@ void gsc_hw_set_in_image_format(struct gsc_ctx
 *ctx)
 			cfg |= GSC_IN_YUV420_2P;
 		else
 			cfg |= GSC_IN_YUV422_2P;
-		if (frame->fmt->corder == GSC_CBCR)
+		if (fmt->corder == GSC_CBCR)
 			cfg |= GSC_IN_CHROMA_ORDER_CBCR;
 		else
drivers/media/platform/exynos-gsc/gsc-regs.c +1 -1
 			cfg |= GSC_IN_CHROMA_ORDER_CRCB;
@@ -213,7 +215,7 @@ void gsc_hw_set_in_image_format(struct gsc_ctx
 *ctx)
 		break;
 	}
 
-	if (is_tiled(frame->fmt))
+	if (is_tiled(fmt))
 		cfg |= GSC_IN_TILE_C_16x8 | GSC_IN_TILE_MODE;
 
drivers/media/platform/exynos-gsc/gsc-regs.c +2 -1
 	writel(cfg, dev->regs + GSC_IN_CON);
@@ -287,6 +289,7 @@ void gsc_hw_set_out_image_format(struct gsc_ctx
 *ctx)  {
 	struct gsc_dev *dev = ctx->gsc_dev;
 	struct gsc_frame *frame = &ctx->d_frame;
+	const struct gsc_fmt *fmt = frame->fmt;
 	u32 i, depth = 0;
 	u32 cfg;
 
@@ -296,7 +299,7 @@ void gsc_hw_set_out_image_format(struct gsc_ctx
 *ctx)
 		 GSC_OUT_TILE_TYPE_MASK | GSC_OUT_TILE_MODE);
 	writel(cfg, dev->regs + GSC_OUT_CON);
 
-	if (is_rgb(frame->fmt->color)) {
+	if (is_rgb(fmt->color)) {
 		gsc_hw_set_out_image_rgb(ctx);
 		return;
drivers/media/platform/exynos-gsc/gsc-regs.c +7 -6
 	}
@@ -306,17 +309,18 @@ void gsc_hw_set_out_image_format(struct gsc_ctx
 *ctx)
 		goto end_set;
 	}
 
-	for (i = 0; i < frame->fmt->num_planes; i++)
-		depth += frame->fmt->depth[i];
+	for (i = 0; i < fmt->num_comp; i++)
+		depth += fmt->depth[i] /
+			(fmt->sampling[i][0] * fmt->sampling[i][1]);
 
-	switch (frame->fmt->num_comp) {
+	switch (fmt->num_comp) {
 	case 1:
 		cfg |= GSC_OUT_YUV422_1P;
-		if (frame->fmt->yorder == GSC_LSB_Y)
+		if (fmt->yorder == GSC_LSB_Y)
 			cfg |= GSC_OUT_YUV422_1P_ORDER_LSB_Y;
 		else
-			cfg |= GSC_OUT_YUV422_1P_OEDER_LSB_C;
-		if (frame->fmt->corder == GSC_CBCR)
+			cfg |= GSC_OUT_YUV422_1P_ORDER_LSB_C;
+		if (fmt->corder == GSC_CBCR)
 			cfg |= GSC_OUT_CHROMA_ORDER_CBCR;
 		else
drivers/media/platform/exynos-gsc/gsc-regs.c +1 -1
 			cfg |= GSC_OUT_CHROMA_ORDER_CRCB;
@@ -326,7 +330,7 @@ void gsc_hw_set_out_image_format(struct gsc_ctx
 *ctx)
 			cfg |= GSC_OUT_YUV420_2P;
 		else
 			cfg |= GSC_OUT_YUV422_2P;
-		if (frame->fmt->corder == GSC_CBCR)
+		if (fmt->corder == GSC_CBCR)
 			cfg |= GSC_OUT_CHROMA_ORDER_CBCR;
 		else
drivers/media/platform/exynos-gsc/gsc-regs.c +1 -1
 			cfg |= GSC_OUT_CHROMA_ORDER_CRCB;
@@ -336,7 +340,7 @@ void gsc_hw_set_out_image_format(struct gsc_ctx
 *ctx)
 		break;
 	}
 
-	if (is_tiled(frame->fmt))
+	if (is_tiled(fmt))
 		cfg |= GSC_OUT_TILE_C_16x8 | GSC_OUT_TILE_MODE;
 

end_set:

drivers/media/platform/exynos-gsc/gsc-regs.h +2 -3
index 4678f9a6..b03401dc 100644
@@ -46,7 +46,7 @@
 #define GSC_IN_RGB_SD_WIDE		(0 << 14)
 #define GSC_IN_YUV422_1P_ORDER_MASK	(1 << 13)
 #define GSC_IN_YUV422_1P_ORDER_LSB_Y	(0 << 13)
-#define GSC_IN_YUV422_1P_OEDER_LSB_C	(1 << 13)
+#define GSC_IN_YUV422_1P_ORDER_LSB_C	(1 << 13)
 #define GSC_IN_CHROMA_ORDER_MASK	(1 << 12)
 #define GSC_IN_CHROMA_ORDER_CBCR	(0 << 12)
 #define GSC_IN_CHROMA_ORDER_CRCB	(1 << 12)
@@ -91,7 +91,7 @@
 #define GSC_OUT_RGB_SD_NARROW		(0 << 10)
 #define GSC_OUT_YUV422_1P_ORDER_MASK	(1 << 9)
 #define GSC_OUT_YUV422_1P_ORDER_LSB_Y	(0 << 9)
-#define GSC_OUT_YUV422_1P_OEDER_LSB_C	(1 << 9)
+#define GSC_OUT_YUV422_1P_ORDER_LSB_C	(1 << 9)
 #define GSC_OUT_CHROMA_ORDER_MASK	(1 << 8)
 #define GSC_OUT_CHROMA_ORDER_CBCR	(0 << 8)
 #define GSC_OUT_CHROMA_ORDER_CRCB	(1 << 8)
--

1.9.0.279.gdc9e3eb

#5 lore raw

Re: [PATCH 3/4] gsc-m2m: report correct format bytesperline and sizeimage

In reply to John Sheu

Hi John Sheu,

Thanks for the patch.
Please find the review comments inline.

Quoted 226 lines · John Sheu

Explicitly specify sampling period for subsampled chroma formats, so stride and image size are properly reported through VIDIOC_{S,G}_FMT.

---
 drivers/media/platform/exynos-gsc/gsc-core.c | 154 +++++++++++++++------------
 drivers/media/platform/exynos-gsc/gsc-core.h |  16 +--
 drivers/media/platform/exynos-gsc/gsc-regs.c |  40 +++----
 drivers/media/platform/exynos-gsc/gsc-regs.h |   4 +-
 4 files changed, 116 insertions(+), 98 deletions(-)
drivers/media/platform/exynos-gsc/gsc-core.c +42 -24
index 9d0cc04d..c02addef 100644
@@ -34,167 +34,185 @@ static const struct gsc_fmt gsc_formats[] = {
        {
                .name           = "RGB565",
                .pixelformat    = V4L2_PIX_FMT_RGB565X,
-               .depth          = { 16 },
                .color          = GSC_RGB,
                .num_planes     = 1,
                .num_comp       = 1,
+               .depth          = { 16 },
+               .sampling       = { { 1, 1 } },
        }, {
                .name           = "XRGB-8-8-8-8, 32 bpp",
                .pixelformat    = V4L2_PIX_FMT_RGB32,
-               .depth          = { 32 },
                .color          = GSC_RGB,
                .num_planes     = 1,
                .num_comp       = 1,
+               .depth          = { 32 },
+               .sampling       = { { 1, 1 } },
        }, {
                .name           = "YUV 4:2:2 packed, YCbYCr",
                .pixelformat    = V4L2_PIX_FMT_YUYV,
-               .depth          = { 16 },
                .color          = GSC_YUV422,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CBCR,
                .num_planes     = 1,
                .num_comp       = 1,
+               .depth          = { 16 },
+               .sampling       = { { 1, 1 } },
                .mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
        }, {
                .name           = "YUV 4:2:2 packed, CbYCrY",
                .pixelformat    = V4L2_PIX_FMT_UYVY,
-               .depth          = { 16 },
                .color          = GSC_YUV422,
                .yorder         = GSC_LSB_C,
                .corder         = GSC_CBCR,
                .num_planes     = 1,
                .num_comp       = 1,
+               .depth          = { 16 },
+               .sampling       = { { 1, 1 } },
                .mbus_code      = V4L2_MBUS_FMT_UYVY8_2X8,
        }, {
                .name           = "YUV 4:2:2 packed, CrYCbY",
                .pixelformat    = V4L2_PIX_FMT_VYUY,
-               .depth          = { 16 },
                .color          = GSC_YUV422,
                .yorder         = GSC_LSB_C,
                .corder         = GSC_CRCB,
                .num_planes     = 1,
                .num_comp       = 1,
+               .depth          = { 16 },
+               .sampling       = { { 1, 1 } },
                .mbus_code      = V4L2_MBUS_FMT_VYUY8_2X8,
        }, {
                .name           = "YUV 4:2:2 packed, YCrYCb",
                .pixelformat    = V4L2_PIX_FMT_YVYU,
-               .depth          = { 16 },
                .color          = GSC_YUV422,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CRCB,
                .num_planes     = 1,
                .num_comp       = 1,
+               .depth          = { 16 },
+               .sampling       = { { 1, 1 } },
                .mbus_code      = V4L2_MBUS_FMT_YVYU8_2X8,
        }, {
                .name           = "YUV 4:4:4 planar, YCbYCr",
                .pixelformat    = V4L2_PIX_FMT_YUV32,
-               .depth          = { 32 },
                .color          = GSC_YUV444,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CBCR,
                .num_planes     = 1,
                .num_comp       = 1,
+               .depth          = { 32 },
+               .sampling       = { { 1, 1 } },
        }, {
                .name           = "YUV 4:2:2 planar, Y/Cb/Cr",
                .pixelformat    = V4L2_PIX_FMT_YUV422P,
-               .depth          = { 16 },
                .color          = GSC_YUV422,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CBCR,
                .num_planes     = 1,
                .num_comp       = 3,
+               .depth          = { 8, 8, 8 },
+               .sampling       = { { 1, 1 }, { 2, 1 }, { 2, 1 } },
        }, {
                .name           = "YUV 4:2:2 planar, Y/CbCr",
                .pixelformat    = V4L2_PIX_FMT_NV16,
-               .depth          = { 16 },
                .color          = GSC_YUV422,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CBCR,
                .num_planes     = 1,
                .num_comp       = 2,
+               .depth          = { 8, 16 },
+               .sampling       = { { 1, 1 }, { 2, 1 } },
        }, {
                .name           = "YUV 4:2:2 planar, Y/CrCb",
                .pixelformat    = V4L2_PIX_FMT_NV61,
-               .depth          = { 16 },
                .color          = GSC_YUV422,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CRCB,
                .num_planes     = 1,
                .num_comp       = 2,
+               .depth          = { 8, 16 },
+               .sampling       = { { 1, 1 }, { 2, 1 } },
        }, {
                .name           = "YUV 4:2:0 planar, YCbCr",
                .pixelformat    = V4L2_PIX_FMT_YUV420,
-               .depth          = { 12 },
                .color          = GSC_YUV420,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CBCR,
                .num_planes     = 1,
                .num_comp       = 3,
+               .depth          = { 8, 8, 8 },
+               .sampling       = { { 1, 1 }, { 2, 2 }, { 2, 2 } },
        }, {
                .name           = "YUV 4:2:0 planar, YCrCb",
                .pixelformat    = V4L2_PIX_FMT_YVU420,
-               .depth          = { 12 },
                .color          = GSC_YUV420,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CRCB,
                .num_planes     = 1,
                .num_comp       = 3,
-
+               .depth          = { 8, 8, 8 },
+               .sampling       = { { 1, 1 }, { 2, 2 }, { 2, 2 } },
        }, {
                .name           = "YUV 4:2:0 planar, Y/CbCr",
                .pixelformat    = V4L2_PIX_FMT_NV12,
-               .depth          = { 12 },
                .color          = GSC_YUV420,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CBCR,
                .num_planes     = 1,
                .num_comp       = 2,
+               .depth          = { 8, 16 },
+               .sampling       = { { 1, 1 }, { 2, 2 } },
        }, {
                .name           = "YUV 4:2:0 planar, Y/CrCb",
                .pixelformat    = V4L2_PIX_FMT_NV21,
-               .depth          = { 12 },
                .color          = GSC_YUV420,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CRCB,
                .num_planes     = 1,
                .num_comp       = 2,
+               .depth          = { 8, 16 },
+               .sampling       = { { 1, 1 }, { 2, 2 } },
        }, {
-               .name           = "YUV 4:2:0 non-contig. 2p, Y/CbCr",
+               .name           = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr",
                .pixelformat    = V4L2_PIX_FMT_NV12M,
-               .depth          = { 8, 4 },
                .color          = GSC_YUV420,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CBCR,
                .num_planes     = 2,
                .num_comp       = 2,
+               .depth          = { 8, 16 },
+               .sampling       = { { 1, 1 }, { 2, 2 } },
        }, {
-               .name           = "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr",
+               .name           = "YUV 4:2:0 non-contiguous 3-planar, Y/Cb/Cr",
                .pixelformat    = V4L2_PIX_FMT_YUV420M,
-               .depth          = { 8, 2, 2 },
                .color          = GSC_YUV420,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CBCR,
                .num_planes     = 3,
                .num_comp       = 3,
+               .depth          = { 8, 8, 8 },
+               .sampling       = { { 1, 1 }, { 2, 2 }, { 2, 2 } },
        }, {
-               .name           = "YUV 4:2:0 non-contig. 3p, Y/Cr/Cb",
+               .name           = "YUV 4:2:0 non-contiguous 3-planar, Y/Cr/Cb",
                .pixelformat    = V4L2_PIX_FMT_YVU420M,
-               .depth          = { 8, 2, 2 },
                .color          = GSC_YUV420,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CRCB,
                .num_planes     = 3,
                .num_comp       = 3,
+               .depth          = { 8, 8, 8 },
+               .sampling       = { { 1, 1 }, { 2, 2 }, { 2, 2 } },
        }, {
-               .name           = "YUV 4:2:0 n.c. 2p, Y/CbCr tiled",
+               .name           =
+                       "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr, tiled",
                .pixelformat    = V4L2_PIX_FMT_NV12MT_16X16,
-               .depth          = { 8, 4 },
                .color          = GSC_YUV420,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CBCR,
                .num_planes     = 2,
                .num_comp       = 2,
-       }
+               .depth          = { 8, 16 },
+               .sampling       = { { 1, 1 }, { 2, 2 } },
+       },
 };
 
 const struct gsc_fmt *get_format(int index)

drivers/media/platform/exynos-gsc/gsc-core.c void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame *frm) · line 410

Quoted 9 lines
drivers/media/platform/exynos-gsc/gsc-core.c +6 -0
@@ -384,6 +402,14 @@ void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame *frm)
                        f_chk_addr, f_chk_len, s_chk_addr, s_chk_len);
 }
 
+static void get_format_size(__u32 width, __u32 height,
+                           const struct gsc_fmt *fmt, int plane,
+                           __u16 *bytesperline, __u32 *sizeimage) {
+       __u16 bpl = ((width * fmt->depth[plane]) / fmt->sampling[plane][0]) / 8;
+       *bytesperline = bpl;
+       *sizeimage = (height * bpl) / fmt->sampling[plane][0];

should use the height sampling instead ?? *sizeimage = (height * bpl) / fmt->sampling[plane][1];

Quoted 127 lines
drivers/media/platform/exynos-gsc/gsc-core.c +35 -40
+}
+
 int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)
 {
        struct gsc_dev *gsc = ctx->gsc_dev;
@@ -448,14 +474,16 @@ int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)
        else /* SD */
                pix_mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
 
-
+       /* V4L2 specifies for contiguous planar formats that bytesperline and
+          sizeimage are set to values appropriate for the first plane. */
        for (i = 0; i < pix_mp->num_planes; ++i) {
-               int bpl = (pix_mp->width * fmt->depth[i]) >> 3;
-               pix_mp->plane_fmt[i].bytesperline = bpl;
-               pix_mp->plane_fmt[i].sizeimage = bpl * pix_mp->height;
+               get_format_size(pix_mp->width, pix_mp->height, fmt, i,
+                               &pix_mp->plane_fmt[i].bytesperline,
+                               &pix_mp->plane_fmt[i].sizeimage);
 
                pr_debug("[%d]: bpl: %d, sizeimage: %d",
-                               i, bpl, pix_mp->plane_fmt[i].sizeimage);
+                               i, pix_mp->plane_fmt[i].bytesperline,
+                               pix_mp->plane_fmt[i].sizeimage);
        }
 
        return 0;
@@ -465,26 +493,27 @@ int gsc_g_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)
 {
        struct gsc_frame *frame;
        struct v4l2_pix_format_mplane *pix_mp;
+       const struct gsc_fmt *fmt;
        int i;
 
        frame = ctx_get_frame(ctx, f->type);
        if (IS_ERR(frame))
                return PTR_ERR(frame);
+       fmt = frame->fmt;
 
        pix_mp = &f->fmt.pix_mp;
 
        pix_mp->width           = frame->f_width;
        pix_mp->height          = frame->f_height;
        pix_mp->field           = V4L2_FIELD_NONE;
-       pix_mp->pixelformat     = frame->fmt->pixelformat;
+       pix_mp->pixelformat     = fmt->pixelformat;
        pix_mp->colorspace      = V4L2_COLORSPACE_REC709;
-       pix_mp->num_planes      = frame->fmt->num_planes;
+       pix_mp->num_planes      = fmt->num_planes;
 
        for (i = 0; i < pix_mp->num_planes; ++i) {
-               pix_mp->plane_fmt[i].bytesperline = (frame->f_width *
-                       frame->fmt->depth[i]) / 8;
-               pix_mp->plane_fmt[i].sizeimage =
-                        pix_mp->plane_fmt[i].bytesperline * frame->f_height;
+               get_format_size(pix_mp->width, pix_mp->height, fmt, i,
+                               &pix_mp->plane_fmt[i].bytesperline,
+                               &pix_mp->plane_fmt[i].sizeimage);
        }
 
        return 0;
@@ -794,11 +823,12 @@ void gsc_ctrls_delete(struct gsc_ctx *ctx)
        }
 }
 
-/* The color format (num_comp, num_planes) must be already configured. */
+/* The color format (num_planes, num_comp) must be already configured. */
 int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb,
                        struct gsc_frame *frame, struct gsc_addr *addr)
 {
        int ret = 0;
+       const struct gsc_fmt *fmt = frame->fmt;
        u32 pix_size;
 
        if ((vb == NULL) || (frame == NULL))
@@ -810,46 +840,30 @@ int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb,
                frame->fmt->num_planes, frame->fmt->num_comp, pix_size);
 
        addr->y = vb2_dma_contig_plane_dma_addr(vb, 0);
-
-       if (frame->fmt->num_planes == 1) {
-               switch (frame->fmt->num_comp) {
-               case 1:
-                       addr->cb = 0;
-                       addr->cr = 0;
-                       break;
-               case 2:
-                       /* decompose Y into Y/Cb */
-                       addr->cb = (dma_addr_t)(addr->y + pix_size);
-                       addr->cr = 0;
-                       break;
-               case 3:
-                       /* decompose Y into Y/Cb/Cr */
-                       addr->cb = (dma_addr_t)(addr->y + pix_size);
-                       if (GSC_YUV420 == frame->fmt->color)
-                               addr->cr = (dma_addr_t)(addr->cb
-                                               + (pix_size >> 2));
-                       else /* 422 */
-                               addr->cr = (dma_addr_t)(addr->cb
-                                               + (pix_size >> 1));
-                       break;
-               default:
-                       pr_err("Invalid the number of color planes");
-                       return -EINVAL;
+       addr->cb = 0;
+       addr->cr = 0;
+
+       if (fmt->num_planes == 1) {
+               if (fmt->num_comp >= 2) {
+                       addr->cb = (dma_addr_t)(addr->y +
+                               ((pix_size * fmt->depth[0]) /
+                               (fmt->sampling[0][0] *
+                                fmt->sampling[0][1]) / 8));
+               }
+               if (fmt->num_comp >= 3) {
+                       addr->cr = (dma_addr_t)(addr->cb +
+                               ((pix_size * fmt->depth[1]) /
+                               (fmt->sampling[1][0] *
+                                fmt->sampling[1][1]) / 8));
                }
        } else {
-               if (frame->fmt->num_planes >= 2)
+               if (fmt->num_comp >= 2)
                        addr->cb = vb2_dma_contig_plane_dma_addr(vb, 1);
-
-               if (frame->fmt->num_planes == 3)
+               if (fmt->num_comp == 3)

drivers/media/platform/exynos-gsc/gsc-core.c int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb, · line 866

Quoted 10 lines
drivers/media/platform/exynos-gsc/gsc-core.c +1 -6
                        addr->cr = vb2_dma_contig_plane_dma_addr(vb, 2);
        }
 
-       if ((frame->fmt->pixelformat == V4L2_PIX_FMT_VYUY) ||
-               (frame->fmt->pixelformat == V4L2_PIX_FMT_YVYU) ||
-               (frame->fmt->pixelformat == V4L2_PIX_FMT_NV61) ||
-               (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420) ||
-               (frame->fmt->pixelformat == V4L2_PIX_FMT_NV21) ||
-               (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420M))
+       if (fmt->corder == GSC_CRCB)
            if ((fmt->corder == GSC_CRCB) && (fmt->num_planes == 3))

I think it shoud only applicable to 3 component formats. for example, Incase of two component formats like V4L2_PIX_FMT_NV61, chroma base address becomes zero.

Regards,
Shaik Ameer Basha

Quoted 192 lines
drivers/media/platform/exynos-gsc/gsc-core.c +0 -0
                swap(addr->cb, addr->cr);
 
        pr_debug("ADDR: y= 0x%X  cb= 0x%X cr= 0x%X ret= %d",
drivers/media/platform/exynos-gsc/gsc-core.h +8 -8
index ef0a6564..8fb07e0d 100644
@@ -106,27 +106,27 @@ enum gsc_yuv_fmt {
        container_of((__ctrl)->handler, struct gsc_ctx, ctrl_handler)
 /**
  * struct gsc_fmt - the driver's internal color format data
- * @mbus_code: Media Bus pixel code, -1 if not applicable
  * @name: format description
  * @pixelformat: the fourcc code for this format, 0 if not applicable
  * @yorder: Y/C order
  * @corder: Chrominance order control
  * @num_planes: number of physically non-contiguous data planes
- * @nr_comp: number of physically contiguous data planes
- * @depth: per plane driver's private 'number of bits per pixel'
- * @flags: flags indicating which operation mode format applies to
+ * @num_comp: number of physically contiguous data planes
+ * @depth: bit depth of each component
+ * @sampling: sampling frequency of each components, X and Y
+ * @mbus_code: Media Bus pixel code, -1 if not applicable
  */
 struct gsc_fmt {
-       enum v4l2_mbus_pixelcode mbus_code;
        char    *name;
        u32     pixelformat;
        u32     color;
        u32     yorder;
        u32     corder;
-       u16     num_planes;
-       u16     num_comp;
+       u8      num_planes;
+       u8      num_comp;
        u8      depth[VIDEO_MAX_PLANES];
-       u32     flags;
+       u8      sampling[VIDEO_MAX_PLANES][2];
+       enum v4l2_mbus_pixelcode mbus_code;
 };
 
 /**
drivers/media/platform/exynos-gsc/gsc-regs.c +22 -18
index e22d147a..a8d6c90b 100644
@@ -167,6 +167,7 @@ void gsc_hw_set_in_image_format(struct gsc_ctx *ctx)
 {
        struct gsc_dev *dev = ctx->gsc_dev;
        struct gsc_frame *frame = &ctx->s_frame;
+       const struct gsc_fmt *fmt = frame->fmt;
        u32 i, depth = 0;
        u32 cfg;
 
@@ -176,21 +177,22 @@ void gsc_hw_set_in_image_format(struct gsc_ctx *ctx)
                 GSC_IN_TILE_TYPE_MASK | GSC_IN_TILE_MODE);
        writel(cfg, dev->regs + GSC_IN_CON);
 
-       if (is_rgb(frame->fmt->color)) {
+       if (is_rgb(fmt->color)) {
                gsc_hw_set_in_image_rgb(ctx);
                return;
        }
-       for (i = 0; i < frame->fmt->num_planes; i++)
-               depth += frame->fmt->depth[i];
+       for (i = 0; i < fmt->num_comp; i++)
+               depth += fmt->depth[i] /
+                       (fmt->sampling[i][0] * fmt->sampling[i][1]);
 
-       switch (frame->fmt->num_comp) {
+       switch (fmt->num_comp) {
        case 1:
                cfg |= GSC_IN_YUV422_1P;
-               if (frame->fmt->yorder == GSC_LSB_Y)
+               if (fmt->yorder == GSC_LSB_Y)
                        cfg |= GSC_IN_YUV422_1P_ORDER_LSB_Y;
                else
-                       cfg |= GSC_IN_YUV422_1P_OEDER_LSB_C;
-               if (frame->fmt->corder == GSC_CBCR)
+                       cfg |= GSC_IN_YUV422_1P_ORDER_LSB_C;
+               if (fmt->corder == GSC_CBCR)
                        cfg |= GSC_IN_CHROMA_ORDER_CBCR;
                else
                        cfg |= GSC_IN_CHROMA_ORDER_CRCB;
@@ -200,7 +202,7 @@ void gsc_hw_set_in_image_format(struct gsc_ctx *ctx)
                        cfg |= GSC_IN_YUV420_2P;
                else
                        cfg |= GSC_IN_YUV422_2P;
-               if (frame->fmt->corder == GSC_CBCR)
+               if (fmt->corder == GSC_CBCR)
                        cfg |= GSC_IN_CHROMA_ORDER_CBCR;
                else
                        cfg |= GSC_IN_CHROMA_ORDER_CRCB;
@@ -213,7 +215,7 @@ void gsc_hw_set_in_image_format(struct gsc_ctx *ctx)
                break;
        }
 
-       if (is_tiled(frame->fmt))
+       if (is_tiled(fmt))
                cfg |= GSC_IN_TILE_C_16x8 | GSC_IN_TILE_MODE;
 
        writel(cfg, dev->regs + GSC_IN_CON);
@@ -287,6 +289,7 @@ void gsc_hw_set_out_image_format(struct gsc_ctx *ctx)
 {
        struct gsc_dev *dev = ctx->gsc_dev;
        struct gsc_frame *frame = &ctx->d_frame;
+       const struct gsc_fmt *fmt = frame->fmt;
        u32 i, depth = 0;
        u32 cfg;
 
@@ -296,7 +299,7 @@ void gsc_hw_set_out_image_format(struct gsc_ctx *ctx)
                 GSC_OUT_TILE_TYPE_MASK | GSC_OUT_TILE_MODE);
        writel(cfg, dev->regs + GSC_OUT_CON);
 
-       if (is_rgb(frame->fmt->color)) {
+       if (is_rgb(fmt->color)) {
                gsc_hw_set_out_image_rgb(ctx);
                return;
        }
@@ -306,17 +309,18 @@ void gsc_hw_set_out_image_format(struct gsc_ctx *ctx)
                goto end_set;
        }
 
-       for (i = 0; i < frame->fmt->num_planes; i++)
-               depth += frame->fmt->depth[i];
+       for (i = 0; i < fmt->num_comp; i++)
+               depth += fmt->depth[i] /
+                       (fmt->sampling[i][0] * fmt->sampling[i][1]);
 
-       switch (frame->fmt->num_comp) {
+       switch (fmt->num_comp) {
        case 1:
                cfg |= GSC_OUT_YUV422_1P;
-               if (frame->fmt->yorder == GSC_LSB_Y)
+               if (fmt->yorder == GSC_LSB_Y)
                        cfg |= GSC_OUT_YUV422_1P_ORDER_LSB_Y;
                else
-                       cfg |= GSC_OUT_YUV422_1P_OEDER_LSB_C;
-               if (frame->fmt->corder == GSC_CBCR)
+                       cfg |= GSC_OUT_YUV422_1P_ORDER_LSB_C;
+               if (fmt->corder == GSC_CBCR)
                        cfg |= GSC_OUT_CHROMA_ORDER_CBCR;
                else
                        cfg |= GSC_OUT_CHROMA_ORDER_CRCB;
@@ -326,7 +330,7 @@ void gsc_hw_set_out_image_format(struct gsc_ctx *ctx)
                        cfg |= GSC_OUT_YUV420_2P;
                else
                        cfg |= GSC_OUT_YUV422_2P;
-               if (frame->fmt->corder == GSC_CBCR)
+               if (fmt->corder == GSC_CBCR)
                        cfg |= GSC_OUT_CHROMA_ORDER_CBCR;
                else
                        cfg |= GSC_OUT_CHROMA_ORDER_CRCB;
@@ -336,7 +340,7 @@ void gsc_hw_set_out_image_format(struct gsc_ctx *ctx)
                break;
        }
 
-       if (is_tiled(frame->fmt))
+       if (is_tiled(fmt))
                cfg |= GSC_OUT_TILE_C_16x8 | GSC_OUT_TILE_MODE;
 
 end_set:
drivers/media/platform/exynos-gsc/gsc-regs.h +2 -3
index 4678f9a6..b03401dc 100644
@@ -46,7 +46,7 @@
 #define GSC_IN_RGB_SD_WIDE             (0 << 14)
 #define GSC_IN_YUV422_1P_ORDER_MASK    (1 << 13)
 #define GSC_IN_YUV422_1P_ORDER_LSB_Y   (0 << 13)
-#define GSC_IN_YUV422_1P_OEDER_LSB_C   (1 << 13)
+#define GSC_IN_YUV422_1P_ORDER_LSB_C   (1 << 13)
 #define GSC_IN_CHROMA_ORDER_MASK       (1 << 12)
 #define GSC_IN_CHROMA_ORDER_CBCR       (0 << 12)
 #define GSC_IN_CHROMA_ORDER_CRCB       (1 << 12)
@@ -91,7 +91,7 @@
 #define GSC_OUT_RGB_SD_NARROW          (0 << 10)
 #define GSC_OUT_YUV422_1P_ORDER_MASK   (1 << 9)
 #define GSC_OUT_YUV422_1P_ORDER_LSB_Y  (0 << 9)
-#define GSC_OUT_YUV422_1P_OEDER_LSB_C  (1 << 9)
+#define GSC_OUT_YUV422_1P_ORDER_LSB_C  (1 << 9)
 #define GSC_OUT_CHROMA_ORDER_MASK      (1 << 8)
 #define GSC_OUT_CHROMA_ORDER_CBCR      (0 << 8)
 #define GSC_OUT_CHROMA_ORDER_CRCB      (1 << 8)
--

1.9.0.279.gdc9e3eb

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

#6 lore raw

Re: [PATCH 3/4] gsc-m2m: report correct format bytesperline and sizeimage

Quoted 375 lines · Shaik Ameer Basha

Hi John Sheu,

Thanks for the patch.
Please find the review comments inline.

Quoted 226 lines · John Sheu

Explicitly specify sampling period for subsampled chroma formats, so stride and image size are properly reported through VIDIOC_{S,G}_FMT.

---
 drivers/media/platform/exynos-gsc/gsc-core.c | 154 +++++++++++++++------------
 drivers/media/platform/exynos-gsc/gsc-core.h |  16 +--
 drivers/media/platform/exynos-gsc/gsc-regs.c |  40 +++----
 drivers/media/platform/exynos-gsc/gsc-regs.h |   4 +-
 4 files changed, 116 insertions(+), 98 deletions(-)
drivers/media/platform/exynos-gsc/gsc-core.c +42 -24
index 9d0cc04d..c02addef 100644
@@ -34,167 +34,185 @@ static const struct gsc_fmt gsc_formats[] = {
        {
                .name           = "RGB565",
                .pixelformat    = V4L2_PIX_FMT_RGB565X,
-               .depth          = { 16 },
                .color          = GSC_RGB,
                .num_planes     = 1,
                .num_comp       = 1,
+               .depth          = { 16 },
+               .sampling       = { { 1, 1 } },
        }, {
                .name           = "XRGB-8-8-8-8, 32 bpp",
                .pixelformat    = V4L2_PIX_FMT_RGB32,
-               .depth          = { 32 },
                .color          = GSC_RGB,
                .num_planes     = 1,
                .num_comp       = 1,
+               .depth          = { 32 },
+               .sampling       = { { 1, 1 } },
        }, {
                .name           = "YUV 4:2:2 packed, YCbYCr",
                .pixelformat    = V4L2_PIX_FMT_YUYV,
-               .depth          = { 16 },
                .color          = GSC_YUV422,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CBCR,
                .num_planes     = 1,
                .num_comp       = 1,
+               .depth          = { 16 },
+               .sampling       = { { 1, 1 } },
                .mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
        }, {
                .name           = "YUV 4:2:2 packed, CbYCrY",
                .pixelformat    = V4L2_PIX_FMT_UYVY,
-               .depth          = { 16 },
                .color          = GSC_YUV422,
                .yorder         = GSC_LSB_C,
                .corder         = GSC_CBCR,
                .num_planes     = 1,
                .num_comp       = 1,
+               .depth          = { 16 },
+               .sampling       = { { 1, 1 } },
                .mbus_code      = V4L2_MBUS_FMT_UYVY8_2X8,
        }, {
                .name           = "YUV 4:2:2 packed, CrYCbY",
                .pixelformat    = V4L2_PIX_FMT_VYUY,
-               .depth          = { 16 },
                .color          = GSC_YUV422,
                .yorder         = GSC_LSB_C,
                .corder         = GSC_CRCB,
                .num_planes     = 1,
                .num_comp       = 1,
+               .depth          = { 16 },
+               .sampling       = { { 1, 1 } },
                .mbus_code      = V4L2_MBUS_FMT_VYUY8_2X8,
        }, {
                .name           = "YUV 4:2:2 packed, YCrYCb",
                .pixelformat    = V4L2_PIX_FMT_YVYU,
-               .depth          = { 16 },
                .color          = GSC_YUV422,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CRCB,
                .num_planes     = 1,
                .num_comp       = 1,
+               .depth          = { 16 },
+               .sampling       = { { 1, 1 } },
                .mbus_code      = V4L2_MBUS_FMT_YVYU8_2X8,
        }, {
                .name           = "YUV 4:4:4 planar, YCbYCr",
                .pixelformat    = V4L2_PIX_FMT_YUV32,
-               .depth          = { 32 },
                .color          = GSC_YUV444,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CBCR,
                .num_planes     = 1,
                .num_comp       = 1,
+               .depth          = { 32 },
+               .sampling       = { { 1, 1 } },
        }, {
                .name           = "YUV 4:2:2 planar, Y/Cb/Cr",
                .pixelformat    = V4L2_PIX_FMT_YUV422P,
-               .depth          = { 16 },
                .color          = GSC_YUV422,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CBCR,
                .num_planes     = 1,
                .num_comp       = 3,
+               .depth          = { 8, 8, 8 },
+               .sampling       = { { 1, 1 }, { 2, 1 }, { 2, 1 } },
        }, {
                .name           = "YUV 4:2:2 planar, Y/CbCr",
                .pixelformat    = V4L2_PIX_FMT_NV16,
-               .depth          = { 16 },
                .color          = GSC_YUV422,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CBCR,
                .num_planes     = 1,
                .num_comp       = 2,
+               .depth          = { 8, 16 },
+               .sampling       = { { 1, 1 }, { 2, 1 } },
        }, {
                .name           = "YUV 4:2:2 planar, Y/CrCb",
                .pixelformat    = V4L2_PIX_FMT_NV61,
-               .depth          = { 16 },
                .color          = GSC_YUV422,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CRCB,
                .num_planes     = 1,
                .num_comp       = 2,
+               .depth          = { 8, 16 },
+               .sampling       = { { 1, 1 }, { 2, 1 } },
        }, {
                .name           = "YUV 4:2:0 planar, YCbCr",
                .pixelformat    = V4L2_PIX_FMT_YUV420,
-               .depth          = { 12 },
                .color          = GSC_YUV420,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CBCR,
                .num_planes     = 1,
                .num_comp       = 3,
+               .depth          = { 8, 8, 8 },
+               .sampling       = { { 1, 1 }, { 2, 2 }, { 2, 2 } },
        }, {
                .name           = "YUV 4:2:0 planar, YCrCb",
                .pixelformat    = V4L2_PIX_FMT_YVU420,
-               .depth          = { 12 },
                .color          = GSC_YUV420,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CRCB,
                .num_planes     = 1,
                .num_comp       = 3,
-
+               .depth          = { 8, 8, 8 },
+               .sampling       = { { 1, 1 }, { 2, 2 }, { 2, 2 } },
        }, {
                .name           = "YUV 4:2:0 planar, Y/CbCr",
                .pixelformat    = V4L2_PIX_FMT_NV12,
-               .depth          = { 12 },
                .color          = GSC_YUV420,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CBCR,
                .num_planes     = 1,
                .num_comp       = 2,
+               .depth          = { 8, 16 },
+               .sampling       = { { 1, 1 }, { 2, 2 } },
        }, {
                .name           = "YUV 4:2:0 planar, Y/CrCb",
                .pixelformat    = V4L2_PIX_FMT_NV21,
-               .depth          = { 12 },
                .color          = GSC_YUV420,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CRCB,
                .num_planes     = 1,
                .num_comp       = 2,
+               .depth          = { 8, 16 },
+               .sampling       = { { 1, 1 }, { 2, 2 } },
        }, {
-               .name           = "YUV 4:2:0 non-contig. 2p, Y/CbCr",
+               .name           = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr",
                .pixelformat    = V4L2_PIX_FMT_NV12M,
-               .depth          = { 8, 4 },
                .color          = GSC_YUV420,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CBCR,
                .num_planes     = 2,
                .num_comp       = 2,
+               .depth          = { 8, 16 },
+               .sampling       = { { 1, 1 }, { 2, 2 } },
        }, {
-               .name           = "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr",
+               .name           = "YUV 4:2:0 non-contiguous 3-planar, Y/Cb/Cr",
                .pixelformat    = V4L2_PIX_FMT_YUV420M,
-               .depth          = { 8, 2, 2 },
                .color          = GSC_YUV420,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CBCR,
                .num_planes     = 3,
                .num_comp       = 3,
+               .depth          = { 8, 8, 8 },
+               .sampling       = { { 1, 1 }, { 2, 2 }, { 2, 2 } },
        }, {
-               .name           = "YUV 4:2:0 non-contig. 3p, Y/Cr/Cb",
+               .name           = "YUV 4:2:0 non-contiguous 3-planar, Y/Cr/Cb",
                .pixelformat    = V4L2_PIX_FMT_YVU420M,
-               .depth          = { 8, 2, 2 },
                .color          = GSC_YUV420,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CRCB,
                .num_planes     = 3,
                .num_comp       = 3,
+               .depth          = { 8, 8, 8 },
+               .sampling       = { { 1, 1 }, { 2, 2 }, { 2, 2 } },
        }, {
-               .name           = "YUV 4:2:0 n.c. 2p, Y/CbCr tiled",
+               .name           =
+                       "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr, tiled",
                .pixelformat    = V4L2_PIX_FMT_NV12MT_16X16,
-               .depth          = { 8, 4 },
                .color          = GSC_YUV420,
                .yorder         = GSC_LSB_Y,
                .corder         = GSC_CBCR,
                .num_planes     = 2,
                .num_comp       = 2,
-       }
+               .depth          = { 8, 16 },
+               .sampling       = { { 1, 1 }, { 2, 2 } },
+       },
 };
 
 const struct gsc_fmt *get_format(int index)

drivers/media/platform/exynos-gsc/gsc-core.c void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame *frm) · line 410

Quoted 9 lines
drivers/media/platform/exynos-gsc/gsc-core.c +6 -0
@@ -384,6 +402,14 @@ void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame *frm)
                        f_chk_addr, f_chk_len, s_chk_addr, s_chk_len);
 }
 
+static void get_format_size(__u32 width, __u32 height,
+                           const struct gsc_fmt *fmt, int plane,
+                           __u16 *bytesperline, __u32 *sizeimage) {
+       __u16 bpl = ((width * fmt->depth[plane]) / fmt->sampling[plane][0]) / 8;
+       *bytesperline = bpl;
+       *sizeimage = (height * bpl) / fmt->sampling[plane][0];

should use the height sampling instead ?? *sizeimage = (height * bpl) / fmt->sampling[plane][1];

Quoted 130 lines
drivers/media/platform/exynos-gsc/gsc-core.c +35 -40
+}
+
 int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)
 {
        struct gsc_dev *gsc = ctx->gsc_dev;
@@ -448,14 +474,16 @@ int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)
        else /* SD */
                pix_mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
 
-
+       /* V4L2 specifies for contiguous planar formats that bytesperline and
+          sizeimage are set to values appropriate for the first plane. */
        for (i = 0; i < pix_mp->num_planes; ++i) {
-               int bpl = (pix_mp->width * fmt->depth[i]) >> 3;
-               pix_mp->plane_fmt[i].bytesperline = bpl;
-               pix_mp->plane_fmt[i].sizeimage = bpl * pix_mp->height;
+               get_format_size(pix_mp->width, pix_mp->height, fmt, i,
+                               &pix_mp->plane_fmt[i].bytesperline,
+                               &pix_mp->plane_fmt[i].sizeimage);
 
                pr_debug("[%d]: bpl: %d, sizeimage: %d",
-                               i, bpl, pix_mp->plane_fmt[i].sizeimage);
+                               i, pix_mp->plane_fmt[i].bytesperline,
+                               pix_mp->plane_fmt[i].sizeimage);
        }
 
        return 0;
@@ -465,26 +493,27 @@ int gsc_g_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)
 {
        struct gsc_frame *frame;
        struct v4l2_pix_format_mplane *pix_mp;
+       const struct gsc_fmt *fmt;
        int i;
 
        frame = ctx_get_frame(ctx, f->type);
        if (IS_ERR(frame))
                return PTR_ERR(frame);
+       fmt = frame->fmt;
 
        pix_mp = &f->fmt.pix_mp;
 
        pix_mp->width           = frame->f_width;
        pix_mp->height          = frame->f_height;
        pix_mp->field           = V4L2_FIELD_NONE;
-       pix_mp->pixelformat     = frame->fmt->pixelformat;
+       pix_mp->pixelformat     = fmt->pixelformat;
        pix_mp->colorspace      = V4L2_COLORSPACE_REC709;
-       pix_mp->num_planes      = frame->fmt->num_planes;
+       pix_mp->num_planes      = fmt->num_planes;
 
        for (i = 0; i < pix_mp->num_planes; ++i) {
-               pix_mp->plane_fmt[i].bytesperline = (frame->f_width *
-                       frame->fmt->depth[i]) / 8;
-               pix_mp->plane_fmt[i].sizeimage =
-                        pix_mp->plane_fmt[i].bytesperline * frame->f_height;
+               get_format_size(pix_mp->width, pix_mp->height, fmt, i,
+                               &pix_mp->plane_fmt[i].bytesperline,
+                               &pix_mp->plane_fmt[i].sizeimage);
        }
 
        return 0;
@@ -794,11 +823,12 @@ void gsc_ctrls_delete(struct gsc_ctx *ctx)
        }
 }
 
-/* The color format (num_comp, num_planes) must be already configured. */
+/* The color format (num_planes, num_comp) must be already configured. */
 int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb,
                        struct gsc_frame *frame, struct gsc_addr *addr)
 {
        int ret = 0;
+       const struct gsc_fmt *fmt = frame->fmt;
        u32 pix_size;
 
        if ((vb == NULL) || (frame == NULL))
@@ -810,46 +840,30 @@ int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb,
                frame->fmt->num_planes, frame->fmt->num_comp, pix_size);
 
        addr->y = vb2_dma_contig_plane_dma_addr(vb, 0);
-
-       if (frame->fmt->num_planes == 1) {
-               switch (frame->fmt->num_comp) {
-               case 1:
-                       addr->cb = 0;
-                       addr->cr = 0;
-                       break;
-               case 2:
-                       /* decompose Y into Y/Cb */
-                       addr->cb = (dma_addr_t)(addr->y + pix_size);
-                       addr->cr = 0;
-                       break;
-               case 3:
-                       /* decompose Y into Y/Cb/Cr */
-                       addr->cb = (dma_addr_t)(addr->y + pix_size);
-                       if (GSC_YUV420 == frame->fmt->color)
-                               addr->cr = (dma_addr_t)(addr->cb
-                                               + (pix_size >> 2));
-                       else /* 422 */
-                               addr->cr = (dma_addr_t)(addr->cb
-                                               + (pix_size >> 1));
-                       break;
-               default:
-                       pr_err("Invalid the number of color planes");
-                       return -EINVAL;
+       addr->cb = 0;
+       addr->cr = 0;
+
+       if (fmt->num_planes == 1) {
+               if (fmt->num_comp >= 2) {
+                       addr->cb = (dma_addr_t)(addr->y +
+                               ((pix_size * fmt->depth[0]) /
+                               (fmt->sampling[0][0] *
+                                fmt->sampling[0][1]) / 8));
+               }
+               if (fmt->num_comp >= 3) {
+                       addr->cr = (dma_addr_t)(addr->cb +
+                               ((pix_size * fmt->depth[1]) /
+                               (fmt->sampling[1][0] *
+                                fmt->sampling[1][1]) / 8));
                }
        } else {
-               if (frame->fmt->num_planes >= 2)
+               if (fmt->num_comp >= 2)
                        addr->cb = vb2_dma_contig_plane_dma_addr(vb, 1);
-
-               if (frame->fmt->num_planes == 3)
+               if (fmt->num_comp == 3)
                        addr->cr = vb2_dma_contig_plane_dma_addr(vb, 2);
        }
 
Quoted 9 lines

drivers/media/platform/exynos-gsc/gsc-core.c int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb, · line 866

Quoted 7 lines
drivers/media/platform/exynos-gsc/gsc-core.c +1 -6
-       if ((frame->fmt->pixelformat == V4L2_PIX_FMT_VYUY) ||
-               (frame->fmt->pixelformat == V4L2_PIX_FMT_YVYU) ||
-               (frame->fmt->pixelformat == V4L2_PIX_FMT_NV61) ||
-               (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420) ||
-               (frame->fmt->pixelformat == V4L2_PIX_FMT_NV21) ||
-               (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420M))
+       if (fmt->corder == GSC_CRCB)
            if ((fmt->corder == GSC_CRCB) && (fmt->num_planes == 3))

sorry, it is....

               if ((fmt->corder == GSC_CRCB) && (fmt->num_comp == 3))
Quoted 201 lines

I think it shoud only applicable to 3 component formats. for example, Incase of two component formats like V4L2_PIX_FMT_NV61, chroma base address becomes zero.

Regards,
Shaik Ameer Basha

Quoted 192 lines
drivers/media/platform/exynos-gsc/gsc-core.c +0 -0
                swap(addr->cb, addr->cr);
 
        pr_debug("ADDR: y= 0x%X  cb= 0x%X cr= 0x%X ret= %d",
drivers/media/platform/exynos-gsc/gsc-core.h +8 -8
index ef0a6564..8fb07e0d 100644
@@ -106,27 +106,27 @@ enum gsc_yuv_fmt {
        container_of((__ctrl)->handler, struct gsc_ctx, ctrl_handler)
 /**
  * struct gsc_fmt - the driver's internal color format data
- * @mbus_code: Media Bus pixel code, -1 if not applicable
  * @name: format description
  * @pixelformat: the fourcc code for this format, 0 if not applicable
  * @yorder: Y/C order
  * @corder: Chrominance order control
  * @num_planes: number of physically non-contiguous data planes
- * @nr_comp: number of physically contiguous data planes
- * @depth: per plane driver's private 'number of bits per pixel'
- * @flags: flags indicating which operation mode format applies to
+ * @num_comp: number of physically contiguous data planes
+ * @depth: bit depth of each component
+ * @sampling: sampling frequency of each components, X and Y
+ * @mbus_code: Media Bus pixel code, -1 if not applicable
  */
 struct gsc_fmt {
-       enum v4l2_mbus_pixelcode mbus_code;
        char    *name;
        u32     pixelformat;
        u32     color;
        u32     yorder;
        u32     corder;
-       u16     num_planes;
-       u16     num_comp;
+       u8      num_planes;
+       u8      num_comp;
        u8      depth[VIDEO_MAX_PLANES];
-       u32     flags;
+       u8      sampling[VIDEO_MAX_PLANES][2];
+       enum v4l2_mbus_pixelcode mbus_code;
 };
 
 /**
drivers/media/platform/exynos-gsc/gsc-regs.c +22 -18
index e22d147a..a8d6c90b 100644
@@ -167,6 +167,7 @@ void gsc_hw_set_in_image_format(struct gsc_ctx *ctx)
 {
        struct gsc_dev *dev = ctx->gsc_dev;
        struct gsc_frame *frame = &ctx->s_frame;
+       const struct gsc_fmt *fmt = frame->fmt;
        u32 i, depth = 0;
        u32 cfg;
 
@@ -176,21 +177,22 @@ void gsc_hw_set_in_image_format(struct gsc_ctx *ctx)
                 GSC_IN_TILE_TYPE_MASK | GSC_IN_TILE_MODE);
        writel(cfg, dev->regs + GSC_IN_CON);
 
-       if (is_rgb(frame->fmt->color)) {
+       if (is_rgb(fmt->color)) {
                gsc_hw_set_in_image_rgb(ctx);
                return;
        }
-       for (i = 0; i < frame->fmt->num_planes; i++)
-               depth += frame->fmt->depth[i];
+       for (i = 0; i < fmt->num_comp; i++)
+               depth += fmt->depth[i] /
+                       (fmt->sampling[i][0] * fmt->sampling[i][1]);
 
-       switch (frame->fmt->num_comp) {
+       switch (fmt->num_comp) {
        case 1:
                cfg |= GSC_IN_YUV422_1P;
-               if (frame->fmt->yorder == GSC_LSB_Y)
+               if (fmt->yorder == GSC_LSB_Y)
                        cfg |= GSC_IN_YUV422_1P_ORDER_LSB_Y;
                else
-                       cfg |= GSC_IN_YUV422_1P_OEDER_LSB_C;
-               if (frame->fmt->corder == GSC_CBCR)
+                       cfg |= GSC_IN_YUV422_1P_ORDER_LSB_C;
+               if (fmt->corder == GSC_CBCR)
                        cfg |= GSC_IN_CHROMA_ORDER_CBCR;
                else
                        cfg |= GSC_IN_CHROMA_ORDER_CRCB;
@@ -200,7 +202,7 @@ void gsc_hw_set_in_image_format(struct gsc_ctx *ctx)
                        cfg |= GSC_IN_YUV420_2P;
                else
                        cfg |= GSC_IN_YUV422_2P;
-               if (frame->fmt->corder == GSC_CBCR)
+               if (fmt->corder == GSC_CBCR)
                        cfg |= GSC_IN_CHROMA_ORDER_CBCR;
                else
                        cfg |= GSC_IN_CHROMA_ORDER_CRCB;
@@ -213,7 +215,7 @@ void gsc_hw_set_in_image_format(struct gsc_ctx *ctx)
                break;
        }
 
-       if (is_tiled(frame->fmt))
+       if (is_tiled(fmt))
                cfg |= GSC_IN_TILE_C_16x8 | GSC_IN_TILE_MODE;
 
        writel(cfg, dev->regs + GSC_IN_CON);
@@ -287,6 +289,7 @@ void gsc_hw_set_out_image_format(struct gsc_ctx *ctx)
 {
        struct gsc_dev *dev = ctx->gsc_dev;
        struct gsc_frame *frame = &ctx->d_frame;
+       const struct gsc_fmt *fmt = frame->fmt;
        u32 i, depth = 0;
        u32 cfg;
 
@@ -296,7 +299,7 @@ void gsc_hw_set_out_image_format(struct gsc_ctx *ctx)
                 GSC_OUT_TILE_TYPE_MASK | GSC_OUT_TILE_MODE);
        writel(cfg, dev->regs + GSC_OUT_CON);
 
-       if (is_rgb(frame->fmt->color)) {
+       if (is_rgb(fmt->color)) {
                gsc_hw_set_out_image_rgb(ctx);
                return;
        }
@@ -306,17 +309,18 @@ void gsc_hw_set_out_image_format(struct gsc_ctx *ctx)
                goto end_set;
        }
 
-       for (i = 0; i < frame->fmt->num_planes; i++)
-               depth += frame->fmt->depth[i];
+       for (i = 0; i < fmt->num_comp; i++)
+               depth += fmt->depth[i] /
+                       (fmt->sampling[i][0] * fmt->sampling[i][1]);
 
-       switch (frame->fmt->num_comp) {
+       switch (fmt->num_comp) {
        case 1:
                cfg |= GSC_OUT_YUV422_1P;
-               if (frame->fmt->yorder == GSC_LSB_Y)
+               if (fmt->yorder == GSC_LSB_Y)
                        cfg |= GSC_OUT_YUV422_1P_ORDER_LSB_Y;
                else
-                       cfg |= GSC_OUT_YUV422_1P_OEDER_LSB_C;
-               if (frame->fmt->corder == GSC_CBCR)
+                       cfg |= GSC_OUT_YUV422_1P_ORDER_LSB_C;
+               if (fmt->corder == GSC_CBCR)
                        cfg |= GSC_OUT_CHROMA_ORDER_CBCR;
                else
                        cfg |= GSC_OUT_CHROMA_ORDER_CRCB;
@@ -326,7 +330,7 @@ void gsc_hw_set_out_image_format(struct gsc_ctx *ctx)
                        cfg |= GSC_OUT_YUV420_2P;
                else
                        cfg |= GSC_OUT_YUV422_2P;
-               if (frame->fmt->corder == GSC_CBCR)
+               if (fmt->corder == GSC_CBCR)
                        cfg |= GSC_OUT_CHROMA_ORDER_CBCR;
                else
                        cfg |= GSC_OUT_CHROMA_ORDER_CRCB;
@@ -336,7 +340,7 @@ void gsc_hw_set_out_image_format(struct gsc_ctx *ctx)
                break;
        }
 
-       if (is_tiled(frame->fmt))
+       if (is_tiled(fmt))
                cfg |= GSC_OUT_TILE_C_16x8 | GSC_OUT_TILE_MODE;
 
 end_set:
drivers/media/platform/exynos-gsc/gsc-regs.h +2 -3
index 4678f9a6..b03401dc 100644
@@ -46,7 +46,7 @@
 #define GSC_IN_RGB_SD_WIDE             (0 << 14)
 #define GSC_IN_YUV422_1P_ORDER_MASK    (1 << 13)
 #define GSC_IN_YUV422_1P_ORDER_LSB_Y   (0 << 13)
-#define GSC_IN_YUV422_1P_OEDER_LSB_C   (1 << 13)
+#define GSC_IN_YUV422_1P_ORDER_LSB_C   (1 << 13)
 #define GSC_IN_CHROMA_ORDER_MASK       (1 << 12)
 #define GSC_IN_CHROMA_ORDER_CBCR       (0 << 12)
 #define GSC_IN_CHROMA_ORDER_CRCB       (1 << 12)
@@ -91,7 +91,7 @@
 #define GSC_OUT_RGB_SD_NARROW          (0 << 10)
 #define GSC_OUT_YUV422_1P_ORDER_MASK   (1 << 9)
 #define GSC_OUT_YUV422_1P_ORDER_LSB_Y  (0 << 9)
-#define GSC_OUT_YUV422_1P_OEDER_LSB_C  (1 << 9)
+#define GSC_OUT_YUV422_1P_ORDER_LSB_C  (1 << 9)
 #define GSC_OUT_CHROMA_ORDER_MASK      (1 << 8)
 #define GSC_OUT_CHROMA_ORDER_CBCR      (0 << 8)
 #define GSC_OUT_CHROMA_ORDER_CRCB      (1 << 8)
--

1.9.0.279.gdc9e3eb

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

author
#7 lore raw

PATCH 4/4 v4l2-mem2mem: allow reqbufs(0) with "in use" MMAP buffers

In reply to John Sheu

v4l2-mem2mem presently does not allow VIDIOC_REQBUFS to destroy outstanding buffers if the queue is of type V4L2_MEMORY_MMAP, and if the buffers are considered "in use". This is different behavior than for other memory types, and prevents us for deallocating buffers in a few cases:

* In the case that there are outstanding mmap()ed views on the buffer, refcounting on the videobuf2 buffer backing the vm_area will track lifetime appropriately,
* In the case that the buffer has been exported as a DMABUF, refcounting on the videobuf2 bufer backing the DMABUF will track lifetime appropriately.

Remove the specific check for type V4L2_MEMOMRY_MMAP when freeing all buffers through VIDIOC_REQBUFS.

---
 drivers/media/v4l2-core/videobuf2-core.c | 26 +-------------------------
 1 file changed, 1 insertion(+), 25 deletions(-)
drivers/media/v4l2-core/videobuf2-core.c +1 -25
index 8e6695c9..5b6f9da6 100644
@@ -414,8 +414,7 @@ static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b)
 }
 
 /**
- * __buffer_in_use() - return true if the buffer is in use and
- * the queue cannot be freed (by the means of REQBUFS(0)) call
+ * __buffer_in_use() - return true if the buffer is in use.
  */
 static bool __buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb)
 {
@@ -435,20 +434,6 @@ static bool __buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb)
 }
 
 /**
- * __buffers_in_use() - return true if any buffers on the queue are in use and
- * the queue cannot be freed (by the means of REQBUFS(0)) call
- */
-static bool __buffers_in_use(struct vb2_queue *q)
-{
-	unsigned int buffer;
-	for (buffer = 0; buffer < q->num_buffers; ++buffer) {
-		if (__buffer_in_use(q, q->bufs[buffer]))
-			return true;
-	}
-	return false;
-}
-
-/**
  * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be
  * returned to userspace
  */
@@ -681,15 +666,6 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
 	}
 
 	if (req->count == 0 || q->num_buffers != 0 || q->memory != req->memory) {
-		/*
-		 * We already have buffers allocated, so first check if they
-		 * are not in use and can be freed.
-		 */
-		if (q->memory == V4L2_MEMORY_MMAP && __buffers_in_use(q)) {
-			dprintk(1, "reqbufs: memory in use, cannot free\n");
-			return -EBUSY;
-		}
-
 		ret = __vb2_queue_free(q, q->num_buffers);
 		if (ret)
 			return ret;
Signature · 1 line
1.9.0.279.gdc9e3eb
#8 lore raw

RE: [PATCH 4/4] v4l2-mem2mem: allow reqbufs(0) with "in use" MMAP buffers

Pawel, Marek,

Before taking this to my tree I wanted to get an ACK from one of the videobuf2 maintainers. Could you spare a moment to look through this patch?

Best wishes,

Signature · 2 lines
Kamil Debski
Samsung R&D Institute Poland
Quoted 90 lines

-----Original Message-----
From: John Sheu [mailto:[email protected]]
Sent: Tuesday, March 11, 2014 11:52 PM
To: [email protected]
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; John Sheu
Subject: [PATCH 4/4] v4l2-mem2mem: allow reqbufs(0) with "in use" MMAP buffers

v4l2-mem2mem presently does not allow VIDIOC_REQBUFS to destroy outstanding buffers if the queue is of type V4L2_MEMORY_MMAP, and if the buffers are considered "in use". This is different behavior than for other memory types, and prevents us for deallocating buffers in a few
cases:

* In the case that there are outstanding mmap()ed views on the buffer, refcounting on the videobuf2 buffer backing the vm_area will track lifetime appropriately,
* In the case that the buffer has been exported as a DMABUF, refcounting
on the videobuf2 bufer backing the DMABUF will track lifetime appropriately.

Remove the specific check for type V4L2_MEMOMRY_MMAP when freeing all buffers through VIDIOC_REQBUFS.

---
 drivers/media/v4l2-core/videobuf2-core.c | 26 +-----------------------
--
 1 file changed, 1 insertion(+), 25 deletions(-)
drivers/media/v4l2-core/videobuf2-core.c +1 -2
index 8e6695c9..5b6f9da6 100644
@@ -414,8 +414,7 @@ static int __verify_length(struct vb2_buffer *vb,
 const struct v4l2_buffer *b)  }
 
 /**
- * __buffer_in_use() - return true if the buffer is in use and
- * the queue cannot be freed (by the means of REQBUFS(0)) call
+ * __buffer_in_use() - return true if the buffer is in use.
  */
 static bool __buffer_in_use(struct vb2_queue *q, struct vb2_buffer
 *vb)  { @@ -435,20 +434,6 @@ static bool __buffer_in_use(struct

vb2_queue *q, struct vb2_buffer *vb) }

/**
- * __buffers_in_use() - return true if any buffers on the queue are in use and
- * the queue cannot be freed (by the means of REQBUFS(0)) call
- */

drivers/media/v4l2-core/videobuf2-core.c +0 -10
-static bool __buffers_in_use(struct vb2_queue *q) -{
-	unsigned int buffer;
-	for (buffer = 0; buffer < q->num_buffers; ++buffer) {
-		if (__buffer_in_use(q, q->bufs[buffer]))
-			return true;
-	}
-	return false;
-}
-
-/**
  * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with

information to be
* returned to userspace
*/

drivers/media/v4l2-core/videobuf2-core.c +0 -2
@@ -681,15 +666,6 @@ static int __reqbufs(struct vb2_queue *q, struct
 v4l2_requestbuffers *req)
 	}
 
 	if (req->count == 0 || q->num_buffers != 0 || q->memory != req-
 >memory) {
-		/*
-		 * We already have buffers allocated, so first check if

they

drivers/media/v4l2-core/videobuf2-core.c +0 -8
-		 * are not in use and can be freed.
-		 */
-		if (q->memory == V4L2_MEMORY_MMAP && __buffers_in_use(q)) {
-			dprintk(1, "reqbufs: memory in use, cannot free\n");
-			return -EBUSY;
-		}
-
 		ret = __vb2_queue_free(q, q->num_buffers);
 		if (ret)
 			return ret;
--

1.9.0.279.gdc9e3eb

#9 lore raw

Re: [PATCH 4/4] v4l2-mem2mem: allow reqbufs(0) with "in use" MMAP buffers

Hello,

Quoted 5 lines · Kamil Debski

Pawel, Marek,

Before taking this to my tree I wanted to get an ACK from one of the videobuf2 maintainers. Could you spare a moment to look through this patch?

It's not a bug, it is a feature. This was one of the fundamental design requirements to allow applications to track if the memory is used or not.

Best regards

Signature · 2 lines
Marek Szyprowski, PhD
Samsung R&D Institute Poland
#10 lore raw

Re: [PATCH 4/4] v4l2-mem2mem: allow reqbufs(0) with "in use" MMAP buffers

Quoted 11 lines · Marek Szyprowski

Hello,

Quoted 7 lines · Kamil Debski

Pawel, Marek,

Before taking this to my tree I wanted to get an ACK from one of the
videobuf2 maintainers. Could you spare a moment to look through this
patch?

Quoted 4 lines

It's not a bug, it is a feature. This was one of the fundamental design
requirements to allow applications to track if the memory is used or not.

I still have the impression it is not fully correct for the case buffers are exported using DMABUF. Like if the dmabuf was owning the vb2 buffer instead of the opposite ...

Nicolas

#11 lore raw

Re: [PATCH 4/4] v4l2-mem2mem: allow reqbufs(0) with "in use" MMAP buffers

Hi,

2015-11-02 19:31 GMT+01:00 Nicolas Dufresne <[email protected]>:

Quoted 12 lines · Marek Szyprowski
Quoted 11 lines

Hello,

Quoted 7 lines · Kamil Debski

Pawel, Marek,

Before taking this to my tree I wanted to get an ACK from one of the
videobuf2 maintainers. Could you spare a moment to look through this
patch?

Quoted 8 lines
Quoted 4 lines

It's not a bug, it is a feature. This was one of the fundamental design
requirements to allow applications to track if the memory is used or not.

I still have the impression it is not fully correct for the case buffers are exported using DMABUF. Like if the dmabuf was owning the vb2 buffer instead of the opposite ...

I am observing this behaviour too... Tried it, but seems to not do the job on dmabuf buffers... with gstreamer at least ;-).

JM