From: Paulo Zanoni <[email protected]>

This is required to prevent hanging the machine on Haswell. We need to
disable everything so when we start using we only enable/disable
exactly what we are using.

Signed-off-by: Paulo Zanoni <[email protected]>
---
 drivers/gpu/drm/i915/i915_reg.h      |  2 +
 drivers/gpu/drm/i915/intel_ddi.c     | 74 ++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_display.c |  7 ++--
 drivers/gpu/drm/i915/intel_drv.h     |  4 ++
 drivers/gpu/drm/i915/intel_sprite.c  |  6 +--
 5 files changed, 86 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 2eed9d4..ee70588 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -4375,6 +4375,7 @@
 #define  PIPE_DDI_FUNC_ENABLE          (1<<31)
 /* Those bits are ignored by pipe EDP since it can only connect to DDI A */
 #define  PIPE_DDI_PORT_MASK            (7<<28)
+#define  PIPE_DDI_PORT_NONE            (0<<28)
 #define  PIPE_DDI_SELECT_PORT(x)       ((x)<<28)
 #define  PIPE_DDI_MODE_SELECT_MASK     (7<<24)
 #define  PIPE_DDI_MODE_SELECT_HDMI     (0<<24)
@@ -4503,6 +4504,7 @@
 #define  PORT_CLK_SEL_SPLL             (3<<29)
 #define  PORT_CLK_SEL_WRPLL1           (4<<29)
 #define  PORT_CLK_SEL_WRPLL2           (5<<29)
+#define  PORT_CLK_SEL_NONE             (7<<29)
 
 /* Pipe clock selection */
 #define PIPE_CLK_SEL_A                 0x46140
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 18ebf15..b8b7670 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -751,6 +751,20 @@ void intel_ddi_mode_set(struct drm_encoder *encoder,
        intel_hdmi->set_infoframes(encoder, adjusted_mode);
 }
 
+static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv,
+                                   enum port port)
+{
+       uint32_t reg = DDI_BUF_CTL(port);
+       int i;
+
+       for (i = 0; i < 8; i++) {
+               udelay(1);
+               if (I915_READ(reg) & DDI_BUF_IS_IDLE)
+                       return;
+       }
+       DRM_ERROR("Timeout waiting for DDI BUF %c idle bit\n", port_name(port));
+}
+
 void intel_ddi_dpms(struct drm_encoder *encoder, int mode)
 {
        struct drm_device *dev = encoder->dev;
@@ -775,11 +789,71 @@ void intel_ddi_dpms(struct drm_encoder *encoder, int mode)
                        temp);
 }
 
+static void intel_ddi_disable_pipe(struct drm_i915_private *dev_priv,
+                                  enum pipe pipe)
+{
+       uint32_t temp;
+
+       temp = I915_READ(DDI_FUNC_CTL(pipe));
+       temp &= ~(PIPE_DDI_FUNC_ENABLE | PIPE_DDI_PORT_MASK);
+       temp |= PIPE_DDI_PORT_NONE;
+       I915_WRITE(DDI_FUNC_CTL(pipe), temp);
+
+       I915_WRITE(PIPE_CLK_SEL(pipe), PIPE_CLK_SEL_DISABLED);
+}
+
+static void intel_ddi_disable_port(struct drm_i915_private *dev_priv,
+                                  enum port port)
+{
+       uint32_t reg, val;
+
+       reg = DDI_BUF_CTL(port);
+       val = I915_READ(reg);
+       if (val & DDI_BUF_CTL_ENABLE) {
+               val &= ~DDI_BUF_CTL_ENABLE;
+               I915_WRITE(reg, val);
+               intel_wait_ddi_buf_idle(dev_priv, port);
+       }
+
+       switch (I915_READ(PORT_CLK_SEL(port))) {
+       case PORT_CLK_SEL_WRPLL1:
+               reg = WRPLL_CTL1;
+               val = I915_READ(reg) & ~WRPLL_PLL_ENABLE;
+               break;
+       case PORT_CLK_SEL_WRPLL2:
+               reg = WRPLL_CTL2;
+               val = I915_READ(reg) & ~WRPLL_PLL_ENABLE;
+               break;
+       case PORT_CLK_SEL_SPLL:
+               reg = SPLL_CTL;
+               val = I915_READ(reg) & ~SPLL_PLL_ENABLE;
+               break;
+       default: /* LCPLL or none or reserved */
+               reg = 0;
+       }
+
+       if (reg)
+               I915_WRITE(reg, val);
+
+       I915_WRITE(PORT_CLK_SEL(port), PORT_CLK_SEL_NONE);
+}
+
 void intel_ddi_pll_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t lcpll_val, clk_val, temp;
        bool lcpll_needs_change = false;
+       int i;
+
+       /* Reset all pipe clocks and ports so we don't hang the machine later */
+       for (i = PIPE_A; i <= PIPE_C; i++) {
+               intel_disable_plane(dev_priv, i, i);
+               intel_disable_pipe(dev_priv, i);
+               intel_ddi_disable_pipe(dev_priv, i);
+       }
+
+       for (i = PORT_A; i <= PORT_E; i++)
+               intel_ddi_disable_port(dev_priv, i);
 
        /* Check the LCPLL state and fix it if needed. */
        lcpll_val = I915_READ(LCPLL_CTL);
diff --git a/drivers/gpu/drm/i915/intel_display.c 
b/drivers/gpu/drm/i915/intel_display.c
index 11687d2..33eebcb 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1773,8 +1773,7 @@ static void intel_enable_pipe(struct drm_i915_private 
*dev_priv, enum pipe pipe,
  *
  * Will wait until the pipe has shut down before returning.
  */
-static void intel_disable_pipe(struct drm_i915_private *dev_priv,
-                              enum pipe pipe)
+void intel_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)
 {
        int reg;
        u32 val;
@@ -1844,8 +1843,8 @@ static void intel_enable_plane(struct drm_i915_private 
*dev_priv,
  *
  * Disable @plane; should be an independent operation.
  */
-static void intel_disable_plane(struct drm_i915_private *dev_priv,
-                               enum plane plane, enum pipe pipe)
+void intel_disable_plane(struct drm_i915_private *dev_priv,
+                        enum plane plane, enum pipe pipe)
 {
        int reg;
        u32 val;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index cf9a1ad..2578158 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -390,6 +390,10 @@ extern bool intel_encoder_is_pch_edp(struct drm_encoder 
*encoder);
 extern int intel_plane_init(struct drm_device *dev, enum pipe pipe);
 extern void intel_flush_display_plane(struct drm_i915_private *dev_priv,
                                      enum plane plane);
+extern void intel_disable_plane(struct drm_i915_private *dev_priv,
+                               enum plane plane, enum pipe pipe);
+extern void intel_disable_pipe(struct drm_i915_private *dev_priv,
+                              enum pipe pipe);
 
 /* intel_panel.c */
 extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
diff --git a/drivers/gpu/drm/i915/intel_sprite.c 
b/drivers/gpu/drm/i915/intel_sprite.c
index cc8df4d..4737303 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -531,7 +531,7 @@ out:
 }
 
 static int
-intel_disable_plane(struct drm_plane *plane)
+intel_disable_drm_plane(struct drm_plane *plane)
 {
        struct drm_device *dev = plane->dev;
        struct intel_plane *intel_plane = to_intel_plane(plane);
@@ -556,7 +556,7 @@ out:
 static void intel_destroy_plane(struct drm_plane *plane)
 {
        struct intel_plane *intel_plane = to_intel_plane(plane);
-       intel_disable_plane(plane);
+       intel_disable_drm_plane(plane);
        drm_plane_cleanup(plane);
        kfree(intel_plane);
 }
@@ -625,7 +625,7 @@ out_unlock:
 
 static const struct drm_plane_funcs intel_plane_funcs = {
        .update_plane = intel_update_plane,
-       .disable_plane = intel_disable_plane,
+       .disable_plane = intel_disable_drm_plane,
        .destroy = intel_destroy_plane,
 };
 
-- 
1.7.11.2

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to