[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250930040348.3702923-15-h.dewangan@samsung.com>
Date: Tue, 30 Sep 2025 09:33:33 +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 14/29] media: mfc: Add buffer‑control framework
From: Nagaraju Siddineni <nagaraju.s@...sung.com>
- Add core buffer‑control module (mfc_core_buf_ctrl.c)
with set/get/recover/restore ops.
- Add context‑control layer (mfc_ctx_ctrl.c) defining
V4L2 decoder controls and per‑buffer handling.
- Export mfc_bufs_ops and mfc_ctrls_ops for integration
with existing MFC core
Provide flexible V4L2‑based management of hardware registers,
including volatile/non‑volatile settings and buffer‑level
restore/recovery.
Signed-off-by: Nagaraju Siddineni <nagaraju.s@...sung.com>
Signed-off-by: Himanshu Dewangan <h.dewangan@...sung.com>
---
.../platform/samsung/exynos-mfc/Makefile | 4 +-
.../samsung/exynos-mfc/mfc_core_buf_ctrl.c | 160 +++++
.../samsung/exynos-mfc/mfc_ctx_ctrl.c | 666 ++++++++++++++++++
3 files changed, 828 insertions(+), 2 deletions(-)
create mode 100644 drivers/media/platform/samsung/exynos-mfc/mfc_core_buf_ctrl.c
create mode 100644 drivers/media/platform/samsung/exynos-mfc/mfc_ctx_ctrl.c
diff --git a/drivers/media/platform/samsung/exynos-mfc/Makefile b/drivers/media/platform/samsung/exynos-mfc/Makefile
index 9def2686cd4e..19e38c886255 100644
--- a/drivers/media/platform/samsung/exynos-mfc/Makefile
+++ b/drivers/media/platform/samsung/exynos-mfc/Makefile
@@ -5,7 +5,7 @@ ccflags-y += -I$(srctree)/$(src)
#Dev interface layer
exynos_mfc-y += mfc.o
#Dev control layer
-exynos_mfc-y += mfc_rm.o mfc_debugfs.o
+exynos_mfc-y += mfc_rm.o mfc_ctx_ctrl.o mfc_debugfs.o
#Core interface layer
exynos_mfc-y += mfc_core.o mfc_core_ops.o mfc_core_isr.o
#Core control layer
@@ -13,7 +13,7 @@ exynos_mfc-y += mfc_core_hwlock.o mfc_core_intlock.o mfc_core_run.o
exynos_mfc-y += mfc_core_pm.o
exynos_mfc-y += mfc_core_sync.o mfc_core_sched_prio.o
#Core HW access layer
-exynos_mfc-y += mfc_core_cmd.o
+exynos_mfc-y += mfc_core_buf_ctrl.o mfc_core_cmd.o
exynos_mfc-y += mfc_core_hw_reg_api.o mfc_core_reg_api.o
#Plugin interface layer
#Plugin control layer
diff --git a/drivers/media/platform/samsung/exynos-mfc/mfc_core_buf_ctrl.c b/drivers/media/platform/samsung/exynos-mfc/mfc_core_buf_ctrl.c
new file mode 100644
index 000000000000..56dc3e734d02
--- /dev/null
+++ b/drivers/media/platform/samsung/exynos-mfc/mfc_core_buf_ctrl.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * mfc_core_buf_ctrl.c file
+ *
+ * Nagaraju Siddineni, <nagaraju.s@...sung.com>
+ * Himanshu Dewangan, <h.dewangan@...sung.com>
+ */
+
+#include "mfc_core_reg_api.h"
+
+static int mfc_core_set_buf_ctrls(struct mfc_core *core,
+ struct mfc_ctx *ctx, struct list_head *head)
+{
+ struct mfc_buf_ctrl *buf_ctrl;
+ unsigned int value = 0;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET) || !buf_ctrl->has_new)
+ continue;
+
+ if (buf_ctrl->mode == MFC_CTRL_MODE_SFR) {
+ /* read old vlaue */
+ value = MFC_CORE_READL(buf_ctrl->addr);
+
+ /* save old vlaue for recovery */
+ if (buf_ctrl->is_volatile)
+ buf_ctrl->old_val =
+ (value >> buf_ctrl->shft) & buf_ctrl->mask;
+
+ /* write new value */
+ value &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ value |=
+ ((buf_ctrl->val & buf_ctrl->mask)
+ << buf_ctrl->shft);
+ MFC_CORE_WRITEL(value, buf_ctrl->addr);
+ }
+
+ /* set change flag bit */
+ if (buf_ctrl->flag_mode == MFC_CTRL_MODE_SFR) {
+ value = MFC_CORE_READL(buf_ctrl->flag_addr);
+ value |= BIT(buf_ctrl->flag_shft);
+ MFC_CORE_WRITEL(value, buf_ctrl->flag_addr);
+ }
+
+ buf_ctrl->has_new = 0;
+ buf_ctrl->updated = 1;
+
+ if (buf_ctrl->id == V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG)
+ ctx->stored_tag = buf_ctrl->val;
+
+ mfc_ctx_debug(6,
+ "[CTRLS] Set buffer control id: 0x%08x, val: %d (%#x)\n",
+ buf_ctrl->id, buf_ctrl->val, buf_ctrl->val);
+ }
+
+ return 0;
+}
+
+static int mfc_core_get_buf_ctrls(struct mfc_core *core,
+ struct mfc_ctx *ctx, struct list_head *head)
+{
+ struct mfc_buf_ctrl *buf_ctrl;
+ unsigned int value = 0;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_GET))
+ continue;
+
+ if (buf_ctrl->mode == MFC_CTRL_MODE_SFR)
+ value = MFC_CORE_READL(buf_ctrl->addr);
+
+ value = (value >> buf_ctrl->shft) & buf_ctrl->mask;
+
+ buf_ctrl->val = value;
+ buf_ctrl->has_new = 1;
+
+ if (buf_ctrl->id == V4L2_CID_MPEG_VIDEO_FRAME_ERROR_TYPE)
+ buf_ctrl->val = mfc_get_frame_error_type(ctx, value);
+
+ mfc_ctx_debug(6,
+ "[CTRLS] Get buffer control id: 0x%08x, val: %d (%#x)\n",
+ buf_ctrl->id, buf_ctrl->val, buf_ctrl->val);
+ }
+
+ return 0;
+}
+
+static int mfc_core_recover_buf_ctrls(struct mfc_core *core,
+ struct mfc_ctx *ctx,
+ struct list_head *head)
+{
+ struct mfc_buf_ctrl *buf_ctrl;
+ unsigned int value = 0;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET) ||
+ !buf_ctrl->is_volatile || !buf_ctrl->updated)
+ continue;
+
+ if (buf_ctrl->mode == MFC_CTRL_MODE_SFR) {
+ value = MFC_CORE_READL(buf_ctrl->addr);
+ value &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ value |=
+ ((buf_ctrl->old_val & buf_ctrl->mask)
+ << buf_ctrl->shft);
+ MFC_CORE_WRITEL(value, buf_ctrl->addr);
+ }
+
+ /* clear change flag bit */
+ if (buf_ctrl->flag_mode == MFC_CTRL_MODE_SFR) {
+ value = MFC_CORE_READL(buf_ctrl->flag_addr);
+ value &= ~BIT(buf_ctrl->flag_shft);
+ MFC_CORE_WRITEL(value, buf_ctrl->flag_addr);
+ }
+
+ buf_ctrl->updated = 0;
+ mfc_ctx_debug(6,
+ "[CTRLS] Recover buffer control id: 0x%08x, old val: %d\n",
+ buf_ctrl->id, buf_ctrl->old_val);
+ }
+
+ return 0;
+}
+
+/*
+ * This function is used when you want to restore buffer ctrls.
+ * 1) NAL_Q stop: It is enqueued in the NAL_Q queue,
+ * but it must be restored because HW is not used.
+ * 2) DRC: The input buffer that caused the DRC was used for HW, but it must be reused.
+ */
+static int mfc_core_restore_buf_ctrls(struct mfc_ctx *ctx,
+ struct list_head *head)
+{
+ struct mfc_buf_ctrl *buf_ctrl;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET) ||
+ !(buf_ctrl->updated))
+ continue;
+
+ buf_ctrl->has_new = 1;
+ buf_ctrl->updated = 0;
+
+ mfc_ctx_debug(6,
+ "[CTRLS] Restore buffer control id: 0x%08x, val: %d\n",
+ buf_ctrl->id, buf_ctrl->val);
+ }
+
+ return 0;
+}
+
+struct mfc_bufs_ops mfc_bufs_ops = {
+ .core_set_buf_ctrls = mfc_core_set_buf_ctrls,
+ .core_get_buf_ctrls = mfc_core_get_buf_ctrls,
+ .core_recover_buf_ctrls = mfc_core_recover_buf_ctrls,
+ .core_restore_buf_ctrls = mfc_core_restore_buf_ctrls,
+};
diff --git a/drivers/media/platform/samsung/exynos-mfc/mfc_ctx_ctrl.c b/drivers/media/platform/samsung/exynos-mfc/mfc_ctx_ctrl.c
new file mode 100644
index 000000000000..8846230f1e20
--- /dev/null
+++ b/drivers/media/platform/samsung/exynos-mfc/mfc_ctx_ctrl.c
@@ -0,0 +1,666 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * mfc_ctx_ctrl.c file
+ *
+ * Nagaraju Siddineni, <nagaraju.s@...sung.com>
+ * Himanshu Dewangan, <h.dewangan@...sung.com>
+ */
+
+#include "base/mfc_common.h"
+
+static struct mfc_ctrl_cfg mfc_dec_ctrl_list[] = {
+ {
+ .type = MFC_CTRL_TYPE_SET_SRC,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_PICTURE_TAG,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_RET_PICTURE_TAG_TOP,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_DISPLAY_STATUS,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_DISPLAY_STATUS,
+ .mask = 0x7,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ /* CRC related definitions are based on non-H.264 type */
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_LUMA,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_DISPLAY_FIRST_PLANE_CRC,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_CHROMA,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_DISPLAY_SECOND_PLANE_CRC,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_CHROMA1,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_DISPLAY_THIRD_PLANE_CRC,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_2BIT_LUMA,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_DISPLAY_FIRST_PLANE_2BIT_CRC,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_2BIT_CHROMA,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_DISPLAY_SECOND_PLANE_2BIT_CRC,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_GENERATED,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_DISPLAY_STATUS,
+ .mask = 0x1,
+ .shft = 6,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_AVAIL,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_SEI_AVAIL,
+ .mask = 0x1,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRGMENT_ID,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_FRAME_PACK_ARRGMENT_ID,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_INFO,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_FRAME_PACK_SEI_INFO,
+ .mask = 0x3FFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_GRID_POS,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_FRAME_PACK_GRID_POS,
+ .mask = 0xFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_H264_MVC_VIEW_ID,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_MVC_VIEW_ID,
+ .mask = 0xFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_SEI_MAX_PIC_AVERAGE_LIGHT,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_CONTENT_LIGHT_LEVEL_INFO_SEI,
+ .mask = 0xFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_SEI_MAX_CONTENT_LIGHT,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_CONTENT_LIGHT_LEVEL_INFO_SEI,
+ .mask = 0xFFFF,
+ .shft = 16,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_SEI_MAX_DISPLAY_LUMINANCE,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_0,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_SEI_MIN_DISPLAY_LUMINANCE,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_1,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_MATRIX_COEFFICIENTS,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_VIDEO_SIGNAL_TYPE,
+ .mask = 0xFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_FORMAT,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_VIDEO_SIGNAL_TYPE,
+ .mask = 0x7,
+ .shft = 26,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_FULL_RANGE_FLAG,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_VIDEO_SIGNAL_TYPE,
+ .mask = 0x1,
+ .shft = 25,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_COLOUR_PRIMARIES,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_VIDEO_SIGNAL_TYPE,
+ .mask = 0xFF,
+ .shft = 16,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_TRANSFER_CHARACTERISTICS,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_VIDEO_SIGNAL_TYPE,
+ .mask = 0xFF,
+ .shft = 8,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_SEI_WHITE_POINT,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_2,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_0,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_3,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_1,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_4,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_2,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_5,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_POC,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_D_RET_PICTURE_TIME_TOP,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_FRAME_ERROR_TYPE,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = MFC_REG_ERROR_CODE,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ { /* buffer additional information */
+ .type = MFC_CTRL_TYPE_SRC,
+ .id = V4L2_CID_MPEG_VIDEO_SRC_BUF_FLAG,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_NONE,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ },
+ { /* buffer additional information */
+ .type = MFC_CTRL_TYPE_DST,
+ .id = V4L2_CID_MPEG_VIDEO_DST_BUF_FLAG,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_NONE,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ }
+};
+
+#define NUM_DEC_CTRL_CFGS ARRAY_SIZE(mfc_dec_ctrl_list)
+
+static void mfc_ctrl_cleanup_ctx(struct mfc_ctx *ctx)
+{
+ struct mfc_ctx_ctrl *ctx_ctrl;
+
+ while (!list_empty(&ctx->ctrls)) {
+ ctx_ctrl = list_entry((&ctx->ctrls)->next,
+ struct mfc_ctx_ctrl, list);
+ list_del(&ctx_ctrl->list);
+ kfree(ctx_ctrl);
+ }
+
+ INIT_LIST_HEAD(&ctx->ctrls);
+}
+
+static int __mfc_ctrl_init_ctx(struct mfc_ctx *ctx, struct mfc_ctrl_cfg *ctrl_list, int count)
+{
+ unsigned long i;
+ struct mfc_ctx_ctrl *ctx_ctrl;
+
+ INIT_LIST_HEAD(&ctx->ctrls);
+
+ for (i = 0; i < count; i++) {
+ ctx_ctrl = kzalloc(sizeof(*ctx_ctrl), GFP_KERNEL);
+ if (!ctx_ctrl) {
+ mfc_ctrl_cleanup_ctx(ctx);
+
+ return -ENOMEM;
+ }
+
+ ctx_ctrl->type = ctrl_list[i].type;
+ ctx_ctrl->id = ctrl_list[i].id;
+ ctx_ctrl->addr = ctrl_list[i].addr;
+ ctx_ctrl->set.has_new = 0;
+ ctx_ctrl->set.val = 0;
+ ctx_ctrl->get.has_new = 0;
+ ctx_ctrl->get.val = 0;
+
+ list_add_tail(&ctx_ctrl->list, &ctx->ctrls);
+ }
+
+ return 0;
+}
+
+static int mfc_ctrl_init_ctx(struct mfc_ctx *ctx)
+{
+ if (ctx->type == MFCINST_DECODER)
+ return __mfc_ctrl_init_ctx(ctx, mfc_dec_ctrl_list, NUM_DEC_CTRL_CFGS);
+
+ mfc_ctx_err("[CTRLS] invalid type %d\n", ctx->type);
+ return -EINVAL;
+}
+
+static void mfc_ctrl_reset_buf(struct list_head *head)
+{
+ struct mfc_buf_ctrl *buf_ctrl;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ buf_ctrl->has_new = 0;
+ buf_ctrl->val = 0;
+ buf_ctrl->old_val = 0;
+ buf_ctrl->updated = 0;
+ }
+}
+
+static void __mfc_ctrl_cleanup_buf(struct list_head *head)
+{
+ struct mfc_buf_ctrl *buf_ctrl;
+
+ while (!list_empty(head)) {
+ buf_ctrl = list_entry(head->next,
+ struct mfc_buf_ctrl, list);
+ list_del(&buf_ctrl->list);
+ kfree(buf_ctrl);
+ }
+
+ INIT_LIST_HEAD(head);
+}
+
+static int mfc_ctrl_cleanup_buf(struct mfc_ctx *ctx, enum mfc_ctrl_type type, unsigned int index)
+{
+ struct list_head *head;
+
+ if (index >= MFC_MAX_BUFFERS) {
+ mfc_ctx_err("Per-buffer control index is out of range\n");
+ return -EINVAL;
+ }
+
+ if (type & MFC_CTRL_TYPE_SRC) {
+ if (!(test_and_clear_bit(index, ctx->src_ctrls_avail)))
+ return 0;
+
+ head = &ctx->src_ctrls[index];
+ } else if (type & MFC_CTRL_TYPE_DST) {
+ if (!(test_and_clear_bit(index, ctx->dst_ctrls_avail)))
+ return 0;
+
+ head = &ctx->dst_ctrls[index];
+ } else {
+ mfc_ctx_err("Control type mismatch. type : %d\n", type);
+ return -EINVAL;
+ }
+
+ __mfc_ctrl_cleanup_buf(head);
+
+ return 0;
+}
+
+static int __mfc_ctrl_init_buf(struct mfc_ctx *ctx, struct mfc_ctrl_cfg *ctrl_list,
+ enum mfc_ctrl_type type, unsigned int index, int count)
+{
+ unsigned long i;
+ struct mfc_buf_ctrl *buf_ctrl;
+ struct list_head *head;
+
+ if (index >= MFC_MAX_BUFFERS) {
+ mfc_ctx_err("Per-buffer control index is out of range\n");
+ return -EINVAL;
+ }
+
+ if (type & MFC_CTRL_TYPE_SRC) {
+ if (test_bit(index, ctx->src_ctrls_avail)) {
+ mfc_ctrl_reset_buf(&ctx->src_ctrls[index]);
+
+ return 0;
+ }
+
+ head = &ctx->src_ctrls[index];
+ } else if (type & MFC_CTRL_TYPE_DST) {
+ if (test_bit(index, ctx->dst_ctrls_avail)) {
+ mfc_ctrl_reset_buf(&ctx->dst_ctrls[index]);
+
+ return 0;
+ }
+
+ head = &ctx->dst_ctrls[index];
+ } else {
+ mfc_ctx_err("Control type mismatch. type : %d\n", type);
+ return -EINVAL;
+ }
+
+ INIT_LIST_HEAD(head);
+
+ for (i = 0; i < count; i++) {
+ if (!(type & ctrl_list[i].type))
+ continue;
+
+ buf_ctrl = kzalloc(sizeof(*buf_ctrl), GFP_KERNEL);
+ if (!buf_ctrl) {
+ __mfc_ctrl_cleanup_buf(head);
+
+ return -ENOMEM;
+ }
+
+ buf_ctrl->type = ctrl_list[i].type;
+ buf_ctrl->id = ctrl_list[i].id;
+ buf_ctrl->is_volatile = ctrl_list[i].is_volatile;
+ buf_ctrl->mode = ctrl_list[i].mode;
+ buf_ctrl->addr = ctrl_list[i].addr;
+ buf_ctrl->mask = ctrl_list[i].mask;
+ buf_ctrl->shft = ctrl_list[i].shft;
+ buf_ctrl->flag_mode = ctrl_list[i].flag_mode;
+ buf_ctrl->flag_addr = ctrl_list[i].flag_addr;
+ buf_ctrl->flag_shft = ctrl_list[i].flag_shft;
+
+ list_add_tail(&buf_ctrl->list, head);
+ }
+
+ mfc_ctrl_reset_buf(head);
+
+ if (type & MFC_CTRL_TYPE_SRC)
+ set_bit(index, ctx->src_ctrls_avail);
+ else
+ set_bit(index, ctx->dst_ctrls_avail);
+
+ return 0;
+}
+
+static int mfc_ctrl_init_buf(struct mfc_ctx *ctx, enum mfc_ctrl_type type, unsigned int index)
+{
+ if (ctx->type == MFCINST_DECODER)
+ return __mfc_ctrl_init_buf(ctx, mfc_dec_ctrl_list, type, index, NUM_DEC_CTRL_CFGS);
+
+ mfc_ctx_err("[CTRLS] invalid type %d\n", ctx->type);
+ return -EINVAL;
+}
+
+static void mfc_ctrl_to_buf(struct mfc_ctx *ctx, struct list_head *head)
+{
+ struct mfc_ctx_ctrl *ctx_ctrl;
+ struct mfc_buf_ctrl *buf_ctrl;
+
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ if (!(ctx_ctrl->type & MFC_CTRL_TYPE_SET) ||
+ !ctx_ctrl->set.has_new)
+ continue;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET))
+ continue;
+
+ if (buf_ctrl->id == ctx_ctrl->id) {
+ buf_ctrl->has_new = 1;
+ buf_ctrl->val = ctx_ctrl->set.val;
+
+ if (buf_ctrl->is_volatile)
+ buf_ctrl->updated = 0;
+
+ ctx_ctrl->set.has_new = 0;
+
+ break;
+ }
+ }
+ }
+}
+
+static void mfc_ctrl_to_ctx(struct mfc_ctx *ctx, struct list_head *head)
+{
+ struct mfc_ctx_ctrl *ctx_ctrl;
+ struct mfc_buf_ctrl *buf_ctrl;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_GET) || !buf_ctrl->has_new)
+ continue;
+
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ if (!(ctx_ctrl->type & MFC_CTRL_TYPE_GET))
+ continue;
+
+ if (ctx_ctrl->id == buf_ctrl->id) {
+ if (ctx_ctrl->get.has_new)
+ mfc_ctx_debug(8, "Overwrite ctx_ctrl value id: %#x, val: %d\n",
+ ctx_ctrl->id, ctx_ctrl->get.val);
+
+ ctx_ctrl->get.has_new = 1;
+ ctx_ctrl->get.val = buf_ctrl->val;
+
+ buf_ctrl->has_new = 0;
+ }
+ }
+ }
+}
+
+static int mfc_ctrl_get_buf_val(struct mfc_ctx *ctx, struct list_head *head, unsigned int id)
+{
+ struct mfc_buf_ctrl *buf_ctrl;
+ int value = 0;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (buf_ctrl->id == id) {
+ value = buf_ctrl->val;
+ mfc_ctx_debug(6, "[CTRLS] Get buffer control id: 0x%08x, val: %d (%#x)\n",
+ buf_ctrl->id, value, value);
+ break;
+ }
+ }
+
+ return value;
+}
+
+static void mfc_ctrl_update_buf_val(struct mfc_ctx *ctx, struct list_head *head,
+ unsigned int id, int value)
+{
+ struct mfc_buf_ctrl *buf_ctrl;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (buf_ctrl->id == id) {
+ buf_ctrl->val = value;
+ mfc_ctx_debug(6, "[CTRLS] Update buffer control id: 0x%08x, val: %d (%#x)\n",
+ buf_ctrl->id, buf_ctrl->val, buf_ctrl->val);
+ break;
+ }
+ }
+}
+
+struct mfc_ctrls_ops mfc_ctrls_ops = {
+ .cleanup_ctx_ctrls = mfc_ctrl_cleanup_ctx,
+ .init_ctx_ctrls = mfc_ctrl_init_ctx,
+ .reset_buf_ctrls = mfc_ctrl_reset_buf,
+ .cleanup_buf_ctrls = mfc_ctrl_cleanup_buf,
+ .init_buf_ctrls = mfc_ctrl_init_buf,
+ .to_buf_ctrls = mfc_ctrl_to_buf,
+ .to_ctx_ctrls = mfc_ctrl_to_ctx,
+ .get_buf_ctrl_val = mfc_ctrl_get_buf_val,
+ .update_buf_val = mfc_ctrl_update_buf_val,
+};
--
2.34.1
Powered by blists - more mailing lists