From 26099a74805eaf79f3058cc4097ebaa8cc55122c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 28 May 2010 10:13:16 +1000 Subject: [PATCH] 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 --- drivers/gpu/drm/nouveau/nouveau_connector.c | 31 +++++++++++---------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index bfa65629517b..256e82bd91dd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -431,24 +431,27 @@ nouveau_connector_set_property(struct drm_connector *connector, } 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 @@ nouveau_connector_get_modes(struct drm_connector *connector) */ 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 @@ nouveau_connector_mode_valid(struct drm_connector *connector, 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 @@ nouveau_connector_create_lvds(struct drm_device *dev, 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);