drm/i915/skl: init/uninit display core as part of the HW power domain state
authorImre Deak <imre.deak@intel.com>
Tue, 17 Nov 2015 15:33:53 +0000 (17:33 +0200)
committerImre Deak <imre.deak@intel.com>
Tue, 17 Nov 2015 18:55:07 +0000 (20:55 +0200)
We need to initialize the display core part early, before initializing
the rest of the display power state. This is also described in the bspec
termed "Display initialization sequence". Atm we run this sequence
during driver loading after power domain HW state initialization which
is too late and during runtime suspend/resume which is unneeded and can
interere with DMC functionality which handles HW resources toggled
by this init/uninit sequence automatically. The init sequence must be
run as the first step of HW power state initialization and during
system resume. The uninit sequence must be run during system suspend.

To address the above move the init sequence to the initial HW power
state setup and the uninit sequence to a new power domains suspend
function called during system suspend.

As part of the init sequence we also have to reprogram the DMC firmware
as it's lost across a system suspend/resume cycle.

After this change CD clock initialization during driver loading will
happen only later after other dependent HW/SW parts are initialized,
while during system resume it will get initialized as the last step of
the init sequence. This distinction can be removed by some refactoring
of platform independent parts. I left this refactoring out from this
series since I didn't want to change non-SKL parts. This is a TODO for
later.

v2:
- fix error path in i915_drm_suspend_late()
- don't try to re-program the DMC firmware if it failed to load

Signed-off-by: Imre Deak <imre.deak@intel.com>
Reviewed-by: Patrik Jakobsson <patrik.jakobsson@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1447774433-20834-1-git-send-email-imre.deak@intel.com
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_runtime_pm.c

index 66e6a1fd27bdcfb432a1fad1655ed8201fc86615..ff7c851445ff21a2081da168b2f4cdada386db9d 100644 (file)
@@ -424,7 +424,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
        if (ret)
                goto cleanup_vga_switcheroo;
 
-       intel_power_domains_init_hw(dev_priv);
+       intel_power_domains_init_hw(dev_priv, false);
 
        intel_csr_ucode_init(dev_priv);
 
index 858d58cfbbd15bec99a799061a8ff1eafa5094b1..8ea1896e3e839e71f53b57d0c594c21a42a0116f 100644 (file)
@@ -704,10 +704,13 @@ static int i915_drm_suspend_late(struct drm_device *drm_dev, bool hibernation)
        struct drm_i915_private *dev_priv = drm_dev->dev_private;
        int ret;
 
+       intel_power_domains_suspend(dev_priv);
+
        ret = intel_suspend_complete(dev_priv);
 
        if (ret) {
                DRM_ERROR("Suspend complete failed: %d\n", ret);
+               intel_power_domains_init_hw(dev_priv, true);
 
                return ret;
        }
@@ -861,7 +864,7 @@ static int i915_drm_resume_early(struct drm_device *dev)
                hsw_disable_pc8(dev_priv);
 
        intel_uncore_sanitize(dev);
-       intel_power_domains_init_hw(dev_priv);
+       intel_power_domains_init_hw(dev_priv, true);
 
        return ret;
 }
@@ -1070,8 +1073,6 @@ static int i915_pm_resume(struct device *dev)
 
 static int skl_suspend_complete(struct drm_i915_private *dev_priv)
 {
-       skl_uninit_cdclk(dev_priv);
-
        if (dev_priv->csr.dmc_payload)
                skl_enable_dc6(dev_priv);
 
@@ -1122,9 +1123,6 @@ static int skl_resume_prepare(struct drm_i915_private *dev_priv)
        if (dev_priv->csr.dmc_payload)
                skl_disable_dc6(dev_priv);
 
-       skl_init_cdclk(dev_priv);
-       intel_csr_load_program(dev_priv);
-
        return 0;
 }
 
index c42d2f3da32ebbdc59acadea9e2535bd717f332b..0dc0fc37e6f6dda07e49eacec18061e1ede28020 100644 (file)
@@ -5712,23 +5712,12 @@ void skl_uninit_cdclk(struct drm_i915_private *dev_priv)
                if (wait_for(!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_LOCK), 1))
                        DRM_ERROR("Couldn't disable DPLL0\n");
        }
-
-       /* disable PG1 and Misc I/O */
-       skl_pw1_misc_io_fini(dev_priv);
 }
 
 void skl_init_cdclk(struct drm_i915_private *dev_priv)
 {
-       u32 val;
        unsigned int required_vco;
 
-       /* enable PCH reset handshake */
-       val = I915_READ(HSW_NDE_RSTWRN_OPT);
-       I915_WRITE(HSW_NDE_RSTWRN_OPT, val | RESET_PCH_HANDSHAKE_ENABLE);
-
-       /* enable PG1 and Misc I/O */
-       skl_pw1_misc_io_init(dev_priv);
-
        /* DPLL0 not enabled (happens on early BIOS versions) */
        if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE)) {
                /* enable DPLL0 */
index ddb38b1853668ad124d595ae5c982345dd18dad3..8376a35daf2967de566805b9345b7e74a9faaf84 100644 (file)
@@ -1412,7 +1412,8 @@ void intel_psr_single_frame_update(struct drm_device *dev,
 /* intel_runtime_pm.c */
 int intel_power_domains_init(struct drm_i915_private *);
 void intel_power_domains_fini(struct drm_i915_private *);
-void intel_power_domains_init_hw(struct drm_i915_private *dev_priv);
+void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume);
+void intel_power_domains_suspend(struct drm_i915_private *dev_priv);
 void skl_pw1_misc_io_init(struct drm_i915_private *dev_priv);
 void skl_pw1_misc_io_fini(struct drm_i915_private *dev_priv);
 void intel_runtime_pm_enable(struct drm_i915_private *dev_priv);
index 3045e8b6ee00ca760cc38b33567ce65cb9a72480..42254b76be0ad9f184c2431938fd7af4de07dd26 100644 (file)
@@ -1903,6 +1903,43 @@ static void intel_power_domains_sync_hw(struct drm_i915_private *dev_priv)
        mutex_unlock(&power_domains->lock);
 }
 
+static void skl_display_core_init(struct drm_i915_private *dev_priv,
+                                 bool resume)
+{
+       struct i915_power_domains *power_domains = &dev_priv->power_domains;
+       uint32_t val;
+
+       /* enable PCH reset handshake */
+       val = I915_READ(HSW_NDE_RSTWRN_OPT);
+       I915_WRITE(HSW_NDE_RSTWRN_OPT, val | RESET_PCH_HANDSHAKE_ENABLE);
+
+       /* enable PG1 and Misc I/O */
+       mutex_lock(&power_domains->lock);
+       skl_pw1_misc_io_init(dev_priv);
+       mutex_unlock(&power_domains->lock);
+
+       if (!resume)
+               return;
+
+       skl_init_cdclk(dev_priv);
+
+       if (dev_priv->csr.dmc_payload)
+               intel_csr_load_program(dev_priv);
+}
+
+static void skl_display_core_uninit(struct drm_i915_private *dev_priv)
+{
+       struct i915_power_domains *power_domains = &dev_priv->power_domains;
+
+       skl_uninit_cdclk(dev_priv);
+
+       /* The spec doesn't call for removing the reset handshake flag */
+       /* disable PG1 and Misc I/O */
+       mutex_lock(&power_domains->lock);
+       skl_pw1_misc_io_fini(dev_priv);
+       mutex_unlock(&power_domains->lock);
+}
+
 static void chv_phy_control_init(struct drm_i915_private *dev_priv)
 {
        struct i915_power_well *cmn_bc =
@@ -2025,14 +2062,16 @@ static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv)
  * This function initializes the hardware power domain state and enables all
  * power domains using intel_display_set_init_power().
  */
-void intel_power_domains_init_hw(struct drm_i915_private *dev_priv)
+void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume)
 {
        struct drm_device *dev = dev_priv->dev;
        struct i915_power_domains *power_domains = &dev_priv->power_domains;
 
        power_domains->initializing = true;
 
-       if (IS_CHERRYVIEW(dev)) {
+       if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
+               skl_display_core_init(dev_priv, resume);
+       } else if (IS_CHERRYVIEW(dev)) {
                mutex_lock(&power_domains->lock);
                chv_phy_control_init(dev_priv);
                mutex_unlock(&power_domains->lock);
@@ -2048,6 +2087,19 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv)
        power_domains->initializing = false;
 }
 
+/**
+ * intel_power_domains_suspend - suspend power domain state
+ * @dev_priv: i915 device instance
+ *
+ * This function prepares the hardware power domain state before entering
+ * system suspend. It must be paired with intel_power_domains_init_hw().
+ */
+void intel_power_domains_suspend(struct drm_i915_private *dev_priv)
+{
+       if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
+               skl_display_core_uninit(dev_priv);
+}
+
 /**
  * intel_aux_display_runtime_get - grab an auxiliary power domain reference
  * @dev_priv: i915 device instance