Skip to content

Commit 1612c8b

Browse files
vsyrjaladanvet
authored andcommitted
drm/i915: Fix the IBX transcoder B workarounds
Currently the IBX transcoder B workarounds are not working correctly. Well, the HDMI one seems to be working somewhat, but the DP one is definitely busted. After a bit of experimentation it looks like the best way to make this work is first disable the port on transcoder B, and then re-enable it transcoder A, and immediately disable it again. We can also clean up the code by noting that we can't be called without a valid crtc. And also note that port A on ILK does not need the workaround, so let's check for that one too. Signed-off-by: Ville Syrjälä <[email protected]> Reviewed-by: Jesse Barnes <[email protected]> Signed-off-by: Daniel Vetter <[email protected]>
1 parent e8504ee commit 1612c8b

File tree

3 files changed

+60
-68
lines changed

3 files changed

+60
-68
lines changed

drivers/gpu/drm/i915/intel_dp.c

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3843,6 +3843,7 @@ static void
38433843
intel_dp_link_down(struct intel_dp *intel_dp)
38443844
{
38453845
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
3846+
struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc);
38463847
enum port port = intel_dig_port->port;
38473848
struct drm_device *dev = intel_dig_port->base.base.dev;
38483849
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3859,34 +3860,38 @@ intel_dp_link_down(struct intel_dp *intel_dp)
38593860
if ((IS_GEN7(dev) && port == PORT_A) ||
38603861
(HAS_PCH_CPT(dev) && port != PORT_A)) {
38613862
DP &= ~DP_LINK_TRAIN_MASK_CPT;
3862-
I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT);
3863+
DP |= DP_LINK_TRAIN_PAT_IDLE_CPT;
38633864
} else {
38643865
if (IS_CHERRYVIEW(dev))
38653866
DP &= ~DP_LINK_TRAIN_MASK_CHV;
38663867
else
38673868
DP &= ~DP_LINK_TRAIN_MASK;
3868-
I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE);
3869+
DP |= DP_LINK_TRAIN_PAT_IDLE;
38693870
}
3871+
I915_WRITE(intel_dp->output_reg, DP);
38703872
POSTING_READ(intel_dp->output_reg);
38713873

3872-
if (HAS_PCH_IBX(dev) &&
3873-
I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) {
3874-
/* Hardware workaround: leaving our transcoder select
3875-
* set to transcoder B while it's off will prevent the
3876-
* corresponding HDMI output on transcoder A.
3877-
*
3878-
* Combine this with another hardware workaround:
3879-
* transcoder select bit can only be cleared while the
3880-
* port is enabled.
3881-
*/
3882-
DP &= ~DP_PIPEB_SELECT;
3874+
DP &= ~(DP_PORT_EN | DP_AUDIO_OUTPUT_ENABLE);
3875+
I915_WRITE(intel_dp->output_reg, DP);
3876+
POSTING_READ(intel_dp->output_reg);
3877+
3878+
/*
3879+
* HW workaround for IBX, we need to move the port
3880+
* to transcoder A after disabling it to allow the
3881+
* matching HDMI port to be enabled on transcoder A.
3882+
*/
3883+
if (HAS_PCH_IBX(dev) && crtc->pipe == PIPE_B && port != PORT_A) {
3884+
/* always enable with pattern 1 (as per spec) */
3885+
DP &= ~(DP_PIPEB_SELECT | DP_LINK_TRAIN_MASK);
3886+
DP |= DP_PORT_EN | DP_LINK_TRAIN_PAT_1;
3887+
I915_WRITE(intel_dp->output_reg, DP);
3888+
POSTING_READ(intel_dp->output_reg);
3889+
3890+
DP &= ~DP_PORT_EN;
38833891
I915_WRITE(intel_dp->output_reg, DP);
38843892
POSTING_READ(intel_dp->output_reg);
38853893
}
38863894

3887-
DP &= ~DP_AUDIO_OUTPUT_ENABLE;
3888-
I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN);
3889-
POSTING_READ(intel_dp->output_reg);
38903895
msleep(intel_dp->panel_power_down_delay);
38913896
}
38923897

drivers/gpu/drm/i915/intel_hdmi.c

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -873,41 +873,37 @@ static void intel_disable_hdmi(struct intel_encoder *encoder)
873873
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
874874
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
875875
u32 temp;
876-
u32 enable_bits = SDVO_ENABLE | SDVO_AUDIO_ENABLE;
877876

878877
if (crtc->config->has_audio)
879878
intel_audio_codec_disable(encoder);
880879

881880
temp = I915_READ(intel_hdmi->hdmi_reg);
882881

883-
/* HW workaround for IBX, we need to move the port to transcoder A
884-
* before disabling it. */
885-
if (HAS_PCH_IBX(dev)) {
886-
struct drm_crtc *crtc = encoder->base.crtc;
887-
int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;
888-
889-
if (temp & SDVO_PIPE_B_SELECT) {
890-
temp &= ~SDVO_PIPE_B_SELECT;
891-
I915_WRITE(intel_hdmi->hdmi_reg, temp);
892-
POSTING_READ(intel_hdmi->hdmi_reg);
893-
894-
/* Again we need to write this twice. */
895-
I915_WRITE(intel_hdmi->hdmi_reg, temp);
896-
POSTING_READ(intel_hdmi->hdmi_reg);
897-
898-
/* Transcoder selection bits only update
899-
* effectively on vblank. */
900-
if (crtc)
901-
intel_wait_for_vblank(dev, pipe);
902-
else
903-
msleep(50);
904-
}
905-
}
906-
907-
temp &= ~enable_bits;
908-
882+
temp &= ~(SDVO_ENABLE | SDVO_AUDIO_ENABLE);
909883
I915_WRITE(intel_hdmi->hdmi_reg, temp);
910884
POSTING_READ(intel_hdmi->hdmi_reg);
885+
886+
/*
887+
* HW workaround for IBX, we need to move the port
888+
* to transcoder A after disabling it to allow the
889+
* matching DP port to be enabled on transcoder A.
890+
*/
891+
if (HAS_PCH_IBX(dev) && crtc->pipe == PIPE_B) {
892+
temp &= ~SDVO_PIPE_B_SELECT;
893+
temp |= SDVO_ENABLE;
894+
/*
895+
* HW workaround, need to write this twice for issue
896+
* that may result in first write getting masked.
897+
*/
898+
I915_WRITE(intel_hdmi->hdmi_reg, temp);
899+
POSTING_READ(intel_hdmi->hdmi_reg);
900+
I915_WRITE(intel_hdmi->hdmi_reg, temp);
901+
POSTING_READ(intel_hdmi->hdmi_reg);
902+
903+
temp &= ~SDVO_ENABLE;
904+
I915_WRITE(intel_hdmi->hdmi_reg, temp);
905+
POSTING_READ(intel_hdmi->hdmi_reg);
906+
}
911907
}
912908

913909
static int hdmi_portclock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit)

drivers/gpu/drm/i915/intel_sdvo.c

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1437,6 +1437,7 @@ static void intel_disable_sdvo(struct intel_encoder *encoder)
14371437
{
14381438
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
14391439
struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
1440+
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
14401441
u32 temp;
14411442

14421443
intel_sdvo_set_active_outputs(intel_sdvo, 0);
@@ -1445,32 +1446,22 @@ static void intel_disable_sdvo(struct intel_encoder *encoder)
14451446
DRM_MODE_DPMS_OFF);
14461447

14471448
temp = I915_READ(intel_sdvo->sdvo_reg);
1448-
if ((temp & SDVO_ENABLE) != 0) {
1449-
/* HW workaround for IBX, we need to move the port to
1450-
* transcoder A before disabling it. */
1451-
if (HAS_PCH_IBX(encoder->base.dev)) {
1452-
struct drm_crtc *crtc = encoder->base.crtc;
1453-
int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;
1454-
1455-
if (temp & SDVO_PIPE_B_SELECT) {
1456-
temp &= ~SDVO_PIPE_B_SELECT;
1457-
I915_WRITE(intel_sdvo->sdvo_reg, temp);
1458-
POSTING_READ(intel_sdvo->sdvo_reg);
1459-
1460-
/* Again we need to write this twice. */
1461-
I915_WRITE(intel_sdvo->sdvo_reg, temp);
1462-
POSTING_READ(intel_sdvo->sdvo_reg);
1463-
1464-
/* Transcoder selection bits only update
1465-
* effectively on vblank. */
1466-
if (crtc)
1467-
intel_wait_for_vblank(encoder->base.dev, pipe);
1468-
else
1469-
msleep(50);
1470-
}
1471-
}
14721449

1473-
intel_sdvo_write_sdvox(intel_sdvo, temp & ~SDVO_ENABLE);
1450+
temp &= ~SDVO_ENABLE;
1451+
intel_sdvo_write_sdvox(intel_sdvo, temp);
1452+
1453+
/*
1454+
* HW workaround for IBX, we need to move the port
1455+
* to transcoder A after disabling it to allow the
1456+
* matching DP port to be enabled on transcoder A.
1457+
*/
1458+
if (HAS_PCH_IBX(dev_priv) && crtc->pipe == PIPE_B) {
1459+
temp &= ~SDVO_PIPE_B_SELECT;
1460+
temp |= SDVO_ENABLE;
1461+
intel_sdvo_write_sdvox(intel_sdvo, temp);
1462+
1463+
temp &= ~SDVO_ENABLE;
1464+
intel_sdvo_write_sdvox(intel_sdvo, temp);
14741465
}
14751466
}
14761467

0 commit comments

Comments
 (0)