static int isp_video_buffer_prepare(struct vb2_buffer *buf) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(buf); struct isp_video_fh *vfh = vb2_get_drv_priv(buf->vb2_queue); struct isp_buffer *buffer = to_isp_buffer(vbuf); struct isp_video *video = vfh->video; dma_addr_t addr; /* Refuse to prepare the buffer is the video node has registered an * error. We don't need to take any lock here as the operation is * inherently racy. The authoritative check will be performed in the * queue handler, which can't return an error, this check is just a best * effort to notify userspace as early as possible. */ if (unlikely(video->error)) return -EIO; addr = vb2_dma_contig_plane_dma_addr(buf, 0); if (!IS_ALIGNED(addr, 32)) { dev_dbg(video->isp->dev, "Buffer address must be aligned to 32 bytes boundary.\n"); return -EINVAL; } vb2_set_plane_payload(&buffer->vb.vb2_buf, 0, vfh->format.fmt.pix.sizeimage); buffer->dma = addr; return 0; }
/* * isp_video_buffer_queue - Add buffer to streaming queue * @buf: Video buffer * * In memory-to-memory mode, start streaming on the pipeline if buffers are * queued on both the input and the output, if the pipeline isn't already busy. * If the pipeline is busy, it will be restarted in the output module interrupt * handler. */ static void isp_video_buffer_queue(struct isp_video_buffer *buf) { struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue); struct isp_buffer *buffer = to_isp_buffer(buf); struct isp_video *video = vfh->video; struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity); enum isp_pipeline_state state; unsigned long flags; unsigned int empty; unsigned int start; empty = list_empty(&video->dmaqueue); list_add_tail(&buffer->buffer.irqlist, &video->dmaqueue); if (empty) { if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) state = ISP_PIPELINE_QUEUE_OUTPUT; else state = ISP_PIPELINE_QUEUE_INPUT; spin_lock_irqsave(&pipe->lock, flags); pipe->state |= state; video->ops->queue(video, buffer); video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_QUEUED; start = isp_pipeline_ready(pipe); if (start) pipe->state |= ISP_PIPELINE_STREAM; spin_unlock_irqrestore(&pipe->lock, flags); if (start) omap3isp_pipeline_set_stream(pipe, ISP_PIPELINE_STREAM_SINGLESHOT); } }
static int isp_video_buffer_prepare(struct isp_video_buffer *buf) { struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue); struct isp_buffer *buffer = to_isp_buffer(buf); struct isp_video *video = vfh->video; unsigned long addr; /* Refuse to prepare the buffer is the video node has registered an * error. We don't need to take any lock here as the operation is * inherently racy. The authoritative check will be performed in the * queue handler, which can't return an error, this check is just a best * effort to notify userspace as early as possible. */ if (unlikely(video->error)) return -EIO; addr = ispmmu_vmap(video->isp, buf->sglist, buf->sglen); if (IS_ERR_VALUE(addr)) return -EIO; if (!IS_ALIGNED(addr, 32)) { dev_dbg(video->isp->dev, "Buffer address must be " "aligned to 32 bytes boundary.\n"); ispmmu_vunmap(video->isp, buffer->isp_addr); return -EINVAL; } buf->vbuf.bytesused = vfh->format.fmt.pix.sizeimage; buffer->isp_addr = addr; return 0; }
static void isp_video_buffer_cleanup(struct isp_video_buffer *buf) { struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue); struct isp_buffer *buffer = to_isp_buffer(buf); struct isp_video *video = vfh->video; if (buffer->isp_addr) { ispmmu_vunmap(video->isp, buffer->isp_addr); buffer->isp_addr = 0; } }
/* * isp_video_buffer_next - Complete the current buffer and return the next one * @video: ISP video object * @error: Whether an error occured during capture * * Remove the current video buffer from the DMA queue and fill its timestamp, * field count and state fields before waking up its completion handler. * * The buffer state is set to VIDEOBUF_DONE if no error occured (@error is 0) * or VIDEOBUF_ERROR otherwise (@error is non-zero). * * The DMA queue is expected to contain at least one buffer. * * Return a pointer to the next buffer in the DMA queue, or NULL if the queue is * empty. */ struct isp_buffer *isp_video_buffer_next(struct isp_video *video, unsigned int error) { struct isp_video_queue *queue = video->queue; enum isp_pipeline_state state; struct isp_video_buffer *buf; unsigned long flags; struct timespec ts; spin_lock_irqsave(&queue->irqlock, flags); BUG_ON(list_empty(&video->dmaqueue)); buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer, irqlist); list_del(&buf->irqlist); spin_unlock_irqrestore(&queue->irqlock, flags); ktime_get_ts(&ts); buf->vbuf.timestamp.tv_sec = ts.tv_sec; buf->vbuf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC; buf->vbuf.sequence = atomic_inc_return(&video->sequence); buf->state = error ? ISP_BUF_STATE_ERROR : ISP_BUF_STATE_DONE; wake_up(&buf->wait); if (list_empty(&video->dmaqueue)) { if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) state = ISP_PIPELINE_QUEUE_OUTPUT | ISP_PIPELINE_STREAM; else state = ISP_PIPELINE_QUEUE_INPUT | ISP_PIPELINE_STREAM; spin_lock_irqsave(&video->pipe->lock, flags); video->pipe->state &= ~state; spin_unlock_irqrestore(&video->pipe->lock, flags); return NULL; } if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && video->pipe->input != NULL) { spin_lock_irqsave(&video->pipe->lock, flags); video->pipe->state &= ~ISP_PIPELINE_STREAM; spin_unlock_irqrestore(&video->pipe->lock, flags); } buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer, irqlist); buf->state = ISP_BUF_STATE_ACTIVE; return to_isp_buffer(buf); }
/* * isp_video_buffer_queue - Add buffer to streaming queue * @buf: Video buffer * * In memory-to-memory mode, start streaming on the pipeline if buffers are * queued on both the input and the output, if the pipeline isn't already busy. * If the pipeline is busy, it will be restarted in the output module interrupt * handler. */ static void isp_video_buffer_queue(struct vb2_buffer *buf) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(buf); struct isp_video_fh *vfh = vb2_get_drv_priv(buf->vb2_queue); struct isp_buffer *buffer = to_isp_buffer(vbuf); struct isp_video *video = vfh->video; struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity); enum isp_pipeline_state state; unsigned long flags; unsigned int empty; unsigned int start; spin_lock_irqsave(&video->irqlock, flags); if (unlikely(video->error)) { vb2_buffer_done(&buffer->vb.vb2_buf, VB2_BUF_STATE_ERROR); spin_unlock_irqrestore(&video->irqlock, flags); return; } empty = list_empty(&video->dmaqueue); list_add_tail(&buffer->irqlist, &video->dmaqueue); spin_unlock_irqrestore(&video->irqlock, flags); if (empty) { if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) state = ISP_PIPELINE_QUEUE_OUTPUT; else state = ISP_PIPELINE_QUEUE_INPUT; spin_lock_irqsave(&pipe->lock, flags); pipe->state |= state; video->ops->queue(video, buffer); video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_QUEUED; start = isp_pipeline_ready(pipe); if (start) pipe->state |= ISP_PIPELINE_STREAM; spin_unlock_irqrestore(&pipe->lock, flags); if (start) omap3isp_pipeline_set_stream(pipe, ISP_PIPELINE_STREAM_SINGLESHOT); } }
static int isp_video_buffer_prepare(struct isp_video_buffer *buf) { struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue); struct isp_buffer *buffer = to_isp_buffer(buf); struct isp_video *video = vfh->video; unsigned long addr; addr = ispmmu_vmap(video->isp, buf->sglist, buf->sglen); if (IS_ERR_VALUE(addr)) return -EIO; if (!IS_ALIGNED(addr, 32)) { dev_dbg(video->isp->dev, "Buffer address must be " "aligned to 32 bytes boundary.\n"); ispmmu_vunmap(video->isp, buffer->isp_addr); return -EINVAL; } buf->vbuf.bytesused = vfh->format.fmt.pix.sizeimage; buffer->isp_addr = addr; return 0; }
/* * omap3isp_video_buffer_next - Complete the current buffer and return the next * @video: ISP video object * @error: Whether an error occurred during capture * * Remove the current video buffer from the DMA queue and fill its timestamp, * field count and state fields before waking up its completion handler. * * The buffer state is set to VIDEOBUF_DONE if no error occurred (@error is 0) * or VIDEOBUF_ERROR otherwise (@error is non-zero). * * The DMA queue is expected to contain at least one buffer. * * Return a pointer to the next buffer in the DMA queue, or NULL if the queue is * empty. */ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video, unsigned int error) { struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity); struct isp_video_queue *queue = video->queue; enum isp_pipeline_state state; struct isp_video_buffer *buf; unsigned long flags; struct timespec ts; spin_lock_irqsave(&queue->irqlock, flags); if (WARN_ON(list_empty(&video->dmaqueue))) { spin_unlock_irqrestore(&queue->irqlock, flags); return NULL; } buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer, irqlist); list_del(&buf->irqlist); spin_unlock_irqrestore(&queue->irqlock, flags); ktime_get_ts(&ts); buf->vbuf.timestamp.tv_sec = ts.tv_sec; buf->vbuf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC; /* Do frame number propagation only if this is the output video node. * Frame number either comes from the CSI receivers or it gets * incremented here if H3A is not active. * Note: There is no guarantee that the output buffer will finish * first, so the input number might lag behind by 1 in some cases. */ if (video == pipe->output && !pipe->do_propagation) buf->vbuf.sequence = atomic_inc_return(&pipe->frame_number); else buf->vbuf.sequence = atomic_read(&pipe->frame_number); buf->state = error ? ISP_BUF_STATE_ERROR : ISP_BUF_STATE_DONE; wake_up(&buf->wait); if (list_empty(&video->dmaqueue)) { if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) state = ISP_PIPELINE_QUEUE_OUTPUT | ISP_PIPELINE_STREAM; else state = ISP_PIPELINE_QUEUE_INPUT | ISP_PIPELINE_STREAM; spin_lock_irqsave(&pipe->lock, flags); pipe->state &= ~state; if (video->pipe.stream_state == ISP_PIPELINE_STREAM_CONTINUOUS) video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN; spin_unlock_irqrestore(&pipe->lock, flags); return NULL; } if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->input != NULL) { spin_lock_irqsave(&pipe->lock, flags); pipe->state &= ~ISP_PIPELINE_STREAM; spin_unlock_irqrestore(&pipe->lock, flags); } buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer, irqlist); buf->state = ISP_BUF_STATE_ACTIVE; return to_isp_buffer(buf); }