diff mbox

drm: tilcdc: simplify the recovery from sync lost error on rev1

Message ID 1481641656-25227-1-git-send-email-bgolaszewski@baylibre.com (mailing list archive)
State New, archived
Headers show

Commit Message

Bartosz Golaszewski Dec. 13, 2016, 3:07 p.m. UTC
Revision 2 of LCDC suffers from an issue where a SYNC_LOST error
caused by limited memory bandwidth may leave the picture shifted a
couple pixels to the right.

This issue has not been observed on revision 1, while the recovery
mechanism introduces a different issue, where the END_OF_FRAME
interrupt doesn't fire while drm is waiting for vblanks.

On rev1: recover from sync lost errors by simply clearing the
RASTER_ENABLE bit in the RASTER_CTRL register and re-enabling it
again as is suggested by the datasheet.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 24 +++++++++++++++---------
 1 file changed, 15 insertions(+), 9 deletions(-)

Comments

Jyri Sarha Dec. 19, 2016, 1:09 p.m. UTC | #1
One comment bellow.

On 12/13/16 17:07, Bartosz Golaszewski wrote:
> Revision 2 of LCDC suffers from an issue where a SYNC_LOST error
> caused by limited memory bandwidth may leave the picture shifted a
> couple pixels to the right.
> 
> This issue has not been observed on revision 1, while the recovery
> mechanism introduces a different issue, where the END_OF_FRAME
> interrupt doesn't fire while drm is waiting for vblanks.
> 
> On rev1: recover from sync lost errors by simply clearing the
> RASTER_ENABLE bit in the RASTER_CTRL register and re-enabling it
> again as is suggested by the datasheet.
> 
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> ---
>  drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 24 +++++++++++++++---------
>  1 file changed, 15 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> index 9942b05..70e57a7 100644
> --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> @@ -921,17 +921,23 @@ irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc)
>  		dev_err_ratelimited(dev->dev, "%s(0x%08x): Sync lost",
>  				    __func__, stat);
>  		tilcdc_crtc->frame_intact = false;
> -		if (tilcdc_crtc->sync_lost_count++ >
> -		    SYNC_LOST_COUNT_LIMIT) {
> -			dev_err(dev->dev, "%s(0x%08x): Sync lost flood detected, recovering", __func__, stat);
> -			queue_work(system_wq, &tilcdc_crtc->recover_work);
> -			if (priv->rev == 1)
> -				tilcdc_clear(dev, LCDC_RASTER_CTRL_REG,
> -					     LCDC_V1_SYNC_LOST_INT_ENA);
> -			else
> +		if (priv->rev == 1) {

I would add here:
+		if ((tilcdc_read(dev, LCDC_RASTER_CTRL_REG) &
+				LCDC_RASTER_ENABLE)) {

> +			tilcdc_clear(dev,
> +				     LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
> +			tilcdc_set(dev,
> +				   LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
+		}

Just in case the interrupt is for some reason handled right after the
crtc is disabled.

With this addition I could send a pull request for this fix still today,
if you agree with the change.

> +		} else {
> +			if (tilcdc_crtc->sync_lost_count++ >
> +			    SYNC_LOST_COUNT_LIMIT) {
> +				dev_err(dev->dev,
> +					"%s(0x%08x): Sync lost flood detected, recovering",
> +					__func__, stat);
> +				queue_work(system_wq,
> +					   &tilcdc_crtc->recover_work);
>  				tilcdc_write(dev, LCDC_INT_ENABLE_CLR_REG,
>  					     LCDC_SYNC_LOST);
> -			tilcdc_crtc->sync_lost_count = 0;
> +				tilcdc_crtc->sync_lost_count = 0;
> +			}
>  		}
>  	}
>  
>
Bartosz Golaszewski Dec. 19, 2016, 2:19 p.m. UTC | #2
2016-12-19 14:09 GMT+01:00 Jyri Sarha <jsarha@ti.com>:
> One comment bellow.
>
> On 12/13/16 17:07, Bartosz Golaszewski wrote:
>> Revision 2 of LCDC suffers from an issue where a SYNC_LOST error
>> caused by limited memory bandwidth may leave the picture shifted a
>> couple pixels to the right.
>>
>> This issue has not been observed on revision 1, while the recovery
>> mechanism introduces a different issue, where the END_OF_FRAME
>> interrupt doesn't fire while drm is waiting for vblanks.
>>
>> On rev1: recover from sync lost errors by simply clearing the
>> RASTER_ENABLE bit in the RASTER_CTRL register and re-enabling it
>> again as is suggested by the datasheet.
>>
>> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>> ---
>>  drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 24 +++++++++++++++---------
>>  1 file changed, 15 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
>> index 9942b05..70e57a7 100644
>> --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
>> +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
>> @@ -921,17 +921,23 @@ irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc)
>>               dev_err_ratelimited(dev->dev, "%s(0x%08x): Sync lost",
>>                                   __func__, stat);
>>               tilcdc_crtc->frame_intact = false;
>> -             if (tilcdc_crtc->sync_lost_count++ >
>> -                 SYNC_LOST_COUNT_LIMIT) {
>> -                     dev_err(dev->dev, "%s(0x%08x): Sync lost flood detected, recovering", __func__, stat);
>> -                     queue_work(system_wq, &tilcdc_crtc->recover_work);
>> -                     if (priv->rev == 1)
>> -                             tilcdc_clear(dev, LCDC_RASTER_CTRL_REG,
>> -                                          LCDC_V1_SYNC_LOST_INT_ENA);
>> -                     else
>> +             if (priv->rev == 1) {
>
> I would add here:
> +               if ((tilcdc_read(dev, LCDC_RASTER_CTRL_REG) &
> +                               LCDC_RASTER_ENABLE)) {
>
>> +                     tilcdc_clear(dev,
>> +                                  LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
>> +                     tilcdc_set(dev,
>> +                                LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
> +               }
>
> Just in case the interrupt is for some reason handled right after the
> crtc is disabled.
>
> With this addition I could send a pull request for this fix still today,
> if you agree with the change.

I'm not sure this can really happen, but it won't hurt either, so I'll
send a v2.

Thanks,
Bartosz
Jyri Sarha Dec. 19, 2016, 4:50 p.m. UTC | #3
On 12/19/16 16:19, Bartosz Golaszewski wrote:
>> I would add here:
>> +               if ((tilcdc_read(dev, LCDC_RASTER_CTRL_REG) &
>> +                               LCDC_RASTER_ENABLE)) {
>>
>>> +                     tilcdc_clear(dev,
>>> +                                  LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
>>> +                     tilcdc_set(dev,
>>> +                                LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
>> +               }
>>
>> Just in case the interrupt is for some reason handled right after the
>> crtc is disabled.
>>
>> With this addition I could send a pull request for this fix still today,
>> if you agree with the change.
> I'm not sure this can really happen, but it won't hurt either, so I'll
> send a v2.

Well, in theory it is quite possible. If the driver clears the raster
enable at the same time when sync lost interrupt is generated, then the
irq routine handles the irq before the interrupts are disabled. Then it
happens that rastere remains on but the driver thinks it has already
turned it off.

In practice this is of course terribly unlikely, but a race is a race
and should be avoided.

Anyway, my vacation has already been started so I won't send a pull
request now. I do not like the idea of doing something like that and
then vanishing for two weeks. I hope they still take fixes for 4.10 in
4th Jan.

Best regards,
Jyri
diff mbox

Patch

diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index 9942b05..70e57a7 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -921,17 +921,23 @@  irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc)
 		dev_err_ratelimited(dev->dev, "%s(0x%08x): Sync lost",
 				    __func__, stat);
 		tilcdc_crtc->frame_intact = false;
-		if (tilcdc_crtc->sync_lost_count++ >
-		    SYNC_LOST_COUNT_LIMIT) {
-			dev_err(dev->dev, "%s(0x%08x): Sync lost flood detected, recovering", __func__, stat);
-			queue_work(system_wq, &tilcdc_crtc->recover_work);
-			if (priv->rev == 1)
-				tilcdc_clear(dev, LCDC_RASTER_CTRL_REG,
-					     LCDC_V1_SYNC_LOST_INT_ENA);
-			else
+		if (priv->rev == 1) {
+			tilcdc_clear(dev,
+				     LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
+			tilcdc_set(dev,
+				   LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
+		} else {
+			if (tilcdc_crtc->sync_lost_count++ >
+			    SYNC_LOST_COUNT_LIMIT) {
+				dev_err(dev->dev,
+					"%s(0x%08x): Sync lost flood detected, recovering",
+					__func__, stat);
+				queue_work(system_wq,
+					   &tilcdc_crtc->recover_work);
 				tilcdc_write(dev, LCDC_INT_ENABLE_CLR_REG,
 					     LCDC_SYNC_LOST);
-			tilcdc_crtc->sync_lost_count = 0;
+				tilcdc_crtc->sync_lost_count = 0;
+			}
 		}
 	}