|
@@ -172,6 +172,139 @@ static int __vsp1_video_try_format(struct vsp1_video *video,
|
|
* Pipeline Management
|
|
* Pipeline Management
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * vsp1_video_complete_buffer - Complete the current buffer
|
|
|
|
+ * @video: the video node
|
|
|
|
+ *
|
|
|
|
+ * This function completes the current buffer by filling its sequence number,
|
|
|
|
+ * time stamp and payload size, and hands it back to the videobuf core.
|
|
|
|
+ *
|
|
|
|
+ * When operating in DU output mode (deep pipeline to the DU through the LIF),
|
|
|
|
+ * the VSP1 needs to constantly supply frames to the display. In that case, if
|
|
|
|
+ * no other buffer is queued, reuse the one that has just been processed instead
|
|
|
|
+ * of handing it back to the videobuf core.
|
|
|
|
+ *
|
|
|
|
+ * Return the next queued buffer or NULL if the queue is empty.
|
|
|
|
+ */
|
|
|
|
+static struct vsp1_vb2_buffer *
|
|
|
|
+vsp1_video_complete_buffer(struct vsp1_video *video)
|
|
|
|
+{
|
|
|
|
+ struct vsp1_pipeline *pipe = video->rwpf->pipe;
|
|
|
|
+ struct vsp1_vb2_buffer *next = NULL;
|
|
|
|
+ struct vsp1_vb2_buffer *done;
|
|
|
|
+ unsigned long flags;
|
|
|
|
+ unsigned int i;
|
|
|
|
+
|
|
|
|
+ spin_lock_irqsave(&video->irqlock, flags);
|
|
|
|
+
|
|
|
|
+ if (list_empty(&video->irqqueue)) {
|
|
|
|
+ spin_unlock_irqrestore(&video->irqlock, flags);
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ done = list_first_entry(&video->irqqueue,
|
|
|
|
+ struct vsp1_vb2_buffer, queue);
|
|
|
|
+
|
|
|
|
+ /* In DU output mode reuse the buffer if the list is singular. */
|
|
|
|
+ if (pipe->lif && list_is_singular(&video->irqqueue)) {
|
|
|
|
+ spin_unlock_irqrestore(&video->irqlock, flags);
|
|
|
|
+ return done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ list_del(&done->queue);
|
|
|
|
+
|
|
|
|
+ if (!list_empty(&video->irqqueue))
|
|
|
|
+ next = list_first_entry(&video->irqqueue,
|
|
|
|
+ struct vsp1_vb2_buffer, queue);
|
|
|
|
+
|
|
|
|
+ spin_unlock_irqrestore(&video->irqlock, flags);
|
|
|
|
+
|
|
|
|
+ done->buf.sequence = video->sequence++;
|
|
|
|
+ done->buf.vb2_buf.timestamp = ktime_get_ns();
|
|
|
|
+ for (i = 0; i < done->buf.vb2_buf.num_planes; ++i)
|
|
|
|
+ vb2_set_plane_payload(&done->buf.vb2_buf, i,
|
|
|
|
+ vb2_plane_size(&done->buf.vb2_buf, i));
|
|
|
|
+ vb2_buffer_done(&done->buf.vb2_buf, VB2_BUF_STATE_DONE);
|
|
|
|
+
|
|
|
|
+ return next;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void vsp1_video_frame_end(struct vsp1_pipeline *pipe,
|
|
|
|
+ struct vsp1_rwpf *rwpf)
|
|
|
|
+{
|
|
|
|
+ struct vsp1_video *video = rwpf->video;
|
|
|
|
+ struct vsp1_vb2_buffer *buf;
|
|
|
|
+ unsigned long flags;
|
|
|
|
+
|
|
|
|
+ buf = vsp1_video_complete_buffer(video);
|
|
|
|
+ if (buf == NULL)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ spin_lock_irqsave(&pipe->irqlock, flags);
|
|
|
|
+
|
|
|
|
+ video->rwpf->mem = buf->mem;
|
|
|
|
+ pipe->buffers_ready |= 1 << video->pipe_index;
|
|
|
|
+
|
|
|
|
+ spin_unlock_irqrestore(&pipe->irqlock, flags);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe)
|
|
|
|
+{
|
|
|
|
+ struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
|
|
|
|
+ unsigned int i;
|
|
|
|
+
|
|
|
|
+ if (!pipe->dl)
|
|
|
|
+ pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < vsp1->info->rpf_count; ++i) {
|
|
|
|
+ struct vsp1_rwpf *rwpf = pipe->inputs[i];
|
|
|
|
+
|
|
|
|
+ if (rwpf)
|
|
|
|
+ vsp1_rwpf_set_memory(rwpf, pipe->dl);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!pipe->lif)
|
|
|
|
+ vsp1_rwpf_set_memory(pipe->output, pipe->dl);
|
|
|
|
+
|
|
|
|
+ vsp1_dl_list_commit(pipe->dl);
|
|
|
|
+ pipe->dl = NULL;
|
|
|
|
+
|
|
|
|
+ vsp1_pipeline_run(pipe);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe)
|
|
|
|
+{
|
|
|
|
+ struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
|
|
|
|
+ enum vsp1_pipeline_state state;
|
|
|
|
+ unsigned long flags;
|
|
|
|
+ unsigned int i;
|
|
|
|
+
|
|
|
|
+ /* Complete buffers on all video nodes. */
|
|
|
|
+ for (i = 0; i < vsp1->info->rpf_count; ++i) {
|
|
|
|
+ if (!pipe->inputs[i])
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ vsp1_video_frame_end(pipe, pipe->inputs[i]);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ vsp1_video_frame_end(pipe, pipe->output);
|
|
|
|
+
|
|
|
|
+ spin_lock_irqsave(&pipe->irqlock, flags);
|
|
|
|
+
|
|
|
|
+ state = pipe->state;
|
|
|
|
+ pipe->state = VSP1_PIPELINE_STOPPED;
|
|
|
|
+
|
|
|
|
+ /* If a stop has been requested, mark the pipeline as stopped and
|
|
|
|
+ * return. Otherwise restart the pipeline if ready.
|
|
|
|
+ */
|
|
|
|
+ if (state == VSP1_PIPELINE_STOPPING)
|
|
|
|
+ wake_up(&pipe->wq);
|
|
|
|
+ else if (vsp1_pipeline_ready(pipe))
|
|
|
|
+ vsp1_video_pipeline_run(pipe);
|
|
|
|
+
|
|
|
|
+ spin_unlock_irqrestore(&pipe->irqlock, flags);
|
|
|
|
+}
|
|
|
|
+
|
|
static int vsp1_video_pipeline_build_branch(struct vsp1_pipeline *pipe,
|
|
static int vsp1_video_pipeline_build_branch(struct vsp1_pipeline *pipe,
|
|
struct vsp1_rwpf *input,
|
|
struct vsp1_rwpf *input,
|
|
struct vsp1_rwpf *output)
|
|
struct vsp1_rwpf *output)
|
|
@@ -369,139 +502,6 @@ static void vsp1_video_pipeline_cleanup(struct vsp1_pipeline *pipe)
|
|
mutex_unlock(&pipe->lock);
|
|
mutex_unlock(&pipe->lock);
|
|
}
|
|
}
|
|
|
|
|
|
-/*
|
|
|
|
- * vsp1_video_complete_buffer - Complete the current buffer
|
|
|
|
- * @video: the video node
|
|
|
|
- *
|
|
|
|
- * This function completes the current buffer by filling its sequence number,
|
|
|
|
- * time stamp and payload size, and hands it back to the videobuf core.
|
|
|
|
- *
|
|
|
|
- * When operating in DU output mode (deep pipeline to the DU through the LIF),
|
|
|
|
- * the VSP1 needs to constantly supply frames to the display. In that case, if
|
|
|
|
- * no other buffer is queued, reuse the one that has just been processed instead
|
|
|
|
- * of handing it back to the videobuf core.
|
|
|
|
- *
|
|
|
|
- * Return the next queued buffer or NULL if the queue is empty.
|
|
|
|
- */
|
|
|
|
-static struct vsp1_vb2_buffer *
|
|
|
|
-vsp1_video_complete_buffer(struct vsp1_video *video)
|
|
|
|
-{
|
|
|
|
- struct vsp1_pipeline *pipe = video->rwpf->pipe;
|
|
|
|
- struct vsp1_vb2_buffer *next = NULL;
|
|
|
|
- struct vsp1_vb2_buffer *done;
|
|
|
|
- unsigned long flags;
|
|
|
|
- unsigned int i;
|
|
|
|
-
|
|
|
|
- spin_lock_irqsave(&video->irqlock, flags);
|
|
|
|
-
|
|
|
|
- if (list_empty(&video->irqqueue)) {
|
|
|
|
- spin_unlock_irqrestore(&video->irqlock, flags);
|
|
|
|
- return NULL;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- done = list_first_entry(&video->irqqueue,
|
|
|
|
- struct vsp1_vb2_buffer, queue);
|
|
|
|
-
|
|
|
|
- /* In DU output mode reuse the buffer if the list is singular. */
|
|
|
|
- if (pipe->lif && list_is_singular(&video->irqqueue)) {
|
|
|
|
- spin_unlock_irqrestore(&video->irqlock, flags);
|
|
|
|
- return done;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- list_del(&done->queue);
|
|
|
|
-
|
|
|
|
- if (!list_empty(&video->irqqueue))
|
|
|
|
- next = list_first_entry(&video->irqqueue,
|
|
|
|
- struct vsp1_vb2_buffer, queue);
|
|
|
|
-
|
|
|
|
- spin_unlock_irqrestore(&video->irqlock, flags);
|
|
|
|
-
|
|
|
|
- done->buf.sequence = video->sequence++;
|
|
|
|
- done->buf.vb2_buf.timestamp = ktime_get_ns();
|
|
|
|
- for (i = 0; i < done->buf.vb2_buf.num_planes; ++i)
|
|
|
|
- vb2_set_plane_payload(&done->buf.vb2_buf, i,
|
|
|
|
- vb2_plane_size(&done->buf.vb2_buf, i));
|
|
|
|
- vb2_buffer_done(&done->buf.vb2_buf, VB2_BUF_STATE_DONE);
|
|
|
|
-
|
|
|
|
- return next;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void vsp1_video_frame_end(struct vsp1_pipeline *pipe,
|
|
|
|
- struct vsp1_rwpf *rwpf)
|
|
|
|
-{
|
|
|
|
- struct vsp1_video *video = rwpf->video;
|
|
|
|
- struct vsp1_vb2_buffer *buf;
|
|
|
|
- unsigned long flags;
|
|
|
|
-
|
|
|
|
- buf = vsp1_video_complete_buffer(video);
|
|
|
|
- if (buf == NULL)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- spin_lock_irqsave(&pipe->irqlock, flags);
|
|
|
|
-
|
|
|
|
- video->rwpf->mem = buf->mem;
|
|
|
|
- pipe->buffers_ready |= 1 << video->pipe_index;
|
|
|
|
-
|
|
|
|
- spin_unlock_irqrestore(&pipe->irqlock, flags);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe)
|
|
|
|
-{
|
|
|
|
- struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
|
|
|
|
- unsigned int i;
|
|
|
|
-
|
|
|
|
- if (!pipe->dl)
|
|
|
|
- pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
|
|
|
|
-
|
|
|
|
- for (i = 0; i < vsp1->info->rpf_count; ++i) {
|
|
|
|
- struct vsp1_rwpf *rwpf = pipe->inputs[i];
|
|
|
|
-
|
|
|
|
- if (rwpf)
|
|
|
|
- vsp1_rwpf_set_memory(rwpf, pipe->dl);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (!pipe->lif)
|
|
|
|
- vsp1_rwpf_set_memory(pipe->output, pipe->dl);
|
|
|
|
-
|
|
|
|
- vsp1_dl_list_commit(pipe->dl);
|
|
|
|
- pipe->dl = NULL;
|
|
|
|
-
|
|
|
|
- vsp1_pipeline_run(pipe);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe)
|
|
|
|
-{
|
|
|
|
- struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
|
|
|
|
- enum vsp1_pipeline_state state;
|
|
|
|
- unsigned long flags;
|
|
|
|
- unsigned int i;
|
|
|
|
-
|
|
|
|
- /* Complete buffers on all video nodes. */
|
|
|
|
- for (i = 0; i < vsp1->info->rpf_count; ++i) {
|
|
|
|
- if (!pipe->inputs[i])
|
|
|
|
- continue;
|
|
|
|
-
|
|
|
|
- vsp1_video_frame_end(pipe, pipe->inputs[i]);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- vsp1_video_frame_end(pipe, pipe->output);
|
|
|
|
-
|
|
|
|
- spin_lock_irqsave(&pipe->irqlock, flags);
|
|
|
|
-
|
|
|
|
- state = pipe->state;
|
|
|
|
- pipe->state = VSP1_PIPELINE_STOPPED;
|
|
|
|
-
|
|
|
|
- /* If a stop has been requested, mark the pipeline as stopped and
|
|
|
|
- * return. Otherwise restart the pipeline if ready.
|
|
|
|
- */
|
|
|
|
- if (state == VSP1_PIPELINE_STOPPING)
|
|
|
|
- wake_up(&pipe->wq);
|
|
|
|
- else if (vsp1_pipeline_ready(pipe))
|
|
|
|
- vsp1_video_pipeline_run(pipe);
|
|
|
|
-
|
|
|
|
- spin_unlock_irqrestore(&pipe->irqlock, flags);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
/* -----------------------------------------------------------------------------
|
|
* videobuf2 Queue Operations
|
|
* videobuf2 Queue Operations
|
|
*/
|
|
*/
|