aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_crtc_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/drm_crtc_helper.c')
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c95
1 files changed, 95 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index b142ac260d97..764401951041 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -807,3 +807,98 @@ int drm_helper_resume_force_mode(struct drm_device *dev)
807 return 0; 807 return 0;
808} 808}
809EXPORT_SYMBOL(drm_helper_resume_force_mode); 809EXPORT_SYMBOL(drm_helper_resume_force_mode);
810
811static struct slow_work_ops output_poll_ops;
812
813#define DRM_OUTPUT_POLL_PERIOD (10*HZ)
814static void output_poll_execute(struct slow_work *work)
815{
816 struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work);
817 struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_slow_work);
818 struct drm_connector *connector;
819 enum drm_connector_status old_status, status;
820 bool repoll = false, changed = false;
821 int ret;
822
823 mutex_lock(&dev->mode_config.mutex);
824 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
825
826 /* if this is HPD or polled don't check it -
827 TV out for instance */
828 if (!connector->polled)
829 continue;
830
831 else if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT))
832 repoll = true;
833
834 old_status = connector->status;
835 /* if we are connected and don't want to poll for disconnect
836 skip it */
837 if (old_status == connector_status_connected &&
838 !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT) &&
839 !(connector->polled & DRM_CONNECTOR_POLL_HPD))
840 continue;
841
842 status = connector->funcs->detect(connector);
843 if (old_status != status)
844 changed = true;
845 }
846
847 mutex_unlock(&dev->mode_config.mutex);
848
849 if (changed) {
850 /* send a uevent + call fbdev */
851 drm_sysfs_hotplug_event(dev);
852 if (dev->mode_config.funcs->output_poll_changed)
853 dev->mode_config.funcs->output_poll_changed(dev);
854 }
855
856 if (repoll) {
857 ret = delayed_slow_work_enqueue(delayed_work, DRM_OUTPUT_POLL_PERIOD);
858 if (ret)
859 DRM_ERROR("delayed enqueue failed %d\n", ret);
860 }
861}
862
863void drm_kms_helper_poll_init(struct drm_device *dev)
864{
865 struct drm_connector *connector;
866 bool poll = false;
867 int ret;
868
869 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
870 if (connector->polled)
871 poll = true;
872 }
873 slow_work_register_user(THIS_MODULE);
874 delayed_slow_work_init(&dev->mode_config.output_poll_slow_work,
875 &output_poll_ops);
876
877 if (poll) {
878 ret = delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, DRM_OUTPUT_POLL_PERIOD);
879 if (ret)
880 DRM_ERROR("delayed enqueue failed %d\n", ret);
881 }
882}
883EXPORT_SYMBOL(drm_kms_helper_poll_init);
884
885void drm_kms_helper_poll_fini(struct drm_device *dev)
886{
887 delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work);
888 slow_work_unregister_user(THIS_MODULE);
889}
890EXPORT_SYMBOL(drm_kms_helper_poll_fini);
891
892void drm_helper_hpd_irq_event(struct drm_device *dev)
893{
894 if (!dev->mode_config.poll_enabled)
895 return;
896 delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work);
897 /* schedule a slow work asap */
898 delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, 0);
899}
900EXPORT_SYMBOL(drm_helper_hpd_irq_event);
901
902static struct slow_work_ops output_poll_ops = {
903 .execute = output_poll_execute,
904};