diff options
-rw-r--r-- | drivers/gpu/drm/drm_crtc_helper.c | 51 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 1 |
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 | } |
1021 | EXPORT_SYMBOL(drm_kms_helper_poll_enable); | 1020 | EXPORT_SYMBOL(drm_kms_helper_poll_enable); |
1022 | 1021 | ||
1022 | static void hpd_irq_event_execute(struct work_struct *work); | ||
1023 | |||
1023 | void drm_kms_helper_poll_init(struct drm_device *dev) | 1024 | void 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 | } |
1036 | EXPORT_SYMBOL(drm_kms_helper_poll_fini); | 1038 | EXPORT_SYMBOL(drm_kms_helper_poll_fini); |
1037 | 1039 | ||
1038 | void drm_helper_hpd_irq_event(struct drm_device *dev) | 1040 | static 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 | |||
1075 | void 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 | } |
1048 | EXPORT_SYMBOL(drm_helper_hpd_irq_event); | 1081 | EXPORT_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; |