From e1cd21bcc8747fcc573708bd4d74df39b60c476a Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sat, 5 Jul 2008 20:17:49 +0200 Subject: NV50: remove edid when monitor is gone, improve fbcon, misc fixes - This should avoid switching crtc's when going to fbcon. --- linux-core/drm_crtc.c | 7 +++++++ linux-core/nv50_fbcon.c | 46 ++++++++++++++++++++++++++++++++++--------- linux-core/nv50_kms_wrapper.c | 31 ++++++++++++++++++----------- 3 files changed, 64 insertions(+), 20 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index f8e09a8c..47885a07 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -2046,6 +2046,13 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, str if (connector->edid_blob_ptr) drm_property_destroy_blob(dev, connector->edid_blob_ptr); + /* Delete edid, when there is none. */ + if (!edid) { + connector->edid_blob_ptr = NULL; + ret = drm_connector_property_set_value(connector, dev->mode_config.edid_property, 0); + return ret; + } + connector->edid_blob_ptr = drm_property_create_blob(connector->dev, 128, edid); ret = drm_connector_property_set_value(connector, dev->mode_config.edid_property, connector->edid_blob_ptr->base.id); diff --git a/linux-core/nv50_fbcon.c b/linux-core/nv50_fbcon.c index c428ff94..8969860b 100644 --- a/linux-core/nv50_fbcon.c +++ b/linux-core/nv50_fbcon.c @@ -284,16 +284,21 @@ static int nv50_fbcon_set_par(struct fb_info *info) } mode_set.mode = drm_mode; - list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) { - if (crtc_used[crtc_count]) { - crtc_count++; - continue; + /* choose crtc it already has, if possible */ + if (drm_connector->encoder) { + struct drm_encoder *drm_encoder = drm_connector->encoder; + + if (drm_encoder->crtc) { + list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) { + crtc_count++; + + if (drm_crtc == drm_encoder->crtc) { + if (!crtc_used[crtc_count]) /* still available? */ + mode_set.crtc = drm_crtc; + break; + } + } } - - /* found a crtc */ - mode_set.crtc = drm_crtc; - - break; } /* proceed as planned */ @@ -302,6 +307,29 @@ static int nv50_fbcon_set_par(struct fb_info *info) crtc_used[crtc_count] = true; } + if (!mode_set.crtc) { + crtc_count = 0; /* reset */ + + /* choose a "random" crtc */ + list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) { + if (crtc_used[crtc_count]) { + crtc_count++; + continue; + } + + /* found a crtc */ + mode_set.crtc = drm_crtc; + + break; + } + + /* proceed as planned */ + if (mode_set.crtc) { + mode_set.crtc->funcs->set_config(&mode_set); + crtc_used[crtc_count] = true; + } + } + kfree(mode_set.connectors); } diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 520028aa..03c60c1f 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -348,16 +348,11 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) blank = true; } - if (!set->connectors && (modeset || switch_fb)) { + if (!set->connectors && !blank) { DRM_ERROR("Sanity check failed\n"); goto out; } - if (!modeset && !switch_fb && !blank) { - DRM_ERROR("There is nothing to do, bad input.\n"); - goto out; - } - /* Basic variable setting */ dev = set->crtc->dev; dev_priv = dev->dev_private; @@ -369,7 +364,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) */ /* for switch_fb we verify if any important changes happened */ - if (modeset || switch_fb) { + if (!blank) { /* Mode validation */ hw_mode = nv50_kms_to_hw_mode(set->mode); @@ -388,6 +383,9 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } connector = to_nv50_connector(drm_connector); + /* This is to ensure it knows the connector subtype. */ + drm_connector->funcs->fill_modes(drm_connector, 0, 0); + output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector)); if (!output) { DRM_ERROR("No output\n"); @@ -409,6 +407,12 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } } + /* Now we verified if anything changed, fail if nothing has. */ + if (!modeset && !switch_fb && !blank) { + DRM_ERROR("There is nothing to do, bad input.\n"); + goto out; + } + /* Validation done, move on to cleaning of existing structures. */ if (modeset) { /* find encoders that use this crtc. */ @@ -913,6 +917,7 @@ static enum drm_connector_status nv50_kms_connector_detect(struct drm_connector /* update our modes whenever there is reason to */ if (old_status != drm_connector->status) { drm_connector->funcs->fill_modes(drm_connector, 0, 0); + /* notify fb of changes */ dev->mode_config.funcs->fb_changed(dev); } @@ -966,16 +971,16 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u if (!connected) { NV50_DEBUG("%s is disconnected\n", drm_get_connector_name(drm_connector)); - /* TODO set EDID to NULL */ - return; } /* Not all connnectors have an i2c channel. */ - if (connector->i2c_chan) + if (connected && connector->i2c_chan) edid = (struct edid *) drm_do_probe_ddc_edid(&connector->i2c_chan->adapter); + /* This will remove edid if needed. */ + drm_mode_connector_update_edid_property(drm_connector, edid); + if (edid) { - drm_mode_connector_update_edid_property(drm_connector, edid); rval = drm_add_edid_modes(drm_connector, edid); /* 2 encoders per connector */ @@ -1026,6 +1031,10 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u drm_mode_prune_invalid(dev, &drm_connector->modes, true); + /* pruning is done, so bail out. */ + if (!connected) + return; + if (list_empty(&drm_connector->modes)) { struct drm_display_mode *stdmode; struct nouveau_hw_mode *hw_mode; -- cgit v1.2.3