[RFC,3/7] All changes from try2.
diff mbox

Message ID 1434700950-16242-4-git-send-email-maarten.lankhorst@linux.intel.com
State New
Headers show

Commit Message

Maarten Lankhorst June 19, 2015, 8:02 a.m. UTC
Always read out plane state, and do an initial modeset in modeset_gem_init.

---
 drivers/gpu/drm/i915/i915_dma.c      |  12 +-
 drivers/gpu/drm/i915/i915_drv.c      |   2 +-
 drivers/gpu/drm/i915/i915_drv.h      |   7 +-
 drivers/gpu/drm/i915/intel_atomic.c  |   7 -
 drivers/gpu/drm/i915/intel_display.c | 501 ++++++++++++++++++-----------------
 drivers/gpu/drm/i915/intel_drv.h     |   3 +-
 drivers/gpu/drm/i915/intel_fbdev.c   |  12 +-
 drivers/gpu/drm/i915/intel_lvds.c    |   2 +-
 8 files changed, 280 insertions(+), 266 deletions(-)

Patch
diff mbox

diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 88795d2f1819..ede07f6fe7f7 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -393,6 +393,7 @@  static const struct vga_switcheroo_client_ops i915_switcheroo_ops = {
 static int i915_load_modeset_init(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_atomic_state *state;
 	int ret;
 
 	ret = intel_parse_bios(dev);
@@ -431,13 +432,18 @@  static int i915_load_modeset_init(struct drm_device *dev)
 
 	/* Important: The output setup functions called by modeset_init need
 	 * working irqs for e.g. gmbus and dp aux transfers. */
-	intel_modeset_init(dev);
+	state = intel_modeset_init(dev);
 
 	ret = i915_gem_init(dev);
-	if (ret)
+	if (ret) {
+		if (state) {
+			drm_atomic_state_free(state);
+			drm_modeset_unlock_all(dev);
+		}
 		goto cleanup_irq;
+	}
 
-	intel_modeset_gem_init(dev);
+	intel_modeset_gem_init(dev, state);
 
 	/* Always safe in the mode setting case. */
 	/* FIXME: do pre/post-mode set stuff in core KMS code */
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 78ef0bb53c36..a29b24bca25e 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -758,7 +758,7 @@  static int i915_drm_resume(struct drm_device *dev)
 	spin_unlock_irq(&dev_priv->irq_lock);
 
 	drm_modeset_lock_all(dev);
-	intel_modeset_setup_hw_state(dev, true);
+	intel_display_resume(dev);
 	drm_modeset_unlock_all(dev);
 
 	intel_dp_mst_resume(dev);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index d9410bd4ab59..e67d2f1e3ab8 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -3233,13 +3233,12 @@  static inline void intel_unregister_dsm_handler(void) { return; }
 
 /* modesetting */
 extern void intel_modeset_init_hw(struct drm_device *dev);
-extern void intel_modeset_init(struct drm_device *dev);
-extern void intel_modeset_gem_init(struct drm_device *dev);
+extern struct drm_atomic_state *intel_modeset_init(struct drm_device *dev);
+extern void intel_modeset_gem_init(struct drm_device *dev, struct drm_atomic_state *);
 extern void intel_modeset_cleanup(struct drm_device *dev);
 extern void intel_connector_unregister(struct intel_connector *);
 extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state);
-extern void intel_modeset_setup_hw_state(struct drm_device *dev,
-					 bool force_restore);
+extern void intel_display_resume(struct drm_device *dev);
 extern void i915_redisable_vga(struct drm_device *dev);
 extern void i915_redisable_vga_power_on(struct drm_device *dev);
 extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
index 4d87574a2032..f36fcc7ceecb 100644
--- a/drivers/gpu/drm/i915/intel_atomic.c
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -98,13 +98,6 @@  int intel_atomic_check(struct drm_device *dev,
 		return -EINVAL;
 	}
 
-	if (crtc_state &&
-	    crtc_state->quirks & PIPE_CONFIG_QUIRK_INITIAL_PLANES) {
-		ret = drm_atomic_add_affected_planes(state, &nuclear_crtc->base);
-		if (ret)
-			return ret;
-	}
-
 	ret = drm_atomic_helper_check_planes(dev, state);
 	if (ret)
 		return ret;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 41193dab58c5..9b2acc7b4e29 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -109,6 +109,9 @@  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 void intel_pre_disable_primary(struct drm_crtc *crtc);
+static struct drm_atomic_state *
+intel_modeset_setup_hw_state(struct drm_device *dev, bool force_restore);
 
 static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe)
 {
@@ -2567,40 +2570,41 @@  update_state_fb(struct drm_plane *plane)
 
 static void
 intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
-			     struct intel_initial_plane_config *plane_config)
+			     struct intel_initial_plane_config *plane_config,
+			     struct intel_plane_state *plane_state)
 {
+	struct drm_atomic_state *state = plane_state->base.state;
 	struct drm_device *dev = intel_crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_crtc *c;
-	struct intel_crtc *i;
 	struct drm_i915_gem_object *obj;
-	struct drm_plane *primary = intel_crtc->base.primary;
 	struct drm_framebuffer *fb;
+	struct drm_plane *plane = plane_state->base.plane, *drm_plane;
+	struct drm_plane_state *drm_plane_state;
+	int i, ret;
 
 	if (!plane_config->fb)
 		return;
 
 	if (intel_alloc_initial_plane_obj(intel_crtc, plane_config)) {
-		fb = &plane_config->fb->base;
-		goto valid_fb;
-	}
+		int ret;
 
-	kfree(plane_config->fb);
+		fb = &plane_config->fb->base;
+		ret = intel_pin_and_fence_fb_obj(plane, fb, &plane_state->base, NULL);
+		if (!ret)
+			goto valid_fb;
+		drm_framebuffer_unreference(fb);
+	} else
+		kfree(plane_config->fb);
 
 	/*
 	 * Failed to alloc the obj, check to see if we should share
 	 * an fb with another CRTC instead
 	 */
-	for_each_crtc(dev, c) {
-		i = to_intel_crtc(c);
-
-		if (c == &intel_crtc->base)
+	for_each_plane_in_state(state, drm_plane, drm_plane_state, i) {
+		if (drm_plane->type != DRM_PLANE_TYPE_PRIMARY)
 			continue;
 
-		if (!i->active)
-			continue;
-
-		fb = c->primary->fb;
+		fb = drm_plane_state->fb;
 		if (!fb)
 			continue;
 
@@ -2611,17 +2615,22 @@  intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
 		}
 	}
 
+	intel_pre_disable_primary(&intel_crtc->base);
+	to_intel_plane(plane)->disable_plane(plane, &intel_crtc->base);
+
 	return;
 
 valid_fb:
+	drm_atomic_set_fb_for_plane(&plane_state->base, fb);
+	ret = drm_atomic_set_crtc_for_plane(&plane_state->base, &intel_crtc->base);
+	WARN_ON(ret);
+	plane->fb = fb;
+
+	plane_state->visible = true;
 	obj = intel_fb_obj(fb);
 	if (obj->tiling_mode != I915_TILING_NONE)
 		dev_priv->preserve_bios_swizzle = true;
 
-	primary->fb = fb;
-	primary->crtc = primary->state->crtc = &intel_crtc->base;
-	update_state_fb(primary);
-	intel_crtc->base.state->plane_mask |= (1 << drm_plane_index(primary));
 	obj->frontbuffer_bits |= INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe);
 }
 
@@ -3229,7 +3238,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);
 
@@ -6190,6 +6199,11 @@  void intel_display_suspend(struct drm_device *dev)
 		intel_crtc_disable_noatomic(crtc);
 }
 
+void intel_display_resume(struct drm_device *dev)
+{
+	intel_modeset_setup_hw_state(dev, true);
+}
+
 /* Master function to enable/disable CRTC and corresponding power wells */
 int intel_crtc_control(struct drm_crtc *crtc, bool enable)
 {
@@ -7700,9 +7714,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)
@@ -11772,34 +11791,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)
 {
@@ -11821,10 +11812,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)
 		intel_crtc->atomic.update_wm = !crtc_state->active;
 
@@ -12374,24 +12361,35 @@  static bool intel_fuzzy_clock_check(int clock1, int clock2)
 static bool
 intel_pipe_config_compare(struct drm_device *dev,
 			  struct intel_crtc_state *current_config,
-			  struct intel_crtc_state *pipe_config)
+			  struct intel_crtc_state *pipe_config,
+			  bool check_only)
 {
+	bool ret = true;
+
+#define INTEL_ERR_OR_DBG_KMS(fmt, ...) \
+	do { \
+		if (!check_only) \
+			DRM_ERROR(fmt, ##__VA_ARGS__); \
+		else \
+			DRM_DEBUG_KMS(fmt, ##__VA_ARGS__); \
+	} while (0)
+
 #define PIPE_CONF_CHECK_X(name)	\
 	if (current_config->name != pipe_config->name) { \
-		DRM_ERROR("mismatch in " #name " " \
+		INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \
 			  "(expected 0x%08x, found 0x%08x)\n", \
 			  current_config->name, \
 			  pipe_config->name); \
-		return false; \
+		ret = false; \
 	}
 
 #define PIPE_CONF_CHECK_I(name)	\
 	if (current_config->name != pipe_config->name) { \
-		DRM_ERROR("mismatch in " #name " " \
+		INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \
 			  "(expected %i, found %i)\n", \
 			  current_config->name, \
 			  pipe_config->name); \
-		return false; \
+		ret = false; \
 	}
 
 /* This is required for BDW+ where there is only one set of registers for
@@ -12402,30 +12400,30 @@  intel_pipe_config_compare(struct drm_device *dev,
 #define PIPE_CONF_CHECK_I_ALT(name, alt_name) \
 	if ((current_config->name != pipe_config->name) && \
 		(current_config->alt_name != pipe_config->name)) { \
-			DRM_ERROR("mismatch in " #name " " \
+			INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \
 				  "(expected %i or %i, found %i)\n", \
 				  current_config->name, \
 				  current_config->alt_name, \
 				  pipe_config->name); \
-			return false; \
+			ret = false; \
 	}
 
 #define PIPE_CONF_CHECK_FLAGS(name, mask)	\
 	if ((current_config->name ^ pipe_config->name) & (mask)) { \
-		DRM_ERROR("mismatch in " #name "(" #mask ") "	   \
+		INTEL_ERR_OR_DBG_KMS("mismatch in " #name "(" #mask ") "	   \
 			  "(expected %i, found %i)\n", \
 			  current_config->name & (mask), \
 			  pipe_config->name & (mask)); \
-		return false; \
+		ret = false; \
 	}
 
 #define PIPE_CONF_CHECK_CLOCK_FUZZY(name) \
 	if (!intel_fuzzy_clock_check(current_config->name, pipe_config->name)) { \
-		DRM_ERROR("mismatch in " #name " " \
+		INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \
 			  "(expected %i, found %i)\n", \
 			  current_config->name, \
 			  pipe_config->name); \
-		return false; \
+		ret = false; \
 	}
 
 #define PIPE_CONF_QUIRK(quirk)	\
@@ -12559,8 +12557,9 @@  intel_pipe_config_compare(struct drm_device *dev,
 #undef PIPE_CONF_CHECK_FLAGS
 #undef PIPE_CONF_CHECK_CLOCK_FUZZY
 #undef PIPE_CONF_QUIRK
+#undef INTEL_ERR_OR_DBG_KMS
 
-	return true;
+	return ret;
 }
 
 static void check_wm_state(struct drm_device *dev)
@@ -12757,7 +12756,7 @@  check_crtc_state(struct drm_device *dev)
 		     "(expected %i, found %i)\n", crtc->base.state->active, crtc->active);
 
 		if (active &&
-		    !intel_pipe_config_compare(dev, crtc->config, &pipe_config)) {
+		    !intel_pipe_config_compare(dev, crtc->config, &pipe_config, false)) {
 			I915_STATE_WARN(1, "pipe state doesn't match!\n");
 			intel_dump_pipe_config(crtc, &pipe_config,
 					       "[hw state]");
@@ -13064,20 +13063,6 @@  intel_modeset_compute_config(struct drm_atomic_state *state)
 			continue;
 		}
 
-		if (to_intel_crtc_state(crtc_state)->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.
-			 */
-		}
-
 		if (!needs_modeset(crtc_state)) {
 			ret = drm_atomic_add_affected_connectors(state, crtc);
 			if (ret)
@@ -13140,6 +13125,12 @@  static int __intel_set_mode(struct drm_atomic_state *state)
 			intel_crtc->active = false;
 			intel_disable_shared_dpll(intel_crtc);
 		}
+
+		/* FIXME: Move this to i9xx_crtc_disable when it gets a pointer
+		 * to the old crtc_state. */
+		if (to_intel_crtc_state(crtc_state)->quirks &
+		    PIPE_CONFIG_QUIRK_WRONG_PLANE)
+			intel_crtc->plane = !intel_crtc->plane;
 	}
 
 	/* Only after disabling all output pipelines that will be changed can we
@@ -14975,12 +14966,12 @@  void intel_modeset_init_hw(struct drm_device *dev)
 	intel_enable_gt_powersave(dev);
 }
 
-void intel_modeset_init(struct drm_device *dev)
+struct drm_atomic_state *intel_modeset_init(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_atomic_state *state;
 	int sprite, ret;
 	enum pipe pipe;
-	struct intel_crtc *crtc;
 
 	drm_mode_config_init(dev);
 
@@ -14999,7 +14990,7 @@  void intel_modeset_init(struct drm_device *dev)
 	intel_init_pm(dev);
 
 	if (INTEL_INFO(dev)->num_pipes == 0)
-		return;
+		return NULL;
 
 	intel_init_display(dev);
 	intel_init_audio(dev);
@@ -15054,30 +15045,11 @@  void intel_modeset_init(struct drm_device *dev)
 	intel_fbc_disable(dev);
 
 	drm_modeset_lock_all(dev);
-	intel_modeset_setup_hw_state(dev, false);
-	drm_modeset_unlock_all(dev);
-
-	for_each_intel_crtc(dev, crtc) {
-		if (!crtc->active)
-			continue;
+	state = intel_modeset_setup_hw_state(dev, false);
+	if (!state)
+		drm_modeset_unlock_all(dev);
 
-		/*
-		 * Note that reserving the BIOS fb up front prevents us
-		 * from stuffing other stolen allocations like the ring
-		 * on top.  This prevents some ugliness at boot time, and
-		 * 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);
-		}
-	}
+	return state;
 }
 
 static void intel_enable_pipe_a(struct drm_device *dev)
@@ -15124,13 +15096,17 @@  intel_check_plane_mapping(struct intel_crtc *crtc)
 	return true;
 }
 
-static void intel_sanitize_crtc(struct intel_crtc *crtc)
+static void intel_sanitize_crtc(struct intel_crtc *crtc,
+				struct intel_crtc_state *pipe_config,
+				bool force_restore)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_encoder *encoder;
+	struct drm_atomic_state *state = pipe_config->base.state;
+	struct intel_crtc_state *hw_state =
+		to_intel_crtc_state(crtc->base.state);
 	u32 reg;
-	bool enable;
 
 	/* Clear any frame start delays used for debugging left by the BIOS */
 	reg = PIPECONF(crtc->config->cpu_transcoder);
@@ -15144,27 +15120,55 @@  static void intel_sanitize_crtc(struct intel_crtc *crtc)
 		drm_crtc_vblank_on(&crtc->base);
 	}
 
-	/* We need to sanitize the plane -> pipe mapping first because this will
-	 * disable the crtc (and hence change the state) if it is wrong. Note
-	 * that gen4+ has a fixed plane -> pipe mapping.  */
-	if (INTEL_INFO(dev)->gen < 4 && !intel_check_plane_mapping(crtc)) {
-		bool plane;
+	/* set up current state */
+	if (!force_restore && hw_state->base.active) {
+		bool enable;
 
-		DRM_DEBUG_KMS("[CRTC:%d] wrong plane connection detected!\n",
-			      crtc->base.base.id);
+		memcpy(pipe_config, hw_state, sizeof(*pipe_config));
+		__drm_atomic_helper_crtc_duplicate_state(&crtc->base, &pipe_config->base);
+		pipe_config->base.state = state;
 
-		/* Pipe has the wrong plane attached and the plane is active.
-		 * Temporarily change the plane mapping and disable everything
-		 * ...  */
-		plane = crtc->plane;
-		to_intel_plane_state(crtc->base.primary->state)->visible = true;
-		crtc->plane = !plane;
-		intel_crtc_disable_noatomic(&crtc->base);
-		crtc->plane = plane;
+		enable = false;
+		for_each_encoder_on_crtc(dev, &crtc->base, encoder)
+			enable |= encoder->connectors_active;
+
+		pipe_config->base.active = !!enable;
+	}
+
+	if (hw_state->quirks & PIPE_CONFIG_QUIRK_WRONG_PLANE) {
+		if (force_restore || i915.fastboot)
+			pipe_config->base.mode_changed = true;
+		else
+			pipe_config->base.active = false;
 	}
 
-	if (dev_priv->quirks & QUIRK_PIPEA_FORCE &&
-	    crtc->pipe == PIPE_A && !crtc->active) {
+	/* XXX: This is needs to be modified for making fastboot possible
+	 * by default without requiring a modeset.
+	 */
+	if (hw_state->base.active && pipe_config->base.active) {
+		struct intel_crtc_state sw_state;
+
+		memset(&sw_state, 0, sizeof(sw_state));
+		sw_state.base = pipe_config->base;
+		sw_state.scaler_state = pipe_config->scaler_state;
+		sw_state.shared_dpll = pipe_config->shared_dpll;
+		sw_state.dpll_hw_state = pipe_config->dpll_hw_state;
+		sw_state.ddi_pll_sel = pipe_config->ddi_pll_sel;
+
+		intel_modeset_pipe_config(&crtc->base, &sw_state);
+
+		/* Check if we need to force a modeset */
+		if (!intel_pipe_config_compare(dev, &sw_state, hw_state, !i915.fastboot)) {
+			DRM_DEBUG_KMS("sw and hw state differ, forcing modeset\n");
+			pipe_config->base.mode_changed = true;
+		} else {
+			*pipe_config = sw_state;
+		}
+	}
+
+
+	if (dev_priv->quirks & QUIRK_PIPEA_FORCE && !hw_state->base.active &&
+	    crtc->pipe == PIPE_A && !pipe_config->base.active) {
 		/* BIOS forgot to enable pipe A, this mostly happens after
 		 * resume. Force-enable the pipe to fix this, the update_dpms
 		 * call below we restore the pipe to the right state, but leave
@@ -15172,44 +15176,7 @@  static void intel_sanitize_crtc(struct intel_crtc *crtc)
 		intel_enable_pipe_a(dev);
 	}
 
-	/* Adjust the state of the output pipe according to whether we
-	 * have active connectors/encoders. */
-	enable = false;
-	for_each_encoder_on_crtc(dev, &crtc->base, encoder)
-		enable |= encoder->connectors_active;
-
-	if (!enable)
-		intel_crtc_disable_noatomic(&crtc->base);
-
-	if (crtc->active != crtc->base.state->active) {
-
-		/* This can happen either due to bugs in the get_hw_state
-		 * functions or because of calls to intel_crtc_disable_noatomic,
-		 * or because the pipe is force-enabled due to the
-		 * pipe A quirk. */
-		DRM_DEBUG_KMS("[CRTC:%d] hw state adjusted, was %s, now %s\n",
-			      crtc->base.base.id,
-			      crtc->base.state->enable ? "enabled" : "disabled",
-			      crtc->active ? "enabled" : "disabled");
-
-		crtc->base.state->enable = crtc->active;
-		crtc->base.state->active = crtc->active;
-		crtc->base.enabled = crtc->active;
-
-		/* Because we only establish the connector -> encoder ->
-		 * crtc links if something is active, this means the
-		 * crtc is now deactivated. Break the links. connector
-		 * -> encoder links are only establish when things are
-		 *  actually up, hence no need to break them. */
-		WARN_ON(crtc->active);
-
-		for_each_encoder_on_crtc(dev, &crtc->base, encoder) {
-			WARN_ON(encoder->connectors_active);
-			encoder->base.crtc = NULL;
-		}
-	}
-
-	if (crtc->active || HAS_GMCH_DISPLAY(dev)) {
+	if (hw_state->base.active || HAS_GMCH_DISPLAY(dev)) {
 		/*
 		 * We start out with underrun reporting disabled to avoid races.
 		 * For correct bookkeeping mark this on active crtcs.
@@ -15265,6 +15232,7 @@  static void intel_sanitize_encoder(struct intel_encoder *encoder)
 		for_each_intel_connector(dev, connector) {
 			if (connector->encoder != encoder)
 				continue;
+
 			connector->base.dpms = DRM_MODE_DPMS_OFF;
 			connector->base.encoder = NULL;
 		}
@@ -15301,74 +15269,54 @@  void i915_redisable_vga(struct drm_device *dev)
 	i915_redisable_vga_power_on(dev);
 }
 
-static bool primary_get_hw_state(struct intel_crtc *crtc)
-{
-	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
-
-	return !!(I915_READ(DSPCNTR(crtc->plane)) & DISPLAY_PLANE_ENABLE);
-}
-
 static int readout_plane_state(struct drm_atomic_state *state,
 				struct intel_crtc *crtc,
 				struct intel_crtc_state *crtc_state)
 {
-	struct intel_plane *p;
+	struct intel_initial_plane_config plane_config = {};
 	struct drm_plane_state *drm_plane_state;
+	struct intel_plane *p;
 	bool active = crtc_state->base.active;
-	int ret = 0;
-
-	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;
+		struct intel_plane_state *plane_state;
 
 		if (crtc->pipe != p->pipe)
 			continue;
 
 		drm_plane_state = drm_atomic_get_plane_state(state, &p->base);
-		if (IS_ERR(drm_plane_state)) {
-			ret = PTR_ERR(drm_plane_state);
-			break;
-		}
+		if (IS_ERR(drm_plane_state))
+			return PTR_ERR(drm_plane_state);
+		plane_state = to_intel_plane_state(drm_plane_state);
 
 		/* Plane scaler state is not touched here. The first atomic
 		 * commit will restore all plane scalers to its old state.
 		 */
 
+		plane_state->visible = false;
 		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;
-		}
+			to_i915(state->dev)->display.get_initial_plane_config(crtc, &plane_config);
+			intel_find_initial_plane_obj(crtc, &plane_config, plane_state);
+		} else if (active)
+			p->disable_plane(&p->base, &crtc->base);
 
-		p->base.crtc = drm_plane_state->crtc;
-		if (visible) {
-			crtc_state->base.plane_mask |=
-				1 << drm_plane_index(&p->base);
-		} else {
-			crtc_state->base.plane_mask &=
-				~(1 << drm_plane_index(&p->base));
+		if (!plane_state->visible) {
+			int ret;
+			ret = drm_atomic_set_crtc_for_plane(drm_plane_state, NULL);
+			WARN_ON(ret);
+			drm_atomic_set_fb_for_plane(drm_plane_state, NULL);
 		}
+		p->base.crtc = drm_plane_state->crtc;
 	}
 
-	return ret;
+	return 0;
 }
 
 static int readout_hw_crtc_state(struct drm_atomic_state *state,
 				 struct intel_crtc *crtc)
 {
-	struct drm_i915_private *dev_priv = to_i915(state->dev);
+	struct drm_device *dev = state->dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
 	struct intel_crtc_state *crtc_state;
 	int ret;
 
@@ -15380,6 +15328,7 @@  static int readout_hw_crtc_state(struct drm_atomic_state *state,
 	if (ret)
 		return ret;
 
+	__drm_atomic_helper_crtc_destroy_state(&crtc->base, &crtc_state->base);
 	memset(crtc_state, 0, sizeof(*crtc_state));
 	crtc_state->base.crtc = &crtc->base;
 	crtc_state->base.state = state;
@@ -15397,6 +15346,22 @@  static int readout_hw_crtc_state(struct drm_atomic_state *state,
 		      crtc->base.base.id,
 		      crtc_state->base.active ? "enabled" : "disabled");
 
+	/* We need to sanitize the plane -> pipe mapping first because this will
+	 * disable the crtc (and hence change the state) if it is wrong. Note
+	 * that gen4+ has a fixed plane -> pipe mapping.  */
+	if (INTEL_INFO(dev)->gen < 4 && !intel_check_plane_mapping(crtc)) {
+		DRM_DEBUG_KMS("[CRTC:%d] wrong plane connection detected!\n",
+			      crtc->base.base.id);
+
+		/* Pipe has the wrong plane attached and the plane is active.
+		 * Temporarily change the plane mapping and disable everything
+		 * ...  */
+		crtc_state->quirks |=
+			PIPE_CONFIG_QUIRK_WRONG_PLANE;
+
+		crtc->plane = !crtc->plane;
+	}
+
 	return readout_plane_state(state, crtc, crtc_state);
 }
 
@@ -15512,7 +15477,7 @@  static int readout_hw_connector_encoder_state(struct drm_atomic_state *state)
 
 			encoder->get_config(encoder, crtc_state);
 
-			if (connector_state)
+			if (!WARN_ON(!connector_state))
 				connector_state->crtc = &crtc->base;
 		} else {
 			encoder->base.crtc = NULL;
@@ -15565,8 +15530,8 @@  err_free:
 
 /* 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)
+static struct drm_atomic_state *
+intel_modeset_setup_hw_state(struct drm_device *dev, bool force_restore)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_crtc *crtc;
@@ -15574,27 +15539,42 @@  void intel_modeset_setup_hw_state(struct drm_device *dev,
 	struct intel_encoder *encoder;
 	struct drm_atomic_state *state;
 	struct intel_shared_dpll_config shared_dplls[I915_NUM_PLLS];
-	int i;
+	int i, ret;
 
 	state = intel_modeset_readout_hw_state(dev);
 	if (IS_ERR(state)) {
 		DRM_ERROR("Failed to read out hw state\n");
-		return;
+		return NULL;
 	}
 
 	drm_atomic_helper_swap_state(dev, state);
 
-	/* swap sw/hw dpll state */
-	intel_atomic_duplicate_dpll_state(dev_priv, shared_dplls);
-	intel_shared_dpll_commit(state);
-	memcpy(to_intel_atomic_state(state)->shared_dpll,
-	       shared_dplls, sizeof(*shared_dplls) * dev_priv->num_shared_dpll);
+	if (force_restore) {
+		/* swap sw/hw dpll state */
+		intel_atomic_duplicate_dpll_state(dev_priv, shared_dplls);
+		intel_shared_dpll_commit(state);
+		memcpy(to_intel_atomic_state(state)->shared_dpll,
+		       shared_dplls, sizeof(*shared_dplls) * dev_priv->num_shared_dpll);
+	} else {
+		intel_shared_dpll_commit(state);
+		to_intel_atomic_state(state)->dpll_set = false;
+	}
 
 	/* HW state is read out, now we need to sanitize this mess. */
 	for_each_intel_encoder(dev, encoder) {
 		intel_sanitize_encoder(encoder);
 	}
 
+	if (!force_restore) {
+		struct drm_connector_state *conn_state;
+		struct drm_connector *connector;
+
+		for_each_connector_in_state(state, connector, conn_state, i) {
+			conn_state->best_encoder = connector->state->best_encoder;
+			conn_state->crtc = connector->state->crtc;
+		}
+	}
+
 	for_each_crtc_in_state(state, crtc, crtc_state, i) {
 		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
@@ -15616,7 +15596,7 @@  void intel_modeset_setup_hw_state(struct drm_device *dev,
 				      &crtc->state->adjusted_mode);
 		}
 
-		intel_sanitize_crtc(intel_crtc);
+		intel_sanitize_crtc(intel_crtc, to_intel_crtc_state(crtc_state), force_restore);
 
 		/*
 		 * sanitize_crtc may have forced an update of crtc->state,
@@ -15646,29 +15626,28 @@  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) {
-		int ret;
+	if (!force_restore)
+		return state;
 
-		i915_redisable_vga(dev);
+	i915_redisable_vga(dev);
 
-		ret = intel_set_mode(state);
-		if (ret) {
-			DRM_ERROR("Failed to restore previous mode\n");
-			drm_atomic_state_free(state);
-		}
-	} else {
+	ret = intel_set_mode(state);
+	if (ret) {
+		DRM_ERROR("Failed to restore previous mode\n");
 		drm_atomic_state_free(state);
 	}
 
 	intel_modeset_check_state(dev);
+	return NULL;
 }
 
-void intel_modeset_gem_init(struct drm_device *dev)
+void intel_modeset_gem_init(struct drm_device *dev, struct drm_atomic_state *state)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_crtc *c;
 	struct drm_i915_gem_object *obj;
-	int ret;
+	struct drm_crtc_state *crtc_state;
+	struct drm_crtc *c;
+	int ret, i;
 
 	mutex_lock(&dev->struct_mutex);
 	intel_init_gt_powersave(dev);
@@ -15693,27 +15672,67 @@  void intel_modeset_gem_init(struct drm_device *dev)
 	 * pinned & fenced.  When we do the allocation it's too early
 	 * for this.
 	 */
-	for_each_crtc(dev, c) {
-		obj = intel_fb_obj(c->primary->fb);
+	for_each_crtc_in_state(state, c, crtc_state, i) {
+		struct drm_connector_state *conn_state;
+		struct drm_connector *connector;
+		int j;
+		struct drm_plane *primary = c->primary;
+
+		obj = intel_fb_obj(primary->state->fb);
 		if (obj == NULL)
-			continue;
+			goto disable;
 
 		mutex_lock(&dev->struct_mutex);
-		ret = intel_pin_and_fence_fb_obj(c->primary,
-						 c->primary->fb,
-						 c->primary->state,
-						 NULL);
+		ret = intel_pin_and_fence_fb_obj(primary, primary->state->fb,
+						 primary->state, NULL);
 		mutex_unlock(&dev->struct_mutex);
-		if (ret) {
-			DRM_ERROR("failed to pin boot fb on pipe %d\n",
-				  to_intel_crtc(c)->pipe);
-			drm_framebuffer_unreference(c->primary->fb);
-			c->primary->fb = NULL;
-			c->primary->crtc = c->primary->state->crtc = NULL;
-			update_state_fb(c->primary);
-			c->state->plane_mask &= ~(1 << drm_plane_index(c->primary));
+		if (!ret && !crtc_state->active)
+			goto disable;
+
+		if (!ret) {
+			struct drm_plane_state *plane_state =
+				drm_atomic_get_existing_plane_state(state, primary);
+
+			ret = drm_atomic_set_crtc_for_plane(plane_state, c);
+			WARN_ON(ret);
+			drm_atomic_set_fb_for_plane(plane_state, primary->state->fb);
+			continue;
+		}
+
+
+		obj->frontbuffer_bits &=
+			~INTEL_FRONTBUFFER_PRIMARY(to_intel_crtc(c)->pipe);
+
+		DRM_ERROR("failed to pin boot fb on pipe %d: %i\n",
+			  to_intel_crtc(c)->pipe, ret);
+
+		drm_framebuffer_unreference(primary->state->fb);
+		drm_framebuffer_unreference(primary->fb);
+		primary->fb = primary->state->fb = NULL;
+		primary->crtc = primary->state->crtc = NULL;
+		/* Do not update crtc_state->plane_mask, this forces
+		 * the disabling of the primary plane during modeset.
+		 */
+
+disable:
+		crtc_state->active = crtc_state->enable = false;
+
+		ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
+		WARN_ON(ret);
+
+		for_each_connector_in_state(state, connector, conn_state, j) {
+			if (conn_state->crtc != c)
+				continue;
+
+			ret = drm_atomic_set_crtc_for_connector(conn_state, NULL);
+			WARN_ON(ret);
 		}
+
 	}
+	ret = intel_set_mode(state);
+	if (ret)
+		DRM_ERROR("Initial modeset failed with %i\n", ret);
+	drm_modeset_unlock_all(dev);
 
 	intel_backlight_register(dev);
 }
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index bc7d0a003c8e..ea380b83eb5d 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -330,7 +330,7 @@  struct intel_crtc_state {
 	 */
 #define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS	(1<<0) /* unreliable sync mode.flags */
 #define PIPE_CONFIG_QUIRK_INHERITED_MODE	(1<<1) /* mode inherited from firmware */
-#define PIPE_CONFIG_QUIRK_INITIAL_PLANES	(1<<2) /* planes are in unknown state */
+#define PIPE_CONFIG_QUIRK_WRONG_PLANE		(1<<2) /* intel_crtc->plane is wrong */
 	unsigned long quirks;
 
 	/* Pipe source size (ie. panel fitter input size)
@@ -528,7 +528,6 @@  struct intel_crtc {
 	uint32_t cursor_size;
 	uint32_t cursor_base;
 
-	struct intel_initial_plane_config plane_config;
 	struct intel_crtc_state *config;
 
 	/* reset counter value when the last flip was submitted */
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index 6372cfc7d053..6ac4990a0c11 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -582,7 +582,6 @@  static bool intel_fbdev_init_bios(struct drm_device *dev,
 	struct intel_framebuffer *fb = NULL;
 	struct drm_crtc *crtc;
 	struct intel_crtc *intel_crtc;
-	struct intel_initial_plane_config *plane_config = NULL;
 	unsigned int max_size = 0;
 
 	if (!i915.fastboot)
@@ -590,20 +589,21 @@  static bool intel_fbdev_init_bios(struct drm_device *dev,
 
 	/* Find the largest fb */
 	for_each_crtc(dev, crtc) {
+		struct intel_framebuffer *plane_fb =
+			to_intel_framebuffer(crtc->primary->state->fb);
 		intel_crtc = to_intel_crtc(crtc);
 
-		if (!intel_crtc->active || !crtc->primary->fb) {
+		if (!intel_crtc->active || !plane_fb) {
 			DRM_DEBUG_KMS("pipe %c not active or no fb, skipping\n",
 				      pipe_name(intel_crtc->pipe));
 			continue;
 		}
 
-		if (intel_crtc->plane_config.size > max_size) {
+		if (plane_fb->obj->base.size > max_size) {
 			DRM_DEBUG_KMS("found possible fb from plane %c\n",
 				      pipe_name(intel_crtc->pipe));
-			plane_config = &intel_crtc->plane_config;
 			fb = to_intel_framebuffer(crtc->primary->fb);
-			max_size = plane_config->size;
+			max_size = fb->obj->base.size;
 		}
 	}
 
@@ -638,7 +638,6 @@  static bool intel_fbdev_init_bios(struct drm_device *dev,
 			DRM_DEBUG_KMS("fb not wide enough for plane %c (%d vs %d)\n",
 				      pipe_name(intel_crtc->pipe),
 				      cur_size, fb->base.pitches[0]);
-			plane_config = NULL;
 			fb = NULL;
 			break;
 		}
@@ -659,7 +658,6 @@  static bool intel_fbdev_init_bios(struct drm_device *dev,
 			DRM_DEBUG_KMS("fb not big enough for plane %c (%d vs %d)\n",
 				      pipe_name(intel_crtc->pipe),
 				      cur_size, max_size);
-			plane_config = NULL;
 			fb = NULL;
 			break;
 		}
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 161ab26f81fb..78d86ae01621 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -452,7 +452,7 @@  static int intel_lid_notify(struct notifier_block *nb, unsigned long val,
 	 */
 	if (!HAS_PCH_SPLIT(dev)) {
 		drm_modeset_lock_all(dev);
-		intel_modeset_setup_hw_state(dev, true);
+		intel_display_resume(dev);
 		drm_modeset_unlock_all(dev);
 	}