static int isp_video_start_streaming(struct vb2_queue *queue, unsigned int count) { struct isp_video_fh *vfh = vb2_get_drv_priv(queue); struct isp_video *video = vfh->video; struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity); unsigned long flags; int ret; /* In sensor-to-memory mode, the stream can be started synchronously * to the stream on command. In memory-to-memory mode, it will be * started when buffers are queued on both the input and output. */ if (pipe->input) return 0; ret = omap3isp_pipeline_set_stream(pipe, ISP_PIPELINE_STREAM_CONTINUOUS); if (ret < 0) { spin_lock_irqsave(&video->irqlock, flags); omap3isp_video_return_buffers(video, VB2_BUF_STATE_QUEUED); spin_unlock_irqrestore(&video->irqlock, flags); return ret; } spin_lock_irqsave(&video->irqlock, flags); if (list_empty(&video->dmaqueue)) video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN; spin_unlock_irqrestore(&video->irqlock, flags); 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); } }
/* * ispccp2_if_enable - Enable CCP2 interface. * @ccp2: pointer to ISP CCP2 device * @enable: enable/disable flag */ static void ispccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable) { struct isp_device *isp = to_isp_device(ccp2); struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); int i; if (enable && ccp2->vdds_csib) regulator_enable(ccp2->vdds_csib); /* Enable/Disable all the LCx channels */ for (i = 0; i < CCP2_LCx_CHANS_NUM; i++) isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(i), ISPCCP2_LCx_CTRL_CHAN_EN, enable ? ISPCCP2_LCx_CTRL_CHAN_EN : 0); /* Enable/Disable ccp2 interface in ccp2 mode */ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL, ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN, enable ? (ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN) : 0); /* For frame count propagation */ if (pipe->do_propagation) { /* We may want the Frame Start IRQ from LC0 */ if (enable) isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQENABLE, ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ); else isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQENABLE, ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ); } if (!enable && ccp2->vdds_csib) regulator_disable(ccp2->vdds_csib); }
/* * omap3isp_csi2_isr - CSI2 interrupt handling. */ void omap3isp_csi2_isr(struct isp_csi2_device *csi2) { struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); u32 csi2_irqstatus, cpxio1_irqstatus; struct isp_device *isp = csi2->isp; if (!csi2->available) return; csi2_irqstatus = isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQSTATUS); isp_reg_writel(isp, csi2_irqstatus, csi2->regs1, ISPCSI2_IRQSTATUS); /* Failure Cases */ if (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ) { cpxio1_irqstatus = isp_reg_readl(isp, csi2->regs1, ISPCSI2_PHY_IRQSTATUS); isp_reg_writel(isp, cpxio1_irqstatus, csi2->regs1, ISPCSI2_PHY_IRQSTATUS); dev_dbg(isp->dev, "CSI2: ComplexIO Error IRQ " "%x\n", cpxio1_irqstatus); pipe->error = true; } if (csi2_irqstatus & (ISPCSI2_IRQSTATUS_OCP_ERR_IRQ | ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ | ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ | ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ | ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ)) { dev_dbg(isp->dev, "CSI2 Err:" " OCP:%d," " Short_pack:%d," " ECC:%d," " CPXIO2:%d," " FIFO_OVF:%d," "\n", (csi2_irqstatus & ISPCSI2_IRQSTATUS_OCP_ERR_IRQ) ? 1 : 0, (csi2_irqstatus & ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ) ? 1 : 0, (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ) ? 1 : 0, (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ) ? 1 : 0, (csi2_irqstatus & ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ) ? 1 : 0); pipe->error = true; } if (omap3isp_module_sync_is_stopping(&csi2->wait, &csi2->stopping)) return; /* Successful cases */ if (csi2_irqstatus & ISPCSI2_IRQSTATUS_CONTEXT(0)) csi2_isr_ctx(csi2, &csi2->contexts[0]); if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ) dev_dbg(isp->dev, "CSI2: ECC correction done\n"); }
/* * csi2_set_stream - Enable/Disable streaming on the CSI2 module * @sd: ISP CSI2 V4L2 subdevice * @enable: ISP pipeline stream state * * Return 0 on success or a negative error code otherwise. */ static int csi2_set_stream(struct v4l2_subdev *sd, int enable) { struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); struct isp_device *isp = csi2->isp; struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); struct isp_video *video_out = &csi2->video_out; switch (enable) { case ISP_PIPELINE_STREAM_CONTINUOUS: if (isp_csiphy_acquire(csi2->phy) < 0) return -ENODEV; csi2->use_fs_irq = pipe->do_propagation; if (csi2->output & CSI2_OUTPUT_MEMORY) isp_sbl_enable(isp, OMAP3_ISP_SBL_CSI2A_WRITE); isp_csi2_configure(csi2); isp_csi2_print_status(csi2); /* * When outputting to memory with no buffer available, let the * buffer queue handler start the hardware. A DMA queue flag * ISP_VIDEO_DMAQUEUE_QUEUED will be set as soon as there is * a buffer available. */ if (csi2->output & CSI2_OUTPUT_MEMORY && !(video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED)) break; /* Enable context 0 and IRQs */ atomic_set(&csi2->stopping, 0); isp_csi2_ctx_enable(isp, csi2, 0, 1); isp_csi2_if_enable(isp, csi2, 1); isp_video_dmaqueue_flags_clr(video_out); break; case ISP_PIPELINE_STREAM_STOPPED: if (csi2->state == ISP_PIPELINE_STREAM_STOPPED) return 0; if (isp_module_sync_idle(&sd->entity, &csi2->wait, &csi2->stopping)) dev_dbg(isp->dev, "%s: module stop timeout.\n", sd->name); isp_csi2_ctx_enable(isp, csi2, 0, 0); isp_csi2_if_enable(isp, csi2, 0); isp_csi2_irq_ctx_set(isp, csi2, 0); isp_csiphy_release(csi2->phy); isp_video_dmaqueue_flags_clr(video_out); isp_sbl_disable(isp, OMAP3_ISP_SBL_CSI2A_WRITE); break; } csi2->state = enable; 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 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 void isp_csi2_isr_ctx(struct isp_csi2_device *csi2, struct isp_csi2_ctx_cfg *ctx) { struct isp_device *isp = csi2->isp; unsigned int n = ctx->ctxnum; u32 status; status = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n)); isp_reg_writel(isp, status, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n)); /* Propagate frame number */ if (status & ISPCSI2_CTX_IRQSTATUS_FS_IRQ) { struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); if (pipe->do_propagation) atomic_inc(&pipe->frame_number); } if (!(status & ISPCSI2_CTX_IRQSTATUS_FE_IRQ)) return; /* Skip interrupts until we reach the frame skip count. The CSI2 will be * automatically disabled, as the frame skip count has been programmed * in the CSI2_CTx_CTRL1::COUNT field, so reenable it. * * It would have been nice to rely on the FRAME_NUMBER interrupt instead * but it turned out that the interrupt is only generated when the CSI2 * writes to memory (the CSI2_CTx_CTRL1::COUNT field is decreased * correctly and reaches 0 when data is forwarded to the video port only * but no interrupt arrives). Maybe a CSI2 hardware bug. */ if (csi2->frame_skip) { csi2->frame_skip--; if (csi2->frame_skip == 0) { ctx->format_id = isp_csi2_ctx_map_format(csi2); isp_csi2_ctx_config(isp, csi2, ctx); isp_csi2_ctx_enable(isp, csi2, n, 1); } return; } if (csi2->output & CSI2_OUTPUT_MEMORY) isp_csi2_isr_buffer(csi2); }
static void ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable) { struct isp_device *isp = to_isp_device(ccp2); struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); int i; if (enable && ccp2->vdds_csib) regulator_enable(ccp2->vdds_csib); for (i = 0; i < CCP2_LCx_CHANS_NUM; i++) isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(i), ISPCCP2_LCx_CTRL_CHAN_EN, enable ? ISPCCP2_LCx_CTRL_CHAN_EN : 0); isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL, ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN, enable ? (ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN) : 0); if (pipe->do_propagation) { if (enable) isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQENABLE, ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ); else isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQENABLE, ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ); } if (!enable && ccp2->vdds_csib) regulator_disable(ccp2->vdds_csib); }
/* * __stat_isr - Interrupt handler for statistic drivers */ static void __stat_isr(struct ispstat *stat, int from_dma) { int ret = STAT_BUF_DONE; int buf_processing; unsigned long irqflags; struct isp_pipeline *pipe; /* * stat->buf_processing must be set before disable module. It's * necessary to not inform too early the buffers aren't busy in case * of SDMA is going to be used. */ spin_lock_irqsave(&stat->isp->stat_lock, irqflags); if (stat->state == ISPSTAT_DISABLED) { spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); return; } buf_processing = stat->buf_processing; stat->buf_processing = 1; stat->ops->enable(stat, 0); if (buf_processing && !from_dma) { if (stat->state == ISPSTAT_ENABLED) { spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); dev_err(stat->isp->dev, "%s: interrupt occurred when module was still " "processing a buffer.\n", stat->subdev.name); ret = STAT_NO_BUF; goto out; } else { /* * Interrupt handler was called from streamoff when * the module wasn't busy anymore to ensure it is being * disabled after process last buffer. If such buffer * processing has already started, no need to do * anything else. */ spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); return; } } spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); /* If it's busy we can't process this buffer anymore */ if (!omap3isp_stat_pcr_busy(stat)) { if (!from_dma && stat->ops->buf_process) /* Module still need to copy data to buffer. */ ret = stat->ops->buf_process(stat); if (ret == STAT_BUF_WAITING_DMA) /* Buffer is not ready yet */ return; spin_lock_irqsave(&stat->isp->stat_lock, irqflags); /* * Histogram needs to read its internal memory to clear it * before be disabled. For that reason, common statistic layer * can return only after call stat's buf_process() operator. */ if (stat->state == ISPSTAT_DISABLING) { stat->state = ISPSTAT_DISABLED; spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); stat->buf_processing = 0; return; } pipe = to_isp_pipeline(&stat->subdev.entity); stat->frame_number = atomic_read(&pipe->frame_number); /* * Before this point, 'ret' stores the buffer's status if it's * ready to be processed. Afterwards, it holds the status if * it was processed successfully. */ ret = isp_stat_buf_process(stat, ret); if (likely(!stat->sbl_ovl_recover)) { stat->ops->setup_regs(stat, stat->priv); } else { /* * Using recover config to increase the chance to have * a good buffer processing and make the H3A module to * go back to a valid state. */ stat->update = 1; stat->ops->setup_regs(stat, stat->recover_priv); stat->sbl_ovl_recover = 0; /* * Set 'update' in case of the module needs to use * regular configuration after next buffer. */ stat->update = 1; } isp_stat_buf_insert_magic(stat, stat->active_buf); /* * Hack: H3A modules may access invalid memory address or send * corrupted data to userspace if more than 1 SBL overflow * happens in a row without re-writing its buffer's start memory * address in the meantime. Such situation is avoided if the * module is not immediately re-enabled when the ISR misses the * timing to process the buffer and to setup the registers. * Because of that, pcr_enable(1) was moved to inside this 'if' * block. But the next interruption will still happen as during * pcr_enable(0) the module was busy. */ isp_stat_pcr_enable(stat, 1); spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); } else { /* * If a SBL overflow occurs and the H3A driver misses the timing * to process the buffer, stat->buf_err is set and won't be * cleared now. So the next buffer will be correctly ignored. * It's necessary due to a hw issue which makes the next H3A * buffer to start from the memory address where the previous * one stopped, instead of start where it was configured to. * Do not "stat->buf_err = 0" here. */ if (stat->ops->buf_process) /* * Driver may need to erase current data prior to * process a new buffer. If it misses the timing, the * next buffer might be wrong. So should be ignored. * It happens only for Histogram. */ atomic_set(&stat->buf_err, 1); ret = STAT_NO_BUF; dev_dbg(stat->isp->dev, "%s: cannot process buffer, " "device is busy.\n", stat->subdev.name); } out: stat->buf_processing = 0; isp_stat_queue_event(stat, ret != STAT_BUF_DONE); }
/* * 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); }
static void __stat_isr(struct ispstat *stat, int from_dma) { int ret = STAT_BUF_DONE; int buf_processing; unsigned long irqflags; struct isp_pipeline *pipe; spin_lock_irqsave(&stat->isp->stat_lock, irqflags); if (stat->state == ISPSTAT_DISABLED) { spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); return; } buf_processing = stat->buf_processing; stat->buf_processing = 1; stat->ops->enable(stat, 0); if (buf_processing && !from_dma) { if (stat->state == ISPSTAT_ENABLED) { spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); dev_err(stat->isp->dev, "%s: interrupt occurred when module was still " "processing a buffer.\n", stat->subdev.name); ret = STAT_NO_BUF; goto out; } else { spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); return; } } spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); if (!omap3isp_stat_pcr_busy(stat)) { if (!from_dma && stat->ops->buf_process) ret = stat->ops->buf_process(stat); if (ret == STAT_BUF_WAITING_DMA) return; spin_lock_irqsave(&stat->isp->stat_lock, irqflags); if (stat->state == ISPSTAT_DISABLING) { stat->state = ISPSTAT_DISABLED; spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); stat->buf_processing = 0; return; } pipe = to_isp_pipeline(&stat->subdev.entity); stat->frame_number = atomic_read(&pipe->frame_number); ret = isp_stat_buf_process(stat, ret); if (likely(!stat->sbl_ovl_recover)) { stat->ops->setup_regs(stat, stat->priv); } else { stat->update = 1; stat->ops->setup_regs(stat, stat->recover_priv); stat->sbl_ovl_recover = 0; stat->update = 1; } isp_stat_buf_insert_magic(stat, stat->active_buf); isp_stat_pcr_enable(stat, 1); spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); } else { if (stat->ops->buf_process) atomic_set(&stat->buf_err, 1); ret = STAT_NO_BUF; dev_dbg(stat->isp->dev, "%s: cannot process buffer, " "device is busy.\n", stat->subdev.name); } out: stat->buf_processing = 0; isp_stat_queue_event(stat, ret != STAT_BUF_DONE); }
/* * omap3isp_video_buffer_next - Complete the current buffer and return the next * @video: ISP video object * * Remove the current video buffer from the DMA queue and fill its timestamp and * field count before handing it back to videobuf2. * * For capture video nodes the buffer state is set to VB2_BUF_STATE_DONE if no * error has been flagged in the pipeline, or to VB2_BUF_STATE_ERROR otherwise. * For video output nodes the buffer state is always set to VB2_BUF_STATE_DONE. * * 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) { struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity); enum isp_pipeline_state state; struct isp_buffer *buf; unsigned long flags; spin_lock_irqsave(&video->irqlock, flags); if (WARN_ON(list_empty(&video->dmaqueue))) { spin_unlock_irqrestore(&video->irqlock, flags); return NULL; } buf = list_first_entry(&video->dmaqueue, struct isp_buffer, irqlist); list_del(&buf->irqlist); spin_unlock_irqrestore(&video->irqlock, flags); v4l2_get_timestamp(&buf->vb.timestamp); /* 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->vb.sequence = atomic_inc_return(&pipe->frame_number); else buf->vb.sequence = atomic_read(&pipe->frame_number); if (pipe->field != V4L2_FIELD_NONE) buf->vb.sequence /= 2; buf->vb.field = pipe->field; /* Report pipeline errors to userspace on the capture device side. */ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->error) { state = VB2_BUF_STATE_ERROR; pipe->error = false; } else { state = VB2_BUF_STATE_DONE; } vb2_buffer_done(&buf->vb.vb2_buf, state); spin_lock_irqsave(&video->irqlock, flags); if (list_empty(&video->dmaqueue)) { spin_unlock_irqrestore(&video->irqlock, flags); if (video->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 (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->input != NULL) { spin_lock(&pipe->lock); pipe->state &= ~ISP_PIPELINE_STREAM; spin_unlock(&pipe->lock); } buf = list_first_entry(&video->dmaqueue, struct isp_buffer, irqlist); spin_unlock_irqrestore(&video->irqlock, flags); return buf; }
static int csi2_configure(struct isp_csi2_device *csi2) { struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); const struct isp_bus_cfg *buscfg; struct isp_device *isp = csi2->isp; struct isp_csi2_timing_cfg *timing = &csi2->timing[0]; struct v4l2_subdev *sensor; struct media_pad *pad; /* * CSI2 fields that can be updated while the context has * been enabled or the interface has been enabled are not * updated dynamically currently. So we do not allow to * reconfigure if either has been enabled */ if (csi2->contexts[0].enabled || csi2->ctrl.if_enable) return -EBUSY; pad = media_entity_remote_pad(&csi2->pads[CSI2_PAD_SINK]); sensor = media_entity_to_v4l2_subdev(pad->entity); buscfg = sensor->host_priv; csi2->frame_skip = 0; v4l2_subdev_call(sensor, sensor, g_skip_frames, &csi2->frame_skip); csi2->ctrl.vp_out_ctrl = clamp_t(unsigned int, pipe->l3_ick / pipe->external_rate - 1, 1, 3); dev_dbg(isp->dev, "%s: l3_ick %lu, external_rate %u, vp_out_ctrl %u\n", __func__, pipe->l3_ick, pipe->external_rate, csi2->ctrl.vp_out_ctrl); csi2->ctrl.frame_mode = ISP_CSI2_FRAME_IMMEDIATE; csi2->ctrl.ecc_enable = buscfg->bus.csi2.crc; timing->ionum = 1; timing->force_rx_mode = 1; timing->stop_state_16x = 1; timing->stop_state_4x = 1; timing->stop_state_counter = 0x1FF; /* * The CSI2 receiver can't do any format conversion except DPCM * decompression, so every set_format call configures both pads * and enables DPCM decompression as a special case: */ if (csi2->formats[CSI2_PAD_SINK].code != csi2->formats[CSI2_PAD_SOURCE].code) csi2->dpcm_decompress = true; else csi2->dpcm_decompress = false; csi2->contexts[0].format_id = csi2_ctx_map_format(csi2); if (csi2->video_out.bpl_padding == 0) csi2->contexts[0].data_offset = 0; else csi2->contexts[0].data_offset = csi2->video_out.bpl_value; /* * Enable end of frame and end of line signals generation for * context 0. These signals are generated from CSI2 receiver to * qualify the last pixel of a frame and the last pixel of a line. * Without enabling the signals CSI2 receiver writes data to memory * beyond buffer size and/or data line offset is not handled correctly. */ csi2->contexts[0].eof_enabled = 1; csi2->contexts[0].eol_enabled = 1; csi2_irq_complexio1_set(isp, csi2, 1); csi2_irq_ctx_set(isp, csi2, 1); csi2_irq_status_set(isp, csi2, 1); /* Set configuration (timings, format and links) */ csi2_timing_config(isp, csi2, timing); csi2_recv_config(isp, csi2, &csi2->ctrl); csi2_ctx_config(isp, csi2, &csi2->contexts[0]); return 0; }