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

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

 



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|                | |       +-+---------+
                                                     | |                | |
                                                     +-+----------------+-+

* 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

* mxr-sd-blender
  sub-device type entity
  blender part of mixer

* hdmi-sd
  sub-device type entity
  hdmi tx

* 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");
+
+	/* 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);
+
+	/* 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);
+	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 = {
+};
+
+static int mxr_link_setup(struct media_entity *entity,
+			      const struct media_pad *local,
+			      const struct media_pad *remote, u32 flags)
+{
+	return 0;
+}
+
+/* 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);
+	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");
+
+	/* 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);
+	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;
-- 
1.7.1


--
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