コード例 #1
0
ファイル: ispvideo.c プロジェクト: AK101111/linux
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;
}
コード例 #2
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);
    }
}
コード例 #3
0
/*
 * 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);
}
コード例 #4
0
ファイル: ispcsi2.c プロジェクト: Sangil-Lee/ZynqFPGA
/*
 * 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");
}
コード例 #5
0
/*
 * 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;
}
コード例 #6
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);
	}
}
コード例 #7
0
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);
}
コード例 #8
0
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);
}
コード例 #9
0
ファイル: ispstat.c プロジェクト: Astralix/mainline-dss11
/*
 * __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);
}
コード例 #10
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);
}
コード例 #11
0
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);
}
コード例 #12
0
/*
 * 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;
}
コード例 #13
0
ファイル: ispcsi2.c プロジェクト: 020gzh/linux
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;
}