lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250930040348.3702923-30-h.dewangan@samsung.com>
Date: Tue, 30 Sep 2025 09:33:48 +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 29/29] media: mfc: Hardware‑accelerated encoding support

From: Nagaraju Siddineni <nagaraju.s@...sung.com>

- Add for MPEG‑4, H.263, VP8/VP9, HEVC codec support with extended
  contexts and buffer allocation.
- Implement LCU sizing, motion‑estimation buffers, and align
  scratch buffers.
- Unify ROI buffer handling across all encoders.
- Register additional pixel formats (`mfc_format.h`).
- Enhance QoS weighting and B‑frame/reference‑count logic.
- Introduce hierarchical‑coding
  controls (layer count, per‑layer bitrate)
  and SVC for HEVC, VP8, VP9.
- Update timestamp handling for H.263 and improved VP8 buffer‑exhaustion
  error reporting.

Signed-off-by: Nagaraju Siddineni <nagaraju.s@...sung.com>
Signed-off-by: Himanshu Dewangan <h.dewangan@...sung.com>
---
 .../samsung/exynos-mfc/base/mfc_buf.c         | 71 ++++++++++++++++++-
 .../samsung/exynos-mfc/base/mfc_format.h      | 40 +++++++++++
 .../samsung/exynos-mfc/base/mfc_qos.c         | 23 +++++-
 .../samsung/exynos-mfc/base/mfc_utils.h       | 10 ++-
 .../samsung/exynos-mfc/mfc_core_buf_ctrl.c    | 59 ++++++++++++++-
 .../samsung/exynos-mfc/mfc_core_isr.c         |  2 +
 6 files changed, 198 insertions(+), 7 deletions(-)

diff --git a/drivers/media/platform/samsung/exynos-mfc/base/mfc_buf.c b/drivers/media/platform/samsung/exynos-mfc/base/mfc_buf.c
index 0186fe3327f1..164852e83e7d 100644
--- a/drivers/media/platform/samsung/exynos-mfc/base/mfc_buf.c
+++ b/drivers/media/platform/samsung/exynos-mfc/base/mfc_buf.c
@@ -133,10 +133,17 @@ int mfc_alloc_instance_context(struct mfc_core_ctx *core_ctx)
 		core_ctx->instance_ctx_buf.size = buf_size->other_dec_ctx;
 		break;
 	case MFC_REG_CODEC_H264_ENC:
+	case MFC_REG_CODEC_AV1_DEC:
 		core_ctx->instance_ctx_buf.size = buf_size->h264_enc_ctx;
 		break;
-	case MFC_REG_CODEC_AV1_DEC:
-		core_ctx->instance_ctx_buf.size = buf_size->av1_dec_ctx;
+	case MFC_REG_CODEC_HEVC_ENC:
+		core_ctx->instance_ctx_buf.size = buf_size->hevc_enc_ctx;
+		break;
+	case MFC_REG_CODEC_MPEG4_ENC:
+	case MFC_REG_CODEC_H263_ENC:
+	case MFC_REG_CODEC_VP8_ENC:
+	case MFC_REG_CODEC_VP9_ENC:
+		core_ctx->instance_ctx_buf.size = buf_size->other_enc_ctx;
 		break;
 	default:
 		core_ctx->instance_ctx_buf.size = 0;
@@ -256,6 +263,7 @@ static void __mfc_enc_calc_codec_buffer_size(struct mfc_core_ctx *core_ctx)
 	struct mfc_ctx *ctx = core_ctx->ctx;
 	struct mfc_enc *enc;
 	unsigned int mb_width, mb_height;
+	unsigned int lcu_width = 0, lcu_height = 0;
 
 	enc = ctx->enc_priv;
 	enc->tmv_buffer_size = 0;
@@ -263,6 +271,9 @@ static void __mfc_enc_calc_codec_buffer_size(struct mfc_core_ctx *core_ctx)
 	mb_width = WIDTH_MB(ctx->crop_width);
 	mb_height = HEIGHT_MB(ctx->crop_height);
 
+	lcu_width = ENC_LCU_WIDTH(ctx->crop_width);
+	lcu_height = ENC_LCU_HEIGHT(ctx->crop_height);
+
 	/* default recon buffer size, it can be changed in case of 422, 10bit */
 	enc->luma_dpb_size =
 		ALIGN(ENC_LUMA_DPB_SIZE(ctx->crop_width, ctx->crop_height), SZ_64);
@@ -293,6 +304,47 @@ static void __mfc_enc_calc_codec_buffer_size(struct mfc_core_ctx *core_ctx)
 			(ctx->dpb_count * (enc->luma_dpb_size +
 			enc->chroma_dpb_size + enc->me_buffer_size));
 		break;
+	case MFC_REG_CODEC_MPEG4_ENC:
+	case MFC_REG_CODEC_H263_ENC:
+		enc->me_buffer_size =
+			ALIGN(ENC_V100_MPEG4_ME_SIZE(mb_width, mb_height), SZ_256);
+
+		ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, SZ_256);
+		core_ctx->codec_buf.size =
+			ctx->scratch_buf_size + enc->tmv_buffer_size +
+			(ctx->dpb_count * (enc->luma_dpb_size +
+			enc->chroma_dpb_size + enc->me_buffer_size));
+		break;
+	case MFC_REG_CODEC_VP8_ENC:
+		enc->me_buffer_size =
+			ALIGN(ENC_V100_VP8_ME_SIZE(mb_width, mb_height), SZ_256);
+
+		ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, SZ_256);
+		core_ctx->codec_buf.size =
+			ctx->scratch_buf_size + enc->tmv_buffer_size +
+			(ctx->dpb_count * (enc->luma_dpb_size +
+			enc->chroma_dpb_size + enc->me_buffer_size));
+		break;
+	case MFC_REG_CODEC_VP9_ENC:
+		enc->me_buffer_size =
+			ALIGN(ENC_V100_VP9_ME_SIZE(lcu_width, lcu_height), SZ_256);
+
+		ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, SZ_256);
+		core_ctx->codec_buf.size =
+			ctx->scratch_buf_size + enc->tmv_buffer_size +
+			(ctx->dpb_count * (enc->luma_dpb_size +
+					   enc->chroma_dpb_size + enc->me_buffer_size));
+		break;
+	case MFC_REG_CODEC_HEVC_ENC:
+		enc->me_buffer_size =
+			ALIGN(ENC_V100_HEVC_ME_SIZE(lcu_width, lcu_height), SZ_256);
+
+		ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, SZ_256);
+		core_ctx->codec_buf.size =
+			ctx->scratch_buf_size + enc->tmv_buffer_size +
+			(ctx->dpb_count * (enc->luma_dpb_size +
+					   enc->chroma_dpb_size + enc->me_buffer_size));
+		break;
 	default:
 		core_ctx->codec_buf.size = 0;
 		mfc_err("invalid codec type: %d\n", ctx->codec_mode);
@@ -493,6 +545,7 @@ int mfc_alloc_enc_roi_buffer(struct mfc_core_ctx *core_ctx)
 	struct mfc_ctx *ctx = core_ctx->ctx;
 	struct mfc_enc *enc = ctx->enc_priv;
 	unsigned int mb_width, mb_height;
+	unsigned int lcu_width = 0, lcu_height = 0;
 	size_t size;
 	int i;
 
@@ -503,6 +556,20 @@ int mfc_alloc_enc_roi_buffer(struct mfc_core_ctx *core_ctx)
 	case MFC_REG_CODEC_H264_ENC:
 		size = ((((mb_width * (mb_height + 1) / 2) + 15) / 16) * 16) * 2;
 		break;
+	case MFC_REG_CODEC_MPEG4_ENC:
+	case MFC_REG_CODEC_VP8_ENC:
+		size = mb_width * mb_height;
+		break;
+	case MFC_REG_CODEC_VP9_ENC:
+		lcu_width = (ctx->crop_width + 63) / 64;
+		lcu_height = (ctx->crop_height + 63) / 64;
+		size = lcu_width * lcu_height * 4;
+		break;
+	case MFC_REG_CODEC_HEVC_ENC:
+		lcu_width = (ctx->crop_width + 31) / 32;
+		lcu_height = (ctx->crop_height + 31) / 32;
+		size = lcu_width * lcu_height;
+		break;
 	default:
 		mfc_debug(2,
 			  "ROI not supported codec type(%d). Allocate with default size\n",
diff --git a/drivers/media/platform/samsung/exynos-mfc/base/mfc_format.h b/drivers/media/platform/samsung/exynos-mfc/base/mfc_format.h
index e8573d6b6005..070c669e1d82 100644
--- a/drivers/media/platform/samsung/exynos-mfc/base/mfc_format.h
+++ b/drivers/media/platform/samsung/exynos-mfc/base/mfc_format.h
@@ -271,6 +271,46 @@ static struct mfc_fmt mfc_formats[] = {
 		.num_planes = 1,
 		.mem_planes = 1,
 	},
+	{
+		.name = "ENC MPEG4",
+		.fourcc = V4L2_PIX_FMT_MPEG4,
+		.codec_mode = MFC_REG_CODEC_MPEG4_ENC,
+		.type = MFC_FMT_STREAM | MFC_FMT_ENC,
+		.num_planes = 1,
+		.mem_planes = 1,
+	},
+	{
+		.name = "ENC H263",
+		.fourcc = V4L2_PIX_FMT_H263,
+		.codec_mode = MFC_REG_CODEC_H263_ENC,
+		.type = MFC_FMT_STREAM | MFC_FMT_ENC,
+		.num_planes = 1,
+		.mem_planes = 1,
+	},
+	{
+		.name = "ENC VP8",
+		.fourcc = V4L2_PIX_FMT_VP8,
+		.codec_mode = MFC_REG_CODEC_VP8_ENC,
+		.type = MFC_FMT_STREAM | MFC_FMT_ENC,
+		.num_planes = 1,
+		.mem_planes = 1,
+	},
+	{
+		.name = "ENC VP9",
+		.fourcc = V4L2_PIX_FMT_VP9,
+		.codec_mode = MFC_REG_CODEC_VP9_ENC,
+		.type = MFC_FMT_STREAM | MFC_FMT_ENC,
+		.num_planes = 1,
+		.mem_planes = 1,
+	},
+	{
+		.name = "ENC HEVC",
+		.fourcc = V4L2_PIX_FMT_HEVC,
+		.codec_mode = MFC_REG_CODEC_HEVC_ENC,
+		.type = MFC_FMT_STREAM | MFC_FMT_ENC,
+		.num_planes = 1,
+		.mem_planes = 1,
+	},
 };
 
 #endif /* __MFC_FORMAT_H */
diff --git a/drivers/media/platform/samsung/exynos-mfc/base/mfc_qos.c b/drivers/media/platform/samsung/exynos-mfc/base/mfc_qos.c
index 40541e2d626f..73058ace1fd6 100644
--- a/drivers/media/platform/samsung/exynos-mfc/base/mfc_qos.c
+++ b/drivers/media/platform/samsung/exynos-mfc/base/mfc_qos.c
@@ -58,6 +58,7 @@ static inline unsigned long __mfc_qos_add_weight(struct mfc_ctx *ctx, unsigned l
 		break;
 
 	case MFC_REG_CODEC_VP8_DEC:
+	case MFC_REG_CODEC_VP8_ENC:
 		weight = (weight * 100) / qos_weight->weight_vp8_vp9;
 		mfc_ctx_debug(3, "[QoS] vp8, vp9 codec, weight: %d\n", weight / 10);
 		if (num_planes == 3) {
@@ -80,12 +81,26 @@ static inline unsigned long __mfc_qos_add_weight(struct mfc_ctx *ctx, unsigned l
 		}
 		break;
 
+	case MFC_REG_CODEC_HEVC_ENC:
+		weight = (weight * 100) / qos_weight->weight_h264_hevc;
+		mfc_ctx_debug(3, "[QoS] h264, hevc codec, weight: %d\n", weight / 10);
+		if (num_planes == 3) {
+			weight = (weight * 100) / qos_weight->weight_3plane;
+			mfc_ctx_debug(3, "[QoS] 3 plane, weight: %d\n", weight / 10);
+		}
+		if (ctx->is_422) {
+			weight = (weight * 100) / qos_weight->weight_422;
+			mfc_ctx_debug(3, "[QoS] 422foramt, weight: %d\n", weight / 10);
+		}
+		break;
+
 	case MFC_REG_CODEC_AV1_DEC:
 		weight = (weight * 100) / qos_weight->weight_av1;
 		mfc_ctx_debug(3, "[QoS] av1 codec, weight: %d\n", weight / 10);
 		break;
 
 	case MFC_REG_CODEC_VP9_DEC:
+	case MFC_REG_CODEC_VP9_ENC:
 		weight = (weight * 100) / qos_weight->weight_vp8_vp9;
 		mfc_ctx_debug(3, "[QoS] vp8, vp9 codec, weight: %d\n", weight / 10);
 
@@ -109,6 +124,8 @@ static inline unsigned long __mfc_qos_add_weight(struct mfc_ctx *ctx, unsigned l
 	case MFC_REG_CODEC_VC1_RCV_DEC:
 	case MFC_REG_CODEC_VC1_DEC:
 	case MFC_REG_CODEC_MPEG2_DEC:
+	case MFC_REG_CODEC_MPEG4_ENC:
+	case MFC_REG_CODEC_H263_ENC:
 		weight = (weight * 100) / qos_weight->weight_other_codec;
 		mfc_ctx_debug(3, "[QoS] other codec, weight: %d\n", weight / 10);
 		break;
@@ -122,9 +139,13 @@ static inline unsigned long __mfc_qos_add_weight(struct mfc_ctx *ctx, unsigned l
 		if (mfc_is_enc_bframe(ctx)) {
 			weight = (weight * 100) / qos_weight->weight_bframe;
 			mfc_ctx_debug(3, "[QoS] B frame encoding, weight: %d\n", weight / 10);
-		} else if (IS_H264_ENC(ctx) && (p->num_refs_for_p >= 2)) {
+		} else if ((IS_H264_ENC(ctx) || IS_HEVC_ENC(ctx) || IS_VP8_ENC(ctx) ||
+					IS_VP9_ENC(ctx)) && (p->num_refs_for_p >= 2)) {
 			weight = (weight * 100) / qos_weight->weight_num_of_ref;
 			mfc_ctx_debug(3, "[QoS] num of ref >= 2, weight: %d\n", weight / 10);
+		} else if (IS_HEVC_ENC(ctx) && p->codec.hevc.general_pb_enable) {
+			weight = (weight * 100) / qos_weight->weight_gpb;
+			mfc_ctx_debug(3, "[QoS] Genaral PB, weight: %d\n", weight / 10);
 		}
 	}
 	if (dec) {
diff --git a/drivers/media/platform/samsung/exynos-mfc/base/mfc_utils.h b/drivers/media/platform/samsung/exynos-mfc/base/mfc_utils.h
index a127f330fe16..8526f5676761 100644
--- a/drivers/media/platform/samsung/exynos-mfc/base/mfc_utils.h
+++ b/drivers/media/platform/samsung/exynos-mfc/base/mfc_utils.h
@@ -229,7 +229,11 @@ static inline int mfc_is_enc_bframe(struct mfc_ctx *ctx)
 	if (IS_H264_ENC(ctx)) {
 		num_hier_layer = p->codec.h264.num_hier_layer;
 		hier_qp_type = (int)p->codec.h264.hier_qp_type;
+	} else if (IS_HEVC_ENC(ctx)) {
+		num_hier_layer = p->codec.hevc.num_hier_layer;
+		hier_qp_type = (int)p->codec.hevc.hier_qp_type;
 	}
+
 	if (enc->params.num_b_frame ||
 	    (num_hier_layer >= 2 &&
 	     hier_qp_type == V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B))
@@ -402,7 +406,11 @@ static inline int mfc_enc_get_ts_delta(struct mfc_ctx *ctx)
 		 * so thie is also divided into pre-calculated 100.
 		 * (Preventing both overflow and calculation duplication)
 		 */
-		ts_delta = ctx->src_ts.ts_last_interval / 100;
+		if (IS_H263_ENC(ctx))
+			ts_delta = ctx->src_ts.ts_last_interval *
+				p->rc_framerate_res / USEC_PER_SEC;
+		else
+			ts_delta = ctx->src_ts.ts_last_interval / 100;
 	}
 	return ts_delta;
 }
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
index cc0a20bea33a..11e9c2622242 100644
--- a/drivers/media/platform/samsung/exynos-mfc/mfc_core_buf_ctrl.c
+++ b/drivers/media/platform/samsung/exynos-mfc/mfc_core_buf_ctrl.c
@@ -11,6 +11,25 @@
 
 #include "mfc_core_reg_api.h"
 
+static int __mfc_enc_check_adaptive_temporal_svc(int id,
+						 struct mfc_enc_params *p,
+						 struct temporal_layer_info
+						 *temporal_LC)
+{
+	unsigned int new_num_layer = temporal_LC->temporal_layer_count;
+	unsigned int old_num_layer, ref_type;
+
+	if (id == V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_CH) {
+		old_num_layer = p->codec.hevc.num_hier_layer;
+		ref_type = p->codec.hevc.hier_ref_type;
+		if (ref_type == 0 && old_num_layer != new_num_layer)
+			if (new_num_layer == 1 || old_num_layer == 1)
+				return 1;
+	}
+
+	return 0;
+}
+
 static void __mfc_enc_store_buf_ctrls_temporal_svc(int id,
 						   struct mfc_enc_params *p,
 						   struct temporal_layer_info
@@ -26,6 +45,24 @@ static void __mfc_enc_store_buf_ctrls_temporal_svc(int id,
 			p->codec.h264.hier_bit_layer[i] =
 			    temporal_LC->temporal_layer_bitrate[i];
 		break;
+	case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_CH:
+		p->codec.hevc.num_hier_layer = num_layer & 0x7;
+		for (i = 0; i < (num_layer & 0x7); i++)
+			p->codec.hevc.hier_bit_layer[i] =
+			    temporal_LC->temporal_layer_bitrate[i];
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_CH:
+		p->codec.vp8.num_hier_layer = num_layer & 0x7;
+		for (i = 0; i < (num_layer & 0x7); i++)
+			p->codec.vp8.hier_bit_layer[i] =
+			    temporal_LC->temporal_layer_bitrate[i];
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_CH:
+		p->codec.vp9.num_hier_layer = num_layer & 0x7;
+		for (i = 0; i < (num_layer & 0x7); i++)
+			p->codec.vp9.hier_bit_layer[i] =
+			    temporal_LC->temporal_layer_bitrate[i];
+		break;
 	default:
 		break;
 	}
@@ -43,12 +80,21 @@ static void __mfc_core_enc_set_buf_ctrls_temporal_svc(struct mfc_core *core,
 	struct mfc_enc_params *p = &enc->params;
 
 	if (buf_ctrl->id
-	    == V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_CH) {
+	    == V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_CH ||
+	    buf_ctrl->id
+	    == V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_CH ||
+	    buf_ctrl->id
+	    == V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_CH ||
+	    buf_ctrl->id
+	    == V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_CH) {
 		memcpy(&temporal_LC,
 		       enc->sh_handle_svc.vaddr,
 		       sizeof(struct temporal_layer_info));
 
-		if ((temporal_LC.temporal_layer_count & 0x7) < 1) {
+		if (((temporal_LC.temporal_layer_count & 0x7) < 1) ||
+		    (temporal_LC.temporal_layer_count > 3 && IS_VP8_ENC(ctx)) ||
+		    (temporal_LC.temporal_layer_count > 3 &&
+			IS_VP9_ENC(ctx))) {
 			/* clear NUM_T_LAYER_CHANGE */
 			value = MFC_CORE_READL(buf_ctrl->flag_addr);
 			value &= ~BIT(10);
@@ -61,7 +107,14 @@ static void __mfc_core_enc_set_buf_ctrls_temporal_svc(struct mfc_core *core,
 
 		value = MFC_CORE_READL(buf_ctrl->flag_addr);
 		value &= ~(0x3 << 21);
-
+		/* Adaptive temporal SVC(layer count 1: IPPP, others: H-B) */
+		if (__mfc_enc_check_adaptive_temporal_svc
+		    (buf_ctrl->id, p, &temporal_LC)) {
+			if (temporal_LC.temporal_layer_count > 1)
+				value |= BIT(21);
+			else
+				value |= (0x2 << 21);
+		}
 		MFC_CORE_WRITEL(value, buf_ctrl->flag_addr);
 
 		/* Store temporal layer information */
diff --git a/drivers/media/platform/samsung/exynos-mfc/mfc_core_isr.c b/drivers/media/platform/samsung/exynos-mfc/mfc_core_isr.c
index 1a3cf7e76e29..9c5be84fcbc6 100644
--- a/drivers/media/platform/samsung/exynos-mfc/mfc_core_isr.c
+++ b/drivers/media/platform/samsung/exynos-mfc/mfc_core_isr.c
@@ -1883,6 +1883,8 @@ static inline void __mfc_handle_nal_abort(struct mfc_core *core,
 	if (ctx->type == MFCINST_ENCODER) {
 		mfc_change_state(core_ctx, MFCINST_RUNNING_BUF_FULL);
 		enc->buf_full = 0;
+		if (IS_VP8_ENC(ctx))
+			mfc_err("stream buffer size isn't enough\n");
 		__mfc_handle_stream(core, ctx, reason);
 	} else {
 		mfc_change_state(core_ctx, MFCINST_ABORT);
-- 
2.34.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ