NV50: remove edid when monitor is gone, improve fbcon, misc fixes

- This should avoid switching crtc's when going to fbcon.
main
Maarten Maathuis 2008-07-05 20:17:49 +02:00
parent c48cddc7ef
commit e1cd21bcc8
3 changed files with 64 additions and 20 deletions

View File

@ -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);

View File

@ -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);
}

View File

@ -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;