diff options
Diffstat (limited to 'kernel/drivers/media/platform/vsp1/vsp1_video.c')
-rw-r--r-- | kernel/drivers/media/platform/vsp1/vsp1_video.c | 108 |
1 files changed, 95 insertions, 13 deletions
diff --git a/kernel/drivers/media/platform/vsp1/vsp1_video.c b/kernel/drivers/media/platform/vsp1/vsp1_video.c index d91f19a9e..b4f8cd74e 100644 --- a/kernel/drivers/media/platform/vsp1/vsp1_video.c +++ b/kernel/drivers/media/platform/vsp1/vsp1_video.c @@ -1,7 +1,7 @@ /* * vsp1_video.c -- R-Car VSP1 Video Node * - * Copyright (C) 2013-2014 Renesas Electronics Corporation + * Copyright (C) 2013-2015 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * @@ -24,7 +24,7 @@ #include <media/v4l2-fh.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-subdev.h> -#include <media/videobuf2-core.h> +#include <media/videobuf2-v4l2.h> #include <media/videobuf2-dma-contig.h> #include "vsp1.h" @@ -245,7 +245,7 @@ static int __vsp1_video_try_format(struct vsp1_video *video, * the datasheet, strides not aligned to a multiple of 128 bytes result * in image corruption. */ - for (i = 0; i < max(info->planes, 2U); ++i) { + for (i = 0; i < min(info->planes, 2U); ++i) { unsigned int hsub = i > 0 ? info->hsub : 1; unsigned int vsub = i > 0 ? info->vsub : 1; unsigned int align = 128; @@ -514,6 +514,18 @@ static void vsp1_pipeline_run(struct vsp1_pipeline *pipe) pipe->buffers_ready = 0; } +static bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe) +{ + unsigned long flags; + bool stopped; + + spin_lock_irqsave(&pipe->irqlock, flags); + stopped = pipe->state == VSP1_PIPELINE_STOPPED; + spin_unlock_irqrestore(&pipe->irqlock, flags); + + return stopped; +} + static int vsp1_pipeline_stop(struct vsp1_pipeline *pipe) { struct vsp1_entity *entity; @@ -525,7 +537,7 @@ static int vsp1_pipeline_stop(struct vsp1_pipeline *pipe) pipe->state = VSP1_PIPELINE_STOPPING; spin_unlock_irqrestore(&pipe->irqlock, flags); - ret = wait_event_timeout(pipe->wq, pipe->state == VSP1_PIPELINE_STOPPED, + ret = wait_event_timeout(pipe->wq, vsp1_pipeline_stopped(pipe), msecs_to_jiffies(500)); ret = ret == 0 ? -ETIMEDOUT : 0; @@ -598,11 +610,11 @@ vsp1_video_complete_buffer(struct vsp1_video *video) spin_unlock_irqrestore(&video->irqlock, flags); - done->buf.v4l2_buf.sequence = video->sequence++; - v4l2_get_timestamp(&done->buf.v4l2_buf.timestamp); - for (i = 0; i < done->buf.num_planes; ++i) - vb2_set_plane_payload(&done->buf, i, done->length[i]); - vb2_buffer_done(&done->buf, VB2_BUF_STATE_DONE); + done->buf.sequence = video->sequence++; + v4l2_get_timestamp(&done->buf.timestamp); + for (i = 0; i < done->buf.vb2_buf.num_planes; ++i) + vb2_set_plane_payload(&done->buf.vb2_buf, i, done->length[i]); + vb2_buffer_done(&done->buf.vb2_buf, VB2_BUF_STATE_DONE); return next; } @@ -703,15 +715,83 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, } } +void vsp1_pipelines_suspend(struct vsp1_device *vsp1) +{ + unsigned long flags; + unsigned int i; + int ret; + + /* To avoid increasing the system suspend time needlessly, loop over the + * pipelines twice, first to set them all to the stopping state, and then + * to wait for the stop to complete. + */ + for (i = 0; i < vsp1->pdata.wpf_count; ++i) { + struct vsp1_rwpf *wpf = vsp1->wpf[i]; + struct vsp1_pipeline *pipe; + + if (wpf == NULL) + continue; + + pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); + if (pipe == NULL) + continue; + + spin_lock_irqsave(&pipe->irqlock, flags); + if (pipe->state == VSP1_PIPELINE_RUNNING) + pipe->state = VSP1_PIPELINE_STOPPING; + spin_unlock_irqrestore(&pipe->irqlock, flags); + } + + for (i = 0; i < vsp1->pdata.wpf_count; ++i) { + struct vsp1_rwpf *wpf = vsp1->wpf[i]; + struct vsp1_pipeline *pipe; + + if (wpf == NULL) + continue; + + pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); + if (pipe == NULL) + continue; + + ret = wait_event_timeout(pipe->wq, vsp1_pipeline_stopped(pipe), + msecs_to_jiffies(500)); + if (ret == 0) + dev_warn(vsp1->dev, "pipeline %u stop timeout\n", + wpf->entity.index); + } +} + +void vsp1_pipelines_resume(struct vsp1_device *vsp1) +{ + unsigned int i; + + /* Resume pipeline all running pipelines. */ + for (i = 0; i < vsp1->pdata.wpf_count; ++i) { + struct vsp1_rwpf *wpf = vsp1->wpf[i]; + struct vsp1_pipeline *pipe; + + if (wpf == NULL) + continue; + + pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); + if (pipe == NULL) + continue; + + if (vsp1_pipeline_ready(pipe)) + vsp1_pipeline_run(pipe); + } +} + /* ----------------------------------------------------------------------------- * videobuf2 Queue Operations */ static int -vsp1_video_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, +vsp1_video_queue_setup(struct vb2_queue *vq, const void *parg, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { + const struct v4l2_format *fmt = parg; struct vsp1_video *video = vb2_get_drv_priv(vq); const struct v4l2_pix_format_mplane *format; struct v4l2_pix_format_mplane pix_mp; @@ -741,8 +821,9 @@ vsp1_video_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, static int vsp1_video_buffer_prepare(struct vb2_buffer *vb) { + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct vsp1_video *video = vb2_get_drv_priv(vb->vb2_queue); - struct vsp1_video_buffer *buf = to_vsp1_video_buffer(vb); + struct vsp1_video_buffer *buf = to_vsp1_video_buffer(vbuf); const struct v4l2_pix_format_mplane *format = &video->format; unsigned int i; @@ -762,9 +843,10 @@ static int vsp1_video_buffer_prepare(struct vb2_buffer *vb) static void vsp1_video_buffer_queue(struct vb2_buffer *vb) { + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct vsp1_video *video = vb2_get_drv_priv(vb->vb2_queue); struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity); - struct vsp1_video_buffer *buf = to_vsp1_video_buffer(vb); + struct vsp1_video_buffer *buf = to_vsp1_video_buffer(vbuf); unsigned long flags; bool empty; @@ -875,7 +957,7 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq) /* Remove all buffers from the IRQ queue. */ spin_lock_irqsave(&video->irqlock, flags); list_for_each_entry(buffer, &video->irqqueue, queue) - vb2_buffer_done(&buffer->buf, VB2_BUF_STATE_ERROR); + vb2_buffer_done(&buffer->buf.vb2_buf, VB2_BUF_STATE_ERROR); INIT_LIST_HEAD(&video->irqqueue); spin_unlock_irqrestore(&video->irqlock, flags); } |