Received: by 2002:a05:6a10:8c0a:0:0:0:0 with SMTP id go10csp7287950pxb; Thu, 18 Feb 2021 06:26:41 -0800 (PST) X-Google-Smtp-Source: ABdhPJw+sdARpWIFwTyv2D89WNeHAfcWL2TlDplXMEhXGLNDvsraJ+wqtJbzAQiWvtX+DX32lHMA X-Received: by 2002:a17:907:da9:: with SMTP id go41mr4308868ejc.326.1613658400980; Thu, 18 Feb 2021 06:26:40 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1613658400; cv=none; d=google.com; s=arc-20160816; b=vqUsDEMVmne2WlP0lJL78OxwSkGMESBl5Gn70aDCh6bQZr4+VutsvOYnXBlXM37fw0 RuUfmz5+MXUNzse3rTbar285433w8uEqhS02KzNsbvjEs5p1mlDuCeQhXgClZqy3DWNc hMtPF6U8S0wmo12oUIQ6uXDUOGuMYB3zMAxO4GtZp8T/dlPpoQnqTL24TgEz2PQcDRST QjeE5/1WKM9Kv8j1mQeQE12NTvRyawBgGASeTUCcx8Od2KWBKt3E1qfrSTouVauK0bNf ObJsXhpJr/3hZi6PhRRMmi+d01tANYuKhj9ybRnwIuDuQ08gE5H92idELt0GyF2oXF/R jsFg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:message-id:date:subject:cc:to:from; bh=brL/FZOFosx8VQfjq5hbwBSx4APidGZgCaRFUR3qfWI=; b=RT60GRh6p0cQpmF70hhHeybicjkbMq95w9Fw5VvA3t4sFXEdGZQ4h6HX+GbcN76JwS plRm65HpjFOEhMzGfFe444BP5VLHc2muUsy7mvGTz5W3jdgtRxBiLf0JVgrFXSI59Djs v4pc6J05w7p91f9iQTl5Xn5y5+lSj9WZzGHEZMSlbPGIG2ekroDJ/iUbnoirdxypKI26 MP9+r/1Oq6nsZHreNjhaQAuySg7+S4ltMJtyvJCmOJyPMHIkeyKYMo+2XmJNn/1K7bdv Zzg6h16eyq/9d34Bn1OugskG7hNZ6mw2o17V/Y3SMUKx3mdec1lkcSsu5T/6414ltq0s SYwA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id f20si3575743ejk.711.2021.02.18.06.26.16; Thu, 18 Feb 2021 06:26:40 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233703AbhBROXv (ORCPT + 99 others); Thu, 18 Feb 2021 09:23:51 -0500 Received: from alexa-out.qualcomm.com ([129.46.98.28]:33420 "EHLO alexa-out.qualcomm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233099AbhBRMhL (ORCPT ); Thu, 18 Feb 2021 07:37:11 -0500 Received: from ironmsg-lv-alpha.qualcomm.com ([10.47.202.13]) by alexa-out.qualcomm.com with ESMTP; 18 Feb 2021 04:36:26 -0800 X-QCInternal: smtphost Received: from ironmsg01-blr.qualcomm.com ([10.86.208.130]) by ironmsg-lv-alpha.qualcomm.com with ESMTP/TLS/AES256-SHA; 18 Feb 2021 04:36:23 -0800 X-QCInternal: smtphost Received: from kalyant-linux.qualcomm.com ([10.204.66.210]) by ironmsg01-blr.qualcomm.com with ESMTP; 18 Feb 2021 18:05:49 +0530 Received: by kalyant-linux.qualcomm.com (Postfix, from userid 94428) id CBA7642A8; Thu, 18 Feb 2021 04:35:47 -0800 (PST) From: Kalyan Thota To: dri-devel@lists.freedesktop.org, linux-arm-msm@vger.kernel.org, freedreno@lists.freedesktop.org, devicetree@vger.kernel.org Cc: Kalyan Thota , linux-kernel@vger.kernel.org, robdclark@gmail.com, seanpaul@chromium.org, hoegsberg@chromium.org, dianders@chromium.org, mkrishn@codeaurora.org, swboyd@chromium.org, abhinavk@codeaurora.org, ddavenport@chromium.org Subject: [v4] drm/msm/disp/dpu1: turn off vblank irqs aggressively in dpu driver Date: Thu, 18 Feb 2021 04:35:46 -0800 Message-Id: <1613651746-12783-1-git-send-email-kalyan_t@codeaurora.org> X-Mailer: git-send-email 2.7.4 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Set the flag vblank_disable_immediate = true to 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. To enable vblank_disable_immediate flag the underlying KMS driver needs to support high precision vblank timestamping and also a reliable way of providing vblank counter which is incrementing at the leading edge of vblank. This patch also brings in changes to support vblank_disable_immediate requirement in dpu driver. Changes in v1: - Specify reason to add vblank timestamp support. (Rob). - Add changes to provide vblank counter from dpu driver. Changes in v2: - Fix warn stack reported by Rob Clark with v2 patch. Changes in v3: - Move back to HW frame counter (Rob). Signed-off-by: Kalyan Thota --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 80 ++++++++++++++++++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 30 ++++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 11 +++ drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h | 1 + .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 26 +++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c | 1 + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h | 1 + drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 5 ++ 8 files changed, 155 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..9a80981 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -65,6 +65,83 @@ 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 u32 dpu_crtc_get_vblank_counter(struct drm_crtc *crtc) +{ + struct drm_encoder *encoder; + + encoder = get_encoder_from_crtc(crtc); + if (!encoder) { + DRM_ERROR("no encoder found for crtc %d\n", crtc->index); + return false; + } + + return dpu_encoder_get_frame_count(encoder); +} + +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 +1320,8 @@ 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, + .get_vblank_counter = dpu_crtc_get_vblank_counter, }; static const struct drm_crtc_helper_funcs dpu_crtc_helper_funcs = { @@ -1251,6 +1330,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..5cd3f31 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -425,6 +425,36 @@ int dpu_encoder_helper_unregister_irq(struct dpu_encoder_phys *phys_enc, return 0; } +int dpu_encoder_get_frame_count(struct drm_encoder *drm_enc) +{ + struct dpu_encoder_virt *dpu_enc; + struct dpu_encoder_phys *phys; + int framecount = 0; + + dpu_enc = to_dpu_encoder_virt(drm_enc); + phys = dpu_enc ? dpu_enc->cur_master : NULL; + + if (phys && phys->ops.get_frame_count) + framecount = phys->ops.get_frame_count(phys); + + return framecount; +} + +int dpu_encoder_get_linecount(struct drm_encoder *drm_enc) +{ + struct dpu_encoder_virt *dpu_enc; + struct dpu_encoder_phys *phys; + 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..99a5d73 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h @@ -156,5 +156,16 @@ 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 + */ +int dpu_encoder_get_linecount(struct drm_encoder *drm_enc); + +/** + * dpu_encoder_get_frame_count - get interface frame count for the encoder. + * @drm_enc: Pointer to previously created drm encoder structure + */ +int dpu_encoder_get_frame_count(struct drm_encoder *drm_enc); #endif /* __DPU_ENCODER_H__ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h index f8f2515..ecbc4be 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h @@ -143,6 +143,7 @@ struct dpu_encoder_phys_ops { void (*prepare_idle_pc)(struct dpu_encoder_phys *phys_enc); void (*restore)(struct dpu_encoder_phys *phys); int (*get_line_count)(struct dpu_encoder_phys *phys); + int (*get_frame_count)(struct dpu_encoder_phys *phys); }; /** diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c index 9a69fad..0e06b7e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c @@ -658,6 +658,31 @@ static int dpu_encoder_phys_vid_get_line_count( return phys_enc->hw_intf->ops.get_line_count(phys_enc->hw_intf); } +static int dpu_encoder_phys_vid_get_frame_count( + struct dpu_encoder_phys *phys_enc) +{ + struct intf_status s = {0}; + u32 fetch_start = 0; + struct drm_display_mode mode = phys_enc->cached_mode; + + if (!dpu_encoder_phys_vid_is_master(phys_enc)) + return -EINVAL; + + if (!phys_enc->hw_intf || !phys_enc->hw_intf->ops.get_status) + return -EINVAL; + + phys_enc->hw_intf->ops.get_status(phys_enc->hw_intf, &s); + + if (s.is_prog_fetch_en && s.is_en) { + fetch_start = mode.vtotal - (mode.vsync_start - mode.vdisplay); + if ((s.line_count > fetch_start) && + (s.line_count <= mode.vtotal)) + return s.frame_count + 1; + } + + return s.frame_count; +} + static void dpu_encoder_phys_vid_init_ops(struct dpu_encoder_phys_ops *ops) { ops->is_master = dpu_encoder_phys_vid_is_master; @@ -676,6 +701,7 @@ static void dpu_encoder_phys_vid_init_ops(struct dpu_encoder_phys_ops *ops) ops->handle_post_kickoff = dpu_encoder_phys_vid_handle_post_kickoff; ops->needs_single_flush = dpu_encoder_phys_vid_needs_single_flush; ops->get_line_count = dpu_encoder_phys_vid_get_line_count; + ops->get_frame_count = dpu_encoder_phys_vid_get_frame_count; } struct dpu_encoder_phys *dpu_encoder_phys_vid_init( diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c index 6f0f545..717178b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c @@ -256,6 +256,7 @@ static void dpu_hw_intf_get_status( struct dpu_hw_blk_reg_map *c = &intf->hw; s->is_en = DPU_REG_READ(c, INTF_TIMING_ENGINE_EN); + s->is_prog_fetch_en = !!(DPU_REG_READ(c, INTF_CONFIG) & BIT(31)); if (s->is_en) { s->frame_count = DPU_REG_READ(c, INTF_FRAME_COUNT); s->line_count = DPU_REG_READ(c, INTF_LINE_COUNT); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h index 0ead64d..3568be8 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h @@ -40,6 +40,7 @@ struct intf_prog_fetch { struct intf_status { u8 is_en; /* interface timing engine is enabled or not */ + u8 is_prog_fetch_en; /* interface prog fetch counter is enabled or not */ u32 frame_count; /* frame count since timing engine enabled */ u32 line_count; /* current line count including blanking */ }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 374b0e8..ed636f1 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 #include +#include #include "msm_drv.h" #include "msm_mmu.h" @@ -1020,6 +1021,10 @@ static int dpu_kms_hw_init(struct msm_kms *kms) */ dev->mode_config.allow_fb_modifiers = true; + dev->max_vblank_count = 0xffffffff; + /* 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