diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_fbdev.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_fbdev.c | 33 |
1 files changed, 32 insertions, 1 deletions
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index fb5bb5b32a60..7f365ac0b549 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c | |||
@@ -679,6 +679,7 @@ int intel_fbdev_init(struct drm_device *dev) | |||
679 | if (ifbdev == NULL) | 679 | if (ifbdev == NULL) |
680 | return -ENOMEM; | 680 | return -ENOMEM; |
681 | 681 | ||
682 | mutex_init(&ifbdev->hpd_lock); | ||
682 | drm_fb_helper_prepare(dev, &ifbdev->helper, &intel_fb_helper_funcs); | 683 | drm_fb_helper_prepare(dev, &ifbdev->helper, &intel_fb_helper_funcs); |
683 | 684 | ||
684 | if (!intel_fbdev_init_bios(dev, ifbdev)) | 685 | if (!intel_fbdev_init_bios(dev, ifbdev)) |
@@ -752,6 +753,26 @@ void intel_fbdev_fini(struct drm_i915_private *dev_priv) | |||
752 | intel_fbdev_destroy(ifbdev); | 753 | intel_fbdev_destroy(ifbdev); |
753 | } | 754 | } |
754 | 755 | ||
756 | /* Suspends/resumes fbdev processing of incoming HPD events. When resuming HPD | ||
757 | * processing, fbdev will perform a full connector reprobe if a hotplug event | ||
758 | * was received while HPD was suspended. | ||
759 | */ | ||
760 | static void intel_fbdev_hpd_set_suspend(struct intel_fbdev *ifbdev, int state) | ||
761 | { | ||
762 | bool send_hpd = false; | ||
763 | |||
764 | mutex_lock(&ifbdev->hpd_lock); | ||
765 | ifbdev->hpd_suspended = state == FBINFO_STATE_SUSPENDED; | ||
766 | send_hpd = !ifbdev->hpd_suspended && ifbdev->hpd_waiting; | ||
767 | ifbdev->hpd_waiting = false; | ||
768 | mutex_unlock(&ifbdev->hpd_lock); | ||
769 | |||
770 | if (send_hpd) { | ||
771 | DRM_DEBUG_KMS("Handling delayed fbcon HPD event\n"); | ||
772 | drm_fb_helper_hotplug_event(&ifbdev->helper); | ||
773 | } | ||
774 | } | ||
775 | |||
755 | void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous) | 776 | void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous) |
756 | { | 777 | { |
757 | struct drm_i915_private *dev_priv = to_i915(dev); | 778 | struct drm_i915_private *dev_priv = to_i915(dev); |
@@ -773,6 +794,7 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous | |||
773 | */ | 794 | */ |
774 | if (state != FBINFO_STATE_RUNNING) | 795 | if (state != FBINFO_STATE_RUNNING) |
775 | flush_work(&dev_priv->fbdev_suspend_work); | 796 | flush_work(&dev_priv->fbdev_suspend_work); |
797 | |||
776 | console_lock(); | 798 | console_lock(); |
777 | } else { | 799 | } else { |
778 | /* | 800 | /* |
@@ -800,17 +822,26 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous | |||
800 | 822 | ||
801 | drm_fb_helper_set_suspend(&ifbdev->helper, state); | 823 | drm_fb_helper_set_suspend(&ifbdev->helper, state); |
802 | console_unlock(); | 824 | console_unlock(); |
825 | |||
826 | intel_fbdev_hpd_set_suspend(ifbdev, state); | ||
803 | } | 827 | } |
804 | 828 | ||
805 | void intel_fbdev_output_poll_changed(struct drm_device *dev) | 829 | void intel_fbdev_output_poll_changed(struct drm_device *dev) |
806 | { | 830 | { |
807 | struct intel_fbdev *ifbdev = to_i915(dev)->fbdev; | 831 | struct intel_fbdev *ifbdev = to_i915(dev)->fbdev; |
832 | bool send_hpd; | ||
808 | 833 | ||
809 | if (!ifbdev) | 834 | if (!ifbdev) |
810 | return; | 835 | return; |
811 | 836 | ||
812 | intel_fbdev_sync(ifbdev); | 837 | intel_fbdev_sync(ifbdev); |
813 | if (ifbdev->vma || ifbdev->helper.deferred_setup) | 838 | |
839 | mutex_lock(&ifbdev->hpd_lock); | ||
840 | send_hpd = !ifbdev->hpd_suspended; | ||
841 | ifbdev->hpd_waiting = true; | ||
842 | mutex_unlock(&ifbdev->hpd_lock); | ||
843 | |||
844 | if (send_hpd && (ifbdev->vma || ifbdev->helper.deferred_setup)) | ||
814 | drm_fb_helper_hotplug_event(&ifbdev->helper); | 845 | drm_fb_helper_hotplug_event(&ifbdev->helper); |
815 | } | 846 | } |
816 | 847 | ||