Re: [Freedreno] [v1] drm/msm/disp/dpu1: turn off vblank irqs aggressively in dpu driver

2020-12-14 Thread Rob Clark
On Mon, Dec 14, 2020 at 3:41 AM Kalyan Thota  wrote:
>
> Turn off vblank irqs immediately as soon as drm_vblank_put is
> requested so that there are no irqs triggered during idle state.
>
> This will reduce cpu wakeups and help in power saving. The change
> also enable driver timestamp for vblanks.
>
> Signed-off-by: Kalyan Thota 
> ---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c| 69 
> +
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 15 +++
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h |  6 +++
>  drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c |  4 ++
>  4 files changed, 94 insertions(+)
>
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
> b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> index d4662e8..a4a5733 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> @@ -65,6 +65,73 @@ static void dpu_crtc_destroy(struct drm_crtc *crtc)
> kfree(dpu_crtc);
>  }
>
> +static struct drm_encoder *get_encoder_from_crtc(struct drm_crtc *crtc)
> +{
> +   struct drm_device *dev = crtc->dev;
> +   struct drm_encoder *encoder;
> +
> +   drm_for_each_encoder(encoder, dev)
> +   if (encoder->crtc == crtc)
> +   return encoder;
> +
> +   return NULL;
> +}
> +
> +static bool dpu_crtc_get_scanout_position(struct drm_crtc *crtc,
> +  bool in_vblank_irq,
> +  int *vpos, int *hpos,
> +  ktime_t *stime, ktime_t *etime,
> +  const struct drm_display_mode 
> *mode)
> +{
> +   unsigned int pipe = crtc->index;
> +   struct drm_encoder *encoder;
> +   int line, vsw, vbp, vactive_start, vactive_end, vfp_end;
> +
> +
> +   encoder = get_encoder_from_crtc(crtc);
> +   if (!encoder) {
> +   DRM_ERROR("no encoder found for crtc %d\n", pipe);
> +   return false;
> +   }
> +
> +   vsw = mode->crtc_vsync_end - mode->crtc_vsync_start;
> +   vbp = mode->crtc_vtotal - mode->crtc_vsync_end;
> +
> +   /*
> +* the line counter is 1 at the start of the VSYNC pulse and VTOTAL at
> +* the end of VFP. Translate the porch values relative to the line
> +* counter positions.
> +*/
> +
> +   vactive_start = vsw + vbp + 1;
> +
> +   vactive_end = vactive_start + mode->crtc_vdisplay;
> +
> +   /* last scan line before VSYNC */
> +   vfp_end = mode->crtc_vtotal;
> +
> +   if (stime)
> +   *stime = ktime_get();
> +
> +   line = dpu_encoder_get_linecount(encoder);
> +
> +   if (line < vactive_start)
> +   line -= vactive_start;
> +   else if (line > vactive_end)
> +   line = line - vfp_end - vactive_start;
> +   else
> +   line -= vactive_start;
> +
> +   *vpos = line;
> +   *hpos = 0;
> +
> +   if (etime)
> +   *etime = ktime_get();
> +
> +   return true;
> +}
> +
> +
>  static void _dpu_crtc_setup_blend_cfg(struct dpu_crtc_mixer *mixer,
> struct dpu_plane_state *pstate, struct dpu_format *format)
>  {
> @@ -1243,6 +1310,7 @@ static const struct drm_crtc_funcs dpu_crtc_funcs = {
> .early_unregister = dpu_crtc_early_unregister,
> .enable_vblank  = msm_crtc_enable_vblank,
> .disable_vblank = msm_crtc_disable_vblank,
> +   .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
>  };
>
>  static const struct drm_crtc_helper_funcs dpu_crtc_helper_funcs = {
> @@ -1251,6 +1319,7 @@ static const struct drm_crtc_helper_funcs 
> dpu_crtc_helper_funcs = {
> .atomic_check = dpu_crtc_atomic_check,
> .atomic_begin = dpu_crtc_atomic_begin,
> .atomic_flush = dpu_crtc_atomic_flush,
> +   .get_scanout_position = dpu_crtc_get_scanout_position,
>  };

I'm happy to see get_vblank_timestamp/get_scanout_position wired up, I
had a WIP patch for this somewhere but never got around to finishing
it.

But you probably should mention in the commit msg why this is part of this patch

>
>  /* initialize crtc */
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
> b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> index f7f5c25..6c7c7fd 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> @@ -425,6 +425,21 @@ int dpu_encoder_helper_unregister_irq(struct 
> dpu_encoder_phys *phys_enc,
> return 0;
>  }
>
> +int dpu_encoder_get_linecount(struct drm_encoder *drm_enc)
> +{
> +   struct dpu_encoder_virt *dpu_enc = NULL;
> +   struct dpu_encoder_phys *phys = NULL;
> +   int linecount = 0;
> +
> +   dpu_enc = to_dpu_encoder_virt(drm_enc);
> +   phys = dpu_enc ? dpu_enc->cur_master : NULL;
> +
> +   if (phys && phys->ops.get_line_count)
> +   linecount = phys->ops.get_line_count(phys);
> +
> +   

[Freedreno] [v1] drm/msm/disp/dpu1: turn off vblank irqs aggressively in dpu driver

2020-12-14 Thread Kalyan Thota
Turn off vblank irqs immediately as soon as drm_vblank_put is
requested so that there are no irqs triggered during idle state.

This will reduce cpu wakeups and help in power saving. The change
also enable driver timestamp for vblanks.

Signed-off-by: Kalyan Thota 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c| 69 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 15 +++
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h |  6 +++
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c |  4 ++
 4 files changed, 94 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index d4662e8..a4a5733 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -65,6 +65,73 @@ static void dpu_crtc_destroy(struct drm_crtc *crtc)
kfree(dpu_crtc);
 }
 
+static struct drm_encoder *get_encoder_from_crtc(struct drm_crtc *crtc)
+{
+   struct drm_device *dev = crtc->dev;
+   struct drm_encoder *encoder;
+
+   drm_for_each_encoder(encoder, dev)
+   if (encoder->crtc == crtc)
+   return encoder;
+
+   return NULL;
+}
+
+static bool dpu_crtc_get_scanout_position(struct drm_crtc *crtc,
+  bool in_vblank_irq,
+  int *vpos, int *hpos,
+  ktime_t *stime, ktime_t *etime,
+  const struct drm_display_mode *mode)
+{
+   unsigned int pipe = crtc->index;
+   struct drm_encoder *encoder;
+   int line, vsw, vbp, vactive_start, vactive_end, vfp_end;
+
+
+   encoder = get_encoder_from_crtc(crtc);
+   if (!encoder) {
+   DRM_ERROR("no encoder found for crtc %d\n", pipe);
+   return false;
+   }
+
+   vsw = mode->crtc_vsync_end - mode->crtc_vsync_start;
+   vbp = mode->crtc_vtotal - mode->crtc_vsync_end;
+
+   /*
+* the line counter is 1 at the start of the VSYNC pulse and VTOTAL at
+* the end of VFP. Translate the porch values relative to the line
+* counter positions.
+*/
+
+   vactive_start = vsw + vbp + 1;
+
+   vactive_end = vactive_start + mode->crtc_vdisplay;
+
+   /* last scan line before VSYNC */
+   vfp_end = mode->crtc_vtotal;
+
+   if (stime)
+   *stime = ktime_get();
+
+   line = dpu_encoder_get_linecount(encoder);
+
+   if (line < vactive_start)
+   line -= vactive_start;
+   else if (line > vactive_end)
+   line = line - vfp_end - vactive_start;
+   else
+   line -= vactive_start;
+
+   *vpos = line;
+   *hpos = 0;
+
+   if (etime)
+   *etime = ktime_get();
+
+   return true;
+}
+
+
 static void _dpu_crtc_setup_blend_cfg(struct dpu_crtc_mixer *mixer,
struct dpu_plane_state *pstate, struct dpu_format *format)
 {
@@ -1243,6 +1310,7 @@ static const struct drm_crtc_funcs dpu_crtc_funcs = {
.early_unregister = dpu_crtc_early_unregister,
.enable_vblank  = msm_crtc_enable_vblank,
.disable_vblank = msm_crtc_disable_vblank,
+   .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
 };
 
 static const struct drm_crtc_helper_funcs dpu_crtc_helper_funcs = {
@@ -1251,6 +1319,7 @@ static const struct drm_crtc_helper_funcs 
dpu_crtc_helper_funcs = {
.atomic_check = dpu_crtc_atomic_check,
.atomic_begin = dpu_crtc_atomic_begin,
.atomic_flush = dpu_crtc_atomic_flush,
+   .get_scanout_position = dpu_crtc_get_scanout_position,
 };
 
 /* initialize crtc */
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index f7f5c25..6c7c7fd 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -425,6 +425,21 @@ int dpu_encoder_helper_unregister_irq(struct 
dpu_encoder_phys *phys_enc,
return 0;
 }
 
+int dpu_encoder_get_linecount(struct drm_encoder *drm_enc)
+{
+   struct dpu_encoder_virt *dpu_enc = NULL;
+   struct dpu_encoder_phys *phys = NULL;
+   int linecount = 0;
+
+   dpu_enc = to_dpu_encoder_virt(drm_enc);
+   phys = dpu_enc ? dpu_enc->cur_master : NULL;
+
+   if (phys && phys->ops.get_line_count)
+   linecount = phys->ops.get_line_count(phys);
+
+   return linecount;
+}
+
 void dpu_encoder_get_hw_resources(struct drm_encoder *drm_enc,
  struct dpu_encoder_hw_resources *hw_res)
 {
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
index b491346..2c4804c 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -156,5 +156,11 @@ void dpu_encoder_prepare_commit(struct drm_encoder 
*drm_enc);
  */
 void dpu_encoder_set_idle_timeout(struct drm_encoder