From: Nagaraju Siddineni <[email protected]>

- 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 <[email protected]>
Signed-off-by: Himanshu Dewangan <[email protected]>
---
 .../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, <[email protected]>
+ * Himanshu Dewangan, <[email protected]>
+ */
+
+#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, <[email protected]>
+ * Himanshu Dewangan, <[email protected]>
+ */
+
+#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

Reply via email to