Rev 6935 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 6935 | Rev 6937 | ||
---|---|---|---|
Line 51... | Line 51... | ||
51 | * track of a per-connector hpd interrupt. |
51 | * track of a per-connector hpd interrupt. |
52 | * |
52 | * |
53 | * This helper library can be used independently of the modeset helper library. |
53 | * This helper library can be used independently of the modeset helper library. |
54 | * Drivers can also overwrite different parts e.g. use their own hotplug |
54 | * Drivers can also overwrite different parts e.g. use their own hotplug |
55 | * handling code to avoid probing unrelated outputs. |
55 | * handling code to avoid probing unrelated outputs. |
- | 56 | * |
|
- | 57 | * The probe helpers share the function table structures with other display |
|
- | 58 | * helper libraries. See struct &drm_connector_helper_funcs for the details. |
|
56 | */ |
59 | */ |
Line 57... | Line 60... | ||
57 | 60 | ||
58 | static bool drm_kms_helper_poll = true; |
61 | static bool drm_kms_helper_poll = true; |
Line 124... | Line 127... | ||
124 | if (poll) |
127 | if (poll) |
125 | schedule_delayed_work(&dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); |
128 | schedule_delayed_work(&dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); |
126 | } |
129 | } |
127 | EXPORT_SYMBOL(drm_kms_helper_poll_enable_locked); |
130 | EXPORT_SYMBOL(drm_kms_helper_poll_enable_locked); |
Line -... | Line 131... | ||
- | 131 | ||
- | 132 | /** |
|
- | 133 | * drm_helper_probe_single_connector_modes - get complete set of display modes |
|
- | 134 | * @connector: connector to probe |
|
- | 135 | * @maxX: max width for modes |
|
- | 136 | * @maxY: max height for modes |
|
- | 137 | * |
|
- | 138 | * Based on the helper callbacks implemented by @connector in struct |
|
- | 139 | * &drm_connector_helper_funcs try to detect all valid modes. Modes will first |
|
- | 140 | * be added to the connector's probed_modes list, then culled (based on validity |
|
- | 141 | * and the @maxX, @maxY parameters) and put into the normal modes list. |
|
- | 142 | * |
|
- | 143 | * Intended to be used as a generic implementation of the ->fill_modes() |
|
- | 144 | * @connector vfunc for drivers that use the CRTC helpers for output mode |
|
- | 145 | * filtering and detection. |
|
- | 146 | * |
|
- | 147 | * The basic procedure is as follows |
|
- | 148 | * |
|
- | 149 | * 1. All modes currently on the connector's modes list are marked as stale |
|
- | 150 | * |
|
- | 151 | * 2. New modes are added to the connector's probed_modes list with |
|
- | 152 | * drm_mode_probed_add(). New modes start their life with status as OK. |
|
- | 153 | * Modes are added from a single source using the following priority order. |
|
- | 154 | * |
|
- | 155 | * - debugfs 'override_edid' (used for testing only) |
|
- | 156 | * - firmware EDID (drm_load_edid_firmware()) |
|
- | 157 | * - connector helper ->get_modes() vfunc |
|
- | 158 | * - if the connector status is connector_status_connected, standard |
|
- | 159 | * VESA DMT modes up to 1024x768 are automatically added |
|
- | 160 | * (drm_add_modes_noedid()) |
|
- | 161 | * |
|
- | 162 | * Finally modes specified via the kernel command line (video=...) are |
|
- | 163 | * added in addition to what the earlier probes produced |
|
- | 164 | * (drm_helper_probe_add_cmdline_mode()). These modes are generated |
|
- | 165 | * using the VESA GTF/CVT formulas. |
|
- | 166 | * |
|
- | 167 | * 3. Modes are moved from the probed_modes list to the modes list. Potential |
|
- | 168 | * duplicates are merged together (see drm_mode_connector_list_update()). |
|
- | 169 | * After this step the probed_modes list will be empty again. |
|
- | 170 | * |
|
- | 171 | * 4. Any non-stale mode on the modes list then undergoes validation |
|
- | 172 | * |
|
- | 173 | * - drm_mode_validate_basic() performs basic sanity checks |
|
- | 174 | * - drm_mode_validate_size() filters out modes larger than @maxX and @maxY |
|
- | 175 | * (if specified) |
|
- | 176 | * - drm_mode_validate_flag() checks the modes againt basic connector |
|
- | 177 | * capabilites (interlace_allowed,doublescan_allowed,stereo_allowed) |
|
- | 178 | * - the optional connector ->mode_valid() helper can perform driver and/or |
|
- | 179 | * hardware specific checks |
|
- | 180 | * |
|
- | 181 | * 5. Any mode whose status is not OK is pruned from the connector's modes list, |
|
- | 182 | * accompanied by a debug message indicating the reason for the mode's |
|
128 | 183 | * rejection (see drm_mode_prune_invalid()). |
|
- | 184 | * |
|
- | 185 | * Returns: |
|
- | 186 | * The number of modes found on @connector. |
|
129 | 187 | */ |
|
130 | static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connector *connector, |
188 | int drm_helper_probe_single_connector_modes(struct drm_connector *connector, |
131 | uint32_t maxX, uint32_t maxY, bool merge_type_bits) |
189 | uint32_t maxX, uint32_t maxY) |
132 | { |
190 | { |
133 | struct drm_device *dev = connector->dev; |
191 | struct drm_device *dev = connector->dev; |
134 | struct drm_display_mode *mode; |
192 | struct drm_display_mode *mode; |
135 | const struct drm_connector_helper_funcs *connector_funcs = |
193 | const struct drm_connector_helper_funcs *connector_funcs = |
Line 141... | Line 199... | ||
141 | 199 | ||
Line 142... | Line 200... | ||
142 | WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); |
200 | WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); |
143 | 201 | ||
144 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, |
202 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, |
145 | connector->name); |
203 | connector->name); |
146 | /* set all modes to the unverified state */ |
204 | /* set all old modes to the stale state */ |
- | 205 | list_for_each_entry(mode, &connector->modes, head) |
|
- | 206 | mode->status = MODE_STALE; |
|
Line 147... | Line 207... | ||
147 | list_for_each_entry(mode, &connector->modes, head) |
207 | |
148 | mode->status = MODE_UNVERIFIED; |
208 | old_status = connector->status; |
149 | 209 | ||
150 | if (connector->force) { |
210 | if (connector->force) { |
151 | if (connector->force == DRM_FORCE_ON || |
211 | if (connector->force == DRM_FORCE_ON || |
152 | connector->force == DRM_FORCE_ON_DIGITAL) |
212 | connector->force == DRM_FORCE_ON_DIGITAL) |
153 | connector->status = connector_status_connected; |
213 | connector->status = connector_status_connected; |
154 | else |
214 | else |
155 | connector->status = connector_status_disconnected; |
215 | connector->status = connector_status_disconnected; |
156 | if (connector->funcs->force) |
- | |
157 | connector->funcs->force(connector); |
- | |
158 | } else { |
216 | if (connector->funcs->force) |
- | 217 | connector->funcs->force(connector); |
|
Line 159... | Line 218... | ||
159 | old_status = connector->status; |
218 | } else { |
160 | 219 | connector->status = connector->funcs->detect(connector, true); |
|
161 | connector->status = connector->funcs->detect(connector, true); |
220 | } |
162 | 221 | ||
163 | /* |
222 | /* |
164 | * Normally either the driver's hpd code or the poll loop should |
223 | * Normally either the driver's hpd code or the poll loop should |
165 | * pick up any changes and fire the hotplug event. But if |
224 | * pick up any changes and fire the hotplug event. But if |
166 | * userspace sneaks in a probe, we might miss a change. Hence |
225 | * userspace sneaks in a probe, we might miss a change. Hence |
167 | * check here, and if anything changed start the hotplug code. |
226 | * check here, and if anything changed start the hotplug code. |
168 | */ |
227 | */ |
- | 228 | if (old_status != connector->status) { |
|
169 | if (old_status != connector->status) { |
229 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", |
Line 170... | Line 230... | ||
170 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n", |
230 | connector->base.id, |
171 | connector->base.id, |
231 | connector->name, |
172 | connector->name, |
232 | drm_get_connector_status_name(old_status), |
173 | old_status, connector->status); |
233 | drm_get_connector_status_name(connector->status)); |
Line 181... | Line 241... | ||
181 | dev->mode_config.delayed_event = true; |
241 | dev->mode_config.delayed_event = true; |
182 | if (dev->mode_config.poll_enabled) |
242 | if (dev->mode_config.poll_enabled) |
183 | schedule_delayed_work(&dev->mode_config.output_poll_work, |
243 | schedule_delayed_work(&dev->mode_config.output_poll_work, |
184 | 0); |
244 | 0); |
185 | } |
245 | } |
186 | } |
- | |
Line 187... | Line 246... | ||
187 | 246 | ||
188 | /* Re-enable polling in case the global poll config changed. */ |
247 | /* Re-enable polling in case the global poll config changed. */ |
189 | if (drm_kms_helper_poll != dev->mode_config.poll_running) |
248 | if (drm_kms_helper_poll != dev->mode_config.poll_running) |
Line 197... | Line 256... | ||
197 | drm_mode_connector_update_edid_property(connector, NULL); |
256 | drm_mode_connector_update_edid_property(connector, NULL); |
198 | verbose_prune = false; |
257 | verbose_prune = false; |
199 | goto prune; |
258 | goto prune; |
200 | } |
259 | } |
Line 201... | Line -... | ||
201 | - | ||
202 | #ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE |
- | |
203 | count = drm_load_edid_firmware(connector); |
- | |
204 | if (count == 0) |
- | |
205 | #endif |
- | |
206 | { |
260 | |
207 | if (connector->override_edid) { |
261 | if (connector->override_edid) { |
Line 208... | Line 262... | ||
208 | struct edid *edid = (struct edid *) connector->edid_blob_ptr->data; |
262 | struct edid *edid = (struct edid *) connector->edid_blob_ptr->data; |
209 | 263 | ||
210 | count = drm_add_edid_modes(connector, edid); |
264 | count = drm_add_edid_modes(connector, edid); |
- | 265 | drm_edid_to_eld(connector, edid); |
|
- | 266 | } else { |
|
- | 267 | #ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE |
|
- | 268 | count = drm_load_edid_firmware(connector); |
|
211 | drm_edid_to_eld(connector, edid); |
269 | if (count == 0) |
212 | } else |
270 | #endif |
Line 213... | Line 271... | ||
213 | count = (*connector_funcs->get_modes)(connector); |
271 | count = (*connector_funcs->get_modes)(connector); |
214 | } |
272 | } |
215 | 273 | ||
216 | if (count == 0 && connector->status == connector_status_connected) |
274 | if (count == 0 && connector->status == connector_status_connected) |
217 | count = drm_add_modes_noedid(connector, 1024, 768); |
275 | count = drm_add_modes_noedid(connector, 1024, 768); |
Line 218... | Line 276... | ||
218 | count += drm_helper_probe_add_cmdline_mode(connector); |
276 | count += drm_helper_probe_add_cmdline_mode(connector); |
Line 219... | Line 277... | ||
219 | if (count == 0) |
277 | if (count == 0) |
220 | goto prune; |
278 | goto prune; |
221 | 279 | ||
222 | drm_mode_connector_list_update(connector, merge_type_bits); |
280 | drm_mode_connector_list_update(connector); |
Line 261... | Line 319... | ||
261 | drm_mode_debug_printmodeline(mode); |
319 | drm_mode_debug_printmodeline(mode); |
262 | } |
320 | } |
Line 263... | Line 321... | ||
263 | 321 | ||
264 | return count; |
322 | return count; |
265 | } |
- | |
266 | - | ||
267 | /** |
- | |
268 | * drm_helper_probe_single_connector_modes - get complete set of display modes |
- | |
269 | * @connector: connector to probe |
- | |
270 | * @maxX: max width for modes |
- | |
271 | * @maxY: max height for modes |
- | |
272 | * |
- | |
273 | * Based on the helper callbacks implemented by @connector try to detect all |
- | |
274 | * valid modes. Modes will first be added to the connector's probed_modes list, |
- | |
275 | * then culled (based on validity and the @maxX, @maxY parameters) and put into |
- | |
276 | * the normal modes list. |
- | |
277 | * |
- | |
278 | * Intended to be use as a generic implementation of the ->fill_modes() |
- | |
279 | * @connector vfunc for drivers that use the crtc helpers for output mode |
- | |
280 | * filtering and detection. |
- | |
281 | * |
- | |
282 | * Returns: |
- | |
283 | * The number of modes found on @connector. |
- | |
284 | */ |
- | |
285 | int drm_helper_probe_single_connector_modes(struct drm_connector *connector, |
- | |
286 | uint32_t maxX, uint32_t maxY) |
- | |
287 | { |
- | |
288 | return drm_helper_probe_single_connector_modes_merge_bits(connector, maxX, maxY, true); |
- | |
289 | } |
323 | } |
Line 290... | Line 324... | ||
290 | EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); |
324 | EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); |
291 | - | ||
292 | /** |
- | |
293 | * drm_helper_probe_single_connector_modes_nomerge - get complete set of display modes |
- | |
294 | * @connector: connector to probe |
- | |
295 | * @maxX: max width for modes |
- | |
296 | * @maxY: max height for modes |
- | |
297 | * |
- | |
298 | * This operates like drm_hehlper_probe_single_connector_modes except it |
- | |
299 | * replaces the mode bits instead of merging them for preferred modes. |
- | |
300 | */ |
- | |
301 | int drm_helper_probe_single_connector_modes_nomerge(struct drm_connector *connector, |
- | |
302 | uint32_t maxX, uint32_t maxY) |
- | |
303 | { |
- | |
304 | return drm_helper_probe_single_connector_modes_merge_bits(connector, maxX, maxY, false); |
- | |
305 | } |
- | |
306 | EXPORT_SYMBOL(drm_helper_probe_single_connector_modes_nomerge); |
- | |
307 | 325 | ||
308 | /** |
326 | /** |
309 | * drm_kms_helper_hotplug_event - fire off KMS hotplug events |
327 | * drm_kms_helper_hotplug_event - fire off KMS hotplug events |
310 | * @dev: drm_device whose connector state changed |
328 | * @dev: drm_device whose connector state changed |
311 | * |
329 | * |