diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_fbdev.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_fbdev.c | 45 |
1 files changed, 39 insertions, 6 deletions
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index fb5bb5b32a60..4ee16b264dbe 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c | |||
@@ -336,8 +336,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | |||
336 | bool *enabled, int width, int height) | 336 | bool *enabled, int width, int height) |
337 | { | 337 | { |
338 | struct drm_i915_private *dev_priv = to_i915(fb_helper->dev); | 338 | struct drm_i915_private *dev_priv = to_i915(fb_helper->dev); |
339 | unsigned long conn_configured, conn_seq, mask; | ||
340 | unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG); | 339 | unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG); |
340 | unsigned long conn_configured, conn_seq; | ||
341 | int i, j; | 341 | int i, j; |
342 | bool *save_enabled; | 342 | bool *save_enabled; |
343 | bool fallback = true, ret = true; | 343 | bool fallback = true, ret = true; |
@@ -355,10 +355,9 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | |||
355 | drm_modeset_backoff(&ctx); | 355 | drm_modeset_backoff(&ctx); |
356 | 356 | ||
357 | memcpy(save_enabled, enabled, count); | 357 | memcpy(save_enabled, enabled, count); |
358 | mask = GENMASK(count - 1, 0); | 358 | conn_seq = GENMASK(count - 1, 0); |
359 | conn_configured = 0; | 359 | conn_configured = 0; |
360 | retry: | 360 | retry: |
361 | conn_seq = conn_configured; | ||
362 | for (i = 0; i < count; i++) { | 361 | for (i = 0; i < count; i++) { |
363 | struct drm_fb_helper_connector *fb_conn; | 362 | struct drm_fb_helper_connector *fb_conn; |
364 | struct drm_connector *connector; | 363 | struct drm_connector *connector; |
@@ -371,7 +370,8 @@ retry: | |||
371 | if (conn_configured & BIT(i)) | 370 | if (conn_configured & BIT(i)) |
372 | continue; | 371 | continue; |
373 | 372 | ||
374 | if (conn_seq == 0 && !connector->has_tile) | 373 | /* First pass, only consider tiled connectors */ |
374 | if (conn_seq == GENMASK(count - 1, 0) && !connector->has_tile) | ||
375 | continue; | 375 | continue; |
376 | 376 | ||
377 | if (connector->status == connector_status_connected) | 377 | if (connector->status == connector_status_connected) |
@@ -475,8 +475,10 @@ retry: | |||
475 | conn_configured |= BIT(i); | 475 | conn_configured |= BIT(i); |
476 | } | 476 | } |
477 | 477 | ||
478 | if ((conn_configured & mask) != mask && conn_configured != conn_seq) | 478 | if (conn_configured != conn_seq) { /* repeat until no more are found */ |
479 | conn_seq = conn_configured; | ||
479 | goto retry; | 480 | goto retry; |
481 | } | ||
480 | 482 | ||
481 | /* | 483 | /* |
482 | * If the BIOS didn't enable everything it could, fall back to have the | 484 | * If the BIOS didn't enable everything it could, fall back to have the |
@@ -679,6 +681,7 @@ int intel_fbdev_init(struct drm_device *dev) | |||
679 | if (ifbdev == NULL) | 681 | if (ifbdev == NULL) |
680 | return -ENOMEM; | 682 | return -ENOMEM; |
681 | 683 | ||
684 | mutex_init(&ifbdev->hpd_lock); | ||
682 | drm_fb_helper_prepare(dev, &ifbdev->helper, &intel_fb_helper_funcs); | 685 | drm_fb_helper_prepare(dev, &ifbdev->helper, &intel_fb_helper_funcs); |
683 | 686 | ||
684 | if (!intel_fbdev_init_bios(dev, ifbdev)) | 687 | if (!intel_fbdev_init_bios(dev, ifbdev)) |
@@ -752,6 +755,26 @@ void intel_fbdev_fini(struct drm_i915_private *dev_priv) | |||
752 | intel_fbdev_destroy(ifbdev); | 755 | intel_fbdev_destroy(ifbdev); |
753 | } | 756 | } |
754 | 757 | ||
758 | /* Suspends/resumes fbdev processing of incoming HPD events. When resuming HPD | ||
759 | * processing, fbdev will perform a full connector reprobe if a hotplug event | ||
760 | * was received while HPD was suspended. | ||
761 | */ | ||
762 | static void intel_fbdev_hpd_set_suspend(struct intel_fbdev *ifbdev, int state) | ||
763 | { | ||
764 | bool send_hpd = false; | ||
765 | |||
766 | mutex_lock(&ifbdev->hpd_lock); | ||
767 | ifbdev->hpd_suspended = state == FBINFO_STATE_SUSPENDED; | ||
768 | send_hpd = !ifbdev->hpd_suspended && ifbdev->hpd_waiting; | ||
769 | ifbdev->hpd_waiting = false; | ||
770 | mutex_unlock(&ifbdev->hpd_lock); | ||
771 | |||
772 | if (send_hpd) { | ||
773 | DRM_DEBUG_KMS("Handling delayed fbcon HPD event\n"); | ||
774 | drm_fb_helper_hotplug_event(&ifbdev->helper); | ||
775 | } | ||
776 | } | ||
777 | |||
755 | void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous) | 778 | void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous) |
756 | { | 779 | { |
757 | struct drm_i915_private *dev_priv = to_i915(dev); | 780 | struct drm_i915_private *dev_priv = to_i915(dev); |
@@ -773,6 +796,7 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous | |||
773 | */ | 796 | */ |
774 | if (state != FBINFO_STATE_RUNNING) | 797 | if (state != FBINFO_STATE_RUNNING) |
775 | flush_work(&dev_priv->fbdev_suspend_work); | 798 | flush_work(&dev_priv->fbdev_suspend_work); |
799 | |||
776 | console_lock(); | 800 | console_lock(); |
777 | } else { | 801 | } else { |
778 | /* | 802 | /* |
@@ -800,17 +824,26 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous | |||
800 | 824 | ||
801 | drm_fb_helper_set_suspend(&ifbdev->helper, state); | 825 | drm_fb_helper_set_suspend(&ifbdev->helper, state); |
802 | console_unlock(); | 826 | console_unlock(); |
827 | |||
828 | intel_fbdev_hpd_set_suspend(ifbdev, state); | ||
803 | } | 829 | } |
804 | 830 | ||
805 | void intel_fbdev_output_poll_changed(struct drm_device *dev) | 831 | void intel_fbdev_output_poll_changed(struct drm_device *dev) |
806 | { | 832 | { |
807 | struct intel_fbdev *ifbdev = to_i915(dev)->fbdev; | 833 | struct intel_fbdev *ifbdev = to_i915(dev)->fbdev; |
834 | bool send_hpd; | ||
808 | 835 | ||
809 | if (!ifbdev) | 836 | if (!ifbdev) |
810 | return; | 837 | return; |
811 | 838 | ||
812 | intel_fbdev_sync(ifbdev); | 839 | intel_fbdev_sync(ifbdev); |
813 | if (ifbdev->vma || ifbdev->helper.deferred_setup) | 840 | |
841 | mutex_lock(&ifbdev->hpd_lock); | ||
842 | send_hpd = !ifbdev->hpd_suspended; | ||
843 | ifbdev->hpd_waiting = true; | ||
844 | mutex_unlock(&ifbdev->hpd_lock); | ||
845 | |||
846 | if (send_hpd && (ifbdev->vma || ifbdev->helper.deferred_setup)) | ||
814 | drm_fb_helper_hotplug_event(&ifbdev->helper); | 847 | drm_fb_helper_hotplug_event(&ifbdev->helper); |
815 | } | 848 | } |
816 | 849 | ||