These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / media / platform / vsp1 / vsp1_video.c
index d91f19a..b4f8cd7 100644 (file)
@@ -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);
 }