[PATCH v2 32/34] media: iris: implement iris v4l2 ioctl ops supported by encoder

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Implement all iris v4l2 ioctls ops supported by encoder.
Add state checks to ensure ioctl are allowed in valid
instance state only. Codec format can be changed by client
during s_fmt. Update the v4l2 control values according
to the updated codec format.

Signed-off-by: Dikshita Agarwal <quic_dikshita@xxxxxxxxxxx>
---
 drivers/media/platform/qcom/vcodec/iris/Makefile   |   1 +
 .../media/platform/qcom/vcodec/iris/iris_core.h    |   8 +-
 .../media/platform/qcom/vcodec/iris/iris_ctrls.c   |  59 ++-
 .../media/platform/qcom/vcodec/iris/iris_helpers.c |  89 +++-
 .../media/platform/qcom/vcodec/iris/iris_helpers.h |   3 +
 .../platform/qcom/vcodec/iris/iris_instance.h      |   5 +
 .../media/platform/qcom/vcodec/iris/iris_probe.c   |   3 +-
 .../media/platform/qcom/vcodec/iris/iris_state.c   |   5 +-
 .../media/platform/qcom/vcodec/iris/iris_vdec.c    |  80 +---
 .../media/platform/qcom/vcodec/iris/iris_venc.c    | 525 +++++++++++++++++++++
 .../media/platform/qcom/vcodec/iris/iris_venc.h    |  24 +
 .../media/platform/qcom/vcodec/iris/iris_vidc.c    | 415 ++++++++++++++--
 .../platform/qcom/vcodec/iris/platform_common.h    |   2 +
 .../platform/qcom/vcodec/iris/platform_sm8550.c    |   1 +
 14 files changed, 1088 insertions(+), 132 deletions(-)
 create mode 100644 drivers/media/platform/qcom/vcodec/iris/iris_venc.c
 create mode 100644 drivers/media/platform/qcom/vcodec/iris/iris_venc.h

diff --git a/drivers/media/platform/qcom/vcodec/iris/Makefile b/drivers/media/platform/qcom/vcodec/iris/Makefile
index 4c8f8f6..b95d627 100644
--- a/drivers/media/platform/qcom/vcodec/iris/Makefile
+++ b/drivers/media/platform/qcom/vcodec/iris/Makefile
@@ -6,6 +6,7 @@ iris-objs += iris_probe.o \
              iris_vidc.o \
              iris_vb2.o \
              iris_vdec.o \
+             iris_venc.o \
              iris_state.o \
              iris_ctrls.o \
              iris_helpers.o \
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_core.h b/drivers/media/platform/qcom/vcodec/iris/iris_core.h
index c56eb24..baced21 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_core.h
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_core.h
@@ -25,7 +25,8 @@
  * @vdev_dec: iris video device structure for decoder
  * @vdev_enc: iris video device structure for encoder
  * @v4l2_file_ops: iris v4l2 file ops
- * @v4l2_ioctl_ops: iris v4l2 ioctl ops
+ * @v4l2_ioctl_ops_dec: iris v4l2 ioctl ops for decoder
+ * @v4l2_ioctl_ops_enc: iris v4l2 ioctl ops for encoder
  * @bus_tbl: table of iris buses
  * @bus_count: count of iris buses
  * @power_domain_tbl: table of iris power domains
@@ -52,6 +53,7 @@
  * @packet_id: id of packet
  * @vpu_ops: a pointer to vpu ops
  * @session_ops: a pointer to session level ops
+ * @enc_codecs_count: supported codec count for encoder
  * @dec_codecs_count: supported codec count for decoder
  * @platform_data: a structure for platform data
  * @cap: an array for supported core capabilities
@@ -69,7 +71,8 @@ struct iris_core {
 	struct video_device			*vdev_dec;
 	struct video_device			*vdev_enc;
 	const struct v4l2_file_operations	*v4l2_file_ops;
-	const struct v4l2_ioctl_ops		*v4l2_ioctl_ops;
+	const struct v4l2_ioctl_ops		*v4l2_ioctl_ops_dec;
+	const struct v4l2_ioctl_ops		*v4l2_ioctl_ops_enc;
 	struct bus_info				*bus_tbl;
 	u32					bus_count;
 	struct power_domain_info		*power_domain_tbl;
@@ -97,6 +100,7 @@ struct iris_core {
 	const struct vpu_ops			*vpu_ops;
 	const struct vpu_session_ops		*session_ops;
 	u32					dec_codecs_count;
+	u32					enc_codecs_count;
 	struct platform_data			*platform_data;
 	struct plat_core_cap			cap[CORE_CAP_MAX + 1];
 	struct plat_inst_caps			*inst_caps;
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_ctrls.c b/drivers/media/platform/qcom/vcodec/iris/iris_ctrls.c
index a648cc1..af99ac73 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_ctrls.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_ctrls.c
@@ -217,7 +217,7 @@ static int set_dynamic_property(struct iris_inst *inst,
 	return ret;
 }
 
-static int vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+static int iris_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 {
 	enum plat_inst_cap_type cap_id;
 	struct iris_inst *inst = NULL;
@@ -242,7 +242,7 @@ static int vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 	return ret;
 }
 
-static int vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
+static int iris_op_s_ctrl(struct v4l2_ctrl *ctrl)
 {
 	struct cap_entry *entry = NULL, *temp = NULL;
 	struct list_head children_list, firmware_list;
@@ -273,7 +273,8 @@ static int vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
 
 	cap[cap_id].flags |= CAP_FLAG_CLIENT_SET;
 
-	if (!inst->vb2q_src->streaming) {
+	if ((inst->domain == ENCODER && !inst->vb2q_dst->streaming) ||
+	    (inst->domain == DECODER && !inst->vb2q_src->streaming)) {
 		inst->cap[cap_id].value = ctrl->val;
 	} else {
 		ret = adjust_dynamic_property(inst, cap_id, ctrl,
@@ -300,16 +301,16 @@ static int vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
 }
 
 static const struct v4l2_ctrl_ops ctrl_ops = {
-	.s_ctrl = vdec_op_s_ctrl,
-	.g_volatile_ctrl = vdec_op_g_volatile_ctrl,
+	.s_ctrl = iris_op_s_ctrl,
+	.g_volatile_ctrl = iris_op_g_volatile_ctrl,
 };
 
 int ctrls_init(struct iris_inst *inst, bool init)
 {
 	int num_ctrls = 0, ctrl_idx = 0;
+	u64 codecs_count, step_or_mask;
 	struct plat_inst_cap *cap;
 	struct iris_core *core;
-	u64 step_or_mask;
 	int idx = 0;
 	int ret = 0;
 
@@ -324,8 +325,11 @@ int ctrls_init(struct iris_inst *inst, bool init)
 		return -EINVAL;
 
 	if (init) {
+		codecs_count = inst->domain == ENCODER ?
+			core->enc_codecs_count :
+			core->dec_codecs_count;
 		ret = v4l2_ctrl_handler_init(&inst->ctrl_handler,
-					     INST_CAP_MAX * core->dec_codecs_count);
+					     INST_CAP_MAX * codecs_count);
 		if (ret)
 			return ret;
 	}
@@ -451,29 +455,49 @@ static int update_inst_capability(struct plat_inst_cap *in,
 int iris_init_instance_caps(struct iris_core *core)
 {
 	struct plat_inst_cap *inst_plat_cap_data = NULL;
-	u8 dec_codecs_count = 0;
-	int num_inst_cap;
-	u32 dec_valid_codecs;
+	u8 enc_codecs_count = 0, dec_codecs_count = 0;
+	u32 enc_valid_codecs, dec_valid_codecs;
 	int i, j, check_bit = 0;
+	u8 codecs_count = 0;
+	int num_inst_cap;
 	int ret = 0;
 
 	inst_plat_cap_data = core->platform_data->inst_cap_data;
 	if (!inst_plat_cap_data)
 		return -EINVAL;
 
+	enc_valid_codecs = core->cap[ENC_CODECS].value;
+	enc_codecs_count = hweight32(enc_valid_codecs);
+	core->enc_codecs_count = enc_codecs_count;
+
 	dec_valid_codecs = core->cap[DEC_CODECS].value;
 	dec_codecs_count = hweight32(dec_valid_codecs);
 	core->dec_codecs_count = dec_codecs_count;
 
+	codecs_count = enc_codecs_count + dec_codecs_count;
 	core->inst_caps = devm_kzalloc(core->dev,
-				       dec_codecs_count * sizeof(struct plat_inst_caps),
+				       codecs_count * sizeof(struct plat_inst_caps),
 				       GFP_KERNEL);
 	if (!core->inst_caps)
 		return -ENOMEM;
 
-	for (i = 0; i < dec_codecs_count; i++) {
+	for (i = 0; i < enc_codecs_count; i++) {
+		while (check_bit < (sizeof(enc_valid_codecs) * 8)) {
+			if (enc_valid_codecs & BIT(check_bit)) {
+				core->inst_caps[i].domain = ENCODER;
+				core->inst_caps[i].codec = enc_valid_codecs &
+						BIT(check_bit);
+				check_bit++;
+				break;
+			}
+			check_bit++;
+		}
+	}
+
+	for (; i < codecs_count; i++) {
 		while (check_bit < (sizeof(dec_valid_codecs) * 8)) {
 			if (dec_valid_codecs & BIT(check_bit)) {
+				core->inst_caps[i].domain = DECODER;
 				core->inst_caps[i].codec = dec_valid_codecs &
 						BIT(check_bit);
 				check_bit++;
@@ -486,9 +510,9 @@ int iris_init_instance_caps(struct iris_core *core)
 	num_inst_cap = core->platform_data->inst_cap_data_size;
 
 	for (i = 0; i < num_inst_cap; i++) {
-		for (j = 0; j < dec_codecs_count; j++) {
-			if ((inst_plat_cap_data[i].codec &
-				core->inst_caps[j].codec)) {
+		for (j = 0; j < codecs_count; j++) {
+			if ((inst_plat_cap_data[i].domain & core->inst_caps[j].domain) &&
+			    (inst_plat_cap_data[i].codec & core->inst_caps[j].codec)) {
 				ret = update_inst_capability(&inst_plat_cap_data[i],
 							     &core->inst_caps[j]);
 				if (ret)
@@ -503,11 +527,14 @@ int iris_init_instance_caps(struct iris_core *core)
 int get_inst_capability(struct iris_inst *inst)
 {
 	struct iris_core *core;
+	u32 codecs_count = 0;
 	int i;
 
 	core = inst->core;
 
-	for (i = 0; i < core->dec_codecs_count; i++) {
+	codecs_count = core->enc_codecs_count + core->dec_codecs_count;
+
+	for (i = 0; i < codecs_count; i++) {
 		if (core->inst_caps[i].codec == inst->codec) {
 			memcpy(&inst->cap[0], &core->inst_caps[i].cap[0],
 			       (INST_CAP_MAX + 1) * sizeof(struct plat_inst_cap));
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_helpers.c b/drivers/media/platform/qcom/vcodec/iris/iris_helpers.c
index d9d22e2..c84bb51 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_helpers.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_helpers.c
@@ -7,6 +7,7 @@
 
 #include "hfi_defines.h"
 #include "iris_core.h"
+#include "iris_ctrls.h"
 #include "iris_helpers.h"
 #include "iris_hfi.h"
 #include "iris_hfi_packet.h"
@@ -273,7 +274,7 @@ int close_session(struct iris_inst *inst)
 	return ret;
 }
 
-static int check_core_mbps_mbpf(struct iris_inst *inst)
+int check_core_mbps_mbpf(struct iris_inst *inst)
 {
 	u32 mbpf = 0, mbps = 0, total_mbpf = 0, total_mbps = 0;
 	struct iris_core *core;
@@ -284,7 +285,9 @@ static int check_core_mbps_mbpf(struct iris_inst *inst)
 
 	mutex_lock(&core->lock);
 	list_for_each_entry(instance, &core->instances, list) {
-		fps = inst->cap[QUEUED_RATE].value >> 16;
+		fps = max3(inst->cap[QUEUED_RATE].value >> 16,
+			   inst->cap[FRAME_RATE].value >> 16,
+			   inst->cap[OPERATING_RATE].value >> 16);
 		mbpf = get_mbpf(inst);
 		mbps = mbpf * fps;
 		total_mbpf += mbpf;
@@ -814,6 +817,88 @@ int session_streamoff(struct iris_inst *inst, u32 plane)
 	return ret;
 }
 
+int process_resume(struct iris_inst *inst)
+{
+	enum iris_inst_sub_state clear_sub_state = IRIS_INST_SUB_NONE;
+	int ret;
+
+	if (inst->sub_state & IRIS_INST_SUB_DRC &&
+	    inst->sub_state & IRIS_INST_SUB_DRC_LAST) {
+		clear_sub_state = IRIS_INST_SUB_DRC | IRIS_INST_SUB_DRC_LAST;
+
+		if (inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) {
+			ret = iris_hfi_resume(inst, INPUT_MPLANE, HFI_CMD_SETTINGS_CHANGE);
+			if (ret)
+				return ret;
+			clear_sub_state |= IRIS_INST_SUB_INPUT_PAUSE;
+		}
+		if (inst->sub_state & IRIS_INST_SUB_OUTPUT_PAUSE) {
+			ret = iris_hfi_resume(inst, OUTPUT_MPLANE, HFI_CMD_SETTINGS_CHANGE);
+			if (ret)
+				return ret;
+			clear_sub_state |= IRIS_INST_SUB_OUTPUT_PAUSE;
+		}
+	} else if (inst->sub_state & IRIS_INST_SUB_DRAIN &&
+		   inst->sub_state & IRIS_INST_SUB_DRAIN_LAST) {
+		clear_sub_state = IRIS_INST_SUB_DRAIN | IRIS_INST_SUB_DRAIN_LAST;
+		if (inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) {
+			ret = iris_hfi_resume(inst, INPUT_MPLANE, HFI_CMD_DRAIN);
+			if (ret)
+				return ret;
+			clear_sub_state |= IRIS_INST_SUB_INPUT_PAUSE;
+		}
+		if (inst->sub_state & IRIS_INST_SUB_OUTPUT_PAUSE) {
+			ret = iris_hfi_resume(inst, OUTPUT_MPLANE, HFI_CMD_DRAIN);
+			if (ret)
+				return ret;
+			clear_sub_state |= IRIS_INST_SUB_OUTPUT_PAUSE;
+		}
+	}
+
+	ret = iris_inst_change_sub_state(inst, clear_sub_state, 0);
+
+	return ret;
+}
+
+int codec_change(struct iris_inst *inst, u32 v4l2_codec)
+{
+	bool session_init = false;
+	int ret;
+
+	if (!inst->codec)
+		session_init = true;
+
+	if (inst->codec &&
+	    ((inst->domain == DECODER && inst->fmt_src->fmt.pix_mp.pixelformat == v4l2_codec) ||
+	     (inst->domain == ENCODER && inst->fmt_dst->fmt.pix_mp.pixelformat == v4l2_codec)))
+		return 0;
+
+	inst->codec = v4l2_codec_to_driver(inst, v4l2_codec);
+	if (!inst->codec)
+		return -EINVAL;
+
+	if (inst->domain == DECODER)
+		inst->fmt_src->fmt.pix_mp.pixelformat = v4l2_codec;
+	else if (inst->domain == ENCODER)
+		inst->fmt_dst->fmt.pix_mp.pixelformat = v4l2_codec;
+
+	ret = get_inst_capability(inst);
+	if (ret)
+		return ret;
+
+	ret = ctrls_init(inst, session_init);
+	if (ret)
+		return ret;
+
+	ret = update_buffer_count(inst, INPUT_MPLANE);
+	if (ret)
+		return ret;
+
+	ret = update_buffer_count(inst, OUTPUT_MPLANE);
+
+	return ret;
+}
+
 int iris_pm_get(struct iris_core *core)
 {
 	int ret;
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_helpers.h b/drivers/media/platform/qcom/vcodec/iris/iris_helpers.h
index c628b2e..39cec8c 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_helpers.h
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_helpers.h
@@ -41,6 +41,7 @@ enum codec_type v4l2_codec_to_driver(struct iris_inst *inst, u32 v4l2_codec);
 u32 v4l2_colorformat_from_driver(struct iris_inst *inst, enum colorformat_type colorformat);
 enum colorformat_type v4l2_colorformat_to_driver(struct iris_inst *inst, u32 v4l2_colorformat);
 struct vb2_queue *get_vb2q(struct iris_inst *inst, u32 type);
+int check_core_mbps_mbpf(struct iris_inst *inst);
 int check_session_supported(struct iris_inst *inst);
 
 struct iris_buffer *get_driver_buf(struct iris_inst *inst, u32 plane, u32 index);
@@ -51,6 +52,8 @@ int iris_vb2_buffer_done(struct iris_inst *inst,
 int iris_release_nonref_buffers(struct iris_inst *inst);
 void iris_destroy_buffers(struct iris_inst *inst);
 int session_streamoff(struct iris_inst *inst, u32 plane);
+int process_resume(struct iris_inst *inst);
+int codec_change(struct iris_inst *inst, u32 v4l2_codec);
 int iris_pm_get(struct iris_core *core);
 int iris_pm_put(struct iris_core *core, bool autosuspend);
 int iris_pm_get_put(struct iris_core *core);
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_instance.h b/drivers/media/platform/qcom/vcodec/iris/iris_instance.h
index 70f4c7d..a1547c5 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_instance.h
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_instance.h
@@ -8,6 +8,7 @@
 
 #include <media/v4l2-ctrls.h>
 
+#include "hfi_defines.h"
 #include "iris_buffer.h"
 #include "iris_common.h"
 #include "iris_core.h"
@@ -29,6 +30,7 @@
  * @fmt_dst: structure of v4l2_format for destination
  * @ctrl_handler: reference of v4l2 ctrl handler
  * @crop: structure of crop info
+ * @compose: structure of compose info
  * @packet: HFI packet
  * @packet_size: HFI packet size
  * @completions: structure of signal completions
@@ -36,6 +38,7 @@
  * @num_ctrls: supported number of controls
  * @caps_list: list head of capability
  * @codec: codec type
+ * @domain: domain type: encoder or decoder
  * @buffers: structure of buffer info
  * @fw_min_count: minimnum count of buffers needed by fw
  * @state: instance state
@@ -70,6 +73,7 @@ struct iris_inst {
 	struct v4l2_format		*fmt_dst;
 	struct v4l2_ctrl_handler	ctrl_handler;
 	struct rect_desc		crop;
+	struct rect_desc		compose;
 	void				*packet;
 	u32				packet_size;
 	struct completion		completions[MAX_SIGNAL];
@@ -77,6 +81,7 @@ struct iris_inst {
 	u32				num_ctrls;
 	struct list_head		caps_list;
 	enum codec_type			codec;
+	enum domain_type		domain;
 	struct iris_buffers_info	buffers;
 	u32				fw_min_count;
 	enum iris_inst_state		state;
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_probe.c b/drivers/media/platform/qcom/vcodec/iris/iris_probe.c
index b487e83..49d2701 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_probe.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_probe.c
@@ -42,13 +42,13 @@ static int iris_register_video_device(struct iris_core *core, enum domain_type t
 
 	vdev->release = video_device_release;
 	vdev->fops = core->v4l2_file_ops;
-	vdev->ioctl_ops = core->v4l2_ioctl_ops;
 	vdev->vfl_dir = VFL_DIR_M2M;
 	vdev->v4l2_dev = &core->v4l2_dev;
 	vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
 
 	if (type == DECODER) {
 		strscpy(vdev->name, "qcom-iris-decoder", sizeof(vdev->name));
+		vdev->ioctl_ops = core->v4l2_ioctl_ops_dec;
 
 		ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
 		if (ret)
@@ -57,6 +57,7 @@ static int iris_register_video_device(struct iris_core *core, enum domain_type t
 		core->vdev_dec = vdev;
 	} else if (type == ENCODER) {
 		strscpy(vdev->name, "qcom-iris-encoder", sizeof(vdev->name));
+		vdev->ioctl_ops = core->v4l2_ioctl_ops_enc;
 
 		ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
 		if (ret)
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_state.c b/drivers/media/platform/qcom/vcodec/iris/iris_state.c
index 952ba2a..e853aec 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_state.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_state.c
@@ -198,8 +198,9 @@ bool allow_s_ctrl(struct iris_inst *inst, u32 cap_id)
 {
 	return ((inst->state == IRIS_INST_OPEN) ||
 		((inst->cap[cap_id].flags & CAP_FLAG_DYNAMIC_ALLOWED) &&
-		(inst->state == IRIS_INST_INPUT_STREAMING ||
-		inst->state == IRIS_INST_STREAMING)));
+		 ((inst->state == IRIS_INST_INPUT_STREAMING && inst->domain == DECODER) ||
+		  (inst->state == IRIS_INST_OUTPUT_STREAMING && inst->domain == ENCODER) ||
+		  (inst->state == IRIS_INST_STREAMING))));
 }
 
 int iris_inst_state_change_streamon(struct iris_inst *inst, u32 plane)
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_vdec.c b/drivers/media/platform/qcom/vcodec/iris/iris_vdec.c
index 371615e..300d0e9 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_vdec.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_vdec.c
@@ -22,39 +22,6 @@ struct vdec_prop_type_handle {
 	int (*handle)(struct iris_inst *inst);
 };
 
-static int vdec_codec_change(struct iris_inst *inst, u32 v4l2_codec)
-{
-	bool session_init = false;
-	int ret;
-
-	if (!inst->codec)
-		session_init = true;
-
-	if (inst->codec && inst->fmt_src->fmt.pix_mp.pixelformat == v4l2_codec)
-		return 0;
-
-	inst->codec = v4l2_codec_to_driver(inst, v4l2_codec);
-	if (!inst->codec)
-		return -EINVAL;
-
-	inst->fmt_src->fmt.pix_mp.pixelformat = v4l2_codec;
-	ret = get_inst_capability(inst);
-	if (ret)
-		return ret;
-
-	ret = ctrls_init(inst, session_init);
-	if (ret)
-		return ret;
-
-	ret = update_buffer_count(inst, INPUT_MPLANE);
-	if (ret)
-		return ret;
-
-	ret = update_buffer_count(inst, OUTPUT_MPLANE);
-
-	return ret;
-}
-
 int vdec_inst_init(struct iris_inst *inst)
 {
 	struct v4l2_format *f;
@@ -93,7 +60,7 @@ int vdec_inst_init(struct iris_inst *inst)
 	inst->buffers.output.size = f->fmt.pix_mp.plane_fmt[0].sizeimage;
 	inst->fw_min_count = 0;
 
-	ret = vdec_codec_change(inst, inst->fmt_src->fmt.pix_mp.pixelformat);
+	ret = codec_change(inst, inst->fmt_src->fmt.pix_mp.pixelformat);
 
 	return ret;
 }
@@ -233,7 +200,7 @@ int vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f)
 	if (f->type == INPUT_MPLANE) {
 		if (inst->fmt_src->fmt.pix_mp.pixelformat !=
 			f->fmt.pix_mp.pixelformat) {
-			ret = vdec_codec_change(inst, f->fmt.pix_mp.pixelformat);
+			ret = codec_change(inst, f->fmt.pix_mp.pixelformat);
 			if (ret)
 				return ret;
 		}
@@ -1304,49 +1271,6 @@ int vdec_qbuf(struct iris_inst *inst, struct vb2_buffer *vb2)
 	return ret;
 }
 
-static int process_resume(struct iris_inst *inst)
-{
-	enum iris_inst_sub_state clear_sub_state = IRIS_INST_SUB_NONE;
-	int ret;
-
-	if (inst->sub_state & IRIS_INST_SUB_DRC &&
-	    inst->sub_state & IRIS_INST_SUB_DRC_LAST) {
-		clear_sub_state = IRIS_INST_SUB_DRC | IRIS_INST_SUB_DRC_LAST;
-
-		if (inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) {
-			ret = iris_hfi_resume(inst, INPUT_MPLANE, HFI_CMD_SETTINGS_CHANGE);
-			if (ret)
-				return ret;
-			clear_sub_state |= IRIS_INST_SUB_INPUT_PAUSE;
-		}
-		if (inst->sub_state & IRIS_INST_SUB_OUTPUT_PAUSE) {
-			ret = iris_hfi_resume(inst, OUTPUT_MPLANE, HFI_CMD_SETTINGS_CHANGE);
-			if (ret)
-				return ret;
-			clear_sub_state |= IRIS_INST_SUB_OUTPUT_PAUSE;
-		}
-	} else if (inst->sub_state & IRIS_INST_SUB_DRAIN &&
-			   inst->sub_state & IRIS_INST_SUB_DRAIN_LAST) {
-		clear_sub_state = IRIS_INST_SUB_DRAIN | IRIS_INST_SUB_DRAIN_LAST;
-		if (inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) {
-			ret = iris_hfi_resume(inst, INPUT_MPLANE, HFI_CMD_DRAIN);
-			if (ret)
-				return ret;
-			clear_sub_state |= IRIS_INST_SUB_INPUT_PAUSE;
-		}
-		if (inst->sub_state & IRIS_INST_SUB_OUTPUT_PAUSE) {
-			ret = iris_hfi_resume(inst, OUTPUT_MPLANE, HFI_CMD_DRAIN);
-			if (ret)
-				return ret;
-			clear_sub_state |= IRIS_INST_SUB_OUTPUT_PAUSE;
-		}
-	}
-
-	ret = iris_inst_change_sub_state(inst, clear_sub_state, 0);
-
-	return ret;
-}
-
 int vdec_start_cmd(struct iris_inst *inst)
 {
 	int ret;
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_venc.c b/drivers/media/platform/qcom/vcodec/iris/iris_venc.c
new file mode 100644
index 0000000..802db40
--- /dev/null
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_venc.c
@@ -0,0 +1,525 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "hfi_defines.h"
+#include "iris_buffer.h"
+#include "iris_common.h"
+#include "iris_ctrls.h"
+#include "iris_helpers.h"
+#include "iris_hfi.h"
+#include "iris_hfi_packet.h"
+#include "iris_power.h"
+#include "iris_venc.h"
+
+int venc_inst_init(struct iris_inst *inst)
+{
+	struct v4l2_format *f;
+	int ret;
+
+	inst->fmt_src = kzalloc(sizeof(*inst->fmt_src), GFP_KERNEL);
+	if (!inst->fmt_src)
+		return -ENOMEM;
+
+	inst->fmt_dst  = kzalloc(sizeof(*inst->fmt_dst), GFP_KERNEL);
+	if (!inst->fmt_dst)
+		return -ENOMEM;
+
+	inst->vb2q_src = kzalloc(sizeof(*inst->vb2q_src), GFP_KERNEL);
+	if (!inst->vb2q_src)
+		return -ENOMEM;
+
+	inst->vb2q_dst = kzalloc(sizeof(*inst->vb2q_dst), GFP_KERNEL);
+	if (!inst->vb2q_dst)
+		return -ENOMEM;
+
+	f = inst->fmt_dst;
+	f->type = OUTPUT_MPLANE;
+	f->fmt.pix_mp.width = DEFAULT_WIDTH;
+	f->fmt.pix_mp.height = DEFAULT_HEIGHT;
+	f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264;
+	f->fmt.pix_mp.num_planes = 1;
+	f->fmt.pix_mp.plane_fmt[0].bytesperline = 0;
+	f->fmt.pix_mp.plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_OUTPUT);
+	f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+	f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT;
+	f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT;
+	f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+	f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT;
+	inst->buffers.output.min_count = iris_get_buf_min_count(inst, BUF_OUTPUT);
+	inst->buffers.output.actual_count = inst->buffers.output.min_count;
+	inst->buffers.output.size = f->fmt.pix_mp.plane_fmt[0].sizeimage;
+
+	inst->crop.left = 0;
+	inst->crop.top = 0;
+	inst->crop.width = f->fmt.pix_mp.width;
+	inst->crop.height = f->fmt.pix_mp.height;
+
+	inst->compose.left = 0;
+	inst->compose.top = 0;
+	inst->compose.width = f->fmt.pix_mp.width;
+	inst->compose.height = f->fmt.pix_mp.height;
+
+	f = inst->fmt_src;
+	f->type = INPUT_MPLANE;
+	f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_QC08C;
+	f->fmt.pix_mp.width = DEFAULT_WIDTH;
+	f->fmt.pix_mp.height = DEFAULT_HEIGHT;
+	f->fmt.pix_mp.num_planes = 1;
+	f->fmt.pix_mp.plane_fmt[0].bytesperline = ALIGN(DEFAULT_WIDTH, 128);
+	f->fmt.pix_mp.plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_INPUT);
+	f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+	f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT;
+	f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT;
+	f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+	f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT;
+	inst->buffers.input.min_count = iris_get_buf_min_count(inst, BUF_INPUT);
+	inst->buffers.input.actual_count = inst->buffers.input.min_count;
+	inst->buffers.input.size = f->fmt.pix_mp.plane_fmt[0].sizeimage;
+
+	inst->hfi_rc_type = HFI_RC_VBR_CFR;
+	inst->hfi_layer_type = HFI_HIER_P_SLIDING_WINDOW;
+
+	ret = codec_change(inst, inst->fmt_dst->fmt.pix_mp.pixelformat);
+
+	return ret;
+}
+
+void venc_inst_deinit(struct iris_inst *inst)
+{
+	kfree(inst->fmt_dst);
+	kfree(inst->fmt_src);
+}
+
+int venc_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f)
+{
+	struct iris_core *core;
+	u32 array[32] = {0};
+	u32 i = 0;
+
+	core = inst->core;
+
+	if (f->type == OUTPUT_MPLANE) {
+		u32 codecs = core->cap[ENC_CODECS].value;
+		u32 idx = 0;
+
+		for (i = 0; i <= 31; i++) {
+			if (codecs & BIT(i)) {
+				if (idx >= ARRAY_SIZE(array))
+					break;
+				array[idx] = codecs & BIT(i);
+				idx++;
+			}
+		}
+		if (!array[f->index])
+			return -EINVAL;
+		f->pixelformat = v4l2_codec_from_driver(inst, array[f->index]);
+		if (!f->pixelformat)
+			return -EINVAL;
+		f->flags = V4L2_FMT_FLAG_COMPRESSED;
+		strscpy(f->description, "codec", sizeof(f->description));
+	} else if (f->type == INPUT_MPLANE) {
+		u32 formats = inst->cap[PIX_FMTS].step_or_mask;
+		u32 idx = 0;
+
+		for (i = 0; i <= 31; i++) {
+			if (formats & BIT(i)) {
+				if (idx >= ARRAY_SIZE(array))
+					break;
+				array[idx] = formats & BIT(i);
+				idx++;
+			}
+		}
+		if (!array[f->index])
+			return -EINVAL;
+		f->pixelformat = v4l2_colorformat_from_driver(inst, array[f->index]);
+		if (!f->pixelformat)
+			return -EINVAL;
+		strscpy(f->description, "colorformat", sizeof(f->description));
+	}
+
+	memset(f->reserved, 0, sizeof(f->reserved));
+
+	return 0;
+}
+
+int venc_try_fmt(struct iris_inst *inst, struct v4l2_format *f)
+{
+	struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
+	u32 pix_fmt;
+
+	memset(pixmp->reserved, 0, sizeof(pixmp->reserved));
+
+	if (f->type == INPUT_MPLANE) {
+		pix_fmt = v4l2_colorformat_to_driver(inst, f->fmt.pix_mp.pixelformat);
+		if (!pix_fmt) {
+			f->fmt.pix_mp.pixelformat = inst->fmt_src->fmt.pix_mp.pixelformat;
+			f->fmt.pix_mp.width = inst->fmt_src->fmt.pix_mp.width;
+			f->fmt.pix_mp.height = inst->fmt_src->fmt.pix_mp.height;
+		}
+	} else if (f->type == OUTPUT_MPLANE) {
+		pix_fmt = v4l2_codec_to_driver(inst, f->fmt.pix_mp.pixelformat);
+		if (!pix_fmt) {
+			f->fmt.pix_mp.width = inst->fmt_dst->fmt.pix_mp.width;
+			f->fmt.pix_mp.height = inst->fmt_dst->fmt.pix_mp.height;
+			f->fmt.pix_mp.pixelformat = inst->fmt_dst->fmt.pix_mp.pixelformat;
+		}
+	} else {
+		return -EINVAL;
+	}
+
+	if (pixmp->field == V4L2_FIELD_ANY)
+		pixmp->field = V4L2_FIELD_NONE;
+	pixmp->num_planes = 1;
+
+	return 0;
+}
+
+static int venc_s_fmt_output(struct iris_inst *inst, struct v4l2_format *f)
+{
+	struct v4l2_format *fmt;
+	enum codec_type codec;
+	u32 codec_align;
+	u32 width, height;
+	int ret = 0;
+
+	venc_try_fmt(inst, f);
+
+	fmt = inst->fmt_dst;
+	if (fmt->fmt.pix_mp.pixelformat != f->fmt.pix_mp.pixelformat) {
+		ret = codec_change(inst, f->fmt.pix_mp.pixelformat);
+		if (ret)
+			return ret;
+	}
+	fmt->type = OUTPUT_MPLANE;
+
+	codec = v4l2_codec_to_driver(inst, f->fmt.pix_mp.pixelformat);
+
+	codec_align = (codec == HEVC) ? 32 : 16;
+	width = inst->compose.width;
+	height = inst->compose.height;
+	if (inst->cap[ROTATION].value == 90 || inst->cap[ROTATION].value == 270) {
+		width = inst->compose.height;
+		height = inst->compose.width;
+	}
+	fmt->fmt.pix_mp.width = ALIGN(width, codec_align);
+	fmt->fmt.pix_mp.height = ALIGN(height, codec_align);
+	fmt->fmt.pix_mp.num_planes = 1;
+	fmt->fmt.pix_mp.plane_fmt[0].bytesperline = 0;
+	fmt->fmt.pix_mp.plane_fmt[0].sizeimage =
+		iris_get_buffer_size(inst, BUF_OUTPUT);
+	if (f->fmt.pix_mp.colorspace != V4L2_COLORSPACE_DEFAULT &&
+	    f->fmt.pix_mp.colorspace != V4L2_COLORSPACE_REC709)
+		f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT;
+	fmt->fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace;
+	fmt->fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func;
+	fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
+	fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization;
+	inst->buffers.output.min_count = iris_get_buf_min_count(inst, BUF_OUTPUT);
+	if (inst->buffers.output.actual_count <
+		inst->buffers.output.min_count) {
+		inst->buffers.output.actual_count =
+			inst->buffers.output.min_count;
+	}
+	inst->buffers.output.size =
+		fmt->fmt.pix_mp.plane_fmt[0].sizeimage;
+
+	memcpy(f, fmt, sizeof(struct v4l2_format));
+
+	return ret;
+}
+
+static int venc_s_fmt_input(struct iris_inst *inst, struct v4l2_format *f)
+{
+	u32 pix_fmt, width, height, size, bytesperline;
+	struct v4l2_format *fmt, *output_fmt;
+	int ret = 0;
+
+	venc_try_fmt(inst, f);
+
+	pix_fmt = v4l2_colorformat_to_driver(inst, f->fmt.pix_mp.pixelformat);
+	inst->cap[PIX_FMTS].value = pix_fmt;
+
+	width = f->fmt.pix_mp.width;
+	height = f->fmt.pix_mp.height;
+
+	bytesperline = pix_fmt == FMT_TP10C ?
+		ALIGN(ALIGN(f->fmt.pix_mp.width, 192) * 4 / 3, 256) :
+		ALIGN(f->fmt.pix_mp.width, 128);
+
+	fmt = inst->fmt_src;
+	fmt->type = INPUT_MPLANE;
+	fmt->fmt.pix_mp.width = width;
+	fmt->fmt.pix_mp.height = height;
+	fmt->fmt.pix_mp.num_planes = 1;
+	fmt->fmt.pix_mp.pixelformat = f->fmt.pix_mp.pixelformat;
+	fmt->fmt.pix_mp.plane_fmt[0].bytesperline = bytesperline;
+	size = iris_get_buffer_size(inst, BUF_INPUT);
+	fmt->fmt.pix_mp.plane_fmt[0].sizeimage = size;
+	fmt->fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace;
+	fmt->fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func;
+	fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
+	fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization;
+
+	output_fmt = inst->fmt_dst;
+	output_fmt->fmt.pix_mp.colorspace = fmt->fmt.pix_mp.colorspace;
+	output_fmt->fmt.pix_mp.xfer_func = fmt->fmt.pix_mp.xfer_func;
+	output_fmt->fmt.pix_mp.ycbcr_enc = fmt->fmt.pix_mp.ycbcr_enc;
+	output_fmt->fmt.pix_mp.quantization = fmt->fmt.pix_mp.quantization;
+
+	inst->buffers.input.min_count = iris_get_buf_min_count(inst, BUF_INPUT);
+	if (inst->buffers.input.actual_count <
+	    inst->buffers.input.min_count) {
+		inst->buffers.input.actual_count =
+			inst->buffers.input.min_count;
+	}
+	inst->buffers.input.size = size;
+
+	if (f->fmt.pix_mp.width != inst->crop.width ||
+	    f->fmt.pix_mp.height != inst->crop.height) {
+		inst->crop.top = 0;
+		inst->crop.left = 0;
+		inst->crop.width = f->fmt.pix_mp.width;
+		inst->crop.height = f->fmt.pix_mp.height;
+
+		inst->compose.top = 0;
+		inst->compose.left = 0;
+		inst->compose.width = f->fmt.pix_mp.width;
+		inst->compose.height = f->fmt.pix_mp.height;
+
+		ret = venc_s_fmt_output(inst, output_fmt);
+		if (ret)
+			return ret;
+	}
+
+	memcpy(f, fmt, sizeof(struct v4l2_format));
+
+	return ret;
+}
+
+int venc_s_fmt(struct iris_inst *inst, struct v4l2_format *f)
+{
+	int ret;
+
+	if (f->type == INPUT_MPLANE)
+		ret = venc_s_fmt_input(inst, f);
+	else if (f->type == OUTPUT_MPLANE)
+		ret = venc_s_fmt_output(inst, f);
+	else
+		ret = -EINVAL;
+
+	return ret;
+}
+
+int venc_s_selection(struct iris_inst *inst, struct v4l2_selection *s)
+{
+	struct v4l2_format *output_fmt;
+	int ret;
+
+	if (s->type != INPUT_MPLANE && s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_CROP:
+		if (s->r.left || s->r.top) {
+			s->r.left = 0;
+			s->r.top = 0;
+		}
+		if (s->r.width > inst->fmt_src->fmt.pix_mp.width)
+			s->r.width = inst->fmt_src->fmt.pix_mp.width;
+
+		if (s->r.height > inst->fmt_src->fmt.pix_mp.height)
+			s->r.height = inst->fmt_src->fmt.pix_mp.height;
+
+		inst->crop.left = s->r.left;
+		inst->crop.top = s->r.top;
+		inst->crop.width = s->r.width;
+		inst->crop.height = s->r.height;
+		inst->compose.left = inst->crop.left;
+		inst->compose.top = inst->crop.top;
+		inst->compose.width = inst->crop.width;
+		inst->compose.height = inst->crop.height;
+		output_fmt = inst->fmt_dst;
+		ret = venc_s_fmt_output(inst, output_fmt);
+		if (ret)
+			return ret;
+		break;
+	case V4L2_SEL_TGT_COMPOSE:
+		if (s->r.left < inst->crop.left)
+			s->r.left = inst->crop.left;
+
+		if (s->r.top < inst->crop.top)
+			s->r.top = inst->crop.top;
+
+		if (s->r.width > inst->crop.width)
+			s->r.width = inst->crop.width;
+
+		if (s->r.height > inst->crop.height)
+			s->r.height = inst->crop.height;
+		inst->compose.left = s->r.left;
+		inst->compose.top = s->r.top;
+		inst->compose.width = s->r.width;
+		inst->compose.height = s->r.height;
+
+		output_fmt = inst->fmt_dst;
+		ret = venc_s_fmt_output(inst, output_fmt);
+		if (ret)
+			return ret;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+int venc_s_param(struct iris_inst *inst, struct v4l2_streamparm *s_parm)
+{
+	struct v4l2_fract *timeperframe = NULL;
+	u32 q16_rate, max_rate, default_rate;
+	u64 us_per_frame = 0, input_rate = 0;
+	bool is_frame_rate = false;
+	int ret = 0;
+
+	if (s_parm->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		timeperframe = &s_parm->parm.output.timeperframe;
+		max_rate = inst->cap[OPERATING_RATE].max >> 16;
+		default_rate = inst->cap[OPERATING_RATE].value >> 16;
+		s_parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+	} else {
+		timeperframe = &s_parm->parm.capture.timeperframe;
+		is_frame_rate = true;
+		max_rate = inst->cap[FRAME_RATE].max >> 16;
+		default_rate = inst->cap[FRAME_RATE].value >> 16;
+		s_parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+	}
+
+	if (!timeperframe->denominator || !timeperframe->numerator) {
+		if (!timeperframe->numerator)
+			timeperframe->numerator = 1;
+		if (!timeperframe->denominator)
+			timeperframe->denominator = default_rate;
+	}
+
+	us_per_frame = timeperframe->numerator * (u64)USEC_PER_SEC;
+	us_per_frame = div64_u64(us_per_frame, timeperframe->denominator);
+
+	if (!us_per_frame) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	input_rate = (u64)USEC_PER_SEC;
+	input_rate = div64_u64(input_rate, us_per_frame);
+
+	q16_rate = (u32)input_rate << 16;
+	if (is_frame_rate)
+		inst->cap[FRAME_RATE].value = q16_rate;
+	else
+		inst->cap[OPERATING_RATE].value = q16_rate;
+
+	if ((s_parm->type == INPUT_MPLANE && inst->vb2q_src->streaming) ||
+	    (s_parm->type == OUTPUT_MPLANE && inst->vb2q_dst->streaming)) {
+		ret = check_core_mbps_mbpf(inst);
+		if (ret)
+			goto reset_rate;
+		ret = input_rate > max_rate;
+		if (ret) {
+			ret = -ENOMEM;
+			goto reset_rate;
+		}
+	}
+
+	if (is_frame_rate)
+		inst->cap[FRAME_RATE].flags |= CAP_FLAG_CLIENT_SET;
+	else
+		inst->cap[OPERATING_RATE].flags |= CAP_FLAG_CLIENT_SET;
+
+	if (inst->vb2q_dst->streaming) {
+		ret = iris_hfi_set_property(inst,
+					    HFI_PROP_FRAME_RATE,
+					    HFI_HOST_FLAGS_NONE,
+					    HFI_PORT_BITSTREAM,
+					    HFI_PAYLOAD_Q16,
+					    &q16_rate,
+					    sizeof(u32));
+		if (ret)
+			goto exit;
+	}
+
+	return ret;
+
+reset_rate:
+	if (ret) {
+		if (is_frame_rate)
+			inst->cap[FRAME_RATE].value = default_rate << 16;
+		else
+			inst->cap[OPERATING_RATE].value = default_rate << 16;
+	}
+exit:
+	return ret;
+}
+
+int venc_g_param(struct iris_inst *inst, struct v4l2_streamparm *s_parm)
+{
+	struct v4l2_fract *timeperframe = NULL;
+
+	if (s_parm->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		timeperframe = &s_parm->parm.output.timeperframe;
+		timeperframe->numerator = 1;
+		timeperframe->denominator =
+			inst->cap[OPERATING_RATE].value >> 16;
+		s_parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+	} else {
+		timeperframe = &s_parm->parm.capture.timeperframe;
+		timeperframe->numerator = 1;
+		timeperframe->denominator =
+			inst->cap[FRAME_RATE].value >> 16;
+		s_parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+	}
+
+	return 0;
+}
+
+int venc_subscribe_event(struct iris_inst *inst,
+			 const struct v4l2_event_subscription *sub)
+{
+	int ret;
+
+	switch (sub->type) {
+	case V4L2_EVENT_EOS:
+		ret = v4l2_event_subscribe(&inst->fh, sub, MAX_EVENTS, NULL);
+		break;
+	case V4L2_EVENT_CTRL:
+		ret = v4l2_ctrl_subscribe_event(&inst->fh, sub);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+int venc_start_cmd(struct iris_inst *inst)
+{
+	vb2_clear_last_buffer_dequeued(inst->vb2q_dst);
+
+	return process_resume(inst);
+}
+
+int venc_stop_cmd(struct iris_inst *inst)
+{
+	int ret;
+
+	ret = iris_hfi_drain(inst, INPUT_MPLANE);
+	if (ret)
+		return ret;
+
+	ret = iris_inst_change_sub_state(inst, 0, IRIS_INST_SUB_DRAIN);
+
+	iris_scale_power(inst);
+
+	return ret;
+}
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_venc.h b/drivers/media/platform/qcom/vcodec/iris/iris_venc.h
new file mode 100644
index 0000000..24da63f
--- /dev/null
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_venc.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _IRIS_VENC_H_
+#define _IRIS_VENC_H_
+
+#include "iris_instance.h"
+
+int venc_inst_init(struct iris_inst *inst);
+void venc_inst_deinit(struct iris_inst *inst);
+int venc_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f);
+int venc_try_fmt(struct iris_inst *inst, struct v4l2_format *f);
+int venc_s_fmt(struct iris_inst *inst, struct v4l2_format *f);
+int venc_s_selection(struct iris_inst *inst, struct v4l2_selection *s);
+int venc_s_param(struct iris_inst *inst, struct v4l2_streamparm *s_parm);
+int venc_g_param(struct iris_inst *inst, struct v4l2_streamparm *s_parm);
+int venc_subscribe_event(struct iris_inst *inst,
+			 const struct v4l2_event_subscription *sub);
+int venc_start_cmd(struct iris_inst *inst);
+int venc_stop_cmd(struct iris_inst *inst);
+
+#endif
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_vidc.c b/drivers/media/platform/qcom/vcodec/iris/iris_vidc.c
index 437d6b4..aa19978 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_vidc.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_vidc.c
@@ -15,6 +15,7 @@
 #include "iris_instance.h"
 #include "iris_power.h"
 #include "iris_vdec.h"
+#include "iris_venc.h"
 #include "iris_vidc.h"
 #include "iris_vb2.h"
 
@@ -30,7 +31,11 @@ static int vidc_v4l2_fh_init(struct iris_inst *inst)
 	if (inst->fh.vdev)
 		return -EINVAL;
 
-	v4l2_fh_init(&inst->fh, core->vdev_dec);
+	if (inst->domain == ENCODER)
+		v4l2_fh_init(&inst->fh, core->vdev_enc);
+	else if (inst->domain == DECODER)
+		v4l2_fh_init(&inst->fh, core->vdev_dec);
+
 	inst->fh.ctrl_handler = &inst->ctrl_handler;
 	v4l2_fh_add(&inst->fh);
 
@@ -160,9 +165,20 @@ int vidc_open(struct file *filp)
 {
 	struct iris_core *core = video_drvdata(filp);
 	struct iris_inst *inst = NULL;
+	struct video_device *vdev;
+	u32 session_type = 0;
 	int i = 0;
 	int ret;
 
+	vdev = video_devdata(filp);
+	if (strcmp(vdev->name, "qcom-iris-decoder") == 0)
+		session_type = DECODER;
+	else if (strcmp(vdev->name, "qcom-iris-encoder") == 0)
+		session_type = ENCODER;
+
+	if (session_type != DECODER && session_type != ENCODER)
+		return -EINVAL;
+
 	ret = iris_pm_get(core);
 	if (ret)
 		return ret;
@@ -182,6 +198,7 @@ int vidc_open(struct file *filp)
 	}
 
 	inst->core = core;
+	inst->domain = session_type;
 	inst->session_id = hash32_ptr(inst);
 	inst->ipsc_properties_set = false;
 	inst->opsc_properties_set = false;
@@ -213,7 +230,12 @@ int vidc_open(struct file *filp)
 	if (ret)
 		goto fail_remove_session;
 
-	vdec_inst_init(inst);
+	if (inst->domain == DECODER)
+		ret = vdec_inst_init(inst);
+	else if (inst->domain == ENCODER)
+		ret = venc_inst_init(inst);
+	if (ret)
+		goto fail_fh_deinit;
 
 	ret = vidc_vb2_queue_init(inst);
 	if (ret)
@@ -238,7 +260,11 @@ int vidc_open(struct file *filp)
 	iris_core_deinit(core);
 	vidc_vb2_queue_deinit(inst);
 fail_inst_deinit:
-	vdec_inst_deinit(inst);
+	if (inst->domain == DECODER)
+		vdec_inst_deinit(inst);
+	else if (inst->domain == ENCODER)
+		venc_inst_deinit(inst);
+fail_fh_deinit:
 	vidc_v4l2_fh_deinit(inst);
 fail_remove_session:
 	vidc_remove_session(inst);
@@ -264,7 +290,11 @@ int vidc_close(struct file *filp)
 	core = inst->core;
 
 	v4l2_ctrl_handler_free(&inst->ctrl_handler);
-	vdec_inst_deinit(inst);
+	if (inst->domain == DECODER)
+		vdec_inst_deinit(inst);
+	else if (inst->domain == ENCODER)
+		venc_inst_deinit(inst);
+
 	mutex_lock(&inst->lock);
 	iris_pm_get(core);
 	close_session(inst);
@@ -342,7 +372,7 @@ static __poll_t vidc_poll(struct file *filp, struct poll_table_struct *pt)
 static int vidc_enum_fmt(struct file *filp, void *fh, struct v4l2_fmtdesc *f)
 {
 	struct iris_inst *inst;
-	int ret;
+	int ret = 0;
 
 	inst = get_vidc_inst(filp, fh);
 	if (!inst)
@@ -354,7 +384,10 @@ static int vidc_enum_fmt(struct file *filp, void *fh, struct v4l2_fmtdesc *f)
 		goto unlock;
 	}
 
-	ret = vdec_enum_fmt(inst, f);
+	if (inst->domain == DECODER)
+		ret = vdec_enum_fmt(inst, f);
+	else if (inst->domain == ENCODER)
+		ret = venc_enum_fmt(inst, f);
 
 unlock:
 	mutex_unlock(&inst->lock);
@@ -365,7 +398,7 @@ static int vidc_enum_fmt(struct file *filp, void *fh, struct v4l2_fmtdesc *f)
 static int vidc_try_fmt(struct file *filp, void *fh, struct v4l2_format *f)
 {
 	struct iris_inst *inst;
-	int ret;
+	int ret = 0;
 
 	inst = get_vidc_inst(filp, fh);
 	if (!inst)
@@ -382,7 +415,10 @@ static int vidc_try_fmt(struct file *filp, void *fh, struct v4l2_format *f)
 		goto unlock;
 	}
 
-	ret = vdec_try_fmt(inst, f);
+	if (inst->domain == DECODER)
+		ret = vdec_try_fmt(inst, f);
+	else if (inst->domain == ENCODER)
+		ret = venc_try_fmt(inst, f);
 
 unlock:
 	mutex_unlock(&inst->lock);
@@ -393,7 +429,7 @@ static int vidc_try_fmt(struct file *filp, void *fh, struct v4l2_format *f)
 static int vidc_s_fmt(struct file *filp, void *fh, struct v4l2_format *f)
 {
 	struct iris_inst *inst;
-	int ret;
+	int ret = 0;
 
 	inst = get_vidc_inst(filp, fh);
 	if (!inst)
@@ -410,7 +446,10 @@ static int vidc_s_fmt(struct file *filp, void *fh, struct v4l2_format *f)
 		goto unlock;
 	}
 
-	ret = vdec_s_fmt(inst, f);
+	if (inst->domain == DECODER)
+		ret = vdec_s_fmt(inst, f);
+	else if (inst->domain == ENCODER)
+		ret = venc_s_fmt(inst, f);
 
 unlock:
 	mutex_unlock(&inst->lock);
@@ -488,6 +527,70 @@ static int vidc_enum_framesizes(struct file *filp, void *fh,
 	return ret;
 }
 
+static int vidc_enum_frameintervals(struct file *filp, void *fh,
+				    struct v4l2_frmivalenum *fival)
+
+{
+	enum colorformat_type colorfmt;
+	struct iris_inst *inst;
+	struct iris_core *core;
+	u32 fps, mbpf;
+	int ret = 0;
+
+	inst = get_vidc_inst(filp, fh);
+	if (!inst || !fival)
+		return -EINVAL;
+
+	mutex_lock(&inst->lock);
+	if (IS_SESSION_ERROR(inst)) {
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	if (inst->domain == DECODER) {
+		ret = -ENOTTY;
+		goto unlock;
+	}
+
+	core = inst->core;
+
+	if (fival->index) {
+		ret = -EINVAL;
+		goto unlock;
+	}
+
+	colorfmt = v4l2_colorformat_to_driver(inst, fival->pixel_format);
+	if (colorfmt == FMT_NONE) {
+		ret = -EINVAL;
+		goto unlock;
+	}
+
+	if (fival->width > inst->cap[FRAME_WIDTH].max ||
+	    fival->width < inst->cap[FRAME_WIDTH].min ||
+	    fival->height > inst->cap[FRAME_HEIGHT].max ||
+	    fival->height < inst->cap[FRAME_HEIGHT].min) {
+		ret = -EINVAL;
+		goto unlock;
+	}
+
+	mbpf = NUM_MBS_PER_FRAME(fival->height, fival->width);
+	fps = core->cap[MAX_MBPS].value / mbpf;
+
+	fival->type = V4L2_FRMIVAL_TYPE_STEPWISE;
+	fival->stepwise.min.numerator = 1;
+	fival->stepwise.min.denominator =
+			min_t(u32, fps, inst->cap[FRAME_RATE].max);
+	fival->stepwise.max.numerator = 1;
+	fival->stepwise.max.denominator = 1;
+	fival->stepwise.step.numerator = 1;
+	fival->stepwise.step.denominator = inst->cap[FRAME_RATE].max;
+
+unlock:
+	mutex_unlock(&inst->lock);
+
+	return ret;
+}
+
 static int vidc_reqbufs(struct file *filp, void *fh, struct v4l2_requestbuffers *b)
 {
 	struct vb2_queue *vb2q = NULL;
@@ -751,7 +854,11 @@ static int vidc_querycap(struct file *filp, void *fh, struct v4l2_capability *ca
 	strscpy(cap->driver, VIDC_DRV_NAME, sizeof(cap->driver));
 	strscpy(cap->bus_info, VIDC_BUS_NAME, sizeof(cap->bus_info));
 	memset(cap->reserved, 0, sizeof(cap->reserved));
-	strscpy(cap->card, "iris_decoder", sizeof(cap->card));
+
+	if (inst->domain == DECODER)
+		strscpy(cap->card, "iris_decoder", sizeof(cap->card));
+	else if (inst->domain == ENCODER)
+		strscpy(cap->card, "iris_encoder", sizeof(cap->card));
 
 unlock:
 	mutex_unlock(&inst->lock);
@@ -839,7 +946,7 @@ static int vidc_querymenu(struct file *filp, void *fh, struct v4l2_querymenu *qm
 static int vidc_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub)
 {
 	struct iris_inst *inst;
-	int ret;
+	int ret = 0;
 
 	inst = container_of(fh, struct iris_inst, fh);
 
@@ -849,7 +956,10 @@ static int vidc_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subs
 		goto unlock;
 	}
 
-	ret = vdec_subscribe_event(inst, sub);
+	if (inst->domain == DECODER)
+		ret = vdec_subscribe_event(inst, sub);
+	else if (inst->domain == ENCODER)
+		ret = venc_subscribe_event(inst, sub);
 
 unlock:
 	mutex_unlock(&inst->lock);
@@ -893,28 +1003,152 @@ static int vidc_g_selection(struct file *filp, void *fh, struct v4l2_selection *
 		goto unlock;
 	}
 
-	if (s->type != OUTPUT_MPLANE && s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+	if (s->type != OUTPUT_MPLANE && s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    inst->domain == DECODER) {
 		ret = -EINVAL;
 		goto unlock;
 	}
 
-	switch (s->target) {
-	case V4L2_SEL_TGT_CROP_BOUNDS:
-	case V4L2_SEL_TGT_CROP_DEFAULT:
-	case V4L2_SEL_TGT_CROP:
-	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
-	case V4L2_SEL_TGT_COMPOSE_PADDED:
-	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
-	case V4L2_SEL_TGT_COMPOSE:
-		s->r.left = inst->crop.left;
-		s->r.top = inst->crop.top;
-		s->r.width = inst->crop.width;
-		s->r.height = inst->crop.height;
-		break;
-	default:
+	if (s->type != INPUT_MPLANE && s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+	    inst->domain == ENCODER) {
 		ret = -EINVAL;
+		goto unlock;
 	}
 
+	if (inst->domain == DECODER) {
+		switch (s->target) {
+		case V4L2_SEL_TGT_CROP_BOUNDS:
+		case V4L2_SEL_TGT_CROP_DEFAULT:
+		case V4L2_SEL_TGT_CROP:
+		case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		case V4L2_SEL_TGT_COMPOSE_PADDED:
+		case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+		case V4L2_SEL_TGT_COMPOSE:
+			s->r.left = inst->crop.left;
+			s->r.top = inst->crop.top;
+			s->r.width = inst->crop.width;
+			s->r.height = inst->crop.height;
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+	} else if (inst->domain == ENCODER) {
+		switch (s->target) {
+		case V4L2_SEL_TGT_CROP_BOUNDS:
+		case V4L2_SEL_TGT_CROP_DEFAULT:
+		case V4L2_SEL_TGT_CROP:
+			s->r.left = inst->crop.left;
+			s->r.top = inst->crop.top;
+			s->r.width = inst->crop.width;
+			s->r.height = inst->crop.height;
+			break;
+		case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		case V4L2_SEL_TGT_COMPOSE_PADDED:
+		case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+		case V4L2_SEL_TGT_COMPOSE:
+			s->r.left = inst->compose.left;
+			s->r.top = inst->compose.top;
+			s->r.width = inst->compose.width;
+			s->r.height = inst->compose.height;
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+	}
+
+unlock:
+	mutex_unlock(&inst->lock);
+
+	return ret;
+}
+
+static int vidc_s_selection(struct file *filp, void *fh, struct v4l2_selection *s)
+{
+	struct iris_inst *inst;
+	int ret = 0;
+
+	inst = get_vidc_inst(filp, fh);
+	if (!inst || !s)
+		return -EINVAL;
+
+	mutex_lock(&inst->lock);
+	if (IS_SESSION_ERROR(inst)) {
+		ret = -EBUSY;
+		goto unlock;
+	}
+	if (inst->domain == DECODER) {
+		ret = -EINVAL;
+		goto unlock;
+	} else if (inst->domain == ENCODER) {
+		ret = venc_s_selection(inst, s);
+	}
+
+unlock:
+	mutex_unlock(&inst->lock);
+
+	return ret;
+}
+
+static int vidc_s_parm(struct file *filp, void *fh, struct v4l2_streamparm *a)
+{
+	struct iris_inst *inst;
+	int ret = 0;
+
+	inst = get_vidc_inst(filp, fh);
+	if (!inst || !a)
+		return -EINVAL;
+
+	mutex_lock(&inst->lock);
+	if (IS_SESSION_ERROR(inst)) {
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+	    a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		ret = -EINVAL;
+		goto unlock;
+	}
+
+	if (inst->domain == ENCODER)
+		ret = venc_s_param(inst, a);
+	else
+		ret = -EINVAL;
+
+unlock:
+	mutex_unlock(&inst->lock);
+
+	return ret;
+}
+
+static int vidc_g_parm(struct file *filp, void *fh, struct v4l2_streamparm *a)
+{
+	struct iris_inst *inst;
+	int ret = 0;
+
+	inst = get_vidc_inst(filp, fh);
+	if (!inst || !a)
+		return -EINVAL;
+
+	mutex_lock(&inst->lock);
+	if (IS_SESSION_ERROR(inst)) {
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+	    a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		ret = -EINVAL;
+		goto unlock;
+	}
+
+	if (inst->domain == ENCODER)
+		ret = venc_g_param(inst, a);
+	else
+		ret = -EINVAL;
+
 unlock:
 	mutex_unlock(&inst->lock);
 
@@ -955,6 +1189,39 @@ static int vidc_try_dec_cmd(struct file *filp, void *fh,
 	return ret;
 }
 
+static int vidc_try_enc_cmd(struct file *filp, void *fh,
+			    struct v4l2_encoder_cmd *enc)
+{
+	struct iris_inst *inst;
+	int ret = 0;
+
+	inst = get_vidc_inst(filp, fh);
+	if (!inst || !enc)
+		return -EINVAL;
+
+	mutex_lock(&inst->lock);
+	if (IS_SESSION_ERROR(inst)) {
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	if (inst->domain != ENCODER) {
+		ret = -ENOTTY;
+		goto unlock;
+	}
+
+	if (enc->cmd != V4L2_ENC_CMD_STOP && enc->cmd != V4L2_ENC_CMD_START) {
+		ret = -EINVAL;
+		goto unlock;
+	}
+	enc->flags = 0;
+
+unlock:
+	mutex_unlock(&inst->lock);
+
+	return ret;
+}
+
 static int vidc_dec_cmd(struct file *filp, void *fh,
 			struct v4l2_decoder_cmd *dec)
 {
@@ -1002,6 +1269,60 @@ static int vidc_dec_cmd(struct file *filp, void *fh,
 	return ret;
 }
 
+static int vidc_enc_cmd(struct file *filp, void *fh,
+			struct v4l2_encoder_cmd *enc)
+{
+	struct iris_inst *inst;
+	int ret = 0;
+
+	inst = get_vidc_inst(filp, fh);
+	if (!inst || !enc)
+		return -EINVAL;
+
+	mutex_lock(&inst->lock);
+	if (IS_SESSION_ERROR(inst)) {
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	if (inst->domain != ENCODER) {
+		ret = -ENOTTY;
+		goto unlock;
+	}
+
+	if (enc->cmd != V4L2_ENC_CMD_START &&
+	    enc->cmd != V4L2_ENC_CMD_STOP) {
+		ret = -EINVAL;
+		goto unlock;
+	}
+
+	if (enc->cmd == V4L2_ENC_CMD_STOP && inst->state == IRIS_INST_OPEN) {
+		ret = 0;
+		goto unlock;
+	}
+
+	if (!allow_cmd(inst, enc->cmd)) {
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	ret = iris_pm_get(inst->core);
+	if (ret)
+		goto unlock;
+
+	if (enc->cmd == V4L2_ENC_CMD_START)
+		ret = venc_start_cmd(inst);
+	else if (enc->cmd == V4L2_ENC_CMD_STOP)
+		ret = venc_stop_cmd(inst);
+
+	iris_pm_put(inst->core, true);
+
+unlock:
+	mutex_unlock(&inst->lock);
+
+	return ret;
+}
+
 static struct v4l2_file_operations v4l2_file_ops = {
 	.owner                          = THIS_MODULE,
 	.open                           = vidc_open,
@@ -1027,7 +1348,7 @@ static struct vb2_mem_ops iris_vb2_mem_ops = {
 	.unmap_dmabuf                   = iris_vb2_unmap_dmabuf,
 };
 
-static const struct v4l2_ioctl_ops v4l2_ioctl_ops = {
+static const struct v4l2_ioctl_ops v4l2_ioctl_ops_dec = {
 	.vidioc_enum_fmt_vid_cap        = vidc_enum_fmt,
 	.vidioc_enum_fmt_vid_out        = vidc_enum_fmt,
 	.vidioc_try_fmt_vid_cap_mplane  = vidc_try_fmt,
@@ -1055,12 +1376,44 @@ static const struct v4l2_ioctl_ops v4l2_ioctl_ops = {
 	.vidioc_decoder_cmd             = vidc_dec_cmd,
 };
 
+static const struct v4l2_ioctl_ops v4l2_ioctl_ops_enc = {
+	.vidioc_enum_fmt_vid_cap        = vidc_enum_fmt,
+	.vidioc_enum_fmt_vid_out        = vidc_enum_fmt,
+	.vidioc_try_fmt_vid_cap_mplane  = vidc_try_fmt,
+	.vidioc_try_fmt_vid_out_mplane  = vidc_try_fmt,
+	.vidioc_s_fmt_vid_cap_mplane    = vidc_s_fmt,
+	.vidioc_s_fmt_vid_out_mplane    = vidc_s_fmt,
+	.vidioc_g_fmt_vid_cap_mplane    = vidc_g_fmt,
+	.vidioc_g_fmt_vid_out_mplane    = vidc_g_fmt,
+	.vidioc_enum_framesizes         = vidc_enum_framesizes,
+	.vidioc_enum_frameintervals     = vidc_enum_frameintervals,
+	.vidioc_reqbufs                 = vidc_reqbufs,
+	.vidioc_querybuf                = vidc_querybuf,
+	.vidioc_create_bufs             = vidc_create_bufs,
+	.vidioc_prepare_buf             = vidc_prepare_buf,
+	.vidioc_qbuf                    = vidc_qbuf,
+	.vidioc_dqbuf                   = vidc_dqbuf,
+	.vidioc_streamon                = vidc_streamon,
+	.vidioc_streamoff               = vidc_streamoff,
+	.vidioc_querycap                = vidc_querycap,
+	.vidioc_queryctrl               = vidc_queryctrl,
+	.vidioc_querymenu               = vidc_querymenu,
+	.vidioc_subscribe_event         = vidc_subscribe_event,
+	.vidioc_unsubscribe_event       = vidc_unsubscribe_event,
+	.vidioc_g_selection             = vidc_g_selection,
+	.vidioc_s_selection             = vidc_s_selection,
+	.vidioc_s_parm                  = vidc_s_parm,
+	.vidioc_g_parm                  = vidc_g_parm,
+	.vidioc_try_encoder_cmd         = vidc_try_enc_cmd,
+	.vidioc_encoder_cmd             = vidc_enc_cmd,
+};
+
 int init_ops(struct iris_core *core)
 {
 	core->v4l2_file_ops = &v4l2_file_ops;
 	core->vb2_ops = &iris_vb2_ops;
 	core->vb2_mem_ops = &iris_vb2_mem_ops;
-	core->v4l2_ioctl_ops = &v4l2_ioctl_ops;
-
+	core->v4l2_ioctl_ops_dec = &v4l2_ioctl_ops_dec;
+	core->v4l2_ioctl_ops_enc = &v4l2_ioctl_ops_enc;
 	return 0;
 }
diff --git a/drivers/media/platform/qcom/vcodec/iris/platform_common.h b/drivers/media/platform/qcom/vcodec/iris/platform_common.h
index 443894c..effecbb 100644
--- a/drivers/media/platform/qcom/vcodec/iris/platform_common.h
+++ b/drivers/media/platform/qcom/vcodec/iris/platform_common.h
@@ -115,6 +115,7 @@ struct iris_inst_power {
 enum plat_core_cap_type {
 	CORE_CAP_NONE = 0,
 	DEC_CODECS,
+	ENC_CODECS,
 	MAX_SESSION_COUNT,
 	MAX_MBPF,
 	MAX_MBPS,
@@ -249,6 +250,7 @@ struct plat_inst_cap {
 
 struct plat_inst_caps {
 	enum codec_type codec;
+	enum domain_type domain;
 	struct plat_inst_cap cap[INST_CAP_MAX + 1];
 };
 
diff --git a/drivers/media/platform/qcom/vcodec/iris/platform_sm8550.c b/drivers/media/platform/qcom/vcodec/iris/platform_sm8550.c
index 6d5192a..ef0aad7 100644
--- a/drivers/media/platform/qcom/vcodec/iris/platform_sm8550.c
+++ b/drivers/media/platform/qcom/vcodec/iris/platform_sm8550.c
@@ -63,6 +63,7 @@ static struct color_format_info color_format_data_sm8550[] = {
 
 static struct plat_core_cap core_data_sm8550[] = {
 	{DEC_CODECS, H264 | HEVC | VP9},
+	{ENC_CODECS, H264 | HEVC},
 	{MAX_SESSION_COUNT, 16},
 	{MAX_MBPF, 278528}, /* ((8192x4352)/256) * 2 */
 	{MAX_MBPS, 7833600}, /* max_load 7680x4320@60fps */
-- 
2.7.4





[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux