1 // SPDX-License-Identifier: MIT
3 * Copyright © 2020 Intel Corporation
5 #include "intel_atomic.h"
6 #include "intel_display_types.h"
10 static int pipe_required_fdi_lanes(struct intel_crtc_state *crtc_state)
12 if (crtc_state->hw.enable && crtc_state->has_pch_encoder)
13 return crtc_state->fdi_lanes;
18 static int ilk_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
19 struct intel_crtc_state *pipe_config)
21 struct drm_i915_private *dev_priv = to_i915(dev);
22 struct drm_atomic_state *state = pipe_config->uapi.state;
23 struct intel_crtc *other_crtc;
24 struct intel_crtc_state *other_crtc_state;
26 drm_dbg_kms(&dev_priv->drm,
27 "checking fdi config on pipe %c, lanes %i\n",
28 pipe_name(pipe), pipe_config->fdi_lanes);
29 if (pipe_config->fdi_lanes > 4) {
30 drm_dbg_kms(&dev_priv->drm,
31 "invalid fdi lane config on pipe %c: %i lanes\n",
32 pipe_name(pipe), pipe_config->fdi_lanes);
36 if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
37 if (pipe_config->fdi_lanes > 2) {
38 drm_dbg_kms(&dev_priv->drm,
39 "only 2 lanes on haswell, required: %i lanes\n",
40 pipe_config->fdi_lanes);
47 if (INTEL_NUM_PIPES(dev_priv) == 2)
50 /* Ivybridge 3 pipe is really complicated */
55 if (pipe_config->fdi_lanes <= 2)
58 other_crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_C);
60 intel_atomic_get_crtc_state(state, other_crtc);
61 if (IS_ERR(other_crtc_state))
62 return PTR_ERR(other_crtc_state);
64 if (pipe_required_fdi_lanes(other_crtc_state) > 0) {
65 drm_dbg_kms(&dev_priv->drm,
66 "invalid shared fdi lane config on pipe %c: %i lanes\n",
67 pipe_name(pipe), pipe_config->fdi_lanes);
72 if (pipe_config->fdi_lanes > 2) {
73 drm_dbg_kms(&dev_priv->drm,
74 "only 2 lanes on pipe %c: required %i lanes\n",
75 pipe_name(pipe), pipe_config->fdi_lanes);
79 other_crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_B);
81 intel_atomic_get_crtc_state(state, other_crtc);
82 if (IS_ERR(other_crtc_state))
83 return PTR_ERR(other_crtc_state);
85 if (pipe_required_fdi_lanes(other_crtc_state) > 2) {
86 drm_dbg_kms(&dev_priv->drm,
87 "fdi link B uses too many lanes to enable link C\n");
96 int ilk_fdi_compute_config(struct intel_crtc *intel_crtc,
97 struct intel_crtc_state *pipe_config)
99 struct drm_device *dev = intel_crtc->base.dev;
100 struct drm_i915_private *i915 = to_i915(dev);
101 const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
102 int lane, link_bw, fdi_dotclock, ret;
103 bool needs_recompute = false;
106 /* FDI is a binary signal running at ~2.7GHz, encoding
107 * each output octet as 10 bits. The actual frequency
108 * is stored as a divider into a 100MHz clock, and the
109 * mode pixel clock is stored in units of 1KHz.
110 * Hence the bw of each lane in terms of the mode signal
113 link_bw = intel_fdi_link_freq(i915, pipe_config);
115 fdi_dotclock = adjusted_mode->crtc_clock;
117 lane = ilk_get_lanes_required(fdi_dotclock, link_bw,
118 pipe_config->pipe_bpp);
120 pipe_config->fdi_lanes = lane;
122 intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock,
123 link_bw, &pipe_config->fdi_m_n, false, false);
125 ret = ilk_check_fdi_lanes(dev, intel_crtc->pipe, pipe_config);
129 if (ret == -EINVAL && pipe_config->pipe_bpp > 6*3) {
130 pipe_config->pipe_bpp -= 2*3;
131 drm_dbg_kms(&i915->drm,
132 "fdi link bw constraint, reducing pipe bpp to %i\n",
133 pipe_config->pipe_bpp);
134 needs_recompute = true;
135 pipe_config->bw_constrained = true;
141 return I915_DISPLAY_CONFIG_RETRY;
146 void intel_fdi_normal_train(struct intel_crtc *crtc)
148 struct drm_device *dev = crtc->base.dev;
149 struct drm_i915_private *dev_priv = to_i915(dev);
150 enum pipe pipe = crtc->pipe;
154 /* enable normal train */
155 reg = FDI_TX_CTL(pipe);
156 temp = intel_de_read(dev_priv, reg);
157 if (IS_IVYBRIDGE(dev_priv)) {
158 temp &= ~FDI_LINK_TRAIN_NONE_IVB;
159 temp |= FDI_LINK_TRAIN_NONE_IVB | FDI_TX_ENHANCE_FRAME_ENABLE;
161 temp &= ~FDI_LINK_TRAIN_NONE;
162 temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
164 intel_de_write(dev_priv, reg, temp);
166 reg = FDI_RX_CTL(pipe);
167 temp = intel_de_read(dev_priv, reg);
168 if (HAS_PCH_CPT(dev_priv)) {
169 temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
170 temp |= FDI_LINK_TRAIN_NORMAL_CPT;
172 temp &= ~FDI_LINK_TRAIN_NONE;
173 temp |= FDI_LINK_TRAIN_NONE;
175 intel_de_write(dev_priv, reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
177 /* wait one idle pattern time */
178 intel_de_posting_read(dev_priv, reg);
181 /* IVB wants error correction enabled */
182 if (IS_IVYBRIDGE(dev_priv))
183 intel_de_write(dev_priv, reg,
184 intel_de_read(dev_priv, reg) | FDI_FS_ERRC_ENABLE | FDI_FE_ERRC_ENABLE);
187 /* The FDI link training functions for ILK/Ibexpeak. */
188 static void ilk_fdi_link_train(struct intel_crtc *crtc,
189 const struct intel_crtc_state *crtc_state)
191 struct drm_device *dev = crtc->base.dev;
192 struct drm_i915_private *dev_priv = to_i915(dev);
193 enum pipe pipe = crtc->pipe;
197 /* FDI needs bits from pipe first */
198 assert_pipe_enabled(dev_priv, crtc_state->cpu_transcoder);
200 /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
202 reg = FDI_RX_IMR(pipe);
203 temp = intel_de_read(dev_priv, reg);
204 temp &= ~FDI_RX_SYMBOL_LOCK;
205 temp &= ~FDI_RX_BIT_LOCK;
206 intel_de_write(dev_priv, reg, temp);
207 intel_de_read(dev_priv, reg);
210 /* enable CPU FDI TX and PCH FDI RX */
211 reg = FDI_TX_CTL(pipe);
212 temp = intel_de_read(dev_priv, reg);
213 temp &= ~FDI_DP_PORT_WIDTH_MASK;
214 temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
215 temp &= ~FDI_LINK_TRAIN_NONE;
216 temp |= FDI_LINK_TRAIN_PATTERN_1;
217 intel_de_write(dev_priv, reg, temp | FDI_TX_ENABLE);
219 reg = FDI_RX_CTL(pipe);
220 temp = intel_de_read(dev_priv, reg);
221 temp &= ~FDI_LINK_TRAIN_NONE;
222 temp |= FDI_LINK_TRAIN_PATTERN_1;
223 intel_de_write(dev_priv, reg, temp | FDI_RX_ENABLE);
225 intel_de_posting_read(dev_priv, reg);
228 /* Ironlake workaround, enable clock pointer after FDI enable*/
229 intel_de_write(dev_priv, FDI_RX_CHICKEN(pipe),
230 FDI_RX_PHASE_SYNC_POINTER_OVR);
231 intel_de_write(dev_priv, FDI_RX_CHICKEN(pipe),
232 FDI_RX_PHASE_SYNC_POINTER_OVR | FDI_RX_PHASE_SYNC_POINTER_EN);
234 reg = FDI_RX_IIR(pipe);
235 for (tries = 0; tries < 5; tries++) {
236 temp = intel_de_read(dev_priv, reg);
237 drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
239 if ((temp & FDI_RX_BIT_LOCK)) {
240 drm_dbg_kms(&dev_priv->drm, "FDI train 1 done.\n");
241 intel_de_write(dev_priv, reg, temp | FDI_RX_BIT_LOCK);
246 drm_err(&dev_priv->drm, "FDI train 1 fail!\n");
249 reg = FDI_TX_CTL(pipe);
250 temp = intel_de_read(dev_priv, reg);
251 temp &= ~FDI_LINK_TRAIN_NONE;
252 temp |= FDI_LINK_TRAIN_PATTERN_2;
253 intel_de_write(dev_priv, reg, temp);
255 reg = FDI_RX_CTL(pipe);
256 temp = intel_de_read(dev_priv, reg);
257 temp &= ~FDI_LINK_TRAIN_NONE;
258 temp |= FDI_LINK_TRAIN_PATTERN_2;
259 intel_de_write(dev_priv, reg, temp);
261 intel_de_posting_read(dev_priv, reg);
264 reg = FDI_RX_IIR(pipe);
265 for (tries = 0; tries < 5; tries++) {
266 temp = intel_de_read(dev_priv, reg);
267 drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
269 if (temp & FDI_RX_SYMBOL_LOCK) {
270 intel_de_write(dev_priv, reg,
271 temp | FDI_RX_SYMBOL_LOCK);
272 drm_dbg_kms(&dev_priv->drm, "FDI train 2 done.\n");
277 drm_err(&dev_priv->drm, "FDI train 2 fail!\n");
279 drm_dbg_kms(&dev_priv->drm, "FDI train done\n");
283 static const int snb_b_fdi_train_param[] = {
284 FDI_LINK_TRAIN_400MV_0DB_SNB_B,
285 FDI_LINK_TRAIN_400MV_6DB_SNB_B,
286 FDI_LINK_TRAIN_600MV_3_5DB_SNB_B,
287 FDI_LINK_TRAIN_800MV_0DB_SNB_B,
290 /* The FDI link training functions for SNB/Cougarpoint. */
291 static void gen6_fdi_link_train(struct intel_crtc *crtc,
292 const struct intel_crtc_state *crtc_state)
294 struct drm_device *dev = crtc->base.dev;
295 struct drm_i915_private *dev_priv = to_i915(dev);
296 enum pipe pipe = crtc->pipe;
300 /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
302 reg = FDI_RX_IMR(pipe);
303 temp = intel_de_read(dev_priv, reg);
304 temp &= ~FDI_RX_SYMBOL_LOCK;
305 temp &= ~FDI_RX_BIT_LOCK;
306 intel_de_write(dev_priv, reg, temp);
308 intel_de_posting_read(dev_priv, reg);
311 /* enable CPU FDI TX and PCH FDI RX */
312 reg = FDI_TX_CTL(pipe);
313 temp = intel_de_read(dev_priv, reg);
314 temp &= ~FDI_DP_PORT_WIDTH_MASK;
315 temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
316 temp &= ~FDI_LINK_TRAIN_NONE;
317 temp |= FDI_LINK_TRAIN_PATTERN_1;
318 temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
320 temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
321 intel_de_write(dev_priv, reg, temp | FDI_TX_ENABLE);
323 intel_de_write(dev_priv, FDI_RX_MISC(pipe),
324 FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
326 reg = FDI_RX_CTL(pipe);
327 temp = intel_de_read(dev_priv, reg);
328 if (HAS_PCH_CPT(dev_priv)) {
329 temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
330 temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
332 temp &= ~FDI_LINK_TRAIN_NONE;
333 temp |= FDI_LINK_TRAIN_PATTERN_1;
335 intel_de_write(dev_priv, reg, temp | FDI_RX_ENABLE);
337 intel_de_posting_read(dev_priv, reg);
340 for (i = 0; i < 4; i++) {
341 reg = FDI_TX_CTL(pipe);
342 temp = intel_de_read(dev_priv, reg);
343 temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
344 temp |= snb_b_fdi_train_param[i];
345 intel_de_write(dev_priv, reg, temp);
347 intel_de_posting_read(dev_priv, reg);
350 for (retry = 0; retry < 5; retry++) {
351 reg = FDI_RX_IIR(pipe);
352 temp = intel_de_read(dev_priv, reg);
353 drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
354 if (temp & FDI_RX_BIT_LOCK) {
355 intel_de_write(dev_priv, reg,
356 temp | FDI_RX_BIT_LOCK);
357 drm_dbg_kms(&dev_priv->drm,
358 "FDI train 1 done.\n");
367 drm_err(&dev_priv->drm, "FDI train 1 fail!\n");
370 reg = FDI_TX_CTL(pipe);
371 temp = intel_de_read(dev_priv, reg);
372 temp &= ~FDI_LINK_TRAIN_NONE;
373 temp |= FDI_LINK_TRAIN_PATTERN_2;
374 if (IS_GEN(dev_priv, 6)) {
375 temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
377 temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
379 intel_de_write(dev_priv, reg, temp);
381 reg = FDI_RX_CTL(pipe);
382 temp = intel_de_read(dev_priv, reg);
383 if (HAS_PCH_CPT(dev_priv)) {
384 temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
385 temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
387 temp &= ~FDI_LINK_TRAIN_NONE;
388 temp |= FDI_LINK_TRAIN_PATTERN_2;
390 intel_de_write(dev_priv, reg, temp);
392 intel_de_posting_read(dev_priv, reg);
395 for (i = 0; i < 4; i++) {
396 reg = FDI_TX_CTL(pipe);
397 temp = intel_de_read(dev_priv, reg);
398 temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
399 temp |= snb_b_fdi_train_param[i];
400 intel_de_write(dev_priv, reg, temp);
402 intel_de_posting_read(dev_priv, reg);
405 for (retry = 0; retry < 5; retry++) {
406 reg = FDI_RX_IIR(pipe);
407 temp = intel_de_read(dev_priv, reg);
408 drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
409 if (temp & FDI_RX_SYMBOL_LOCK) {
410 intel_de_write(dev_priv, reg,
411 temp | FDI_RX_SYMBOL_LOCK);
412 drm_dbg_kms(&dev_priv->drm,
413 "FDI train 2 done.\n");
422 drm_err(&dev_priv->drm, "FDI train 2 fail!\n");
424 drm_dbg_kms(&dev_priv->drm, "FDI train done.\n");
427 /* Manual link training for Ivy Bridge A0 parts */
428 static void ivb_manual_fdi_link_train(struct intel_crtc *crtc,
429 const struct intel_crtc_state *crtc_state)
431 struct drm_device *dev = crtc->base.dev;
432 struct drm_i915_private *dev_priv = to_i915(dev);
433 enum pipe pipe = crtc->pipe;
437 /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
439 reg = FDI_RX_IMR(pipe);
440 temp = intel_de_read(dev_priv, reg);
441 temp &= ~FDI_RX_SYMBOL_LOCK;
442 temp &= ~FDI_RX_BIT_LOCK;
443 intel_de_write(dev_priv, reg, temp);
445 intel_de_posting_read(dev_priv, reg);
448 drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR before link train 0x%x\n",
449 intel_de_read(dev_priv, FDI_RX_IIR(pipe)));
451 /* Try each vswing and preemphasis setting twice before moving on */
452 for (j = 0; j < ARRAY_SIZE(snb_b_fdi_train_param) * 2; j++) {
453 /* disable first in case we need to retry */
454 reg = FDI_TX_CTL(pipe);
455 temp = intel_de_read(dev_priv, reg);
456 temp &= ~(FDI_LINK_TRAIN_AUTO | FDI_LINK_TRAIN_NONE_IVB);
457 temp &= ~FDI_TX_ENABLE;
458 intel_de_write(dev_priv, reg, temp);
460 reg = FDI_RX_CTL(pipe);
461 temp = intel_de_read(dev_priv, reg);
462 temp &= ~FDI_LINK_TRAIN_AUTO;
463 temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
464 temp &= ~FDI_RX_ENABLE;
465 intel_de_write(dev_priv, reg, temp);
467 /* enable CPU FDI TX and PCH FDI RX */
468 reg = FDI_TX_CTL(pipe);
469 temp = intel_de_read(dev_priv, reg);
470 temp &= ~FDI_DP_PORT_WIDTH_MASK;
471 temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
472 temp |= FDI_LINK_TRAIN_PATTERN_1_IVB;
473 temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
474 temp |= snb_b_fdi_train_param[j/2];
475 temp |= FDI_COMPOSITE_SYNC;
476 intel_de_write(dev_priv, reg, temp | FDI_TX_ENABLE);
478 intel_de_write(dev_priv, FDI_RX_MISC(pipe),
479 FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
481 reg = FDI_RX_CTL(pipe);
482 temp = intel_de_read(dev_priv, reg);
483 temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
484 temp |= FDI_COMPOSITE_SYNC;
485 intel_de_write(dev_priv, reg, temp | FDI_RX_ENABLE);
487 intel_de_posting_read(dev_priv, reg);
488 udelay(1); /* should be 0.5us */
490 for (i = 0; i < 4; i++) {
491 reg = FDI_RX_IIR(pipe);
492 temp = intel_de_read(dev_priv, reg);
493 drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
495 if (temp & FDI_RX_BIT_LOCK ||
496 (intel_de_read(dev_priv, reg) & FDI_RX_BIT_LOCK)) {
497 intel_de_write(dev_priv, reg,
498 temp | FDI_RX_BIT_LOCK);
499 drm_dbg_kms(&dev_priv->drm,
500 "FDI train 1 done, level %i.\n",
504 udelay(1); /* should be 0.5us */
507 drm_dbg_kms(&dev_priv->drm,
508 "FDI train 1 fail on vswing %d\n", j / 2);
513 reg = FDI_TX_CTL(pipe);
514 temp = intel_de_read(dev_priv, reg);
515 temp &= ~FDI_LINK_TRAIN_NONE_IVB;
516 temp |= FDI_LINK_TRAIN_PATTERN_2_IVB;
517 intel_de_write(dev_priv, reg, temp);
519 reg = FDI_RX_CTL(pipe);
520 temp = intel_de_read(dev_priv, reg);
521 temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
522 temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
523 intel_de_write(dev_priv, reg, temp);
525 intel_de_posting_read(dev_priv, reg);
526 udelay(2); /* should be 1.5us */
528 for (i = 0; i < 4; i++) {
529 reg = FDI_RX_IIR(pipe);
530 temp = intel_de_read(dev_priv, reg);
531 drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
533 if (temp & FDI_RX_SYMBOL_LOCK ||
534 (intel_de_read(dev_priv, reg) & FDI_RX_SYMBOL_LOCK)) {
535 intel_de_write(dev_priv, reg,
536 temp | FDI_RX_SYMBOL_LOCK);
537 drm_dbg_kms(&dev_priv->drm,
538 "FDI train 2 done, level %i.\n",
542 udelay(2); /* should be 1.5us */
545 drm_dbg_kms(&dev_priv->drm,
546 "FDI train 2 fail on vswing %d\n", j / 2);
550 drm_dbg_kms(&dev_priv->drm, "FDI train done.\n");
553 void ilk_fdi_pll_enable(const struct intel_crtc_state *crtc_state)
555 struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->uapi.crtc);
556 struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
557 enum pipe pipe = intel_crtc->pipe;
561 /* enable PCH FDI RX PLL, wait warmup plus DMI latency */
562 reg = FDI_RX_CTL(pipe);
563 temp = intel_de_read(dev_priv, reg);
564 temp &= ~(FDI_DP_PORT_WIDTH_MASK | (0x7 << 16));
565 temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
566 temp |= (intel_de_read(dev_priv, PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
567 intel_de_write(dev_priv, reg, temp | FDI_RX_PLL_ENABLE);
569 intel_de_posting_read(dev_priv, reg);
572 /* Switch from Rawclk to PCDclk */
573 temp = intel_de_read(dev_priv, reg);
574 intel_de_write(dev_priv, reg, temp | FDI_PCDCLK);
576 intel_de_posting_read(dev_priv, reg);
579 /* Enable CPU FDI TX PLL, always on for Ironlake */
580 reg = FDI_TX_CTL(pipe);
581 temp = intel_de_read(dev_priv, reg);
582 if ((temp & FDI_TX_PLL_ENABLE) == 0) {
583 intel_de_write(dev_priv, reg, temp | FDI_TX_PLL_ENABLE);
585 intel_de_posting_read(dev_priv, reg);
590 void ilk_fdi_pll_disable(struct intel_crtc *intel_crtc)
592 struct drm_device *dev = intel_crtc->base.dev;
593 struct drm_i915_private *dev_priv = to_i915(dev);
594 enum pipe pipe = intel_crtc->pipe;
598 /* Switch from PCDclk to Rawclk */
599 reg = FDI_RX_CTL(pipe);
600 temp = intel_de_read(dev_priv, reg);
601 intel_de_write(dev_priv, reg, temp & ~FDI_PCDCLK);
603 /* Disable CPU FDI TX PLL */
604 reg = FDI_TX_CTL(pipe);
605 temp = intel_de_read(dev_priv, reg);
606 intel_de_write(dev_priv, reg, temp & ~FDI_TX_PLL_ENABLE);
608 intel_de_posting_read(dev_priv, reg);
611 reg = FDI_RX_CTL(pipe);
612 temp = intel_de_read(dev_priv, reg);
613 intel_de_write(dev_priv, reg, temp & ~FDI_RX_PLL_ENABLE);
615 /* Wait for the clocks to turn off. */
616 intel_de_posting_read(dev_priv, reg);
620 void ilk_fdi_disable(struct intel_crtc *crtc)
622 struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
623 enum pipe pipe = crtc->pipe;
627 /* disable CPU FDI tx and PCH FDI rx */
628 reg = FDI_TX_CTL(pipe);
629 temp = intel_de_read(dev_priv, reg);
630 intel_de_write(dev_priv, reg, temp & ~FDI_TX_ENABLE);
631 intel_de_posting_read(dev_priv, reg);
633 reg = FDI_RX_CTL(pipe);
634 temp = intel_de_read(dev_priv, reg);
635 temp &= ~(0x7 << 16);
636 temp |= (intel_de_read(dev_priv, PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
637 intel_de_write(dev_priv, reg, temp & ~FDI_RX_ENABLE);
639 intel_de_posting_read(dev_priv, reg);
642 /* Ironlake workaround, disable clock pointer after downing FDI */
643 if (HAS_PCH_IBX(dev_priv))
644 intel_de_write(dev_priv, FDI_RX_CHICKEN(pipe),
645 FDI_RX_PHASE_SYNC_POINTER_OVR);
647 /* still set train pattern 1 */
648 reg = FDI_TX_CTL(pipe);
649 temp = intel_de_read(dev_priv, reg);
650 temp &= ~FDI_LINK_TRAIN_NONE;
651 temp |= FDI_LINK_TRAIN_PATTERN_1;
652 intel_de_write(dev_priv, reg, temp);
654 reg = FDI_RX_CTL(pipe);
655 temp = intel_de_read(dev_priv, reg);
656 if (HAS_PCH_CPT(dev_priv)) {
657 temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
658 temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
660 temp &= ~FDI_LINK_TRAIN_NONE;
661 temp |= FDI_LINK_TRAIN_PATTERN_1;
663 /* BPC in FDI rx is consistent with that in PIPECONF */
664 temp &= ~(0x07 << 16);
665 temp |= (intel_de_read(dev_priv, PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
666 intel_de_write(dev_priv, reg, temp);
668 intel_de_posting_read(dev_priv, reg);
673 intel_fdi_init_hook(struct drm_i915_private *dev_priv)
675 if (IS_GEN(dev_priv, 5)) {
676 dev_priv->display.fdi_link_train = ilk_fdi_link_train;
677 } else if (IS_GEN(dev_priv, 6)) {
678 dev_priv->display.fdi_link_train = gen6_fdi_link_train;
679 } else if (IS_IVYBRIDGE(dev_priv)) {
680 /* FIXME: detect B0+ stepping and use auto training */
681 dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;