drm/i915: dynamic Haswell display power well support
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Tue, 29 Jan 2013 18:35:20 +0000 (16:35 -0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Thu, 31 Jan 2013 10:50:11 +0000 (11:50 +0100)
We can disable (almost) all the display hw if we only use pipe A, with
the integrated edp transcoder on port A. Because we don't set the cpu
transcoder that early (yet), we need to help us with a trick to simply
check for any edp encoders.

v2: Paulo Zanoni pointed out that we also need to configure the eDP
cpu transcoder correctly.

v3: Made by Paulo Zanoni
  - Rebase patch to be on top of "fix intel_init_power_wells" patch
  - Fix typos
  - Fix a small bug by adding a "connectors_active" check
  - Restore the initial code that unconditionally enables the power
    well when taking over from the BIOS

v4: Made by Paulo Zanoni
  - One more typo spotted by Jani Nikula

v5: Made by Paulo Zanoni
  - Rebase

Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_display.c

index 33b911218023bceae87a084ac867a224b4538688..cedf4ab5ff16228debe97435f86bf694d6af87b2 100644 (file)
@@ -988,7 +988,13 @@ void intel_ddi_enable_pipe_func(struct drm_crtc *crtc)
        if (cpu_transcoder == TRANSCODER_EDP) {
                switch (pipe) {
                case PIPE_A:
-                       temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
+                       /* Can only use the always-on power well for eDP when
+                        * not using the panel fitter, and when not using motion
+                         * blur mitigation (which we don't support). */
+                       if (dev_priv->pch_pf_size)
+                               temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
+                       else
+                               temp |= TRANS_DDI_EDP_INPUT_A_ON;
                        break;
                case PIPE_B:
                        temp |= TRANS_DDI_EDP_INPUT_B_ONOFF;
index 429b66bcb5b28314ab428f984c02130a5240d290..1f1d045912fb086392d52c9c9a4a17370a8ffed7 100644 (file)
@@ -5607,6 +5607,35 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
        return fdi_config_ok ? ret : -EINVAL;
 }
 
+static void haswell_modeset_global_resources(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       bool enable = false;
+       struct intel_crtc *crtc;
+       struct intel_encoder *encoder;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) {
+               if (crtc->pipe != PIPE_A && crtc->base.enabled)
+                       enable = true;
+               /* XXX: Should check for edp transcoder here, but thanks to init
+                * sequence that's not yet available. Just in case desktop eDP
+                * on PORT D is possible on haswell, too. */
+       }
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
+                           base.head) {
+               if (encoder->type != INTEL_OUTPUT_EDP &&
+                   encoder->connectors_active)
+                       enable = true;
+       }
+
+       /* Even the eDP panel fitter is outside the always-on well. */
+       if (dev_priv->pch_pf_size)
+               enable = true;
+
+       intel_set_power_well(dev, enable);
+}
+
 static int haswell_crtc_mode_set(struct drm_crtc *crtc,
                                 struct drm_display_mode *mode,
                                 struct drm_display_mode *adjusted_mode,
@@ -8480,6 +8509,8 @@ static void intel_init_display(struct drm_device *dev)
                } else if (IS_HASWELL(dev)) {
                        dev_priv->display.fdi_link_train = hsw_fdi_link_train;
                        dev_priv->display.write_eld = haswell_write_eld;
+                       dev_priv->display.modeset_global_resources =
+                               haswell_modeset_global_resources;
                }
        } else if (IS_G4X(dev)) {
                dev_priv->display.write_eld = g4x_write_eld;