lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250930040348.3702923-18-h.dewangan@samsung.com>
Date: Tue, 30 Sep 2025 09:33:36 +0530
From: Himanshu Dewangan <h.dewangan@...sung.com>
To: mchehab@...nel.org, robh@...nel.org, krzk+dt@...nel.org,
	conor+dt@...nel.org, sumit.semwal@...aro.org, christian.koenig@....com,
	alim.akhtar@...sung.com, manjun@...sung.com, nagaraju.s@...sung.com,
	ih0206.lee@...sung.com, jehyung.lee@...sung.com
Cc: linux-arm-kernel@...ts.infradead.org, linux-media@...r.kernel.org,
	devicetree@...r.kernel.org, linux-samsung-soc@...r.kernel.org,
	linux-kernel@...r.kernel.org, dri-devel@...ts.freedesktop.org,
	linaro-mm-sig@...ts.linaro.org, Himanshu Dewangan <h.dewangan@...sung.com>
Subject: [PATCH 17/29] media: mfc: Add VB2 decoder support

From: Nagaraju Siddineni <nagaraju.s@...sung.com>

- Implement VB2 queue operations for decoding (setup, buffer handling,
  streaming control, multi‑view and DMA direction support).
- Added header exposing decoder VB2 operations to other MFC components.

This introduces a full VB2 backend for video decoding, aligning the driver
with standard V4L2 buffer management.

Signed-off-by: Nagaraju Siddineni <nagaraju.s@...sung.com>
Signed-off-by: Himanshu Dewangan <h.dewangan@...sung.com>
---
 .../platform/samsung/exynos-mfc/Makefile      |   2 +-
 .../platform/samsung/exynos-mfc/mfc_dec_vb2.c | 393 ++++++++++++++++++
 .../platform/samsung/exynos-mfc/mfc_dec_vb2.h |  19 +
 3 files changed, 413 insertions(+), 1 deletion(-)
 create mode 100644 drivers/media/platform/samsung/exynos-mfc/mfc_dec_vb2.c
 create mode 100644 drivers/media/platform/samsung/exynos-mfc/mfc_dec_vb2.h

diff --git a/drivers/media/platform/samsung/exynos-mfc/Makefile b/drivers/media/platform/samsung/exynos-mfc/Makefile
index 19e38c886255..9127f2dc4df6 100644
--- a/drivers/media/platform/samsung/exynos-mfc/Makefile
+++ b/drivers/media/platform/samsung/exynos-mfc/Makefile
@@ -3,7 +3,7 @@ obj-$(CONFIG_VIDEO_EXYNOS_MFC) := exynos_mfc.o
 ccflags-y += -I$(srctree)/$(src)
 
 #Dev interface layer
-exynos_mfc-y += mfc.o
+exynos_mfc-y += mfc.o mfc_dec_vb2.o
 #Dev control layer
 exynos_mfc-y += mfc_rm.o mfc_ctx_ctrl.o mfc_debugfs.o
 #Core interface layer
diff --git a/drivers/media/platform/samsung/exynos-mfc/mfc_dec_vb2.c b/drivers/media/platform/samsung/exynos-mfc/mfc_dec_vb2.c
new file mode 100644
index 000000000000..3097a6c0bf14
--- /dev/null
+++ b/drivers/media/platform/samsung/exynos-mfc/mfc_dec_vb2.c
@@ -0,0 +1,393 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * mfc_dec_vb2.c file
+ *
+ * Nagaraju Siddineni, <nagaraju.s@...sung.com>
+ * Himanshu Dewangan, <h.dewangan@...sung.com>
+ */
+
+#include "mfc_dec_vb2.h"
+
+#include "mfc_rm.h"
+
+#include "base/mfc_queue.h"
+#include "base/mfc_utils.h"
+#include "base/mfc_buf.h"
+#include "base/mfc_mem.h"
+
+static int mfc_dec_queue_setup(struct vb2_queue *vq,
+			       unsigned int *buf_count, unsigned int *plane_count,
+			       unsigned int psize[], struct device *alloc_devs[])
+{
+	struct mfc_ctx *ctx = vq->drv_priv;
+	struct mfc_dev *dev = ctx->dev;
+	struct mfc_core *core;
+	struct mfc_core_ctx *core_ctx;
+	struct mfc_raw_info *raw;
+	int i, offset;
+
+	mfc_ctx_debug_enter();
+
+	raw = &ctx->raw_buf;
+
+	/*
+	 * During queue_setup,
+	 * context information is need to for only main core
+	 */
+	core = mfc_get_main_core_lock(dev, ctx);
+	core_ctx = core->core_ctx[ctx->num];
+
+	/* Video output for decoding (source)
+	 * this can be set after getting an instance
+	 */
+	if (core_ctx->state == MFCINST_GOT_INST &&
+	    vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		mfc_debug(4, "dec src\n");
+		/* A single plane is required for input */
+		*plane_count = 1;
+		if (*buf_count < 1)
+			*buf_count = 1;
+		if (*buf_count > MFC_MAX_BUFFERS)
+			*buf_count = MFC_MAX_BUFFERS;
+
+		/* need to use minimum size to prevent qbuf fail */
+		psize[0] = 1;
+		alloc_devs[0] = dev->device;
+	/* Video capture for decoding (destination)
+	 * this can be set after the header was parsed
+	 */
+	} else if (core_ctx->state >= MFCINST_HEAD_PARSED &&
+		vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		mfc_debug(4, "dec dst\n");
+		/* Output plane count is different by the pixel format */
+		*plane_count = ctx->num_fd_frame;
+		/* Setup buffer count */
+		if (*buf_count < ctx->dpb_count)
+			*buf_count = ctx->dpb_count;
+		if (*buf_count > MFC_MAX_BUFFERS)
+			*buf_count = MFC_MAX_BUFFERS;
+
+		if (ctx->dst_fmt->mem_planes == 1) {
+			psize[0] = raw->total_plane_size;
+			alloc_devs[0] = dev->device;
+		} else {
+			for (i = 0; i < ctx->dst_fmt->num_planes; i++) {
+				psize[i] = ctx->min_dpb_size[i];
+				alloc_devs[i] = dev->device;
+			}
+		}
+		if (ctx->multi_view_enable) {
+			offset = ctx->view_buf_info[MFC_MV_BUF_IDX_VIEW1].offset;
+			if (ctx->dst_fmt->mem_planes == 1) {
+				psize[offset] = raw->total_plane_size;
+				alloc_devs[offset] = dev->device;
+			} else {
+				for (i = 0; i < ctx->dst_fmt->num_planes; i++) {
+					psize[offset + i] = ctx->min_dpb_size[i];
+					alloc_devs[offset + i] = dev->device;
+				}
+			}
+		}
+
+		/* Decoder DPB should be read for reference */
+		vq->dma_dir = DMA_BIDIRECTIONAL;
+	} else {
+		mfc_err("State seems invalid. State = %d, vq->type = %d\n",
+			core_ctx->state, vq->type);
+		return -EINVAL;
+	}
+
+	mfc_debug(2, "buf_count: %d, plane_count: %d, type: %#x\n",
+		  *buf_count, *plane_count, vq->type);
+	for (i = 0; i < *plane_count; i++)
+		mfc_debug(2, "plane[%d] size: %d\n", i, psize[i]);
+
+	mfc_ctx_debug_leave();
+
+	return 0;
+}
+
+static void mfc_dec_unlock(struct vb2_queue *q)
+{
+	struct mfc_ctx *ctx = q->drv_priv;
+	struct mfc_dev *dev = ctx->dev;
+
+	mutex_unlock(&dev->mfc_mutex);
+}
+
+static void mfc_dec_lock(struct vb2_queue *q)
+{
+	struct mfc_ctx *ctx = q->drv_priv;
+	struct mfc_dev *dev = ctx->dev;
+
+	mutex_lock(&dev->mfc_mutex);
+}
+
+static int mfc_dec_buf_init(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct mfc_ctx *ctx = vq->drv_priv;
+	struct mfc_buf *buf = vb_to_mfc_buf(vb);
+	int ret;
+
+	mfc_ctx_debug_enter();
+
+	if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		ret = mfc_check_vb_with_fmt(ctx->dst_fmt, vb);
+		if (ret < 0)
+			return ret;
+		mfc_calc_base_addr(ctx, vb, ctx->dst_fmt);
+
+		buf->paddr = mfc_mem_get_paddr_vb(vb);
+		mfc_ctx_debug(2, "[DPB] vb index [%d] vb paddr %#llx daddr %#llx\n",
+			      vb->index, buf->paddr, buf->addr[0][0]);
+
+		if (call_cop(ctx, init_buf_ctrls, ctx, MFC_CTRL_TYPE_DST,
+			     vb->index) < 0)
+			mfc_ctx_err("failed in init_buf_ctrls\n");
+	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		ret = mfc_check_vb_with_fmt(ctx->src_fmt, vb);
+		if (ret < 0)
+			return ret;
+
+		buf->addr[0][0] = mfc_mem_get_daddr_vb(vb, 0);
+
+		if (call_cop(ctx, init_buf_ctrls, ctx, MFC_CTRL_TYPE_SRC,
+			     vb->index) < 0)
+			mfc_ctx_err("failed in init_buf_ctrls\n");
+	} else {
+		mfc_ctx_err("unknown queue type\n");
+		return -EINVAL;
+	}
+
+	mfc_ctx_debug_leave();
+
+	return 0;
+}
+
+static int mfc_dec_buf_prepare(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct mfc_ctx *ctx = vq->drv_priv;
+	struct mfc_buf *buf = vb_to_mfc_buf(vb);
+	struct mfc_raw_info *raw;
+	unsigned int index = vb->index;
+	size_t buf_size;
+	int i;
+
+	if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		raw = &ctx->raw_buf;
+		/* check the size per plane */
+		if (ctx->dst_fmt->mem_planes == 1) {
+			buf_size = vb2_plane_size(vb, 0);
+			mfc_ctx_debug(2, "[FRAME] single plane vb size: %lu, calc size: %d\n",
+				      buf_size, raw->total_plane_size);
+			if (buf_size < raw->total_plane_size) {
+				mfc_ctx_err("[FRAME] single plane size(%lu) is smaller than (%d)\n",
+					    buf_size, raw->total_plane_size);
+				return -EINVAL;
+			}
+		} else {
+			for (i = 0; i < ctx->dst_fmt->mem_planes; i++) {
+				buf_size = vb2_plane_size(vb, i);
+				mfc_ctx_debug(2, "[FRAME] plane[%d] vb size: %lu, calc size: %d\n",
+					      i, buf_size, raw->plane_size[i]);
+				if (buf_size < raw->plane_size[i]) {
+					mfc_ctx_err("[FRAME] plane[%d] size(%lu) is smaller than (%d)\n",
+						    i, buf_size, raw->plane_size[i]);
+					return -EINVAL;
+				}
+			}
+		}
+		/* Copy dst buffer flag to buf_ctrl */
+		buf->flag = call_cop(ctx, get_buf_ctrl_val, ctx,
+				     &ctx->dst_ctrls[index],
+				     V4L2_CID_MPEG_VIDEO_DST_BUF_FLAG);
+
+		mfc_mem_buf_prepare(vb, 0);
+	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		buf_size = vb2_plane_size(vb, 0);
+		buf->sg_size = mfc_mem_get_sg_length(ctx->dev, vb2_dma_sg_plane_desc(vb, 0));
+		vb->planes[0].bytesused = buf->vb.planes[0].bytesused;
+		vb->planes[0].data_offset = buf->vb.planes[0].data_offset;
+		mfc_ctx_debug(2, "[STREAM] vb size, %ld, %s, %ld, sg_size, %zu, %s, %u, %s, %u\n",
+			      buf_size,
+			      "dbuf size", vb->planes[0].dbuf->size,
+			      buf->sg_size,
+			      "bytesused", vb->planes[0].bytesused,
+			      "data_offset", vb->planes[0].data_offset);
+
+		call_cop(ctx, to_buf_ctrls, ctx, &ctx->src_ctrls[index]);
+
+		/* Copy src buffer flag to buf_ctrl */
+		buf->flag = call_cop(ctx, get_buf_ctrl_val, ctx,
+				     &ctx->src_ctrls[index],
+				     V4L2_CID_MPEG_VIDEO_SRC_BUF_FLAG);
+
+		mfc_mem_buf_prepare(vb, 1);
+	}
+
+	return 0;
+}
+
+static void mfc_dec_buf_finish(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct mfc_ctx *ctx = vq->drv_priv;
+	struct mfc_buf *buf = vb_to_mfc_buf(vb);
+	unsigned int index = vb->index;
+
+	if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		/* Copy to dst buffer flag */
+		call_cop(ctx, update_buf_val, ctx, &ctx->dst_ctrls[index],
+			 V4L2_CID_MPEG_VIDEO_DST_BUF_FLAG, buf->flag);
+		mfc_ctx_debug(4, "[FLAG] dst update buf[%d] flag = %#x\n",
+			      index, buf->flag);
+
+		call_cop(ctx, to_ctx_ctrls, ctx, &ctx->dst_ctrls[index]);
+
+		mfc_mem_buf_finish(vb, 0);
+	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		/* Copy to src buffer flag */
+		call_cop(ctx, update_buf_val, ctx, &ctx->src_ctrls[index],
+			 V4L2_CID_MPEG_VIDEO_SRC_BUF_FLAG, buf->flag);
+		mfc_ctx_debug(4, "[FLAG] src update buf[%d] flag = %#x\n",
+			      index, buf->flag);
+
+		call_cop(ctx, to_ctx_ctrls, ctx, &ctx->src_ctrls[index]);
+	}
+}
+
+static void mfc_dec_buf_cleanup(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct mfc_ctx *ctx = vq->drv_priv;
+	unsigned int index = vb->index;
+
+	mfc_ctx_debug_enter();
+
+	if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		if (call_cop(ctx, cleanup_buf_ctrls, ctx,
+			     MFC_CTRL_TYPE_DST, index) < 0)
+			mfc_ctx_err("failed in cleanup_buf_ctrls\n");
+	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		if (call_cop(ctx, cleanup_buf_ctrls, ctx,
+			     MFC_CTRL_TYPE_SRC, index) < 0)
+			mfc_ctx_err("failed in cleanup_buf_ctrls\n");
+	} else {
+		mfc_ctx_err("unknown queue type\n");
+	}
+
+	mfc_ctx_debug_leave();
+}
+
+static int mfc_dec_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct mfc_ctx *ctx = q->drv_priv;
+	struct mfc_dev *dev = ctx->dev;
+
+	mfc_rm_update_real_time(ctx);
+
+	mfc_rm_request_work(dev, MFC_WORK_TRY, ctx);
+
+	return 0;
+}
+
+static void mfc_dec_stop_streaming(struct vb2_queue *q)
+{
+	struct mfc_ctx *ctx = q->drv_priv;
+	struct mfc_dev *dev = ctx->dev;
+
+	mfc_ctx_info("dec stop_streaming is called, type : %d\n", q->type);
+	MFC_TRACE_CTX("** DEC streamoff(type:%d)\n", q->type);
+
+	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		mfc_rm_request_work(ctx->dev, MFC_WORK_BUTLER, ctx);
+
+	mfc_rm_instance_dec_stop(dev, ctx, q->type);
+}
+
+static void mfc_dec_buf_queue(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct mfc_ctx *ctx = vq->drv_priv;
+	struct mfc_dev *dev = ctx->dev;
+	struct mfc_dec *dec = ctx->dec_priv;
+	struct mfc_buf *buf = vb_to_mfc_buf(vb);
+	int i;
+	unsigned char *stream_vir = NULL;
+
+	mfc_ctx_debug_enter();
+
+	if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		mutex_lock(&ctx->op_mode_mutex);
+		buf->src_index = ctx->serial_src_index++;
+		mfc_ctx_debug(2, "[BUFINFO] ctx[%d] add src index: %d(%d), addr: 0x%08llx\n",
+			      ctx->num, vb->index, buf->src_index,
+			      buf->addr[0][0]);
+		mutex_unlock(&ctx->op_mode_mutex);
+
+		if (vb->memory == V4L2_MEMORY_DMABUF &&
+		    mfc_rm_query_state(ctx, SMALLER, MFCINST_HEAD_PARSED))
+			stream_vir = vb2_plane_vaddr(vb, 0);
+
+		buf->vir_addr[0] = stream_vir;
+
+		mfc_add_tail_buf(ctx, &ctx->src_buf_ready_queue, buf);
+
+		if (dev->debugfs.debug_ts == 1)
+			mfc_ctx_info("[TS] framerate: %ld, timestamp: %lld\n",
+				     ctx->framerate, buf->vb.vb2_buf.timestamp);
+
+		MFC_TRACE_CTX("Q src[%d](%d) fd: %d, %#llx\n",
+			      vb->index, buf->src_index, vb->planes[0].m.fd, buf->addr[0][0]);
+	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		for (i = 0; i < ctx->num_fd_frame; i++) {
+			// ToDo: if multi_view, vir_addr array_size could be over 3
+			buf->vir_addr[i] = vb2_plane_vaddr(vb, i);
+			mfc_ctx_debug(2, "[BUFINFO] ctx[%d] add dst index: %d, addr[0][%d]: 0x%08llx\n",
+				      ctx->num, vb->index, i, buf->addr[0][i]);
+			if (ctx->multi_view_enable) {
+				mfc_ctx_debug(2, "[BUFINFO-VIEW1] ctx[%d] add dst index: %d, addr[2][%d]: 0x%08llx\n",
+					      ctx->num, vb->index, i, buf->addr[2][i]);
+			}
+		}
+		mfc_store_dpb(ctx, vb);
+
+		if ((vb->memory == V4L2_MEMORY_USERPTR || vb->memory == V4L2_MEMORY_DMABUF) &&
+		    mfc_is_queue_count_same(&ctx->buf_queue_lock,
+					    &ctx->dst_buf_queue, dec->total_dpb_count))
+			ctx->capture_state = QUEUE_BUFS_MMAPED;
+
+		MFC_TRACE_CTX("Q dst[%d][%d] fd: %d, %#llx / used %#lx\n",
+			      vb->index, buf->dpb_index, vb->planes[0].m.fd,
+			      buf->addr[0][0], dec->dynamic_used);
+	} else {
+		mfc_ctx_err("Unsupported buffer type (%d)\n", vq->type);
+	}
+
+	mfc_rm_request_work(dev, MFC_WORK_TRY, ctx);
+
+	mfc_ctx_debug_leave();
+}
+
+static const struct vb2_ops mfc_dec_qops = {
+	.queue_setup		= mfc_dec_queue_setup,
+	.wait_prepare		= mfc_dec_unlock,
+	.wait_finish		= mfc_dec_lock,
+	.buf_init		= mfc_dec_buf_init,
+	.buf_prepare		= mfc_dec_buf_prepare,
+	.buf_finish		= mfc_dec_buf_finish,
+	.buf_cleanup		= mfc_dec_buf_cleanup,
+	.start_streaming	= mfc_dec_start_streaming,
+	.stop_streaming		= mfc_dec_stop_streaming,
+	.buf_queue		= mfc_dec_buf_queue,
+};
+
+const struct vb2_ops *mfc_get_dec_vb2_ops(void)
+{
+	return &mfc_dec_qops;
+}
diff --git a/drivers/media/platform/samsung/exynos-mfc/mfc_dec_vb2.h b/drivers/media/platform/samsung/exynos-mfc/mfc_dec_vb2.h
new file mode 100644
index 000000000000..3d0cb7b14ce5
--- /dev/null
+++ b/drivers/media/platform/samsung/exynos-mfc/mfc_dec_vb2.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * mfc_dec_vb2.h file
+ *
+ * Nagaraju Siddineni, <nagaraju.s@...sung.com>
+ * Himanshu Dewangan, <h.dewangan@...sung.com>
+ */
+
+#ifndef __MFC_DEC_VB2_H
+#define __MFC_DEC_VB2_H __FILE__
+
+#include "base/mfc_common.h"
+
+const struct vb2_ops *mfc_get_dec_vb2_ops(void);
+
+#endif /* __MFC_DEC_VB2_H */
-- 
2.34.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ