Buffer translations for DDI links must be initialized prior to enablement. For FDI and DP, first 9 pairs of values are used to select the connection parameters. HDMI uses the last pair of values and ignores the first 9 pairs. So we program HDMI values in both cases, which allows HDMI to work over both FDI and DP-friendly buffers. Signed-off-by: Eugeni Dodonov <eugeni.dodonov at intel.com> --- drivers/gpu/drm/i915/intel_display.c | 84 +++++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_drv.h | 1 + 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 72f2211..1fdcd56 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2728,6 +2728,86 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) DRM_DEBUG_KMS("FDI train done.\n"); } +/* HDMI/DVI modes ignore everything but the last 2 items. So we share + * them for both DP and FDI transports, allowing those ports to + * automatically adapt to HDMI connections as well + */ +static const long hsw_ddi_translations_dp[] = { + 0x00FFFFFF, 0x0006000E, + 0x00D75FFF, 0x0005000A, + 0x00C30FFF, 0x00040006, + 0x80AAAFFF, 0x000B0000, + 0x00FFFFFF, 0x0005000A, + 0x00D75FFF, 0x000C0004, + 0x80C30FFF, 0x000B0000, + 0x00FFFFFF, 0x00040006, + 0x80D75FFF, 0x000B0000, + 0x00FFFFFF, 0x00040006 +}; + +static const long hsw_ddi_translations_fdi[] = { + 0x00FFFFFF, 0x0007000E, + 0x00D75FFF, 0x000F000A, + 0x00C30FFF, 0x00060006, + 0x00AAAFFF, 0x001E0000, + 0x00FFFFFF, 0x000F000A, + 0x00D75FFF, 0x00160004, + 0x00C30FFF, 0x001E0000, + 0x00FFFFFF, 0x00060006, + 0x00D75FFF, 0x001E0000, + 0x00FFFFFF, 0x00040006 +}; + +/* On Haswell, DDI port buffers must be programmed with correct values + * in advance. The buffer values are different for FDI and DP modes, + * but the HDMI/DVI fields are shared among those. So we program the DDI + * in either FDI or DP modes only, as HDMI connections will work with both + * of those + */ +void hsw_prepare_ddi_buffers(struct drm_device *dev, enum port port, bool use_fdi_mode) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 reg; + int i, j; + + DRM_DEBUG_DRIVER("Initializing DDI buffers for port %c in %s mode\n", + port_name(port), + use_fdi_mode ? "FDI" : "DP"); + + WARN((use_fdi_mode && (port != PORT_E)), + "Programming port %c in FDI mode, this probably will not work.\n", + port_name(port)); + + /* Those registers seem to be double-buffered, so write them twice */ + for (j=0; j < 2; j++) { + for (i=0, reg=DDI_BUF_TRANS(port); i < ARRAY_SIZE(hsw_ddi_translations_fdi); i++) { + I915_WRITE(reg, + (use_fdi_mode) ? + hsw_ddi_translations_fdi[i] : + hsw_ddi_translations_dp[i]); + reg += 4; + } + udelay(20); + } +} + +/* Program DDI buffers translations for DP. By default, program ports A-D in DP + * mode and port E for FDI. + */ +static void intel_hsw_prepare_ddi_buffers(struct drm_device *dev) +{ + int port; + + for (port = PORT_A; port < PORT_E; port++) + hsw_prepare_ddi_buffers(dev, port, false); + + /* DDI E is the suggested one to work in FDI mode, so program is as such by + * default. It will have to be re-programmed in case a digital DP output + * will be detected on it + */ + hsw_prepare_ddi_buffers(dev, PORT_E, true); +} + /* Manual link training for Ivy Bridge A0 parts */ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc) { @@ -9235,8 +9315,10 @@ void intel_modeset_init(struct drm_device *dev) intel_init_quirks(dev); - if (IS_HASWELL(dev)) + if (IS_HASWELL(dev)) { intel_init_power_wells(dev); + intel_hsw_prepare_ddi_buffers(dev); + } intel_init_display(dev); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 9cec6c3..ef1d4ca 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -407,6 +407,7 @@ extern void intel_init_clock_gating(struct drm_device *dev); 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 hsw_prepare_ddi_buffers(struct drm_device *dev, enum port port, bool use_fdi_mode); /* For use by IVB LP watermark workaround in intel_sprite.c */ extern void sandybridge_update_wm(struct drm_device *dev); -- 1.7.9.5