Separate modeset fallbacks are retained for each crtc

Change-Id: I51d6e27f3bf961dae72d580220e895c3b49ce326
diff --git a/src/armsoc_driver.c b/src/armsoc_driver.c
index e69430b..59aafbd 100644
--- a/src/armsoc_driver.c
+++ b/src/armsoc_driver.c
@@ -70,8 +70,6 @@
 static void ARMSOCLeaveVT(VT_FUNC_ARGS_DECL);
 static void ARMSOCFreeScreen(FREE_SCREEN_ARGS_DECL);
 
-
-
 /**
  * A structure used by the XFree86 code when loading this driver, so that it
  * can access the Probe() function, and other functions/info that it uses
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index a6edfa8..216195e 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -72,6 +72,11 @@
 	struct drmmode_rec *drmmode;
 	drmModeCrtcPtr mode_crtc;
 	int cursor_visible;
+	/* settings retained on last good modeset */
+	int last_good_x;
+	int last_good_y;
+	Rotation last_good_rotation;
+	DisplayModePtr last_good_mode;
 };
 
 struct drmmode_prop_rec {
@@ -96,7 +101,7 @@
 };
 
 static void drmmode_output_dpms(xf86OutputPtr output, int mode);
-static Bool drmmode_xf86crtc_resize(ScrnInfoPtr pScrn, int width, int height);
+static Bool resize_scanout_bo(ScrnInfoPtr pScrn, int width, int height);
 
 static struct drmmode_rec *
 drmmode_from_scrn(ScrnInfoPtr pScrn)
@@ -190,12 +195,6 @@
 	uint32_t fb_id;
 	drmModeModeInfo kmode;
 	drmModeCrtcPtr newcrtc = NULL;
-	static int got_last_good = -1;
-	static int last_good_x;
-	static int last_good_y;
-	static Rotation last_good_rotation;
-	static DisplayModeRec last_good_mode;
-
 
 	TRACE_ENTER();
 
@@ -277,10 +276,6 @@
 	if (kmode.hdisplay != newcrtc->mode.hdisplay ||
 		kmode.vdisplay != newcrtc->mode.vdisplay) {
 
-		xf86CrtcConfigPtr xf86_config;
-		int i;
-		Bool *enables;
-
 		ret = FALSE;
 		ERROR_MSG(
 				"drm did not set requested mode! (requested %dx%d, actual %dx%d)",
@@ -288,37 +283,29 @@
 				newcrtc->mode.hdisplay,
 				newcrtc->mode.vdisplay);
 
-		if (got_last_good < 0) {
+		if (!drmmode_crtc->last_good_mode) {
 			DEBUG_MSG("No last good values to use");
 			goto done;
 		}
 
-		DEBUG_MSG("Reverting to last_good values");
-		/* disable crtcs to prevent resize calling back here */
-		xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
-		enables = malloc(xf86_config->num_crtc * sizeof(Bool));
-		for (i = 0; i < xf86_config->num_crtc; i++) {
-			xf86CrtcPtr crtc = xf86_config->crtc[i];
-			enables[i] = crtc->enabled;
-			crtc->enabled = 0;
-		}
 		/* revert to last good settings */
-		drmmode_xf86crtc_resize(pScrn,
-				last_good_mode.HDisplay,
-				last_good_mode.VDisplay);
+		DEBUG_MSG("Reverting to last_good values");
+		if (!resize_scanout_bo(pScrn,
+				drmmode_crtc->last_good_mode->HDisplay,
+				drmmode_crtc->last_good_mode->VDisplay)) {
+			ERROR_MSG("Could not revert to last good mode");
+			goto done;
+		}
+
 		fb_id = armsoc_bo_get_fb(pARMSOC->scanout);
 		drmmode_ConvertToKMode(crtc->scrn, &kmode,
-				&last_good_mode);
+				drmmode_crtc->last_good_mode);
 		drmModeSetCrtc(drmmode->fd,
 				drmmode_crtc->mode_crtc->crtc_id,
-				fb_id, last_good_x, last_good_y,
+				fb_id,
+				drmmode_crtc->last_good_x,
+				drmmode_crtc->last_good_y,
 				output_ids, output_count, &kmode);
-		/* re-enable crtcs */
-		for (i = 0; i < xf86_config->num_crtc; i++) {
-			xf86CrtcPtr crtc = xf86_config->crtc[i];
-			crtc->enabled = enables[i];
-		}
-		free(enables);
 
 		/* let RandR know we changed things */
 		xf86RandR12TellChanged(pScrn->pScreen);
@@ -331,11 +318,16 @@
 		 * that on failure.
 		 */
 		DEBUG_MSG("Setting last good values");
-		got_last_good = 1;
-		last_good_x = crtc->x;
-		last_good_y = crtc->y;
-		last_good_rotation = crtc->rotation;
-		last_good_mode = crtc->mode;
+		drmmode_crtc->last_good_x = crtc->x;
+		drmmode_crtc->last_good_y = crtc->y;
+		drmmode_crtc->last_good_rotation = crtc->rotation;
+		if (drmmode_crtc->last_good_mode) {
+			if (drmmode_crtc->last_good_mode->name) {
+				free(drmmode_crtc->last_good_mode->name);
+			}
+			free(drmmode_crtc->last_good_mode);
+		}
+		drmmode_crtc->last_good_mode = xf86DuplicateMode(&crtc->mode);
 
 		ret = TRUE;
 	}
@@ -361,12 +353,12 @@
 	if (output_ids)
 		free(output_ids);
 
-	if (!ret && got_last_good > 0) {
+	if (!ret && !drmmode_crtc->last_good_mode) {
 		/* If there was a problem, restore the last good mode: */
-		crtc->x = last_good_x;
-		crtc->y = last_good_y;
-		crtc->rotation = last_good_rotation;
-		crtc->mode = last_good_mode;
+		crtc->x = drmmode_crtc->last_good_x;
+		crtc->y = drmmode_crtc->last_good_y;
+		crtc->rotation = drmmode_crtc->last_good_rotation;
+		crtc->mode = *drmmode_crtc->last_good_mode;
 	}
 
 	TRACE_EXIT();
@@ -680,8 +672,10 @@
 	drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd,
 			drmmode->mode_res->crtcs[num]);
 	drmmode_crtc->drmmode = drmmode;
-	INFO_MSG("Got CRTC: %d", num);
+	drmmode_crtc->last_good_mode = NULL;
 
+	INFO_MSG("Got CRTC: %d (id: %d)",
+			num, drmmode_crtc->mode_crtc->crtc_id);
 	crtc->driver_private = drmmode_crtc;
 
 	TRACE_EXIT();
@@ -1186,14 +1180,11 @@
 	pARMSOC->scanout = bo;
 }
 
-static Bool
-drmmode_xf86crtc_resize(ScrnInfoPtr pScrn, int width, int height)
+static Bool resize_scanout_bo(ScrnInfoPtr pScrn, int width, int height)
 {
 	struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
 	ScreenPtr pScreen = pScrn->pScreen;
 	uint32_t pitch;
-	int i;
-	xf86CrtcConfigPtr xf86_config;
 
 	TRACE_ENTER();
 	DEBUG_MSG("Resize: %dx%d", width, height);
@@ -1300,6 +1291,20 @@
 		 */
 		rootPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
 	}
+	TRACE_EXIT();
+	return TRUE;
+}
+
+static Bool
+drmmode_xf86crtc_resize(ScrnInfoPtr pScrn, int width, int height)
+{
+	int i;
+	xf86CrtcConfigPtr xf86_config;
+
+	TRACE_ENTER();
+
+	if (!resize_scanout_bo(pScrn, width, height))
+		return FALSE;
 
 	/* Framebuffer needs to be reset on all CRTCs, not just
 	 * those that have repositioned */
diff --git a/src/drmmode_pl111/drmmode_pl111.c b/src/drmmode_pl111/drmmode_pl111.c
index 2346112..14d9624 100644
--- a/src/drmmode_pl111/drmmode_pl111.c
+++ b/src/drmmode_pl111/drmmode_pl111.c
@@ -136,7 +136,8 @@
 	}
 }
 
-/* TODO MIDEGL-1718: this should be included from kernel headers when pl111 is mainline */
+/* TODO MIDEGL-1718: this should be included
+ * from kernel headers when pl111 is mainline */
 struct drm_pl111_gem_create {
 	uint32_t height;
 	uint32_t width;