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