NV50: remove edid when monitor is gone, improve fbcon, misc fixes
authorMaarten Maathuis <madman2003@gmail.com>
Sat, 5 Jul 2008 18:17:49 +0000 (20:17 +0200)
committerMaarten Maathuis <madman2003@gmail.com>
Sat, 5 Jul 2008 18:17:49 +0000 (20:17 +0200)
- This should avoid switching crtc's when going to fbcon.

linux-core/drm_crtc.c
linux-core/nv50_fbcon.c
linux-core/nv50_kms_wrapper.c

index f8e09a8..47885a0 100644 (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);
index c428ff9..8969860 100644 (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);
        }
 
index 520028a..03c60c1 100644 (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;