aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux-core/drm_crtc.c7
-rw-r--r--linux-core/nv50_fbcon.c46
-rw-r--r--linux-core/nv50_kms_wrapper.c31
3 files changed, 64 insertions, 20 deletions
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;