[PATCH 40/41] drm/i915: prepare HDMI link for Haswell

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.dodonov at 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



[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux