Merge tag 'drm-intel-fixes-2015-07-15' into drm-intel-next-queued
[linux-drm-fsl-dcu.git] / drivers / gpu / drm / i915 / intel_display.c
index d013a34dde7fd528e1937e0015c2b41da44d8956..ede6528675969f6ef39e84ccf626614603dcc16c 100644 (file)
@@ -86,7 +86,6 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
 static void ironlake_pch_clock_get(struct intel_crtc *crtc,
                                   struct intel_crtc_state *pipe_config);
 
-static int intel_set_mode(struct drm_atomic_state *state);
 static int intel_framebuffer_init(struct drm_device *dev,
                                  struct intel_framebuffer *ifb,
                                  struct drm_mode_fb_cmd2 *mode_cmd,
@@ -109,14 +108,7 @@ static void skl_init_scalers(struct drm_device *dev, struct intel_crtc *intel_cr
        struct intel_crtc_state *crtc_state);
 static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state,
                           int num_connectors);
-
-static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe)
-{
-       if (!connector->mst_port)
-               return connector->encoder;
-       else
-               return &connector->mst_port->mst_encoders[pipe]->base;
-}
+static void intel_modeset_setup_hw_state(struct drm_device *dev);
 
 typedef struct {
        int     min, max;
@@ -3251,7 +3243,7 @@ void intel_finish_reset(struct drm_device *dev)
                dev_priv->display.hpd_irq_setup(dev);
        spin_unlock_irq(&dev_priv->irq_lock);
 
-       intel_modeset_setup_hw_state(dev, true);
+       intel_display_resume(dev);
 
        intel_hpd_init(dev_priv);
 
@@ -5195,6 +5187,9 @@ static unsigned long get_crtc_power_domains(struct drm_crtc *crtc)
        unsigned long mask;
        enum transcoder transcoder;
 
+       if (!crtc->state->active)
+               return 0;
+
        transcoder = intel_pipe_to_cpu_transcoder(dev->dev_private, pipe);
 
        mask = BIT(POWER_DOMAIN_PIPE(pipe));
@@ -5209,27 +5204,46 @@ static unsigned long get_crtc_power_domains(struct drm_crtc *crtc)
        return mask;
 }
 
-static void modeset_update_crtc_power_domains(struct drm_atomic_state *state)
+static unsigned long modeset_get_crtc_power_domains(struct drm_crtc *crtc)
 {
-       struct drm_device *dev = state->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long pipe_domains[I915_MAX_PIPES] = { 0, };
-       struct intel_crtc *crtc;
+       struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       enum intel_display_power_domain domain;
+       unsigned long domains, new_domains, old_domains;
 
-       /*
-        * First get all needed power domains, then put all unneeded, to avoid
-        * any unnecessary toggling of the power wells.
-        */
-       for_each_intel_crtc(dev, crtc) {
-               enum intel_display_power_domain domain;
+       old_domains = intel_crtc->enabled_power_domains;
+       intel_crtc->enabled_power_domains = new_domains = get_crtc_power_domains(crtc);
 
-               if (!crtc->base.state->enable)
-                       continue;
+       domains = new_domains & ~old_domains;
 
-               pipe_domains[crtc->pipe] = get_crtc_power_domains(&crtc->base);
+       for_each_power_domain(domain, domains)
+               intel_display_power_get(dev_priv, domain);
+
+       return old_domains & ~new_domains;
+}
+
+static void modeset_put_power_domains(struct drm_i915_private *dev_priv,
+                                     unsigned long domains)
+{
+       enum intel_display_power_domain domain;
 
-               for_each_power_domain(domain, pipe_domains[crtc->pipe])
-                       intel_display_power_get(dev_priv, domain);
+       for_each_power_domain(domain, domains)
+               intel_display_power_put(dev_priv, domain);
+}
+
+static void modeset_update_crtc_power_domains(struct drm_atomic_state *state)
+{
+       struct drm_device *dev = state->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long put_domains[I915_MAX_PIPES] = {};
+       struct drm_crtc_state *crtc_state;
+       struct drm_crtc *crtc;
+       int i;
+
+       for_each_crtc_in_state(state, crtc, crtc_state, i) {
+               if (needs_modeset(crtc->state))
+                       put_domains[to_intel_crtc(crtc)->pipe] =
+                               modeset_get_crtc_power_domains(crtc);
        }
 
        if (dev_priv->display.modeset_commit_cdclk) {
@@ -5240,16 +5254,9 @@ static void modeset_update_crtc_power_domains(struct drm_atomic_state *state)
                        dev_priv->display.modeset_commit_cdclk(state);
        }
 
-       for_each_intel_crtc(dev, crtc) {
-               enum intel_display_power_domain domain;
-
-               for_each_power_domain(domain, crtc->enabled_power_domains)
-                       intel_display_power_put(dev_priv, domain);
-
-               crtc->enabled_power_domains = pipe_domains[crtc->pipe];
-       }
-
-       intel_display_set_init_power(dev_priv, false);
+       for (i = 0; i < I915_MAX_PIPES; i++)
+               if (put_domains[i])
+                       modeset_put_power_domains(dev_priv, put_domains[i]);
 }
 
 static void intel_update_max_cdclk(struct drm_device *dev)
@@ -6198,6 +6205,7 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
 
        intel_crtc_disable_planes(crtc, crtc->state->plane_mask);
        dev_priv->display.crtc_disable(crtc);
+       intel_disable_shared_dpll(intel_crtc);
 
        domains = intel_crtc->enabled_power_domains;
        for_each_power_domain(domain, domains)
@@ -6209,12 +6217,58 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
  * turn all crtc's off, but do not adjust state
  * This has to be paired with a call to intel_modeset_setup_hw_state.
  */
-void intel_display_suspend(struct drm_device *dev)
+int intel_display_suspend(struct drm_device *dev)
 {
+       struct drm_mode_config *config = &dev->mode_config;
+       struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx;
+       struct drm_atomic_state *state;
        struct drm_crtc *crtc;
+       unsigned crtc_mask = 0;
+       int ret = 0;
 
-       for_each_crtc(dev, crtc)
-               intel_crtc_disable_noatomic(crtc);
+       if (WARN_ON(!ctx))
+               return 0;
+
+       lockdep_assert_held(&ctx->ww_ctx);
+       state = drm_atomic_state_alloc(dev);
+       if (WARN_ON(!state))
+               return -ENOMEM;
+
+       state->acquire_ctx = ctx;
+       state->allow_modeset = true;
+
+       for_each_crtc(dev, crtc) {
+               struct drm_crtc_state *crtc_state =
+                       drm_atomic_get_crtc_state(state, crtc);
+
+               ret = PTR_ERR_OR_ZERO(crtc_state);
+               if (ret)
+                       goto free;
+
+               if (!crtc_state->active)
+                       continue;
+
+               crtc_state->active = false;
+               crtc_mask |= 1 << drm_crtc_index(crtc);
+       }
+
+       if (crtc_mask) {
+               ret = drm_atomic_commit(state);
+
+               if (!ret) {
+                       for_each_crtc(dev, crtc)
+                               if (crtc_mask & (1 << drm_crtc_index(crtc)))
+                                       crtc->state->active = true;
+
+                       return ret;
+               }
+       }
+
+free:
+       if (ret)
+               DRM_ERROR("Suspending crtc's failed with %i\n", ret);
+       drm_atomic_state_free(state);
+       return ret;
 }
 
 /* Master function to enable/disable CRTC and corresponding power wells */
@@ -6253,7 +6307,7 @@ int intel_crtc_control(struct drm_crtc *crtc, bool enable)
        }
        pipe_config->base.active = enable;
 
-       ret = intel_set_mode(state);
+       ret = drm_atomic_commit(state);
        if (!ret)
                return ret;
 
@@ -7755,9 +7809,14 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode,
        mode->vsync_end = pipe_config->base.adjusted_mode.crtc_vsync_end;
 
        mode->flags = pipe_config->base.adjusted_mode.flags;
+       mode->type = DRM_MODE_TYPE_DRIVER;
 
        mode->clock = pipe_config->base.adjusted_mode.crtc_clock;
        mode->flags |= pipe_config->base.adjusted_mode.flags;
+
+       mode->hsync = drm_mode_hsync(mode);
+       mode->vrefresh = drm_mode_vrefresh(mode);
+       drm_mode_set_name(mode);
 }
 
 static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
@@ -8037,7 +8096,7 @@ static void chv_crtc_clock_get(struct intel_crtc *crtc,
        int pipe = pipe_config->cpu_transcoder;
        enum dpio_channel port = vlv_pipe_to_channel(pipe);
        intel_clock_t clock;
-       u32 cmn_dw13, pll_dw0, pll_dw1, pll_dw2;
+       u32 cmn_dw13, pll_dw0, pll_dw1, pll_dw2, pll_dw3;
        int refclk = 100000;
 
        mutex_lock(&dev_priv->sb_lock);
@@ -8045,10 +8104,13 @@ static void chv_crtc_clock_get(struct intel_crtc *crtc,
        pll_dw0 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW0(port));
        pll_dw1 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW1(port));
        pll_dw2 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW2(port));
+       pll_dw3 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW3(port));
        mutex_unlock(&dev_priv->sb_lock);
 
        clock.m1 = (pll_dw1 & 0x7) == DPIO_CHV_M1_DIV_BY_2 ? 2 : 0;
-       clock.m2 = ((pll_dw0 & 0xff) << 22) | (pll_dw2 & 0x3fffff);
+       clock.m2 = (pll_dw0 & 0xff) << 22;
+       if (pll_dw3 & DPIO_CHV_FRAC_DIV_EN)
+               clock.m2 |= pll_dw2 & 0x3fffff;
        clock.n = (pll_dw1 >> DPIO_CHV_N_DIV_SHIFT) & 0xf;
        clock.p1 = (cmn_dw13 >> DPIO_CHV_P1_DIV_SHIFT) & 0x7;
        clock.p2 = (cmn_dw13 >> DPIO_CHV_P2_DIV_SHIFT) & 0x1f;
@@ -10246,7 +10308,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
 retry:
        ret = drm_modeset_lock(&config->connection_mutex, ctx);
        if (ret)
-               goto fail_unlock;
+               goto fail;
 
        /*
         * Algorithm gets a little messy:
@@ -10264,10 +10326,10 @@ retry:
 
                ret = drm_modeset_lock(&crtc->mutex, ctx);
                if (ret)
-                       goto fail_unlock;
+                       goto fail;
                ret = drm_modeset_lock(&crtc->primary->mutex, ctx);
                if (ret)
-                       goto fail_unlock;
+                       goto fail;
 
                old->dpms_mode = connector->dpms;
                old->load_detect_temp = false;
@@ -10286,9 +10348,6 @@ retry:
                        continue;
                if (possible_crtc->state->enable)
                        continue;
-               /* This can occur when applying the pipe A quirk on resume. */
-               if (to_intel_crtc(possible_crtc)->new_enabled)
-                       continue;
 
                crtc = possible_crtc;
                break;
@@ -10299,20 +10358,17 @@ retry:
         */
        if (!crtc) {
                DRM_DEBUG_KMS("no pipe available for load-detect\n");
-               goto fail_unlock;
+               goto fail;
        }
 
        ret = drm_modeset_lock(&crtc->mutex, ctx);
        if (ret)
-               goto fail_unlock;
+               goto fail;
        ret = drm_modeset_lock(&crtc->primary->mutex, ctx);
        if (ret)
-               goto fail_unlock;
-       intel_encoder->new_crtc = to_intel_crtc(crtc);
-       to_intel_connector(connector)->new_encoder = intel_encoder;
+               goto fail;
 
        intel_crtc = to_intel_crtc(crtc);
-       intel_crtc->new_enabled = true;
        old->dpms_mode = connector->dpms;
        old->load_detect_temp = true;
        old->release_fb = NULL;
@@ -10368,7 +10424,7 @@ retry:
 
        drm_mode_copy(&crtc_state->base.mode, mode);
 
-       if (intel_set_mode(state)) {
+       if (drm_atomic_commit(state)) {
                DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
                if (old->release_fb)
                        old->release_fb->funcs->destroy(old->release_fb);
@@ -10380,9 +10436,7 @@ retry:
        intel_wait_for_vblank(dev, intel_crtc->pipe);
        return true;
 
- fail:
-       intel_crtc->new_enabled = crtc->state->enable;
-fail_unlock:
+fail:
        drm_atomic_state_free(state);
        state = NULL;
 
@@ -10428,10 +10482,6 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
                if (IS_ERR(crtc_state))
                        goto fail;
 
-               to_intel_connector(connector)->new_encoder = NULL;
-               intel_encoder->new_crtc = NULL;
-               intel_crtc->new_enabled = false;
-
                connector_state->best_encoder = NULL;
                connector_state->crtc = NULL;
 
@@ -10442,7 +10492,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
                if (ret)
                        goto fail;
 
-               ret = intel_set_mode(state);
+               ret = drm_atomic_commit(state);
                if (ret)
                        goto fail;
 
@@ -11200,12 +11250,11 @@ static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc)
 static void intel_do_mmio_flip(struct intel_crtc *intel_crtc)
 {
        struct drm_device *dev = intel_crtc->base.dev;
-       bool atomic_update;
        u32 start_vbl_count;
 
        intel_mark_page_flip_active(intel_crtc);
 
-       atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
+       intel_pipe_update_start(intel_crtc, &start_vbl_count);
 
        if (INTEL_INFO(dev)->gen >= 9)
                skl_do_mmio_flip(intel_crtc);
@@ -11213,8 +11262,7 @@ static void intel_do_mmio_flip(struct intel_crtc *intel_crtc)
                /* use_mmio_flip() retricts MMIO flips to ilk+ */
                ilk_do_mmio_flip(intel_crtc);
 
-       if (atomic_update)
-               intel_pipe_update_end(intel_crtc, start_vbl_count);
+       intel_pipe_update_end(intel_crtc, start_vbl_count);
 }
 
 static void intel_mmio_flip_work_func(struct work_struct *work)
@@ -11781,34 +11829,6 @@ static bool check_encoder_cloning(struct drm_atomic_state *state,
        return true;
 }
 
-static void intel_crtc_check_initial_planes(struct drm_crtc *crtc,
-                                           struct drm_crtc_state *crtc_state)
-{
-       struct intel_crtc_state *pipe_config =
-               to_intel_crtc_state(crtc_state);
-       struct drm_plane *p;
-       unsigned visible_mask = 0;
-
-       drm_for_each_plane_mask(p, crtc->dev, crtc_state->plane_mask) {
-               struct drm_plane_state *plane_state =
-                       drm_atomic_get_existing_plane_state(crtc_state->state, p);
-
-               if (WARN_ON(!plane_state))
-                       continue;
-
-               if (!plane_state->fb)
-                       crtc_state->plane_mask &=
-                               ~(1 << drm_plane_index(p));
-               else if (to_intel_plane_state(plane_state)->visible)
-                       visible_mask |= 1 << drm_plane_index(p);
-       }
-
-       if (!visible_mask)
-               return;
-
-       pipe_config->quirks &= ~PIPE_CONFIG_QUIRK_INITIAL_PLANES;
-}
-
 static int intel_crtc_atomic_check(struct drm_crtc *crtc,
                                   struct drm_crtc_state *crtc_state)
 {
@@ -11830,10 +11850,6 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
                "[CRTC:%i] mismatch between state->active(%i) and crtc->active(%i)\n",
                idx, crtc->state->active, intel_crtc->active);
 
-       /* plane mask is fixed up after all initial planes are calculated */
-       if (pipe_config->quirks & PIPE_CONFIG_QUIRK_INITIAL_PLANES)
-               intel_crtc_check_initial_planes(crtc, crtc_state);
-
        if (mode_changed && !crtc_state->active)
                intel_crtc->atomic.update_wm_post = true;
 
@@ -11867,37 +11883,6 @@ static const struct drm_crtc_helper_funcs intel_helper_funcs = {
        .atomic_check = intel_crtc_atomic_check,
 };
 
-/**
- * intel_modeset_update_staged_output_state
- *
- * Updates the staged output configuration state, e.g. after we've read out the
- * current hw state.
- */
-static void intel_modeset_update_staged_output_state(struct drm_device *dev)
-{
-       struct intel_crtc *crtc;
-       struct intel_encoder *encoder;
-       struct intel_connector *connector;
-
-       for_each_intel_connector(dev, connector) {
-               connector->new_encoder =
-                       to_intel_encoder(connector->base.encoder);
-       }
-
-       for_each_intel_encoder(dev, encoder) {
-               encoder->new_crtc =
-                       to_intel_crtc(encoder->base.crtc);
-       }
-
-       for_each_intel_crtc(dev, crtc) {
-               crtc->new_enabled = crtc->base.state->enable;
-       }
-}
-
-/* Transitional helper to copy current connector/encoder state to
- * connector->state. This is needed so that code that is partially
- * converted to atomic does the right thing.
- */
 static void intel_modeset_update_connector_atomic_state(struct drm_device *dev)
 {
        struct intel_connector *connector;
@@ -12338,7 +12323,6 @@ intel_modeset_update_state(struct drm_atomic_state *state)
        }
 
        drm_atomic_helper_update_legacy_modeset_state(state->dev, state);
-       intel_modeset_update_staged_output_state(state->dev);
 
        /* Double check state. */
        for_each_crtc_in_state(state, crtc, crtc_state, i) {
@@ -12738,11 +12722,14 @@ check_connector_state(struct drm_device *dev)
        struct intel_connector *connector;
 
        for_each_intel_connector(dev, connector) {
+               struct drm_encoder *encoder = connector->base.encoder;
+               struct drm_connector_state *state = connector->base.state;
+
                /* This also checks the encoder/connector hw state with the
                 * ->get_hw_state callbacks. */
                intel_connector_check_state(connector);
 
-               I915_STATE_WARN(&connector->new_encoder->base != connector->base.encoder,
+               I915_STATE_WARN(state->best_encoder != encoder,
                     "connector's staged encoder doesn't match current encoder\n");
        }
 }
@@ -12762,8 +12749,6 @@ check_encoder_state(struct drm_device *dev)
                              encoder->base.base.id,
                              encoder->base.name);
 
-               I915_STATE_WARN(&encoder->new_crtc->base != encoder->base.crtc,
-                    "encoder's stage crtc doesn't match current crtc\n");
                I915_STATE_WARN(encoder->connectors_active && !encoder->base.crtc,
                     "encoder's active_connectors set, but no crtc\n");
 
@@ -12773,6 +12758,10 @@ check_encoder_state(struct drm_device *dev)
                        enabled = true;
                        if (connector->base.dpms != DRM_MODE_DPMS_OFF)
                                active = true;
+
+                       I915_STATE_WARN(connector->base.state->crtc !=
+                                       encoder->base.crtc,
+                            "connector's crtc doesn't match encoder crtc\n");
                }
                /*
                 * for MST connectors if we unplug the connector is gone
@@ -13122,7 +13111,6 @@ static int intel_modeset_all_pipes(struct drm_atomic_state *state)
 }
 
 
-/* Code that should eventually be part of atomic_check() */
 static int intel_modeset_checks(struct drm_atomic_state *state)
 {
        struct drm_device *dev = state->dev;
@@ -13163,22 +13151,27 @@ static int intel_modeset_checks(struct drm_atomic_state *state)
        return 0;
 }
 
-static int
-intel_modeset_compute_config(struct drm_atomic_state *state)
+/**
+ * intel_atomic_check - validate state object
+ * @dev: drm device
+ * @state: state to validate
+ */
+static int intel_atomic_check(struct drm_device *dev,
+                             struct drm_atomic_state *state)
 {
        struct drm_crtc *crtc;
        struct drm_crtc_state *crtc_state;
        int ret, i;
        bool any_ms = false;
 
-       ret = drm_atomic_helper_check_modeset(state->dev, state);
+       ret = drm_atomic_helper_check_modeset(dev, state);
        if (ret)
                return ret;
 
        for_each_crtc_in_state(state, crtc, crtc_state, i) {
                struct intel_crtc_state *pipe_config =
                        to_intel_crtc_state(crtc_state);
-               bool modeset, recalc;
+               bool modeset, recalc = false;
 
                if (!crtc_state->enable) {
                        if (needs_modeset(crtc_state))
@@ -13186,21 +13179,11 @@ intel_modeset_compute_config(struct drm_atomic_state *state)
                        continue;
                }
 
-               if (pipe_config->quirks & PIPE_CONFIG_QUIRK_INITIAL_PLANES) {
-                       ret = drm_atomic_add_affected_planes(state, crtc);
-                       if (ret)
-                               return ret;
-
-                       /*
-                        * We ought to handle i915.fastboot here.
-                        * If no modeset is required and the primary plane has
-                        * a fb, update the members of crtc_state as needed,
-                        * and run the necessary updates during vblank evasion.
-                        */
-               }
-
                modeset = needs_modeset(crtc_state);
-               recalc = pipe_config->quirks & PIPE_CONFIG_QUIRK_INHERITED_MODE;
+               /* see comment in intel_modeset_readout_hw_state */
+               if (!modeset && crtc_state->mode_blob != crtc->state->mode_blob &&
+                   pipe_config->quirks & PIPE_CONFIG_QUIRK_INHERITED_MODE)
+                       recalc = true;
 
                if (!modeset && !recalc)
                        continue;
@@ -13215,9 +13198,10 @@ intel_modeset_compute_config(struct drm_atomic_state *state)
                if (ret)
                        return ret;
 
-               if (recalc && !intel_pipe_config_compare(state->dev,
+               if (recalc && (!i915.fastboot ||
+                   !intel_pipe_config_compare(state->dev,
                                        to_intel_crtc_state(crtc->state),
-                                       pipe_config, true)) {
+                                       pipe_config, true))) {
                        modeset = crtc_state->mode_changed = true;
 
                        ret = drm_atomic_add_affected_planes(state, crtc);
@@ -13243,9 +13227,26 @@ intel_modeset_compute_config(struct drm_atomic_state *state)
        return drm_atomic_helper_check_planes(state->dev, state);
 }
 
-static int __intel_set_mode(struct drm_atomic_state *state)
+/**
+ * intel_atomic_commit - commit validated state object
+ * @dev: DRM device
+ * @state: the top-level driver state object
+ * @async: asynchronous commit
+ *
+ * This function commits a top-level state object that has been validated
+ * with drm_atomic_helper_check().
+ *
+ * FIXME:  Atomic modeset support for i915 is not yet complete.  At the moment
+ * we can only handle plane-related operations and do not yet support
+ * asynchronous commit.
+ *
+ * RETURNS
+ * Zero for success or -errno.
+ */
+static int intel_atomic_commit(struct drm_device *dev,
+                              struct drm_atomic_state *state,
+                              bool async)
 {
-       struct drm_device *dev = state->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc;
        struct drm_crtc_state *crtc_state;
@@ -13253,6 +13254,11 @@ static int __intel_set_mode(struct drm_atomic_state *state)
        int i;
        bool any_ms = false;
 
+       if (async) {
+               DRM_DEBUG_KMS("i915 does not yet support async commit\n");
+               return -EINVAL;
+       }
+
        ret = drm_atomic_helper_prepare_planes(dev, state);
        if (ret)
                return ret;
@@ -13287,310 +13293,76 @@ static int __intel_set_mode(struct drm_atomic_state *state)
 
        /* Now enable the clocks, plane, pipe, and connectors that we set up. */
        for_each_crtc_in_state(state, crtc, crtc_state, i) {
-               if (needs_modeset(crtc->state) && crtc->state->active) {
+               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+               bool modeset = needs_modeset(crtc->state);
+
+               if (modeset && crtc->state->active) {
                        update_scanline_offset(to_intel_crtc(crtc));
                        dev_priv->display.crtc_enable(crtc);
                }
 
+               if (!modeset)
+                       intel_pre_plane_update(intel_crtc);
+
                drm_atomic_helper_commit_planes_on_crtc(crtc_state);
+               intel_post_plane_update(intel_crtc);
        }
 
        /* FIXME: add subpixel order */
 
+       drm_atomic_helper_wait_for_vblanks(dev, state);
        drm_atomic_helper_cleanup_planes(dev, state);
-
        drm_atomic_state_free(state);
 
-       return 0;
-}
-
-static int intel_set_mode_checked(struct drm_atomic_state *state)
-{
-       struct drm_device *dev = state->dev;
-       int ret;
-
-       ret = __intel_set_mode(state);
-       if (ret == 0)
+       if (any_ms)
                intel_modeset_check_state(dev);
 
-       return ret;
-}
-
-static int intel_set_mode(struct drm_atomic_state *state)
-{
-       int ret;
-
-       ret = intel_modeset_compute_config(state);
-       if (ret)
-               return ret;
-
-       return intel_set_mode_checked(state);
+       return 0;
 }
 
 void intel_crtc_restore_mode(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_atomic_state *state;
-       struct intel_encoder *encoder;
-       struct intel_connector *connector;
-       struct drm_connector_state *connector_state;
-       struct intel_crtc_state *crtc_state;
+       struct drm_crtc_state *crtc_state;
        int ret;
 
        state = drm_atomic_state_alloc(dev);
        if (!state) {
-               DRM_DEBUG_KMS("[CRTC:%d] mode restore failed, out of memory",
+               DRM_DEBUG_KMS("[CRTC:%d] crtc restore failed, out of memory",
                              crtc->base.id);
                return;
        }
 
-       state->acquire_ctx = dev->mode_config.acquire_ctx;
-
-       /* The force restore path in the HW readout code relies on the staged
-        * config still keeping the user requested config while the actual
-        * state has been overwritten by the configuration read from HW. We
-        * need to copy the staged config to the atomic state, otherwise the
-        * mode set will just reapply the state the HW is already in. */
-       for_each_intel_encoder(dev, encoder) {
-               if (&encoder->new_crtc->base != crtc)
-                       continue;
+       state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
 
-               for_each_intel_connector(dev, connector) {
-                       if (connector->new_encoder != encoder)
-                               continue;
-
-                       connector_state = drm_atomic_get_connector_state(state, &connector->base);
-                       if (IS_ERR(connector_state)) {
-                               DRM_DEBUG_KMS("Failed to add [CONNECTOR:%d:%s] to state: %ld\n",
-                                             connector->base.base.id,
-                                             connector->base.name,
-                                             PTR_ERR(connector_state));
-                               continue;
-                       }
+retry:
+       crtc_state = drm_atomic_get_crtc_state(state, crtc);
+       ret = PTR_ERR_OR_ZERO(crtc_state);
+       if (!ret) {
+               if (!crtc_state->active)
+                       goto out;
 
-                       connector_state->crtc = crtc;
-                       connector_state->best_encoder = &encoder->base;
-               }
+               crtc_state->mode_changed = true;
+               ret = drm_atomic_commit(state);
        }
 
-       crtc_state = intel_atomic_get_crtc_state(state, to_intel_crtc(crtc));
-       if (IS_ERR(crtc_state)) {
-               DRM_DEBUG_KMS("Failed to add [CRTC:%d] to state: %ld\n",
-                             crtc->base.id, PTR_ERR(crtc_state));
-               drm_atomic_state_free(state);
-               return;
+       if (ret == -EDEADLK) {
+               drm_atomic_state_clear(state);
+               drm_modeset_backoff(state->acquire_ctx);
+               goto retry;
        }
 
-       crtc_state->base.active = crtc_state->base.enable =
-               to_intel_crtc(crtc)->new_enabled;
-
-       drm_mode_copy(&crtc_state->base.mode, &crtc->mode);
-
-       intel_modeset_setup_plane_state(state, crtc, &crtc->mode,
-                                       crtc->primary->fb, crtc->x, crtc->y);
-
-       ret = intel_set_mode(state);
        if (ret)
+out:
                drm_atomic_state_free(state);
 }
 
 #undef for_each_intel_crtc_masked
 
-static bool intel_connector_in_mode_set(struct intel_connector *connector,
-                                       struct drm_mode_set *set)
-{
-       int ro;
-
-       for (ro = 0; ro < set->num_connectors; ro++)
-               if (set->connectors[ro] == &connector->base)
-                       return true;
-
-       return false;
-}
-
-static int
-intel_modeset_stage_output_state(struct drm_device *dev,
-                                struct drm_mode_set *set,
-                                struct drm_atomic_state *state)
-{
-       struct intel_connector *connector;
-       struct drm_connector *drm_connector;
-       struct drm_connector_state *connector_state;
-       struct drm_crtc *crtc;
-       struct drm_crtc_state *crtc_state;
-       int i, ret;
-
-       /* The upper layers ensure that we either disable a crtc or have a list
-        * of connectors. For paranoia, double-check this. */
-       WARN_ON(!set->fb && (set->num_connectors != 0));
-       WARN_ON(set->fb && (set->num_connectors == 0));
-
-       for_each_intel_connector(dev, connector) {
-               bool in_mode_set = intel_connector_in_mode_set(connector, set);
-
-               if (!in_mode_set && connector->base.state->crtc != set->crtc)
-                       continue;
-
-               connector_state =
-                       drm_atomic_get_connector_state(state, &connector->base);
-               if (IS_ERR(connector_state))
-                       return PTR_ERR(connector_state);
-
-               if (in_mode_set) {
-                       int pipe = to_intel_crtc(set->crtc)->pipe;
-                       connector_state->best_encoder =
-                               &intel_find_encoder(connector, pipe)->base;
-               }
-
-               if (connector->base.state->crtc != set->crtc)
-                       continue;
-
-               /* If we disable the crtc, disable all its connectors. Also, if
-                * the connector is on the changing crtc but not on the new
-                * connector list, disable it. */
-               if (!set->fb || !in_mode_set) {
-                       connector_state->best_encoder = NULL;
-
-                       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n",
-                               connector->base.base.id,
-                               connector->base.name);
-               }
-       }
-       /* connector->new_encoder is now updated for all connectors. */
-
-       for_each_connector_in_state(state, drm_connector, connector_state, i) {
-               connector = to_intel_connector(drm_connector);
-
-               if (!connector_state->best_encoder) {
-                       ret = drm_atomic_set_crtc_for_connector(connector_state,
-                                                               NULL);
-                       if (ret)
-                               return ret;
-
-                       continue;
-               }
-
-               if (intel_connector_in_mode_set(connector, set)) {
-                       struct drm_crtc *crtc = connector->base.state->crtc;
-
-                       /* If this connector was in a previous crtc, add it
-                        * to the state. We might need to disable it. */
-                       if (crtc) {
-                               crtc_state =
-                                       drm_atomic_get_crtc_state(state, crtc);
-                               if (IS_ERR(crtc_state))
-                                       return PTR_ERR(crtc_state);
-                       }
-
-                       ret = drm_atomic_set_crtc_for_connector(connector_state,
-                                                               set->crtc);
-                       if (ret)
-                               return ret;
-               }
-
-               /* Make sure the new CRTC will work with the encoder */
-               if (!drm_encoder_crtc_ok(connector_state->best_encoder,
-                                        connector_state->crtc)) {
-                       return -EINVAL;
-               }
-
-               DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",
-                       connector->base.base.id,
-                       connector->base.name,
-                       connector_state->crtc->base.id);
-
-               if (connector_state->best_encoder != &connector->encoder->base)
-                       connector->encoder =
-                               to_intel_encoder(connector_state->best_encoder);
-       }
-
-       for_each_crtc_in_state(state, crtc, crtc_state, i) {
-               bool has_connectors;
-
-               ret = drm_atomic_add_affected_connectors(state, crtc);
-               if (ret)
-                       return ret;
-
-               has_connectors = !!drm_atomic_connectors_for_crtc(state, crtc);
-               if (has_connectors != crtc_state->enable)
-                       crtc_state->enable =
-                       crtc_state->active = has_connectors;
-       }
-
-       ret = intel_modeset_setup_plane_state(state, set->crtc, set->mode,
-                                             set->fb, set->x, set->y);
-       if (ret)
-               return ret;
-
-       crtc_state = drm_atomic_get_crtc_state(state, set->crtc);
-       if (IS_ERR(crtc_state))
-               return PTR_ERR(crtc_state);
-
-       ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode);
-       if (ret)
-               return ret;
-
-       if (set->num_connectors)
-               crtc_state->active = true;
-
-       return 0;
-}
-
-static int intel_crtc_set_config(struct drm_mode_set *set)
-{
-       struct drm_device *dev;
-       struct drm_atomic_state *state = NULL;
-       int ret;
-
-       BUG_ON(!set);
-       BUG_ON(!set->crtc);
-       BUG_ON(!set->crtc->helper_private);
-
-       /* Enforce sane interface api - has been abused by the fb helper. */
-       BUG_ON(!set->mode && set->fb);
-       BUG_ON(set->fb && set->num_connectors == 0);
-
-       if (set->fb) {
-               DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n",
-                               set->crtc->base.id, set->fb->base.id,
-                               (int)set->num_connectors, set->x, set->y);
-       } else {
-               DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id);
-       }
-
-       dev = set->crtc->dev;
-
-       state = drm_atomic_state_alloc(dev);
-       if (!state)
-               return -ENOMEM;
-
-       state->acquire_ctx = dev->mode_config.acquire_ctx;
-
-       ret = intel_modeset_stage_output_state(dev, set, state);
-       if (ret)
-               goto out;
-
-       ret = intel_modeset_compute_config(state);
-       if (ret)
-               goto out;
-
-       intel_update_pipe_size(to_intel_crtc(set->crtc));
-
-       ret = intel_set_mode_checked(state);
-       if (ret) {
-               DRM_DEBUG_KMS("failed to set mode on [CRTC:%d], err = %d\n",
-                             set->crtc->base.id, ret);
-       }
-
-out:
-       if (ret)
-               drm_atomic_state_free(state);
-       return ret;
-}
-
 static const struct drm_crtc_funcs intel_crtc_funcs = {
        .gamma_set = intel_crtc_gamma_set,
-       .set_config = intel_crtc_set_config,
+       .set_config = drm_atomic_helper_set_config,
        .destroy = intel_crtc_destroy,
        .page_flip = intel_crtc_page_flip,
        .atomic_duplicate_state = intel_crtc_duplicate_state,
@@ -13868,22 +13640,14 @@ intel_disable_primary_plane(struct drm_plane *plane,
 static void intel_begin_crtc_commit(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-       if (!needs_modeset(crtc->state))
-               intel_pre_plane_update(intel_crtc);
-
        if (intel_crtc->atomic.update_wm_pre)
                intel_update_watermarks(crtc);
 
-       intel_runtime_pm_get(dev_priv);
-
        /* Perform vblank evasion around commit operation */
        if (crtc->state->active)
-               intel_crtc->atomic.evade =
-                       intel_pipe_update_start(intel_crtc,
-                                               &intel_crtc->atomic.start_vbl_count);
+               intel_pipe_update_start(intel_crtc, &intel_crtc->start_vbl_count);
 
        if (!needs_modeset(crtc->state) && INTEL_INFO(dev)->gen >= 9)
                skl_detach_scalers(intel_crtc);
@@ -13891,17 +13655,10 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc)
 
 static void intel_finish_crtc_commit(struct drm_crtc *crtc)
 {
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-       if (intel_crtc->atomic.evade)
-               intel_pipe_update_end(intel_crtc,
-                                     intel_crtc->atomic.start_vbl_count);
-
-       intel_runtime_pm_put(dev_priv);
-
-       intel_post_plane_update(intel_crtc);
+       if (crtc->state->active)
+               intel_pipe_update_end(intel_crtc, intel_crtc->start_vbl_count);
 }
 
 /**
@@ -15198,10 +14955,12 @@ void intel_modeset_init(struct drm_device *dev)
        intel_fbc_disable(dev_priv);
 
        drm_modeset_lock_all(dev);
-       intel_modeset_setup_hw_state(dev, false);
+       intel_modeset_setup_hw_state(dev);
        drm_modeset_unlock_all(dev);
 
        for_each_intel_crtc(dev, crtc) {
+               struct intel_initial_plane_config plane_config = {};
+
                if (!crtc->active)
                        continue;
 
@@ -15212,15 +14971,14 @@ void intel_modeset_init(struct drm_device *dev)
                 * can even allow for smooth boot transitions if the BIOS
                 * fb is large enough for the active pipe configuration.
                 */
-               if (dev_priv->display.get_initial_plane_config) {
-                       dev_priv->display.get_initial_plane_config(crtc,
-                                                          &crtc->plane_config);
-                       /*
-                        * If the fb is shared between multiple heads, we'll
-                        * just get the first one.
-                        */
-                       intel_find_initial_plane_obj(crtc, &crtc->plane_config);
-               }
+               dev_priv->display.get_initial_plane_config(crtc,
+                                                          &plane_config);
+
+               /*
+                * If the fb is shared between multiple heads, we'll
+                * just get the first one.
+                */
+               intel_find_initial_plane_obj(crtc, &plane_config);
        }
 }
 
@@ -15283,6 +15041,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
        /* restore vblank interrupts to correct state */
        drm_crtc_vblank_reset(&crtc->base);
        if (crtc->active) {
+               drm_calc_timestamping_constants(&crtc->base, &crtc->base.hwmode);
                update_scanline_offset(crtc);
                drm_crtc_vblank_on(&crtc->base);
        }
@@ -15335,7 +15094,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
                              crtc->base.state->enable ? "enabled" : "disabled",
                              crtc->active ? "enabled" : "disabled");
 
-               crtc->base.state->enable = crtc->active;
+               WARN_ON(drm_atomic_set_mode_for_crtc(crtc->base.state, NULL) < 0);
                crtc->base.state->active = crtc->active;
                crtc->base.enabled = crtc->active;
 
@@ -15455,47 +15214,22 @@ static void readout_plane_state(struct intel_crtc *crtc,
                                struct intel_crtc_state *crtc_state)
 {
        struct intel_plane *p;
-       struct drm_plane_state *drm_plane_state;
+       struct intel_plane_state *plane_state;
        bool active = crtc_state->base.active;
 
-       if (active) {
-               crtc_state->quirks |= PIPE_CONFIG_QUIRK_INITIAL_PLANES;
-
-               /* apply to previous sw state too */
-               to_intel_crtc_state(crtc->base.state)->quirks |=
-                       PIPE_CONFIG_QUIRK_INITIAL_PLANES;
-       }
-
        for_each_intel_plane(crtc->base.dev, p) {
-               bool visible = active;
-
                if (crtc->pipe != p->pipe)
                        continue;
 
-               drm_plane_state = p->base.state;
+               plane_state = to_intel_plane_state(p->base.state);
 
-               /* Plane scaler state is not touched here. The first atomic
-                * commit will restore all plane scalers to its old state.
-                */
-
-               if (active && p->base.type == DRM_PLANE_TYPE_PRIMARY) {
-                       visible = primary_get_hw_state(crtc);
-                       to_intel_plane_state(drm_plane_state)->visible = visible;
-               } else {
-                       /*
-                        * unknown state, assume it's off to force a transition
-                        * to on when calculating state changes.
-                        */
-                       to_intel_plane_state(drm_plane_state)->visible = false;
-               }
+               if (p->base.type == DRM_PLANE_TYPE_PRIMARY)
+                       plane_state->visible = primary_get_hw_state(crtc);
+               else {
+                       if (active)
+                               p->disable_plane(&p->base, &crtc->base);
 
-               if (visible) {
-                       crtc_state->base.plane_mask |=
-                               1 << drm_plane_index(&p->base);
-               } else if (crtc_state->base.state) {
-                       /* Make this unconditional for atomic hw readout. */
-                       crtc_state->base.plane_mask &=
-                               ~(1 << drm_plane_index(&p->base));
+                       plane_state->visible = false;
                }
        }
 }
@@ -15510,6 +15244,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
        int i;
 
        for_each_intel_crtc(dev, crtc) {
+               __drm_atomic_helper_crtc_destroy_state(&crtc->base, crtc->base.state);
                memset(crtc->config, 0, sizeof(*crtc->config));
                crtc->config->base.crtc = &crtc->base;
 
@@ -15518,11 +15253,42 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
                crtc->active = dev_priv->display.get_pipe_config(crtc,
                                                                 crtc->config);
 
-               crtc->base.state->enable = crtc->active;
                crtc->base.state->active = crtc->active;
                crtc->base.enabled = crtc->active;
-               crtc->base.hwmode = crtc->config->base.adjusted_mode;
 
+               memset(&crtc->base.mode, 0, sizeof(crtc->base.mode));
+               if (crtc->base.state->active) {
+                       intel_mode_from_pipe_config(&crtc->base.mode, crtc->config);
+                       intel_mode_from_pipe_config(&crtc->base.state->adjusted_mode, crtc->config);
+                       WARN_ON(drm_atomic_set_mode_for_crtc(crtc->base.state, &crtc->base.mode));
+
+                       /*
+                        * The initial mode needs to be set in order to keep
+                        * the atomic core happy. It wants a valid mode if the
+                        * crtc's enabled, so we do the above call.
+                        *
+                        * At this point some state updated by the connectors
+                        * in their ->detect() callback has not run yet, so
+                        * no recalculation can be done yet.
+                        *
+                        * Even if we could do a recalculation and modeset
+                        * right now it would cause a double modeset if
+                        * fbdev or userspace chooses a different initial mode.
+                        *
+                        * So to prevent the double modeset, fail the memcmp
+                        * test in drm_atomic_set_mode_for_crtc to get a new
+                        * mode blob, and compare if the mode blob changed
+                        * when the PIPE_CONFIG_QUIRK_INHERITED_MODE quirk is
+                        * set.
+                        *
+                        * If that happens, someone indicated they wanted a
+                        * mode change, which means it's safe to do a full
+                        * recalculation.
+                        */
+                       crtc->base.state->mode.private_flags = ~0;
+               }
+
+               crtc->base.hwmode = crtc->config->base.adjusted_mode;
                readout_plane_state(crtc, to_intel_crtc_state(crtc->base.state));
 
                DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n",
@@ -15586,10 +15352,11 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
        }
 }
 
-/* Scan out the current hw modeset state, sanitizes it and maps it into the drm
- * and i915 state tracking structures. */
-void intel_modeset_setup_hw_state(struct drm_device *dev,
-                                 bool force_restore)
+/* Scan out the current hw modeset state,
+ * and sanitizes it to the current state
+ */
+static void
+intel_modeset_setup_hw_state(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        enum pipe pipe;
@@ -15599,21 +15366,6 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
 
        intel_modeset_readout_hw_state(dev);
 
-       /*
-        * Now that we have the config, copy it to each CRTC struct
-        * Note that this could go away if we move to using crtc_config
-        * checking everywhere.
-        */
-       for_each_intel_crtc(dev, crtc) {
-               if (crtc->active && i915.fastboot) {
-                       intel_mode_from_pipe_config(&crtc->base.mode,
-                                                   crtc->config);
-                       DRM_DEBUG_KMS("[CRTC:%d] found active mode: ",
-                                     crtc->base.base.id);
-                       drm_mode_debug_printmodeline(&crtc->base.mode);
-               }
-       }
-
        /* HW state is read out, now we need to sanitize this mess. */
        for_each_intel_encoder(dev, encoder) {
                intel_sanitize_encoder(encoder);
@@ -15647,24 +15399,66 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
        else if (HAS_PCH_SPLIT(dev))
                ilk_wm_get_hw_state(dev);
 
-       if (force_restore) {
-               i915_redisable_vga(dev);
+       for_each_intel_crtc(dev, crtc) {
+               unsigned long put_domains;
 
-               /*
-                * We need to use raw interfaces for restoring state to avoid
-                * checking (bogus) intermediate states.
-                */
-               for_each_pipe(dev_priv, pipe) {
-                       struct drm_crtc *crtc =
-                               dev_priv->pipe_to_crtc_mapping[pipe];
+               put_domains = modeset_get_crtc_power_domains(&crtc->base);
+               if (WARN_ON(put_domains))
+                       modeset_put_power_domains(dev_priv, put_domains);
+       }
+       intel_display_set_init_power(dev_priv, false);
+}
 
-                       intel_crtc_restore_mode(crtc);
-               }
-       } else {
-               intel_modeset_update_staged_output_state(dev);
+void intel_display_resume(struct drm_device *dev)
+{
+       struct drm_atomic_state *state = drm_atomic_state_alloc(dev);
+       struct intel_connector *conn;
+       struct intel_plane *plane;
+       struct drm_crtc *crtc;
+       int ret;
+
+       if (!state)
+               return;
+
+       state->acquire_ctx = dev->mode_config.acquire_ctx;
+
+       /* preserve complete old state, including dpll */
+       intel_atomic_get_shared_dpll_state(state);
+
+       for_each_crtc(dev, crtc) {
+               struct drm_crtc_state *crtc_state =
+                       drm_atomic_get_crtc_state(state, crtc);
+
+               ret = PTR_ERR_OR_ZERO(crtc_state);
+               if (ret)
+                       goto err;
+
+               /* force a restore */
+               crtc_state->mode_changed = true;
        }
 
-       intel_modeset_check_state(dev);
+       for_each_intel_plane(dev, plane) {
+               ret = PTR_ERR_OR_ZERO(drm_atomic_get_plane_state(state, &plane->base));
+               if (ret)
+                       goto err;
+       }
+
+       for_each_intel_connector(dev, conn) {
+               ret = PTR_ERR_OR_ZERO(drm_atomic_get_connector_state(state, &conn->base));
+               if (ret)
+                       goto err;
+       }
+
+       intel_modeset_setup_hw_state(dev);
+
+       i915_redisable_vga(dev);
+       ret = drm_atomic_commit(state);
+       if (!ret)
+               return;
+
+err:
+       DRM_ERROR("Restoring old state failed with %i\n", ret);
+       drm_atomic_state_free(state);
 }
 
 void intel_modeset_gem_init(struct drm_device *dev)