From: Nagaraju Siddineni <[email protected]>

- Integrate encoder command API into core flow.
- Extend hardware‑lock handling for encoder state.
- Manage encoder resources on instance open/close.
- Add APIs for buffers, codec parameters, and status.
- Update core ops, macros, headers, and error handling.

Signed-off-by: Nagaraju Siddineni <[email protected]>
Signed-off-by: Himanshu Dewangan <[email protected]>
---
 .../samsung/exynos-mfc/mfc_core_cmd.c         | 119 ++++++++++++
 .../samsung/exynos-mfc/mfc_core_cmd.h         |   6 +
 .../samsung/exynos-mfc/mfc_core_hwlock.c      |  61 +++++++
 .../samsung/exynos-mfc/mfc_core_ops.c         | 154 ++++++++++++++++
 .../samsung/exynos-mfc/mfc_core_reg_api.c     | 169 ++++++++++++++++++
 .../samsung/exynos-mfc/mfc_core_reg_api.h     |  55 ++++++
 .../samsung/exynos-mfc/mfc_core_run.c         | 127 +++++++++++++
 .../samsung/exynos-mfc/mfc_core_run.h         |   5 +
 8 files changed, 696 insertions(+)

diff --git a/drivers/media/platform/samsung/exynos-mfc/mfc_core_cmd.c 
b/drivers/media/platform/samsung/exynos-mfc/mfc_core_cmd.c
index aaf216741575..a1de7920786b 100644
--- a/drivers/media/platform/samsung/exynos-mfc/mfc_core_cmd.c
+++ b/drivers/media/platform/samsung/exynos-mfc/mfc_core_cmd.c
@@ -12,6 +12,7 @@
 #include "mfc_core_cmd.h"
 #include "mfc_core_intlock.h"
 
+#include "mfc_core_enc_param.h"
 #include "mfc_core_hw_reg_api.h"
 
 #include "base/mfc_utils.h"
@@ -286,6 +287,28 @@ void mfc_core_cmd_dec_seq_header(struct mfc_core *core, 
struct mfc_ctx *ctx)
        mfc_debug_leave();
 }
 
+int mfc_core_cmd_enc_seq_header(struct mfc_core *core, struct mfc_ctx *ctx)
+{
+       struct mfc_core_ctx *core_ctx = core->core_ctx[ctx->num];
+       int ret;
+
+       mfc_debug_enter();
+
+       ret = mfc_core_set_enc_params(core, ctx);
+       if (ret) {
+               mfc_debug(2, "fail to set enc params\n");
+               return ret;
+       }
+
+       MFC_CORE_WRITEL(core_ctx->inst_no, MFC_REG_INSTANCE_ID);
+
+       mfc_core_cmd_host2risc(core, MFC_REG_H2R_CMD_SEQ_HEADER);
+
+       mfc_debug_leave();
+
+       return 0;
+}
+
 int mfc_core_cmd_dec_init_buffers(struct mfc_core *core, struct mfc_ctx *ctx)
 {
        struct mfc_core_ctx *core_ctx = core->core_ctx[ctx->num];
@@ -326,6 +349,58 @@ int mfc_core_cmd_dec_init_buffers(struct mfc_core *core, 
struct mfc_ctx *ctx)
        return ret;
 }
 
+int mfc_core_cmd_enc_init_buffers(struct mfc_core *core, struct mfc_ctx *ctx)
+{
+       struct mfc_core_ctx *core_ctx = core->core_ctx[ctx->num];
+       unsigned int reg = 0;
+       int ret;
+
+       /*
+        * Header was generated now starting processing
+        * First set the reference frame buffers
+        */
+       if (!core_ctx->codec_buffer_allocated) {
+               mfc_info("there isn't codec buffer, re-alloc!\n");
+               ret = mfc_alloc_codec_buffers(core_ctx);
+               if (ret) {
+                       mfc_err("Failed to allocate encoding buffers\n");
+                       mfc_change_state(core_ctx, MFCINST_ERROR);
+                       return ret;
+               }
+       }
+
+       mfc_clean_core_ctx_int_flags(core_ctx);
+       ret = mfc_core_set_enc_codec_buffers(core_ctx);
+       if (ret) {
+               mfc_info("isn't enough codec buffer size, re-alloc!\n");
+
+               mfc_release_codec_buffers(core_ctx);
+               ret = mfc_alloc_codec_buffers(core_ctx);
+               if (ret) {
+                       mfc_err("Failed to allocate encoding buffers\n");
+                       return ret;
+               }
+               ret = mfc_core_set_enc_codec_buffers(core_ctx);
+               if (ret) {
+                       mfc_err("Failed to set enc codec buffers\n");
+                       return ret;
+               }
+       }
+
+       if (IS_MULTI_MODE(ctx)) {
+               reg |= ((ctx->subcore_inst_no & 
MFC_REG_RET_INSTANCE_ID_OF_MFC1_MASK)
+                       << MFC_REG_RET_INSTANCE_ID_OF_MFC1_SHIFT);
+               reg |= (core_ctx->inst_no & MFC_REG_RET_INSTANCE_ID_MASK);
+               MFC_CORE_WRITEL(reg, MFC_REG_INSTANCE_ID);
+       } else {
+               MFC_CORE_WRITEL(core_ctx->inst_no, MFC_REG_INSTANCE_ID);
+       }
+
+       mfc_core_cmd_host2risc(core, MFC_REG_H2R_CMD_INIT_BUFFERS);
+
+       return ret;
+}
+
 static int __mfc_set_scratch_dpb_buffer(struct mfc_core *core, struct mfc_ctx 
*ctx)
 {
        struct mfc_core_ctx *core_ctx = core->core_ctx[ctx->num];
@@ -455,3 +530,47 @@ int mfc_core_cmd_dec_one_frame(struct mfc_core *core, 
struct mfc_ctx *ctx,
        mfc_debug(2, "Decoding a usual frame\n");
        return 0;
 }
+
+/* Encode a single frame */
+void mfc_core_cmd_enc_one_frame(struct mfc_core *core, struct mfc_ctx *ctx,
+                               int last_frame)
+{
+       struct mfc_core_ctx *core_ctx = core->core_ctx[ctx->num];
+       u32 timeout_value = MFC_TIMEOUT_VALUE;
+       unsigned int reg = 0;
+
+       mfc_debug_enter();
+
+       if (core->dev->pdata->support_enc_mode1) {
+               reg = MFC_CORE_READL(MFC_REG_E_HEVC_NAL_CONTROL);
+               mfc_clear_set_bits(reg, 0x1, 11, IS_MULTI_MODE(ctx));
+               MFC_CORE_WRITEL(reg, MFC_REG_E_HEVC_NAL_CONTROL);
+       }
+
+       reg = MFC_CORE_READL(MFC_REG_E_HEVC_NAL_CONTROL);
+       mfc_clear_set_bits(reg, 0x3, 12, ctx->select_view ? 0x3 : 0x0);
+       MFC_CORE_WRITEL(reg, MFC_REG_E_HEVC_NAL_CONTROL);
+
+       if (core->last_mfc_freq)
+               timeout_value = (core->last_mfc_freq * 
MFC_TIMEOUT_VALUE_IN_MSEC);
+       mfc_debug(2, "Last MFC Freq: %d, Timeout Value: %d\n",
+                 core->last_mfc_freq, timeout_value);
+
+       MFC_CORE_WRITEL(timeout_value, MFC_REG_TIMEOUT_VALUE);
+       MFC_CORE_WRITEL(core_ctx->inst_no, MFC_REG_INSTANCE_ID);
+
+       /*
+        * Issue different commands to instance basing on whether it
+        * is the last frame or not.
+        */
+       switch (last_frame) {
+       case 0:
+               mfc_core_cmd_host2risc(core, MFC_REG_H2R_CMD_NAL_START);
+               break;
+       case 1:
+               mfc_core_cmd_host2risc(core, MFC_REG_H2R_CMD_LAST_FRAME);
+               break;
+       }
+
+       mfc_debug_leave();
+}
diff --git a/drivers/media/platform/samsung/exynos-mfc/mfc_core_cmd.h 
b/drivers/media/platform/samsung/exynos-mfc/mfc_core_cmd.h
index 216d07c564ae..91da9eeff904 100644
--- a/drivers/media/platform/samsung/exynos-mfc/mfc_core_cmd.h
+++ b/drivers/media/platform/samsung/exynos-mfc/mfc_core_cmd.h
@@ -28,8 +28,14 @@ void mfc_core_cmd_dpb_flush(struct mfc_core *core, struct 
mfc_ctx *ctx);
 void mfc_core_cmd_cache_flush(struct mfc_core *core);
 
 void mfc_core_cmd_dec_seq_header(struct mfc_core *core, struct mfc_ctx *ctx);
+int mfc_core_cmd_enc_seq_header(struct mfc_core *core, struct mfc_ctx *ctx);
 
 int mfc_core_cmd_dec_init_buffers(struct mfc_core *core, struct mfc_ctx *ctx);
+int mfc_core_cmd_enc_init_buffers(struct mfc_core *core, struct mfc_ctx *ctx);
+
 int mfc_core_cmd_dec_one_frame(struct mfc_core *core, struct mfc_ctx *ctx,
                               int last_frame, int src_index);
+void mfc_core_cmd_enc_one_frame(struct mfc_core *core, struct mfc_ctx *ctx,
+                               int last_frame);
+
 #endif /* __MFC_CORE_CMD_H */
diff --git a/drivers/media/platform/samsung/exynos-mfc/mfc_core_hwlock.c 
b/drivers/media/platform/samsung/exynos-mfc/mfc_core_hwlock.c
index 0b594429fd59..5456368f5410 100644
--- a/drivers/media/platform/samsung/exynos-mfc/mfc_core_hwlock.c
+++ b/drivers/media/platform/samsung/exynos-mfc/mfc_core_hwlock.c
@@ -508,6 +508,65 @@ static int __mfc_just_run_dec(struct mfc_core *core, 
struct mfc_ctx *ctx)
        return ret;
 }
 
+static int __mfc_just_run_enc(struct mfc_core *core, struct mfc_ctx *ctx)
+{
+       struct mfc_core_ctx *core_ctx = core->core_ctx[ctx->num];
+       struct mfc_core *subcore;
+       struct mfc_core_ctx *subcore_ctx;
+       int ret = 0;
+
+       switch (core_ctx->state) {
+       case MFCINST_FINISHING:
+               ret = mfc_core_run_enc_last_frames(core, ctx);
+               break;
+       case MFCINST_RUNNING:
+               ret = mfc_core_run_enc_frame(core, ctx);
+               break;
+       case MFCINST_INIT:
+               mfc_core_cmd_open_inst(core, ctx);
+               break;
+       case MFCINST_RETURN_INST:
+               ret = mfc_core_cmd_close_inst(core, ctx);
+               break;
+       case MFCINST_GOT_INST:
+               ret = mfc_core_run_enc_init(core, ctx);
+               break;
+       case MFCINST_HEAD_PARSED:
+               if (ctx->stream_op_mode == MFC_OP_TWO_MODE1) {
+                       if (core->id == MFC_CORE_SUB) {
+                               mfc_ctx_err("init buffer should be called to 
main core, so try again\n");
+                               return -EAGAIN;
+                       }
+
+                       subcore = mfc_get_sub_core(ctx->dev, ctx);
+                       if (!subcore) {
+                               mfc_ctx_err("Failed to get subcore before 
calling INIT_BUF\n");
+                               return -EAGAIN;
+                       }
+                       subcore_ctx = subcore->core_ctx[ctx->num];
+                       if (mfc_wait_for_done_core_ctx(subcore_ctx,
+                                                      
MFC_REG_R2H_CMD_SEQ_DONE_RET)) {
+                               mfc_ctx_err("sub core header parsing should be 
done before init buffer\n");
+                               return -EAGAIN;
+                       }
+               }
+               ret = mfc_core_cmd_enc_init_buffers(core, ctx);
+               break;
+       case MFCINST_ABORT_INST:
+               mfc_core_cmd_abort_inst(core, ctx);
+               break;
+       case MFCINST_MOVE_INST:
+               mfc_core_cmd_move_inst(core, ctx);
+               break;
+       default:
+               mfc_info("can't try command(encoder just_run), state : %d\n",
+                        core_ctx->state);
+               ret = -EAGAIN;
+       }
+
+       return ret;
+}
+
 /* Run an operation on hardware */
 int mfc_core_just_run(struct mfc_core *core, int new_ctx_index)
 {
@@ -557,6 +616,8 @@ int mfc_core_just_run(struct mfc_core *core, int 
new_ctx_index)
 
        if (ctx->type == MFCINST_DECODER) {
                ret = __mfc_just_run_dec(core, ctx);
+       } else if (ctx->type == MFCINST_ENCODER) {
+               ret = __mfc_just_run_enc(core, ctx);
        } else {
                mfc_err("invalid context type: %d\n", ctx->type);
                ret = -EAGAIN;
diff --git a/drivers/media/platform/samsung/exynos-mfc/mfc_core_ops.c 
b/drivers/media/platform/samsung/exynos-mfc/mfc_core_ops.c
index f8a27548b218..fc90650c228c 100644
--- a/drivers/media/platform/samsung/exynos-mfc/mfc_core_ops.c
+++ b/drivers/media/platform/samsung/exynos-mfc/mfc_core_ops.c
@@ -322,6 +322,9 @@ static int mfc_core_instance_deinit(struct mfc_core *core, 
struct mfc_ctx *ctx)
        mfc_core_release_hwlock_ctx(core_ctx);
        mfc_core_destroy_listable_wq_ctx(core_ctx);
 
+       if (ctx->type == MFCINST_ENCODER)
+               mfc_release_enc_roi_buffer(core_ctx);
+
        mfc_delete_queue(&core_ctx->src_buf_queue);
 
        core->core_ctx[core_ctx->num] = 0;
@@ -361,6 +364,32 @@ static int __mfc_core_instance_open_dec(struct mfc_ctx 
*ctx,
        return 0;
 }
 
+static int __mfc_core_instance_open_enc(struct mfc_ctx *ctx,
+                                       struct mfc_core_ctx *core_ctx)
+{
+       int ret = 0;
+
+       ret = mfc_alloc_instance_context(core_ctx);
+       if (ret) {
+               mfc_err("Failed to allocate enc instance[%d] buffers\n",
+                       core_ctx->num);
+               mfc_core_release_hwlock_ctx(core_ctx);
+               return -ENOMEM;
+       }
+
+       ctx->capture_state = QUEUE_FREE;
+
+       ret = mfc_alloc_enc_roi_buffer(core_ctx);
+       if (ret) {
+               mfc_err("[ROI] Failed to allocate ROI buffers\n");
+               mfc_release_instance_context(core_ctx);
+               mfc_core_release_hwlock_ctx(core_ctx);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
 static int mfc_core_instance_open(struct mfc_core *core, struct mfc_ctx *ctx)
 {
        struct mfc_core_ctx *core_ctx = core->core_ctx[ctx->num];
@@ -380,6 +409,9 @@ static int mfc_core_instance_open(struct mfc_core *core, 
struct mfc_ctx *ctx)
        if (ctx->type == MFCINST_DECODER) {
                if (__mfc_core_instance_open_dec(ctx, core_ctx))
                        return -EAGAIN;
+       } else if (ctx->type == MFCINST_ENCODER) {
+               if (__mfc_core_instance_open_enc(ctx, core_ctx))
+                       return -EAGAIN;
        } else {
                mfc_err("invalid codec type: %d\n", ctx->type);
                return -EINVAL;
@@ -414,6 +446,8 @@ static int mfc_core_instance_open(struct mfc_core *core, 
struct mfc_ctx *ctx)
        mfc_core_release_hwlock_ctx(core_ctx);
        core->sched->yield_work(core, core_ctx);
        mfc_release_instance_context(core_ctx);
+       if (ctx->type == MFCINST_ENCODER)
+               mfc_release_enc_roi_buffer(core_ctx);
 
        return ret;
 }
@@ -619,6 +653,124 @@ static int mfc_core_instance_init_buf(struct mfc_core 
*core, struct mfc_ctx *ctx
        return 0;
 }
 
+static void mfc_core_instance_q_flush(struct mfc_core *core, struct mfc_ctx 
*ctx)
+{
+       struct mfc_core_ctx *core_ctx = core->core_ctx[ctx->num];
+       int index = 0;
+       int ret = 0;
+
+       /* If a H/W operation is in progress, wait for it complete */
+       if (NEED_TO_WAIT_NAL_ABORT(core_ctx)) {
+               if (mfc_wait_for_done_core_ctx(core_ctx, 
MFC_REG_R2H_CMD_NAL_ABORT_RET)) {
+                       mfc_err("time out during nal abort\n");
+                       core->sched->yield_work(core, core_ctx);
+               }
+       }
+
+       ret = mfc_core_get_hwlock_ctx(core_ctx);
+       if (ret < 0) {
+               mfc_err("Failed to get hwlock\n");
+               MFC_TRACE_CTX_LT("[ERR][Release] failed to get hwlock 
(shutdown: %d)\n",
+                                core->shutdown);
+               return;
+       }
+
+       mfc_cleanup_queue(&ctx->buf_queue_lock, &ctx->dst_buf_queue);
+
+       while (index < MFC_MAX_BUFFERS) {
+               index = find_next_bit(ctx->dst_ctrls_avail, MFC_MAX_BUFFERS, 
index);
+               if (index < MFC_MAX_BUFFERS)
+                       call_cop(ctx, reset_buf_ctrls, &ctx->dst_ctrls[index]);
+               index++;
+       }
+
+       if (core_ctx->state == MFCINST_FINISHING)
+               mfc_change_state(core_ctx, MFCINST_FINISHED);
+
+       mfc_debug(2, "encoder destination stop sequence done\n");
+
+       core->sched->clear_work(core, core_ctx);
+       mfc_core_release_hwlock_ctx(core_ctx);
+
+       core->sched->enqueue_work(core, core_ctx);
+       if (core->sched->is_work(core))
+               core->sched->queue_work(core);
+}
+
+static void mfc_core_instance_finishing(struct mfc_core *core, struct mfc_ctx 
*ctx)
+{
+       struct mfc_core_ctx *core_ctx = core->core_ctx[ctx->num];
+       int index = 0;
+       int ret = 0;
+
+       /* If a H/W operation is in progress, wait for it complete */
+       if (NEED_TO_WAIT_NAL_ABORT(core_ctx)) {
+               if (mfc_wait_for_done_core_ctx(core_ctx, 
MFC_REG_R2H_CMD_NAL_ABORT_RET)) {
+                       mfc_err("time out during nal abort\n");
+                       core->sched->yield_work(core, core_ctx);
+               }
+       }
+
+       ret = mfc_core_get_hwlock_ctx(core_ctx);
+       if (ret < 0) {
+               mfc_err("Failed to get hwlock\n");
+               MFC_TRACE_CTX_LT("[ERR][Release] failed to get hwlock 
(shutdown: %d)\n",
+                                core->shutdown);
+               return;
+       }
+
+       if (core_ctx->state == MFCINST_RUNNING || core_ctx->state == 
MFCINST_FINISHING ||
+           (IS_SWITCH_SINGLE_MODE(ctx) && core->id == 
ctx->op_core_num[MFC_CORE_SUB])) {
+               mfc_change_state(core_ctx, MFCINST_FINISHING);
+               core->sched->set_work(core, core_ctx);
+
+               while (core_ctx->state != MFCINST_FINISHED) {
+                       ret = mfc_core_just_run(core, ctx->num);
+                       if (ret) {
+                               mfc_err("Failed to run MFC\n");
+                               break;
+                       }
+                       if (mfc_wait_for_done_core_ctx(core_ctx,
+                                                      
MFC_REG_R2H_CMD_FRAME_DONE_RET)) {
+                               mfc_err("Waiting for LAST_SEQ timed out\n");
+                               break;
+                       }
+               }
+       }
+
+       ctx->serial_src_index = 0;
+       mfc_move_buf_all(ctx, &core_ctx->src_buf_queue,
+                        &ctx->ref_buf_queue, MFC_QUEUE_ADD_BOTTOM);
+       mfc_move_buf_all(ctx, &core_ctx->src_buf_queue,
+                        &ctx->src_buf_ready_queue, MFC_QUEUE_ADD_BOTTOM);
+       mfc_cleanup_enc_src_queue(core_ctx);
+       mfc_cleanup_queue(&ctx->buf_queue_lock, &ctx->err_buf_queue);
+
+       while (index < MFC_MAX_BUFFERS) {
+               index = find_next_bit(ctx->src_ctrls_avail, MFC_MAX_BUFFERS, 
index);
+               if (index < MFC_MAX_BUFFERS)
+                       call_cop(ctx, reset_buf_ctrls, &ctx->src_ctrls[index]);
+               index++;
+       }
+
+       if (core_ctx->state == MFCINST_FINISHING ||
+           core_ctx->state == MFCINST_GOT_INST ||
+           core_ctx->state == MFCINST_HEAD_PARSED) {
+               mfc_debug(2, "%d status can continue encoding without 
CLOSE_INSTANCE\n",
+                         core_ctx->state);
+               mfc_change_state(core_ctx, MFCINST_FINISHED);
+       }
+
+       mfc_debug(2, "encoder source stop sequence done\n");
+
+       core->sched->clear_work(core, core_ctx);
+       mfc_core_release_hwlock_ctx(core_ctx);
+
+       core->sched->enqueue_work(core, core_ctx);
+       if (core->sched->is_work(core))
+               core->sched->queue_work(core);
+}
+
 static int mfc_core_request_work(struct mfc_core *core,
                                 enum mfc_request_work work,
                                 struct mfc_ctx *ctx)
@@ -650,6 +802,8 @@ static const struct mfc_core_ops mfc_core_ops = {
        .instance_move_from = mfc_core_instance_move_from,
        .instance_dpb_flush = mfc_core_instance_dpb_flush,
        .instance_init_buf = mfc_core_instance_init_buf,
+       .instance_q_flush = mfc_core_instance_q_flush,
+       .instance_finishing = mfc_core_instance_finishing,
        .request_work = mfc_core_request_work,
 };
 
diff --git a/drivers/media/platform/samsung/exynos-mfc/mfc_core_reg_api.c 
b/drivers/media/platform/samsung/exynos-mfc/mfc_core_reg_api.c
index 0cc5d1d9433e..d4e9cb4e4e79 100644
--- a/drivers/media/platform/samsung/exynos-mfc/mfc_core_reg_api.c
+++ b/drivers/media/platform/samsung/exynos-mfc/mfc_core_reg_api.c
@@ -225,6 +225,63 @@ int mfc_core_set_dec_codec_buffers(struct mfc_core_ctx 
*core_ctx)
        return 0;
 }
 
+/* Set encoding ref & codec buffer */
+int mfc_core_set_enc_codec_buffers(struct mfc_core_ctx *core_ctx)
+{
+       struct mfc_core *core = core_ctx->core;
+       struct mfc_ctx *ctx = core_ctx->ctx;
+       struct mfc_enc *enc = ctx->enc_priv;
+       dma_addr_t buf_addr;
+       int buf_size;
+       int i;
+
+       mfc_debug_enter();
+
+       buf_addr = core_ctx->codec_buf.daddr;
+       buf_size = core_ctx->codec_buf.size;
+
+       mfc_debug(2, "[MEMINFO] codec buf 0x%llx, size: %d\n", buf_addr, 
buf_size);
+       mfc_debug(2, "DPB COUNT: %d\n", ctx->dpb_count);
+
+       MFC_CORE_DMA_WRITEL(buf_addr, MFC_REG_E_SCRATCH_BUFFER_ADDR);
+       MFC_CORE_WRITEL(ctx->scratch_buf_size, MFC_REG_E_SCRATCH_BUFFER_SIZE);
+       buf_addr += ctx->scratch_buf_size;
+       buf_size -= ctx->scratch_buf_size;
+
+       /* start address of per buffer is aligned */
+       for (i = 0; i < ctx->dpb_count; i++) {
+               MFC_CORE_DMA_WRITEL(buf_addr, MFC_REG_E_LUMA_DPB + (4 * i));
+               buf_addr += enc->luma_dpb_size;
+               buf_size -= enc->luma_dpb_size;
+       }
+       for (i = 0; i < ctx->dpb_count; i++) {
+               MFC_CORE_DMA_WRITEL(buf_addr, MFC_REG_E_CHROMA_DPB + (4 * i));
+               buf_addr += enc->chroma_dpb_size;
+               buf_size -= enc->chroma_dpb_size;
+       }
+       for (i = 0; i < ctx->dpb_count; i++) {
+               MFC_CORE_DMA_WRITEL(buf_addr, MFC_REG_E_ME_BUFFER + (4 * i));
+               buf_addr += enc->me_buffer_size;
+               buf_size -= enc->me_buffer_size;
+       }
+
+       MFC_CORE_DMA_WRITEL(buf_addr, MFC_REG_E_TMV_BUFFER0);
+       buf_addr += enc->tmv_buffer_size >> 1;
+       MFC_CORE_DMA_WRITEL(buf_addr, MFC_REG_E_TMV_BUFFER1);
+       buf_addr += enc->tmv_buffer_size >> 1;
+       buf_size -= enc->tmv_buffer_size;
+
+       mfc_debug(2, "[MEMINFO] codec buf 0x%llx, remained size: %d\n", 
buf_addr, buf_size);
+       if (buf_size < 0) {
+               mfc_debug(2, "[MEMINFO] Not enough memory has been 
allocated\n");
+               return -ENOMEM;
+       }
+
+       mfc_debug_leave();
+
+       return 0;
+}
+
 /* Set registers for decoding stream buffer */
 int mfc_core_set_dec_stream_buffer(struct mfc_core *core, struct mfc_ctx *ctx,
                                   struct mfc_buf *mfc_buf, unsigned int 
start_num_byte,
@@ -273,6 +330,118 @@ int mfc_core_set_dec_stream_buffer(struct mfc_core *core, 
struct mfc_ctx *ctx,
        return 0;
 }
 
+void mfc_core_set_enc_frame_buffer(struct mfc_core *core, struct mfc_ctx *ctx,
+                                  struct mfc_buf *mfc_buf, int num_planes)
+{
+       dma_addr_t addr[3] = { 0, 0, 0 };
+       int index, i;
+       int index_view;
+
+       if (!mfc_buf) {
+               mfc_ctx_debug(3, "enc zero buffer set\n");
+               goto buffer_set;
+       }
+
+       index = mfc_buf->vb.vb2_buf.index;
+       if (mfc_buf->num_valid_bufs > 0) {
+               for (i = 0; i < num_planes; i++) {
+                       addr[i] = mfc_buf->addr[mfc_buf->next_index][i];
+                       mfc_ctx_debug(2, "[BUFCON][BUFINFO] set src index: %d, 
batch[%d], addr[%d]: 0x%08llx\n",
+                                     index, mfc_buf->next_index, i, addr[i]);
+               }
+               mfc_buf->next_index++;
+       } else {
+               index_view = ctx->select_view == MFC_VIEW_ID_MAIN ? 
MFC_MV_BUF_IDX_VIEW0
+                                                                 : 
MFC_MV_BUF_IDX_VIEW1;
+               for (i = 0; i < num_planes; i++) {
+                       addr[i] = mfc_buf->addr[index_view][i];
+                       mfc_ctx_debug(2, "[BUFINFO] set src index: %d(%d), 
addr[%d]: 0x%08llx\n",
+                                     index, mfc_buf->src_index, i, addr[i]);
+               }
+       }
+
+buffer_set:
+       for (i = 0; i < num_planes; i++)
+               MFC_CORE_DMA_WRITEL(addr[i], MFC_REG_E_SOURCE_FIRST_ADDR + (i * 
4));
+}
+
+/* Set registers for encoding stream buffer */
+int mfc_core_set_enc_stream_buffer(struct mfc_core *core, struct mfc_ctx *ctx,
+                                  struct mfc_buf *mfc_buf)
+{
+       dma_addr_t addr = 0;
+       unsigned int size = 0, offset = 0, index = -1;
+
+       if (mfc_buf) {
+               index = mfc_buf->vb.vb2_buf.index;
+               addr = mfc_buf->addr[0][0];
+               offset = mfc_buf->vb.vb2_buf.planes[0].data_offset;
+               size = (unsigned int)vb2_plane_size(&mfc_buf->vb.vb2_buf, 0);
+               size = ALIGN(size, STREAM_BUF_ALIGN);
+       } else {
+               /*
+                * When LAST_SEQ of B frame encoding
+                * if there is no output buffer, set addr and size with 
0xffffffff
+                * and then FW returns COMPLETE_SEQ.
+                */
+               addr = 0xffffffff;
+               size = 0xffffffff;
+       }
+
+       MFC_CORE_DMA_WRITEL(addr, MFC_REG_E_STREAM_BUFFER_ADDR); /* 16B align */
+       MFC_CORE_WRITEL(size, MFC_REG_E_STREAM_BUFFER_SIZE);
+       MFC_CORE_WRITEL(offset, MFC_REG_E_STREAM_BUFFER_OFFSET);
+
+       if (IS_MULTI_MODE(ctx) &&
+           !(ctx->dev->debugfs.feature_option & 
MFC_OPTION_STREAM_COPY_DISABLE)) {
+               dma_addr_t tile1_addr = 0;
+               unsigned int tile0_size = 0;
+               unsigned int tile1_size = 0;
+
+               tile0_size = ALIGN(size / 2, 16);
+               tile1_addr = addr + tile0_size;
+               tile1_size = (size > tile0_size) ? size - tile0_size : 0;
+
+               MFC_CORE_DMA_WRITEL(tile1_addr, 
MFC_REG_E_TILE1_STREAM_BUFFER_ADDR); /* 16B align */
+               MFC_CORE_WRITEL(tile1_size, MFC_REG_E_TILE1_STREAM_BUFFER_SIZE);
+       }
+
+       mfc_ctx_debug(2, "[BUFINFO] set dst index: %d, addr: 0x%08llx\n", 
index, addr);
+       mfc_ctx_debug(2, "[STREAM] buf_size: %u, offset: %d\n", size, offset);
+
+       return 0;
+}
+
+void mfc_core_get_enc_frame_buffer(struct mfc_core *core, struct mfc_ctx *ctx,
+                                  dma_addr_t addr[], int num_planes)
+{
+       dma_addr_t enc_recon_y_addr, enc_recon_c_addr;
+       int i, addr_offset;
+
+       addr_offset = MFC_REG_E_ENCODED_SOURCE_FIRST_ADDR;
+
+       for (i = 0; i < num_planes; i++)
+               addr[i] = MFC_CORE_DMA_READL(addr_offset + (i * 4));
+
+       enc_recon_y_addr = MFC_CORE_DMA_READL(MFC_REG_E_RECON_LUMA_DPB_ADDR);
+       enc_recon_c_addr = MFC_CORE_DMA_READL(MFC_REG_E_RECON_CHROMA_DPB_ADDR);
+
+       mfc_ctx_debug(2, "[MEMINFO] recon y: %#llx c: %#llx\n",
+                     enc_recon_y_addr, enc_recon_c_addr);
+}
+
+void mfc_core_set_enc_stride(struct mfc_core *core, struct mfc_ctx *ctx)
+{
+       int i;
+
+       for (i = 0; i < ctx->raw_buf.num_planes; i++) {
+               MFC_CORE_WRITEL(ctx->raw_buf.stride[i],
+                               MFC_REG_E_SOURCE_FIRST_STRIDE + (i * 4));
+               mfc_ctx_debug(2, "[FRAME] enc src plane[%d] stride: %d\n",
+                             i, ctx->raw_buf.stride[i]);
+       }
+}
+
 void mfc_core_set_dynamic_dpb(struct mfc_core *core, struct mfc_ctx *ctx,
                              struct mfc_buf *dst_mb)
 {
diff --git a/drivers/media/platform/samsung/exynos-mfc/mfc_core_reg_api.h 
b/drivers/media/platform/samsung/exynos-mfc/mfc_core_reg_api.h
index 08f74bd56f3f..6042f3a8a6ba 100644
--- a/drivers/media/platform/samsung/exynos-mfc/mfc_core_reg_api.h
+++ b/drivers/media/platform/samsung/exynos-mfc/mfc_core_reg_api.h
@@ -116,6 +116,14 @@
        MFC_CORE_READL(MFC_REG_D_FIRST_PLANE_2BIT_DPB_STRIDE_SIZE + ((x) * 4))
 #define mfc_core_get_mv_count()                        
MFC_CORE_READL(MFC_REG_D_MIN_NUM_MV)
 #define mfc_core_get_inst_no()                 
MFC_CORE_READL(MFC_REG_RET_INSTANCE_ID)
+#define mfc_core_get_enc_dpb_count()           
MFC_CORE_READL(MFC_REG_E_NUM_DPB)
+#define mfc_core_get_enc_scratch_size()                
MFC_CORE_READL(MFC_REG_E_MIN_SCRATCH_BUFFER_SIZE)
+#define mfc_core_get_enc_luma_size()           
MFC_CORE_READL(MFC_REG_E_MIN_LUMA_DPB_SIZE)
+#define mfc_core_get_enc_chroma_size()         
MFC_CORE_READL(MFC_REG_E_MIN_CHROMA_DPB_SIZE)
+#define mfc_core_get_enc_strm_size()           
MFC_CORE_READL(MFC_REG_E_STREAM_SIZE)
+#define mfc_core_get_enc_slice_type()          
(MFC_CORE_READL(MFC_REG_E_SLICE_TYPE)           \
+                                               & MFC_REG_E_SLICE_TYPE_MASK)
+#define mfc_core_get_enc_pic_count()           
MFC_CORE_READL(MFC_REG_E_PICTURE_COUNT)
 #define mfc_core_get_sei_avail()               
MFC_CORE_READL(MFC_REG_D_SEI_AVAIL)
 #define mfc_core_get_sei_content_light()       \
        MFC_CORE_READL(MFC_REG_D_CONTENT_LIGHT_LEVEL_INFO_SEI)
@@ -209,6 +217,14 @@
 #define mfc_core_get_dec_used_flag()           (((unsigned 
long)(MFC_CORE_READL                \
                                                
(MFC_REG_D_USED_DPB_FLAG_UPPER)) << 32) |       \
                                                
MFC_CORE_READL(MFC_REG_D_USED_DPB_FLAG_LOWER))
+#define mfc_core_get_enc_idr_flag()                            \
+       ((MFC_CORE_READL(MFC_REG_E_NAL_DONE_INFO)               \
+       >> MFC_REG_E_NAL_DONE_INFO_IDR_SHIFT)                   \
+       & MFC_REG_E_NAL_DONE_INFO_IDR_MASK)
+#define mfc_core_get_enc_comp_err()                                    \
+       ((MFC_CORE_READL(MFC_REG_E_NAL_DONE_INFO)               \
+       >> MFC_REG_E_NAL_DONE_INFO_COMP_ERR_SHIFT)                      \
+       & MFC_REG_E_NAL_DONE_INFO_COMP_ERR_MASK)
 #define mfc_core_get_chroma_format()           
(MFC_CORE_READL(MFC_REG_D_CHROMA_FORMAT)        \
                                                & MFC_REG_D_CHROMA_FORMAT_MASK)
 #define mfc_core_get_color_range()             
((MFC_CORE_READL(MFC_REG_D_CHROMA_FORMAT)       \
@@ -257,6 +273,15 @@ static inline void mfc_core_dec_get_crop_info(struct 
mfc_core *core,
        dec->cr_bot = bottom;
 }
 
+static inline void mfc_core_clear_enc_res_change(struct mfc_core *core)
+{
+       unsigned int reg = 0;
+
+       reg = MFC_CORE_READL(MFC_REG_E_PARAM_CHANGE);
+       reg &= ~(0x7 << 6);
+       MFC_CORE_WRITEL(reg, MFC_REG_E_PARAM_CHANGE);
+}
+
 static inline void mfc_core_clear_roi_enable(struct mfc_core *core)
 {
        unsigned int reg = 0;
@@ -276,6 +301,25 @@ static inline void mfc_core_update_tag(struct mfc_core 
*core, struct mfc_ctx *ct
        }
 }
 
+static inline void mfc_core_set_enc_src_votf(struct mfc_core *core, int onoff)
+{
+       unsigned int reg = 0;
+
+       reg = MFC_CORE_READL(MFC_REG_E_PARAM_CHANGE);
+       reg &= ~(0x3 << 18);
+       reg |= (onoff << 18);
+       MFC_CORE_WRITEL(reg, MFC_REG_E_PARAM_CHANGE);
+}
+
+static inline void mfc_core_clear_enc_src_votf(struct mfc_core *core)
+{
+       unsigned int reg = 0;
+
+       reg = MFC_CORE_READL(MFC_REG_E_PARAM_CHANGE);
+       reg &= ~(0x3 << 18);
+       MFC_CORE_WRITEL(reg, MFC_REG_E_PARAM_CHANGE);
+}
+
 static inline void mfc_core_set_migration_addr(struct mfc_core *core, struct 
mfc_ctx *ctx,
                                               dma_addr_t fw_addr, dma_addr_t 
common_ctx_addr)
 {
@@ -311,10 +355,21 @@ unsigned int mfc_get_frame_error_type(struct mfc_ctx 
*ctx, unsigned int err);
 
 void mfc_core_set_dec_dpb_and_scratch(struct mfc_core_ctx *core_ctx, 
dma_addr_t scratch_addr);
 int mfc_core_set_dec_codec_buffers(struct mfc_core_ctx *core_ctx);
+int mfc_core_set_enc_codec_buffers(struct mfc_core_ctx *core_ctx);
+
 int mfc_core_set_dec_stream_buffer(struct mfc_core *core, struct mfc_ctx *ctx,
                                   struct mfc_buf *mfc_buf, unsigned int 
start_num_byte,
                                   unsigned int buf_size);
 
+void mfc_core_set_enc_frame_buffer(struct mfc_core *core, struct mfc_ctx *ctx,
+                                  struct mfc_buf *mfc_buf, int num_planes);
+int mfc_core_set_enc_stream_buffer(struct mfc_core *core, struct mfc_ctx *ctx,
+                                  struct mfc_buf *mfc_buf);
+
+void mfc_core_get_enc_frame_buffer(struct mfc_core *core, struct mfc_ctx *ctx,
+                                  dma_addr_t addr[], int num_planes);
+void mfc_core_set_enc_stride(struct mfc_core *core, struct mfc_ctx *ctx);
+
 void mfc_core_set_dynamic_dpb(struct mfc_core *core, struct mfc_ctx *ctx,
                              struct mfc_buf *dst_vb);
 
diff --git a/drivers/media/platform/samsung/exynos-mfc/mfc_core_run.c 
b/drivers/media/platform/samsung/exynos-mfc/mfc_core_run.c
index 127d19c4d1cb..6270d22d3806 100644
--- a/drivers/media/platform/samsung/exynos-mfc/mfc_core_run.c
+++ b/drivers/media/platform/samsung/exynos-mfc/mfc_core_run.c
@@ -16,6 +16,7 @@
 
 #include "mfc_core_cmd.h"
 #include "mfc_core_hw_reg_api.h"
+#include "mfc_core_enc_param.h"
 
 #include "base/mfc_queue.h"
 #include "base/mfc_utils.h"
@@ -412,3 +413,129 @@ int mfc_core_run_dec_last_frames(struct mfc_core *core, 
struct mfc_ctx *ctx)
 
        return 0;
 }
+
+int mfc_core_run_enc_init(struct mfc_core *core, struct mfc_ctx *ctx)
+{
+       struct mfc_buf *dst_mb;
+       int ret;
+
+       if (!(ctx->stream_op_mode == MFC_OP_TWO_MODE1 && core->id == 
MFC_CORE_SUB)) {
+               dst_mb = mfc_get_buf(ctx, &ctx->dst_buf_queue, 
MFC_BUF_SET_USED);
+               if (!dst_mb) {
+                       mfc_ctx_debug(2, "no dst buffers\n");
+                       return -EAGAIN;
+               }
+
+               mfc_core_set_enc_stream_buffer(core, ctx, dst_mb);
+               mfc_ctx_debug(2, "[BUFINFO] Header addr: 0x%08llx\n", 
dst_mb->addr[0][0]);
+       }
+
+       mfc_core_set_enc_stride(core, ctx);
+
+       mfc_clean_core_ctx_int_flags(core->core_ctx[ctx->num]);
+
+       ret = mfc_core_cmd_enc_seq_header(core, ctx);
+       return ret;
+}
+
+int mfc_core_run_enc_frame(struct mfc_core *core, struct mfc_ctx *ctx)
+{
+       struct mfc_core_ctx *core_ctx = core->core_ctx[ctx->num];
+       struct mfc_enc *enc = ctx->enc_priv;
+       struct mfc_buf *dst_mb;
+       struct mfc_buf *src_mb;
+       struct mfc_raw_info *raw;
+       unsigned int index;
+       int last_frame = 0;
+
+       raw = &ctx->raw_buf;
+
+       /* Get the next source buffer */
+       src_mb = mfc_get_buf(ctx, &core_ctx->src_buf_queue, MFC_BUF_SET_USED);
+       if (!src_mb) {
+               mfc_debug(2, "no src buffers\n");
+               return -EAGAIN;
+       }
+
+       if (src_mb->num_valid_bufs > 0) {
+               /* last image in a buffer container */
+               if (src_mb->next_index == (src_mb->num_valid_bufs - 1)) {
+                       mfc_debug(4, "[BUFCON] last image in a container\n");
+                       last_frame = __mfc_check_last_frame(core_ctx, src_mb);
+               }
+       } else {
+               last_frame = __mfc_check_last_frame(core_ctx, src_mb);
+       }
+
+       if (mfc_check_mb_flag(src_mb, MFC_FLAG_ENC_SRC_FAKE)) {
+               enc->fake_src = 1;
+               mfc_debug(2, "src is fake\n");
+       }
+
+       index = src_mb->vb.vb2_buf.index;
+       if (mfc_check_mb_flag(src_mb, MFC_FLAG_EMPTY_DATA)) {
+               enc->empty_data = 1;
+               mfc_debug(2, "[FRAME] src is empty data\n");
+               mfc_core_set_enc_frame_buffer(core, ctx, 0, raw->num_planes);
+       } else {
+               mfc_core_set_enc_frame_buffer(core, ctx, src_mb, 
raw->num_planes);
+       }
+
+       dst_mb = mfc_get_buf(ctx, &ctx->dst_buf_queue, MFC_BUF_SET_USED);
+       if (!dst_mb) {
+               mfc_debug(2, "no dst buffers\n");
+               return -EAGAIN;
+       }
+
+       mfc_debug(2, "nal start : src index from src_buf_queue:%d\n",
+                 src_mb->vb.vb2_buf.index);
+       mfc_debug(2, "nal start : dst index from dst_buf_queue:%d\n",
+                 dst_mb->vb.vb2_buf.index);
+
+       mfc_core_set_enc_stream_buffer(core, ctx, dst_mb);
+
+       if (call_bop(ctx, core_set_buf_ctrls, core, ctx, 
&ctx->src_ctrls[index]) < 0)
+               mfc_err("failed in core_set_buf_ctrls\n");
+
+       mfc_clean_core_ctx_int_flags(core_ctx);
+
+       if (IS_H264_ENC(ctx))
+               mfc_core_set_aso_slice_order_h264(core, ctx);
+
+       mfc_core_set_slice_mode(core, ctx);
+       mfc_core_set_enc_config_qp(core, ctx);
+       mfc_core_set_enc_ts_delta(core, ctx);
+
+       mfc_core_cmd_enc_one_frame(core, ctx, last_frame);
+
+       return 0;
+}
+
+int mfc_core_run_enc_last_frames(struct mfc_core *core, struct mfc_ctx *ctx)
+{
+       struct mfc_buf *dst_mb = NULL;
+       struct mfc_raw_info *raw;
+
+       raw = &ctx->raw_buf;
+
+       if (IS_SWITCH_SINGLE_MODE(ctx) && core->id == 
ctx->op_core_num[MFC_CORE_SUB]) {
+               mfc_ctx_info("last-frame of subcore doesn't have dst buffer\n");
+       } else {
+               dst_mb = mfc_get_buf(ctx, &ctx->dst_buf_queue, 
MFC_BUF_SET_USED);
+               if (!dst_mb) {
+                       mfc_ctx_debug(2, "no dst buffers set to zero\n");
+
+                       if (mfc_is_enc_bframe(ctx))
+                               mfc_ctx_info("B frame encoding doesn't have dst 
buffer\n");
+               }
+       }
+
+       mfc_ctx_debug(2, "Set address zero for all planes\n");
+       mfc_core_set_enc_frame_buffer(core, ctx, 0, raw->num_planes);
+       mfc_core_set_enc_stream_buffer(core, ctx, dst_mb);
+
+       mfc_clean_core_ctx_int_flags(core->core_ctx[ctx->num]);
+       mfc_core_cmd_enc_one_frame(core, ctx, 1);
+
+       return 0;
+}
diff --git a/drivers/media/platform/samsung/exynos-mfc/mfc_core_run.h 
b/drivers/media/platform/samsung/exynos-mfc/mfc_core_run.h
index 6b9c9ef91e47..410c2aadcf5d 100644
--- a/drivers/media/platform/samsung/exynos-mfc/mfc_core_run.h
+++ b/drivers/media/platform/samsung/exynos-mfc/mfc_core_run.h
@@ -27,4 +27,9 @@ int mfc_core_run_wakeup(struct mfc_core *core);
 int mfc_core_run_dec_init(struct mfc_core *core, struct mfc_ctx *ctx);
 int mfc_core_run_dec_frame(struct mfc_core *core, struct mfc_ctx *ctx);
 int mfc_core_run_dec_last_frames(struct mfc_core *core, struct mfc_ctx *ctx);
+
+int mfc_core_run_enc_init(struct mfc_core *core, struct mfc_ctx *ctx);
+int mfc_core_run_enc_frame(struct mfc_core *core, struct mfc_ctx *ctx);
+int mfc_core_run_enc_last_frames(struct mfc_core *core, struct mfc_ctx *ctx);
+
 #endif /* __MFC_CORE_RUN_H */
-- 
2.34.1

Reply via email to