Starting with Haswell, DDI ports can work in FDI mode to support
connectivity with the outputs located on the PCH.

This commit adds support for such connections in the intel_ddi module, and
provides Haswell-specific functionality to make it work.

Signed-off-by: Eugeni Dodonov <[email protected]>
---
 drivers/gpu/drm/i915/intel_ddi.c     |  121 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_display.c |    3 +
 drivers/gpu/drm/i915/intel_drv.h     |    1 +
 drivers/gpu/drm/i915/intel_pm.c      |   10 +++
 4 files changed, 135 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 32594a8..93436caa 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -109,3 +109,124 @@ void intel_prepare_ddi(struct drm_device *dev)
                intel_prepare_ddi_buffers(dev, PORT_E, true);
        }
 }
+
+static const long hsw_ddi_buf_ctl_values[] = {
+       DDI_BUF_EMP_400MV_0DB_HSW,
+       DDI_BUF_EMP_400MV_3_5DB_HSW,
+       DDI_BUF_EMP_400MV_6DB_HSW,
+       DDI_BUF_EMP_400MV_9_5DB_HSW,
+       DDI_BUF_EMP_600MV_0DB_HSW,
+       DDI_BUF_EMP_600MV_3_5DB_HSW,
+       DDI_BUF_EMP_600MV_6DB_HSW,
+       DDI_BUF_EMP_800MV_0DB_HSW,
+       DDI_BUF_EMP_800MV_3_5DB_HSW
+};
+
+
+/* Link training for Haswell DDI port to work in FDI mode */
+static void hsw_fdi_link_train(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       u32 reg, temp, i;
+
+       /* Configure CPU PLL, wait for warmup */
+       I915_WRITE(SPLL_CTL,
+                       SPLL_PLL_ENABLE |
+                       SPLL_PLL_FREQ_1350MHz |
+                       SPLL_PLL_SCC);
+
+       /* Use SPLL to drive the output when in FDI mode */
+       I915_WRITE(PORT_CLK_SEL(PORT_E),
+                       PORT_CLK_SEL_SPLL);
+       I915_WRITE(PIPE_CLK_SEL(pipe),
+                       PIPE_CLK_SEL_PORT(PORT_E));
+
+       udelay(20);
+
+       /* Start the training iterating through available voltages and emphasis 
*/
+       for (i=0; i < ARRAY_SIZE(hsw_ddi_buf_ctl_values); i++) {
+               /* Configure DP_TP_CTL with auto-training */
+               I915_WRITE(DP_TP_CTL(PORT_E),
+                                       DP_TP_CTL_FDI_AUTOTRAIN |
+                                       DP_TP_CTL_ENHANCED_FRAME_ENABLE |
+                                       DP_TP_CTL_LINK_TRAIN_PAT1 |
+                                       DP_TP_CTL_ENABLE);
+
+               /* Configure and enable DDI_BUF_CTL for DDI E with next voltage 
*/
+               temp = I915_READ(DDI_BUF_CTL(PORT_E));
+               temp = (temp & ~DDI_BUF_EMP_MASK);
+               I915_WRITE(DDI_BUF_CTL(PORT_E),
+                               temp |
+                               DDI_BUF_CTL_ENABLE |
+                               DDI_PORT_WIDTH_X2 |
+                               hsw_ddi_buf_ctl_values[i]);
+
+               udelay(600);
+
+               /* Enable CPU FDI Receiver with auto-training */
+               reg = FDI_RX_CTL(pipe);
+               I915_WRITE(reg,
+                               I915_READ(reg) |
+                                       FDI_LINK_TRAIN_AUTO |
+                                       FDI_RX_ENABLE |
+                                       FDI_LINK_TRAIN_PATTERN_1_CPT |
+                                       FDI_RX_ENHANCE_FRAME_ENABLE |
+                                       FDI_PORT_WIDTH_2X_LPT |
+                                       FDI_RX_PLL_ENABLE);
+               POSTING_READ(reg);
+               udelay(100);
+
+               temp = I915_READ(DP_TP_STATUS(PORT_E));
+               if (temp & DP_TP_STATUS_AUTOTRAIN_DONE) {
+                       DRM_DEBUG_DRIVER("BUF_CTL training done on %d step\n", 
i);
+
+                       /* Enable normal pixel sending for FDI */
+                       I915_WRITE(DP_TP_CTL(PORT_E),
+                                               DP_TP_CTL_FDI_AUTOTRAIN |
+                                               DP_TP_CTL_LINK_TRAIN_NORMAL |
+                                               DP_TP_CTL_ENHANCED_FRAME_ENABLE 
|
+                                               DP_TP_CTL_ENABLE);
+
+                       /* Enable PIPE_DDI_FUNC_CTL for the pipe to work in FDI 
mode */
+                       temp = I915_READ(DDI_FUNC_CTL(pipe));
+                       temp &= ~PIPE_DDI_PORT_MASK;
+                       temp |= PIPE_DDI_SELECT_PORT(PORT_E) |
+                                       PIPE_DDI_MODE_SELECT_FDI |
+                                       PIPE_DDI_FUNC_ENABLE |
+                                       PIPE_DDI_PORT_WIDTH_X2;
+                       I915_WRITE(DDI_FUNC_CTL(pipe),
+                                       temp);
+                       break;
+               } else {
+                       DRM_ERROR("Error training BUF_CTL %d\n", i);
+
+                       /* Disable DP_TP_CTL and FDI_RX_CTL) and retry */
+                       I915_WRITE(DP_TP_CTL(PORT_E),
+                                       I915_READ(DP_TP_CTL(PORT_E)) &
+                                               ~DP_TP_CTL_ENABLE);
+                       I915_WRITE(FDI_RX_CTL(pipe),
+                                       I915_READ(FDI_RX_CTL(pipe)) &
+                                               ~FDI_RX_PLL_ENABLE);
+                       continue;
+               }
+       }
+
+       DRM_DEBUG_KMS("FDI train done.\n");
+}
+
+/* Starting with Haswell, different DDI ports can work in FDI mode for
+ * connection to the PCH-located connectors.
+ *
+ * To avoid exporting generation-specific functions, we abstract the DDI port
+ * training in FDI mode here.
+ */
+void ddi_fdi_link_train(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+
+       if (IS_HASWELL(dev))
+               hsw_fdi_link_train(crtc);
+}
diff --git a/drivers/gpu/drm/i915/intel_display.c 
b/drivers/gpu/drm/i915/intel_display.c
index ad080b7..5be2ff1 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6617,6 +6617,9 @@ static void intel_init_display(struct drm_device *dev)
                        /* FIXME: detect B0+ stepping and use auto training */
                        dev_priv->display.fdi_link_train = 
ivb_manual_fdi_link_train;
                        dev_priv->display.write_eld = ironlake_write_eld;
+               } else if (IS_HASWELL(dev)) {
+                       dev_priv->display.fdi_link_train = ddi_fdi_link_train;
+                       dev_priv->display.write_eld = ironlake_write_eld;
                } else
                        dev_priv->display.update_wm = NULL;
        } else if (IS_VALLEYVIEW(dev)) {
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 8e93d2e..df3536f 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -443,6 +443,7 @@ extern void intel_write_eld(struct drm_encoder *encoder,
                            struct drm_display_mode *mode);
 extern void intel_cpt_verify_modeset(struct drm_device *dev, int pipe);
 extern void intel_prepare_ddi(struct drm_device *dev);
+extern void ddi_fdi_link_train(struct drm_crtc *crtc);
 
 /* For use by IVB LP watermark workaround in intel_sprite.c */
 extern void intel_update_watermarks(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index f87768d..2b437c9 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3055,6 +3055,16 @@ void intel_init_pm(struct drm_device *dev)
                                dev_priv->display.update_wm = NULL;
                        }
                        dev_priv->display.init_clock_gating = 
ivybridge_init_clock_gating;
+               } else if (IS_HASWELL(dev)) {
+                       if (SNB_READ_WM0_LATENCY()) {
+                               dev_priv->display.update_wm = 
sandybridge_update_wm;
+                               dev_priv->display.update_sprite_wm = 
sandybridge_update_sprite_wm;
+                       } else {
+                               DRM_DEBUG_KMS("Failed to read display plane 
latency. "
+                                             "Disable CxSR\n");
+                               dev_priv->display.update_wm = NULL;
+                       }
+                       dev_priv->display.init_clock_gating = 
ivybridge_init_clock_gating;
                } else
                        dev_priv->display.update_wm = NULL;
        } else if (IS_VALLEYVIEW(dev)) {
-- 
1.7.10

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

Reply via email to