All of lore.kernel.org
 help / color / mirror / Atom feed
From: Smitha T Murthy <smitha.t@samsung.com>
To: linux-arm-kernel@lists.infradead.org,
	linux-media@vger.kernel.org, linux-kernel@vger.kernel.org,
	devicetree@vger.kernel.org
Cc: m.szyprowski@samsung.com, andrzej.hajda@intel.com,
	mchehab@kernel.org, hverkuil-cisco@xs4all.nl,
	ezequiel@vanguardiasur.com.ar, jernej.skrabec@gmail.com,
	benjamin.gaignard@collabora.com, stanimir.varbanov@linaro.org,
	dillon.minfei@gmail.com, david.plowman@raspberrypi.com,
	mark.rutland@arm.com, robh+dt@kernel.org, krzk+dt@kernel.org,
	andi@etezian.org, alim.akhtar@samsung.com,
	aswani.reddy@samsung.com, pankaj.dubey@samsung.com,
	Smitha T Murthy <smitha.t@samsung.com>,
	linux-fsd@tesla.com
Subject: [PATCH 08/20] media: s5p-mfc: Add support for VP9 encoder.
Date: Tue, 17 May 2022 18:25:36 +0530	[thread overview]
Message-ID: <20220517125548.14746-9-smitha.t@samsung.com> (raw)
In-Reply-To: <20220517125548.14746-1-smitha.t@samsung.com>

Add VP9 encoder support and necessary registers,
V4L2 CIDs, vp9 encoder parameters.

Cc: linux-fsd@tesla.com
Signed-off-by: Smitha T Murthy <smitha.t@samsung.com>
---
 .../platform/samsung/s5p-mfc/regs-mfc-v12.h   |   9 +
 .../platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c |   3 +
 .../platform/samsung/s5p-mfc/s5p_mfc_common.h |  27 +-
 .../platform/samsung/s5p-mfc/s5p_mfc_enc.c    | 272 ++++++++++++++++++
 .../platform/samsung/s5p-mfc/s5p_mfc_opr.h    |   2 +
 .../platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c | 121 ++++++++
 6 files changed, 433 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
index efb77c2bf913..1e2904ab872a 100644
--- a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
+++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
@@ -12,6 +12,10 @@
 #include <linux/sizes.h>
 #include "regs-mfc-v10.h"
 
+/* MFCv12 register definitions*/
+#define S5P_FIMV_E_VP9_OPTION_V12		0xFD90
+#define S5P_FIMV_E_VP9_GOLDEN_FRAME_OPTION_V12	0xFD98
+
 /* MFCv12 Context buffer sizes */
 #define MFC_CTX_BUF_SIZE_V12		(30 * SZ_1K)
 #define MFC_H264_DEC_CTX_BUF_SIZE_V12   (2 * SZ_1M)
@@ -25,6 +29,7 @@
 #define MAX_CPB_SIZE_V12		(7 * SZ_1M)
 #define MFC_VERSION_V12			0xC0
 #define MFC_NUM_PORTS_V12		1
+#define S5P_FIMV_CODEC_VP9_ENC		27
 
 /* Encoder buffer size for MFCv12 */
 #define ENC_V120_BASE_SIZE(x, y) \
@@ -46,4 +51,8 @@
 	(((x + 3) * (y + 3) * 32)       \
 	+ (((y * 128) + 2304) * (x + 3) / 4))
 
+#define ENC_V120_VP9_ME_SIZE(x, y)      \
+	((((x * 2) + 3) * ((y * 2) + 3) * 128)	\
+	+ (((y * 256) + 2304) * (x + 1) / 2))
+
 #endif /*_REGS_MFC_V12_H*/
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c
index f8588e52dfc8..d524815cd38a 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c
@@ -121,6 +121,9 @@ static int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx)
 	case S5P_MFC_CODEC_HEVC_ENC:
 		codec_type = S5P_FIMV_CODEC_HEVC_ENC;
 		break;
+	case S5P_MFC_CODEC_VP9_ENC:
+		codec_type = S5P_FIMV_CODEC_VP9_ENC;
+		break;
 	default:
 		codec_type = S5P_FIMV_CODEC_NONE_V6;
 	}
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
index eed4d8f71a3a..04cdfeca13d3 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
@@ -57,7 +57,7 @@
 #define MFC_ENC_CAP_PLANE_COUNT	1
 #define MFC_ENC_OUT_PLANE_COUNT	2
 #define STUFF_BYTE		4
-#define MFC_MAX_CTRLS		128
+#define MFC_MAX_CTRLS		147
 
 #define S5P_MFC_CODEC_NONE		-1
 #define S5P_MFC_CODEC_H264_DEC		0
@@ -77,6 +77,7 @@
 #define S5P_MFC_CODEC_H263_ENC		23
 #define S5P_MFC_CODEC_VP8_ENC		24
 #define S5P_MFC_CODEC_HEVC_ENC		26
+#define S5P_MFC_CODEC_VP9_ENC		27
 
 #define S5P_MFC_R2H_CMD_EMPTY			0
 #define S5P_MFC_R2H_CMD_SYS_INIT_RET		1
@@ -483,6 +484,29 @@ struct s5p_mfc_hevc_enc_params {
 	u8 prepend_sps_pps_to_idr;
 };
 
+/**
+ * struct s5p_mfc_vp9_enc_params - encoding parameters for vp9
+ */
+struct s5p_mfc_vp9_enc_params {
+	u32 rc_framerate;
+	u8 vp9_profile;
+	u8 rc_min_qp;
+	u8 rc_max_qp;
+	u8 rc_frame_qp;
+	u8 rc_p_frame_qp;
+	u8 vp9_goldenframesel;
+	u8 vp9_gfrefreshperiod;
+	u8 hier_qp_enable;
+	u8 hier_qp_layer[3];
+	u8 hier_rc_enable;
+	u32 hier_bit_layer[3];
+	u8 num_refs_for_p;
+	u8 num_hier_layer;
+	u8 max_partition_depth;
+	u8 intra_pu_split_disable;
+	u8 ivf_header;
+};
+
 /*
  * struct s5p_mfc_enc_params - general encoding parameters
  */
@@ -521,6 +545,7 @@ struct s5p_mfc_enc_params {
 		struct s5p_mfc_mpeg4_enc_params mpeg4;
 		struct s5p_mfc_vp8_enc_params vp8;
 		struct s5p_mfc_hevc_enc_params hevc;
+		struct s5p_mfc_vp9_enc_params vp9;
 	} codec;
 
 };
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
index ae2c0977b24e..b5f9e7bbdead 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
@@ -94,6 +94,13 @@ static struct s5p_mfc_fmt formats[] = {
 		.num_planes	= 1,
 		.versions	= MFC_V10_BIT | MFC_V12_BIT,
 	},
+	{
+		.fourcc		= V4L2_PIX_FMT_VP9,
+		.codec_mode	= S5P_FIMV_CODEC_VP9_ENC,
+		.type		= MFC_FMT_ENC,
+		.num_planes	= 1,
+		.versions	= MFC_V12_BIT,
+	},
 };
 
 #define NUM_FORMATS ARRAY_SIZE(formats)
@@ -1055,6 +1062,174 @@ static struct mfc_control controls[] = {
 		.step = 1,
 		.default_value = 0,
 	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_PROFILE,
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_VP9_PROFILE_0,
+		.maximum = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
+		.step = 1,
+		.default_value = V4L2_MPEG_VIDEO_VP9_PROFILE_0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_I_FRAME_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 255,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_P_FRAME_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 255,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_MAX_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 230,
+		.maximum = 255,
+		.step = 1,
+		.default_value = 255,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_MIN_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 24,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_RC_FRAME_RATE,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = (1 << 16) - 1,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_GOLDEN_FRAMESEL,
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_CID_MPEG_VIDEO_VP9_GOLDEN_FRAME_USE_PREV,
+		.maximum = V4L2_CID_MPEG_VIDEO_VP9_GOLDEN_FRAME_USE_REF_PERIOD,
+		.step = 1,
+		.default_value = V4L2_CID_MPEG_VIDEO_VP9_GOLDEN_FRAME_USE_PREV,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_GF_REFRESH_PERIOD,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = ((1 << 16) - 1),
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_HIERARCHY_QP_ENABLE,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_HIERARCHY_RC_ENABLE,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L0_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = INT_MIN,
+		.maximum = INT_MAX,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L1_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = INT_MIN,
+		.maximum = INT_MAX,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L2_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = INT_MIN,
+		.maximum = INT_MAX,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_REF_NUMBER_FOR_PFRAMES,
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_CID_MPEG_VIDEO_VP9_1_REF_PFRAME,
+		.maximum = V4L2_CID_MPEG_VIDEO_VP9_2_REF_PFRAME,
+		.step = 1,
+		.default_value = V4L2_CID_MPEG_VIDEO_VP9_1_REF_PFRAME,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 2,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_MAX_PARTITION_DEPTH,
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_CID_MPEG_VIDEO_VP9_0_PARTITION,
+		.maximum = V4L2_CID_MPEG_VIDEO_VP9_1_PARTITION,
+		.step = 1,
+		.default_value = V4L2_CID_MPEG_VIDEO_VP9_0_PARTITION,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_DISABLE_INTRA_PU_SPLIT,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L0_BR,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = INT_MIN,
+		.maximum = INT_MAX,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L1_BR,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = INT_MIN,
+		.maximum = INT_MAX,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L2_BR,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = INT_MIN,
+		.maximum = INT_MAX,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_DISABLE_IVF_HEADER,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 0,
+	},
 	{
 		.id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT,
 		.type = V4L2_CTRL_TYPE_INTEGER,
@@ -1793,6 +1968,36 @@ static void __enc_update_hevc_qp_ctrls_range(struct s5p_mfc_ctx *ctx,
 	}
 }
 
+/*
+ * Update range of all VP9 quantization parameter controls that depend on the
+ * V4L2_CID_MPEG_VIDEO_VP9_MIN_QP, V4L2_CID_MPEG_VIDEO_VP9_MAX_QP controls.
+ */
+static void __enc_update_vp9_qp_ctrls_range(struct s5p_mfc_ctx *ctx,
+						int min, int max)
+{
+	static const int __vp9_qp_ctrls[] = {
+		V4L2_CID_MPEG_VIDEO_VP9_I_FRAME_QP,
+		V4L2_CID_MPEG_VIDEO_VP9_P_FRAME_QP,
+		V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L0_QP,
+		V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L1_QP,
+		V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L2_QP,
+	};
+	struct v4l2_ctrl *ctrl = NULL;
+	int i, j;
+
+	for (i = 0; i < ARRAY_SIZE(__vp9_qp_ctrls); i++) {
+		for (j = 0; j < ARRAY_SIZE(ctx->ctrls); j++) {
+			if (ctx->ctrls[j]->id == __vp9_qp_ctrls[i]) {
+				ctrl = ctx->ctrls[j];
+				break;
+			}
+		}
+		if (WARN_ON(!ctrl))
+			break;
+		__v4l2_ctrl_modify_range(ctrl, min, max, ctrl->step, min);
+	}
+}
+
 static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
 {
 	struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
@@ -2196,6 +2401,73 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
 	case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR:
 		p->codec.hevc.prepend_sps_pps_to_idr = ctrl->val;
 		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_PROFILE:
+		p->codec.vp9.vp9_profile = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_RC_FRAME_RATE:
+		p->codec.vp9.rc_framerate = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_MIN_QP:
+		p->codec.vp9.rc_min_qp = ctrl->val;
+		__enc_update_vp9_qp_ctrls_range(ctx, ctrl->val,
+			p->codec.vp9.rc_max_qp);
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_MAX_QP:
+		p->codec.vp9.rc_max_qp = ctrl->val;
+		__enc_update_vp9_qp_ctrls_range(ctx,
+				p->codec.vp9.rc_min_qp, ctrl->val);
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_I_FRAME_QP:
+		p->codec.vp9.rc_frame_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_P_FRAME_QP:
+		p->codec.vp9.rc_p_frame_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_GOLDEN_FRAMESEL:
+		p->codec.vp9.vp9_goldenframesel = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_GF_REFRESH_PERIOD:
+		p->codec.vp9.vp9_gfrefreshperiod = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHY_QP_ENABLE:
+		p->codec.vp9.hier_qp_enable = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHY_RC_ENABLE:
+		p->codec.vp9.hier_rc_enable = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L0_QP:
+		p->codec.vp9.hier_qp_layer[0] = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L1_QP:
+		p->codec.vp9.hier_qp_layer[1] = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L2_QP:
+		p->codec.vp9.hier_qp_layer[2] = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L0_BR:
+		p->codec.vp9.hier_bit_layer[0] = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L1_BR:
+		p->codec.vp9.hier_bit_layer[1] = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L2_BR:
+		p->codec.vp9.hier_bit_layer[2] = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_REF_NUMBER_FOR_PFRAMES:
+		p->codec.vp9.num_refs_for_p = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER:
+		p->codec.vp9.num_hier_layer = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_MAX_PARTITION_DEPTH:
+		p->codec.vp9.max_partition_depth = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_DISABLE_INTRA_PU_SPLIT:
+		p->codec.vp9.intra_pu_split_disable = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_DISABLE_IVF_HEADER:
+		p->codec.vp9.ivf_header = ctrl->val;
+		break;
 	default:
 		v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n",
 							ctrl->id, ctrl->val);
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
index 87ac56756a16..a005623e2daa 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
@@ -277,6 +277,8 @@ struct s5p_mfc_regs {
 	void __iomem *e_hevc_lf_beta_offset_div2; /* v10 */
 	void __iomem *e_hevc_lf_tc_offset_div2; /* v10 */
 	void __iomem *e_hevc_nal_control; /* v10 */
+	void __iomem *e_vp9_options; /* v12 */
+	void __iomem *e_vp9_golden_frame_option; /* v12 */
 };
 
 struct s5p_mfc_hw_ops {
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
index 98c524688b45..913fe5d5a93a 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
@@ -374,6 +374,17 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
 			ctx->chroma_dpb_size + ctx->me_buffer_size));
 		ctx->bank2.size = 0;
 		break;
+	case S5P_FIMV_CODEC_VP9_ENC:
+		mfc_debug(2, "Use min scratch buffer size\n");
+		ctx->me_buffer_size =
+			ALIGN(ENC_V120_VP9_ME_SIZE(lcu_width, lcu_height), 16);
+		ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+		ctx->bank1.size =
+			ctx->scratch_buf_size + ctx->tmv_buffer_size +
+			(ctx->pb_count * (ctx->luma_dpb_size +
+			ctx->chroma_dpb_size + ctx->me_buffer_size));
+		ctx->bank2.size = 0;
+		break;
 	default:
 		break;
 	}
@@ -429,6 +440,7 @@ static int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx)
 	case S5P_MFC_CODEC_MPEG4_ENC:
 	case S5P_MFC_CODEC_H263_ENC:
 	case S5P_MFC_CODEC_VP8_ENC:
+	case S5P_FIMV_CODEC_VP9_ENC:
 		ctx->ctx.size = buf_size->other_enc_ctx;
 		break;
 	default:
@@ -1663,6 +1675,102 @@ static int s5p_mfc_set_enc_params_hevc(struct s5p_mfc_ctx *ctx)
 	return 0;
 }
 
+int s5p_mfc_set_enc_params_vp9(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
+	struct s5p_mfc_enc_params *p = &ctx->enc_params;
+	struct s5p_mfc_vp9_enc_params *p_vp9 = &p->codec.vp9;
+	unsigned int reg = 0;
+	int i;
+
+	mfc_debug_enter();
+
+	s5p_mfc_set_enc_params(ctx);
+
+	/* profile*/
+	reg = 0;
+	reg |= (p_vp9->vp9_profile);
+	writel(reg, mfc_regs->e_picture_profile);
+
+	reg = 0;
+	reg |= ((p_vp9->ivf_header & 0x1) << 12);
+	reg |= ((p_vp9->hier_qp_enable & 0x1) << 11);
+	reg |= (p_vp9->max_partition_depth & 0x1) << 3;
+	reg |= (p_vp9->intra_pu_split_disable & 0x1) << 1;
+	reg |= (p_vp9->num_refs_for_p - 1) & 0x1;
+	writel(reg, mfc_regs->e_vp9_options);
+
+	reg = 0;
+	reg |= (p_vp9->vp9_goldenframesel & 0x1);
+	reg |= (p_vp9->vp9_gfrefreshperiod & 0xffff) << 1;
+	writel(reg, mfc_regs->e_vp9_golden_frame_option);
+
+	reg = 0;
+	if (p_vp9->num_hier_layer) {
+		reg |= p_vp9->num_hier_layer & 0x3;
+		writel(reg, mfc_regs->e_num_t_layer);
+		/* QP value for each layer */
+		if (p_vp9->hier_qp_enable) {
+			for (i = 0; i < (p_vp9->num_hier_layer & 0x3); i++)
+				writel(p_vp9->hier_qp_layer[i],
+						mfc_regs->e_hier_qp_layer0
+						+ i * 4);
+		}
+		if (p_vp9->hier_rc_enable) {
+			for (i = 0; i < (p_vp9->num_hier_layer & 0x3); i++)
+				writel(p_vp9->hier_bit_layer[i],
+						mfc_regs->e_hier_bit_rate_layer0
+						+ i * 4);
+		}
+	}
+	/* number of coding layer should be zero when hierarchical is disable */
+	reg |= p_vp9->num_hier_layer;
+	writel(reg, mfc_regs->e_num_t_layer);
+
+	/* qp */
+	writel(0x0, mfc_regs->e_fixed_picture_qp);
+	if (!p->rc_frame && !p->rc_mb) {
+		reg = 0;
+		reg &= ~(0xff << 8);
+		reg |= (p_vp9->rc_p_frame_qp << 8);
+		reg &= ~(0xff);
+		reg |= p_vp9->rc_frame_qp;
+		writel(reg, mfc_regs->e_fixed_picture_qp);
+	}
+
+	/* frame rate */
+	if (p->rc_frame) {
+		reg = 0;
+		reg &= ~(0xffff << 16);
+		reg |= ((p_vp9->rc_framerate * FRAME_DELTA_DEFAULT) << 16);
+		reg &= ~(0xffff);
+		reg |= FRAME_DELTA_DEFAULT;
+		writel(reg, mfc_regs->e_rc_frame_rate);
+	}
+
+	/* rate control config. */
+	reg = readl(mfc_regs->e_rc_config);
+	/** macroblock level rate control */
+	reg &= ~(0x1 << 8);
+	reg |= ((p->rc_mb & 0x1) << 8);
+	writel(reg, mfc_regs->e_rc_config);
+
+	/* max & min value of QP */
+	reg = 0;
+	/** max QP */
+	reg &= ~(0xFF << 8);
+	reg |= (p_vp9->rc_max_qp << 8);
+	/** min QP */
+	reg &= ~(0xFF);
+	reg |= p_vp9->rc_min_qp;
+	writel(reg, mfc_regs->e_rc_qp_bound);
+
+	mfc_debug_leave();
+
+	return 0;
+}
+
 /* Initialize decoding */
 static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
 {
@@ -1784,6 +1892,8 @@ static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx)
 		s5p_mfc_set_enc_params_vp8(ctx);
 	else if (ctx->codec_mode == S5P_FIMV_CODEC_HEVC_ENC)
 		s5p_mfc_set_enc_params_hevc(ctx);
+	else if (ctx->codec_mode == S5P_FIMV_CODEC_VP9_ENC)
+		s5p_mfc_set_enc_params_vp9(ctx);
 	else {
 		mfc_err("Unknown codec for encoding (%x).\n",
 			ctx->codec_mode);
@@ -2547,6 +2657,17 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev)
 	R(e_hevc_lf_tc_offset_div2, S5P_FIMV_E_HEVC_LF_TC_OFFSET_DIV2_V10);
 	R(e_hevc_nal_control, S5P_FIMV_E_HEVC_NAL_CONTROL_V10);
 
+	if (!IS_MFCV12(dev))
+		goto done;
+
+	/* Initialize registers used in MFC v10 only.
+	 * Also, over-write the registers which have
+	 * a different offset for MFC v10.
+	 */
+
+	R(e_vp9_options, S5P_FIMV_E_VP9_OPTION_V12);
+	R(e_vp9_golden_frame_option, S5P_FIMV_E_VP9_GOLDEN_FRAME_OPTION_V12);
+
 done:
 	return &mfc_regs;
 #undef S5P_MFC_REG_ADDR
-- 
2.17.1


WARNING: multiple messages have this Message-ID (diff)
From: Smitha T Murthy <smitha.t@samsung.com>
To: linux-arm-kernel@lists.infradead.org,
	linux-media@vger.kernel.org, linux-kernel@vger.kernel.org,
	devicetree@vger.kernel.org
Cc: m.szyprowski@samsung.com, andrzej.hajda@intel.com,
	mchehab@kernel.org, hverkuil-cisco@xs4all.nl,
	ezequiel@vanguardiasur.com.ar, jernej.skrabec@gmail.com,
	benjamin.gaignard@collabora.com, stanimir.varbanov@linaro.org,
	dillon.minfei@gmail.com, david.plowman@raspberrypi.com,
	mark.rutland@arm.com, robh+dt@kernel.org, krzk+dt@kernel.org,
	andi@etezian.org, alim.akhtar@samsung.com,
	aswani.reddy@samsung.com, pankaj.dubey@samsung.com,
	Smitha T Murthy <smitha.t@samsung.com>,
	linux-fsd@tesla.com
Subject: [PATCH 08/20] media: s5p-mfc: Add support for VP9 encoder.
Date: Tue, 17 May 2022 18:25:36 +0530	[thread overview]
Message-ID: <20220517125548.14746-9-smitha.t@samsung.com> (raw)
In-Reply-To: <20220517125548.14746-1-smitha.t@samsung.com>

Add VP9 encoder support and necessary registers,
V4L2 CIDs, vp9 encoder parameters.

Cc: linux-fsd@tesla.com
Signed-off-by: Smitha T Murthy <smitha.t@samsung.com>
---
 .../platform/samsung/s5p-mfc/regs-mfc-v12.h   |   9 +
 .../platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c |   3 +
 .../platform/samsung/s5p-mfc/s5p_mfc_common.h |  27 +-
 .../platform/samsung/s5p-mfc/s5p_mfc_enc.c    | 272 ++++++++++++++++++
 .../platform/samsung/s5p-mfc/s5p_mfc_opr.h    |   2 +
 .../platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c | 121 ++++++++
 6 files changed, 433 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
index efb77c2bf913..1e2904ab872a 100644
--- a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
+++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
@@ -12,6 +12,10 @@
 #include <linux/sizes.h>
 #include "regs-mfc-v10.h"
 
+/* MFCv12 register definitions*/
+#define S5P_FIMV_E_VP9_OPTION_V12		0xFD90
+#define S5P_FIMV_E_VP9_GOLDEN_FRAME_OPTION_V12	0xFD98
+
 /* MFCv12 Context buffer sizes */
 #define MFC_CTX_BUF_SIZE_V12		(30 * SZ_1K)
 #define MFC_H264_DEC_CTX_BUF_SIZE_V12   (2 * SZ_1M)
@@ -25,6 +29,7 @@
 #define MAX_CPB_SIZE_V12		(7 * SZ_1M)
 #define MFC_VERSION_V12			0xC0
 #define MFC_NUM_PORTS_V12		1
+#define S5P_FIMV_CODEC_VP9_ENC		27
 
 /* Encoder buffer size for MFCv12 */
 #define ENC_V120_BASE_SIZE(x, y) \
@@ -46,4 +51,8 @@
 	(((x + 3) * (y + 3) * 32)       \
 	+ (((y * 128) + 2304) * (x + 3) / 4))
 
+#define ENC_V120_VP9_ME_SIZE(x, y)      \
+	((((x * 2) + 3) * ((y * 2) + 3) * 128)	\
+	+ (((y * 256) + 2304) * (x + 1) / 2))
+
 #endif /*_REGS_MFC_V12_H*/
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c
index f8588e52dfc8..d524815cd38a 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c
@@ -121,6 +121,9 @@ static int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx)
 	case S5P_MFC_CODEC_HEVC_ENC:
 		codec_type = S5P_FIMV_CODEC_HEVC_ENC;
 		break;
+	case S5P_MFC_CODEC_VP9_ENC:
+		codec_type = S5P_FIMV_CODEC_VP9_ENC;
+		break;
 	default:
 		codec_type = S5P_FIMV_CODEC_NONE_V6;
 	}
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
index eed4d8f71a3a..04cdfeca13d3 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
@@ -57,7 +57,7 @@
 #define MFC_ENC_CAP_PLANE_COUNT	1
 #define MFC_ENC_OUT_PLANE_COUNT	2
 #define STUFF_BYTE		4
-#define MFC_MAX_CTRLS		128
+#define MFC_MAX_CTRLS		147
 
 #define S5P_MFC_CODEC_NONE		-1
 #define S5P_MFC_CODEC_H264_DEC		0
@@ -77,6 +77,7 @@
 #define S5P_MFC_CODEC_H263_ENC		23
 #define S5P_MFC_CODEC_VP8_ENC		24
 #define S5P_MFC_CODEC_HEVC_ENC		26
+#define S5P_MFC_CODEC_VP9_ENC		27
 
 #define S5P_MFC_R2H_CMD_EMPTY			0
 #define S5P_MFC_R2H_CMD_SYS_INIT_RET		1
@@ -483,6 +484,29 @@ struct s5p_mfc_hevc_enc_params {
 	u8 prepend_sps_pps_to_idr;
 };
 
+/**
+ * struct s5p_mfc_vp9_enc_params - encoding parameters for vp9
+ */
+struct s5p_mfc_vp9_enc_params {
+	u32 rc_framerate;
+	u8 vp9_profile;
+	u8 rc_min_qp;
+	u8 rc_max_qp;
+	u8 rc_frame_qp;
+	u8 rc_p_frame_qp;
+	u8 vp9_goldenframesel;
+	u8 vp9_gfrefreshperiod;
+	u8 hier_qp_enable;
+	u8 hier_qp_layer[3];
+	u8 hier_rc_enable;
+	u32 hier_bit_layer[3];
+	u8 num_refs_for_p;
+	u8 num_hier_layer;
+	u8 max_partition_depth;
+	u8 intra_pu_split_disable;
+	u8 ivf_header;
+};
+
 /*
  * struct s5p_mfc_enc_params - general encoding parameters
  */
@@ -521,6 +545,7 @@ struct s5p_mfc_enc_params {
 		struct s5p_mfc_mpeg4_enc_params mpeg4;
 		struct s5p_mfc_vp8_enc_params vp8;
 		struct s5p_mfc_hevc_enc_params hevc;
+		struct s5p_mfc_vp9_enc_params vp9;
 	} codec;
 
 };
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
index ae2c0977b24e..b5f9e7bbdead 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
@@ -94,6 +94,13 @@ static struct s5p_mfc_fmt formats[] = {
 		.num_planes	= 1,
 		.versions	= MFC_V10_BIT | MFC_V12_BIT,
 	},
+	{
+		.fourcc		= V4L2_PIX_FMT_VP9,
+		.codec_mode	= S5P_FIMV_CODEC_VP9_ENC,
+		.type		= MFC_FMT_ENC,
+		.num_planes	= 1,
+		.versions	= MFC_V12_BIT,
+	},
 };
 
 #define NUM_FORMATS ARRAY_SIZE(formats)
@@ -1055,6 +1062,174 @@ static struct mfc_control controls[] = {
 		.step = 1,
 		.default_value = 0,
 	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_PROFILE,
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_VP9_PROFILE_0,
+		.maximum = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
+		.step = 1,
+		.default_value = V4L2_MPEG_VIDEO_VP9_PROFILE_0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_I_FRAME_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 255,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_P_FRAME_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 255,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_MAX_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 230,
+		.maximum = 255,
+		.step = 1,
+		.default_value = 255,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_MIN_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 24,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_RC_FRAME_RATE,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = (1 << 16) - 1,
+		.step = 1,
+		.default_value = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_GOLDEN_FRAMESEL,
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_CID_MPEG_VIDEO_VP9_GOLDEN_FRAME_USE_PREV,
+		.maximum = V4L2_CID_MPEG_VIDEO_VP9_GOLDEN_FRAME_USE_REF_PERIOD,
+		.step = 1,
+		.default_value = V4L2_CID_MPEG_VIDEO_VP9_GOLDEN_FRAME_USE_PREV,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_GF_REFRESH_PERIOD,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = ((1 << 16) - 1),
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_HIERARCHY_QP_ENABLE,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_HIERARCHY_RC_ENABLE,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L0_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = INT_MIN,
+		.maximum = INT_MAX,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L1_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = INT_MIN,
+		.maximum = INT_MAX,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L2_QP,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = INT_MIN,
+		.maximum = INT_MAX,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_REF_NUMBER_FOR_PFRAMES,
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_CID_MPEG_VIDEO_VP9_1_REF_PFRAME,
+		.maximum = V4L2_CID_MPEG_VIDEO_VP9_2_REF_PFRAME,
+		.step = 1,
+		.default_value = V4L2_CID_MPEG_VIDEO_VP9_1_REF_PFRAME,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 2,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_MAX_PARTITION_DEPTH,
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_CID_MPEG_VIDEO_VP9_0_PARTITION,
+		.maximum = V4L2_CID_MPEG_VIDEO_VP9_1_PARTITION,
+		.step = 1,
+		.default_value = V4L2_CID_MPEG_VIDEO_VP9_0_PARTITION,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_DISABLE_INTRA_PU_SPLIT,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L0_BR,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = INT_MIN,
+		.maximum = INT_MAX,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L1_BR,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = INT_MIN,
+		.maximum = INT_MAX,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L2_BR,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = INT_MIN,
+		.maximum = INT_MAX,
+		.step = 1,
+		.default_value = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VP9_DISABLE_IVF_HEADER,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 0,
+	},
 	{
 		.id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT,
 		.type = V4L2_CTRL_TYPE_INTEGER,
@@ -1793,6 +1968,36 @@ static void __enc_update_hevc_qp_ctrls_range(struct s5p_mfc_ctx *ctx,
 	}
 }
 
+/*
+ * Update range of all VP9 quantization parameter controls that depend on the
+ * V4L2_CID_MPEG_VIDEO_VP9_MIN_QP, V4L2_CID_MPEG_VIDEO_VP9_MAX_QP controls.
+ */
+static void __enc_update_vp9_qp_ctrls_range(struct s5p_mfc_ctx *ctx,
+						int min, int max)
+{
+	static const int __vp9_qp_ctrls[] = {
+		V4L2_CID_MPEG_VIDEO_VP9_I_FRAME_QP,
+		V4L2_CID_MPEG_VIDEO_VP9_P_FRAME_QP,
+		V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L0_QP,
+		V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L1_QP,
+		V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L2_QP,
+	};
+	struct v4l2_ctrl *ctrl = NULL;
+	int i, j;
+
+	for (i = 0; i < ARRAY_SIZE(__vp9_qp_ctrls); i++) {
+		for (j = 0; j < ARRAY_SIZE(ctx->ctrls); j++) {
+			if (ctx->ctrls[j]->id == __vp9_qp_ctrls[i]) {
+				ctrl = ctx->ctrls[j];
+				break;
+			}
+		}
+		if (WARN_ON(!ctrl))
+			break;
+		__v4l2_ctrl_modify_range(ctrl, min, max, ctrl->step, min);
+	}
+}
+
 static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
 {
 	struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
@@ -2196,6 +2401,73 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
 	case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR:
 		p->codec.hevc.prepend_sps_pps_to_idr = ctrl->val;
 		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_PROFILE:
+		p->codec.vp9.vp9_profile = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_RC_FRAME_RATE:
+		p->codec.vp9.rc_framerate = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_MIN_QP:
+		p->codec.vp9.rc_min_qp = ctrl->val;
+		__enc_update_vp9_qp_ctrls_range(ctx, ctrl->val,
+			p->codec.vp9.rc_max_qp);
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_MAX_QP:
+		p->codec.vp9.rc_max_qp = ctrl->val;
+		__enc_update_vp9_qp_ctrls_range(ctx,
+				p->codec.vp9.rc_min_qp, ctrl->val);
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_I_FRAME_QP:
+		p->codec.vp9.rc_frame_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_P_FRAME_QP:
+		p->codec.vp9.rc_p_frame_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_GOLDEN_FRAMESEL:
+		p->codec.vp9.vp9_goldenframesel = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_GF_REFRESH_PERIOD:
+		p->codec.vp9.vp9_gfrefreshperiod = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHY_QP_ENABLE:
+		p->codec.vp9.hier_qp_enable = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHY_RC_ENABLE:
+		p->codec.vp9.hier_rc_enable = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L0_QP:
+		p->codec.vp9.hier_qp_layer[0] = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L1_QP:
+		p->codec.vp9.hier_qp_layer[1] = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L2_QP:
+		p->codec.vp9.hier_qp_layer[2] = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L0_BR:
+		p->codec.vp9.hier_bit_layer[0] = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L1_BR:
+		p->codec.vp9.hier_bit_layer[1] = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_HIER_CODING_L2_BR:
+		p->codec.vp9.hier_bit_layer[2] = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_REF_NUMBER_FOR_PFRAMES:
+		p->codec.vp9.num_refs_for_p = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER:
+		p->codec.vp9.num_hier_layer = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_MAX_PARTITION_DEPTH:
+		p->codec.vp9.max_partition_depth = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_DISABLE_INTRA_PU_SPLIT:
+		p->codec.vp9.intra_pu_split_disable = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_VP9_DISABLE_IVF_HEADER:
+		p->codec.vp9.ivf_header = ctrl->val;
+		break;
 	default:
 		v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n",
 							ctrl->id, ctrl->val);
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
index 87ac56756a16..a005623e2daa 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
@@ -277,6 +277,8 @@ struct s5p_mfc_regs {
 	void __iomem *e_hevc_lf_beta_offset_div2; /* v10 */
 	void __iomem *e_hevc_lf_tc_offset_div2; /* v10 */
 	void __iomem *e_hevc_nal_control; /* v10 */
+	void __iomem *e_vp9_options; /* v12 */
+	void __iomem *e_vp9_golden_frame_option; /* v12 */
 };
 
 struct s5p_mfc_hw_ops {
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
index 98c524688b45..913fe5d5a93a 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
@@ -374,6 +374,17 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
 			ctx->chroma_dpb_size + ctx->me_buffer_size));
 		ctx->bank2.size = 0;
 		break;
+	case S5P_FIMV_CODEC_VP9_ENC:
+		mfc_debug(2, "Use min scratch buffer size\n");
+		ctx->me_buffer_size =
+			ALIGN(ENC_V120_VP9_ME_SIZE(lcu_width, lcu_height), 16);
+		ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+		ctx->bank1.size =
+			ctx->scratch_buf_size + ctx->tmv_buffer_size +
+			(ctx->pb_count * (ctx->luma_dpb_size +
+			ctx->chroma_dpb_size + ctx->me_buffer_size));
+		ctx->bank2.size = 0;
+		break;
 	default:
 		break;
 	}
@@ -429,6 +440,7 @@ static int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx)
 	case S5P_MFC_CODEC_MPEG4_ENC:
 	case S5P_MFC_CODEC_H263_ENC:
 	case S5P_MFC_CODEC_VP8_ENC:
+	case S5P_FIMV_CODEC_VP9_ENC:
 		ctx->ctx.size = buf_size->other_enc_ctx;
 		break;
 	default:
@@ -1663,6 +1675,102 @@ static int s5p_mfc_set_enc_params_hevc(struct s5p_mfc_ctx *ctx)
 	return 0;
 }
 
+int s5p_mfc_set_enc_params_vp9(struct s5p_mfc_ctx *ctx)
+{
+	struct s5p_mfc_dev *dev = ctx->dev;
+	const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
+	struct s5p_mfc_enc_params *p = &ctx->enc_params;
+	struct s5p_mfc_vp9_enc_params *p_vp9 = &p->codec.vp9;
+	unsigned int reg = 0;
+	int i;
+
+	mfc_debug_enter();
+
+	s5p_mfc_set_enc_params(ctx);
+
+	/* profile*/
+	reg = 0;
+	reg |= (p_vp9->vp9_profile);
+	writel(reg, mfc_regs->e_picture_profile);
+
+	reg = 0;
+	reg |= ((p_vp9->ivf_header & 0x1) << 12);
+	reg |= ((p_vp9->hier_qp_enable & 0x1) << 11);
+	reg |= (p_vp9->max_partition_depth & 0x1) << 3;
+	reg |= (p_vp9->intra_pu_split_disable & 0x1) << 1;
+	reg |= (p_vp9->num_refs_for_p - 1) & 0x1;
+	writel(reg, mfc_regs->e_vp9_options);
+
+	reg = 0;
+	reg |= (p_vp9->vp9_goldenframesel & 0x1);
+	reg |= (p_vp9->vp9_gfrefreshperiod & 0xffff) << 1;
+	writel(reg, mfc_regs->e_vp9_golden_frame_option);
+
+	reg = 0;
+	if (p_vp9->num_hier_layer) {
+		reg |= p_vp9->num_hier_layer & 0x3;
+		writel(reg, mfc_regs->e_num_t_layer);
+		/* QP value for each layer */
+		if (p_vp9->hier_qp_enable) {
+			for (i = 0; i < (p_vp9->num_hier_layer & 0x3); i++)
+				writel(p_vp9->hier_qp_layer[i],
+						mfc_regs->e_hier_qp_layer0
+						+ i * 4);
+		}
+		if (p_vp9->hier_rc_enable) {
+			for (i = 0; i < (p_vp9->num_hier_layer & 0x3); i++)
+				writel(p_vp9->hier_bit_layer[i],
+						mfc_regs->e_hier_bit_rate_layer0
+						+ i * 4);
+		}
+	}
+	/* number of coding layer should be zero when hierarchical is disable */
+	reg |= p_vp9->num_hier_layer;
+	writel(reg, mfc_regs->e_num_t_layer);
+
+	/* qp */
+	writel(0x0, mfc_regs->e_fixed_picture_qp);
+	if (!p->rc_frame && !p->rc_mb) {
+		reg = 0;
+		reg &= ~(0xff << 8);
+		reg |= (p_vp9->rc_p_frame_qp << 8);
+		reg &= ~(0xff);
+		reg |= p_vp9->rc_frame_qp;
+		writel(reg, mfc_regs->e_fixed_picture_qp);
+	}
+
+	/* frame rate */
+	if (p->rc_frame) {
+		reg = 0;
+		reg &= ~(0xffff << 16);
+		reg |= ((p_vp9->rc_framerate * FRAME_DELTA_DEFAULT) << 16);
+		reg &= ~(0xffff);
+		reg |= FRAME_DELTA_DEFAULT;
+		writel(reg, mfc_regs->e_rc_frame_rate);
+	}
+
+	/* rate control config. */
+	reg = readl(mfc_regs->e_rc_config);
+	/** macroblock level rate control */
+	reg &= ~(0x1 << 8);
+	reg |= ((p->rc_mb & 0x1) << 8);
+	writel(reg, mfc_regs->e_rc_config);
+
+	/* max & min value of QP */
+	reg = 0;
+	/** max QP */
+	reg &= ~(0xFF << 8);
+	reg |= (p_vp9->rc_max_qp << 8);
+	/** min QP */
+	reg &= ~(0xFF);
+	reg |= p_vp9->rc_min_qp;
+	writel(reg, mfc_regs->e_rc_qp_bound);
+
+	mfc_debug_leave();
+
+	return 0;
+}
+
 /* Initialize decoding */
 static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
 {
@@ -1784,6 +1892,8 @@ static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx)
 		s5p_mfc_set_enc_params_vp8(ctx);
 	else if (ctx->codec_mode == S5P_FIMV_CODEC_HEVC_ENC)
 		s5p_mfc_set_enc_params_hevc(ctx);
+	else if (ctx->codec_mode == S5P_FIMV_CODEC_VP9_ENC)
+		s5p_mfc_set_enc_params_vp9(ctx);
 	else {
 		mfc_err("Unknown codec for encoding (%x).\n",
 			ctx->codec_mode);
@@ -2547,6 +2657,17 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev)
 	R(e_hevc_lf_tc_offset_div2, S5P_FIMV_E_HEVC_LF_TC_OFFSET_DIV2_V10);
 	R(e_hevc_nal_control, S5P_FIMV_E_HEVC_NAL_CONTROL_V10);
 
+	if (!IS_MFCV12(dev))
+		goto done;
+
+	/* Initialize registers used in MFC v10 only.
+	 * Also, over-write the registers which have
+	 * a different offset for MFC v10.
+	 */
+
+	R(e_vp9_options, S5P_FIMV_E_VP9_OPTION_V12);
+	R(e_vp9_golden_frame_option, S5P_FIMV_E_VP9_GOLDEN_FRAME_OPTION_V12);
+
 done:
 	return &mfc_regs;
 #undef S5P_MFC_REG_ADDR
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  parent reply	other threads:[~2022-05-17 12:59 UTC|newest]

Thread overview: 92+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <CGME20220517125511epcas5p4e9a4e3c327771dd1faf0a50057a2c17b@epcas5p4.samsung.com>
2022-05-17 12:55 ` [PATCH 00/20] Add MFC v12 support Smitha T Murthy
2022-05-17 12:55   ` Smitha T Murthy
     [not found]   ` <CGME20220517125551epcas5p42cca7f0a2db6dc1d16d0e27265c43f56@epcas5p4.samsung.com>
2022-05-17 12:55     ` [PATCH 01/20] MAINTAINERS: Add git repo path for MFC Smitha T Murthy
2022-05-17 12:55       ` Smitha T Murthy
2022-05-17 13:35       ` Krzysztof Kozlowski
2022-05-17 13:35         ` Krzysztof Kozlowski
     [not found]   ` <CGME20220517125554epcas5p4e87a71471525056281f1578f4f80f760@epcas5p4.samsung.com>
2022-05-17 12:55     ` [PATCH 02/20] dt-bindings: media: s5p-mfc: Convert s5p-mfc.txt to new DT schema Smitha T Murthy
2022-05-17 12:55       ` Smitha T Murthy
2022-05-17 13:55       ` Krzysztof Kozlowski
2022-05-17 13:55         ` Krzysztof Kozlowski
2022-07-05 11:44         ` Smitha T Murthy
2022-07-05 11:44           ` Smitha T Murthy
2022-07-05 12:08           ` Krzysztof Kozlowski
2022-07-05 12:08             ` Krzysztof Kozlowski
2022-05-17 20:19       ` Rob Herring
2022-05-17 20:19         ` Rob Herring
     [not found]   ` <CGME20220517125558epcas5p228cdf5f665468d3fd065d88a5d0ad157@epcas5p2.samsung.com>
2022-05-17 12:55     ` [PATCH 03/20] dt-bindings: media: s5p-mfc: Add mfcv12 variant Smitha T Murthy
2022-05-17 12:55       ` Smitha T Murthy
2022-05-17 13:58       ` Krzysztof Kozlowski
2022-05-17 13:58         ` Krzysztof Kozlowski
2022-07-05 11:46         ` Smitha T Murthy
2022-07-05 11:46           ` Smitha T Murthy
     [not found]   ` <CGME20220517125601epcas5p47dfcac0c5e0c412eb0c335759c51c941@epcas5p4.samsung.com>
2022-05-17 12:55     ` [PATCH 04/20] media: s5p-mfc: Rename IS_MFCV10 macro Smitha T Murthy
2022-05-17 12:55       ` Smitha T Murthy
2022-05-18  8:41       ` Andrzej Hajda
2022-05-18  8:41         ` Andrzej Hajda
2022-05-19  6:46         ` Andrzej Hajda
2022-05-19  6:46           ` Andrzej Hajda
     [not found]   ` <CGME20220517125605epcas5p44cbb77e6bc15ceb32a934e326fc777ef@epcas5p4.samsung.com>
2022-05-17 12:55     ` [PATCH 05/20] media: s5p-mfc: Add initial support for MFCv12 Smitha T Murthy
2022-05-17 12:55       ` Smitha T Murthy
2022-05-18 11:38       ` Andrzej Hajda
2022-05-18 11:38         ` Andrzej Hajda
     [not found]   ` <CGME20220517125608epcas5p48b5d2f91c711e5728f993169b1d4b9a1@epcas5p4.samsung.com>
2022-05-17 12:55     ` [PATCH 06/20] Documention: v4l: Documentation for VP9 CIDs Smitha T Murthy
2022-05-17 12:55       ` Smitha T Murthy
2022-05-17 13:13       ` Nicolas Dufresne
2022-05-17 13:13         ` Nicolas Dufresne
2022-07-05 11:26         ` Smitha T Murthy
2022-07-05 11:26           ` Smitha T Murthy
2022-05-18  9:45       ` Hans Verkuil
2022-05-18  9:45         ` Hans Verkuil
     [not found]   ` <CGME20220517125612epcas5p28e4cc7a208d1ac68267fa845e932ccc9@epcas5p2.samsung.com>
2022-05-17 12:55     ` [PATCH 07/20] media: v4l2: Add v4l2 control IDs for VP9 encoder Smitha T Murthy
2022-05-17 12:55       ` Smitha T Murthy
     [not found]   ` <CGME20220517125615epcas5p200c1b10090dc03e430d720d1435afccf@epcas5p2.samsung.com>
2022-05-17 12:55     ` Smitha T Murthy [this message]
2022-05-17 12:55       ` [PATCH 08/20] media: s5p-mfc: Add support " Smitha T Murthy
     [not found]   ` <CGME20220517125618epcas5p2e52b4a0e2895c7bd3dab3df27ae2ea1d@epcas5p2.samsung.com>
2022-05-17 12:55     ` [PATCH 09/20] media: s5p-mfc: Add YV12 and I420 multiplanar format support Smitha T Murthy
2022-05-17 12:55       ` Smitha T Murthy
     [not found]   ` <CGME20220517125622epcas5p324e57e1a7d76f77898d54eb01686945a@epcas5p3.samsung.com>
2022-05-17 12:55     ` [PATCH 10/20] media: s5p-mfc: Add support for rate controls in MFCv12 Smitha T Murthy
2022-05-17 12:55       ` Smitha T Murthy
     [not found]   ` <CGME20220517125625epcas5p3a5d6e217570e2e2f4e11b4c099d45767@epcas5p3.samsung.com>
2022-05-17 12:55     ` [PATCH 11/20] media: s5p-mfc: Add support for UHD encoding Smitha T Murthy
2022-05-17 12:55       ` Smitha T Murthy
2022-05-18  9:50       ` Hans Verkuil
2022-05-18  9:50         ` Hans Verkuil
     [not found]   ` <CGME20220517125629epcas5p4c99993ea5e464b296ff6dfec85b4c441@epcas5p4.samsung.com>
2022-05-17 12:55     ` [PATCH 12/20] media: s5p-mfc: Add support for DMABUF for encoder Smitha T Murthy
2022-05-17 12:55       ` Smitha T Murthy
     [not found]   ` <CGME20220517125634epcas5p40259b75a9ea07495330144310d61a5c9@epcas5p4.samsung.com>
2022-05-17 12:55     ` [PATCH 13/20] media: s5p-mfc: Set context for valid case before calling try_run Smitha T Murthy
2022-05-17 12:55       ` Smitha T Murthy
     [not found]   ` <CGME20220517125637epcas5p4f691d6c9011d3e82f2d776c440816d98@epcas5p4.samsung.com>
2022-05-17 12:55     ` [PATCH 14/20] media: s5p-mfc: Load firmware for each run in MFCv12 Smitha T Murthy
2022-05-17 12:55       ` Smitha T Murthy
     [not found]   ` <CGME20220517125641epcas5p48fc3d48ad5e4a02879a1063da36c0063@epcas5p4.samsung.com>
2022-05-17 12:55     ` [PATCH 15/20] media: s5p-mfc: DPB Count Independent of VIDIOC_REQBUF Smitha T Murthy
2022-05-17 12:55       ` Smitha T Murthy
2022-05-17 13:59       ` Krzysztof Kozlowski
2022-05-17 13:59         ` Krzysztof Kozlowski
2022-07-05 11:47         ` Smitha T Murthy
2022-07-05 11:47           ` Smitha T Murthy
     [not found]   ` <CGME20220517125644epcas5p3fcabdc953c042cc9f2697f7fbfc74121@epcas5p3.samsung.com>
2022-05-17 12:55     ` [PATCH 16/20] media: s5p-mfc: Fix to handle reference queue during finishing Smitha T Murthy
2022-05-17 12:55       ` Smitha T Murthy
2022-05-17 14:04       ` Krzysztof Kozlowski
2022-05-17 14:04         ` Krzysztof Kozlowski
     [not found]   ` <CGME20220517125648epcas5p22201053e8a71dcd5ccc8d0566511b635@epcas5p2.samsung.com>
2022-05-17 12:55     ` [PATCH 17/20] media: s5p-mfc: Clear workbit to handle error condition Smitha T Murthy
2022-05-17 12:55       ` Smitha T Murthy
2022-05-17 14:04       ` Krzysztof Kozlowski
2022-05-17 14:04         ` Krzysztof Kozlowski
2022-07-05 11:52         ` Smitha T Murthy
2022-07-05 11:52           ` Smitha T Murthy
     [not found]   ` <CGME20220517125652epcas5p31abe2138fbff6218c9031da714bfb448@epcas5p3.samsung.com>
2022-05-17 12:55     ` [PATCH 18/20] media: s5p-mfc: Correction in register read and write for H264 Smitha T Murthy
2022-05-17 12:55       ` Smitha T Murthy
2022-05-17 14:04       ` Krzysztof Kozlowski
2022-05-17 14:04         ` Krzysztof Kozlowski
2022-07-05 11:50         ` Smitha T Murthy
2022-07-05 11:50           ` Smitha T Murthy
     [not found]   ` <CGME20220517125656epcas5p1cc1296b200ff8801f24243aa47de8fe1@epcas5p1.samsung.com>
2022-05-17 12:55     ` [PATCH 19/20] arm64: dts: fsd: Add MFC related DT enteries Smitha T Murthy
2022-05-17 12:55       ` Smitha T Murthy
2022-05-17 14:02       ` Krzysztof Kozlowski
2022-05-17 14:02         ` Krzysztof Kozlowski
2022-07-05 11:49         ` Smitha T Murthy
2022-07-05 11:49           ` Smitha T Murthy
     [not found]   ` <CGME20220517125659epcas5p4f344138f5b8a64f9e49c6cba4f0af92f@epcas5p4.samsung.com>
2022-05-17 12:55     ` [PATCH 20/20] arm64 defconfig: Add MFC in defconfig Smitha T Murthy
2022-05-17 12:55       ` Smitha T Murthy
2022-05-17 14:03       ` Krzysztof Kozlowski
2022-05-17 14:03         ` Krzysztof Kozlowski
2022-05-18  9:42   ` [PATCH 00/20] Add MFC v12 support Hans Verkuil
2022-05-18  9:42     ` Hans Verkuil

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220517125548.14746-9-smitha.t@samsung.com \
    --to=smitha.t@samsung.com \
    --cc=alim.akhtar@samsung.com \
    --cc=andi@etezian.org \
    --cc=andrzej.hajda@intel.com \
    --cc=aswani.reddy@samsung.com \
    --cc=benjamin.gaignard@collabora.com \
    --cc=david.plowman@raspberrypi.com \
    --cc=devicetree@vger.kernel.org \
    --cc=dillon.minfei@gmail.com \
    --cc=ezequiel@vanguardiasur.com.ar \
    --cc=hverkuil-cisco@xs4all.nl \
    --cc=jernej.skrabec@gmail.com \
    --cc=krzk+dt@kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-fsd@tesla.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=m.szyprowski@samsung.com \
    --cc=mark.rutland@arm.com \
    --cc=mchehab@kernel.org \
    --cc=pankaj.dubey@samsung.com \
    --cc=robh+dt@kernel.org \
    --cc=stanimir.varbanov@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.