Change-Id: I5a9629d562ef80560361d777da79ff06c3e00131 Signed-off-by: Dikshita Agarwal <dikshita@xxxxxxxxxxxxxx> --- drivers/media/platform/Kconfig | 2 +- drivers/media/platform/qcom/venus/core.h | 33 ++++++ drivers/media/platform/qcom/venus/helpers.c | 172 ++++++++++++++++++++++++++++ drivers/media/platform/qcom/venus/helpers.h | 15 +++ drivers/media/platform/qcom/venus/venc.c | 36 ++++++ 5 files changed, 257 insertions(+), 1 deletion(-) 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; -- 1.9.1