mirror of https://gitee.com/openkylin/linux.git
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ä <ville.syrjala@linux.intel.com> Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
parent
e8504ee293
commit
1612c8bd4c
|
@ -3843,6 +3843,7 @@ static void
|
|||
intel_dp_link_down(struct intel_dp *intel_dp)
|
||||
{
|
||||
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
|
||||
struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc);
|
||||
enum port port = intel_dig_port->port;
|
||||
struct drm_device *dev = intel_dig_port->base.base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
@ -3859,34 +3860,38 @@ intel_dp_link_down(struct intel_dp *intel_dp)
|
|||
if ((IS_GEN7(dev) && port == PORT_A) ||
|
||||
(HAS_PCH_CPT(dev) && port != PORT_A)) {
|
||||
DP &= ~DP_LINK_TRAIN_MASK_CPT;
|
||||
I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT);
|
||||
DP |= DP_LINK_TRAIN_PAT_IDLE_CPT;
|
||||
} else {
|
||||
if (IS_CHERRYVIEW(dev))
|
||||
DP &= ~DP_LINK_TRAIN_MASK_CHV;
|
||||
else
|
||||
DP &= ~DP_LINK_TRAIN_MASK;
|
||||
I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE);
|
||||
DP |= DP_LINK_TRAIN_PAT_IDLE;
|
||||
}
|
||||
I915_WRITE(intel_dp->output_reg, DP);
|
||||
POSTING_READ(intel_dp->output_reg);
|
||||
|
||||
if (HAS_PCH_IBX(dev) &&
|
||||
I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) {
|
||||
/* Hardware workaround: leaving our transcoder select
|
||||
* set to transcoder B while it's off will prevent the
|
||||
* corresponding HDMI output on transcoder A.
|
||||
*
|
||||
* Combine this with another hardware workaround:
|
||||
* transcoder select bit can only be cleared while the
|
||||
* port is enabled.
|
||||
*/
|
||||
DP &= ~DP_PIPEB_SELECT;
|
||||
DP &= ~(DP_PORT_EN | DP_AUDIO_OUTPUT_ENABLE);
|
||||
I915_WRITE(intel_dp->output_reg, DP);
|
||||
POSTING_READ(intel_dp->output_reg);
|
||||
|
||||
/*
|
||||
* HW workaround for IBX, we need to move the port
|
||||
* to transcoder A after disabling it to allow the
|
||||
* matching HDMI port to be enabled on transcoder A.
|
||||
*/
|
||||
if (HAS_PCH_IBX(dev) && crtc->pipe == PIPE_B && port != PORT_A) {
|
||||
/* always enable with pattern 1 (as per spec) */
|
||||
DP &= ~(DP_PIPEB_SELECT | DP_LINK_TRAIN_MASK);
|
||||
DP |= DP_PORT_EN | DP_LINK_TRAIN_PAT_1;
|
||||
I915_WRITE(intel_dp->output_reg, DP);
|
||||
POSTING_READ(intel_dp->output_reg);
|
||||
|
||||
DP &= ~DP_PORT_EN;
|
||||
I915_WRITE(intel_dp->output_reg, DP);
|
||||
POSTING_READ(intel_dp->output_reg);
|
||||
}
|
||||
|
||||
DP &= ~DP_AUDIO_OUTPUT_ENABLE;
|
||||
I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN);
|
||||
POSTING_READ(intel_dp->output_reg);
|
||||
msleep(intel_dp->panel_power_down_delay);
|
||||
}
|
||||
|
||||
|
|
|
@ -873,41 +873,37 @@ static void intel_disable_hdmi(struct intel_encoder *encoder)
|
|||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
|
||||
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
|
||||
u32 temp;
|
||||
u32 enable_bits = SDVO_ENABLE | SDVO_AUDIO_ENABLE;
|
||||
|
||||
if (crtc->config->has_audio)
|
||||
intel_audio_codec_disable(encoder);
|
||||
|
||||
temp = I915_READ(intel_hdmi->hdmi_reg);
|
||||
|
||||
/* HW workaround for IBX, we need to move the port to transcoder A
|
||||
* before disabling it. */
|
||||
if (HAS_PCH_IBX(dev)) {
|
||||
struct drm_crtc *crtc = encoder->base.crtc;
|
||||
int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;
|
||||
|
||||
if (temp & SDVO_PIPE_B_SELECT) {
|
||||
temp &= ~SDVO_PIPE_B_SELECT;
|
||||
I915_WRITE(intel_hdmi->hdmi_reg, temp);
|
||||
POSTING_READ(intel_hdmi->hdmi_reg);
|
||||
|
||||
/* Again we need to write this twice. */
|
||||
I915_WRITE(intel_hdmi->hdmi_reg, temp);
|
||||
POSTING_READ(intel_hdmi->hdmi_reg);
|
||||
|
||||
/* Transcoder selection bits only update
|
||||
* effectively on vblank. */
|
||||
if (crtc)
|
||||
intel_wait_for_vblank(dev, pipe);
|
||||
else
|
||||
msleep(50);
|
||||
}
|
||||
}
|
||||
|
||||
temp &= ~enable_bits;
|
||||
|
||||
temp &= ~(SDVO_ENABLE | SDVO_AUDIO_ENABLE);
|
||||
I915_WRITE(intel_hdmi->hdmi_reg, temp);
|
||||
POSTING_READ(intel_hdmi->hdmi_reg);
|
||||
|
||||
/*
|
||||
* HW workaround for IBX, we need to move the port
|
||||
* to transcoder A after disabling it to allow the
|
||||
* matching DP port to be enabled on transcoder A.
|
||||
*/
|
||||
if (HAS_PCH_IBX(dev) && crtc->pipe == PIPE_B) {
|
||||
temp &= ~SDVO_PIPE_B_SELECT;
|
||||
temp |= SDVO_ENABLE;
|
||||
/*
|
||||
* HW workaround, need to write this twice for issue
|
||||
* that may result in first write getting masked.
|
||||
*/
|
||||
I915_WRITE(intel_hdmi->hdmi_reg, temp);
|
||||
POSTING_READ(intel_hdmi->hdmi_reg);
|
||||
I915_WRITE(intel_hdmi->hdmi_reg, temp);
|
||||
POSTING_READ(intel_hdmi->hdmi_reg);
|
||||
|
||||
temp &= ~SDVO_ENABLE;
|
||||
I915_WRITE(intel_hdmi->hdmi_reg, temp);
|
||||
POSTING_READ(intel_hdmi->hdmi_reg);
|
||||
}
|
||||
}
|
||||
|
||||
static int hdmi_portclock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit)
|
||||
|
|
|
@ -1437,6 +1437,7 @@ static void intel_disable_sdvo(struct intel_encoder *encoder)
|
|||
{
|
||||
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
|
||||
struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
|
||||
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
|
||||
u32 temp;
|
||||
|
||||
intel_sdvo_set_active_outputs(intel_sdvo, 0);
|
||||
|
@ -1445,32 +1446,22 @@ static void intel_disable_sdvo(struct intel_encoder *encoder)
|
|||
DRM_MODE_DPMS_OFF);
|
||||
|
||||
temp = I915_READ(intel_sdvo->sdvo_reg);
|
||||
if ((temp & SDVO_ENABLE) != 0) {
|
||||
/* HW workaround for IBX, we need to move the port to
|
||||
* transcoder A before disabling it. */
|
||||
if (HAS_PCH_IBX(encoder->base.dev)) {
|
||||
struct drm_crtc *crtc = encoder->base.crtc;
|
||||
int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;
|
||||
|
||||
if (temp & SDVO_PIPE_B_SELECT) {
|
||||
temp &= ~SDVO_PIPE_B_SELECT;
|
||||
I915_WRITE(intel_sdvo->sdvo_reg, temp);
|
||||
POSTING_READ(intel_sdvo->sdvo_reg);
|
||||
temp &= ~SDVO_ENABLE;
|
||||
intel_sdvo_write_sdvox(intel_sdvo, temp);
|
||||
|
||||
/* Again we need to write this twice. */
|
||||
I915_WRITE(intel_sdvo->sdvo_reg, temp);
|
||||
POSTING_READ(intel_sdvo->sdvo_reg);
|
||||
/*
|
||||
* HW workaround for IBX, we need to move the port
|
||||
* to transcoder A after disabling it to allow the
|
||||
* matching DP port to be enabled on transcoder A.
|
||||
*/
|
||||
if (HAS_PCH_IBX(dev_priv) && crtc->pipe == PIPE_B) {
|
||||
temp &= ~SDVO_PIPE_B_SELECT;
|
||||
temp |= SDVO_ENABLE;
|
||||
intel_sdvo_write_sdvox(intel_sdvo, temp);
|
||||
|
||||
/* Transcoder selection bits only update
|
||||
* effectively on vblank. */
|
||||
if (crtc)
|
||||
intel_wait_for_vblank(encoder->base.dev, pipe);
|
||||
else
|
||||
msleep(50);
|
||||
}
|
||||
}
|
||||
|
||||
intel_sdvo_write_sdvox(intel_sdvo, temp & ~SDVO_ENABLE);
|
||||
temp &= ~SDVO_ENABLE;
|
||||
intel_sdvo_write_sdvox(intel_sdvo, temp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue