From: Jiun Yu <[email protected]>
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 <[email protected]>
---
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, <[email protected]>");
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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html