diff options
| author | Paulo Zanoni <paulo.r.zanoni@intel.com> | 2012-10-15 14:51:41 -0400 |
|---|---|---|
| committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2012-10-18 15:24:07 -0400 |
| commit | c19b0669925cb00dc1c7b2362bfa85128afba882 (patch) | |
| tree | bcb01c8ebe663e2a95f992ea71a612987f2df5ae | |
| parent | 1eb8dfec8dea44610dbaceea0151b3d1a8591fde (diff) | |
drm/i915: implement Haswell DP link train sequence
Previous patch "drm/i915: add basic Haswell DP link train bits"
implemented the basic structure to set the voltage levels and training
patterns. This patch adds the higher-level bits that are part of the
mode set sequence and hot plug.
Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Reviewed-by: Damien Lespiau <damien.lespiau@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
| -rw-r--r-- | drivers/gpu/drm/i915/intel_ddi.c | 53 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_dp.c | 32 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 4 |
3 files changed, 81 insertions, 8 deletions
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 601ffc277a35..81cca482c9dc 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c | |||
| @@ -1108,14 +1108,23 @@ void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc) | |||
| 1108 | 1108 | ||
| 1109 | void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) | 1109 | void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) |
| 1110 | { | 1110 | { |
| 1111 | struct drm_crtc *crtc = intel_encoder->base.crtc; | 1111 | struct drm_encoder *encoder = &intel_encoder->base; |
| 1112 | struct drm_i915_private *dev_priv = crtc->dev->dev_private; | 1112 | struct drm_crtc *crtc = encoder->crtc; |
| 1113 | struct drm_i915_private *dev_priv = encoder->dev->dev_private; | ||
| 1113 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | 1114 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
| 1114 | enum port port = intel_ddi_get_encoder_port(intel_encoder); | 1115 | enum port port = intel_ddi_get_encoder_port(intel_encoder); |
| 1115 | 1116 | ||
| 1116 | WARN_ON(intel_crtc->ddi_pll_sel == PORT_CLK_SEL_NONE); | 1117 | WARN_ON(intel_crtc->ddi_pll_sel == PORT_CLK_SEL_NONE); |
| 1117 | 1118 | ||
| 1118 | I915_WRITE(PORT_CLK_SEL(port), intel_crtc->ddi_pll_sel); | 1119 | I915_WRITE(PORT_CLK_SEL(port), intel_crtc->ddi_pll_sel); |
| 1120 | |||
| 1121 | if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) { | ||
| 1122 | struct intel_dp *intel_dp = enc_to_intel_dp(encoder); | ||
| 1123 | |||
| 1124 | intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); | ||
| 1125 | intel_dp_start_link_train(intel_dp); | ||
| 1126 | intel_dp_complete_link_train(intel_dp); | ||
| 1127 | } | ||
| 1119 | } | 1128 | } |
| 1120 | 1129 | ||
| 1121 | static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, | 1130 | static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, |
| @@ -1210,3 +1219,43 @@ void intel_ddi_pll_init(struct drm_device *dev) | |||
| 1210 | if (val & LCPLL_PLL_DISABLE) | 1219 | if (val & LCPLL_PLL_DISABLE) |
| 1211 | DRM_ERROR("LCPLL is disabled\n"); | 1220 | DRM_ERROR("LCPLL is disabled\n"); |
| 1212 | } | 1221 | } |
| 1222 | |||
| 1223 | void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder) | ||
| 1224 | { | ||
| 1225 | struct intel_dp *intel_dp = enc_to_intel_dp(encoder); | ||
| 1226 | struct drm_i915_private *dev_priv = encoder->dev->dev_private; | ||
| 1227 | enum port port = intel_dp->port; | ||
| 1228 | bool wait; | ||
| 1229 | uint32_t val; | ||
| 1230 | |||
| 1231 | if (I915_READ(DP_TP_CTL(port)) & DP_TP_CTL_ENABLE) { | ||
| 1232 | val = I915_READ(DDI_BUF_CTL(port)); | ||
| 1233 | if (val & DDI_BUF_CTL_ENABLE) { | ||
| 1234 | val &= ~DDI_BUF_CTL_ENABLE; | ||
| 1235 | I915_WRITE(DDI_BUF_CTL(port), val); | ||
| 1236 | wait = true; | ||
| 1237 | } | ||
| 1238 | |||
| 1239 | val = I915_READ(DP_TP_CTL(port)); | ||
| 1240 | val &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK); | ||
| 1241 | val |= DP_TP_CTL_LINK_TRAIN_PAT1; | ||
| 1242 | I915_WRITE(DP_TP_CTL(port), val); | ||
| 1243 | POSTING_READ(DP_TP_CTL(port)); | ||
| 1244 | |||
| 1245 | if (wait) | ||
| 1246 | intel_wait_ddi_buf_idle(dev_priv, port); | ||
| 1247 | } | ||
| 1248 | |||
| 1249 | val = DP_TP_CTL_ENABLE | DP_TP_CTL_MODE_SST | | ||
| 1250 | DP_TP_CTL_LINK_TRAIN_PAT1 | DP_TP_CTL_SCRAMBLE_DISABLE; | ||
| 1251 | if (intel_dp->link_configuration[1] & DP_LANE_COUNT_ENHANCED_FRAME_EN) | ||
| 1252 | val |= DP_TP_CTL_ENHANCED_FRAME_ENABLE; | ||
| 1253 | I915_WRITE(DP_TP_CTL(port), val); | ||
| 1254 | POSTING_READ(DP_TP_CTL(port)); | ||
| 1255 | |||
| 1256 | intel_dp->DP |= DDI_BUF_CTL_ENABLE; | ||
| 1257 | I915_WRITE(DDI_BUF_CTL(port), intel_dp->DP); | ||
| 1258 | POSTING_READ(DDI_BUF_CTL(port)); | ||
| 1259 | |||
| 1260 | udelay(600); | ||
| 1261 | } | ||
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index db6ef136a1b6..f6d86492ba3e 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c | |||
| @@ -102,8 +102,6 @@ bool intel_encoder_is_pch_edp(struct drm_encoder *encoder) | |||
| 102 | return is_pch_edp(intel_dp); | 102 | return is_pch_edp(intel_dp); |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | static void intel_dp_start_link_train(struct intel_dp *intel_dp); | ||
| 106 | static void intel_dp_complete_link_train(struct intel_dp *intel_dp); | ||
| 107 | static void intel_dp_link_down(struct intel_dp *intel_dp); | 105 | static void intel_dp_link_down(struct intel_dp *intel_dp); |
| 108 | 106 | ||
| 109 | void | 107 | void |
| @@ -1266,7 +1264,7 @@ static void ironlake_edp_pll_off(struct intel_dp *intel_dp) | |||
| 1266 | } | 1264 | } |
| 1267 | 1265 | ||
| 1268 | /* If the sink supports it, try to set the power state appropriately */ | 1266 | /* If the sink supports it, try to set the power state appropriately */ |
| 1269 | static void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode) | 1267 | void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode) |
| 1270 | { | 1268 | { |
| 1271 | int ret, i; | 1269 | int ret, i; |
| 1272 | 1270 | ||
| @@ -1854,16 +1852,20 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, | |||
| 1854 | } | 1852 | } |
| 1855 | 1853 | ||
| 1856 | /* Enable corresponding port and start training pattern 1 */ | 1854 | /* Enable corresponding port and start training pattern 1 */ |
| 1857 | static void | 1855 | void |
| 1858 | intel_dp_start_link_train(struct intel_dp *intel_dp) | 1856 | intel_dp_start_link_train(struct intel_dp *intel_dp) |
| 1859 | { | 1857 | { |
| 1860 | struct drm_device *dev = intel_dp->base.base.dev; | 1858 | struct drm_encoder *encoder = &intel_dp->base.base; |
| 1859 | struct drm_device *dev = encoder->dev; | ||
| 1861 | int i; | 1860 | int i; |
| 1862 | uint8_t voltage; | 1861 | uint8_t voltage; |
| 1863 | bool clock_recovery = false; | 1862 | bool clock_recovery = false; |
| 1864 | int voltage_tries, loop_tries; | 1863 | int voltage_tries, loop_tries; |
| 1865 | uint32_t DP = intel_dp->DP; | 1864 | uint32_t DP = intel_dp->DP; |
| 1866 | 1865 | ||
| 1866 | if (IS_HASWELL(dev)) | ||
| 1867 | intel_ddi_prepare_link_retrain(encoder); | ||
| 1868 | |||
| 1867 | /* Write the link configuration data */ | 1869 | /* Write the link configuration data */ |
| 1868 | intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET, | 1870 | intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET, |
| 1869 | intel_dp->link_configuration, | 1871 | intel_dp->link_configuration, |
| @@ -1949,7 +1951,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) | |||
| 1949 | intel_dp->DP = DP; | 1951 | intel_dp->DP = DP; |
| 1950 | } | 1952 | } |
| 1951 | 1953 | ||
| 1952 | static void | 1954 | void |
| 1953 | intel_dp_complete_link_train(struct intel_dp *intel_dp) | 1955 | intel_dp_complete_link_train(struct intel_dp *intel_dp) |
| 1954 | { | 1956 | { |
| 1955 | struct drm_device *dev = intel_dp->base.base.dev; | 1957 | struct drm_device *dev = intel_dp->base.base.dev; |
| @@ -2035,6 +2037,24 @@ intel_dp_link_down(struct intel_dp *intel_dp) | |||
| 2035 | struct drm_i915_private *dev_priv = dev->dev_private; | 2037 | struct drm_i915_private *dev_priv = dev->dev_private; |
| 2036 | uint32_t DP = intel_dp->DP; | 2038 | uint32_t DP = intel_dp->DP; |
| 2037 | 2039 | ||
| 2040 | /* | ||
| 2041 | * DDI code has a strict mode set sequence and we should try to respect | ||
| 2042 | * it, otherwise we might hang the machine in many different ways. So we | ||
| 2043 | * really should be disabling the port only on a complete crtc_disable | ||
| 2044 | * sequence. This function is just called under two conditions on DDI | ||
| 2045 | * code: | ||
| 2046 | * - Link train failed while doing crtc_enable, and on this case we | ||
| 2047 | * really should respect the mode set sequence and wait for a | ||
| 2048 | * crtc_disable. | ||
| 2049 | * - Someone turned the monitor off and intel_dp_check_link_status | ||
| 2050 | * called us. We don't need to disable the whole port on this case, so | ||
| 2051 | * when someone turns the monitor on again, | ||
| 2052 | * intel_ddi_prepare_link_retrain will take care of redoing the link | ||
| 2053 | * train. | ||
| 2054 | */ | ||
| 2055 | if (IS_HASWELL(dev)) | ||
| 2056 | return; | ||
| 2057 | |||
| 2038 | if (WARN_ON((I915_READ(intel_dp->output_reg) & DP_PORT_EN) == 0)) | 2058 | if (WARN_ON((I915_READ(intel_dp->output_reg) & DP_PORT_EN) == 0)) |
| 2039 | return; | 2059 | return; |
| 2040 | 2060 | ||
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d89d428ac6ec..95cbd67ebf97 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
| @@ -423,6 +423,9 @@ void | |||
| 423 | intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, | 423 | intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, |
| 424 | struct drm_display_mode *adjusted_mode); | 424 | struct drm_display_mode *adjusted_mode); |
| 425 | extern void intel_dp_init_link_config(struct intel_dp *intel_dp); | 425 | extern void intel_dp_init_link_config(struct intel_dp *intel_dp); |
| 426 | extern void intel_dp_start_link_train(struct intel_dp *intel_dp); | ||
| 427 | extern void intel_dp_complete_link_train(struct intel_dp *intel_dp); | ||
| 428 | extern void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode); | ||
| 426 | extern bool intel_dpd_is_edp(struct drm_device *dev); | 429 | extern bool intel_dpd_is_edp(struct drm_device *dev); |
| 427 | extern void intel_edp_link_config(struct intel_encoder *, int *, int *); | 430 | extern void intel_edp_link_config(struct intel_encoder *, int *, int *); |
| 428 | extern int intel_edp_target_clock(struct intel_encoder *, | 431 | extern int intel_edp_target_clock(struct intel_encoder *, |
| @@ -599,5 +602,6 @@ extern void intel_ddi_pre_enable(struct intel_encoder *intel_encoder); | |||
| 599 | extern void intel_ddi_post_disable(struct intel_encoder *intel_encoder); | 602 | extern void intel_ddi_post_disable(struct intel_encoder *intel_encoder); |
| 600 | extern void intel_ddi_put_crtc_pll(struct drm_crtc *crtc); | 603 | extern void intel_ddi_put_crtc_pll(struct drm_crtc *crtc); |
| 601 | extern void intel_ddi_set_pipe_settings(struct drm_crtc *crtc); | 604 | extern void intel_ddi_set_pipe_settings(struct drm_crtc *crtc); |
| 605 | extern void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder); | ||
| 602 | 606 | ||
| 603 | #endif /* __INTEL_DRV_H__ */ | 607 | #endif /* __INTEL_DRV_H__ */ |
