Commit 875e2e3e authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab
Browse files

[media] omap3isp: Mark next captured frame as faulty when an SBL overflow occurs



Instead of trying to propagate errors down the pipeline manually (and
failing to do so properly in all cases), flag SBL errors in the pipeline
to which the entity that triggered the error belongs, and use pipeline
error flags to mark buffers as faulty when completing them.

Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent c3cd2574
Loading
Loading
Loading
Loading
+29 −24
Original line number Diff line number Diff line
@@ -410,6 +410,7 @@ static inline void isp_isr_dbg(struct isp_device *isp, u32 irqstatus)
static void isp_isr_sbl(struct isp_device *isp)
{
	struct device *dev = isp->dev;
	struct isp_pipeline *pipe;
	u32 sbl_pcr;

	/*
@@ -423,27 +424,38 @@ static void isp_isr_sbl(struct isp_device *isp)
	if (sbl_pcr)
		dev_dbg(dev, "SBL overflow (PCR = 0x%08x)\n", sbl_pcr);

	if (sbl_pcr & (ISPSBL_PCR_CCDC_WBL_OVF | ISPSBL_PCR_CSIA_WBL_OVF
		     | ISPSBL_PCR_CSIB_WBL_OVF)) {
		isp->isp_ccdc.error = 1;
		if (isp->isp_ccdc.output & CCDC_OUTPUT_PREVIEW)
			isp->isp_prev.error = 1;
		if (isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER)
			isp->isp_res.error = 1;
	if (sbl_pcr & ISPSBL_PCR_CSIB_WBL_OVF) {
		pipe = to_isp_pipeline(&isp->isp_ccp2.subdev.entity);
		if (pipe != NULL)
			pipe->error = true;
	}

	if (sbl_pcr & ISPSBL_PCR_CSIA_WBL_OVF) {
		pipe = to_isp_pipeline(&isp->isp_csi2a.subdev.entity);
		if (pipe != NULL)
			pipe->error = true;
	}

	if (sbl_pcr & ISPSBL_PCR_CCDC_WBL_OVF) {
		pipe = to_isp_pipeline(&isp->isp_ccdc.subdev.entity);
		if (pipe != NULL)
			pipe->error = true;
	}

	if (sbl_pcr & ISPSBL_PCR_PRV_WBL_OVF) {
		isp->isp_prev.error = 1;
		if (isp->isp_res.input == RESIZER_INPUT_VP &&
		    !(isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER))
			isp->isp_res.error = 1;
		pipe = to_isp_pipeline(&isp->isp_prev.subdev.entity);
		if (pipe != NULL)
			pipe->error = true;
	}

	if (sbl_pcr & (ISPSBL_PCR_RSZ1_WBL_OVF
		       | ISPSBL_PCR_RSZ2_WBL_OVF
		       | ISPSBL_PCR_RSZ3_WBL_OVF
		       | ISPSBL_PCR_RSZ4_WBL_OVF))
		isp->isp_res.error = 1;
		       | ISPSBL_PCR_RSZ4_WBL_OVF)) {
		pipe = to_isp_pipeline(&isp->isp_res.subdev.entity);
		if (pipe != NULL)
			pipe->error = true;
	}

	if (sbl_pcr & ISPSBL_PCR_H3A_AF_WBL_OVF)
		omap3isp_stat_sbl_overflow(&isp->isp_af);
@@ -471,24 +483,17 @@ static irqreturn_t isp_isr(int irq, void *_isp)
				       IRQ0STATUS_HS_VS_IRQ;
	struct isp_device *isp = _isp;
	u32 irqstatus;
	int ret;

	irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
	isp_reg_writel(isp, irqstatus, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);

	isp_isr_sbl(isp);

	if (irqstatus & IRQ0STATUS_CSIA_IRQ) {
		ret = omap3isp_csi2_isr(&isp->isp_csi2a);
		if (ret)
			isp->isp_ccdc.error = 1;
	}
	if (irqstatus & IRQ0STATUS_CSIA_IRQ)
		omap3isp_csi2_isr(&isp->isp_csi2a);

	if (irqstatus & IRQ0STATUS_CSIB_IRQ) {
		ret = omap3isp_ccp2_isr(&isp->isp_ccp2);
		if (ret)
			isp->isp_ccdc.error = 1;
	}
	if (irqstatus & IRQ0STATUS_CSIB_IRQ)
		omap3isp_ccp2_isr(&isp->isp_ccp2);

	if (irqstatus & IRQ0STATUS_CCDC_VD0_IRQ) {
		if (isp->isp_ccdc.output & CCDC_OUTPUT_PREVIEW)
+5 −4
Original line number Diff line number Diff line
@@ -1427,8 +1427,11 @@ static void ccdc_lsc_isr(struct isp_ccdc_device *ccdc, u32 events)
	unsigned long flags;

	if (events & IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ) {
		struct isp_pipeline *pipe =
			to_isp_pipeline(&ccdc->subdev.entity);

		ccdc_lsc_error_handler(ccdc);
		ccdc->error = 1;
		pipe->error = true;
		dev_dbg(to_device(ccdc), "lsc prefetch error\n");
	}

@@ -1503,7 +1506,7 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
		goto done;
	}

	buffer = omap3isp_video_buffer_next(&ccdc->video_out, ccdc->error);
	buffer = omap3isp_video_buffer_next(&ccdc->video_out);
	if (buffer != NULL) {
		ccdc_set_outaddr(ccdc, buffer->isp_addr);
		restart = 1;
@@ -1517,7 +1520,6 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
					ISP_PIPELINE_STREAM_SINGLESHOT);

done:
	ccdc->error = 0;
	return restart;
}

@@ -1743,7 +1745,6 @@ static int ccdc_set_stream(struct v4l2_subdev *sd, int enable)
		 */
		ccdc_config_vp(ccdc);
		ccdc_enable_vp(ccdc, 1);
		ccdc->error = 0;
		ccdc_print_status(ccdc);
	}

+0 −2
Original line number Diff line number Diff line
@@ -150,7 +150,6 @@ struct ispccdc_lsc {
 * @input: Active input
 * @output: Active outputs
 * @video_out: Output video node
 * @error: A hardware error occurred during capture
 * @alaw: A-law compression enabled (1) or disabled (0)
 * @lpf: Low pass filter enabled (1) or disabled (0)
 * @obclamp: Optical-black clamp enabled (1) or disabled (0)
@@ -178,7 +177,6 @@ struct isp_ccdc_device {
	enum ccdc_input_entity input;
	unsigned int output;
	struct isp_video video_out;
	unsigned int error;

	unsigned int alaw:1,
		     lpf:1,
+7 −15
Original line number Diff line number Diff line
@@ -556,7 +556,7 @@ static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2)
	struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity);
	struct isp_buffer *buffer;

	buffer = omap3isp_video_buffer_next(&ccp2->video_in, ccp2->error);
	buffer = omap3isp_video_buffer_next(&ccp2->video_in);
	if (buffer != NULL)
		ccp2_set_inaddr(ccp2, buffer->isp_addr);

@@ -567,8 +567,6 @@ static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2)
			omap3isp_pipeline_set_stream(pipe,
						ISP_PIPELINE_STREAM_SINGLESHOT);
	}

	ccp2->error = 0;
}

/*
@@ -576,13 +574,11 @@ static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2)
 * @ccp2: Pointer to ISP CCP2 device
 *
 * This will handle the CCP2 interrupts
 *
 * Returns -EIO in case of error, or 0 on success.
 */
int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2)
void omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2)
{
	struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity);
	struct isp_device *isp = to_isp_device(ccp2);
	int ret = 0;
	static const u32 ISPCCP2_LC01_ERROR =
		ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ |
		ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ |
@@ -604,19 +600,18 @@ int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2)
		       ISPCCP2_LCM_IRQSTATUS);
	/* Errors */
	if (lcx_irqstatus & ISPCCP2_LC01_ERROR) {
		ccp2->error = 1;
		pipe->error = true;
		dev_dbg(isp->dev, "CCP2 err:%x\n", lcx_irqstatus);
		return -EIO;
		return;
	}

	if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ) {
		ccp2->error = 1;
		pipe->error = true;
		dev_dbg(isp->dev, "CCP2 OCP err:%x\n", lcm_irqstatus);
		ret = -EIO;
	}

	if (omap3isp_module_sync_is_stopping(&ccp2->wait, &ccp2->stopping))
		return 0;
		return;

	/* Frame number propagation */
	if (lcx_irqstatus & ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ) {
@@ -629,8 +624,6 @@ int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2)
	/* Handle queued buffers on frame end interrupts */
	if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_EOF_IRQ)
		ccp2_isr_buffer(ccp2);

	return ret;
}

/* -----------------------------------------------------------------------------
@@ -867,7 +860,6 @@ static int ccp2_s_stream(struct v4l2_subdev *sd, int enable)
		if (enable == ISP_PIPELINE_STREAM_STOPPED)
			return 0;
		atomic_set(&ccp2->stopping, 0);
		ccp2->error = 0;
	}

	switch (enable) {
+1 −2
Original line number Diff line number Diff line
@@ -82,7 +82,6 @@ struct isp_ccp2_device {
	struct isp_video video_in;
	struct isp_csiphy *phy;
	struct regulator *vdds_csib;
	unsigned int error;
	enum isp_pipeline_stream_state state;
	wait_queue_head_t wait;
	atomic_t stopping;
@@ -94,6 +93,6 @@ void omap3isp_ccp2_cleanup(struct isp_device *isp);
int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2,
			struct v4l2_device *vdev);
void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2);
int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2);
void omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2);

#endif	/* OMAP3_ISP_CCP2_H */
Loading