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 <jbar...@virtuousgeek.org>
---
 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);
 }
 
 /*
-- 
1.8.3.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to