diff options
Diffstat (limited to 'drivers/gpu/drm/drm_crtc_helper.c')
-rw-r--r-- | drivers/gpu/drm/drm_crtc_helper.c | 40 |
1 files changed, 38 insertions, 2 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 2957636161e..d2619d72cec 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c | |||
@@ -456,6 +456,30 @@ done: | |||
456 | EXPORT_SYMBOL(drm_crtc_helper_set_mode); | 456 | EXPORT_SYMBOL(drm_crtc_helper_set_mode); |
457 | 457 | ||
458 | 458 | ||
459 | static int | ||
460 | drm_crtc_helper_disable(struct drm_crtc *crtc) | ||
461 | { | ||
462 | struct drm_device *dev = crtc->dev; | ||
463 | struct drm_connector *connector; | ||
464 | struct drm_encoder *encoder; | ||
465 | |||
466 | /* Decouple all encoders and their attached connectors from this crtc */ | ||
467 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
468 | if (encoder->crtc != crtc) | ||
469 | continue; | ||
470 | |||
471 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
472 | if (connector->encoder != encoder) | ||
473 | continue; | ||
474 | |||
475 | connector->encoder = NULL; | ||
476 | } | ||
477 | } | ||
478 | |||
479 | drm_helper_disable_unused_functions(dev); | ||
480 | return 0; | ||
481 | } | ||
482 | |||
459 | /** | 483 | /** |
460 | * drm_crtc_helper_set_config - set a new config from userspace | 484 | * drm_crtc_helper_set_config - set a new config from userspace |
461 | * @crtc: CRTC to setup | 485 | * @crtc: CRTC to setup |
@@ -484,6 +508,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) | |||
484 | struct drm_connector *save_connectors, *connector; | 508 | struct drm_connector *save_connectors, *connector; |
485 | int count = 0, ro, fail = 0; | 509 | int count = 0, ro, fail = 0; |
486 | struct drm_crtc_helper_funcs *crtc_funcs; | 510 | struct drm_crtc_helper_funcs *crtc_funcs; |
511 | struct drm_mode_set save_set; | ||
487 | int ret = 0; | 512 | int ret = 0; |
488 | int i; | 513 | int i; |
489 | 514 | ||
@@ -509,8 +534,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) | |||
509 | (int)set->num_connectors, set->x, set->y); | 534 | (int)set->num_connectors, set->x, set->y); |
510 | } else { | 535 | } else { |
511 | DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id); | 536 | DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id); |
512 | set->mode = NULL; | 537 | return drm_crtc_helper_disable(set->crtc); |
513 | set->num_connectors = 0; | ||
514 | } | 538 | } |
515 | 539 | ||
516 | dev = set->crtc->dev; | 540 | dev = set->crtc->dev; |
@@ -556,6 +580,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) | |||
556 | save_connectors[count++] = *connector; | 580 | save_connectors[count++] = *connector; |
557 | } | 581 | } |
558 | 582 | ||
583 | save_set.crtc = set->crtc; | ||
584 | save_set.mode = &set->crtc->mode; | ||
585 | save_set.x = set->crtc->x; | ||
586 | save_set.y = set->crtc->y; | ||
587 | save_set.fb = set->crtc->fb; | ||
588 | |||
559 | /* We should be able to check here if the fb has the same properties | 589 | /* We should be able to check here if the fb has the same properties |
560 | * and then just flip_or_move it */ | 590 | * and then just flip_or_move it */ |
561 | if (set->crtc->fb != set->fb) { | 591 | if (set->crtc->fb != set->fb) { |
@@ -721,6 +751,12 @@ fail: | |||
721 | *connector = save_connectors[count++]; | 751 | *connector = save_connectors[count++]; |
722 | } | 752 | } |
723 | 753 | ||
754 | /* Try to restore the config */ | ||
755 | if (mode_changed && | ||
756 | !drm_crtc_helper_set_mode(save_set.crtc, save_set.mode, save_set.x, | ||
757 | save_set.y, save_set.fb)) | ||
758 | DRM_ERROR("failed to restore config after modeset failure\n"); | ||
759 | |||
724 | kfree(save_connectors); | 760 | kfree(save_connectors); |
725 | kfree(save_encoders); | 761 | kfree(save_encoders); |
726 | kfree(save_crtcs); | 762 | kfree(save_crtcs); |