[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250930040348.3702923-27-h.dewangan@samsung.com>
Date: Tue, 30 Sep 2025 09:33:45 +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 26/29] media: mfc: Add full encoder support
From: Nagaraju Siddineni <nagaraju.s@...sung.com>
- 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 <nagaraju.s@...sung.com>
Signed-off-by: Himanshu Dewangan <h.dewangan@...sung.com>
---
.../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
Powered by blists - more mailing lists