aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_crtc_helper.c
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2012-10-23 14:23:33 -0400
committerDave Airlie <airlied@redhat.com>2012-11-20 00:50:42 -0500
commit816da85a0990c2b52cfffa77637d1c770d6790e9 (patch)
tree3e3bd2c22624db838a8456c167058b4e56b177fc /drivers/gpu/drm/drm_crtc_helper.c
parent3d3683f04a32da16df71e3b089da8f5a13059ef4 (diff)
drm: handle HPD and polled connectors separately
Instead of reusing the polling code for hpd handling, split them up. This has a few consequences: - Don't touch HPD capable connectors in the poll loop. - Only touch HPD capable connectors in drm_helper_hpd_irq_event. - We could run the HPD handling directly (because all callers already use their own work item), but for easier bisect that happens in it's own patch. The ultimate goal is that drivers grow some smarts about which connectors have received a hotplug event and only call the detect code of that connector. But that's a second step. v2: s/hdp/hpd/, noticed by Adam Jackson. I can't type. v3: Split out the work item removal as requested by Dave Airlie. This results in a temporary mode_config.hpd_irq_work item to keep things the same. v4: In the hpd_irq_event handler don't bail out if other bits than HPD are set. This is useful where e.g. hpd is unreliably, but mostly works. Drivers can then set both HPD and POLL flags, and users get the best of both worlds: Quick hotplug feedback if the hpd works, but still reliable detection with the polling. The poll loop already works the same, and doesn't bail if HPD is set. Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/drm_crtc_helper.c')
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c51
1 files changed, 42 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);