On Haswell, we need to properly train the DDI buffers prior to enabling
HDMI.

Note that we do enable the DDI Function for the corresponding pipe, in a
similar fashion as we do with FDI. This ensures that the pipe DDI
transport is left in a almost-ready state, and we only need to enable the
pipe afterwards to get a working modesetting.

Signed-off-by: Eugeni Dodonov <eugeni.dodo...@intel.com>
---
 drivers/gpu/drm/i915/intel_hdmi.c |   63 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 62 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_hdmi.c 
b/drivers/gpu/drm/i915/intel_hdmi.c
index 6921756..480f54b 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -324,6 +324,67 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder 
*encoder,
        return true;
 }
 
+static void intel_hdmi_prepare(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc = encoder->crtc;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+       int port = intel_hdmi->ddi_port;
+       int pipe = intel_crtc->pipe;
+       u32 reg, temp;
+
+       /* On Haswell, we need to enable the clocks and prepare DDI function to
+        * work in HDMI mode for this pipe.
+        */
+       if (IS_HASWELL(encoder->dev)) {
+               DRM_DEBUG_KMS("Preparing HDMI DDI mode for Haswell on port %c, 
pipe %c\n", port_name(port), pipe_name(pipe));
+
+               /* Enable LCPLL if disabled */
+               reg = I915_READ(LCPLL_CTL);
+               if (reg & LCPLL_PLL_DISABLE)
+                       I915_WRITE(LCPLL_CTL,
+                                       reg & ~LCPLL_PLL_DISABLE);
+
+               /* Configure CPU PLL, wait for warmup */
+               I915_WRITE(WRPLL_CTL1,
+                               WRPLL_PLL_ENABLE |
+                               WRPLL_PLL_SELECT_LCPLL_2700);
+
+               udelay(20);
+
+               /* Use WRPLL1 clock to drive the output to the port, and tell 
the pipe to use
+                * this port for connection.
+                */
+               I915_WRITE(PORT_CLK_SEL(port),
+                               PORT_CLK_SEL_WRPLL1);
+               I915_WRITE(PIPE_CLK_SEL(pipe),
+                               PIPE_CLK_SEL_PORT(port));
+
+               udelay(20);
+
+               /* Enable PIPE_DDI_FUNC_CTL for the pipe to work in HDMI mode */
+               temp = I915_READ(DDI_FUNC_CTL(pipe));
+               temp &= ~PIPE_DDI_PORT_MASK;
+               temp |= PIPE_DDI_SELECT_PORT(port) |
+                               PIPE_DDI_MODE_SELECT_HDMI |
+                               PIPE_DDI_FUNC_ENABLE;
+               I915_WRITE(DDI_FUNC_CTL(pipe),
+                                       temp);
+
+               /* Enable DDI_BUF_CTL. In HDMI/DVI mode, the port width,
+                * and swing/emphasis values are ignored so nothing special 
needs
+                * to be done besides enabling the port.
+                */
+               I915_WRITE(DDI_BUF_CTL(port),
+                               I915_READ(DDI_BUF_CTL(port)) |
+                                       DDI_BUF_CTL_ENABLE);
+       }
+
+       return intel_encoder_prepare(encoder);
+}
+
 static enum drm_connector_status
 intel_hdmi_detect(struct drm_connector *connector, bool force)
 {
@@ -457,7 +518,7 @@ static void intel_hdmi_destroy(struct drm_connector 
*connector)
 static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = {
        .dpms = intel_hdmi_dpms,
        .mode_fixup = intel_hdmi_mode_fixup,
-       .prepare = intel_encoder_prepare,
+       .prepare = intel_hdmi_prepare,
        .mode_set = intel_hdmi_mode_set,
        .commit = intel_encoder_commit,
 };
-- 
1.7.9.5

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

Reply via email to