Skip to content

Commit

Permalink
media: vimc: Add vimc-streamer for stream control
Browse files Browse the repository at this point in the history
Add a linear pipeline logic for the stream control. It's created by
walking backwards on the entity graph. When the stream starts it will
simply loop through the pipeline calling the respective process_frame
function of each entity.

Fixes: f2fe890 ("vimc: Virtual Media Controller core, capture
and sensor")

Cc: stable@vger.kernel.org # for v4.20
Signed-off-by: Lucas A. M. Magalhães <lucmaga@gmail.com>
Acked-by: Helen Koike <helen.koike@collabora.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
[hverkuil-cisco@xs4all.nl: fixed small space-after-tab issue in the patch]
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
  • Loading branch information
Lucas A. M. Magalhães authored and Mauro Carvalho Chehab committed Feb 7, 2019
1 parent 276c1f0 commit adc589d
Show file tree
Hide file tree
Showing 9 changed files with 260 additions and 147 deletions.
3 changes: 2 additions & 1 deletion drivers/media/platform/vimc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ vimc_common-objs := vimc-common.o
vimc_debayer-objs := vimc-debayer.o
vimc_scaler-objs := vimc-scaler.o
vimc_sensor-objs := vimc-sensor.o
vimc_streamer-objs := vimc-streamer.o

obj-$(CONFIG_VIDEO_VIMC) += vimc.o vimc_capture.o vimc_common.o vimc-debayer.o \
vimc_scaler.o vimc_sensor.o
vimc_scaler.o vimc_sensor.o vimc_streamer.o
18 changes: 9 additions & 9 deletions drivers/media/platform/vimc/vimc-capture.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <media/videobuf2-vmalloc.h>

#include "vimc-common.h"
#include "vimc-streamer.h"

#define VIMC_CAP_DRV_NAME "vimc-capture"

Expand All @@ -44,7 +45,7 @@ struct vimc_cap_device {
spinlock_t qlock;
struct mutex lock;
u32 sequence;
struct media_pipeline pipe;
struct vimc_stream stream;
};

static const struct v4l2_pix_format fmt_default = {
Expand Down Expand Up @@ -248,14 +249,13 @@ static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count)
vcap->sequence = 0;

/* Start the media pipeline */
ret = media_pipeline_start(entity, &vcap->pipe);
ret = media_pipeline_start(entity, &vcap->stream.pipe);
if (ret) {
vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED);
return ret;
}

/* Enable streaming from the pipe */
ret = vimc_pipeline_s_stream(&vcap->vdev.entity, 1);
ret = vimc_streamer_s_stream(&vcap->stream, &vcap->ved, 1);
if (ret) {
media_pipeline_stop(entity);
vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED);
Expand All @@ -273,8 +273,7 @@ static void vimc_cap_stop_streaming(struct vb2_queue *vq)
{
struct vimc_cap_device *vcap = vb2_get_drv_priv(vq);

/* Disable streaming from the pipe */
vimc_pipeline_s_stream(&vcap->vdev.entity, 0);
vimc_streamer_s_stream(&vcap->stream, &vcap->ved, 0);

/* Stop the media pipeline */
media_pipeline_stop(&vcap->vdev.entity);
Expand Down Expand Up @@ -355,8 +354,8 @@ static void vimc_cap_comp_unbind(struct device *comp, struct device *master,
kfree(vcap);
}

static void vimc_cap_process_frame(struct vimc_ent_device *ved,
struct media_pad *sink, const void *frame)
static void *vimc_cap_process_frame(struct vimc_ent_device *ved,
const void *frame)
{
struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device,
ved);
Expand All @@ -370,7 +369,7 @@ static void vimc_cap_process_frame(struct vimc_ent_device *ved,
typeof(*vimc_buf), list);
if (!vimc_buf) {
spin_unlock(&vcap->qlock);
return;
return ERR_PTR(-EAGAIN);
}

/* Remove this entry from the list */
Expand All @@ -391,6 +390,7 @@ static void vimc_cap_process_frame(struct vimc_ent_device *ved,
vb2_set_plane_payload(&vimc_buf->vb2.vb2_buf, 0,
vcap->format.sizeimage);
vb2_buffer_done(&vimc_buf->vb2.vb2_buf, VB2_BUF_STATE_DONE);
return NULL;
}

static int vimc_cap_comp_bind(struct device *comp, struct device *master,
Expand Down
35 changes: 0 additions & 35 deletions drivers/media/platform/vimc/vimc-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,41 +207,6 @@ const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat)
}
EXPORT_SYMBOL_GPL(vimc_pix_map_by_pixelformat);

int vimc_propagate_frame(struct media_pad *src, const void *frame)
{
struct media_link *link;

if (!(src->flags & MEDIA_PAD_FL_SOURCE))
return -EINVAL;

/* Send this frame to all sink pads that are direct linked */
list_for_each_entry(link, &src->entity->links, list) {
if (link->source == src &&
(link->flags & MEDIA_LNK_FL_ENABLED)) {
struct vimc_ent_device *ved = NULL;
struct media_entity *entity = link->sink->entity;

if (is_media_entity_v4l2_subdev(entity)) {
struct v4l2_subdev *sd =
container_of(entity, struct v4l2_subdev,
entity);
ved = v4l2_get_subdevdata(sd);
} else if (is_media_entity_v4l2_video_device(entity)) {
struct video_device *vdev =
container_of(entity,
struct video_device,
entity);
ved = video_get_drvdata(vdev);
}
if (ved && ved->process_frame)
ved->process_frame(ved, link->sink, frame);
}
}

return 0;
}
EXPORT_SYMBOL_GPL(vimc_propagate_frame);

/* Helper function to allocate and initialize pads */
struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag)
{
Expand Down
15 changes: 2 additions & 13 deletions drivers/media/platform/vimc/vimc-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,23 +115,12 @@ struct vimc_pix_map {
struct vimc_ent_device {
struct media_entity *ent;
struct media_pad *pads;
void (*process_frame)(struct vimc_ent_device *ved,
struct media_pad *sink, const void *frame);
void * (*process_frame)(struct vimc_ent_device *ved,
const void *frame);
void (*vdev_get_format)(struct vimc_ent_device *ved,
struct v4l2_pix_format *fmt);
};

/**
* vimc_propagate_frame - propagate a frame through the topology
*
* @src: the source pad where the frame is being originated
* @frame: the frame to be propagated
*
* This function will call the process_frame callback from the vimc_ent_device
* struct of the nodes directly connected to the @src pad
*/
int vimc_propagate_frame(struct media_pad *src, const void *frame);

/**
* vimc_pads_init - initialize pads
*
Expand Down
26 changes: 4 additions & 22 deletions drivers/media/platform/vimc/vimc-debayer.c
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,6 @@ static void vimc_deb_set_rgb_mbus_fmt_rgb888_1x24(struct vimc_deb_device *vdeb,
static int vimc_deb_s_stream(struct v4l2_subdev *sd, int enable)
{
struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
int ret;

if (enable) {
const struct vimc_pix_map *vpix;
Expand Down Expand Up @@ -351,22 +350,10 @@ static int vimc_deb_s_stream(struct v4l2_subdev *sd, int enable)
if (!vdeb->src_frame)
return -ENOMEM;

/* Turn the stream on in the subdevices directly connected */
ret = vimc_pipeline_s_stream(&vdeb->sd.entity, 1);
if (ret) {
vfree(vdeb->src_frame);
vdeb->src_frame = NULL;
return ret;
}
} else {
if (!vdeb->src_frame)
return 0;

/* Disable streaming from the pipe */
ret = vimc_pipeline_s_stream(&vdeb->sd.entity, 0);
if (ret)
return ret;

vfree(vdeb->src_frame);
vdeb->src_frame = NULL;
}
Expand Down Expand Up @@ -480,9 +467,8 @@ static void vimc_deb_calc_rgb_sink(struct vimc_deb_device *vdeb,
}
}

static void vimc_deb_process_frame(struct vimc_ent_device *ved,
struct media_pad *sink,
const void *sink_frame)
static void *vimc_deb_process_frame(struct vimc_ent_device *ved,
const void *sink_frame)
{
struct vimc_deb_device *vdeb = container_of(ved, struct vimc_deb_device,
ved);
Expand All @@ -491,20 +477,16 @@ static void vimc_deb_process_frame(struct vimc_ent_device *ved,

/* If the stream in this node is not active, just return */
if (!vdeb->src_frame)
return;
return ERR_PTR(-EINVAL);

for (i = 0; i < vdeb->sink_fmt.height; i++)
for (j = 0; j < vdeb->sink_fmt.width; j++) {
vimc_deb_calc_rgb_sink(vdeb, sink_frame, i, j, rgb);
vdeb->set_rgb_src(vdeb, i, j, rgb);
}

/* Propagate the frame through all source pads */
for (i = 1; i < vdeb->sd.entity.num_pads; i++) {
struct media_pad *pad = &vdeb->sd.entity.pads[i];
return vdeb->src_frame;

vimc_propagate_frame(pad, vdeb->src_frame);
}
}

static void vimc_deb_comp_unbind(struct device *comp, struct device *master,
Expand Down
28 changes: 4 additions & 24 deletions drivers/media/platform/vimc/vimc-scaler.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,6 @@ static const struct v4l2_subdev_pad_ops vimc_sca_pad_ops = {
static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable)
{
struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
int ret;

if (enable) {
const struct vimc_pix_map *vpix;
Expand Down Expand Up @@ -245,22 +244,10 @@ static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable)
if (!vsca->src_frame)
return -ENOMEM;

/* Turn the stream on in the subdevices directly connected */
ret = vimc_pipeline_s_stream(&vsca->sd.entity, 1);
if (ret) {
vfree(vsca->src_frame);
vsca->src_frame = NULL;
return ret;
}
} else {
if (!vsca->src_frame)
return 0;

/* Disable streaming from the pipe */
ret = vimc_pipeline_s_stream(&vsca->sd.entity, 0);
if (ret)
return ret;

vfree(vsca->src_frame);
vsca->src_frame = NULL;
}
Expand Down Expand Up @@ -346,26 +333,19 @@ static void vimc_sca_fill_src_frame(const struct vimc_sca_device *const vsca,
vimc_sca_scale_pix(vsca, i, j, sink_frame);
}

static void vimc_sca_process_frame(struct vimc_ent_device *ved,
struct media_pad *sink,
const void *sink_frame)
static void *vimc_sca_process_frame(struct vimc_ent_device *ved,
const void *sink_frame)
{
struct vimc_sca_device *vsca = container_of(ved, struct vimc_sca_device,
ved);
unsigned int i;

/* If the stream in this node is not active, just return */
if (!vsca->src_frame)
return;
return ERR_PTR(-EINVAL);

vimc_sca_fill_src_frame(vsca, sink_frame);

/* Propagate the frame through all source pads */
for (i = 1; i < vsca->sd.entity.num_pads; i++) {
struct media_pad *pad = &vsca->sd.entity.pads[i];

vimc_propagate_frame(pad, vsca->src_frame);
}
return vsca->src_frame;
};

static void vimc_sca_comp_unbind(struct device *comp, struct device *master,
Expand Down
56 changes: 13 additions & 43 deletions drivers/media/platform/vimc/vimc-sensor.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
*/

#include <linux/component.h>
#include <linux/freezer.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
Expand Down Expand Up @@ -201,38 +199,27 @@ static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = {
.set_fmt = vimc_sen_set_fmt,
};

static int vimc_sen_tpg_thread(void *data)
static void *vimc_sen_process_frame(struct vimc_ent_device *ved,
const void *sink_frame)
{
struct vimc_sen_device *vsen = data;
unsigned int i;

set_freezable();
set_current_state(TASK_UNINTERRUPTIBLE);

for (;;) {
try_to_freeze();
if (kthread_should_stop())
break;

tpg_fill_plane_buffer(&vsen->tpg, 0, 0, vsen->frame);
struct vimc_sen_device *vsen = container_of(ved, struct vimc_sen_device,
ved);
const struct vimc_pix_map *vpix;
unsigned int frame_size;

/* Send the frame to all source pads */
for (i = 0; i < vsen->sd.entity.num_pads; i++)
vimc_propagate_frame(&vsen->sd.entity.pads[i],
vsen->frame);
/* Calculate the frame size */
vpix = vimc_pix_map_by_code(vsen->mbus_format.code);
frame_size = vsen->mbus_format.width * vpix->bpp *
vsen->mbus_format.height;

/* 60 frames per second */
schedule_timeout(HZ/60);
}

return 0;
tpg_fill_plane_buffer(&vsen->tpg, 0, 0, vsen->frame);
return vsen->frame;
}

static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable)
{
struct vimc_sen_device *vsen =
container_of(sd, struct vimc_sen_device, sd);
int ret;

if (enable) {
const struct vimc_pix_map *vpix;
Expand All @@ -258,26 +245,8 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable)
/* configure the test pattern generator */
vimc_sen_tpg_s_format(vsen);

/* Initialize the image generator thread */
vsen->kthread_sen = kthread_run(vimc_sen_tpg_thread, vsen,
"%s-sen", vsen->sd.v4l2_dev->name);
if (IS_ERR(vsen->kthread_sen)) {
dev_err(vsen->dev, "%s: kernel_thread() failed\n",
vsen->sd.name);
vfree(vsen->frame);
vsen->frame = NULL;
return PTR_ERR(vsen->kthread_sen);
}
} else {
if (!vsen->kthread_sen)
return 0;

/* Stop image generator */
ret = kthread_stop(vsen->kthread_sen);
if (ret)
return ret;

vsen->kthread_sen = NULL;
vfree(vsen->frame);
vsen->frame = NULL;
return 0;
Expand Down Expand Up @@ -413,6 +382,7 @@ static int vimc_sen_comp_bind(struct device *comp, struct device *master,
if (ret)
goto err_free_hdl;

vsen->ved.process_frame = vimc_sen_process_frame;
dev_set_drvdata(comp, &vsen->ved);
vsen->dev = comp;

Expand Down
Loading

0 comments on commit adc589d

Please sign in to comment.