Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/i915: make sure VDD is turned off during system suspend

Atm we may leave eDP VDD enabled during system suspend after the CRTCs
are disabled through an HPD->DPCD read event. So disable VDD during
suspend at a point when no HPDs can occur.

Note that runtime suspend doesn't have the same problem, since there the
RPM ref held by VDD provides already the needed serialization.

v2:
- add note to commit message about the runtime suspend path (Ville)
- use edp_panel_vdd_off_sync(), so we can keep the WARN in
edp_panel_vdd_off() (Ville)
v3:
- rebased on -fixes (for_each_intel_encoder()->list_for_each_entry())
(Imre)

Signed-off-by: Imre Deak <imre.deak@intel.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> (v2)
Cc: stable@vger.kernel.org (3.16+)
[Jani: fix sparse warning reported by Fengguang Wu]
Signed-off-by: Jani Nikula <jani.nikula@intel.com>

authored by

Imre Deak and committed by
Jani Nikula
07f9cd0b 1d0d343a

+34
+17
drivers/gpu/drm/i915/i915_drv.c
··· 509 509 cancel_delayed_work_sync(&dev_priv->hotplug_reenable_work); 510 510 } 511 511 512 + static void intel_suspend_encoders(struct drm_i915_private *dev_priv) 513 + { 514 + struct drm_device *dev = dev_priv->dev; 515 + struct drm_encoder *encoder; 516 + 517 + drm_modeset_lock_all(dev); 518 + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 519 + struct intel_encoder *intel_encoder = to_intel_encoder(encoder); 520 + 521 + if (intel_encoder->suspend) 522 + intel_encoder->suspend(intel_encoder); 523 + } 524 + drm_modeset_unlock_all(dev); 525 + } 526 + 512 527 static int i915_drm_freeze(struct drm_device *dev) 513 528 { 514 529 struct drm_i915_private *dev_priv = dev->dev_private; ··· 569 554 570 555 intel_runtime_pm_disable_interrupts(dev); 571 556 intel_hpd_cancel_work(dev_priv); 557 + 558 + intel_suspend_encoders(dev_priv); 572 559 573 560 intel_suspend_gt_powersave(dev); 574 561
+11
drivers/gpu/drm/i915/intel_dp.c
··· 4003 4003 kfree(intel_dig_port); 4004 4004 } 4005 4005 4006 + static void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder) 4007 + { 4008 + struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base); 4009 + 4010 + if (!is_edp(intel_dp)) 4011 + return; 4012 + 4013 + edp_panel_vdd_off_sync(intel_dp); 4014 + } 4015 + 4006 4016 static void intel_dp_encoder_reset(struct drm_encoder *encoder) 4007 4017 { 4008 4018 intel_edp_panel_vdd_sanitize(to_intel_encoder(encoder)); ··· 4741 4731 intel_encoder->disable = intel_disable_dp; 4742 4732 intel_encoder->get_hw_state = intel_dp_get_hw_state; 4743 4733 intel_encoder->get_config = intel_dp_get_config; 4734 + intel_encoder->suspend = intel_dp_encoder_suspend; 4744 4735 if (IS_CHERRYVIEW(dev)) { 4745 4736 intel_encoder->pre_pll_enable = chv_dp_pre_pll_enable; 4746 4737 intel_encoder->pre_enable = chv_pre_enable_dp;
+6
drivers/gpu/drm/i915/intel_drv.h
··· 153 153 * be set correctly before calling this function. */ 154 154 void (*get_config)(struct intel_encoder *, 155 155 struct intel_crtc_config *pipe_config); 156 + /* 157 + * Called during system suspend after all pending requests for the 158 + * encoder are flushed (for example for DP AUX transactions) and 159 + * device interrupts are disabled. 160 + */ 161 + void (*suspend)(struct intel_encoder *); 156 162 int crtc_mask; 157 163 enum hpd_pin hpd_pin; 158 164 };