diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index d03fc05..2a32405 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -305,13 +305,11 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector)
 }
 
 static enum drm_connector_status
-intel_crt_load_detect(struct drm_crtc *crtc, struct intel_crt *crt)
+intel_crt_load_detect(struct intel_crt *crt)
 {
-	struct drm_encoder *encoder = &crt->base.base;
-	struct drm_device *dev = encoder->dev;
+	struct drm_device *dev = crt->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	uint32_t pipe = intel_crtc->pipe;
+	uint32_t pipe = to_intel_crtc(crt->base.base.crtc)->pipe;
 	uint32_t save_bclrpat;
 	uint32_t save_vtotal;
 	uint32_t vtotal, vactive;
@@ -432,7 +430,6 @@ intel_crt_detect(struct drm_connector *connector, bool force)
 	struct drm_device *dev = connector->dev;
 	struct intel_crt *crt = intel_attached_crt(connector);
 	struct drm_crtc *crtc;
-	int dpms_mode;
 	enum drm_connector_status status;
 
 	if (I915_HAS_HOTPLUG(dev)) {
@@ -454,17 +451,18 @@ intel_crt_detect(struct drm_connector *connector, bool force)
 	/* for pre-945g platforms use load detect */
 	crtc = crt->base.base.crtc;
 	if (crtc && crtc->enabled) {
-		status = intel_crt_load_detect(crtc, crt);
+		status = intel_crt_load_detect(crt);
 	} else {
-		crtc = intel_get_load_detect_pipe(&crt->base, connector,
-						  NULL, &dpms_mode);
-		if (crtc) {
+		struct intel_load_detect_pipe tmp;
+
+		if (intel_get_load_detect_pipe(&crt->base,
+					       connector, NULL,
+					       &tmp)) {
 			if (intel_crt_detect_ddc(connector))
 				status = connector_status_connected;
 			else
-				status = intel_crt_load_detect(crtc, crt);
-			intel_release_load_detect_pipe(&crt->base,
-						       connector, dpms_mode);
+				status = intel_crt_load_detect(crt);
+			intel_release_load_detect_pipe(&tmp);
 		} else
 			status = connector_status_unknown;
 	}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index b7d63a5..b9bb20d 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -5541,115 +5541,133 @@ static struct drm_display_mode load_detect_mode = {
 		 704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
 };
 
-struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
-					    struct drm_connector *connector,
-					    struct drm_display_mode *mode,
-					    int *dpms_mode)
+bool intel_get_load_detect_pipe(struct intel_encoder *encoder,
+				struct drm_connector *connector,
+				struct drm_display_mode *mode,
+				struct intel_load_detect_pipe *old)
 {
-	struct intel_crtc *intel_crtc;
-	struct drm_crtc *possible_crtc;
-	struct drm_crtc *supported_crtc =NULL;
-	struct drm_encoder *encoder = &intel_encoder->base;
-	struct drm_crtc *crtc = NULL;
-	struct drm_device *dev = encoder->dev;
-	struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
-	struct drm_crtc_helper_funcs *crtc_funcs;
-	int i = -1;
-
-	/*
-	 * Algorithm gets a little messy:
-	 *   - if the connector already has an assigned crtc, use it (but make
-	 *     sure it's on first)
-	 *   - try to find the first unused crtc that can drive this connector,
-	 *     and use that if we find one
-	 *   - if there are no unused crtcs available, try to use the first
-	 *     one we found that supports the connector
-	 */
+	struct drm_device *dev = encoder->base.dev;
+	struct drm_crtc *crtc;
+	struct drm_framebuffer *fb, *old_fb;
+	int x, y;
 
 	/* See if we already have a CRTC for this connector */
-	if (encoder->crtc) {
-		crtc = encoder->crtc;
-		/* Make sure the crtc and connector are running */
-		intel_crtc = to_intel_crtc(crtc);
-		*dpms_mode = intel_crtc->dpms_mode;
-		if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) {
-			crtc_funcs = crtc->helper_private;
-			crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
-			encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
-		}
-		return crtc;
-	}
+	crtc = NULL;
+	if (encoder->base.crtc)
+		crtc = encoder->base.crtc;
 
-	/* Find an unused one (if possible) */
-	list_for_each_entry(possible_crtc, &dev->mode_config.crtc_list, head) {
-		i++;
-		if (!(encoder->possible_crtcs & (1 << i)))
-			continue;
-		if (!possible_crtc->enabled) {
-			crtc = possible_crtc;
-			break;
+	if (crtc == NULL) {
+		struct drm_crtc *pos;
+		int i = 0;
+
+		/* Find an unused one (if possible) */
+		list_for_each_entry(pos, &dev->mode_config.crtc_list, head) {
+			if (!(encoder->base.possible_crtcs & (1 << i++)))
+				continue;
+
+			if (!pos->enabled) {
+				crtc = pos;
+				break;
+			}
 		}
-		if (!supported_crtc)
-			supported_crtc = possible_crtc;
 	}
 
 	/*
 	 * If we didn't find an unused CRTC, don't use any.
 	 */
-	if (!crtc) {
-		return NULL;
-	}
+	if (crtc == NULL)
+		return false;
 
-	encoder->crtc = crtc;
-	connector->encoder = encoder;
-	intel_encoder->load_detect_temp = true;
+	/* Reuse the existing crtc->fb unless absent */
+	old_fb = crtc->fb;
+	if (old_fb == NULL || !crtc->enabled) {
+		struct drm_i915_private *dev_priv = dev->dev_private;
+		struct intel_fbdev *ifbdev = dev_priv->fbdev;
 
-	intel_crtc = to_intel_crtc(crtc);
-	*dpms_mode = intel_crtc->dpms_mode;
+		fb = &ifbdev->ifb.base;
+		x = y = 0;
 
-	if (!crtc->enabled) {
 		if (!mode)
 			mode = &load_detect_mode;
-		drm_crtc_helper_set_mode(crtc, mode, 0, 0, crtc->fb);
 	} else {
-		if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) {
-			crtc_funcs = crtc->helper_private;
-			crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
-		}
+		fb = crtc->fb;
+		x = crtc->x;
+		y = crtc->y;
+		mode = &crtc->mode;
+	}
+
+	/* We may be called during ifbdev init, before the fb is bound */
+	if (fb == NULL || to_intel_framebuffer(fb)->obj == NULL)
+		return false;
+
+	/* Save the current configuration to be restored after load-detect */
+	old->connector = connector;
+	old->encoder = connector->encoder;
+	old->crtc = connector->encoder ? connector->encoder->crtc : NULL;
+	if (old->crtc) {
+		struct intel_crtc *intel_crtc;
 
-		/* Add this connector to the crtc */
-		encoder_funcs->mode_set(encoder, &crtc->mode, &crtc->mode);
-		encoder_funcs->commit(encoder);
+		intel_crtc = to_intel_crtc(connector->encoder->crtc);
+		old->crtc = &intel_crtc->base;
+		old->dpms_mode = intel_crtc->dpms_mode;
+		old->fb = intel_crtc->base.fb;
+		old->mode = intel_crtc->base.mode;
+		old->x = intel_crtc->base.x;
+		old->y = intel_crtc->base.y;
 	}
+
+	/* Set the new connector->encoder->crtc->fb configuration */
+	crtc->fb = fb;
+	encoder->base.crtc = crtc;
+	connector->encoder = &encoder->base;
+
+	if (!drm_crtc_helper_set_mode(crtc, mode, x, y, old_fb)) {
+		DRM_DEBUG_KMS("failed to set mode for load-detect\n");
+
+		old->connector->encoder = old->encoder;
+		old->encoder->crtc = old->crtc;
+		old->crtc->fb = old->fb;
+
+		crtc->fb = old_fb;
+
+		drm_helper_disable_unused_functions(dev);
+		return false;
+	}
+	connector->dpms = DRM_MODE_DPMS_ON;
+
 	/* let the connector get through one full cycle before testing */
-	intel_wait_for_vblank(dev, intel_crtc->pipe);
+	intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe);
 
-	return crtc;
+	return true;
 }
 
-void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
-				    struct drm_connector *connector, int dpms_mode)
+void intel_release_load_detect_pipe(struct intel_load_detect_pipe *old)
 {
-	struct drm_encoder *encoder = &intel_encoder->base;
-	struct drm_device *dev = encoder->dev;
-	struct drm_crtc *crtc = encoder->crtc;
-	struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
-	struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+	struct drm_crtc *crtc = old->crtc;
+
+	old->connector->encoder = old->encoder;
+	if (old->encoder != NULL)
+		old->encoder->crtc = crtc;
+	if (crtc != NULL) {
+		struct drm_framebuffer *fb;
+
+		fb = crtc->fb;
+		crtc->fb = old->fb;
 
-	if (intel_encoder->load_detect_temp) {
-		encoder->crtc = NULL;
-		connector->encoder = NULL;
-		intel_encoder->load_detect_temp = false;
 		crtc->enabled = drm_helper_crtc_in_use(crtc);
-		drm_helper_disable_unused_functions(dev);
+		if (crtc->enabled) {
+			if (!drm_crtc_helper_set_mode(crtc, &old->mode,
+						      old->x, old->y, fb))
+				DRM_ERROR("failed to restore mode after load-detect\n");
+
+			old->connector = DRM_MODE_DPMS_ON;
+			if (old->dpms_mode != DRM_MODE_DPMS_ON)
+				drm_helper_connector_dpms(old->connector,
+							  old->dpms_mode);
+		}
 	}
 
-	/* Switch crtc and encoder back off if necessary */
-	if (crtc->enabled && dpms_mode != DRM_MODE_DPMS_ON) {
-		if (encoder->crtc == crtc)
-			encoder_funcs->dpms(encoder, dpms_mode);
-		crtc_funcs->dpms(crtc, dpms_mode);
-	}
+	drm_helper_disable_unused_functions(crtc->dev);
 }
 
 /* Returns the clock of the currently programmed mode of the given pipe. */
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index aeb1b98..64cfc88 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -140,7 +140,6 @@ struct intel_fbdev {
 struct intel_encoder {
 	struct drm_encoder base;
 	int type;
-	bool load_detect_temp;
 	bool needs_tv_clock;
 	void (*hot_plug)(struct intel_encoder *);
 	int crtc_mask;
@@ -298,13 +297,23 @@ static inline void intel_wait_for_crtc_vblank_safe(struct drm_crtc *crtc)
 		msleep(50);
 }
 extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe);
-extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
-						   struct drm_connector *connector,
-						   struct drm_display_mode *mode,
-						   int *dpms_mode);
-extern void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
-					   struct drm_connector *connector,
-					   int dpms_mode);
+
+struct intel_load_detect_pipe {
+	struct drm_connector *connector;
+	struct drm_encoder *encoder;
+	struct drm_crtc *crtc;
+
+	int dpms_mode;
+	struct drm_framebuffer *fb;
+	struct drm_display_mode mode;
+	int x, y;
+};
+
+extern bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
+				       struct drm_connector *connector,
+				       struct drm_display_mode *mode,
+				       struct intel_load_detect_pipe *tmp);
+extern void intel_release_load_detect_pipe(struct intel_load_detect_pipe *tmp);
 
 extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB);
 extern int intel_sdvo_supports_hotplug(struct drm_connector *connector);
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 3047a66..1352acf 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1370,15 +1370,12 @@ intel_tv_detect(struct drm_connector *connector, bool force)
 	if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) {
 		type = intel_tv_detect_type(intel_tv, connector);
 	} else if (force) {
-		struct drm_crtc *crtc;
-		int dpms_mode;
+		struct intel_load_detect_pipe tmp;
 
-		crtc = intel_get_load_detect_pipe(&intel_tv->base, connector,
-						  &mode, &dpms_mode);
-		if (crtc) {
+		if (intel_get_load_detect_pipe(&intel_tv->base, connector,
+					       &mode, &tmp)) {
 			type = intel_tv_detect_type(intel_tv, connector);
-			intel_release_load_detect_pipe(&intel_tv->base, connector,
-						       dpms_mode);
+			intel_release_load_detect_pipe(&tmp);
 		} else
 			return connector_status_unknown;
 	} else
