diff options
author | Dave Airlie <airlied@gmail.com> | 2012-09-19 20:00:10 +1000 |
---|---|---|
committer | Dave Airlie <airlied@gmail.com> | 2012-09-19 20:00:10 +1000 |
commit | 7facf16690dc4160e5ff605271704183ff56b2d9 (patch) | |
tree | 77b19e5a0cbc32e2b03cf429a753402e1f1b566f /drivers/gpu/drm/i915/intel_hdmi.c | |
parent | 87229ad9de079cb12ee09a3dc16113c390b729d5 (diff) | |
parent | 3b7a89fce3e3dc96b549d6d829387b4439044d0d (diff) |
Merge branch 'for-airlied' of git://people.freedesktop.org/~danvet/drm-intel into drm-next
Daniel writes:
"The big ticket item here is the new i915 modeset infrastructure.
Shockingly it didn't not blow up all over the place (i.e. I've managed to
fix the ugly issues before merging). 1-2 smaller corner cases broke, but
we have patches. Also, there's tons of patches on top of this that clean
out cruft and fix a few bugs that couldn't be fixed with the crtc helper
based stuff. So more stuff to come ;-)
Also a few other things:
- Tiny fix in the fb helper to go through the official dpms interface
instead of calling the crtc helper code.
- forcewake code frobbery from Ben, code should be more in-line with
what Windows does now.
- fixes for the render ring flush on hsw (Paulo)
- gpu frequency tracepoint
- vlv forcewake changes to better align it with our understanding of the
forcewake magic.
- a few smaller cleanups"
+ 2 fixes.
* 'for-airlied' of git://people.freedesktop.org/~danvet/drm-intel: (78 commits)
drm/i915: fix OOPS in lid_notify
drm/i915: correctly update crtc->x/y in set_base
drm/fb helper: don't call drm_helper_connector_dpms directly
drm/i915: improve modeset state checking after dpms calls
drm/i915: add tons of modeset state checks
drm/i915: no longer call drm_helper_resume_force_mode
drm/i915: disable all crtcs at suspend time
drm/i915: push commit_output_state past the crtc/encoder preparing
drm/i915: switch the load detect code to the staged modeset config
drm/i915: WARN if the pipe won't turn off
drm/i915: s/intel_encoder_disable/intel_encoder_noop
drm/i915: push commit_output_state past crtc disabling
drm/i915: implement new set_mode code flow
drm/i915: compute masks of crtcs affected in set_mode
drm/i915: use staged outuput config in lvds->mode_fixup
drm/i915: use staged outuput config in tv->mode_fixup
drm/i915: extract adjusted mode computation
drm/i915: move output commit and crtc disabling into set_mode
drm/i915: remove crtc disabling special case
drm/i915: push crtc->fb update into pipe_set_base
...
Diffstat (limited to 'drivers/gpu/drm/i915/intel_hdmi.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_hdmi.c | 151 |
1 files changed, 107 insertions, 44 deletions
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 35a6ee7a8cc..5d02aad0de8 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -601,11 +601,32 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, intel_hdmi->set_infoframes(encoder, adjusted_mode); } -static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) +static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder, + enum pipe *pipe) { - struct drm_device *dev = encoder->dev; + struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); + u32 tmp; + + tmp = I915_READ(intel_hdmi->sdvox_reg); + + if (!(tmp & SDVO_ENABLE)) + return false; + + if (HAS_PCH_CPT(dev)) + *pipe = PORT_TO_PIPE_CPT(tmp); + else + *pipe = PORT_TO_PIPE(tmp); + + return true; +} + +static void intel_enable_hdmi(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); u32 temp; u32 enable_bits = SDVO_ENABLE; @@ -617,31 +638,12 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) /* 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->crtc; + struct drm_crtc *crtc = encoder->base.crtc; int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1; - if (mode != DRM_MODE_DPMS_ON) { - if (temp & SDVO_PIPE_B_SELECT) { - temp &= ~SDVO_PIPE_B_SELECT; - I915_WRITE(intel_hdmi->sdvox_reg, temp); - POSTING_READ(intel_hdmi->sdvox_reg); - - /* Again we need to write this twice. */ - I915_WRITE(intel_hdmi->sdvox_reg, temp); - POSTING_READ(intel_hdmi->sdvox_reg); - - /* Transcoder selection bits only update - * effectively on vblank. */ - if (crtc) - intel_wait_for_vblank(dev, pipe); - else - msleep(50); - } - } else { - /* Restore the transcoder select bit. */ - if (pipe == PIPE_B) - enable_bits |= SDVO_PIPE_B_SELECT; - } + /* Restore the transcoder select bit. */ + if (pipe == PIPE_B) + enable_bits |= SDVO_PIPE_B_SELECT; } /* HW workaround, need to toggle enable bit off and on for 12bpc, but @@ -652,11 +654,66 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) POSTING_READ(intel_hdmi->sdvox_reg); } - if (mode != DRM_MODE_DPMS_ON) { - temp &= ~enable_bits; - } else { - temp |= enable_bits; + temp |= enable_bits; + + I915_WRITE(intel_hdmi->sdvox_reg, temp); + POSTING_READ(intel_hdmi->sdvox_reg); + + /* HW workaround, need to write this twice for issue that may result + * in first write getting masked. + */ + if (HAS_PCH_SPLIT(dev)) { + I915_WRITE(intel_hdmi->sdvox_reg, temp); + POSTING_READ(intel_hdmi->sdvox_reg); } +} + +static void intel_disable_hdmi(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); + u32 temp; + u32 enable_bits = SDVO_ENABLE; + + if (intel_hdmi->has_audio) + enable_bits |= SDVO_AUDIO_ENABLE; + + temp = I915_READ(intel_hdmi->sdvox_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->sdvox_reg, temp); + POSTING_READ(intel_hdmi->sdvox_reg); + + /* Again we need to write this twice. */ + I915_WRITE(intel_hdmi->sdvox_reg, temp); + POSTING_READ(intel_hdmi->sdvox_reg); + + /* Transcoder selection bits only update + * effectively on vblank. */ + if (crtc) + intel_wait_for_vblank(dev, pipe); + else + msleep(50); + } + } + + /* HW workaround, need to toggle enable bit off and on for 12bpc, but + * we do this anyway which shows more stable in testing. + */ + if (HAS_PCH_SPLIT(dev)) { + I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE); + POSTING_READ(intel_hdmi->sdvox_reg); + } + + temp &= ~enable_bits; I915_WRITE(intel_hdmi->sdvox_reg, temp); POSTING_READ(intel_hdmi->sdvox_reg); @@ -830,9 +887,8 @@ intel_hdmi_set_property(struct drm_connector *connector, done: if (intel_hdmi->base.base.crtc) { struct drm_crtc *crtc = intel_hdmi->base.base.crtc; - drm_crtc_helper_set_mode(crtc, &crtc->mode, - crtc->x, crtc->y, - crtc->fb); + intel_set_mode(crtc, &crtc->mode, + crtc->x, crtc->y, crtc->fb); } return 0; @@ -846,23 +902,19 @@ static void intel_hdmi_destroy(struct drm_connector *connector) } static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs_hsw = { - .dpms = intel_ddi_dpms, .mode_fixup = intel_hdmi_mode_fixup, - .prepare = intel_encoder_prepare, .mode_set = intel_ddi_mode_set, - .commit = intel_encoder_commit, + .disable = intel_encoder_noop, }; static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = { - .dpms = intel_hdmi_dpms, .mode_fixup = intel_hdmi_mode_fixup, - .prepare = intel_encoder_prepare, .mode_set = intel_hdmi_mode_set, - .commit = intel_encoder_commit, + .disable = intel_encoder_noop, }; static const struct drm_connector_funcs intel_hdmi_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = intel_connector_dpms, .detect = intel_hdmi_detect, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = intel_hdmi_set_property, @@ -961,10 +1013,21 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port) intel_hdmi->set_infoframes = cpt_set_infoframes; } - if (IS_HASWELL(dev)) - drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs_hsw); - else - drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); + if (IS_HASWELL(dev)) { + intel_encoder->enable = intel_enable_ddi; + intel_encoder->disable = intel_disable_ddi; + intel_encoder->get_hw_state = intel_ddi_get_hw_state; + drm_encoder_helper_add(&intel_encoder->base, + &intel_hdmi_helper_funcs_hsw); + } else { + intel_encoder->enable = intel_enable_hdmi; + intel_encoder->disable = intel_disable_hdmi; + intel_encoder->get_hw_state = intel_hdmi_get_hw_state; + drm_encoder_helper_add(&intel_encoder->base, + &intel_hdmi_helper_funcs); + } + intel_connector->get_hw_state = intel_connector_get_hw_state; + intel_hdmi_add_properties(intel_hdmi, connector); |