From patchwork Tue Sep 3 17:59:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Gupta, Anshuman" X-Patchwork-Id: 11128541 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D788014F7 for ; Tue, 3 Sep 2019 18:03:05 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id BF4A7206BB for ; Tue, 3 Sep 2019 18:03:05 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org BF4A7206BB Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id A13C189786; Tue, 3 Sep 2019 18:03:04 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) by gabe.freedesktop.org (Postfix) with ESMTPS id C0C218979F for ; Tue, 3 Sep 2019 18:03:01 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Sep 2019 11:03:01 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.64,463,1559545200"; d="scan'208";a="382213031" Received: from genxfsim-desktop.iind.intel.com ([10.223.74.120]) by fmsmga005.fm.intel.com with ESMTP; 03 Sep 2019 11:02:59 -0700 From: Anshuman Gupta To: intel-gfx@lists.freedesktop.org Date: Tue, 3 Sep 2019 23:29:38 +0530 Message-Id: <20190903175939.6741-7-anshuman.gupta@intel.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190903175939.6741-1-anshuman.gupta@intel.com> References: <20190903175939.6741-1-anshuman.gupta@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v6 6/7] drm/i915/tgl: switch between dc3co and dc5 based on display idleness X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jani.nikula@intel.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" DC3CO is useful power state, when DMC detects PSR2 idle frame while an active video playback, playing 30fps video on 60hz panel is the classic example of this use case. DC5 and DC6 saves more power, but can't be entered during video playback because there are not enough idle frames in a row to meet most PSR2 panel deep sleep entry requirement typically 4 frames. It will be worthy to enable DC3CO after completion of each flip and switch back to DC5 when display is idle, as driver doesn't differentiate between video playback and a normal flip. It is safer to allow DC5 after 6 idle frame, as PSR2 requires minimum 6 idle frame. v2: calculated s/w state to switch over dc3co when there is an update. [Imre] used cancel_delayed_work_sync() in order to avoid any race with already scheduled delayed work. [Imre] v3: cancel_delayed_work_sync() may blocked the commit work. Hence dropping it, dc5_idle_thread() checks the valid wakeref before putting the reference count, which avoids any chances of dropping a zero wakeref. [Imre (IRC)] v4: use frontbuffer flush mechanism. [Imre] Cc: Jani Nikula Cc: Imre Deak Cc: Animesh Manna Signed-off-by: Anshuman Gupta --- drivers/gpu/drm/i915/display/intel_display.c | 2 + .../drm/i915/display/intel_display_power.c | 75 +++++++++++++++++++ .../drm/i915/display/intel_display_power.h | 7 ++ .../gpu/drm/i915/display/intel_frontbuffer.c | 1 + drivers/gpu/drm/i915/display/intel_psr.c | 1 + drivers/gpu/drm/i915/i915_drv.h | 1 + 6 files changed, 87 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 01b23443c96b..94ee4fe6cc85 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -16166,6 +16166,7 @@ int intel_modeset_init(struct drm_device *dev) init_llist_head(&dev_priv->atomic_helper.free_list); INIT_WORK(&dev_priv->atomic_helper.free_work, intel_atomic_helper_free_state_worker); + INIT_DELAYED_WORK(&dev_priv->csr.idle_work, tgl_dc5_idle_thread); intel_init_quirks(dev_priv); @@ -17107,6 +17108,7 @@ void intel_modeset_driver_remove(struct drm_device *dev) flush_workqueue(dev_priv->modeset_wq); flush_work(&dev_priv->atomic_helper.free_work); + flush_delayed_work(&dev_priv->csr.idle_work); WARN_ON(!llist_empty(&dev_priv->atomic_helper.free_list)); /* diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index 95f352bf0173..57248a2a6ad7 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -20,6 +20,7 @@ #include "intel_sideband.h" #include "intel_tc.h" #include "intel_pm.h" +#include "intel_psr.h" bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv, enum i915_power_well_id power_well_id); @@ -773,6 +774,27 @@ static void gen9_set_dc_state(struct drm_i915_private *dev_priv, u32 state) dev_priv->csr.dc_state = val & mask; } +static u32 intel_get_frame_time_us(const struct intel_crtc_state *cstate) +{ + u32 pixel_rate, crtc_htotal, crtc_vtotal; + u32 frametime_us; + + if (!cstate || !cstate->base.active) + return 0; + + pixel_rate = cstate->pixel_rate; + + if (WARN_ON(pixel_rate == 0)) + return 0; + + crtc_htotal = cstate->base.adjusted_mode.crtc_htotal; + crtc_vtotal = cstate->base.adjusted_mode.crtc_vtotal; + frametime_us = DIV_ROUND_UP(crtc_htotal * crtc_vtotal * 1000ULL, + pixel_rate); + + return frametime_us; +} + void tgl_enable_psr2_transcoder_exitline(const struct intel_crtc_state *cstate) { u32 linetime_us, val, exit_scanlines; @@ -801,6 +823,50 @@ void tgl_enable_psr2_transcoder_exitline(const struct intel_crtc_state *cstate) I915_WRITE(EXITLINE(cstate->cpu_transcoder), val); } +void tgl_dc3co_flush(struct drm_i915_private *dev_priv, + unsigned int frontbuffer_bits, enum fb_op_origin origin) +{ + struct intel_crtc_state *cstate; + u32 delay; + unsigned int busy_frontbuffer_bits; + + if (!IS_TIGERLAKE(dev_priv)) + return; + + if (origin != ORIGIN_FLIP) + return; + + if (!dev_priv->csr.dc3co_crtc) + return; + + cstate = to_intel_crtc_state(dev_priv->csr.dc3co_crtc->base.state); + frontbuffer_bits &= + INTEL_FRONTBUFFER_ALL_MASK(dev_priv->csr.dc3co_crtc->pipe); + busy_frontbuffer_bits &= ~frontbuffer_bits; + + mutex_lock(&dev_priv->psr.lock); + + if (!dev_priv->psr.psr2_enabled || !dev_priv->psr.active) + goto unlock; + + /* + * At every flip frontbuffer flush first cancel the delayed work, + * when delayed schedules that means display has been idle + * for the 6 idle frame. + */ + if (!busy_frontbuffer_bits) { + cancel_delayed_work(&dev_priv->csr.idle_work); + tgl_psr2_deep_sleep_disable(dev_priv); + tgl_set_target_dc_state(dev_priv, DC_STATE_EN_DC3CO); + delay = DC5_REQ_IDLE_FRAMES * intel_get_frame_time_us(cstate); + schedule_delayed_work(&dev_priv->csr.idle_work, + usecs_to_jiffies(delay)); + } + +unlock: + mutex_unlock(&dev_priv->psr.lock); +} + static bool tgl_dc3co_is_edp_connected(struct intel_crtc_state *crtc_state) { struct drm_atomic_state *state = crtc_state->base.state; @@ -867,6 +933,15 @@ void tgl_compute_dc3co_crtc(struct intel_crtc_state *crtc_state) } } +void tgl_dc5_idle_thread(struct work_struct *work) +{ + struct drm_i915_private *dev_priv = + container_of(work, typeof(*dev_priv), csr.idle_work.work); + + tgl_set_target_dc_state(dev_priv, DC_STATE_EN_UPTO_DC6); + tgl_psr2_deep_sleep_enable(dev_priv); +} + static void tgl_allow_dc3co(struct drm_i915_private *dev_priv) { if (!dev_priv->psr.sink_psr2_support) diff --git a/drivers/gpu/drm/i915/display/intel_display_power.h b/drivers/gpu/drm/i915/display/intel_display_power.h index c37c4ce24a5f..aefdb72db131 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.h +++ b/drivers/gpu/drm/i915/display/intel_display_power.h @@ -9,6 +9,9 @@ #include "intel_display.h" #include "intel_runtime_pm.h" #include "i915_reg.h" +#include "intel_frontbuffer.h" + +#define DC5_REQ_IDLE_FRAMES 6 struct drm_i915_private; struct intel_encoder; @@ -259,11 +262,15 @@ void intel_display_power_suspend_late(struct drm_i915_private *i915); void intel_display_power_resume_early(struct drm_i915_private *i915); void intel_display_power_suspend(struct drm_i915_private *i915); void intel_display_power_resume(struct drm_i915_private *i915); + void tgl_set_target_dc_state(struct drm_i915_private *dev_priv, u32 state); bool tgl_dc3co_can_enable_fastset(struct intel_crtc_state *crtc_state); void tgl_compute_dc3co_crtc(struct intel_crtc_state *crtc_state); void tgl_dc5_idle_thread(struct work_struct *work); void tgl_enable_psr2_transcoder_exitline(const struct intel_crtc_state *cstate); +void tgl_dc5_idle_thread(struct work_struct *work); +void tgl_dc3co_flush(struct drm_i915_private *dev_priv, + unsigned int frontbuffer_bits, enum fb_op_origin origin); const char * intel_display_power_domain_str(enum intel_display_power_domain domain); diff --git a/drivers/gpu/drm/i915/display/intel_frontbuffer.c b/drivers/gpu/drm/i915/display/intel_frontbuffer.c index fc40dc1fdbcc..c3b10f6e4382 100644 --- a/drivers/gpu/drm/i915/display/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/display/intel_frontbuffer.c @@ -90,6 +90,7 @@ static void frontbuffer_flush(struct drm_i915_private *i915, might_sleep(); intel_edp_drrs_flush(i915, frontbuffer_bits); intel_psr_flush(i915, frontbuffer_bits, origin); + tgl_dc3co_flush(i915, frontbuffer_bits, origin); intel_fbc_flush(i915, frontbuffer_bits, origin); } diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 0098465ef573..cfa4f306af7e 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -583,6 +583,7 @@ void tgl_psr2_deep_sleep_enable(struct drm_i915_private *dev_priv) static void tgl_disallow_dc3co_on_psr2_exit(struct drm_i915_private *dev_priv) { + cancel_delayed_work(&dev_priv->csr.idle_work); /* Before PSR2 exit disallow dc3co*/ tgl_set_target_dc_state(dev_priv, DC_STATE_EN_UPTO_DC6); } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d593980e3d51..c7f145791311 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -338,6 +338,7 @@ struct intel_csr { u32 dc_state; u32 max_dc_state; u32 allowed_dc_mask; + struct delayed_work idle_work; intel_wakeref_t wakeref; bool dc3co_boot_modeset; /* cache the crtc on which DC3CO will be allowed */