aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915
diff options
context:
space:
mode:
authorEugeni Dodonov <eugeni.dodonov@intel.com>2012-05-09 14:37:21 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2012-05-19 16:39:48 -0400
commitc82e4d265d98aed94547435605b5e05f8aae9676 (patch)
tree17669fca135527db282179b89d0925b8bbfec6c6 /drivers/gpu/drm/i915
parent45244b87943b1173353b48854352bb9f4b065867 (diff)
drm/i915: support DDI training in FDI mode
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. v2: simplify the commit as per Daniel Vetter suggestion. Signed-off-by: Eugeni Dodonov <eugeni.dodonov@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915')
-rw-r--r--drivers/gpu/drm/i915/intel_ddi.c115
-rw-r--r--drivers/gpu/drm/i915/intel_display.c2
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h1
3 files changed, 118 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 08f210b8dafa..f44aae124771 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -105,3 +105,118 @@ void intel_prepare_ddi(struct drm_device *dev)
105 intel_prepare_ddi_buffers(dev, PORT_E, true); 105 intel_prepare_ddi_buffers(dev, PORT_E, true);
106 } 106 }
107} 107}
108
109static const long hsw_ddi_buf_ctl_values[] = {
110 DDI_BUF_EMP_400MV_0DB_HSW,
111 DDI_BUF_EMP_400MV_3_5DB_HSW,
112 DDI_BUF_EMP_400MV_6DB_HSW,
113 DDI_BUF_EMP_400MV_9_5DB_HSW,
114 DDI_BUF_EMP_600MV_0DB_HSW,
115 DDI_BUF_EMP_600MV_3_5DB_HSW,
116 DDI_BUF_EMP_600MV_6DB_HSW,
117 DDI_BUF_EMP_800MV_0DB_HSW,
118 DDI_BUF_EMP_800MV_3_5DB_HSW
119};
120
121
122/* Starting with Haswell, different DDI ports can work in FDI mode for
123 * connection to the PCH-located connectors. For this, it is necessary to train
124 * both the DDI port and PCH receiver for the desired DDI buffer settings.
125 *
126 * The recommended port to work in FDI mode is DDI E, which we use here. Also,
127 * please note that when FDI mode is active on DDI E, it shares 2 lines with
128 * DDI A (which is used for eDP)
129 */
130
131void hsw_fdi_link_train(struct drm_crtc *crtc)
132{
133 struct drm_device *dev = crtc->dev;
134 struct drm_i915_private *dev_priv = dev->dev_private;
135 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
136 int pipe = intel_crtc->pipe;
137 u32 reg, temp, i;
138
139 /* Configure CPU PLL, wait for warmup */
140 I915_WRITE(SPLL_CTL,
141 SPLL_PLL_ENABLE |
142 SPLL_PLL_FREQ_1350MHz |
143 SPLL_PLL_SCC);
144
145 /* Use SPLL to drive the output when in FDI mode */
146 I915_WRITE(PORT_CLK_SEL(PORT_E),
147 PORT_CLK_SEL_SPLL);
148 I915_WRITE(PIPE_CLK_SEL(pipe),
149 PIPE_CLK_SEL_PORT(PORT_E));
150
151 udelay(20);
152
153 /* Start the training iterating through available voltages and emphasis */
154 for (i=0; i < ARRAY_SIZE(hsw_ddi_buf_ctl_values); i++) {
155 /* Configure DP_TP_CTL with auto-training */
156 I915_WRITE(DP_TP_CTL(PORT_E),
157 DP_TP_CTL_FDI_AUTOTRAIN |
158 DP_TP_CTL_ENHANCED_FRAME_ENABLE |
159 DP_TP_CTL_LINK_TRAIN_PAT1 |
160 DP_TP_CTL_ENABLE);
161
162 /* Configure and enable DDI_BUF_CTL for DDI E with next voltage */
163 temp = I915_READ(DDI_BUF_CTL(PORT_E));
164 temp = (temp & ~DDI_BUF_EMP_MASK);
165 I915_WRITE(DDI_BUF_CTL(PORT_E),
166 temp |
167 DDI_BUF_CTL_ENABLE |
168 DDI_PORT_WIDTH_X2 |
169 hsw_ddi_buf_ctl_values[i]);
170
171 udelay(600);
172
173 /* Enable CPU FDI Receiver with auto-training */
174 reg = FDI_RX_CTL(pipe);
175 I915_WRITE(reg,
176 I915_READ(reg) |
177 FDI_LINK_TRAIN_AUTO |
178 FDI_RX_ENABLE |
179 FDI_LINK_TRAIN_PATTERN_1_CPT |
180 FDI_RX_ENHANCE_FRAME_ENABLE |
181 FDI_PORT_WIDTH_2X_LPT |
182 FDI_RX_PLL_ENABLE);
183 POSTING_READ(reg);
184 udelay(100);
185
186 temp = I915_READ(DP_TP_STATUS(PORT_E));
187 if (temp & DP_TP_STATUS_AUTOTRAIN_DONE) {
188 DRM_DEBUG_DRIVER("BUF_CTL training done on %d step\n", i);
189
190 /* Enable normal pixel sending for FDI */
191 I915_WRITE(DP_TP_CTL(PORT_E),
192 DP_TP_CTL_FDI_AUTOTRAIN |
193 DP_TP_CTL_LINK_TRAIN_NORMAL |
194 DP_TP_CTL_ENHANCED_FRAME_ENABLE |
195 DP_TP_CTL_ENABLE);
196
197 /* Enable PIPE_DDI_FUNC_CTL for the pipe to work in FDI mode */
198 temp = I915_READ(DDI_FUNC_CTL(pipe));
199 temp &= ~PIPE_DDI_PORT_MASK;
200 temp |= PIPE_DDI_SELECT_PORT(PORT_E) |
201 PIPE_DDI_MODE_SELECT_FDI |
202 PIPE_DDI_FUNC_ENABLE |
203 PIPE_DDI_PORT_WIDTH_X2;
204 I915_WRITE(DDI_FUNC_CTL(pipe),
205 temp);
206 break;
207 } else {
208 DRM_ERROR("Error training BUF_CTL %d\n", i);
209
210 /* Disable DP_TP_CTL and FDI_RX_CTL) and retry */
211 I915_WRITE(DP_TP_CTL(PORT_E),
212 I915_READ(DP_TP_CTL(PORT_E)) &
213 ~DP_TP_CTL_ENABLE);
214 I915_WRITE(FDI_RX_CTL(pipe),
215 I915_READ(FDI_RX_CTL(pipe)) &
216 ~FDI_RX_PLL_ENABLE);
217 continue;
218 }
219 }
220
221 DRM_DEBUG_KMS("FDI train done.\n");
222}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 096a1b1eaf46..3edf8f6ce2f4 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6607,6 +6607,8 @@ static void intel_init_display(struct drm_device *dev)
6607 /* FIXME: detect B0+ stepping and use auto training */ 6607 /* FIXME: detect B0+ stepping and use auto training */
6608 dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train; 6608 dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
6609 dev_priv->display.write_eld = ironlake_write_eld; 6609 dev_priv->display.write_eld = ironlake_write_eld;
6610 } else if (IS_HASWELL(dev)) {
6611 dev_priv->display.fdi_link_train = hsw_fdi_link_train;
6610 } else 6612 } else
6611 dev_priv->display.update_wm = NULL; 6613 dev_priv->display.update_wm = NULL;
6612 } else if (IS_VALLEYVIEW(dev)) { 6614 } else if (IS_VALLEYVIEW(dev)) {
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index e6ce02b57305..a5bb5b6ebb4f 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -447,6 +447,7 @@ extern void intel_write_eld(struct drm_encoder *encoder,
447 struct drm_display_mode *mode); 447 struct drm_display_mode *mode);
448extern void intel_cpt_verify_modeset(struct drm_device *dev, int pipe); 448extern void intel_cpt_verify_modeset(struct drm_device *dev, int pipe);
449extern void intel_prepare_ddi(struct drm_device *dev); 449extern void intel_prepare_ddi(struct drm_device *dev);
450extern void hsw_fdi_link_train(struct drm_crtc *crtc);
450 451
451/* For use by IVB LP watermark workaround in intel_sprite.c */ 452/* For use by IVB LP watermark workaround in intel_sprite.c */
452extern void intel_update_watermarks(struct drm_device *dev); 453extern void intel_update_watermarks(struct drm_device *dev);