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

From: Rob Clark
Date: Mon Dec 14 2020 - 13:33:08 EST


On Mon, Dec 14, 2020 at 3:41 AM Kalyan Thota <kalyan_t@xxxxxxxxxxxxxx> 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 <kalyan_t@xxxxxxxxxxxxxx>
> ---
> 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);
> +
> + 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 *drm_enc,
> u32 idle_timeout);
> +/**
> + * dpu_encoder_get_linecount - get interface line count for the encoder.
> + * @drm_enc: Pointer to previously created drm encoder structure
> + */
> +

nit: remove extra line

BR,
-R

> +int dpu_encoder_get_linecount(struct drm_encoder *drm_enc);
>
> #endif /* __DPU_ENCODER_H__ */
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> index 374b0e8..49bd0729 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> @@ -14,6 +14,7 @@
>
> #include <drm/drm_crtc.h>
> #include <drm/drm_file.h>
> +#include <drm/drm_vblank.h>
>
> #include "msm_drv.h"
> #include "msm_mmu.h"
> @@ -1020,6 +1021,9 @@ static int dpu_kms_hw_init(struct msm_kms *kms)
> */
> dev->mode_config.allow_fb_modifiers = true;
>
> + /* Disable vblank irqs aggressively for power-saving */
> + dev->vblank_disable_immediate = true;
> +
> /*
> * _dpu_kms_drm_obj_init should create the DRM related objects
> * i.e. CRTCs, planes, encoders, connectors and so forth
> --
> 2.7.4
>