[2/3] omap3isp: Disable CCDC's VD0 and VD1 interrupts when stream is not enabled

Message ID 1426015494-16799-3-git-send-email-tim.nordell@logicpd.com (mailing list archive)
State New
Delegated to: Laurent Pinchart
Headers

Commit Message

Tim Nordell March 10, 2015, 7:24 p.m. UTC
  During testing there appeared to be a race condition where the IRQs
for VD0 and VD1 could be triggered while enabling the CCDC module
before the pipeline status was updated.  Simply modify the trigger
conditions for VD0 and VD1 so they won't occur when the CCDC module
is not enabled.

(When this occurred during testing, the VD0 interrupt was occurring
over and over again starving the rest of the system.)

Signed-off-by: Tim Nordell <tim.nordell@logicpd.com>
---
 drivers/media/platform/omap3isp/ispccdc.c | 25 ++++++++++++++++++-------
 1 file changed, 18 insertions(+), 7 deletions(-)
  

Comments

Laurent Pinchart March 18, 2015, 3:19 p.m. UTC | #1
Hi Tim,

Thank you for the patch.

On Tuesday 10 March 2015 14:24:53 Tim Nordell wrote:
> During testing there appeared to be a race condition where the IRQs
> for VD0 and VD1 could be triggered while enabling the CCDC module
> before the pipeline status was updated.  Simply modify the trigger
> conditions for VD0 and VD1 so they won't occur when the CCDC module
> is not enabled.
> 
> (When this occurred during testing, the VD0 interrupt was occurring
> over and over again starving the rest of the system.)

I'm curious, might this be caused by the input (adv7180 in your case) being 
enabled before the ISP ? The CCDC is very sensitive to any glitch in its input 
signals, you need to make sure that the source is disabled before its subdev 
s_stream operation is called. Given that the adv7180 driver doesn't implement 
s_stream, I expect it to be free-running, which is definitely a problem.

> Signed-off-by: Tim Nordell <tim.nordell@logicpd.com>
> ---
>  drivers/media/platform/omap3isp/ispccdc.c | 25 ++++++++++++++++++-------
>  1 file changed, 18 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/media/platform/omap3isp/ispccdc.c
> b/drivers/media/platform/omap3isp/ispccdc.c index 587489a..d5de843 100644
> --- a/drivers/media/platform/omap3isp/ispccdc.c
> +++ b/drivers/media/platform/omap3isp/ispccdc.c
> @@ -1218,13 +1218,6 @@ static void ccdc_configure(struct isp_ccdc_device
> *ccdc) }
>  	ccdc_config_imgattr(ccdc, ccdc_pattern);
> 
> -	/* Generate VD0 on the last line of the image and VD1 on the
> -	 * 2/3 height line.
> -	 */
> -	isp_reg_writel(isp, ((format->height - 2) << ISPCCDC_VDINT_0_SHIFT) |
> -		       ((format->height * 2 / 3) << ISPCCDC_VDINT_1_SHIFT),
> -		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT);
> -
>  	/* CCDC_PAD_SOURCE_OF */
>  	format = &ccdc->formats[CCDC_PAD_SOURCE_OF];
>  	crop = &ccdc->crop;
> @@ -1316,11 +1309,29 @@ unlock:
> 
>  static void __ccdc_enable(struct isp_ccdc_device *ccdc, int enable)
>  {
> +	struct v4l2_mbus_framefmt *format = &ccdc->formats[CCDC_PAD_SINK];
>  	struct isp_device *isp = to_isp_device(ccdc);
> +	int vd0, vd1;
> 
>  	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR,
>  			ISPCCDC_PCR_EN, enable ? ISPCCDC_PCR_EN : 0);
> 
> +	/* Generate VD0 on the last line of the image and VD1 on the
> +	* 2/3 height line when enabled.  Otherwise, set VD0 and VD1
> +	* interrupts high enough that they won't be generated.
> +	*/
> +	if (enable) {
> +		vd0 = format->height - 2;
> +		vd1 = format->height * 2 / 3;
> +	} else {
> +		vd0 = 0xffff;
> +		vd1 = 0xffff;
> +	}
> +
> +	isp_reg_writel(isp, (vd0 << ISPCCDC_VDINT_0_SHIFT) |
> +		(vd1 << ISPCCDC_VDINT_1_SHIFT),
> +		OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT);
> +
>  	ccdc->running = enable;
>  }
  
Tim Nordell March 18, 2015, 3:25 p.m. UTC | #2
Laurent -

On 03/18/15 10:19, Laurent Pinchart wrote:
> Hi Tim,
>
> Thank you for the patch.
>
> On Tuesday 10 March 2015 14:24:53 Tim Nordell wrote:
>> During testing there appeared to be a race condition where the IRQs
>> for VD0 and VD1 could be triggered while enabling the CCDC module
>> before the pipeline status was updated.  Simply modify the trigger
>> conditions for VD0 and VD1 so they won't occur when the CCDC module
>> is not enabled.
>>
>> (When this occurred during testing, the VD0 interrupt was occurring
>> over and over again starving the rest of the system.)
> I'm curious, might this be caused by the input (adv7180 in your case) being
> enabled before the ISP ? The CCDC is very sensitive to any glitch in its input
> signals, you need to make sure that the source is disabled before its subdev
> s_stream operation is called. Given that the adv7180 driver doesn't implement
> s_stream, I expect it to be free-running, which is definitely a problem.
>
I'll give that a shot and try add code into the adv7180 driver to turn 
on and off its output signals.  However, it seems like if the driver can 
avoid a problem presented by external hardware (or other drivers), that 
it should.  Something like either turning off the VD0 and VD1 interrupts 
when not in use, or by simply moving the trigger points for those 
interrupts (as I did here) to avoid problems by presented by signals to 
the system is probably a good thing for robustness.

- Tim

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
  
Laurent Pinchart April 21, 2015, 5:58 p.m. UTC | #3
Hi Tim,

On Wednesday 18 March 2015 10:25:34 Tim Nordell wrote:
> On 03/18/15 10:19, Laurent Pinchart wrote:
> > On Tuesday 10 March 2015 14:24:53 Tim Nordell wrote:
> >> During testing there appeared to be a race condition where the IRQs
> >> for VD0 and VD1 could be triggered while enabling the CCDC module
> >> before the pipeline status was updated.  Simply modify the trigger
> >> conditions for VD0 and VD1 so they won't occur when the CCDC module
> >> is not enabled.
> >> 
> >> (When this occurred during testing, the VD0 interrupt was occurring
> >> over and over again starving the rest of the system.)
> > 
> > I'm curious, might this be caused by the input (adv7180 in your case)
> > being enabled before the ISP ? The CCDC is very sensitive to any glitch in
> > its input signals, you need to make sure that the source is disabled
> > before its subdev s_stream operation is called. Given that the adv7180
> > driver doesn't implement s_stream, I expect it to be free-running, which
> > is definitely a problem.
>
> I'll give that a shot and try add code into the adv7180 driver to turn on
> and off its output signals.  However, it seems like if the driver can avoid
> a problem presented by external hardware (or other drivers), that it should. 
> Something like either turning off the VD0 and VD1 interrupts when not in
> use, or by simply moving the trigger points for those interrupts (as I did
> here) to avoid problems by presented by signals to the system is probably a
> good thing for robustness.

I don't disagree with that. I'll have to review the patch in details, as the 
CCDC code is quite sensitive. In order to do so, I'd like to know whether the 
problem in your case was caused by the adv7180 always being enabled. Any luck 
with adding a s_stream implementation in the adv7180 driver ? :-)
  
Tim Nordell April 21, 2015, 6:05 p.m. UTC | #4
Laurent -

On 04/21/15 12:58, Laurent Pinchart wrote:
> Hi Tim,
>
> On Wednesday 18 March 2015 10:25:34 Tim Nordell wrote:
>> I'll give that a shot and try add code into the adv7180 driver to turn on
>> and off its output signals.  However, it seems like if the driver can avoid
>> a problem presented by external hardware (or other drivers), that it should.
>> Something like either turning off the VD0 and VD1 interrupts when not in
>> use, or by simply moving the trigger points for those interrupts (as I did
>> here) to avoid problems by presented by signals to the system is probably a
>> good thing for robustness.
> I don't disagree with that. I'll have to review the patch in details, as the
> CCDC code is quite sensitive. In order to do so, I'd like to know whether the
> problem in your case was caused by the adv7180 always being enabled. Any luck
> with adding a s_stream implementation in the adv7180 driver ? :-)
>

I did add the stream on/off code, but it still seemed to have some 
difficulties.  The codebase has effectively been handed off to our 
client, however, at this point.  I still happen to have hardware (we're 
wrapping things up with the client), but likely I won't have the 
hardware in a week or so.

I still think that the driver should avoid having the interrupts enabled 
if it knows it shouldn't be receiving any at a given point. I personally 
like the approach of modifying the VD0/VD1 trigger points as it 
effectively silences those interrupts without touching the central 
interrupt register (less potential locking issues between the various 
components in the OMAP3 ISP), but it could be reworked of course to 
touch the central interrupt register too.

- Tim

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
  

Patch

diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c
index 587489a..d5de843 100644
--- a/drivers/media/platform/omap3isp/ispccdc.c
+++ b/drivers/media/platform/omap3isp/ispccdc.c
@@ -1218,13 +1218,6 @@  static void ccdc_configure(struct isp_ccdc_device *ccdc)
 	}
 	ccdc_config_imgattr(ccdc, ccdc_pattern);
 
-	/* Generate VD0 on the last line of the image and VD1 on the
-	 * 2/3 height line.
-	 */
-	isp_reg_writel(isp, ((format->height - 2) << ISPCCDC_VDINT_0_SHIFT) |
-		       ((format->height * 2 / 3) << ISPCCDC_VDINT_1_SHIFT),
-		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT);
-
 	/* CCDC_PAD_SOURCE_OF */
 	format = &ccdc->formats[CCDC_PAD_SOURCE_OF];
 	crop = &ccdc->crop;
@@ -1316,11 +1309,29 @@  unlock:
 
 static void __ccdc_enable(struct isp_ccdc_device *ccdc, int enable)
 {
+	struct v4l2_mbus_framefmt *format = &ccdc->formats[CCDC_PAD_SINK];
 	struct isp_device *isp = to_isp_device(ccdc);
+	int vd0, vd1;
 
 	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR,
 			ISPCCDC_PCR_EN, enable ? ISPCCDC_PCR_EN : 0);
 
+	/* Generate VD0 on the last line of the image and VD1 on the
+	* 2/3 height line when enabled.  Otherwise, set VD0 and VD1
+	* interrupts high enough that they won't be generated.
+	*/
+	if (enable) {
+		vd0 = format->height - 2;
+		vd1 = format->height * 2 / 3;
+	} else {
+		vd0 = 0xffff;
+		vd1 = 0xffff;
+	}
+
+	isp_reg_writel(isp, (vd0 << ISPCCDC_VDINT_0_SHIFT) |
+		(vd1 << ISPCCDC_VDINT_1_SHIFT),
+		OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT);
+
 	ccdc->running = enable;
 }