On Sun, 19 Aug 2012 21:12:21 +0200 Daniel Vetter <daniel.vetter at ffwll.ch> wrote: > +/* Even simpler default implementation, if there's really no special case to > + * consider. */ > +void intel_connector_dpms(struct drm_connector *connector, int mode) > +{ > + struct intel_encoder *encoder = intel_attached_encoder(connector); > + > + /* All the simple cases only support two dpms states. */ > + if (mode != DRM_MODE_DPMS_ON) > + mode = DRM_MODE_DPMS_OFF; > + > + if (mode == connector->dpms) > + return; > + > + connector->dpms = mode; > + > + /* Only need to change hw state when actually enabled */ > + if (encoder->base.crtc) > + intel_encoder_dpms(encoder, mode); > + else > + encoder->connectors_active = false; > +} We only ever call this under the mode_config lock right? > + > static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, > const struct drm_display_mode *mode, > struct drm_display_mode *adjusted_mode) > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h > index 9a5adcc..759dcba 100644 > --- a/drivers/gpu/drm/i915/intel_drv.h > +++ b/drivers/gpu/drm/i915/intel_drv.h > @@ -140,6 +140,7 @@ struct intel_encoder { > * simple flag is enough to compute the possible_clones mask. > */ > bool cloneable; > + bool connectors_active; > void (*hot_plug)(struct intel_encoder *); > void (*enable)(struct intel_encoder *); > void (*disable)(struct intel_encoder *); > @@ -412,7 +413,11 @@ extern enum drm_connector_status intel_panel_detect(struct drm_device *dev); > extern void intel_crtc_load_lut(struct drm_crtc *crtc); > extern void intel_encoder_prepare(struct drm_encoder *encoder); > extern void intel_encoder_commit(struct drm_encoder *encoder); > +extern void intel_encoder_noop(struct drm_encoder *encoder); > +extern void intel_encoder_disable(struct drm_encoder *encoder); > extern void intel_encoder_destroy(struct drm_encoder *encoder); > +extern void intel_encoder_dpms(struct intel_encoder *encoder, int mode); > +extern void intel_connector_dpms(struct drm_connector *, int mode); > > static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector) > { > @@ -519,7 +524,8 @@ extern void intel_disable_gt_powersave(struct drm_device *dev); > extern void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv); > extern void ironlake_teardown_rc6(struct drm_device *dev); > > -extern void intel_ddi_dpms(struct drm_encoder *encoder, int mode); > +extern void intel_enable_ddi(struct intel_encoder *encoder); > +extern void intel_disable_ddi(struct intel_encoder *encoder); > extern void intel_ddi_mode_set(struct drm_encoder *encoder, > struct drm_display_mode *mode, > struct drm_display_mode *adjusted_mode); > diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c > index e4c37bb..acddaaa 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, > intel_hdmi->set_infoframes(encoder, adjusted_mode); > } > > -static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) > +static void intel_enable_hdmi(struct intel_encoder *encoder) > { > - 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 temp; > u32 enable_bits = SDVO_ENABLE; > > @@ -617,31 +617,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,12 +633,67 @@ 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); > + } > } The IBX stuff can be split out into a separate function hook with a later patch... Reviewed-by: Jesse Barnes <jbarnes at virtuousgeek.org> -- Jesse Barnes, Intel Open Source Technology Center