drm/i915: Do not touch the PCH SSC reference if a PLL is using it
[sfrench/cifs-2.6.git] / drivers / gpu / drm / i915 / intel_display.c
index 04fb75af48b2810fb40760bb2c3dbb7adbde7c49..352c42826cb1a2482bfc7e83971f78e4736c5a03 100644 (file)
@@ -2463,10 +2463,14 @@ static unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier)
  * main surface.
  */
 static const struct drm_format_info ccs_formats[] = {
-       { .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 2, .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, },
-       { .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 2, .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, },
-       { .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 2, .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, },
-       { .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 2, .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, },
+       { .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 2,
+         .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, },
+       { .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 2,
+         .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, },
+       { .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 2,
+         .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, .has_alpha = true, },
+       { .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 2,
+         .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, .has_alpha = true, },
 };
 
 static const struct drm_format_info *
@@ -8661,6 +8665,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
                pipe_config->cgm_mode = I915_READ(CGM_PIPE_MODE(crtc->pipe));
 
        i9xx_get_pipe_color_config(pipe_config);
+       intel_color_get_config(pipe_config);
 
        if (INTEL_GEN(dev_priv) < 4)
                pipe_config->double_wide = tmp & PIPECONF_DOUBLE_WIDE;
@@ -9121,22 +9126,95 @@ static void lpt_bend_clkout_dp(struct drm_i915_private *dev_priv, int steps)
 
 #undef BEND_IDX
 
+static bool spll_uses_pch_ssc(struct drm_i915_private *dev_priv)
+{
+       u32 fuse_strap = I915_READ(FUSE_STRAP);
+       u32 ctl = I915_READ(SPLL_CTL);
+
+       if ((ctl & SPLL_PLL_ENABLE) == 0)
+               return false;
+
+       if ((ctl & SPLL_PLL_REF_MASK) == SPLL_PLL_SSC &&
+           (fuse_strap & HSW_CPU_SSC_ENABLE) == 0)
+               return true;
+
+       if (IS_BROADWELL(dev_priv) &&
+           (ctl & SPLL_PLL_REF_MASK) == SPLL_PLL_NON_SSC)
+               return true;
+
+       return false;
+}
+
+static bool wrpll_uses_pch_ssc(struct drm_i915_private *dev_priv,
+                              enum intel_dpll_id id)
+{
+       u32 fuse_strap = I915_READ(FUSE_STRAP);
+       u32 ctl = I915_READ(WRPLL_CTL(id));
+
+       if ((ctl & WRPLL_PLL_ENABLE) == 0)
+               return false;
+
+       if ((ctl & WRPLL_PLL_REF_MASK) == WRPLL_PLL_SSC)
+               return true;
+
+       if ((IS_BROADWELL(dev_priv) || IS_HSW_ULT(dev_priv)) &&
+           (ctl & WRPLL_PLL_REF_MASK) == WRPLL_PLL_NON_SSC &&
+           (fuse_strap & HSW_CPU_SSC_ENABLE) == 0)
+               return true;
+
+       return false;
+}
+
 static void lpt_init_pch_refclk(struct drm_i915_private *dev_priv)
 {
        struct intel_encoder *encoder;
-       bool has_vga = false;
+       bool pch_ssc_in_use = false;
+       bool has_fdi = false;
 
        for_each_intel_encoder(&dev_priv->drm, encoder) {
                switch (encoder->type) {
                case INTEL_OUTPUT_ANALOG:
-                       has_vga = true;
+                       has_fdi = true;
                        break;
                default:
                        break;
                }
        }
 
-       if (has_vga) {
+       /*
+        * The BIOS may have decided to use the PCH SSC
+        * reference so we must not disable it until the
+        * relevant PLLs have stopped relying on it. We'll
+        * just leave the PCH SSC reference enabled in case
+        * any active PLL is using it. It will get disabled
+        * after runtime suspend if we don't have FDI.
+        *
+        * TODO: Move the whole reference clock handling
+        * to the modeset sequence proper so that we can
+        * actually enable/disable/reconfigure these things
+        * safely. To do that we need to introduce a real
+        * clock hierarchy. That would also allow us to do
+        * clock bending finally.
+        */
+       if (spll_uses_pch_ssc(dev_priv)) {
+               DRM_DEBUG_KMS("SPLL using PCH SSC\n");
+               pch_ssc_in_use = true;
+       }
+
+       if (wrpll_uses_pch_ssc(dev_priv, DPLL_ID_WRPLL1)) {
+               DRM_DEBUG_KMS("WRPLL1 using PCH SSC\n");
+               pch_ssc_in_use = true;
+       }
+
+       if (wrpll_uses_pch_ssc(dev_priv, DPLL_ID_WRPLL2)) {
+               DRM_DEBUG_KMS("WRPLL2 using PCH SSC\n");
+               pch_ssc_in_use = true;
+       }
+
+       if (pch_ssc_in_use)
+               return;
+
+       if (has_fdi) {
                lpt_bend_clkout_dp(dev_priv, 0);
                lpt_enable_clkout_dp(dev_priv, true, true);
        } else {
@@ -9758,6 +9836,7 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
        pipe_config->csc_mode = I915_READ(PIPE_CSC_MODE(crtc->pipe));
 
        i9xx_get_pipe_color_config(pipe_config);
+       intel_color_get_config(pipe_config);
 
        if (I915_READ(PCH_TRANSCONF(crtc->pipe)) & TRANS_ENABLE) {
                struct intel_shared_dpll *pll;
@@ -10206,6 +10285,8 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
                i9xx_get_pipe_color_config(pipe_config);
        }
 
+       intel_color_get_config(pipe_config);
+
        power_domain = POWER_DOMAIN_PIPE_PANEL_FITTER(crtc->pipe);
        WARN_ON(power_domain_mask & BIT_ULL(power_domain));
 
@@ -11705,17 +11786,19 @@ compute_baseline_pipe_bpp(struct intel_crtc *crtc,
 static void intel_dump_crtc_timings(const struct drm_display_mode *mode)
 {
        DRM_DEBUG_KMS("crtc timings: %d %d %d %d %d %d %d %d %d, "
-                       "type: 0x%x flags: 0x%x\n",
-               mode->crtc_clock,
-               mode->crtc_hdisplay, mode->crtc_hsync_start,
-               mode->crtc_hsync_end, mode->crtc_htotal,
-               mode->crtc_vdisplay, mode->crtc_vsync_start,
-               mode->crtc_vsync_end, mode->crtc_vtotal, mode->type, mode->flags);
+                     "type: 0x%x flags: 0x%x\n",
+                     mode->crtc_clock,
+                     mode->crtc_hdisplay, mode->crtc_hsync_start,
+                     mode->crtc_hsync_end, mode->crtc_htotal,
+                     mode->crtc_vdisplay, mode->crtc_vsync_start,
+                     mode->crtc_vsync_end, mode->crtc_vtotal,
+                     mode->type, mode->flags);
 }
 
 static inline void
-intel_dump_m_n_config(struct intel_crtc_state *pipe_config, char *id,
-                     unsigned int lane_count, struct intel_link_m_n *m_n)
+intel_dump_m_n_config(const struct intel_crtc_state *pipe_config,
+                     const char *id, unsigned int lane_count,
+                     const struct intel_link_m_n *m_n)
 {
        DRM_DEBUG_KMS("%s: lanes: %i; gmch_m: %u, gmch_n: %u, link_m: %u, link_n: %u, tu: %u\n",
                      id, lane_count,
@@ -11793,26 +11876,54 @@ static const char *output_formats(enum intel_output_format format)
        return output_format_str[format];
 }
 
-static void intel_dump_pipe_config(struct intel_crtc_state *pipe_config,
+static void intel_dump_plane_state(const struct intel_plane_state *plane_state)
+{
+       struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       struct drm_format_name_buf format_name;
+
+       if (!fb) {
+               DRM_DEBUG_KMS("[PLANE:%d:%s] fb: [NOFB], visible: %s\n",
+                             plane->base.base.id, plane->base.name,
+                             yesno(plane_state->base.visible));
+               return;
+       }
+
+       DRM_DEBUG_KMS("[PLANE:%d:%s] fb: [FB:%d] %ux%u format = %s, visible: %s\n",
+                     plane->base.base.id, plane->base.name,
+                     fb->base.id, fb->width, fb->height,
+                     drm_get_format_name(fb->format->format, &format_name),
+                     yesno(plane_state->base.visible));
+       DRM_DEBUG_KMS("\trotation: 0x%x, scaler: %d\n",
+                     plane_state->base.rotation, plane_state->scaler_id);
+       if (plane_state->base.visible)
+               DRM_DEBUG_KMS("\tsrc: " DRM_RECT_FP_FMT " dst: " DRM_RECT_FMT "\n",
+                             DRM_RECT_FP_ARG(&plane_state->base.src),
+                             DRM_RECT_ARG(&plane_state->base.dst));
+}
+
+static void intel_dump_pipe_config(const struct intel_crtc_state *pipe_config,
+                                  struct intel_atomic_state *state,
                                   const char *context)
 {
        struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct drm_plane *plane;
-       struct intel_plane *intel_plane;
-       struct intel_plane_state *state;
-       struct drm_framebuffer *fb;
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       const struct intel_plane_state *plane_state;
+       struct intel_plane *plane;
        char buf[64];
+       int i;
 
-       DRM_DEBUG_KMS("[CRTC:%d:%s]%s\n",
-                     crtc->base.base.id, crtc->base.name, context);
+       DRM_DEBUG_KMS("[CRTC:%d:%s] enable: %s %s\n",
+                     crtc->base.base.id, crtc->base.name,
+                     yesno(pipe_config->base.enable), context);
 
-       snprintf_output_types(buf, sizeof(buf), pipe_config->output_types);
-       DRM_DEBUG_KMS("output_types: %s (0x%x)\n",
-                     buf, pipe_config->output_types);
+       if (!pipe_config->base.enable)
+               goto dump_planes;
 
-       DRM_DEBUG_KMS("output format: %s\n",
+       snprintf_output_types(buf, sizeof(buf), pipe_config->output_types);
+       DRM_DEBUG_KMS("active: %s, output_types: %s (0x%x), output format: %s\n",
+                     yesno(pipe_config->base.active),
+                     buf, pipe_config->output_types,
                      output_formats(pipe_config->output_format));
 
        DRM_DEBUG_KMS("cpu_transcoder: %s, pipe bpp: %i, dithering: %i\n",
@@ -11833,10 +11944,8 @@ static void intel_dump_pipe_config(struct intel_crtc_state *pipe_config,
                                              &pipe_config->dp_m2_n2);
        }
 
-       DRM_DEBUG_KMS("audio: %i, infoframes: %i\n",
-                     pipe_config->has_audio, pipe_config->has_infoframe);
-
-       DRM_DEBUG_KMS("infoframes enabled: 0x%x\n",
+       DRM_DEBUG_KMS("audio: %i, infoframes: %i, infoframes enabled: 0x%x\n",
+                     pipe_config->has_audio, pipe_config->has_infoframe,
                      pipe_config->infoframes.enable);
 
        if (pipe_config->infoframes.enable &
@@ -11885,35 +11994,13 @@ static void intel_dump_pipe_config(struct intel_crtc_state *pipe_config,
 
        intel_dpll_dump_hw_state(dev_priv, &pipe_config->dpll_hw_state);
 
-       DRM_DEBUG_KMS("planes on this crtc\n");
-       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
-               struct drm_format_name_buf format_name;
-               intel_plane = to_intel_plane(plane);
-               if (intel_plane->pipe != crtc->pipe)
-                       continue;
-
-               state = to_intel_plane_state(plane->state);
-               fb = state->base.fb;
-               if (!fb) {
-                       DRM_DEBUG_KMS("[PLANE:%d:%s] disabled, scaler_id = %d\n",
-                                     plane->base.id, plane->name, state->scaler_id);
-                       continue;
-               }
+dump_planes:
+       if (!state)
+               return;
 
-               DRM_DEBUG_KMS("[PLANE:%d:%s] FB:%d, fb = %ux%u format = %s\n",
-                             plane->base.id, plane->name,
-                             fb->base.id, fb->width, fb->height,
-                             drm_get_format_name(fb->format->format, &format_name));
-               if (INTEL_GEN(dev_priv) >= 9)
-                       DRM_DEBUG_KMS("\tscaler:%d src %dx%d+%d+%d dst %dx%d+%d+%d\n",
-                                     state->scaler_id,
-                                     state->base.src.x1 >> 16,
-                                     state->base.src.y1 >> 16,
-                                     drm_rect_width(&state->base.src) >> 16,
-                                     drm_rect_height(&state->base.src) >> 16,
-                                     state->base.dst.x1, state->base.dst.y1,
-                                     drm_rect_width(&state->base.dst),
-                                     drm_rect_height(&state->base.dst));
+       for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
+               if (plane->pipe == crtc->pipe)
+                       intel_dump_plane_state(plane_state);
        }
 }
 
@@ -12017,9 +12104,9 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
 }
 
 static int
-intel_modeset_pipe_config(struct drm_crtc *crtc,
-                         struct intel_crtc_state *pipe_config)
+intel_modeset_pipe_config(struct intel_crtc_state *pipe_config)
 {
+       struct drm_crtc *crtc = pipe_config->base.crtc;
        struct drm_atomic_state *state = pipe_config->base.state;
        struct intel_encoder *encoder;
        struct drm_connector *connector;
@@ -12153,7 +12240,7 @@ encoder_retry:
        return 0;
 }
 
-static bool intel_fuzzy_clock_check(int clock1, int clock2)
+bool intel_fuzzy_clock_check(int clock1, int clock2)
 {
        int diff;
 
@@ -12903,8 +12990,8 @@ verify_crtc_state(struct drm_crtc *crtc,
        if (!intel_pipe_config_compare(dev_priv, sw_config,
                                       pipe_config, false)) {
                I915_STATE_WARN(1, "pipe state doesn't match!\n");
-               intel_dump_pipe_config(pipe_config, "[hw state]");
-               intel_dump_pipe_config(sw_config, "[sw state]");
+               intel_dump_pipe_config(pipe_config, NULL, "[hw state]");
+               intel_dump_pipe_config(sw_config, NULL, "[sw state]");
        }
 }
 
@@ -13222,38 +13309,37 @@ static int intel_modeset_all_pipes(struct drm_atomic_state *state)
        return 0;
 }
 
-static int intel_modeset_checks(struct drm_atomic_state *state)
+static int intel_modeset_checks(struct intel_atomic_state *state)
 {
-       struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
-       struct drm_i915_private *dev_priv = to_i915(state->dev);
-       struct drm_crtc *crtc;
-       struct drm_crtc_state *old_crtc_state, *new_crtc_state;
+       struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+       struct intel_crtc_state *old_crtc_state, *new_crtc_state;
+       struct intel_crtc *crtc;
        int ret = 0, i;
 
-       if (!check_digital_port_conflicts(intel_state)) {
+       if (!check_digital_port_conflicts(state)) {
                DRM_DEBUG_KMS("rejecting conflicting digital port configuration\n");
                return -EINVAL;
        }
 
        /* keep the current setting */
-       if (!intel_state->cdclk.force_min_cdclk_changed)
-               intel_state->cdclk.force_min_cdclk =
-                       dev_priv->cdclk.force_min_cdclk;
+       if (!state->cdclk.force_min_cdclk_changed)
+               state->cdclk.force_min_cdclk = dev_priv->cdclk.force_min_cdclk;
 
-       intel_state->modeset = true;
-       intel_state->active_crtcs = dev_priv->active_crtcs;
-       intel_state->cdclk.logical = dev_priv->cdclk.logical;
-       intel_state->cdclk.actual = dev_priv->cdclk.actual;
-       intel_state->cdclk.pipe = INVALID_PIPE;
+       state->modeset = true;
+       state->active_crtcs = dev_priv->active_crtcs;
+       state->cdclk.logical = dev_priv->cdclk.logical;
+       state->cdclk.actual = dev_priv->cdclk.actual;
+       state->cdclk.pipe = INVALID_PIPE;
 
-       for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
-               if (new_crtc_state->active)
-                       intel_state->active_crtcs |= 1 << i;
+       for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
+                                           new_crtc_state, i) {
+               if (new_crtc_state->base.active)
+                       state->active_crtcs |= 1 << i;
                else
-                       intel_state->active_crtcs &= ~(1 << i);
+                       state->active_crtcs &= ~(1 << i);
 
-               if (old_crtc_state->active != new_crtc_state->active)
-                       intel_state->active_pipe_changes |= drm_crtc_mask(crtc);
+               if (old_crtc_state->base.active != new_crtc_state->base.active)
+                       state->active_pipe_changes |= drm_crtc_mask(&crtc->base);
        }
 
        /*
@@ -13266,7 +13352,7 @@ static int intel_modeset_checks(struct drm_atomic_state *state)
        if (dev_priv->display.modeset_calc_cdclk) {
                enum pipe pipe;
 
-               ret = dev_priv->display.modeset_calc_cdclk(intel_state);
+               ret = dev_priv->display.modeset_calc_cdclk(state);
                if (ret < 0)
                        return ret;
 
@@ -13276,19 +13362,19 @@ static int intel_modeset_checks(struct drm_atomic_state *state)
                 * touching the hardware
                 */
                if (intel_cdclk_changed(&dev_priv->cdclk.logical,
-                                       &intel_state->cdclk.logical)) {
-                       ret = intel_lock_all_pipes(state);
+                                       &state->cdclk.logical)) {
+                       ret = intel_lock_all_pipes(&state->base);
                        if (ret < 0)
                                return ret;
                }
 
-               if (is_power_of_2(intel_state->active_crtcs)) {
+               if (is_power_of_2(state->active_crtcs)) {
                        struct drm_crtc *crtc;
                        struct drm_crtc_state *crtc_state;
 
-                       pipe = ilog2(intel_state->active_crtcs);
+                       pipe = ilog2(state->active_crtcs);
                        crtc = &intel_get_crtc_for_pipe(dev_priv, pipe)->base;
-                       crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+                       crtc_state = drm_atomic_get_new_crtc_state(&state->base, crtc);
                        if (crtc_state && needs_modeset(crtc_state))
                                pipe = INVALID_PIPE;
                } else {
@@ -13299,33 +13385,33 @@ static int intel_modeset_checks(struct drm_atomic_state *state)
                if (pipe != INVALID_PIPE &&
                    intel_cdclk_needs_cd2x_update(dev_priv,
                                                  &dev_priv->cdclk.actual,
-                                                 &intel_state->cdclk.actual)) {
-                       ret = intel_lock_all_pipes(state);
+                                                 &state->cdclk.actual)) {
+                       ret = intel_lock_all_pipes(&state->base);
                        if (ret < 0)
                                return ret;
 
-                       intel_state->cdclk.pipe = pipe;
+                       state->cdclk.pipe = pipe;
                } else if (intel_cdclk_needs_modeset(&dev_priv->cdclk.actual,
-                                                    &intel_state->cdclk.actual)) {
-                       ret = intel_modeset_all_pipes(state);
+                                                    &state->cdclk.actual)) {
+                       ret = intel_modeset_all_pipes(&state->base);
                        if (ret < 0)
                                return ret;
 
-                       intel_state->cdclk.pipe = INVALID_PIPE;
+                       state->cdclk.pipe = INVALID_PIPE;
                }
 
                DRM_DEBUG_KMS("New cdclk calculated to be logical %u kHz, actual %u kHz\n",
-                             intel_state->cdclk.logical.cdclk,
-                             intel_state->cdclk.actual.cdclk);
+                             state->cdclk.logical.cdclk,
+                             state->cdclk.actual.cdclk);
                DRM_DEBUG_KMS("New voltage level calculated to be logical %u, actual %u\n",
-                             intel_state->cdclk.logical.voltage_level,
-                             intel_state->cdclk.actual.voltage_level);
+                             state->cdclk.logical.voltage_level,
+                             state->cdclk.actual.voltage_level);
        }
 
-       intel_modeset_clear_plls(intel_state);
+       intel_modeset_clear_plls(state);
 
        if (IS_HASWELL(dev_priv))
-               return haswell_mode_set_planes_workaround(intel_state);
+               return haswell_mode_set_planes_workaround(state);
 
        return 0;
 }
@@ -13353,93 +13439,106 @@ static int calc_watermark_data(struct intel_atomic_state *state)
  * @state: state to validate
  */
 static int intel_atomic_check(struct drm_device *dev,
-                             struct drm_atomic_state *state)
+                             struct drm_atomic_state *_state)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
-       struct drm_crtc *crtc;
-       struct drm_crtc_state *old_crtc_state, *crtc_state;
+       struct intel_atomic_state *state = to_intel_atomic_state(_state);
+       struct intel_crtc_state *old_crtc_state, *new_crtc_state;
+       struct intel_crtc *crtc;
        int ret, i;
-       bool any_ms = intel_state->cdclk.force_min_cdclk_changed;
+       bool any_ms = state->cdclk.force_min_cdclk_changed;
 
        /* Catch I915_MODE_FLAG_INHERITED */
-       for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state,
-                                     crtc_state, i) {
-               if (crtc_state->mode.private_flags !=
-                   old_crtc_state->mode.private_flags)
-                       crtc_state->mode_changed = true;
+       for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
+                                           new_crtc_state, i) {
+               if (new_crtc_state->base.mode.private_flags !=
+                   old_crtc_state->base.mode.private_flags)
+                       new_crtc_state->base.mode_changed = true;
        }
 
-       ret = drm_atomic_helper_check_modeset(dev, state);
+       ret = drm_atomic_helper_check_modeset(dev, &state->base);
        if (ret)
-               return ret;
-
-       for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, crtc_state, i) {
-               struct intel_crtc_state *pipe_config =
-                       to_intel_crtc_state(crtc_state);
+               goto fail;
 
-               if (!needs_modeset(crtc_state))
+       for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
+                                           new_crtc_state, i) {
+               if (!needs_modeset(&new_crtc_state->base))
                        continue;
 
-               if (!crtc_state->enable) {
+               if (!new_crtc_state->base.enable) {
                        any_ms = true;
                        continue;
                }
 
-               ret = intel_modeset_pipe_config(crtc, pipe_config);
-               if (ret == -EDEADLK)
-                       return ret;
-               if (ret) {
-                       intel_dump_pipe_config(pipe_config, "[failed]");
-                       return ret;
-               }
+               ret = intel_modeset_pipe_config(new_crtc_state);
+               if (ret)
+                       goto fail;
 
-               if (intel_pipe_config_compare(dev_priv,
-                                       to_intel_crtc_state(old_crtc_state),
-                                       pipe_config, true)) {
-                       crtc_state->mode_changed = false;
-                       pipe_config->update_pipe = true;
+               if (intel_pipe_config_compare(dev_priv, old_crtc_state,
+                                             new_crtc_state, true)) {
+                       new_crtc_state->base.mode_changed = false;
+                       new_crtc_state->update_pipe = true;
                }
 
-               if (needs_modeset(crtc_state))
+               if (needs_modeset(&new_crtc_state->base))
                        any_ms = true;
-
-               intel_dump_pipe_config(pipe_config,
-                                      needs_modeset(crtc_state) ?
-                                      "[modeset]" : "[fastset]");
        }
 
-       ret = drm_dp_mst_atomic_check(state);
+       ret = drm_dp_mst_atomic_check(&state->base);
        if (ret)
-               return ret;
+               goto fail;
 
        if (any_ms) {
                ret = intel_modeset_checks(state);
-
                if (ret)
-                       return ret;
+                       goto fail;
        } else {
-               intel_state->cdclk.logical = dev_priv->cdclk.logical;
+               state->cdclk.logical = dev_priv->cdclk.logical;
        }
 
-       ret = icl_add_linked_planes(intel_state);
+       ret = icl_add_linked_planes(state);
        if (ret)
-               return ret;
+               goto fail;
 
-       ret = drm_atomic_helper_check_planes(dev, state);
+       ret = drm_atomic_helper_check_planes(dev, &state->base);
        if (ret)
-               return ret;
+               goto fail;
 
-       intel_fbc_choose_crtc(dev_priv, intel_state);
-       ret = calc_watermark_data(intel_state);
+       intel_fbc_choose_crtc(dev_priv, state);
+       ret = calc_watermark_data(state);
        if (ret)
-               return ret;
+               goto fail;
 
-       ret = intel_bw_atomic_check(intel_state);
+       ret = intel_bw_atomic_check(state);
        if (ret)
-               return ret;
+               goto fail;
+
+       for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
+                                           new_crtc_state, i) {
+               if (!needs_modeset(&new_crtc_state->base) &&
+                   !new_crtc_state->update_pipe)
+                       continue;
+
+               intel_dump_pipe_config(new_crtc_state, state,
+                                      needs_modeset(&new_crtc_state->base) ?
+                                      "[modeset]" : "[fastset]");
+       }
 
        return 0;
+
+ fail:
+       if (ret == -EDEADLK)
+               return ret;
+
+       /*
+        * FIXME would probably be nice to know which crtc specifically
+        * caused the failure, in cases where we can pinpoint it.
+        */
+       for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
+                                           new_crtc_state, i)
+               intel_dump_pipe_config(new_crtc_state, state, "[failed]");
+
+       return ret;
 }
 
 static int intel_atomic_prepare_commit(struct drm_device *dev,
@@ -16665,7 +16764,7 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
        for_each_intel_crtc(&dev_priv->drm, crtc) {
                crtc_state = to_intel_crtc_state(crtc->base.state);
                intel_sanitize_crtc(crtc, ctx);
-               intel_dump_pipe_config(crtc_state, "[setup_hw_state]");
+               intel_dump_pipe_config(crtc_state, NULL, "[setup_hw_state]");
        }
 
        intel_modeset_update_connector_atomic_state(dev);