Re: [PATCH] media: s5p-tv: support mc framework

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

 



Hi Jiun Yu,
Thanks for proposing this patch. I was considering moving
V4L2 TV drivers to Media Controller framework. I am glad that
this patch was posted.

However, there are still some important issues.
Please refer to the comments below.

On 02/29/2012 12:03 PM, Jiun Yu wrote:
> From: Jiun Yu<jiun.yu@xxxxxxxxxxx>
>
> Samsung Exynos tv subsystem is composed of video processor, mixer, HDMI Tx
> and analog TV. Each h/w IP becomes a entity and also inputs of video and graphic
> layers become entities in media controller framework like below figure.
>
>    +-------------+-+       +-+--------------+-+       +-+----------------+-+
>    | mxr-vd-grp0 |0| ----> |0| mxr-sd-grp0  |1| ----> | |                | |
>    +-------------+-+       +-+--------------+-+       |0|                | |       +-+---------+
>                                                       | |                | | ----> |0| hdmi-sd |
>    +-------------+-+       +-+--------------+-+       +-+                | |       +-+---------+
>    | mxr-vd-grp1 |0| ----> |0| mxr-sd-grp1  |1| ----> | |                | |
>    +-------------+-+       +-+--------------+-+       |1| mxr-sd-blender |3|
>                                                       | |                | |
>                            +-+--------------+-+       +-+                | |       +-+---------+
>                            |0| mxr-sd-video |1| ----> | |                | | ----> |0| sdo-sd  |
>                            +-+--------------+-+       |2|                | |       +-+---------+
>                                                       | |                | |
>                                                       +-+----------------+-+

What is the purpose for separating mxr-vd-* from mxr-sd-*.
There is no additional HW chip hidden behind mxr-sd-* subdev.

Using mxr-sd-video is rational because this subdev refers to VideoProcessor.
This chip may makes use of its controls like
brightness/contrast adjustment or image filtering.
But why mxr-sd-video is not connected to any video node?

What do you think about following topology:

                            +-+--------------+-+       +-+----------------+-+
                            |0| mxr-vd-grp0  |1| ----> | |                | |
                            +-+--------------+-+       |0|                | |       +-+---------+
                                                       | |                | | ----> |0| hdmi-sd |
                            +-+--------------+-+       +-+                | |       +-+---------+
                            |0| mxr-vd-grp1  |1| ----> | |                | |
                            +-+--------------+-+       |1| mxr-sd-blender |3|
                                                       | |                | |
    +-------------+-+       +-+--------------+-+       +-+                | |       +-+---------+
    | mxr-vd-video|0| ----> |0|   mxr-sd-vp  |1| ----> | |                | | ----> |0| sdo-sd  |
    +-------------+-+       +-+--------------+-+       |2|                | |       +-+---------+
                                                       | |                | |
                                                       +-+----------------+-+

It is much simpler because if contains 4 subdevs instead of 6 and allows to
use every data sink as video node.

>
> * mxr-vd-grp0
>    video device type entity
>    input of graphic0 layer
>
> * mxr-vd-grp1
>    video device type entity
>    input of graphic1 layer
>
> * mxr-sd-grp0
>    sub-device type entity
>    graphic0 layer part of mixer
>
> * mxr-sd-grp1
>    sub-device type entity
>    graphic1 layer part of mixer
>
> * mxr-sd-video
>    sub-device type entity
>    video layer part of mixer

I prefer to call it mxr-sd-vp (Video Processor).
>
> * mxr-sd-blender
>    sub-device type entity
>    blender part of mixer

Would it be better to use name 'mxr-sd-mixer' instead of 'mxr-sd-blender'?
The chip is called 'Mixer". The 'Blender' is some internal subblock of Mixer.

>
> * hdmi-sd
>    sub-device type entity
>    hdmi tx

In future we should consider adding entities like HDMIPHY and MHL to MC topology.
For now let HDMI driver deal with its slave devices.

>
> * sdo-sd
>    sub-device type entity
>    analog TV-out
>
> Signed-off-by: Jiun Yu<jiun.yu@xxxxxxxxxxx>
> ---
>   drivers/media/video/s5p-tv/hdmi_drv.c        |   77 ++++++++-
>   drivers/media/video/s5p-tv/mixer.h           |   52 ++++++
>   drivers/media/video/s5p-tv/mixer_drv.c       |  224 ++++++++++++++++++++++++++
>   drivers/media/video/s5p-tv/mixer_grp_layer.c |    2 +-
>   drivers/media/video/s5p-tv/mixer_video.c     |  127 ++++++++-------
>   drivers/media/video/s5p-tv/sdo_drv.c         |   75 ++++++++-
>   6 files changed, 478 insertions(+), 79 deletions(-)
>
> diff --git a/drivers/media/video/s5p-tv/hdmi_drv.c b/drivers/media/video/s5p-tv/hdmi_drv.c
> index 8b41a04..4c3cb7b 100644
> --- a/drivers/media/video/s5p-tv/hdmi_drv.c
> +++ b/drivers/media/video/s5p-tv/hdmi_drv.c
> @@ -33,6 +33,8 @@
>   #include<media/v4l2-common.h>
>   #include<media/v4l2-dev.h>
>   #include<media/v4l2-device.h>
> +#include<media/v4l2-subdev.h>
> +#include<media/exynos_mc.h>
>
>   #include "regs-hdmi.h"
>
> @@ -42,6 +44,10 @@ MODULE_LICENSE("GPL");
>
>   /* default preset configured on probe */
>   #define HDMI_DEFAULT_PRESET V4L2_DV_1080P60
> +/* sink pad number of hdmi subdev */
> +#define HDMI_PAD_SINK	0
> +/* number of hdmi subdev pads */
> +#define HDMI_PADS_NUM	1
>
>   struct hdmi_resources {
>   	struct clk *hdmi;
> @@ -62,6 +68,8 @@ struct hdmi_device {
>   	struct device *dev;
>   	/** subdev generated by HDMI device */
>   	struct v4l2_subdev sd;
> +	/** sink pad of hdmi subdev */
> +	struct media_pad pad;
>   	/** V4L2 device structure */
>   	struct v4l2_device v4l2_dev;
>   	/** subdev of HDMIPHY interface */
> @@ -863,12 +871,68 @@ fail:
>   	return -ENODEV;
>   }
>
> +static int hdmi_link_setup(struct media_entity *entity,
> +			      const struct media_pad *local,
> +			      const struct media_pad *remote, u32 flags)
> +{
> +	return 0;
> +}
> +
> +/* hdmi entity operations */
> +static const struct media_entity_operations hdmi_entity_ops = {
> +	.link_setup = hdmi_link_setup,
> +};
> +
> +static int hdmi_register_entity(struct hdmi_device *hdev)
> +{
> +	struct v4l2_subdev *sd =&hdev->sd;
> +	struct media_pad *pad =&hdev->pad;
> +	struct media_entity *me =&sd->entity;
> +	struct device *dev = hdev->dev;
> +	struct exynos_md *md;
> +	int ret;
> +
> +	dev_dbg(dev, "HDMI entity init\n");
> +

Why this code (till [end]) was moved from hdmi_probe?

> +	/* init hdmi subdev */
> +	v4l2_subdev_init(sd,&hdmi_sd_ops);
> +	sd->owner = THIS_MODULE;
> +	strlcpy(sd->name, "hdmi-sd", sizeof(sd->name));
> +
> +	dev_set_drvdata(dev, sd);

[end]

> +
> +	/* init hdmi subdev as entity */
> +	pad[HDMI_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
> +	me->ops =&hdmi_entity_ops;
> +	ret = media_entity_init(me, HDMI_PADS_NUM, pad, 0);
> +	if (ret) {
> +		dev_err(dev, "failed to initialize media entity\n");
> +		return ret;
> +	}
> +
> +	/* get output media ptr for registering hdmi's sd */
> +	md = (struct exynos_md *)module_name_to_driver_data(MDEV_MODULE_NAME);

The dependency between S5P-HDMI and EXYNOS_MD should be reflected in Kconfig.

> +	if (!md) {
> +		dev_err(dev, "failed to get output media device\n");
> +		return -ENODEV;
> +	}
> +
> +	/* regiser HDMI subdev as entity to v4l2_dev pointer of
> +	 * output media device */
> +	ret = v4l2_device_register_subdev(&md->v4l2_dev, sd);
> +	if (ret) {
> +		dev_err(dev, "failed to register HDMI subdev\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
>   static int __devinit hdmi_probe(struct platform_device *pdev)
>   {
>   	struct device *dev =&pdev->dev;
>   	struct resource *res;
>   	struct i2c_adapter *phy_adapter;
> -	struct v4l2_subdev *sd;
>   	struct hdmi_device *hdmi_dev = NULL;
>   	struct hdmi_driver_data *drv_data;
>   	int ret;
> @@ -950,17 +1014,14 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
>
>   	pm_runtime_enable(dev);
>
> -	sd =&hdmi_dev->sd;
> -	v4l2_subdev_init(sd,&hdmi_sd_ops);
> -	sd->owner = THIS_MODULE;
> -
> -	strlcpy(sd->name, "s5p-hdmi", sizeof sd->name);
>   	hdmi_dev->cur_preset = HDMI_DEFAULT_PRESET;
>   	/* FIXME: missing fail preset is not supported */
>   	hdmi_dev->cur_conf = hdmi_preset2conf(hdmi_dev->cur_preset);
>
> -	/* storing subdev for call that have only access to struct device */
> -	dev_set_drvdata(dev, sd);
> +	/* register hdmi subdev as entity */
> +	ret = hdmi_register_entity(hdmi_dev);
> +	if (ret)
> +		goto fail_vdev;
>
>   	dev_info(dev, "probe sucessful\n");
>
> diff --git a/drivers/media/video/s5p-tv/mixer.h b/drivers/media/video/s5p-tv/mixer.h
> index 1597078..2f6b773 100644
> --- a/drivers/media/video/s5p-tv/mixer.h
> +++ b/drivers/media/video/s5p-tv/mixer.h
> @@ -23,18 +23,43 @@
>   #include<linux/spinlock.h>
>   #include<linux/wait.h>
>   #include<media/v4l2-device.h>
> +#include<media/v4l2-subdev.h>
>   #include<media/videobuf2-core.h>
>
>   #include "regs-mixer.h"
>
>   /** maximum number of output interfaces */
>   #define MXR_MAX_OUTPUTS 2
> +/** index of graphic0 layer */
> +#define MXR_GRP0_LAYER	0
> +/** index of graphic1 layer */
> +#define MXR_GRP1_LAYER	1
> +/** index of video layer */
> +#define MXR_VIDEO_LAYER	2
>   /** maximum number of input interfaces (layers) */
>   #define MXR_MAX_LAYERS 3
>   #define MXR_DRIVER_NAME "s5p-mixer"
>   /** maximal number of planes for every layer */
>   #define MXR_MAX_PLANES	2
>
> +/** sink pad of each layer subdev */
> +#define MXR_PAD_SINK		0
> +/** source pad of each layer subdev */
> +#define MXR_PAD_SOURCE		1
> +/** sink pad of blender connected to graphic0 layer subdev */
> +#define MXR_PAD_SINK_GRP0	0
> +/** sink pad of blender connected to graphic1 layer subdev */
> +#define MXR_PAD_SINK_GRP1	1
> +/** sink pad of blender connected to video layer subdev */
> +#define MXR_PAD_SINK_VIDEO	2
> +/** source pad of blender connected to hdmi subdev */
> +#define MXR_PAD_SOURCE_OUTPUT	3
> +
> +/** maximum pad number of mixer subdev */
> +#define MXR_PADS_NUM	2
> +/** maximum pad number of blender subdev */
> +#define MXR_BLENDER_PADS_NUM	4
> +
>   #define MXR_ENABLE 1
>   #define MXR_DISABLE 0
>
> @@ -117,6 +142,12 @@ struct mxr_buffer {
>   	struct list_head	list;
>   };
>
> +/** TV graphic layer pipeline structure for streaming media data */
> +struct tv_graph_pipeline {
> +	struct media_pipeline pipe;
> +	/** starting point on pipeline */
> +	struct mxr_layer *layer;
> +};
>
>   /** internal states of layer */
>   enum mxr_layer_state {
> @@ -176,12 +207,21 @@ struct mxr_layer {
>   	struct mutex mutex;
>   	/** handler for video node */
>   	struct video_device vfd;
> +	/** source pad of mixer video device */
> +	struct media_pad vd_pad;
>   	/** queue for output buffers */
>   	struct vb2_queue vb_queue;
>   	/** current image format */
>   	const struct mxr_format *fmt;
>   	/** current geometry of image */
>   	struct mxr_geometry geo;
> +
> +	/** each layer subdev of a mixer */
> +	struct v4l2_subdev sd;
> +	/** pads for each layer subdev */
> +	struct media_pad sd_pads[MXR_PADS_NUM];
> +	/** pipeline structure for streaming TV graphic layer */
> +	struct tv_graph_pipeline pipe;
>   };
>
>   /** description of mixers output interface */
> @@ -263,6 +303,11 @@ struct mxr_device {
>   	int current_output;
>   	/** auxiliary resources used my mixer */
>   	struct mxr_resources res;
> +
> +	/** subdev of mixer blender */
> +	struct v4l2_subdev sd;
> +	/** pads of mixer blender */
> +	struct media_pad pads[MXR_BLENDER_PADS_NUM];
>   };
>
>   /** transform device structure into mixer device */
> @@ -272,6 +317,13 @@ static inline struct mxr_device *to_mdev(struct device *dev)
>   	return container_of(vdev, struct mxr_device, v4l2_dev);
>   }
>
> +/** transform subdev structure into mixer device */
> +static inline struct mxr_device *sd_to_mdev(struct v4l2_subdev *sd)
> +{
> +	struct mxr_layer *layer = container_of(sd, struct mxr_layer, sd);
> +	return layer->mdev;
> +}
> +
>   /** get current output data, should be called under mdev's mutex */
>   static inline struct mxr_output *to_output(struct mxr_device *mdev)
>   {
> diff --git a/drivers/media/video/s5p-tv/mixer_drv.c b/drivers/media/video/s5p-tv/mixer_drv.c
> index 0064309..a07cd1e 100644
> --- a/drivers/media/video/s5p-tv/mixer_drv.c
> +++ b/drivers/media/video/s5p-tv/mixer_drv.c
> @@ -23,6 +23,8 @@
>   #include<linux/pm_runtime.h>
>   #include<linux/clk.h>
>
> +#include<media/exynos_mc.h>
> +
>   MODULE_AUTHOR("Tomasz Stanislawski,<t.stanislaws@xxxxxxxxxxx>");
>   MODULE_DESCRIPTION("Samsung MIXER");
>   MODULE_LICENSE("GPL");
> @@ -370,6 +372,213 @@ static const struct dev_pm_ops mxr_pm_ops = {
>   	.runtime_resume	 = mxr_runtime_resume,
>   };
>
> +/* ---------- MEDIA CONTROLLER MANAGEMENT ----------- */
> +
> +static int mxr_s_stream(struct v4l2_subdev *sd, int enable)
> +{
> +	struct mxr_device *mdev = sd_to_mdev(sd);
> +
> +	if (enable)
> +		mxr_streamer_get(mdev);
> +	else
> +		mxr_streamer_put(mdev);
> +
> +	return 0;
> +}
> +
> +static const struct v4l2_subdev_video_ops mxr_sd_video_ops = {
> +	.s_stream = mxr_s_stream,
> +};
> +
> +static const struct v4l2_subdev_ops mxr_sd_ops = {
> +	.video =&mxr_sd_video_ops,
> +};
> +
> +static const struct v4l2_subdev_ops blend_sd_ops = {
> +};

what is the purpose of introducing the subdev that does nothing.
Maybe you should add at least s_stream.

> +
> +static int mxr_link_setup(struct media_entity *entity,
> +			      const struct media_pad *local,
> +			      const struct media_pad *remote, u32 flags)
> +{
> +	return 0;

There might be a bug here.
Returning zero indicate that mixer subdev can be connected with
any other subdev. Is it correct?

> +}
> +
> +/* mixer entity operations */
> +static const struct media_entity_operations mxr_entity_ops = {
> +	.link_setup = mxr_link_setup,
> +};
> +
> +static int mxr_register_entities(struct mxr_device *mdev)
> +{
> +	struct v4l2_subdev *sd;
> +	struct v4l2_subdev *blend_sd;
> +	struct media_pad *pads;
> +	struct media_pad *blend_pads;
> +	struct media_entity *me;
> +	struct media_entity *blend_me;
> +	struct exynos_md *md;
> +	int ret, i;
> +
> +	mxr_dbg(mdev, "initialize and register mixer entities\n");
> +
> +	md = (struct exynos_md *)module_name_to_driver_data(MDEV_MODULE_NAME);

no dependency in Kconfig

> +	if (!md) {
> +		mxr_err(mdev, "failed to get output media device\n");
> +		return -ENODEV;
> +	}
> +
> +	/* initialize and register each layer subdev of mixer */
> +	for (i = 0; i<  MXR_MAX_LAYERS; ++i) {
> +		sd =&mdev->layer[i]->sd;
> +		pads = mdev->layer[i]->sd_pads;
> +		me =&sd->entity;
> +
> +		v4l2_subdev_init(sd,&mxr_sd_ops);
> +		sd->owner = THIS_MODULE;
> +
> +		if (i == MXR_VIDEO_LAYER)
> +			sprintf(sd->name, "mxr-sd-video");
> +		else
> +			sprintf(sd->name, "mxr-sd-grp%d", i);
> +
> +		pads[MXR_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
> +		pads[MXR_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
> +
> +		me->ops =&mxr_entity_ops;
> +
> +		ret = media_entity_init(me, MXR_PADS_NUM, pads, 0);
> +		if (ret) {
> +			mxr_err(mdev, "failed to initialize media entity\n");
> +			return ret;
> +		}
> +
> +		ret = v4l2_device_register_subdev(&md->v4l2_dev, sd);
> +		if (ret) {
> +			mxr_err(mdev, "failed to register mixer subdev\n");
> +			return ret;
> +		}
> +	}
> +
> +	/* initialize and register mixer blender */
> +	blend_sd =&mdev->sd;
> +	blend_pads = mdev->pads;
> +	blend_me =&blend_sd->entity;
> +
> +	v4l2_subdev_init(blend_sd,&blend_sd_ops);
> +	sd->owner = THIS_MODULE;
> +
> +	sprintf(blend_sd->name, "mxr-sd-blender");
> +
> +	blend_pads[MXR_PAD_SINK_GRP0].flags = MEDIA_PAD_FL_SINK;
> +	blend_pads[MXR_PAD_SINK_GRP1].flags = MEDIA_PAD_FL_SINK;
> +	blend_pads[MXR_PAD_SINK_VIDEO].flags = MEDIA_PAD_FL_SINK;
> +	blend_pads[MXR_PAD_SOURCE_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
> +
> +	blend_me->ops =&mxr_entity_ops;
> +
> +	ret = media_entity_init(blend_me, MXR_BLENDER_PADS_NUM, blend_pads, 0);
> +	if (ret) {
> +		mxr_err(mdev, "failed to initialize media entity\n");
> +		return ret;
> +	}
> +
> +	ret = v4l2_device_register_subdev(&md->v4l2_dev, blend_sd);
> +	if (ret) {
> +		mxr_err(mdev, "failed to register mixer subdev\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static void mxr_unregister_entities(struct mxr_device *mdev)
> +{
> +	int i;
> +
> +	/* unregister subdevs of all layers */
> +	for (i = 0; i<  MXR_MAX_LAYERS; ++i)
> +		v4l2_device_unregister_subdev(&mdev->layer[i]->sd);
> +
> +	/* unregister blender subdev */
> +	v4l2_device_unregister_subdev(&mdev->sd);
> +}
> +
> +static void mxr_entities_info_print(struct mxr_device *mdev)
> +{
> +	struct media_entity *me;
> +	int i;
> +
> +	for (i = 0; i<  MXR_VIDEO_LAYER; ++i) {
> +		me =&mdev->layer[i]->vfd.entity;
> +		entity_info_print(me, mdev->dev);
> +	}
> +
> +	for (i = 0; i<  MXR_MAX_LAYERS; ++i) {
> +		me =&mdev->layer[i]->sd.entity;
> +		entity_info_print(me, mdev->dev);
> +	}
> +
> +	me =&mdev->sd.entity;
> +	entity_info_print(me, mdev->dev);
> +
> +	for (i = 0; i<  mdev->output_cnt; ++i) {
> +		me =&mdev->output[i]->sd->entity;
> +		entity_info_print(me, mdev->dev);
> +	}
> +}
> +
> +static int mxr_create_links(struct mxr_device *mdev)
> +{
> +	struct media_entity *source, *sink;
> +	char err[80];
> +	int ret, i;
> +
> +	mxr_dbg(mdev, "%s start\n", __func__);
> +
> +	memset(err, 0, sizeof(err));
> +
> +	/* create link between graphic layer vd to graphic layer sd */
> +	for (i = 0; i<  MXR_VIDEO_LAYER; ++i) {
> +		source =&mdev->layer[i]->vfd.entity;
> +		sink =&mdev->layer[i]->sd.entity;
> +		ret = media_entity_create_link(source, 0, sink, MXR_PAD_SINK, 0);
> +		if (ret) {
> +			sprintf(err, "%s ->  %s", source->name, sink->name);
> +			goto fail;
> +		}
> +	}
> +
> +	/* create link between all layers sd to blender sd*/
> +	for (i = 0; i<  MXR_MAX_LAYERS; ++i) {
> +		source =&mdev->layer[i]->sd.entity;
> +		sink =&mdev->sd.entity;
> +		ret = media_entity_create_link(source, MXR_PAD_SOURCE, sink, i, 0);
> +		if (ret) {
> +			sprintf(err, "%s ->  %s", source->name, sink->name);
> +			goto fail;
> +		}
> +	}
> +
> +	/* create link between blender to output devices */
> +	for (i = 0; i<  mdev->output_cnt; ++i) {
> +		source =&mdev->sd.entity;
> +		sink =&mdev->output[i]->sd->entity;
> +		ret = media_entity_create_link(source, MXR_PAD_SOURCE_OUTPUT,
> +				sink, 0, 0);
> +		if (ret) {
> +			sprintf(err, "%s ->  %s", source->name, sink->name);
> +			goto fail;
> +		}
> +	}
> +
> +	return 0;
> +
> +fail:
> +	mxr_err(mdev, "failed to create link : %s\n", err);
> +	return ret;
> +}
> +
>   /* --------- DRIVER INITIALIZATION ---------- */
>
>   static int __devinit mxr_probe(struct platform_device *pdev)
> @@ -410,13 +619,28 @@ static int __devinit mxr_probe(struct platform_device *pdev)
>   	/* configure layers */
>   	ret = mxr_acquire_layers(mdev, pdata);
>   	if (ret)
> +		goto fail_entities;
> +
> +	/* register mixer subdevs as entity */
> +	ret = mxr_register_entities(mdev);
> +	if (ret)
>   		goto fail_video;
>
> +	/* create all links related to exynos-tv driver */
> +	ret = mxr_create_links(mdev);
> +	if (ret)
> +		goto fail_entities;
> +
>   	pm_runtime_enable(dev);
>
> +	mxr_entities_info_print(mdev);
> +
>   	mxr_info(mdev, "probe successful\n");
>   	return 0;
>
> +fail_entities:
> +	mxr_unregister_entities(mdev);
> +
>   fail_video:
>   	mxr_release_video(mdev);
>
> diff --git a/drivers/media/video/s5p-tv/mixer_grp_layer.c b/drivers/media/video/s5p-tv/mixer_grp_layer.c
> index b93a21f..eb29d38 100644
> --- a/drivers/media/video/s5p-tv/mixer_grp_layer.c
> +++ b/drivers/media/video/s5p-tv/mixer_grp_layer.c
> @@ -244,7 +244,7 @@ struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx)
>   	};
>   	char name[32];
>
> -	sprintf(name, "graph%d", idx);
> +	sprintf(name, "mxr-vd-grp%d", idx);
>
>   	layer = mxr_base_layer_create(mdev, idx, name,&ops);
>   	if (layer == NULL) {
> diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c
> index 7884bae..2ca580b 100644
> --- a/drivers/media/video/s5p-tv/mixer_video.c
> +++ b/drivers/media/video/s5p-tv/mixer_video.c
> @@ -20,69 +20,19 @@
>   #include<linux/version.h>
>   #include<linux/timer.h>
>   #include<media/videobuf2-dma-contig.h>
> -
> -static int find_reg_callback(struct device *dev, void *p)
> -{
> -	struct v4l2_subdev **sd = p;
> -
> -	*sd = dev_get_drvdata(dev);
> -	/* non-zero value stops iteration */
> -	return 1;
> -}
> -
> -static struct v4l2_subdev *find_and_register_subdev(
> -	struct mxr_device *mdev, char *module_name)
> -{
> -	struct device_driver *drv;
> -	struct v4l2_subdev *sd = NULL;
> -	int ret;
> -
> -	/* TODO: add waiting until probe is finished */
> -	drv = driver_find(module_name,&platform_bus_type);
> -	if (!drv) {
> -		mxr_warn(mdev, "module %s is missing\n", module_name);
> -		return NULL;
> -	}
> -	/* driver refcnt is increased, it is safe to iterate over devices */
> -	ret = driver_for_each_device(drv, NULL,&sd, find_reg_callback);
> -	/* ret == 0 means that find_reg_callback was never executed */
> -	if (sd == NULL) {
> -		mxr_warn(mdev, "module %s provides no subdev!\n", module_name);
> -		goto done;
> -	}
> -	/* v4l2_device_register_subdev detects if sd is NULL */
> -	ret = v4l2_device_register_subdev(&mdev->v4l2_dev, sd);
> -	if (ret) {
> -		mxr_warn(mdev, "failed to register subdev %s\n", sd->name);
> -		sd = NULL;
> -	}
> -
> -done:
> -	put_driver(drv);
> -	return sd;
> -}
> +#include<media/exynos_mc.h>
>
>   int __devinit mxr_acquire_video(struct mxr_device *mdev,
>   	struct mxr_output_conf *output_conf, int output_count)
>   {
> -	struct device *dev = mdev->dev;
> -	struct v4l2_device *v4l2_dev =&mdev->v4l2_dev;
>   	int i;
>   	int ret = 0;
>   	struct v4l2_subdev *sd;
>
> -	strlcpy(v4l2_dev->name, dev_name(mdev->dev), sizeof(v4l2_dev->name));
> -	/* prepare context for V4L2 device */
> -	ret = v4l2_device_register(dev, v4l2_dev);
> -	if (ret) {
> -		mxr_err(mdev, "could not register v4l2 device.\n");
> -		goto fail;
> -	}
> -
>   	mdev->alloc_ctx = vb2_dma_contig_init_ctx(mdev->dev);
>   	if (IS_ERR_OR_NULL(mdev->alloc_ctx)) {
>   		mxr_err(mdev, "could not acquire vb2 allocator\n");
> -		goto fail_v4l2_dev;
> +		goto fail;
>   	}
>
>   	/* registering outputs */
> @@ -91,7 +41,9 @@ int __devinit mxr_acquire_video(struct mxr_device *mdev,
>   		struct mxr_output_conf *conf =&output_conf[i];
>   		struct mxr_output *out;
>
> -		sd = find_and_register_subdev(mdev, conf->module_name);
> +		/* find subdev of output devices */
> +		sd = (struct v4l2_subdev *)
> +			module_name_to_driver_data(conf->module_name);
>   		/* trying to register next output */
>   		if (sd == NULL)
>   			continue;
> @@ -133,10 +85,6 @@ fail_vb2_allocator:
>   	/* freeing allocator context */
>   	vb2_dma_contig_cleanup_ctx(mdev->alloc_ctx);
>
> -fail_v4l2_dev:
> -	/* NOTE: automatically unregister all subdevs */
> -	v4l2_device_unregister(v4l2_dev);
> -
>   fail:
>   	return ret;
>   }
> @@ -153,6 +101,28 @@ void __devexit mxr_release_video(struct mxr_device *mdev)
>   	v4l2_device_unregister(&mdev->v4l2_dev);
>   }
>
> +static void tv_graph_pipeline_stream(struct tv_graph_pipeline *pipe, int on)
> +{
> +	struct mxr_device *mdev = pipe->layer->mdev;
> +	struct media_entity *me =&pipe->layer->vfd.entity;
> +	/* source pad of graphic layer entity */
> +	struct media_pad *pad =&me->pads[0];
> +	struct v4l2_subdev *sd;
> +
> +	mxr_dbg(mdev, "%s TV graphic layer pipeline\n", on ? "start" : "stop");
> +
> +	/* find remote pad through enabled link */
> +	pad = media_entity_remote_source(pad);
> +	if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV
> +			|| pad == NULL)
> +		mxr_warn(mdev, "cannot find remote pad\n");
> +
> +	sd = media_entity_to_v4l2_subdev(pad->entity);
> +	mxr_dbg(mdev, "s_stream of %s sub-device is called\n", sd->name);
> +
> +	v4l2_subdev_call(sd, video, s_stream, on);
> +}
> +
>   static int mxr_querycap(struct file *file, void *priv,
>   	struct v4l2_capability *cap)
>   {
> @@ -869,12 +839,21 @@ static void buf_queue(struct vb2_buffer *vb)
>   	struct mxr_buffer *buffer = container_of(vb, struct mxr_buffer, vb);
>   	struct mxr_layer *layer = vb2_get_drv_priv(vb->vb2_queue);
>   	struct mxr_device *mdev = layer->mdev;
> +	struct tv_graph_pipeline *pipe =&layer->pipe;
>   	unsigned long flags;
>
>   	spin_lock_irqsave(&layer->enq_slock, flags);
>   	list_add_tail(&buffer->list,&layer->enq_list);
>   	spin_unlock_irqrestore(&layer->enq_slock, flags);
>
> +	if (layer->state == MXR_LAYER_STREAMING) {
> +		layer->ops.stream_set(layer, MXR_ENABLE);
> +		/* store starting entity ptr on the tv graphic pipeline */
> +		pipe->layer = layer;
> +		/* start streaming all entities on the tv graphic pipeline */
> +		tv_graph_pipeline_stream(pipe, 1);
> +	}
> +
>   	mxr_dbg(mdev, "queuing buffer\n");
>   }
>
> @@ -917,9 +896,6 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
>   	layer->state = MXR_LAYER_STREAMING;
>   	spin_unlock_irqrestore(&layer->enq_slock, flags);
>
> -	layer->ops.stream_set(layer, MXR_ENABLE);
> -	mxr_streamer_get(mdev);
> -
>   	return 0;
>   }
>
> @@ -953,6 +929,7 @@ static int stop_streaming(struct vb2_queue *vq)
>   	unsigned long flags;
>   	struct timer_list watchdog;
>   	struct mxr_buffer *buf, *buf_tmp;
> +	struct tv_graph_pipeline *pipe =&layer->pipe;
>
>   	mxr_dbg(mdev, "%s\n", __func__);
>
> @@ -988,8 +965,12 @@ static int stop_streaming(struct vb2_queue *vq)
>
>   	/* disabling layer in hardware */
>   	layer->ops.stream_set(layer, MXR_DISABLE);
> -	/* remove one streamer */
> -	mxr_streamer_put(mdev);
> +
> +	/* starting entity on the pipeline */
> +	pipe->layer = layer;
> +	/* stop streaming all entities on the pipeline */
> +	tv_graph_pipeline_stream(pipe, 0);
> +
>   	/* allow changes in output configuration */
>   	mxr_output_put(mdev);
>   	return 0;
> @@ -1008,8 +989,16 @@ static struct vb2_ops mxr_video_qops = {
>   int mxr_base_layer_register(struct mxr_layer *layer)
>   {
>   	struct mxr_device *mdev = layer->mdev;
> +	struct exynos_md *md;
>   	int ret;
>
> +	md = (struct exynos_md *)module_name_to_driver_data(MDEV_MODULE_NAME);
> +	if (!md) {
> +		mxr_err(mdev, "failed to get output media device\n");
> +		return -ENODEV;
> +	}
> +
> +	layer->vfd.v4l2_dev =&md->v4l2_dev;
>   	ret = video_register_device(&layer->vfd, VFL_TYPE_GRABBER, -1);
>   	if (ret)
>   		mxr_err(mdev, "failed to register video device\n");
> @@ -1044,6 +1033,7 @@ struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
>   	int idx, char *name, struct mxr_layer_ops *ops)
>   {
>   	struct mxr_layer *layer;
> +	int ret;
>
>   	layer = kzalloc(sizeof *layer, GFP_KERNEL);
>   	if (layer == NULL) {
> @@ -1065,13 +1055,21 @@ struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
>   		.fops =&mxr_fops,
>   		.ioctl_ops =&mxr_ioctl_ops,
>   	};
> +
> +	ret = media_entity_init(&layer->vfd.entity, 1,&layer->vd_pad, 0);
> +	if (ret) {
> +		mxr_err(mdev, "failed to initialize media entity\n");
> +		goto fail_alloc;
> +	}
> +
>   	strlcpy(layer->vfd.name, name, sizeof(layer->vfd.name));
> +	layer->vfd.entity.name = layer->vfd.name;
> +
>   	/* let framework control PRIORITY */
>   	set_bit(V4L2_FL_USE_FH_PRIO,&layer->vfd.flags);
>
>   	video_set_drvdata(&layer->vfd, layer);
>   	layer->vfd.lock =&layer->mutex;
> -	layer->vfd.v4l2_dev =&mdev->v4l2_dev;
>
>   	layer->vb_queue = (struct vb2_queue) {
>   		.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
> @@ -1084,6 +1082,9 @@ struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
>
>   	return layer;
>
> +fail_alloc:
> +	kfree(layer);
> +
>   fail:
>   	return NULL;
>   }
> diff --git a/drivers/media/video/s5p-tv/sdo_drv.c b/drivers/media/video/s5p-tv/sdo_drv.c
> index 059e774..df3ebe0 100644
> --- a/drivers/media/video/s5p-tv/sdo_drv.c
> +++ b/drivers/media/video/s5p-tv/sdo_drv.c
> @@ -24,6 +24,7 @@
>   #include<linux/slab.h>
>
>   #include<media/v4l2-subdev.h>
> +#include<media/exynos_mc.h>
>
>   #include "regs-sdo.h"
>
> @@ -32,6 +33,10 @@ MODULE_DESCRIPTION("Samsung Standard Definition Output (SDO)");
>   MODULE_LICENSE("GPL");
>
>   #define SDO_DEFAULT_STD	V4L2_STD_PAL
> +/* sink pad number of sdo subdev */
> +#define SDO_PAD_SINK	0
> +/* number of sdo subdev pads */
> +#define SDO_PADS_NUM	1
>
>   struct sdo_format {
>   	v4l2_std_id id;
> @@ -61,6 +66,8 @@ struct sdo_device {
>   	struct regulator *vdet;
>   	/** subdev used as device interface */
>   	struct v4l2_subdev sd;
> +	/** sink pad of sdo subdev */
> +	struct media_pad pad;
>   	/** current format */
>   	const struct sdo_format *fmt;
>   };
> @@ -292,6 +299,63 @@ static const struct dev_pm_ops sdo_pm_ops = {
>   	.runtime_resume	 = sdo_runtime_resume,
>   };
>
> +static int sdo_link_setup(struct media_entity *entity,
> +			      const struct media_pad *local,
> +			      const struct media_pad *remote, u32 flags)
> +{
> +	return 0;
> +}
> +
> +/* sdo entity operations */
> +static const struct media_entity_operations sdo_entity_ops = {
> +	.link_setup = sdo_link_setup,
> +};
> +
> +static int sdo_register_entity(struct sdo_device *sdev)
> +{
> +	struct v4l2_subdev *sd =&sdev->sd;
> +	struct media_pad *pad =&sdev->pad;
> +	struct media_entity *me =&sd->entity;
> +	struct device *dev = sdev->dev;
> +	struct exynos_md *md;
> +	int ret;
> +
> +	dev_dbg(dev, "SDO entity init\n");
> +
why code below is moved? (similar to hdmi)
> +	/* init sdo subdev */
> +	v4l2_subdev_init(sd,&sdo_sd_ops);
> +	sd->owner = THIS_MODULE;
> +	strlcpy(sd->name, "sdo-sd", sizeof(sd->name));
> +
> +	dev_set_drvdata(dev, sd);
> +
> +	/* init sdo sub-device as entity */
> +	pad[SDO_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
> +	me->ops =&sdo_entity_ops;
> +	ret = media_entity_init(me, SDO_PADS_NUM, pad, 0);
> +	if (ret) {
> +		dev_err(dev, "failed to initialize media entity\n");
> +		return ret;
> +	}
> +
> +	/* get output media ptr for registering sdo's sd */
> +	md = (struct exynos_md *)module_name_to_driver_data(MDEV_MODULE_NAME);

Please update dependence in Kconfig.

> +	if (!md) {
> +		dev_err(dev, "failed to get output media device\n");
> +		return -ENODEV;
> +	}
> +
> +	/* regiser SDO subdev as entity to v4l2_dev pointer of
> +	 * output media device */
> +	ret = v4l2_device_register_subdev(&md->v4l2_dev, sd);
> +	if (ret) {
> +		dev_err(dev, "failed to register SDO subdev\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
>   static int __devinit sdo_probe(struct platform_device *pdev)
>   {
>   	struct device *dev =&pdev->dev;
> @@ -390,17 +454,14 @@ static int __devinit sdo_probe(struct platform_device *pdev)
>   	/* configure power management */
>   	pm_runtime_enable(dev);
>
> -	/* configuration of interface subdevice */
> -	v4l2_subdev_init(&sdev->sd,&sdo_sd_ops);
> -	sdev->sd.owner = THIS_MODULE;
> -	strlcpy(sdev->sd.name, "s5p-sdo", sizeof sdev->sd.name);
> -
>   	/* set default format */
>   	sdev->fmt = sdo_find_format(SDO_DEFAULT_STD);
>   	BUG_ON(sdev->fmt == NULL);
>
> -	/* keeping subdev in device's private for use by other drivers */
> -	dev_set_drvdata(dev,&sdev->sd);
> +	/* register sdo subdev as entity */
> +	ret = sdo_register_entity(sdev);
> +	if (ret)
> +		goto fail_vdac;
>
>   	dev_info(dev, "probe succeeded\n");
>   	return 0;

Regardds,
Tomasz Stanislawski
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[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