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
