Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 26099a74 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

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: default avatarBen Skeggs <bskeggs@redhat.com>
parent 2c580775
Loading
Loading
Loading
Loading
+17 −14
Original line number Original line Diff line number Diff line
@@ -431,24 +431,27 @@ nouveau_connector_set_property(struct drm_connector *connector,
}
}


static struct drm_display_mode *
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;
	struct drm_display_mode *mode, *largest = NULL;
	int high_w = 0, high_h = 0, high_v = 0;
	int high_w = 0, high_h = 0, high_v = 0;


	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.. */
		/* Use preferred mode if there is one.. */
	list_for_each_entry(mode, &connector->base.probed_modes, head) {
		if (mode->type & DRM_MODE_TYPE_PREFERRED) {
		if (mode->type & DRM_MODE_TYPE_PREFERRED) {
			NV_DEBUG_KMS(dev, "native mode from preferred\n");
			NV_DEBUG_KMS(dev, "native mode from preferred\n");
			return drm_mode_duplicate(dev, mode);
			return drm_mode_duplicate(dev, mode);
		}
		}
	}


	/* Otherwise, take the resolution with the largest width, then height,
		/* Otherwise, take the resolution with the largest width, then
	 * then vertical refresh
		 * height, then vertical refresh
		 */
		 */
	list_for_each_entry(mode, &connector->base.probed_modes, head) {
		if (mode->hdisplay < high_w)
		if (mode->hdisplay < high_w)
			continue;
			continue;


@@ -552,7 +555,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
	 */
	 */
	if (!nv_connector->native_mode)
	if (!nv_connector->native_mode)
		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) {
	if (ret == 0 && nv_connector->native_mode) {
		struct drm_display_mode *mode;
		struct drm_display_mode *mode;


@@ -583,9 +586,9 @@ nouveau_connector_mode_valid(struct drm_connector *connector,


	switch (nv_encoder->dcb->type) {
	switch (nv_encoder->dcb->type) {
	case OUTPUT_LVDS:
	case OUTPUT_LVDS:
		BUG_ON(!nv_connector->native_mode);
		if (nv_connector->native_mode &&
		if (mode->hdisplay > nv_connector->native_mode->hdisplay ||
		    (mode->hdisplay > nv_connector->native_mode->hdisplay ||
		    mode->vdisplay > nv_connector->native_mode->vdisplay)
		     mode->vdisplay > nv_connector->native_mode->vdisplay))
			return MODE_PANEL;
			return MODE_PANEL;


		min_clock = 0;
		min_clock = 0;
@@ -727,7 +730,7 @@ nouveau_connector_create_lvds(struct drm_device *dev,
	if (ret == 0)
	if (ret == 0)
		goto out;
		goto out;
	nv_connector->detected_encoder = nv_encoder;
	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)
	list_for_each_entry_safe(mode, temp, &connector->probed_modes, head)
		drm_mode_remove(connector, mode);
		drm_mode_remove(connector, mode);