aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c51
-rw-r--r--include/drm/drm_crtc.h1
2 files changed, 43 insertions, 9 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 760a67534c6c..9adbd2b311d0 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -960,9 +960,9 @@ static void output_poll_execute(struct work_struct *work)
960 mutex_lock(&dev->mode_config.mutex); 960 mutex_lock(&dev->mode_config.mutex);
961 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 961 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
962 962
963 /* if this is HPD or polled don't check it - 963 /* Ignore HPD capable connectors and connectors where we don't
964 TV out for instance */ 964 * want any hotplug detection at all for polling. */
965 if (!connector->polled) 965 if (!connector->polled || connector->polled == DRM_CONNECTOR_POLL_HPD)
966 continue; 966 continue;
967 967
968 else if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT)) 968 else if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT))
@@ -972,8 +972,7 @@ static void output_poll_execute(struct work_struct *work)
972 /* if we are connected and don't want to poll for disconnect 972 /* if we are connected and don't want to poll for disconnect
973 skip it */ 973 skip it */
974 if (old_status == connector_status_connected && 974 if (old_status == connector_status_connected &&
975 !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT) && 975 !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT))
976 !(connector->polled & DRM_CONNECTOR_POLL_HPD))
977 continue; 976 continue;
978 977
979 connector->status = connector->funcs->detect(connector, false); 978 connector->status = connector->funcs->detect(connector, false);
@@ -1020,9 +1019,12 @@ void drm_kms_helper_poll_enable(struct drm_device *dev)
1020} 1019}
1021EXPORT_SYMBOL(drm_kms_helper_poll_enable); 1020EXPORT_SYMBOL(drm_kms_helper_poll_enable);
1022 1021
1022static void hpd_irq_event_execute(struct work_struct *work);
1023
1023void drm_kms_helper_poll_init(struct drm_device *dev) 1024void drm_kms_helper_poll_init(struct drm_device *dev)
1024{ 1025{
1025 INIT_DELAYED_WORK(&dev->mode_config.output_poll_work, output_poll_execute); 1026 INIT_DELAYED_WORK(&dev->mode_config.output_poll_work, output_poll_execute);
1027 INIT_DELAYED_WORK(&dev->mode_config.hpd_irq_work, hpd_irq_event_execute);
1026 dev->mode_config.poll_enabled = true; 1028 dev->mode_config.poll_enabled = true;
1027 1029
1028 drm_kms_helper_poll_enable(dev); 1030 drm_kms_helper_poll_enable(dev);
@@ -1035,14 +1037,45 @@ void drm_kms_helper_poll_fini(struct drm_device *dev)
1035} 1037}
1036EXPORT_SYMBOL(drm_kms_helper_poll_fini); 1038EXPORT_SYMBOL(drm_kms_helper_poll_fini);
1037 1039
1038void drm_helper_hpd_irq_event(struct drm_device *dev) 1040static void hpd_irq_event_execute(struct work_struct *work)
1039{ 1041{
1042 struct delayed_work *delayed_work = to_delayed_work(work);
1043 struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.hpd_irq_work);
1044 struct drm_connector *connector;
1045 enum drm_connector_status old_status;
1046 bool changed = false;
1047
1040 if (!dev->mode_config.poll_enabled) 1048 if (!dev->mode_config.poll_enabled)
1041 return; 1049 return;
1042 1050
1043 /* kill timer and schedule immediate execution, this doesn't block */ 1051 mutex_lock(&dev->mode_config.mutex);
1044 cancel_delayed_work(&dev->mode_config.output_poll_work); 1052 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1053
1054 /* Only handle HPD capable connectors. */
1055 if (!(connector->polled & DRM_CONNECTOR_POLL_HPD))
1056 continue;
1057
1058 old_status = connector->status;
1059
1060 connector->status = connector->funcs->detect(connector, false);
1061 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
1062 connector->base.id,
1063 drm_get_connector_name(connector),
1064 old_status, connector->status);
1065 if (old_status != connector->status)
1066 changed = true;
1067 }
1068
1069 mutex_unlock(&dev->mode_config.mutex);
1070
1071 if (changed)
1072 drm_kms_helper_hotplug_event(dev);
1073}
1074
1075void drm_helper_hpd_irq_event(struct drm_device *dev)
1076{
1077 cancel_delayed_work(&dev->mode_config.hpd_irq_work);
1045 if (drm_kms_helper_poll) 1078 if (drm_kms_helper_poll)
1046 schedule_delayed_work(&dev->mode_config.output_poll_work, 0); 1079 schedule_delayed_work(&dev->mode_config.hpd_irq_work, 0);
1047} 1080}
1048EXPORT_SYMBOL(drm_helper_hpd_irq_event); 1081EXPORT_SYMBOL(drm_helper_hpd_irq_event);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 1f5f1d642a98..ccff8c9b3780 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -793,6 +793,7 @@ struct drm_mode_config {
793 /* output poll support */ 793 /* output poll support */
794 bool poll_enabled; 794 bool poll_enabled;
795 struct delayed_work output_poll_work; 795 struct delayed_work output_poll_work;
796 struct delayed_work hpd_irq_work;
796 797
797 /* pointers to standard properties */ 798 /* pointers to standard properties */
798 struct list_head property_blob_list; 799 struct list_head property_blob_list;