m2_n2->gmch_m, m2_n2->gmch_n, !adjust) &&
            intel_compare_m_n(m_n->link_m, m_n->link_n,
                              m2_n2->link_m, m2_n2->link_n, !adjust)) {
-               if (adjust)
-                       *m2_n2 = *m_n;
-
                return true;
        }
 
        return 0;
 }
 
+static void intel_crtc_check_fastset(struct intel_crtc_state *old_crtc_state,
+                                    struct intel_crtc_state *new_crtc_state)
+{
+       struct drm_i915_private *dev_priv =
+               to_i915(new_crtc_state->base.crtc->dev);
+
+       if (!intel_pipe_config_compare(dev_priv, old_crtc_state,
+                                      new_crtc_state, true))
+               return;
+
+       new_crtc_state->base.mode_changed = false;
+       new_crtc_state->update_pipe = true;
+
+       /*
+        * If we're not doing the full modeset we want to
+        * keep the current M/N values as they may be
+        * sufficiently different to the computed values
+        * to cause problems.
+        *
+        * FIXME: should really copy more fuzzy state here
+        */
+       new_crtc_state->fdi_m_n = old_crtc_state->fdi_m_n;
+       new_crtc_state->dp_m_n = old_crtc_state->dp_m_n;
+       new_crtc_state->dp_m2_n2 = old_crtc_state->dp_m2_n2;
+       new_crtc_state->has_drrs = old_crtc_state->has_drrs;
+}
+
 /**
  * intel_atomic_check - validate state object
  * @dev: drm device
                        return ret;
                }
 
-               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;
-               }
+               intel_crtc_check_fastset(to_intel_crtc_state(old_crtc_state),
+                                        pipe_config);
 
                if (needs_modeset(crtc_state))
                        any_ms = true;