mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-29 22:16:47 +07:00
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>
This commit is contained in:
parent
45244b8794
commit
c82e4d265d
@ -105,3 +105,118 @@ 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
|
||||
};
|
||||
|
||||
|
||||
/* Starting with Haswell, different DDI ports can work in FDI mode for
|
||||
* connection to the PCH-located connectors. For this, it is necessary to train
|
||||
* both the DDI port and PCH receiver for the desired DDI buffer settings.
|
||||
*
|
||||
* The recommended port to work in FDI mode is DDI E, which we use here. Also,
|
||||
* please note that when FDI mode is active on DDI E, it shares 2 lines with
|
||||
* DDI A (which is used for eDP)
|
||||
*/
|
||||
|
||||
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");
|
||||
}
|
||||
|
@ -6607,6 +6607,8 @@ 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 = hsw_fdi_link_train;
|
||||
} else
|
||||
dev_priv->display.update_wm = NULL;
|
||||
} else if (IS_VALLEYVIEW(dev)) {
|
||||
|
@ -447,6 +447,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 hsw_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);
|
||||
|
Loading…
Reference in New Issue
Block a user