From patchwork Tue Jan 26 15:45:31 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mika Kuoppala X-Patchwork-Id: 8124231 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 858B49F1C0 for ; Tue, 26 Jan 2016 15:45:31 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 6999C201BC for ; Tue, 26 Jan 2016 15:45:30 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 2F36F2025B for ; Tue, 26 Jan 2016 15:45:28 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 7F5046E606; Tue, 26 Jan 2016 07:45:27 -0800 (PST) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by gabe.freedesktop.org (Postfix) with ESMTP id 9DFAF6E606 for ; Tue, 26 Jan 2016 07:45:26 -0800 (PST) Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga104.fm.intel.com with ESMTP; 26 Jan 2016 07:45:26 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.22,350,1449561600"; d="scan'208";a="901467315" Received: from rosetta.fi.intel.com (HELO rosetta) ([10.237.72.66]) by fmsmga002.fm.intel.com with ESMTP; 26 Jan 2016 07:45:25 -0800 Received: by rosetta (Postfix, from userid 1000) id 3D6FF81941; Tue, 26 Jan 2016 17:45:37 +0200 (EET) From: Mika Kuoppala To: intel-gfx@lists.freedesktop.org Date: Tue, 26 Jan 2016 17:45:31 +0200 Message-Id: <1453823131-16139-1-git-send-email-mika.kuoppala@intel.com> X-Mailer: git-send-email 2.5.0 Cc: miku@iki.fi Subject: [Intel-gfx] [PATCH] drm/i915/gen9: Probe power well 1 status on dc status query X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP There has been cases where we read DC_STATE and get something that we did not write there. As DMC owns power well 1, this could be that DMC snoops DC_STATE accesses and needs to wake up power well 1 up to serve the access. But the waking up power well 1 takes time and we might end up reading during unfinished well wakeup. When we want the dc status, wake up DMC and make sure that DMC has properly woken up well 1 before we read for the final value. References: https://bugs.freedesktop.org/show_bug.cgi?id=93768 Suggested-by: Patrik Jakobsson Cc: Patrik Jakobsson Cc: Imre Deak Cc: Chris Wilson Signed-off-by: Mika Kuoppala --- drivers/gpu/drm/i915/intel_runtime_pm.c | 86 ++++++++++++++++++++++++++------- 1 file changed, 69 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index bbca527184d0..83c24e73cb88 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -418,15 +418,62 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv, BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS)) | \ BIT(POWER_DOMAIN_INIT)) + +static bool __gen9_power_well_enabled(struct drm_i915_private *dev_priv, + const enum skl_disp_power_wells pw, + const bool req) +{ + uint32_t mask = SKL_POWER_WELL_STATE(pw); + + if (req) + mask |= SKL_POWER_WELL_REQ(pw); + + return (I915_READ(HSW_PWR_WELL_DRIVER) & mask) == mask; +} + +static bool gen9_power_well_enabled(struct drm_i915_private *dev_priv, + const enum skl_disp_power_wells pw) +{ + return __gen9_power_well_enabled(dev_priv, pw, true); +} + +static bool gen9_power_well_enabled_noreq(struct drm_i915_private *dev_priv, + const enum skl_disp_power_wells pw) +{ + return __gen9_power_well_enabled(dev_priv, pw, false); +} + +static bool gen9_pw1_enabled(struct drm_i915_private *dev_priv) +{ + /* DMC owns the pw1. Don't check for request */ + return gen9_power_well_enabled_noreq(dev_priv, SKL_DISP_PW_1); +} + +static u32 gen9_get_dc_state(struct drm_i915_private *dev_priv) +{ + if (gen9_pw1_enabled(dev_priv)) + return I915_READ(DC_STATE_EN); + + /* DMC should snoop this and wakeup */ + I915_READ(DC_STATE_EN); + + if (wait_for(gen9_pw1_enabled(dev_priv), 1)) + DRM_ERROR("pw1 enabling timeout 0x%x\n", + I915_READ(HSW_PWR_WELL_DRIVER)); + + return I915_READ(DC_STATE_EN); +} + static void assert_can_enable_dc9(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; + const u32 dc_state = gen9_get_dc_state(dev_priv); WARN(!IS_BROXTON(dev), "Platform doesn't support DC9.\n"); - WARN((I915_READ(DC_STATE_EN) & DC_STATE_EN_DC9), - "DC9 already programmed to be enabled.\n"); - WARN(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5, - "DC5 still not disabled to enable DC9.\n"); + WARN(dc_state & DC_STATE_EN_DC9, + "DC9 already programmed to be enabled.\n"); + WARN(dc_state & DC_STATE_EN_UPTO_DC5, + "DC5 still not disabled to enable DC9.\n"); WARN(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on.\n"); WARN(intel_irqs_enabled(dev_priv), "Interrupts not disabled yet.\n"); @@ -441,10 +488,12 @@ static void assert_can_enable_dc9(struct drm_i915_private *dev_priv) static void assert_can_disable_dc9(struct drm_i915_private *dev_priv) { + const u32 dc_state = gen9_get_dc_state(dev_priv); + WARN(intel_irqs_enabled(dev_priv), "Interrupts not disabled yet.\n"); - WARN(!(I915_READ(DC_STATE_EN) & DC_STATE_EN_DC9), + WARN(!(dc_state & DC_STATE_EN_DC9), "DC9 already programmed to be disabled.\n"); - WARN(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5, + WARN(dc_state & DC_STATE_EN_UPTO_DC5, "DC5 still not disabled.\n"); /* @@ -491,13 +540,14 @@ static void gen9_set_dc_state(struct drm_i915_private *dev_priv, uint32_t state) if (state & DC_STATE_EN_UPTO_DC5_DC6_MASK) gen9_set_dc_state_debugmask_memory_up(dev_priv); - val = I915_READ(DC_STATE_EN); + val = gen9_get_dc_state(dev_priv); DRM_DEBUG_KMS("Setting DC state from %02x to %02x\n", val & mask, state); val &= ~mask; val |= state; I915_WRITE(DC_STATE_EN, val); - POSTING_READ(DC_STATE_EN); + + WARN_ON((gen9_get_dc_state(dev_priv) & mask) != state); } void bxt_enable_dc9(struct drm_i915_private *dev_priv) @@ -531,13 +581,13 @@ static void assert_can_enable_dc5(struct drm_i915_private *dev_priv) struct drm_device *dev = dev_priv->dev; bool pg2_enabled = intel_display_power_well_is_enabled(dev_priv, SKL_DISP_PW_2); + const u32 dc_state = gen9_get_dc_state(dev_priv); WARN_ONCE(!IS_SKYLAKE(dev) && !IS_KABYLAKE(dev), "Platform doesn't support DC5.\n"); WARN_ONCE(!HAS_RUNTIME_PM(dev), "Runtime PM not enabled.\n"); WARN_ONCE(pg2_enabled, "PG2 not disabled to enable DC5.\n"); - - WARN_ONCE((I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5), + WARN_ONCE(dc_state & DC_STATE_EN_UPTO_DC5, "DC5 already programmed to be enabled.\n"); assert_rpm_wakelock_held(dev_priv); @@ -568,13 +618,14 @@ static void gen9_enable_dc5(struct drm_i915_private *dev_priv) static void assert_can_enable_dc6(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; + const u32 dc_state = gen9_get_dc_state(dev_priv); WARN_ONCE(!IS_SKYLAKE(dev) && !IS_KABYLAKE(dev), "Platform doesn't support DC6.\n"); WARN_ONCE(!HAS_RUNTIME_PM(dev), "Runtime PM not enabled.\n"); WARN_ONCE(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE, "Backlight is not disabled.\n"); - WARN_ONCE((I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC6), + WARN_ONCE(dc_state & DC_STATE_EN_UPTO_DC6, "DC6 already programmed to be enabled.\n"); assert_csr_loaded(dev_priv); @@ -589,7 +640,7 @@ static void assert_can_disable_dc6(struct drm_i915_private *dev_priv) if (dev_priv->power_domains.initializing) return; - WARN_ONCE(!(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC6), + WARN_ONCE(!(gen9_get_dc_state(dev_priv) & DC_STATE_EN_UPTO_DC6), "DC6 already programmed to be disabled.\n"); } @@ -732,10 +783,7 @@ static void hsw_power_well_disable(struct drm_i915_private *dev_priv, static bool skl_power_well_enabled(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - uint32_t mask = SKL_POWER_WELL_REQ(power_well->data) | - SKL_POWER_WELL_STATE(power_well->data); - - return (I915_READ(HSW_PWR_WELL_DRIVER) & mask) == mask; + return gen9_power_well_enabled(dev_priv, power_well->data); } static void skl_power_well_sync_hw(struct drm_i915_private *dev_priv, @@ -762,7 +810,11 @@ static void skl_power_well_disable(struct drm_i915_private *dev_priv, static bool gen9_dc_off_power_well_enabled(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - return (I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5_DC6_MASK) == 0; + if (gen9_pw1_enabled(dev_priv)) + return (I915_READ(DC_STATE_EN) & + DC_STATE_EN_UPTO_DC5_DC6_MASK) == 0; + + return true; } static void gen9_dc_off_power_well_enable(struct drm_i915_private *dev_priv,