aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_hdmi.c
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2012-06-30 02:59:56 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2012-09-06 01:53:37 -0400
commit5ab432ef4997ce32c9406721b37ef6e97e57dae1 (patch)
treed10c2de94fd561befbccc99f77025e430301b1f8 /drivers/gpu/drm/i915/intel_hdmi.c
parentef9c3aee60442d1eaf81fbd7b63f256410cc0aa9 (diff)
drm/i915/hdmi: convert to encoder->disable/enable
I've picked hdmi as the first encoder to convert because it's rather simple: - no cloning possible - no differences between prepare/commit and dpms off/on switching. A few changes are required to do so: - Split up the dpms code into an enable/disable function and wire it up with the intel encoder. - Noop out the existing encoder prepare/commit functions used by the crtc helper - our crtc enable/disable code now calls back into the encoder enable/disable code at the right spot. - Create new helper functions to handle dpms changes. - Add intel_encoder->connectors_active to better track dpms state. Atm this is unused, but it will be useful to correctly disable the entire display pipe for cloned configurations. Also note that for now this is only useful in the dpms code - thanks to the crtc helper's dpms confusion across a modeset operation we can't (yet) rely on this having a sensible value in all circumstances. - Rip out the encoder helper dpms callback, if this is still getting called somewhere we have a bug. The slight issue with that is that the crtc helper abuses dpms off to disable unused functions. Hence we also need to implement a default encoder disable function to do just that with the new encoder->disable callback. - Note that we drop the cpt modeset verification in the commit callback, too. The right place to do this would be in the crtc's enable function, _after_ all the encoders are set up. But because not all encoders are converted yet, we can't do that. Hence disable this check temporarily as a minor concession to bisectability. v2: Squash the dpms mode to only the supported values - connector->dpms is for internal tracking only, we can hence avoid needless state-changes a bit whithout causing harm. v3: Apply bikeshed to disable|enable_ddi, suggested by Paulo Zanoni. Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_hdmi.c')
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c126
1 files changed, 85 insertions, 41 deletions
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index e4c37bb572e8..acddaaa5f04c 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -601,11 +601,11 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
601 intel_hdmi->set_infoframes(encoder, adjusted_mode); 601 intel_hdmi->set_infoframes(encoder, adjusted_mode);
602} 602}
603 603
604static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) 604static void intel_enable_hdmi(struct intel_encoder *encoder)
605{ 605{
606 struct drm_device *dev = encoder->dev; 606 struct drm_device *dev = encoder->base.dev;
607 struct drm_i915_private *dev_priv = dev->dev_private; 607 struct drm_i915_private *dev_priv = dev->dev_private;
608 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 608 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
609 u32 temp; 609 u32 temp;
610 u32 enable_bits = SDVO_ENABLE; 610 u32 enable_bits = SDVO_ENABLE;
611 611
@@ -617,31 +617,12 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
617 /* HW workaround for IBX, we need to move the port to transcoder A 617 /* HW workaround for IBX, we need to move the port to transcoder A
618 * before disabling it. */ 618 * before disabling it. */
619 if (HAS_PCH_IBX(dev)) { 619 if (HAS_PCH_IBX(dev)) {
620 struct drm_crtc *crtc = encoder->crtc; 620 struct drm_crtc *crtc = encoder->base.crtc;
621 int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1; 621 int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;
622 622
623 if (mode != DRM_MODE_DPMS_ON) { 623 /* Restore the transcoder select bit. */
624 if (temp & SDVO_PIPE_B_SELECT) { 624 if (pipe == PIPE_B)
625 temp &= ~SDVO_PIPE_B_SELECT; 625 enable_bits |= SDVO_PIPE_B_SELECT;
626 I915_WRITE(intel_hdmi->sdvox_reg, temp);
627 POSTING_READ(intel_hdmi->sdvox_reg);
628
629 /* Again we need to write this twice. */
630 I915_WRITE(intel_hdmi->sdvox_reg, temp);
631 POSTING_READ(intel_hdmi->sdvox_reg);
632
633 /* Transcoder selection bits only update
634 * effectively on vblank. */
635 if (crtc)
636 intel_wait_for_vblank(dev, pipe);
637 else
638 msleep(50);
639 }
640 } else {
641 /* Restore the transcoder select bit. */
642 if (pipe == PIPE_B)
643 enable_bits |= SDVO_PIPE_B_SELECT;
644 }
645 } 626 }
646 627
647 /* HW workaround, need to toggle enable bit off and on for 12bpc, but 628 /* HW workaround, need to toggle enable bit off and on for 12bpc, but
@@ -652,12 +633,67 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
652 POSTING_READ(intel_hdmi->sdvox_reg); 633 POSTING_READ(intel_hdmi->sdvox_reg);
653 } 634 }
654 635
655 if (mode != DRM_MODE_DPMS_ON) { 636 temp |= enable_bits;
656 temp &= ~enable_bits; 637
657 } else { 638 I915_WRITE(intel_hdmi->sdvox_reg, temp);
658 temp |= enable_bits; 639 POSTING_READ(intel_hdmi->sdvox_reg);
640
641 /* HW workaround, need to write this twice for issue that may result
642 * in first write getting masked.
643 */
644 if (HAS_PCH_SPLIT(dev)) {
645 I915_WRITE(intel_hdmi->sdvox_reg, temp);
646 POSTING_READ(intel_hdmi->sdvox_reg);
647 }
648}
649
650static void intel_disable_hdmi(struct intel_encoder *encoder)
651{
652 struct drm_device *dev = encoder->base.dev;
653 struct drm_i915_private *dev_priv = dev->dev_private;
654 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
655 u32 temp;
656 u32 enable_bits = SDVO_ENABLE;
657
658 if (intel_hdmi->has_audio)
659 enable_bits |= SDVO_AUDIO_ENABLE;
660
661 temp = I915_READ(intel_hdmi->sdvox_reg);
662
663 /* HW workaround for IBX, we need to move the port to transcoder A
664 * before disabling it. */
665 if (HAS_PCH_IBX(dev)) {
666 struct drm_crtc *crtc = encoder->base.crtc;
667 int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;
668
669 if (temp & SDVO_PIPE_B_SELECT) {
670 temp &= ~SDVO_PIPE_B_SELECT;
671 I915_WRITE(intel_hdmi->sdvox_reg, temp);
672 POSTING_READ(intel_hdmi->sdvox_reg);
673
674 /* Again we need to write this twice. */
675 I915_WRITE(intel_hdmi->sdvox_reg, temp);
676 POSTING_READ(intel_hdmi->sdvox_reg);
677
678 /* Transcoder selection bits only update
679 * effectively on vblank. */
680 if (crtc)
681 intel_wait_for_vblank(dev, pipe);
682 else
683 msleep(50);
684 }
659 } 685 }
660 686
687 /* HW workaround, need to toggle enable bit off and on for 12bpc, but
688 * we do this anyway which shows more stable in testing.
689 */
690 if (HAS_PCH_SPLIT(dev)) {
691 I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE);
692 POSTING_READ(intel_hdmi->sdvox_reg);
693 }
694
695 temp &= ~enable_bits;
696
661 I915_WRITE(intel_hdmi->sdvox_reg, temp); 697 I915_WRITE(intel_hdmi->sdvox_reg, temp);
662 POSTING_READ(intel_hdmi->sdvox_reg); 698 POSTING_READ(intel_hdmi->sdvox_reg);
663 699
@@ -849,23 +885,23 @@ static void intel_hdmi_destroy(struct drm_connector *connector)
849} 885}
850 886
851static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs_hsw = { 887static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs_hsw = {
852 .dpms = intel_ddi_dpms,
853 .mode_fixup = intel_hdmi_mode_fixup, 888 .mode_fixup = intel_hdmi_mode_fixup,
854 .prepare = intel_encoder_prepare, 889 .prepare = intel_encoder_noop,
855 .mode_set = intel_ddi_mode_set, 890 .mode_set = intel_ddi_mode_set,
856 .commit = intel_encoder_commit, 891 .commit = intel_encoder_noop,
892 .disable = intel_encoder_disable,
857}; 893};
858 894
859static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = { 895static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = {
860 .dpms = intel_hdmi_dpms,
861 .mode_fixup = intel_hdmi_mode_fixup, 896 .mode_fixup = intel_hdmi_mode_fixup,
862 .prepare = intel_encoder_prepare, 897 .prepare = intel_encoder_noop,
863 .mode_set = intel_hdmi_mode_set, 898 .mode_set = intel_hdmi_mode_set,
864 .commit = intel_encoder_commit, 899 .commit = intel_encoder_noop,
900 .disable = intel_encoder_disable,
865}; 901};
866 902
867static const struct drm_connector_funcs intel_hdmi_connector_funcs = { 903static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
868 .dpms = drm_helper_connector_dpms, 904 .dpms = intel_connector_dpms,
869 .detect = intel_hdmi_detect, 905 .detect = intel_hdmi_detect,
870 .fill_modes = drm_helper_probe_single_connector_modes, 906 .fill_modes = drm_helper_probe_single_connector_modes,
871 .set_property = intel_hdmi_set_property, 907 .set_property = intel_hdmi_set_property,
@@ -964,10 +1000,18 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port)
964 intel_hdmi->set_infoframes = cpt_set_infoframes; 1000 intel_hdmi->set_infoframes = cpt_set_infoframes;
965 } 1001 }
966 1002
967 if (IS_HASWELL(dev)) 1003 if (IS_HASWELL(dev)) {
968 drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs_hsw); 1004 intel_encoder->enable = intel_enable_ddi;
969 else 1005 intel_encoder->disable = intel_disable_ddi;
970 drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); 1006 drm_encoder_helper_add(&intel_encoder->base,
1007 &intel_hdmi_helper_funcs_hsw);
1008 } else {
1009 intel_encoder->enable = intel_enable_hdmi;
1010 intel_encoder->disable = intel_disable_hdmi;
1011 drm_encoder_helper_add(&intel_encoder->base,
1012 &intel_hdmi_helper_funcs);
1013 }
1014
971 1015
972 intel_hdmi_add_properties(intel_hdmi, connector); 1016 intel_hdmi_add_properties(intel_hdmi, connector);
973 1017