drm/nouveau: fix dual-link displays when plugged into single-link outputs

When selecting the native mode for a display we weren't taking into account
whether or not it was actually supported on that particular output.

This patch modifies our native mode selection to run all modes through
mode_valid() first.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index bfa6562..256e82b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -431,24 +431,27 @@
 }
 
 static struct drm_display_mode *
-nouveau_connector_native_mode(struct nouveau_connector *connector)
+nouveau_connector_native_mode(struct drm_connector *connector)
 {
-	struct drm_device *dev = connector->base.dev;
+	struct drm_connector_helper_funcs *helper = connector->helper_private;
+	struct nouveau_connector *nv_connector = nouveau_connector(connector);
+	struct drm_device *dev = connector->dev;
 	struct drm_display_mode *mode, *largest = NULL;
 	int high_w = 0, high_h = 0, high_v = 0;
 
-	/* Use preferred mode if there is one.. */
-	list_for_each_entry(mode, &connector->base.probed_modes, head) {
+	list_for_each_entry(mode, &nv_connector->base.probed_modes, head) {
+		if (helper->mode_valid(connector, mode) != MODE_OK)
+			continue;
+
+		/* Use preferred mode if there is one.. */
 		if (mode->type & DRM_MODE_TYPE_PREFERRED) {
 			NV_DEBUG_KMS(dev, "native mode from preferred\n");
 			return drm_mode_duplicate(dev, mode);
 		}
-	}
 
-	/* Otherwise, take the resolution with the largest width, then height,
-	 * then vertical refresh
-	 */
-	list_for_each_entry(mode, &connector->base.probed_modes, head) {
+		/* Otherwise, take the resolution with the largest width, then
+		 * height, then vertical refresh
+		 */
 		if (mode->hdisplay < high_w)
 			continue;
 
@@ -552,7 +555,7 @@
 	 */
 	if (!nv_connector->native_mode)
 		nv_connector->native_mode =
-			nouveau_connector_native_mode(nv_connector);
+			nouveau_connector_native_mode(connector);
 	if (ret == 0 && nv_connector->native_mode) {
 		struct drm_display_mode *mode;
 
@@ -583,9 +586,9 @@
 
 	switch (nv_encoder->dcb->type) {
 	case OUTPUT_LVDS:
-		BUG_ON(!nv_connector->native_mode);
-		if (mode->hdisplay > nv_connector->native_mode->hdisplay ||
-		    mode->vdisplay > nv_connector->native_mode->vdisplay)
+		if (nv_connector->native_mode &&
+		    (mode->hdisplay > nv_connector->native_mode->hdisplay ||
+		     mode->vdisplay > nv_connector->native_mode->vdisplay))
 			return MODE_PANEL;
 
 		min_clock = 0;
@@ -727,7 +730,7 @@
 	if (ret == 0)
 		goto out;
 	nv_connector->detected_encoder = nv_encoder;
-	nv_connector->native_mode = nouveau_connector_native_mode(nv_connector);
+	nv_connector->native_mode = nouveau_connector_native_mode(connector);
 	list_for_each_entry_safe(mode, temp, &connector->probed_modes, head)
 		drm_mode_remove(connector, mode);