diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index ca3cb4f..a51f76e 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -481,7 +481,7 @@ config VIDEO_TI_VPE_DEBUG
 
 config VIDEO_QCOM_VENUS
 	tristate "Qualcomm Venus V4L2 encoder/decoder driver"
-	depends on VIDEO_DEV && VIDEO_V4L2
+	depends on VIDEO_DEV && VIDEO_V4L2 && MEDIA_CONTROLLER
 	depends on (ARCH_QCOM && IOMMU_DMA) || COMPILE_TEST
 	select QCOM_MDT_LOADER if ARCH_QCOM
 	select QCOM_SCM if ARCH_QCOM
diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h
index 922cb7e..91ff08d 100644
--- a/drivers/media/platform/qcom/venus/core.h
+++ b/drivers/media/platform/qcom/venus/core.h
@@ -74,6 +74,37 @@ struct venus_caps {
 };
 
 /**
+ * struct venus_media - per-device context
+ * @source:		&struct media_entity pointer with the source entity
+ *			Used only when the M2M device is registered via
+ *			v4l2_m2m_unregister_media_controller().
+ * @source_pad:		&struct media_pad with the source pad.
+ *			Used only when the M2M device is registered via
+ *			v4l2_m2m_unregister_media_controller().
+ * @sink:		&struct media_entity pointer with the sink entity
+ *			Used only when the M2M device is registered via
+ *			v4l2_m2m_unregister_media_controller().
+ * @sink_pad:		&struct media_pad with the sink pad.
+ *			Used only when the M2M device is registered via
+ *			v4l2_m2m_unregister_media_controller().
+ * @proc:		&struct media_entity pointer with the M2M device itself.
+ * @proc_pads:		&struct media_pad with the @proc pads.
+ *			Used only when the M2M device is registered via
+ *			v4l2_m2m_unregister_media_controller().
+ * @intf_devnode:	&struct media_intf devnode pointer with the interface
+ *			with controls the M2M device.
+ */
+struct venus_media {
+	struct media_entity	*source;
+	struct media_pad	source_pad;
+	struct media_entity	sink;
+	struct media_pad	sink_pad;
+	struct media_entity	proc;
+	struct media_pad	proc_pads[2];
+	struct media_intf_devnode *intf_devnode;
+};
+
+/**
  * struct venus_core - holds core parameters valid for all instances
  *
  * @base:	IO memory base address
@@ -118,6 +149,8 @@ struct venus_core {
 	struct video_device *vdev_dec;
 	struct video_device *vdev_enc;
 	struct v4l2_device v4l2_dev;
+	struct media_device	m_dev;
+	struct venus_media *media;
 	const struct venus_resources *res;
 	struct device *dev;
 	struct device *dev_dec;
diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c
index 1ad96c2..2c766cd 100644
--- a/drivers/media/platform/qcom/venus/helpers.c
+++ b/drivers/media/platform/qcom/venus/helpers.c
@@ -1378,3 +1378,175 @@ int venus_helper_power_enable(struct venus_core *core, u32 session_type,
 	return 0;
 }
 EXPORT_SYMBOL_GPL(venus_helper_power_enable);
+
+static int venus_helper_register_entity(struct media_device *mdev,
+	struct venus_media *media, enum venus_helper_entity_type type,
+	struct video_device *vdev, int function)
+{
+	struct media_entity *entity;
+	struct media_pad *pads;
+	char *name;
+	unsigned int len;
+	int num_pads;
+	int ret;
+
+	switch (type) {
+	case MEM2MEM_ENT_TYPE_SOURCE:
+		entity = media->source;
+		pads = &media->source_pad;
+		pads[0].flags = MEDIA_PAD_FL_SOURCE;
+		num_pads = 1;
+		break;
+	case MEM2MEM_ENT_TYPE_SINK:
+		entity = &media->sink;
+		pads = &media->sink_pad;
+		pads[0].flags = MEDIA_PAD_FL_SINK;
+		num_pads = 1;
+		break;
+	case MEM2MEM_ENT_TYPE_PROC:
+		entity = &media->proc;
+		pads = media->proc_pads;
+		pads[0].flags = MEDIA_PAD_FL_SINK;
+		pads[1].flags = MEDIA_PAD_FL_SOURCE;
+		num_pads = 2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	entity->obj_type = MEDIA_ENTITY_TYPE_BASE;
+	if (type != MEM2MEM_ENT_TYPE_PROC) {
+		entity->info.dev.major = VIDEO_MAJOR;
+		entity->info.dev.minor = vdev->minor;
+	}
+	len = strlen(vdev->name) + 2 + strlen(venus_helper_entity_name[type]);
+	name = kmalloc(len, GFP_KERNEL);
+	if (!name)
+		return -ENOMEM;
+	snprintf(name, len, "%s-%s", vdev->name, venus_helper_entity_name[type]);
+	entity->name = name;
+	entity->function = function;
+
+	ret = media_entity_pads_init(entity, num_pads, pads);
+	if (ret)
+		return ret;
+	ret = media_device_register_entity(mdev, entity);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int venus_helper_register_media_controller(struct venus_media *media,
+		struct video_device *vdev, int function)
+{
+	struct media_device *mdev = vdev->v4l2_dev->mdev;
+	struct media_link *link;
+	int ret;
+	v4l2_err(vdev, "1.\n");
+	if (!mdev)
+		return 0;
+	v4l2_err(vdev, "2.\n");
+	/* A memory-to-memory device consists in two
+	 * DMA engine and one video processing entities.
+	 * The DMA engine entities are linked to a V4L interface
+	 */
+
+	/* Create the three entities with their pads */
+	media->source = &vdev->entity;
+	ret = venus_helper_register_entity(mdev, media,
+			MEM2MEM_ENT_TYPE_SOURCE, vdev, MEDIA_ENT_F_IO_V4L);
+	if (ret) {
+		v4l2_err(vdev, "3_error.\n");
+		return ret;
+		}
+	v4l2_err(vdev, "3 pass.\n");
+	ret = venus_helper_register_entity(mdev, media,
+			MEM2MEM_ENT_TYPE_PROC, vdev, function);
+	if (ret){
+		v4l2_err(vdev, "4 error.\n");
+		goto err_rel_entity0;
+	}
+	v4l2_err(vdev, "4 pass.\n");
+	ret = venus_helper_register_entity(mdev, media,
+			MEM2MEM_ENT_TYPE_SINK, vdev, MEDIA_ENT_F_IO_V4L);
+	if (ret)
+		goto err_rel_entity1;
+	v4l2_err(vdev, "5 pass.\n");
+	/* Connect the three entities */
+	ret = media_create_pad_link(media->source, 0, &media->proc, 1,
+			MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
+	if (ret)
+		goto err_rel_entity2;
+	v4l2_err(vdev, "6 pass.\n");
+	ret = media_create_pad_link(&media->proc, 0, &media->sink, 0,
+			MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
+	if (ret)
+		goto err_rm_links0;
+	v4l2_err(vdev, "7 pass.\n");
+	/* Create video interface */
+	media->intf_devnode = media_devnode_create(mdev,
+			MEDIA_INTF_T_V4L_VIDEO, 0,
+			VIDEO_MAJOR, vdev->minor);
+	if (!media->intf_devnode) {
+		ret = -ENOMEM;
+		goto err_rm_links1;
+	}
+	v4l2_err(vdev, "8 pass.\n");
+	/* Connect the two DMA engines to the interface */
+	link = media_create_intf_link(media->source,
+			&media->intf_devnode->intf,
+			MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
+	if (!link) {
+		ret = -ENOMEM;
+		goto err_rm_devnode;
+	}
+
+	link = media_create_intf_link(&media->sink,
+			&media->intf_devnode->intf,
+			MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
+	if (!link) {
+		ret = -ENOMEM;
+		goto err_rm_intf_link;
+	}
+	return 0;
+
+err_rm_intf_link:
+	media_remove_intf_links(&media->intf_devnode->intf);
+err_rm_devnode:
+	media_devnode_remove(media->intf_devnode);
+err_rm_links1:
+	media_entity_remove_links(&media->sink);
+err_rm_links0:
+	media_entity_remove_links(&media->proc);
+	media_entity_remove_links(media->source);
+err_rel_entity2:
+	media_device_unregister_entity(&media->proc);
+	kfree(media->proc.name);
+err_rel_entity1:
+	media_device_unregister_entity(&media->sink);
+	kfree(media->sink.name);
+err_rel_entity0:
+	media_device_unregister_entity(media->source);
+	kfree(media->source->name);
+	return ret;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(venus_helper_register_media_controller);
+
+void venus_helper_unregister_media_controller(struct venus_media *media)
+{
+	media_remove_intf_links(&media->intf_devnode->intf);
+	media_devnode_remove(media->intf_devnode);
+
+	media_entity_remove_links(media->source);
+	media_entity_remove_links(&media->sink);
+	media_entity_remove_links(&media->proc);
+	media_device_unregister_entity(media->source);
+	media_device_unregister_entity(&media->sink);
+	media_device_unregister_entity(&media->proc);
+	kfree(media->source->name);
+	kfree(media->sink.name);
+	kfree(media->proc.name);
+}
+EXPORT_SYMBOL_GPL(venus_helper_unregister_media_controller);
diff --git a/drivers/media/platform/qcom/venus/helpers.h b/drivers/media/platform/qcom/venus/helpers.h
index 01f411b..ca4db82 100644
--- a/drivers/media/platform/qcom/venus/helpers.h
+++ b/drivers/media/platform/qcom/venus/helpers.h
@@ -11,6 +11,18 @@
 struct venus_inst;
 struct venus_core;
 
+enum venus_helper_entity_type {
+	MEM2MEM_ENT_TYPE_SOURCE,
+	MEM2MEM_ENT_TYPE_SINK,
+	MEM2MEM_ENT_TYPE_PROC
+};
+
+static const char * const venus_helper_entity_name[] = {
+	"source",
+	"sink",
+	"proc"
+};
+
 bool venus_helper_check_codec(struct venus_inst *inst, u32 v4l2_pixfmt);
 struct vb2_v4l2_buffer *venus_helper_find_buf(struct venus_inst *inst,
 					      unsigned int type, u32 idx);
@@ -64,4 +76,7 @@ int venus_helper_power_enable(struct venus_core *core, u32 session_type,
 int venus_helper_process_initial_out_bufs(struct venus_inst *inst);
 void venus_helper_get_ts_metadata(struct venus_inst *inst, u64 timestamp_us,
 				  struct vb2_v4l2_buffer *vbuf);
+int venus_helper_register_media_controller(struct venus_media *media,
+		struct video_device *vdev, int function);
+void venus_helper_unregister_media_controller(struct venus_media *media);
 #endif
diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c
index 30028ce..f57542f 100644
--- a/drivers/media/platform/qcom/venus/venc.c
+++ b/drivers/media/platform/qcom/venus/venc.c
@@ -22,6 +22,17 @@
 #include "venc.h"
 
 #define NUM_B_FRAMES_MAX	4
+#ifdef CONFIG_MEDIA_CONTROLLER
+	struct media_device	mdev;
+#endif
+static int venc_request_validate(struct media_request *req)
+{
+	return vb2_request_validate(req);
+}
+static const struct media_device_ops venus_m2m_media_ops = {
+	.req_validate	= venc_request_validate,
+	.req_queue	= v4l2_m2m_request_queue,
+};
 
 /*
  * Three resons to keep MPLANE formats (despite that the number of planes
@@ -1287,8 +1298,33 @@ static int venc_probe(struct platform_device *pdev)
 	video_set_drvdata(vdev, core);
 	pm_runtime_enable(dev);
 
+#ifdef CONFIG_MEDIA_CONTROLLER
+	core->m_dev.dev = &pdev->dev;
+	strscpy(core->m_dev.model, "media_enc", sizeof(core->m_dev.model));
+	media_device_init(&core->m_dev);
+	core->m_dev.ops = &venus_m2m_media_ops;
+	core->v4l2_dev.mdev = &core->m_dev;
+	core->media = kzalloc(sizeof *core->media, GFP_KERNEL);
+	if (!core->media)
+		return ERR_PTR(-ENOMEM);
+	ret = venus_helper_register_media_controller(core->media,
+						 core->vdev_enc,
+						 MEDIA_ENT_F_PROC_VIDEO_ENCODER);
+	if (ret) {
+		v4l2_err(core->vdev_enc, "Failed to init mem2mem media controller for enc\n");
+		goto err_vdev_release;
+	}
+
+	ret = media_device_register(&core->m_dev);
+	if (ret) {
+		//v4l2_err(&core->m_dev, "Failed to register mem2mem media device\n");
+		goto err_unreg_m2m;
+	}
+#endif
 	return 0;
 
+err_unreg_m2m:
+	venus_helper_unregister_media_controller(core->media);
 err_vdev_release:
 	video_device_release(vdev);
 	return ret;
