diff options
Diffstat (limited to 'linux-core')
-rw-r--r-- | linux-core/nv50_kms_wrapper.c | 52 |
1 files changed, 37 insertions, 15 deletions
diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index ee18b36a..520028aa 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -348,7 +348,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) blank = true; } - if (!set->connectors && modeset) { + if (!set->connectors && (modeset || switch_fb)) { DRM_ERROR("Sanity check failed\n"); goto out; } @@ -368,7 +368,8 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) * Wiring up the encoders and connectors. */ - if (modeset) { + /* for switch_fb we verify if any important changes happened */ + if (modeset || switch_fb) { /* Mode validation */ hw_mode = nv50_kms_to_hw_mode(set->mode); @@ -398,10 +399,18 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) DRM_ERROR("Mode not ok\n"); goto out; } - } - /* Validation done, move on to cleaning of existing structures. */ + /* verify if any "sneaky" changes happened */ + if (output != connector->output) + modeset = true; + + if (output->crtc != crtc) + modeset = true; + } + } + /* Validation done, move on to cleaning of existing structures. */ + if (modeset) { /* find encoders that use this crtc. */ list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { if (drm_encoder->crtc == set->crtc) { @@ -474,8 +483,18 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (blank) { crtc = to_nv50_crtc(set->crtc); - /* keeping the encoders and connectors attached, so they can be tracked */ set->crtc->enabled = false; + + /* disconnect encoders and connectors */ + for (i = 0; i < set->num_connectors; i++) { + drm_connector = set->connectors[i]; + + if (!drm_connector->encoder) + continue; + + drm_connector->encoder->crtc = NULL; + drm_connector->encoder = NULL; + } } /** @@ -535,9 +554,9 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) goto out; } - /* detach any outputs that are currently running on this crtc */ + /* detach any outputs that are currently unused */ list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { - if (drm_encoder->crtc == set->crtc) { + if (!drm_encoder->crtc) { output = to_nv50_output(drm_encoder); rval = output->execute_mode(output, true); @@ -556,12 +575,6 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (switch_fb && !modeset && !blank) { crtc = to_nv50_crtc(set->crtc); - rval = crtc->blank(crtc, true); - if (rval != 0) { - DRM_ERROR("blanking failed\n"); - goto out; - } - rval = crtc->set_fb(crtc); if (rval != 0) { DRM_ERROR("set_fb failed\n"); @@ -657,7 +670,9 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) /* next line changes crtc, so putting it here is important */ display->last_crtc = crtc->index; + } + if (switch_fb || modeset) { /* this is executed immediately */ list_for_each_entry(output, &display->outputs, item) { if (output->crtc != crtc) @@ -690,6 +705,13 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) display->update(display); + /* Update the current mode, now that all has gone well. */ + if (modeset) { + set->crtc->mode = *(set->mode); + set->crtc->x = set->x; + set->crtc->y = set->y; + } + kfree(hw_mode); return 0; @@ -826,7 +848,7 @@ bool nv50_kms_connector_is_digital(struct drm_connector *drm_connector) uint64_t prop_val; rval = drm_connector_property_get_value(drm_connector, dev->mode_config.dvi_i_select_subconnector_property, &prop_val); - if (!rval) { + if (rval) { DRM_ERROR("Unable to find select subconnector property, defaulting to DVI-D\n"); return true; } @@ -842,7 +864,7 @@ bool nv50_kms_connector_is_digital(struct drm_connector *drm_connector) } rval = drm_connector_property_get_value(drm_connector, dev->mode_config.dvi_i_subconnector_property, &prop_val); - if (!rval) { + if (rval) { DRM_ERROR("Unable to find subconnector property, defaulting to DVI-D\n"); return true; } |