From patchwork Mon Oct 14 23:07:47 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jesse Barnes X-Patchwork-Id: 3040981 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id B9029BF924 for ; Mon, 14 Oct 2013 23:28:12 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 70D8C20200 for ; Mon, 14 Oct 2013 23:28:11 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 4EBC1201FD for ; Mon, 14 Oct 2013 23:28:10 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 31F01E640C for ; Mon, 14 Oct 2013 16:28:10 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from oproxy9-pub.mail.unifiedlayer.com (oproxy9-pub.mail.unifiedlayer.com [69.89.24.6]) by gabe.freedesktop.org (Postfix) with SMTP id 12F44E70AA for ; Mon, 14 Oct 2013 16:07:55 -0700 (PDT) Received: (qmail 29401 invoked by uid 0); 14 Oct 2013 23:07:54 -0000 Received: from unknown (HELO box514.bluehost.com) (74.220.219.114) by oproxy9.mail.unifiedlayer.com with SMTP; 14 Oct 2013 23:07:54 -0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=virtuousgeek.org; s=default; h=References:In-Reply-To:Message-Id:Date:Subject:To:From; bh=0mXyfVxJQduhEfqKen41lluUor8lZ1ZTwPNl/wgAPNU=; b=Ho3xvY8HIDjBvFOhx64+q0puuCxkASRaCdE1eokBcMNb0rN4TF7a7noFA4blTpTMRiG2Z/+vKLgqjE4IY3vam81CPu8NHSXkHzCRGvpm2fqfHJPAQlzFvOX9GRy3rg3v; Received: from [67.161.37.189] (port=56824 helo=localhost.localdomain) by box514.bluehost.com with esmtpsa (TLSv1:CAMELLIA256-SHA:256) (Exim 4.80) (envelope-from ) id 1VVrEw-0000hc-Ab for intel-gfx@lists.freedesktop.org; Mon, 14 Oct 2013 17:07:54 -0600 From: Jesse Barnes To: intel-gfx@lists.freedesktop.org Date: Mon, 14 Oct 2013 16:07:47 -0700 Message-Id: <1381792069-27800-4-git-send-email-jbarnes@virtuousgeek.org> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1381792069-27800-1-git-send-email-jbarnes@virtuousgeek.org> References: <1381792069-27800-1-git-send-email-jbarnes@virtuousgeek.org> X-Identified-User: {10642:box514.bluehost.com:virtuous:virtuousgeek.org} {sentby:smtp auth 67.161.37.189 authed with jbarnes@virtuousgeek.org} Subject: [Intel-gfx] [PATCH 3/5] drm/i915/vlv: suspend/resume fixes for VLV/BYT X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: intel-gfx-bounces+patchwork-intel-gfx=patchwork.kernel.org@lists.freedesktop.org Errors-To: intel-gfx-bounces+patchwork-intel-gfx=patchwork.kernel.org@lists.freedesktop.org X-Spam-Status: No, score=-4.6 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,RP_MATCHES_RCVD,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=ham 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 We were missing a few bits around power well handling and Gunit save/restore. The code added should be sufficient for runtime D3 as well (though that requires additional changes to how we handle save/restore of state). Signed-off-by: Jesse Barnes --- drivers/gpu/drm/i915/i915_drv.c | 31 +++++++++ drivers/gpu/drm/i915/i915_drv.h | 11 +++ drivers/gpu/drm/i915/i915_gem.c | 5 +- drivers/gpu/drm/i915/i915_reg.h | 8 +++ drivers/gpu/drm/i915/intel_uncore.c | 133 ++++++++++++++++++++++++++++++++---- 5 files changed, 174 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 82a1d53..01ff272 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -459,6 +459,21 @@ bool i915_semaphore_is_enabled(struct drm_device *dev) return 1; } +/* + * On VLV/BYT, transitioning from D0 to a Dx state requires the following + * steps: + * 1) force enable gfx clocks with GTLC survivability reg + * 2) take force wake ref for register saving (really necessary?) + * 3) save Gunit regs + * 4) drop gfx freq to minimum + * 5) drop force wake ref (not needed if we don't need #2) + * 6) clear allow wake bit (prevents further forcewake requests) + * 7) power gate render, media, and display power wells + * 8) release gfx clocks + * Along with the usual steps of idling the GPU, dealing with display state, + * etc. + */ + static int i915_drm_freeze(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -471,6 +486,7 @@ static int i915_drm_freeze(struct drm_device *dev) /* We do a lot of poking in a lot of registers, make sure they work * properly. */ + intel_uncore_prepare_suspend(dev); hsw_disable_package_c8(dev_priv); intel_set_power_well(dev, true); @@ -515,6 +531,8 @@ static int i915_drm_freeze(struct drm_device *dev) intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED); console_unlock(); + intel_uncore_suspend(dev); + return 0; } @@ -578,6 +596,17 @@ static void intel_resume_hotplug(struct drm_device *dev) drm_helper_hpd_irq_event(dev); } +/* + * On VLV/BYT, the resume steps from a Dx state are as follows: + * 1) force gfx clocks on + * 2) ungate render, media, display power wells + * 3) restore gunit regs + * 4) set allow wake bit in wake control + * 5) take force wake ref on render & media + * 6) re-enable RC6 + * 7) drop force wake ref + * 8) release gfx clocks + */ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -587,6 +616,8 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) intel_uncore_sanitize(dev); + intel_uncore_resume(dev); + if (drm_core_check_feature(dev, DRIVER_MODESET) && restore_gtt_mappings) { mutex_lock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4e97840..85cd5be 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -409,6 +409,9 @@ struct intel_uncore_funcs { enum intel_display_power_domain domain); void (*display_power_put)(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain); + void (*prepare_suspend)(struct drm_i915_private *dev_priv); + void (*suspend)(struct drm_i915_private *dev_priv); + void (*resume)(struct drm_i915_private *dev_priv); }; struct intel_uncore { @@ -842,6 +845,11 @@ struct i915_suspend_saved_registers { u32 savePIPEB_LINK_N1; u32 saveMCHBAR_RENDER_STANDBY; u32 savePCH_PORT_HOTPLUG; + u32 saveGUNIT_Control; + u32 saveGUNIT_Control2; + u32 saveGUNIT_CZClockGatingDisable1; + u32 saveGUNIT_CZClockGatingDisable2; + u32 saveDPIO_CFG_DATA; }; struct intel_gen6_power_mgmt { @@ -1824,6 +1832,9 @@ extern void intel_pm_init(struct drm_device *dev); extern void intel_hpd_init(struct drm_device *dev); extern void intel_pm_init(struct drm_device *dev); +extern void intel_uncore_prepare_suspend(struct drm_device *dev); +extern void intel_uncore_suspend(struct drm_device *dev); +extern void intel_uncore_resume(struct drm_device *dev); extern void intel_uncore_sanitize(struct drm_device *dev); extern void intel_uncore_early_sanitize(struct drm_device *dev); extern void intel_uncore_init(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index eb29a23..bd189d6 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4470,8 +4470,9 @@ int i915_gem_init(struct drm_device *dev) if (IS_VALLEYVIEW(dev)) { /* VLVA0 (potential hack), BIOS isn't actually waking us */ - I915_WRITE(VLV_GTLC_WAKE_CTRL, 1); - if (wait_for((I915_READ(VLV_GTLC_PW_STATUS) & 1) == 1, 10)) + I915_WRITE(VLV_GTLC_WAKE_CTRL, VLV_ALLOW_WAKE_REQ); + if (wait_for((I915_READ(VLV_GTLC_PW_STATUS) & + VLV_ALLOW_WAKE_REQ), 10)) DRM_DEBUG_DRIVER("allow wake ack timed out\n"); } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b64b1a6..cbf3e48 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -791,8 +791,11 @@ #define IIR 0x020a4 #define IMR 0x020a8 #define ISR 0x020ac +#define VLV_GUNIT_CONTROL (VLV_DISPLAY_BASE + 0x2030) +#define VLV_GUNIT_CONTROL2 (VLV_DISPLAY_BASE + 0x2034) #define VLV_GUNIT_CLOCK_GATE (VLV_DISPLAY_BASE + 0x2060) #define GCFG_DIS (1<<8) +#define VLV_GUNIT_CLOCK_GATE2 (VLV_DISPLAY_BASE + 0x2064) #define VLV_IIR_RW (VLV_DISPLAY_BASE + 0x2084) #define VLV_IER (VLV_DISPLAY_BASE + 0x20a0) #define VLV_IIR (VLV_DISPLAY_BASE + 0x20a4) @@ -4644,7 +4647,12 @@ #define FORCEWAKE_ACK_HSW 0x130044 #define FORCEWAKE_ACK 0x130090 #define VLV_GTLC_WAKE_CTRL 0x130090 +#define VLV_ALLOW_WAKE_REQ (1<<0) #define VLV_GTLC_PW_STATUS 0x130094 +#define VLV_ALLOW_WAKE_ACK (1<<0) +#define VLV_GTLC_SURVIVABILITY_REG 0x130098 +#define VLV_GFX_CLK_STATUS (1<<3) +#define VLV_GFX_CLK_FORCE_ON (1<<2) #define FORCEWAKE_MT 0xa188 /* multi-threaded */ #define FORCEWAKE_KERNEL 0x1 #define FORCEWAKE_USER 0x2 diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index ef5d7fd..b126f5a 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -419,10 +419,110 @@ static void vlv_set_media_power(struct drm_i915_private *dev_priv, bool enable) __vlv_set_power_well(dev_priv, MEDIA_PWRGT, enable); } +static void vlv_set_gfx_clock(struct drm_i915_private *dev_priv, bool enable) +{ + u32 reg; + + if (!IS_VALLEYVIEW(dev_priv->dev)) + return; + + reg = I915_READ(VLV_GTLC_SURVIVABILITY_REG); + if (enable) + reg |= VLV_GFX_CLK_FORCE_ON; + else + reg &= ~VLV_GFX_CLK_FORCE_ON; + I915_WRITE(VLV_GTLC_SURVIVABILITY_REG, reg); + if (wait_for_atomic(((VLV_GFX_CLK_STATUS & + I915_READ(VLV_GTLC_SURVIVABILITY_REG)) != 0), + 100)) { + dev_err(&dev_priv->dev->pdev->dev, + "GFX_CLK_ON timed out, suspend might fail\n"); + } +} + +static void vlv_gunit_save(struct drm_i915_private *dev_priv) +{ + dev_priv->regfile.saveGUNIT_Control = I915_READ(VLV_GUNIT_CONTROL); + dev_priv->regfile.saveGUNIT_Control2 = I915_READ(VLV_GUNIT_CONTROL2); + dev_priv->regfile.saveGUNIT_CZClockGatingDisable1 = + I915_READ(VLV_GUNIT_CLOCK_GATE); + dev_priv->regfile.saveGUNIT_CZClockGatingDisable2 = + I915_READ(VLV_GUNIT_CLOCK_GATE2); + dev_priv->regfile.saveDPIO_CFG_DATA = I915_READ(DPIO_CTL); +} + +static void vlv_gunit_restore(struct drm_i915_private *dev_priv) +{ + I915_WRITE(VLV_GUNIT_CONTROL, dev_priv->regfile.saveGUNIT_Control); + I915_WRITE(VLV_GUNIT_CONTROL2, dev_priv->regfile.saveGUNIT_Control2); + I915_WRITE(VLV_GUNIT_CLOCK_GATE, + dev_priv->regfile.saveGUNIT_CZClockGatingDisable1); + I915_WRITE(VLV_GUNIT_CLOCK_GATE2, + dev_priv->regfile.saveGUNIT_CZClockGatingDisable2); + I915_WRITE(DPIO_CTL, dev_priv->regfile.saveDPIO_CFG_DATA); +} + +static void vlv_uncore_prepare_suspend(struct drm_i915_private *dev_priv) +{ + vlv_set_gfx_clock(dev_priv, true); + vlv_gunit_save(dev_priv); +} + +static void vlv_uncore_suspend(struct drm_i915_private *dev_priv) +{ + u32 reg; + + mutex_lock(&dev_priv->rps.hw_lock); + valleyview_set_rps(dev_priv->dev, dev_priv->rps.min_delay); + mutex_unlock(&dev_priv->rps.hw_lock); + + reg = I915_READ(VLV_GTLC_WAKE_CTRL); + reg &= ~VLV_ALLOW_WAKE_REQ; + I915_WRITE(VLV_GTLC_WAKE_CTRL, reg); + if (wait_for_atomic(!(I915_READ(VLV_GTLC_PW_STATUS) & + VLV_ALLOW_WAKE_ACK), 100)) { + dev_err(&dev_priv->dev->pdev->dev, + "ALLOW_WAKE_SET timed out, suspend might fail\n"); + } + + intel_set_power_well(dev_priv->dev, false); + + vlv_set_display_power(dev_priv, false); + vlv_set_render_power(dev_priv, false); + vlv_set_media_power(dev_priv, false); + + vlv_set_gfx_clock(dev_priv, false); +} + +static void vlv_uncore_resume(struct drm_i915_private *dev_priv) +{ + u32 reg; + + vlv_gunit_restore(dev_priv); + + reg = I915_READ(VLV_GTLC_WAKE_CTRL); + reg |= VLV_ALLOW_WAKE_REQ; + I915_WRITE(VLV_GTLC_WAKE_CTRL, reg); + if (wait_for_atomic((0 != (I915_READ(VLV_GTLC_PW_STATUS) & + VLV_ALLOW_WAKE_ACK)), 100)) { + dev_err(&dev_priv->dev->pdev->dev, + "ALLOW_WAKE_SET timed out, resume might fail\n"); + } + + vlv_set_gfx_clock(dev_priv, false); +} + void intel_uncore_early_sanitize(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + if (IS_VALLEYVIEW(dev)) { + vlv_set_gfx_clock(dev_priv, true); + vlv_set_display_power(dev_priv, true); + vlv_set_render_power(dev_priv, true); + vlv_set_media_power(dev_priv, true); + } + if (HAS_FPGA_DBG_UNCLAIMED(dev)) __raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM); } @@ -441,6 +541,9 @@ void intel_uncore_init(struct drm_device *dev) dev_priv->uncore.funcs.display_power_enabled = vlv_display_power_enabled; dev_priv->uncore.funcs.display_power_get = vlv_display_power_get; dev_priv->uncore.funcs.display_power_put = vlv_display_power_put; + dev_priv->uncore.funcs.prepare_suspend = vlv_uncore_prepare_suspend; + dev_priv->uncore.funcs.suspend = vlv_uncore_suspend; + dev_priv->uncore.funcs.resume = vlv_uncore_resume; } else if (IS_HASWELL(dev)) { dev_priv->uncore.funcs.force_wake_get = __gen6_gt_force_wake_mt_get; dev_priv->uncore.funcs.force_wake_put = __gen6_gt_force_wake_mt_put; @@ -512,26 +615,32 @@ static void intel_uncore_forcewake_reset(struct drm_device *dev) void intel_uncore_sanitize(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; - u32 reg_val; - intel_uncore_forcewake_reset(dev); /* BIOS often leaves RC6 enabled, but disable it for hw init */ intel_disable_gt_powersave(dev); +} - /* Turn off power gate, require especially for the BIOS less system */ - if (IS_VALLEYVIEW(dev)) { - - mutex_lock(&dev_priv->rps.hw_lock); - reg_val = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS); - if (reg_val & (RENDER_PWRGT | MEDIA_PWRGT | DISP2D_PWRGT)) - vlv_punit_write(dev_priv, PUNIT_REG_PWRGT_CTRL, 0x0); +void intel_uncore_prepare_suspend(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + if (dev_priv->uncore.funcs.prepare_suspend) + dev_priv->uncore.funcs.prepare_suspend(dev_priv); +} - mutex_unlock(&dev_priv->rps.hw_lock); +void intel_uncore_suspend(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + if (dev_priv->uncore.funcs.suspend) + dev_priv->uncore.funcs.suspend(dev_priv); +} - } +void intel_uncore_resume(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + if (dev_priv->uncore.funcs.resume) + dev_priv->uncore.funcs.resume(dev_priv); } /*