diff mbox

[v2] drm/tilcdc: Precalculate total frametime in tilcdc_crtc_set_mode()

Message ID 1507887353-30360-1-git-send-email-jsarha@ti.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jyri Sarha Oct. 13, 2017, 9:35 a.m. UTC
We need the total frame refresh time to check if we are too close to
vertical sync when updating the two framebuffer DMA registers and risk
a collision. This new method is more accurate that the previous that
based on mode's vrefresh value, which itself is inaccurate or may not
even be initialized.

Reported-by: Kevin Hao <kexin.hao@windriver.com>
Fixes: 11abbc9f39e0 ("drm/tilcdc: Set framebuffer DMA address to HW only if CRTC is enabled")
Cc: <stable@vger.kernel.org> # v4.11+
Signed-off-by: Jyri Sarha <jsarha@ti.com>
---
Since first version:

Change frametime* variable names to hvtotal and use 64-bit division
instead of dynamcally scaled 32-bit division as suggested by Tomi
Valkeinen.

 drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

Comments

Tomi Valkeinen Oct. 13, 2017, 11:04 a.m. UTC | #1

Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

On 13/10/17 12:35, Jyri Sarha wrote:
> We need the total frame refresh time to check if we are too close to
> vertical sync when updating the two framebuffer DMA registers and risk
> a collision. This new method is more accurate that the previous that
> based on mode's vrefresh value, which itself is inaccurate or may not
> even be initialized.
> 
> Reported-by: Kevin Hao <kexin.hao@windriver.com>
> Fixes: 11abbc9f39e0 ("drm/tilcdc: Set framebuffer DMA address to HW only if CRTC is enabled")
> Cc: <stable@vger.kernel.org> # v4.11+
> Signed-off-by: Jyri Sarha <jsarha@ti.com>
> ---
> Since first version:
> 
> Change frametime* variable names to hvtotal and use 64-bit division
> instead of dynamcally scaled 32-bit division as suggested by Tomi
> Valkeinen.
> 
>  drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 17 ++++++++++++++++-
>  1 file changed, 16 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> index 704db24..a8b22aa 100644
> --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> @@ -24,6 +24,7 @@
>  #include <linux/completion.h>
>  #include <linux/dma-mapping.h>
>  #include <linux/of_graph.h>
> +#include <linux/math64.h>
>  
>  #include "tilcdc_drv.h"
>  #include "tilcdc_regs.h"
> @@ -48,6 +49,7 @@ struct tilcdc_crtc {
>  	unsigned int lcd_fck_rate;
>  
>  	ktime_t last_vblank;
> +	unsigned int hvtotal_us;
>  
>  	struct drm_framebuffer *curr_fb;
>  	struct drm_framebuffer *next_fb;
> @@ -292,6 +294,16 @@ static void tilcdc_crtc_set_clk(struct drm_crtc *crtc)
>  				LCDC_V2_CORE_CLK_EN);
>  }
>  
> +uint tilcdc_mode_hvtotal(const struct drm_display_mode *mode)
> +{
> +	uint ret;
> +
> +	ret = (uint) div_u64(1000llu * mode->htotal * mode->vtotal,
> +			     mode->clock);
> +
> +	return ret;
> +}

I don't think "uint" is recommended. Just use u32. And drop the ret
variable, just one-line return statement should be enough.

Otherwise:

Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ti.com>

 Tomi
Jyri Sarha Oct. 13, 2017, noon UTC | #2

Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

On 10/13/17 14:04, Tomi Valkeinen wrote:
>> +uint tilcdc_mode_hvtotal(const struct drm_display_mode *mode)
>> +{
>> +	uint ret;
>> +
>> +	ret = (uint) div_u64(1000llu * mode->htotal * mode->vtotal,
>> +			     mode->clock);
>> +
>> +	return ret;
>> +}
> I don't think "uint" is recommended. Just use u32. And drop the ret
> variable, just one-line return statement should be enough.
> 

The ret variable can of course be dropped, but how u32 is better than
uint? If the driver would ever be used in 64bit architecture (highly
unlikely), then it would automatically use the higher precision, and on
32-bit architecture there is no difference.

Also the data member in the private struct is uint and so are the other
similar data members like lcd_fck_rate.

So why change?

Best regards,
Jyri

> Otherwise:
> 
> Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
> 
>  Tomi
Tomi Valkeinen Oct. 13, 2017, 12:32 p.m. UTC | #3
This message contains a digitally signed email which can be read by opening the attachment.
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
On 13/10/17 15:00, Jyri Sarha wrote:
> On 10/13/17 14:04, Tomi Valkeinen wrote:
>>> +uint tilcdc_mode_hvtotal(const struct drm_display_mode *mode)
>>> +{
>>> +	uint ret;
>>> +
>>> +	ret = (uint) div_u64(1000llu * mode->htotal * mode->vtotal,
>>> +			     mode->clock);
>>> +
>>> +	return ret;
>>> +}
>> I don't think "uint" is recommended. Just use u32. And drop the ret
>> variable, just one-line return statement should be enough.
>>
> 
> The ret variable can of course be dropped, but how u32 is better than
> uint? If the driver would ever be used in 64bit architecture (highly
> unlikely), then it would automatically use the higher precision, and on
> 32-bit architecture there is no difference.

I think int is normally 32 bit on 64 bit platforms too. But that depends
on compiler flags.

Where does "uint" come from anyway? I don't think it's part of a C standard.

> Also the data member in the private struct is uint and so are the other
> similar data members like lcd_fck_rate.

Ok. Well, it's good to stick to one way of doing things, so maybe uint
is fine. For any new code, I would not recommend using it.

 Tomi
Jyri Sarha Oct. 13, 2017, 12:38 p.m. UTC | #4

Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

On 10/13/17 15:32, Tomi Valkeinen wrote:
> Where does "uint" come from anyway? I don't think it's part of a C standard.

AFAIK, it is just a Linux commodity typedef for unsigned int, and
because of that a defacto typedef in many other environments too.

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 704db24..a8b22aa 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -24,6 +24,7 @@ 
 #include <linux/completion.h>
 #include <linux/dma-mapping.h>
 #include <linux/of_graph.h>
+#include <linux/math64.h>
 
 #include "tilcdc_drv.h"
 #include "tilcdc_regs.h"
@@ -48,6 +49,7 @@  struct tilcdc_crtc {
 	unsigned int lcd_fck_rate;
 
 	ktime_t last_vblank;
+	unsigned int hvtotal_us;
 
 	struct drm_framebuffer *curr_fb;
 	struct drm_framebuffer *next_fb;
@@ -292,6 +294,16 @@  static void tilcdc_crtc_set_clk(struct drm_crtc *crtc)
 				LCDC_V2_CORE_CLK_EN);
 }
 
+uint tilcdc_mode_hvtotal(const struct drm_display_mode *mode)
+{
+	uint ret;
+
+	ret = (uint) div_u64(1000llu * mode->htotal * mode->vtotal,
+			     mode->clock);
+
+	return ret;
+}
+
 static void tilcdc_crtc_set_mode(struct drm_crtc *crtc)
 {
 	struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
@@ -459,6 +471,9 @@  static void tilcdc_crtc_set_mode(struct drm_crtc *crtc)
 	drm_framebuffer_get(fb);
 
 	crtc->hwmode = crtc->state->adjusted_mode;
+
+	tilcdc_crtc->hvtotal_us =
+		tilcdc_mode_hvtotal(&crtc->hwmode);
 }
 
 static void tilcdc_crtc_enable(struct drm_crtc *crtc)
@@ -642,7 +657,7 @@  int tilcdc_crtc_update_fb(struct drm_crtc *crtc,
 		spin_lock_irqsave(&tilcdc_crtc->irq_lock, flags);
 
 		next_vblank = ktime_add_us(tilcdc_crtc->last_vblank,
-					   1000000 / crtc->hwmode.vrefresh);
+					   tilcdc_crtc->hvtotal_us);
 		tdiff = ktime_to_us(ktime_sub(next_vblank, ktime_get()));
 
 		if (tdiff < TILCDC_VBLANK_SAFETY_THRESHOLD_US)