diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2014-04-10 04:51:11 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2014-04-17 23:21:17 -0400 |
commit | 8d754544202c0e4ef02e9c1abdf379bcf7ef9384 (patch) | |
tree | 9642efef9e6e223ebd8d6754fdfa2f5d30ce7b4f /drivers/gpu/drm/drm_crtc_helper.c | |
parent | b6ccd7b9873dc46becd11838c885d5c783784156 (diff) |
drm: Split out drm_probe_helper.c from drm_crtc_helper.c
This is leftover stuff from my previous doc round which I kinda wanted
to do but didn't yet due to rebase hell.
The modeset helpers and the probing helpers a independent and e.g.
i915 uses the probing stuff but has its own modeset infrastructure. It
hence makes to split this up. While at it add a DOC: comment for the
probing libraray.
It would be rather neat to pull some of the DocBook documenting these
two helpers into in-line DOC: comments. But unfortunately kerneldoc
doesn't support markdown or something similar to make nice-looking
documentation, so the current state is better.
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
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.c | 370 |
1 files changed, 0 insertions, 370 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index c43825e8f5c1..df281b54db01 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c | |||
@@ -72,147 +72,6 @@ void drm_helper_move_panel_connectors_to_head(struct drm_device *dev) | |||
72 | } | 72 | } |
73 | EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head); | 73 | EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head); |
74 | 74 | ||
75 | static bool drm_kms_helper_poll = true; | ||
76 | module_param_named(poll, drm_kms_helper_poll, bool, 0600); | ||
77 | |||
78 | static void drm_mode_validate_flag(struct drm_connector *connector, | ||
79 | int flags) | ||
80 | { | ||
81 | struct drm_display_mode *mode; | ||
82 | |||
83 | if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE | | ||
84 | DRM_MODE_FLAG_3D_MASK)) | ||
85 | return; | ||
86 | |||
87 | list_for_each_entry(mode, &connector->modes, head) { | ||
88 | if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && | ||
89 | !(flags & DRM_MODE_FLAG_INTERLACE)) | ||
90 | mode->status = MODE_NO_INTERLACE; | ||
91 | if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) && | ||
92 | !(flags & DRM_MODE_FLAG_DBLSCAN)) | ||
93 | mode->status = MODE_NO_DBLESCAN; | ||
94 | if ((mode->flags & DRM_MODE_FLAG_3D_MASK) && | ||
95 | !(flags & DRM_MODE_FLAG_3D_MASK)) | ||
96 | mode->status = MODE_NO_STEREO; | ||
97 | } | ||
98 | |||
99 | return; | ||
100 | } | ||
101 | |||
102 | /** | ||
103 | * drm_helper_probe_single_connector_modes - get complete set of display modes | ||
104 | * @connector: connector to probe | ||
105 | * @maxX: max width for modes | ||
106 | * @maxY: max height for modes | ||
107 | * | ||
108 | * Based on the helper callbacks implemented by @connector try to detect all | ||
109 | * valid modes. Modes will first be added to the connector's probed_modes list, | ||
110 | * then culled (based on validity and the @maxX, @maxY parameters) and put into | ||
111 | * the normal modes list. | ||
112 | * | ||
113 | * Intended to be use as a generic implementation of the ->fill_modes() | ||
114 | * @connector vfunc for drivers that use the crtc helpers for output mode | ||
115 | * filtering and detection. | ||
116 | * | ||
117 | * Returns: | ||
118 | * The number of modes found on @connector. | ||
119 | */ | ||
120 | int drm_helper_probe_single_connector_modes(struct drm_connector *connector, | ||
121 | uint32_t maxX, uint32_t maxY) | ||
122 | { | ||
123 | struct drm_device *dev = connector->dev; | ||
124 | struct drm_display_mode *mode; | ||
125 | struct drm_connector_helper_funcs *connector_funcs = | ||
126 | connector->helper_private; | ||
127 | int count = 0; | ||
128 | int mode_flags = 0; | ||
129 | bool verbose_prune = true; | ||
130 | |||
131 | WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); | ||
132 | |||
133 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, | ||
134 | drm_get_connector_name(connector)); | ||
135 | /* set all modes to the unverified state */ | ||
136 | list_for_each_entry(mode, &connector->modes, head) | ||
137 | mode->status = MODE_UNVERIFIED; | ||
138 | |||
139 | if (connector->force) { | ||
140 | if (connector->force == DRM_FORCE_ON) | ||
141 | connector->status = connector_status_connected; | ||
142 | else | ||
143 | connector->status = connector_status_disconnected; | ||
144 | if (connector->funcs->force) | ||
145 | connector->funcs->force(connector); | ||
146 | } else { | ||
147 | connector->status = connector->funcs->detect(connector, true); | ||
148 | } | ||
149 | |||
150 | /* Re-enable polling in case the global poll config changed. */ | ||
151 | if (drm_kms_helper_poll != dev->mode_config.poll_running) | ||
152 | drm_kms_helper_poll_enable(dev); | ||
153 | |||
154 | dev->mode_config.poll_running = drm_kms_helper_poll; | ||
155 | |||
156 | if (connector->status == connector_status_disconnected) { | ||
157 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n", | ||
158 | connector->base.id, drm_get_connector_name(connector)); | ||
159 | drm_mode_connector_update_edid_property(connector, NULL); | ||
160 | verbose_prune = false; | ||
161 | goto prune; | ||
162 | } | ||
163 | |||
164 | #ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE | ||
165 | count = drm_load_edid_firmware(connector); | ||
166 | if (count == 0) | ||
167 | #endif | ||
168 | count = (*connector_funcs->get_modes)(connector); | ||
169 | |||
170 | if (count == 0 && connector->status == connector_status_connected) | ||
171 | count = drm_add_modes_noedid(connector, 1024, 768); | ||
172 | if (count == 0) | ||
173 | goto prune; | ||
174 | |||
175 | drm_mode_connector_list_update(connector); | ||
176 | |||
177 | if (maxX && maxY) | ||
178 | drm_mode_validate_size(dev, &connector->modes, maxX, maxY); | ||
179 | |||
180 | if (connector->interlace_allowed) | ||
181 | mode_flags |= DRM_MODE_FLAG_INTERLACE; | ||
182 | if (connector->doublescan_allowed) | ||
183 | mode_flags |= DRM_MODE_FLAG_DBLSCAN; | ||
184 | if (connector->stereo_allowed) | ||
185 | mode_flags |= DRM_MODE_FLAG_3D_MASK; | ||
186 | drm_mode_validate_flag(connector, mode_flags); | ||
187 | |||
188 | list_for_each_entry(mode, &connector->modes, head) { | ||
189 | if (mode->status == MODE_OK) | ||
190 | mode->status = connector_funcs->mode_valid(connector, | ||
191 | mode); | ||
192 | } | ||
193 | |||
194 | prune: | ||
195 | drm_mode_prune_invalid(dev, &connector->modes, verbose_prune); | ||
196 | |||
197 | if (list_empty(&connector->modes)) | ||
198 | return 0; | ||
199 | |||
200 | list_for_each_entry(mode, &connector->modes, head) | ||
201 | mode->vrefresh = drm_mode_vrefresh(mode); | ||
202 | |||
203 | drm_mode_sort(&connector->modes); | ||
204 | |||
205 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id, | ||
206 | drm_get_connector_name(connector)); | ||
207 | list_for_each_entry(mode, &connector->modes, head) { | ||
208 | drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); | ||
209 | drm_mode_debug_printmodeline(mode); | ||
210 | } | ||
211 | |||
212 | return count; | ||
213 | } | ||
214 | EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); | ||
215 | |||
216 | /** | 75 | /** |
217 | * drm_helper_encoder_in_use - check if a given encoder is in use | 76 | * drm_helper_encoder_in_use - check if a given encoder is in use |
218 | * @encoder: encoder to check | 77 | * @encoder: encoder to check |
@@ -1020,232 +879,3 @@ void drm_helper_resume_force_mode(struct drm_device *dev) | |||
1020 | drm_modeset_unlock_all(dev); | 879 | drm_modeset_unlock_all(dev); |
1021 | } | 880 | } |
1022 | EXPORT_SYMBOL(drm_helper_resume_force_mode); | 881 | EXPORT_SYMBOL(drm_helper_resume_force_mode); |
1023 | |||
1024 | /** | ||
1025 | * drm_kms_helper_hotplug_event - fire off KMS hotplug events | ||
1026 | * @dev: drm_device whose connector state changed | ||
1027 | * | ||
1028 | * This function fires off the uevent for userspace and also calls the | ||
1029 | * output_poll_changed function, which is most commonly used to inform the fbdev | ||
1030 | * emulation code and allow it to update the fbcon output configuration. | ||
1031 | * | ||
1032 | * Drivers should call this from their hotplug handling code when a change is | ||
1033 | * detected. Note that this function does not do any output detection of its | ||
1034 | * own, like drm_helper_hpd_irq_event() does - this is assumed to be done by the | ||
1035 | * driver already. | ||
1036 | * | ||
1037 | * This function must be called from process context with no mode | ||
1038 | * setting locks held. | ||
1039 | */ | ||
1040 | void drm_kms_helper_hotplug_event(struct drm_device *dev) | ||
1041 | { | ||
1042 | /* send a uevent + call fbdev */ | ||
1043 | drm_sysfs_hotplug_event(dev); | ||
1044 | if (dev->mode_config.funcs->output_poll_changed) | ||
1045 | dev->mode_config.funcs->output_poll_changed(dev); | ||
1046 | } | ||
1047 | EXPORT_SYMBOL(drm_kms_helper_hotplug_event); | ||
1048 | |||
1049 | #define DRM_OUTPUT_POLL_PERIOD (10*HZ) | ||
1050 | static void output_poll_execute(struct work_struct *work) | ||
1051 | { | ||
1052 | struct delayed_work *delayed_work = to_delayed_work(work); | ||
1053 | struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work); | ||
1054 | struct drm_connector *connector; | ||
1055 | enum drm_connector_status old_status; | ||
1056 | bool repoll = false, changed = false; | ||
1057 | |||
1058 | if (!drm_kms_helper_poll) | ||
1059 | return; | ||
1060 | |||
1061 | mutex_lock(&dev->mode_config.mutex); | ||
1062 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
1063 | |||
1064 | /* Ignore forced connectors. */ | ||
1065 | if (connector->force) | ||
1066 | continue; | ||
1067 | |||
1068 | /* Ignore HPD capable connectors and connectors where we don't | ||
1069 | * want any hotplug detection at all for polling. */ | ||
1070 | if (!connector->polled || connector->polled == DRM_CONNECTOR_POLL_HPD) | ||
1071 | continue; | ||
1072 | |||
1073 | repoll = true; | ||
1074 | |||
1075 | old_status = connector->status; | ||
1076 | /* if we are connected and don't want to poll for disconnect | ||
1077 | skip it */ | ||
1078 | if (old_status == connector_status_connected && | ||
1079 | !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT)) | ||
1080 | continue; | ||
1081 | |||
1082 | connector->status = connector->funcs->detect(connector, false); | ||
1083 | if (old_status != connector->status) { | ||
1084 | const char *old, *new; | ||
1085 | |||
1086 | old = drm_get_connector_status_name(old_status); | ||
1087 | new = drm_get_connector_status_name(connector->status); | ||
1088 | |||
1089 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] " | ||
1090 | "status updated from %s to %s\n", | ||
1091 | connector->base.id, | ||
1092 | drm_get_connector_name(connector), | ||
1093 | old, new); | ||
1094 | |||
1095 | changed = true; | ||
1096 | } | ||
1097 | } | ||
1098 | |||
1099 | mutex_unlock(&dev->mode_config.mutex); | ||
1100 | |||
1101 | if (changed) | ||
1102 | drm_kms_helper_hotplug_event(dev); | ||
1103 | |||
1104 | if (repoll) | ||
1105 | schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD); | ||
1106 | } | ||
1107 | |||
1108 | /** | ||
1109 | * drm_kms_helper_poll_disable - disable output polling | ||
1110 | * @dev: drm_device | ||
1111 | * | ||
1112 | * This function disables the output polling work. | ||
1113 | * | ||
1114 | * Drivers can call this helper from their device suspend implementation. It is | ||
1115 | * not an error to call this even when output polling isn't enabled or arlready | ||
1116 | * disabled. | ||
1117 | */ | ||
1118 | void drm_kms_helper_poll_disable(struct drm_device *dev) | ||
1119 | { | ||
1120 | if (!dev->mode_config.poll_enabled) | ||
1121 | return; | ||
1122 | cancel_delayed_work_sync(&dev->mode_config.output_poll_work); | ||
1123 | } | ||
1124 | EXPORT_SYMBOL(drm_kms_helper_poll_disable); | ||
1125 | |||
1126 | /** | ||
1127 | * drm_kms_helper_poll_enable - re-enable output polling. | ||
1128 | * @dev: drm_device | ||
1129 | * | ||
1130 | * This function re-enables the output polling work. | ||
1131 | * | ||
1132 | * Drivers can call this helper from their device resume implementation. It is | ||
1133 | * an error to call this when the output polling support has not yet been set | ||
1134 | * up. | ||
1135 | */ | ||
1136 | void drm_kms_helper_poll_enable(struct drm_device *dev) | ||
1137 | { | ||
1138 | bool poll = false; | ||
1139 | struct drm_connector *connector; | ||
1140 | |||
1141 | if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll) | ||
1142 | return; | ||
1143 | |||
1144 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
1145 | if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | | ||
1146 | DRM_CONNECTOR_POLL_DISCONNECT)) | ||
1147 | poll = true; | ||
1148 | } | ||
1149 | |||
1150 | if (poll) | ||
1151 | schedule_delayed_work(&dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); | ||
1152 | } | ||
1153 | EXPORT_SYMBOL(drm_kms_helper_poll_enable); | ||
1154 | |||
1155 | /** | ||
1156 | * drm_kms_helper_poll_init - initialize and enable output polling | ||
1157 | * @dev: drm_device | ||
1158 | * | ||
1159 | * This function intializes and then also enables output polling support for | ||
1160 | * @dev. Drivers which do not have reliable hotplug support in hardware can use | ||
1161 | * this helper infrastructure to regularly poll such connectors for changes in | ||
1162 | * their connection state. | ||
1163 | * | ||
1164 | * Drivers can control which connectors are polled by setting the | ||
1165 | * DRM_CONNECTOR_POLL_CONNECT and DRM_CONNECTOR_POLL_DISCONNECT flags. On | ||
1166 | * connectors where probing live outputs can result in visual distortion drivers | ||
1167 | * should not set the DRM_CONNECTOR_POLL_DISCONNECT flag to avoid this. | ||
1168 | * Connectors which have no flag or only DRM_CONNECTOR_POLL_HPD set are | ||
1169 | * completely ignored by the polling logic. | ||
1170 | * | ||
1171 | * Note that a connector can be both polled and probed from the hotplug handler, | ||
1172 | * in case the hotplug interrupt is known to be unreliable. | ||
1173 | */ | ||
1174 | void drm_kms_helper_poll_init(struct drm_device *dev) | ||
1175 | { | ||
1176 | INIT_DELAYED_WORK(&dev->mode_config.output_poll_work, output_poll_execute); | ||
1177 | dev->mode_config.poll_enabled = true; | ||
1178 | |||
1179 | drm_kms_helper_poll_enable(dev); | ||
1180 | } | ||
1181 | EXPORT_SYMBOL(drm_kms_helper_poll_init); | ||
1182 | |||
1183 | /** | ||
1184 | * drm_kms_helper_poll_fini - disable output polling and clean it up | ||
1185 | * @dev: drm_device | ||
1186 | */ | ||
1187 | void drm_kms_helper_poll_fini(struct drm_device *dev) | ||
1188 | { | ||
1189 | drm_kms_helper_poll_disable(dev); | ||
1190 | } | ||
1191 | EXPORT_SYMBOL(drm_kms_helper_poll_fini); | ||
1192 | |||
1193 | /** | ||
1194 | * drm_helper_hpd_irq_event - hotplug processing | ||
1195 | * @dev: drm_device | ||
1196 | * | ||
1197 | * Drivers can use this helper function to run a detect cycle on all connectors | ||
1198 | * which have the DRM_CONNECTOR_POLL_HPD flag set in their &polled member. All | ||
1199 | * other connectors are ignored, which is useful to avoid reprobing fixed | ||
1200 | * panels. | ||
1201 | * | ||
1202 | * This helper function is useful for drivers which can't or don't track hotplug | ||
1203 | * interrupts for each connector. | ||
1204 | * | ||
1205 | * Drivers which support hotplug interrupts for each connector individually and | ||
1206 | * which have a more fine-grained detect logic should bypass this code and | ||
1207 | * directly call drm_kms_helper_hotplug_event() in case the connector state | ||
1208 | * changed. | ||
1209 | * | ||
1210 | * This function must be called from process context with no mode | ||
1211 | * setting locks held. | ||
1212 | * | ||
1213 | * Note that a connector can be both polled and probed from the hotplug handler, | ||
1214 | * in case the hotplug interrupt is known to be unreliable. | ||
1215 | */ | ||
1216 | bool drm_helper_hpd_irq_event(struct drm_device *dev) | ||
1217 | { | ||
1218 | struct drm_connector *connector; | ||
1219 | enum drm_connector_status old_status; | ||
1220 | bool changed = false; | ||
1221 | |||
1222 | if (!dev->mode_config.poll_enabled) | ||
1223 | return false; | ||
1224 | |||
1225 | mutex_lock(&dev->mode_config.mutex); | ||
1226 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
1227 | |||
1228 | /* Only handle HPD capable connectors. */ | ||
1229 | if (!(connector->polled & DRM_CONNECTOR_POLL_HPD)) | ||
1230 | continue; | ||
1231 | |||
1232 | old_status = connector->status; | ||
1233 | |||
1234 | connector->status = connector->funcs->detect(connector, false); | ||
1235 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", | ||
1236 | connector->base.id, | ||
1237 | drm_get_connector_name(connector), | ||
1238 | drm_get_connector_status_name(old_status), | ||
1239 | drm_get_connector_status_name(connector->status)); | ||
1240 | if (old_status != connector->status) | ||
1241 | changed = true; | ||
1242 | } | ||
1243 | |||
1244 | mutex_unlock(&dev->mode_config.mutex); | ||
1245 | |||
1246 | if (changed) | ||
1247 | drm_kms_helper_hotplug_event(dev); | ||
1248 | |||
1249 | return changed; | ||
1250 | } | ||
1251 | EXPORT_SYMBOL(drm_helper_hpd_irq_event); | ||