Rev 1430 | Rev 2160 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1430 | Rev 1963 | ||
---|---|---|---|
Line 32... | Line 32... | ||
32 | #include "drmP.h" |
32 | #include "drmP.h" |
33 | #include "drm_crtc.h" |
33 | #include "drm_crtc.h" |
34 | #include "drm_crtc_helper.h" |
34 | #include "drm_crtc_helper.h" |
35 | #include "drm_fb_helper.h" |
35 | #include "drm_fb_helper.h" |
Line -... | Line 36... | ||
- | 36 | ||
- | 37 | static bool drm_kms_helper_poll = true; |
|
36 | 38 | ||
37 | static void drm_mode_validate_flag(struct drm_connector *connector, |
39 | static void drm_mode_validate_flag(struct drm_connector *connector, |
38 | int flags) |
40 | int flags) |
39 | { |
41 | { |
Line 53... | Line 55... | ||
53 | 55 | ||
54 | return; |
56 | return; |
Line 55... | Line 57... | ||
55 | } |
57 | } |
56 | 58 | ||
57 | /** |
59 | /** |
58 | * drm_helper_probe_connector_modes - get complete set of display modes |
60 | * drm_helper_probe_single_connector_modes - get complete set of display modes |
59 | * @dev: DRM device |
61 | * @dev: DRM device |
60 | * @maxX: max width for modes |
62 | * @maxX: max width for modes |
61 | * @maxY: max height for modes |
63 | * @maxY: max height for modes |
Line 84... | Line 86... | ||
84 | struct drm_connector_helper_funcs *connector_funcs = |
86 | struct drm_connector_helper_funcs *connector_funcs = |
85 | connector->helper_private; |
87 | connector->helper_private; |
86 | int count = 0; |
88 | int count = 0; |
87 | int mode_flags = 0; |
89 | int mode_flags = 0; |
Line -... | Line 90... | ||
- | 90 | ||
88 | 91 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, |
|
89 | DRM_DEBUG_KMS("%s\n", drm_get_connector_name(connector)); |
92 | drm_get_connector_name(connector)); |
90 | /* set all modes to the unverified state */ |
93 | /* set all modes to the unverified state */ |
91 | list_for_each_entry_safe(mode, t, &connector->modes, head) |
94 | list_for_each_entry_safe(mode, t, &connector->modes, head) |
Line 92... | Line 95... | ||
92 | mode->status = MODE_UNVERIFIED; |
95 | mode->status = MODE_UNVERIFIED; |
Line 96... | Line 99... | ||
96 | connector->status = connector_status_connected; |
99 | connector->status = connector_status_connected; |
97 | else |
100 | else |
98 | connector->status = connector_status_disconnected; |
101 | connector->status = connector_status_disconnected; |
99 | if (connector->funcs->force) |
102 | if (connector->funcs->force) |
100 | connector->funcs->force(connector); |
103 | connector->funcs->force(connector); |
101 | } else |
104 | } else { |
102 | connector->status = connector->funcs->detect(connector); |
105 | connector->status = connector->funcs->detect(connector, true); |
- | 106 | // drm_kms_helper_poll_enable(dev); |
|
- | 107 | } |
|
Line 103... | Line 108... | ||
103 | 108 | ||
104 | if (connector->status == connector_status_disconnected) { |
109 | if (connector->status == connector_status_disconnected) { |
105 | DRM_DEBUG_KMS("%s is disconnected\n", |
110 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n", |
- | 111 | connector->base.id, drm_get_connector_name(connector)); |
|
106 | drm_get_connector_name(connector)); |
112 | drm_mode_connector_update_edid_property(connector, NULL); |
107 | goto prune; |
113 | goto prune; |
Line 108... | Line 114... | ||
108 | } |
114 | } |
109 | 115 | ||
110 | count = (*connector_funcs->get_modes)(connector); |
116 | count = (*connector_funcs->get_modes)(connector); |
111 | if (!count) { |
117 | if (count == 0 && connector->status == connector_status_connected) |
112 | count = drm_add_modes_noedid(connector, 1024, 768); |
118 | count = drm_add_modes_noedid(connector, 1024, 768); |
113 | if (!count) |
- | |
Line 114... | Line 119... | ||
114 | return 0; |
119 | if (count == 0) |
Line 115... | Line 120... | ||
115 | } |
120 | goto prune; |
116 | 121 | ||
Line 138... | Line 143... | ||
138 | if (list_empty(&connector->modes)) |
143 | if (list_empty(&connector->modes)) |
139 | return 0; |
144 | return 0; |
Line 140... | Line 145... | ||
140 | 145 | ||
Line 141... | Line 146... | ||
141 | drm_mode_sort(&connector->modes); |
146 | drm_mode_sort(&connector->modes); |
142 | 147 | ||
143 | DRM_DEBUG_KMS("Probed modes for %s\n", |
148 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id, |
144 | drm_get_connector_name(connector)); |
149 | drm_get_connector_name(connector)); |
Line 145... | Line 150... | ||
145 | list_for_each_entry_safe(mode, t, &connector->modes, head) { |
150 | list_for_each_entry_safe(mode, t, &connector->modes, head) { |
Line 151... | Line 156... | ||
151 | 156 | ||
152 | return count; |
157 | return count; |
153 | } |
158 | } |
Line 154... | Line -... | ||
154 | EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); |
- | |
155 | - | ||
156 | int drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX, |
- | |
157 | uint32_t maxY) |
- | |
158 | { |
- | |
159 | struct drm_connector *connector; |
- | |
160 | int count = 0; |
- | |
161 | - | ||
162 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
- | |
163 | count += drm_helper_probe_single_connector_modes(connector, |
- | |
164 | maxX, maxY); |
- | |
165 | } |
- | |
166 | - | ||
167 | return count; |
- | |
168 | } |
- | |
169 | EXPORT_SYMBOL(drm_helper_probe_connector_modes); |
159 | EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); |
170 | 160 | ||
171 | /** |
161 | /** |
172 | * drm_helper_encoder_in_use - check if a given encoder is in use |
162 | * drm_helper_encoder_in_use - check if a given encoder is in use |
173 | * @encoder: encoder to check |
163 | * @encoder: encoder to check |
Line 213... | Line 203... | ||
213 | return true; |
203 | return true; |
214 | return false; |
204 | return false; |
215 | } |
205 | } |
216 | EXPORT_SYMBOL(drm_helper_crtc_in_use); |
206 | EXPORT_SYMBOL(drm_helper_crtc_in_use); |
Line -... | Line 207... | ||
- | 207 | ||
- | 208 | static void |
|
- | 209 | drm_encoder_disable(struct drm_encoder *encoder) |
|
- | 210 | { |
|
- | 211 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; |
|
- | 212 | ||
- | 213 | if (encoder_funcs->disable) |
|
- | 214 | (*encoder_funcs->disable)(encoder); |
|
- | 215 | else |
|
- | 216 | (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); |
|
- | 217 | } |
|
217 | 218 | ||
218 | /** |
219 | /** |
219 | * drm_helper_disable_unused_functions - disable unused objects |
220 | * drm_helper_disable_unused_functions - disable unused objects |
220 | * @dev: DRM device |
221 | * @dev: DRM device |
221 | * |
222 | * |
Line 227... | Line 228... | ||
227 | */ |
228 | */ |
228 | void drm_helper_disable_unused_functions(struct drm_device *dev) |
229 | void drm_helper_disable_unused_functions(struct drm_device *dev) |
229 | { |
230 | { |
230 | struct drm_encoder *encoder; |
231 | struct drm_encoder *encoder; |
231 | struct drm_connector *connector; |
232 | struct drm_connector *connector; |
232 | struct drm_encoder_helper_funcs *encoder_funcs; |
- | |
233 | struct drm_crtc *crtc; |
233 | struct drm_crtc *crtc; |
Line 234... | Line 234... | ||
234 | 234 | ||
235 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
235 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
236 | if (!connector->encoder) |
236 | if (!connector->encoder) |
237 | continue; |
237 | continue; |
238 | if (connector->status == connector_status_disconnected) |
238 | if (connector->status == connector_status_disconnected) |
239 | connector->encoder = NULL; |
239 | connector->encoder = NULL; |
Line 240... | Line 240... | ||
240 | } |
240 | } |
241 | - | ||
242 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
241 | |
243 | encoder_funcs = encoder->helper_private; |
- | |
244 | if (!drm_helper_encoder_in_use(encoder)) { |
242 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
245 | if (encoder_funcs->disable) |
- | |
246 | (*encoder_funcs->disable)(encoder); |
- | |
247 | else |
243 | if (!drm_helper_encoder_in_use(encoder)) { |
248 | (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); |
244 | drm_encoder_disable(encoder); |
249 | /* disconnector encoder from any connector */ |
245 | /* disconnector encoder from any connector */ |
250 | encoder->crtc = NULL; |
246 | encoder->crtc = NULL; |
Line 251... | Line 247... | ||
251 | } |
247 | } |
252 | } |
248 | } |
253 | 249 | ||
254 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
250 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
- | 251 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
|
- | 252 | crtc->enabled = drm_helper_crtc_in_use(crtc); |
|
- | 253 | if (!crtc->enabled) { |
|
255 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
254 | if (crtc_funcs->disable) |
256 | crtc->enabled = drm_helper_crtc_in_use(crtc); |
255 | (*crtc_funcs->disable)(crtc); |
257 | if (!crtc->enabled) { |
256 | else |
258 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); |
257 | (*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF); |
259 | crtc->fb = NULL; |
258 | crtc->fb = NULL; |
260 | } |
259 | } |
Line 261... | Line -... | ||
261 | } |
- | |
262 | } |
- | |
263 | EXPORT_SYMBOL(drm_helper_disable_unused_functions); |
- | |
264 | - | ||
265 | static struct drm_display_mode *drm_has_preferred_mode(struct drm_connector *connector, int width, int height) |
- | |
266 | { |
- | |
267 | struct drm_display_mode *mode; |
- | |
268 | - | ||
269 | list_for_each_entry(mode, &connector->modes, head) { |
- | |
270 | if (drm_mode_width(mode) > width || |
- | |
271 | drm_mode_height(mode) > height) |
- | |
272 | continue; |
- | |
273 | if (mode->type & DRM_MODE_TYPE_PREFERRED) |
- | |
274 | return mode; |
- | |
275 | } |
- | |
276 | return NULL; |
- | |
277 | } |
- | |
278 | - | ||
279 | static bool drm_has_cmdline_mode(struct drm_connector *connector) |
- | |
280 | { |
- | |
281 | struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private; |
- | |
282 | struct drm_fb_helper_cmdline_mode *cmdline_mode; |
- | |
283 | - | ||
284 | if (!fb_help_conn) |
- | |
285 | return false; |
- | |
286 | - | ||
287 | cmdline_mode = &fb_help_conn->cmdline_mode; |
- | |
288 | return cmdline_mode->specified; |
- | |
289 | } |
- | |
290 | - | ||
291 | static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_connector *connector, int width, int height) |
- | |
292 | { |
- | |
293 | struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private; |
- | |
294 | struct drm_fb_helper_cmdline_mode *cmdline_mode; |
- | |
295 | struct drm_display_mode *mode = NULL; |
- | |
296 | - | ||
297 | if (!fb_help_conn) |
- | |
298 | return mode; |
- | |
299 | - | ||
300 | cmdline_mode = &fb_help_conn->cmdline_mode; |
- | |
301 | if (cmdline_mode->specified == false) |
- | |
302 | return mode; |
- | |
303 | - | ||
304 | /* attempt to find a matching mode in the list of modes |
- | |
305 | * we have gotten so far, if not add a CVT mode that conforms |
- | |
306 | */ |
- | |
307 | if (cmdline_mode->rb || cmdline_mode->margins) |
- | |
308 | goto create_mode; |
- | |
309 | - | ||
310 | list_for_each_entry(mode, &connector->modes, head) { |
- | |
311 | /* check width/height */ |
- | |
312 | if (mode->hdisplay != cmdline_mode->xres || |
- | |
313 | mode->vdisplay != cmdline_mode->yres) |
- | |
314 | continue; |
- | |
315 | - | ||
316 | if (cmdline_mode->refresh_specified) { |
- | |
317 | if (mode->vrefresh != cmdline_mode->refresh) |
- | |
318 | continue; |
- | |
319 | } |
- | |
320 | - | ||
321 | if (cmdline_mode->interlace) { |
- | |
322 | if (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) |
- | |
323 | continue; |
- | |
324 | } |
- | |
325 | return mode; |
- | |
326 | } |
- | |
327 | - | ||
328 | create_mode: |
- | |
329 | mode = drm_cvt_mode(connector->dev, cmdline_mode->xres, |
- | |
330 | cmdline_mode->yres, |
- | |
331 | cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60, |
- | |
332 | cmdline_mode->rb, cmdline_mode->interlace, |
- | |
333 | cmdline_mode->margins); |
- | |
334 | drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); |
- | |
335 | list_add(&mode->head, &connector->modes); |
- | |
336 | return mode; |
- | |
337 | } |
- | |
338 | - | ||
339 | static bool drm_connector_enabled(struct drm_connector *connector, bool strict) |
- | |
340 | { |
- | |
341 | bool enable; |
- | |
342 | - | ||
343 | if (strict) { |
- | |
344 | enable = connector->status == connector_status_connected; |
- | |
345 | } else { |
- | |
346 | enable = connector->status != connector_status_disconnected; |
- | |
347 | } |
- | |
348 | return enable; |
- | |
349 | } |
- | |
350 | - | ||
351 | static void drm_enable_connectors(struct drm_device *dev, bool *enabled) |
- | |
352 | { |
- | |
353 | bool any_enabled = false; |
- | |
354 | struct drm_connector *connector; |
- | |
355 | int i = 0; |
- | |
356 | - | ||
357 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
- | |
358 | enabled[i] = drm_connector_enabled(connector, true); |
- | |
359 | DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id, |
- | |
360 | enabled[i] ? "yes" : "no"); |
- | |
361 | any_enabled |= enabled[i]; |
- | |
362 | i++; |
- | |
363 | } |
- | |
364 | - | ||
365 | if (any_enabled) |
- | |
366 | return; |
- | |
367 | - | ||
368 | i = 0; |
- | |
369 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
- | |
370 | enabled[i] = drm_connector_enabled(connector, false); |
- | |
371 | i++; |
- | |
372 | } |
- | |
373 | } |
- | |
374 | - | ||
375 | static bool drm_target_preferred(struct drm_device *dev, |
- | |
376 | struct drm_display_mode **modes, |
- | |
377 | bool *enabled, int width, int height) |
- | |
378 | { |
- | |
379 | struct drm_connector *connector; |
- | |
380 | int i = 0; |
- | |
381 | - | ||
382 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
- | |
383 | - | ||
384 | if (enabled[i] == false) { |
- | |
385 | i++; |
- | |
386 | continue; |
- | |
387 | } |
- | |
388 | - | ||
389 | DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", |
- | |
390 | connector->base.id); |
- | |
391 | - | ||
392 | /* got for command line mode first */ |
- | |
393 | modes[i] = drm_pick_cmdline_mode(connector, width, height); |
- | |
394 | if (!modes[i]) { |
- | |
395 | DRM_DEBUG_KMS("looking for preferred mode on connector %d\n", |
- | |
396 | connector->base.id); |
- | |
397 | modes[i] = drm_has_preferred_mode(connector, width, height); |
- | |
398 | } |
- | |
399 | /* No preferred modes, pick one off the list */ |
- | |
400 | if (!modes[i] && !list_empty(&connector->modes)) { |
- | |
401 | list_for_each_entry(modes[i], &connector->modes, head) |
- | |
402 | break; |
- | |
403 | } |
- | |
404 | DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name : |
- | |
405 | "none"); |
- | |
406 | i++; |
- | |
407 | } |
- | |
408 | return true; |
- | |
409 | } |
- | |
410 | - | ||
411 | static int drm_pick_crtcs(struct drm_device *dev, |
- | |
412 | struct drm_crtc **best_crtcs, |
- | |
413 | struct drm_display_mode **modes, |
- | |
414 | int n, int width, int height) |
- | |
415 | { |
- | |
416 | int c, o; |
- | |
417 | struct drm_connector *connector; |
- | |
418 | struct drm_connector_helper_funcs *connector_funcs; |
- | |
419 | struct drm_encoder *encoder; |
- | |
420 | struct drm_crtc *best_crtc; |
- | |
421 | int my_score, best_score, score; |
- | |
422 | struct drm_crtc **crtcs, *crtc; |
- | |
423 | - | ||
424 | if (n == dev->mode_config.num_connector) |
- | |
425 | return 0; |
- | |
426 | c = 0; |
- | |
427 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
- | |
428 | if (c == n) |
- | |
429 | break; |
- | |
430 | c++; |
- | |
431 | } |
- | |
432 | - | ||
433 | best_crtcs[n] = NULL; |
- | |
434 | best_crtc = NULL; |
- | |
435 | best_score = drm_pick_crtcs(dev, best_crtcs, modes, n+1, width, height); |
- | |
436 | if (modes[n] == NULL) |
- | |
437 | return best_score; |
- | |
438 | - | ||
439 | crtcs = kmalloc(dev->mode_config.num_connector * |
- | |
440 | sizeof(struct drm_crtc *), GFP_KERNEL); |
- | |
441 | if (!crtcs) |
- | |
442 | return best_score; |
- | |
443 | - | ||
444 | my_score = 1; |
- | |
445 | if (connector->status == connector_status_connected) |
- | |
446 | my_score++; |
- | |
447 | if (drm_has_cmdline_mode(connector)) |
- | |
448 | my_score++; |
- | |
449 | if (drm_has_preferred_mode(connector, width, height)) |
- | |
450 | my_score++; |
- | |
451 | - | ||
452 | connector_funcs = connector->helper_private; |
- | |
453 | encoder = connector_funcs->best_encoder(connector); |
- | |
454 | if (!encoder) |
- | |
455 | goto out; |
- | |
456 | - | ||
457 | connector->encoder = encoder; |
- | |
458 | - | ||
459 | /* select a crtc for this connector and then attempt to configure |
- | |
460 | remaining connectors */ |
- | |
461 | c = 0; |
- | |
462 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
- | |
463 | - | ||
464 | if ((encoder->possible_crtcs & (1 << c)) == 0) { |
- | |
465 | c++; |
- | |
466 | continue; |
- | |
467 | } |
- | |
468 | - | ||
469 | for (o = 0; o < n; o++) |
- | |
470 | if (best_crtcs[o] == crtc) |
- | |
471 | break; |
- | |
472 | - | ||
473 | if (o < n) { |
- | |
474 | /* ignore cloning for now */ |
- | |
475 | c++; |
- | |
476 | continue; |
- | |
477 | } |
- | |
478 | - | ||
479 | crtcs[n] = crtc; |
- | |
480 | memcpy(crtcs, best_crtcs, n * sizeof(struct drm_crtc *)); |
- | |
481 | score = my_score + drm_pick_crtcs(dev, crtcs, modes, n + 1, |
- | |
482 | width, height); |
- | |
483 | if (score > best_score) { |
- | |
484 | best_crtc = crtc; |
- | |
485 | best_score = score; |
- | |
486 | memcpy(best_crtcs, crtcs, |
- | |
487 | dev->mode_config.num_connector * |
- | |
488 | sizeof(struct drm_crtc *)); |
- | |
489 | } |
- | |
490 | c++; |
- | |
491 | } |
- | |
492 | out: |
- | |
493 | kfree(crtcs); |
- | |
494 | return best_score; |
- | |
495 | } |
- | |
496 | - | ||
497 | static void drm_setup_crtcs(struct drm_device *dev) |
- | |
498 | { |
- | |
499 | struct drm_crtc **crtcs; |
- | |
500 | struct drm_display_mode **modes; |
- | |
501 | struct drm_encoder *encoder; |
- | |
502 | struct drm_connector *connector; |
- | |
503 | bool *enabled; |
- | |
504 | int width, height; |
- | |
505 | int i, ret; |
- | |
506 | - | ||
507 | DRM_DEBUG_KMS("\n"); |
- | |
508 | - | ||
509 | width = dev->mode_config.max_width; |
- | |
510 | height = dev->mode_config.max_height; |
- | |
511 | - | ||
512 | /* clean out all the encoder/crtc combos */ |
- | |
513 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
- | |
514 | encoder->crtc = NULL; |
- | |
515 | } |
- | |
516 | - | ||
517 | crtcs = kcalloc(dev->mode_config.num_connector, |
- | |
518 | sizeof(struct drm_crtc *), GFP_KERNEL); |
- | |
519 | modes = kcalloc(dev->mode_config.num_connector, |
- | |
520 | sizeof(struct drm_display_mode *), GFP_KERNEL); |
- | |
521 | enabled = kcalloc(dev->mode_config.num_connector, |
- | |
522 | sizeof(bool), GFP_KERNEL); |
- | |
523 | - | ||
524 | drm_enable_connectors(dev, enabled); |
- | |
525 | - | ||
526 | ret = drm_target_preferred(dev, modes, enabled, width, height); |
- | |
527 | if (!ret) |
- | |
528 | DRM_ERROR("Unable to find initial modes\n"); |
- | |
529 | - | ||
530 | DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height); |
- | |
531 | - | ||
532 | drm_pick_crtcs(dev, crtcs, modes, 0, width, height); |
- | |
533 | - | ||
534 | i = 0; |
- | |
535 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
- | |
536 | struct drm_display_mode *mode = modes[i]; |
- | |
537 | struct drm_crtc *crtc = crtcs[i]; |
- | |
538 | - | ||
539 | if (connector->encoder == NULL) { |
- | |
540 | i++; |
- | |
541 | continue; |
- | |
542 | } |
- | |
543 | - | ||
544 | if (mode && crtc) { |
- | |
545 | DRM_DEBUG_KMS("desired mode %s set on crtc %d\n", |
- | |
546 | mode->name, crtc->base.id); |
- | |
547 | crtc->desired_mode = mode; |
- | |
548 | connector->encoder->crtc = crtc; |
- | |
549 | } else { |
- | |
550 | connector->encoder->crtc = NULL; |
- | |
551 | connector->encoder = NULL; |
- | |
552 | } |
- | |
553 | i++; |
- | |
554 | } |
- | |
555 | - | ||
556 | kfree(crtcs); |
- | |
557 | kfree(modes); |
260 | } |
558 | kfree(enabled); |
261 | } |
559 | } |
262 | EXPORT_SYMBOL(drm_helper_disable_unused_functions); |
560 | 263 | ||
561 | /** |
264 | /** |
Line 570... | Line 273... | ||
570 | { |
273 | { |
571 | struct drm_device *dev; |
274 | struct drm_device *dev; |
572 | struct drm_crtc *tmp; |
275 | struct drm_crtc *tmp; |
573 | int crtc_mask = 1; |
276 | int crtc_mask = 1; |
Line 574... | Line 277... | ||
574 | 277 | ||
Line 575... | Line 278... | ||
575 | WARN(!crtc, "checking null crtc?"); |
278 | WARN(!crtc, "checking null crtc?\n"); |
Line 576... | Line 279... | ||
576 | 279 | ||
577 | dev = crtc->dev; |
280 | dev = crtc->dev; |
Line 600... | Line 303... | ||
600 | 303 | ||
601 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
304 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
602 | encoder_funcs = encoder->helper_private; |
305 | encoder_funcs = encoder->helper_private; |
603 | /* Disable unused encoders */ |
306 | /* Disable unused encoders */ |
604 | if (encoder->crtc == NULL) |
307 | if (encoder->crtc == NULL) |
605 | (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); |
308 | drm_encoder_disable(encoder); |
606 | /* Disable encoders whose CRTC is about to change */ |
309 | /* Disable encoders whose CRTC is about to change */ |
607 | if (encoder_funcs->get_crtc && |
310 | if (encoder_funcs->get_crtc && |
608 | encoder->crtc != (*encoder_funcs->get_crtc)(encoder)) |
311 | encoder->crtc != (*encoder_funcs->get_crtc)(encoder)) |
609 | (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); |
312 | drm_encoder_disable(encoder); |
610 | } |
313 | } |
Line 611... | Line 314... | ||
611 | } |
314 | } |
612 | 315 | ||
Line 630... | Line 333... | ||
630 | struct drm_display_mode *mode, |
333 | struct drm_display_mode *mode, |
631 | int x, int y, |
334 | int x, int y, |
632 | struct drm_framebuffer *old_fb) |
335 | struct drm_framebuffer *old_fb) |
633 | { |
336 | { |
634 | struct drm_device *dev = crtc->dev; |
337 | struct drm_device *dev = crtc->dev; |
635 | struct drm_display_mode *adjusted_mode, saved_mode; |
338 | struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode; |
636 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
339 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
637 | struct drm_encoder_helper_funcs *encoder_funcs; |
340 | struct drm_encoder_helper_funcs *encoder_funcs; |
638 | int saved_x, saved_y; |
341 | int saved_x, saved_y; |
639 | struct drm_encoder *encoder; |
342 | struct drm_encoder *encoder; |
640 | bool ret = true; |
343 | bool ret = true; |
Line 641... | Line -... | ||
641 | - | ||
642 | adjusted_mode = drm_mode_duplicate(dev, mode); |
- | |
643 | 344 | ||
644 | crtc->enabled = drm_helper_crtc_in_use(crtc); |
- | |
645 | 345 | crtc->enabled = drm_helper_crtc_in_use(crtc); |
|
646 | if (!crtc->enabled) |
346 | if (!crtc->enabled) |
Line -... | Line 347... | ||
- | 347 | return true; |
|
- | 348 | ||
- | 349 | adjusted_mode = drm_mode_duplicate(dev, mode); |
|
647 | return true; |
350 | |
648 | 351 | saved_hwmode = crtc->hwmode; |
|
649 | saved_mode = crtc->mode; |
352 | saved_mode = crtc->mode; |
Line 650... | Line 353... | ||
650 | saved_x = crtc->x; |
353 | saved_x = crtc->x; |
Line 673... | Line 376... | ||
673 | } |
376 | } |
Line 674... | Line 377... | ||
674 | 377 | ||
675 | if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) { |
378 | if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) { |
676 | goto done; |
379 | goto done; |
- | 380 | } |
|
Line 677... | Line 381... | ||
677 | } |
381 | DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); |
678 | 382 | ||
Line 679... | Line 383... | ||
679 | /* Prepare the encoders and CRTCs before setting the mode. */ |
383 | /* Prepare the encoders and CRTCs before setting the mode. */ |
Line 700... | Line 404... | ||
700 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
404 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
Line 701... | Line 405... | ||
701 | 405 | ||
702 | if (encoder->crtc != crtc) |
406 | if (encoder->crtc != crtc) |
Line -... | Line 407... | ||
- | 407 | continue; |
|
703 | continue; |
408 | |
704 | 409 | DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n", |
|
705 | DRM_DEBUG("%s: set mode %s %x\n", drm_get_encoder_name(encoder), |
410 | encoder->base.id, drm_get_encoder_name(encoder), |
706 | mode->name, mode->base.id); |
411 | mode->base.id, mode->name); |
707 | encoder_funcs = encoder->helper_private; |
412 | encoder_funcs = encoder->helper_private; |
Line 708... | Line 413... | ||
708 | encoder_funcs->mode_set(encoder, mode, adjusted_mode); |
413 | encoder_funcs->mode_set(encoder, mode, adjusted_mode); |
Line 719... | Line 424... | ||
719 | encoder_funcs = encoder->helper_private; |
424 | encoder_funcs = encoder->helper_private; |
720 | encoder_funcs->commit(encoder); |
425 | encoder_funcs->commit(encoder); |
Line 721... | Line 426... | ||
721 | 426 | ||
Line 722... | Line 427... | ||
722 | } |
427 | } |
723 | 428 | ||
- | 429 | /* Store real post-adjustment hardware mode. */ |
|
- | 430 | crtc->hwmode = *adjusted_mode; |
|
- | 431 | ||
- | 432 | /* Calculate and store various constants which |
|
- | 433 | * are later needed by vblank and swap-completion |
|
- | 434 | * timestamping. They are derived from true hwmode. |
|
- | 435 | */ |
|
724 | /* XXX free adjustedmode */ |
436 | drm_calc_timestamping_constants(crtc); |
725 | drm_mode_destroy(dev, adjusted_mode); |
437 | |
- | 438 | /* FIXME: add subpixel order */ |
|
726 | /* FIXME: add subpixel order */ |
439 | done: |
- | 440 | drm_mode_destroy(dev, adjusted_mode); |
|
727 | done: |
441 | if (!ret) { |
728 | if (!ret) { |
442 | crtc->hwmode = saved_hwmode; |
729 | crtc->mode = saved_mode; |
443 | crtc->mode = saved_mode; |
730 | crtc->x = saved_x; |
444 | crtc->x = saved_x; |
Line 763... | Line 477... | ||
763 | bool fb_changed = false; /* if true and !mode_changed just do a flip */ |
477 | bool fb_changed = false; /* if true and !mode_changed just do a flip */ |
764 | struct drm_connector *save_connectors, *connector; |
478 | struct drm_connector *save_connectors, *connector; |
765 | int count = 0, ro, fail = 0; |
479 | int count = 0, ro, fail = 0; |
766 | struct drm_crtc_helper_funcs *crtc_funcs; |
480 | struct drm_crtc_helper_funcs *crtc_funcs; |
767 | int ret = 0; |
481 | int ret = 0; |
- | 482 | int i; |
|
Line 768... | Line 483... | ||
768 | 483 | ||
Line 769... | Line 484... | ||
769 | DRM_DEBUG_KMS("\n"); |
484 | DRM_DEBUG_KMS("\n"); |
770 | 485 | ||
Line 777... | Line 492... | ||
777 | if (!set->crtc->helper_private) |
492 | if (!set->crtc->helper_private) |
778 | return -EINVAL; |
493 | return -EINVAL; |
Line 779... | Line 494... | ||
779 | 494 | ||
Line -... | Line 495... | ||
- | 495 | crtc_funcs = set->crtc->helper_private; |
|
- | 496 | ||
- | 497 | if (!set->mode) |
|
- | 498 | set->fb = NULL; |
|
780 | crtc_funcs = set->crtc->helper_private; |
499 | |
781 | - | ||
782 | DRM_DEBUG_KMS("crtc: %p %d fb: %p connectors: %p num_connectors:" |
500 | if (set->fb) { |
783 | " %d (x, y) (%i, %i)\n", |
501 | DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n", |
- | 502 | set->crtc->base.id, set->fb->base.id, |
|
- | 503 | (int)set->num_connectors, set->x, set->y); |
|
- | 504 | } else { |
|
- | 505 | DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id); |
|
- | 506 | set->mode = NULL; |
|
Line 784... | Line 507... | ||
784 | set->crtc, set->crtc->base.id, set->fb, set->connectors, |
507 | set->num_connectors = 0; |
Line 785... | Line 508... | ||
785 | (int)set->num_connectors, set->x, set->y); |
508 | } |
786 | 509 | ||
Line 909... | Line 632... | ||
909 | if (new_crtc != connector->encoder->crtc) { |
632 | if (new_crtc != connector->encoder->crtc) { |
910 | DRM_DEBUG_KMS("crtc changed, full mode switch\n"); |
633 | DRM_DEBUG_KMS("crtc changed, full mode switch\n"); |
911 | mode_changed = true; |
634 | mode_changed = true; |
912 | connector->encoder->crtc = new_crtc; |
635 | connector->encoder->crtc = new_crtc; |
913 | } |
636 | } |
- | 637 | if (new_crtc) { |
|
914 | DRM_DEBUG_KMS("setting connector %d crtc to %p\n", |
638 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n", |
- | 639 | connector->base.id, drm_get_connector_name(connector), |
|
- | 640 | new_crtc->base.id); |
|
- | 641 | } else { |
|
- | 642 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n", |
|
915 | connector->base.id, new_crtc); |
643 | connector->base.id, drm_get_connector_name(connector)); |
- | 644 | } |
|
916 | } |
645 | } |
Line 917... | Line 646... | ||
917 | 646 | ||
918 | /* mode_set_base is not a required function */ |
647 | /* mode_set_base is not a required function */ |
919 | if (fb_changed && !crtc_funcs->mode_set_base) |
648 | if (fb_changed && !crtc_funcs->mode_set_base) |
Line 920... | Line 649... | ||
920 | mode_changed = true; |
649 | mode_changed = true; |
921 | - | ||
922 | if (mode_changed) { |
- | |
923 | old_fb = set->crtc->fb; |
650 | |
924 | set->crtc->fb = set->fb; |
651 | if (mode_changed) { |
925 | set->crtc->enabled = (set->mode != NULL); |
652 | set->crtc->enabled = drm_helper_crtc_in_use(set->crtc); |
926 | if (set->mode != NULL) { |
653 | if (set->crtc->enabled) { |
927 | DRM_DEBUG_KMS("attempting to set mode from" |
654 | DRM_DEBUG_KMS("attempting to set mode from" |
- | 655 | " userspace\n"); |
|
- | 656 | drm_mode_debug_printmodeline(set->mode); |
|
928 | " userspace\n"); |
657 | old_fb = set->crtc->fb; |
929 | drm_mode_debug_printmodeline(set->mode); |
658 | set->crtc->fb = set->fb; |
930 | if (!drm_crtc_helper_set_mode(set->crtc, set->mode, |
659 | if (!drm_crtc_helper_set_mode(set->crtc, set->mode, |
931 | set->x, set->y, |
660 | set->x, set->y, |
932 | old_fb)) { |
661 | old_fb)) { |
- | 662 | DRM_ERROR("failed to set mode on [CRTC:%d]\n", |
|
933 | DRM_ERROR("failed to set mode on crtc %p\n", |
663 | set->crtc->base.id); |
934 | set->crtc); |
664 | set->crtc->fb = old_fb; |
935 | ret = -EINVAL; |
665 | ret = -EINVAL; |
936 | goto fail; |
666 | goto fail; |
937 | } |
667 | } |
- | 668 | DRM_DEBUG_KMS("Setting connector DPMS state to on\n"); |
|
938 | /* TODO are these needed? */ |
669 | for (i = 0; i < set->num_connectors; i++) { |
939 | set->crtc->desired_x = set->x; |
670 | DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id, |
- | 671 | drm_get_connector_name(set->connectors[i])); |
|
940 | set->crtc->desired_y = set->y; |
672 | set->connectors[i]->dpms = DRM_MODE_DPMS_ON; |
941 | set->crtc->desired_mode = set->mode; |
673 | } |
942 | } |
674 | } |
943 | drm_helper_disable_unused_functions(dev); |
675 | drm_helper_disable_unused_functions(dev); |
944 | } else if (fb_changed) { |
676 | } else if (fb_changed) { |
Line 948... | Line 680... | ||
948 | old_fb = set->crtc->fb; |
680 | old_fb = set->crtc->fb; |
949 | if (set->crtc->fb != set->fb) |
681 | if (set->crtc->fb != set->fb) |
950 | set->crtc->fb = set->fb; |
682 | set->crtc->fb = set->fb; |
951 | ret = crtc_funcs->mode_set_base(set->crtc, |
683 | ret = crtc_funcs->mode_set_base(set->crtc, |
952 | set->x, set->y, old_fb); |
684 | set->x, set->y, old_fb); |
953 | if (ret != 0) |
685 | if (ret != 0) { |
- | 686 | set->crtc->fb = old_fb; |
|
954 | goto fail; |
687 | goto fail; |
955 | } |
688 | } |
- | 689 | } |
|
Line 956... | Line 690... | ||
956 | 690 | ||
957 | kfree(save_connectors); |
691 | kfree(save_connectors); |
958 | kfree(save_encoders); |
692 | kfree(save_encoders); |
959 | kfree(save_crtcs); |
693 | kfree(save_crtcs); |
Line 981... | Line 715... | ||
981 | kfree(save_crtcs); |
715 | kfree(save_crtcs); |
982 | return ret; |
716 | return ret; |
983 | } |
717 | } |
984 | EXPORT_SYMBOL(drm_crtc_helper_set_config); |
718 | EXPORT_SYMBOL(drm_crtc_helper_set_config); |
Line 985... | Line -... | ||
985 | - | ||
986 | bool drm_helper_plugged_event(struct drm_device *dev) |
- | |
987 | { |
- | |
988 | DRM_DEBUG_KMS("\n"); |
- | |
989 | - | ||
990 | drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, |
- | |
991 | dev->mode_config.max_height); |
- | |
992 | - | ||
993 | drm_setup_crtcs(dev); |
- | |
994 | - | ||
995 | /* alert the driver fb layer */ |
- | |
996 | dev->mode_config.funcs->fb_changed(dev); |
- | |
997 | - | ||
998 | /* FIXME: send hotplug event */ |
- | |
999 | return true; |
- | |
1000 | } |
- | |
1001 | /** |
- | |
1002 | * drm_initial_config - setup a sane initial connector configuration |
- | |
1003 | * @dev: DRM device |
- | |
1004 | * |
- | |
1005 | * LOCKING: |
- | |
1006 | * Called at init time, must take mode config lock. |
- | |
1007 | * |
- | |
1008 | * Scan the CRTCs and connectors and try to put together an initial setup. |
- | |
1009 | * At the moment, this is a cloned configuration across all heads with |
- | |
1010 | * a new framebuffer object as the backing store. |
- | |
1011 | * |
- | |
1012 | * RETURNS: |
- | |
1013 | * Zero if everything went ok, nonzero otherwise. |
- | |
1014 | */ |
- | |
1015 | bool drm_helper_initial_config(struct drm_device *dev) |
- | |
1016 | { |
- | |
1017 | int count = 0; |
- | |
1018 | - | ||
1019 | /* disable all the possible outputs/crtcs before entering KMS mode */ |
- | |
1020 | // drm_helper_disable_unused_functions(dev); |
- | |
1021 | - | ||
1022 | // drm_fb_helper_parse_command_line(dev); |
- | |
1023 | - | ||
1024 | count = drm_helper_probe_connector_modes(dev, |
- | |
1025 | dev->mode_config.max_width, |
- | |
1026 | dev->mode_config.max_height); |
- | |
1027 | - | ||
1028 | /* |
- | |
1029 | * we shouldn't end up with no modes here. |
- | |
1030 | */ |
- | |
1031 | if (count == 0) |
- | |
1032 | printk(KERN_INFO "No connectors reported connected with modes\n"); |
- | |
1033 | - | ||
1034 | drm_setup_crtcs(dev); |
- | |
1035 | - | ||
1036 | /* alert the driver fb layer */ |
- | |
1037 | dev->mode_config.funcs->fb_changed(dev); |
- | |
1038 | - | ||
1039 | return 0; |
- | |
1040 | } |
- | |
1041 | EXPORT_SYMBOL(drm_helper_initial_config); |
- | |
1042 | 719 | ||
1043 | static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder) |
720 | static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder) |
1044 | { |
721 | { |
1045 | int dpms = DRM_MODE_DPMS_OFF; |
722 | int dpms = DRM_MODE_DPMS_OFF; |
1046 | struct drm_connector *connector; |
723 | struct drm_connector *connector; |
Line 1120... | Line 797... | ||
1120 | 797 | ||
1121 | return; |
798 | return; |
1122 | } |
799 | } |
Line 1123... | Line -... | ||
1123 | EXPORT_SYMBOL(drm_helper_connector_dpms); |
- | |
1124 | - | ||
1125 | /** |
- | |
1126 | * drm_hotplug_stage_two |
- | |
1127 | * @dev DRM device |
- | |
1128 | * @connector hotpluged connector |
- | |
1129 | * |
- | |
1130 | * LOCKING. |
- | |
1131 | * Caller must hold mode config lock, function might grab struct lock. |
- | |
1132 | * |
- | |
1133 | * Stage two of a hotplug. |
- | |
1134 | * |
- | |
1135 | * RETURNS: |
- | |
1136 | * Zero on success, errno on failure. |
- | |
1137 | */ |
- | |
1138 | int drm_helper_hotplug_stage_two(struct drm_device *dev) |
- | |
1139 | { |
- | |
1140 | drm_helper_plugged_event(dev); |
- | |
1141 | - | ||
1142 | return 0; |
- | |
1143 | } |
- | |
1144 | EXPORT_SYMBOL(drm_helper_hotplug_stage_two); |
800 | EXPORT_SYMBOL(drm_helper_connector_dpms); |
1145 | 801 | ||
1146 | int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, |
802 | int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, |
1147 | struct drm_mode_fb_cmd *mode_cmd) |
803 | struct drm_mode_fb_cmd *mode_cmd) |
1148 | { |
804 | { |
Line 1184... | Line 840... | ||
1184 | 840 | ||
1185 | encoder_funcs = encoder->helper_private; |
841 | encoder_funcs = encoder->helper_private; |
1186 | if (encoder_funcs->dpms) |
842 | if (encoder_funcs->dpms) |
1187 | (*encoder_funcs->dpms) (encoder, |
843 | (*encoder_funcs->dpms) (encoder, |
- | 844 | drm_helper_choose_encoder_dpms(encoder)); |
|
Line 1188... | Line 845... | ||
1188 | drm_helper_choose_encoder_dpms(encoder)); |
845 | } |
1189 | 846 | ||
1190 | crtc_funcs = crtc->helper_private; |
847 | crtc_funcs = crtc->helper_private; |
1191 | if (crtc_funcs->dpms) |
848 | if (crtc_funcs->dpms) |
1192 | (*crtc_funcs->dpms) (crtc, |
849 | (*crtc_funcs->dpms) (crtc, |
1193 | drm_helper_choose_crtc_dpms(crtc)); |
850 | drm_helper_choose_crtc_dpms(crtc)); |
1194 | } |
- | |
1195 | } |
851 | } |
1196 | } |
852 | } |
1197 | /* disable the unused connectors while restoring the modesetting */ |
853 | /* disable the unused connectors while restoring the modesetting */ |
1198 | drm_helper_disable_unused_functions(dev); |
854 | drm_helper_disable_unused_functions(dev); |
1199 | return 0; |
855 | return 0; |
- | 856 | } |
|
- | 857 | EXPORT_SYMBOL(drm_helper_resume_force_mode); |
|
- | 858 | ||
- | 859 | #if 0 |
|
- | 860 | ||
- | 861 | #define DRM_OUTPUT_POLL_PERIOD (10*HZ) |
|
- | 862 | static void output_poll_execute(struct work_struct *work) |
|
- | 863 | { |
|
- | 864 | struct delayed_work *delayed_work = to_delayed_work(work); |
|
- | 865 | struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work); |
|
- | 866 | struct drm_connector *connector; |
|
- | 867 | enum drm_connector_status old_status; |
|
- | 868 | bool repoll = false, changed = false; |
|
- | 869 | ||
- | 870 | if (!drm_kms_helper_poll) |
|
- | 871 | return; |
|
- | 872 | ||
- | 873 | mutex_lock(&dev->mode_config.mutex); |
|
- | 874 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
|
- | 875 | ||
- | 876 | /* if this is HPD or polled don't check it - |
|
- | 877 | TV out for instance */ |
|
- | 878 | if (!connector->polled) |
|
- | 879 | continue; |
|
- | 880 | ||
- | 881 | else if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT)) |
|
- | 882 | repoll = true; |
|
- | 883 | ||
- | 884 | old_status = connector->status; |
|
- | 885 | /* if we are connected and don't want to poll for disconnect |
|
- | 886 | skip it */ |
|
- | 887 | if (old_status == connector_status_connected && |
|
- | 888 | !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT) && |
|
- | 889 | !(connector->polled & DRM_CONNECTOR_POLL_HPD)) |
|
- | 890 | continue; |
|
- | 891 | ||
- | 892 | connector->status = connector->funcs->detect(connector, false); |
|
- | 893 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n", |
|
- | 894 | connector->base.id, |
|
- | 895 | drm_get_connector_name(connector), |
|
- | 896 | old_status, connector->status); |
|
- | 897 | if (old_status != connector->status) |
|
- | 898 | changed = true; |
|
- | 899 | } |
|
- | 900 | ||
- | 901 | mutex_unlock(&dev->mode_config.mutex); |
|
- | 902 | ||
- | 903 | if (changed) { |
|
- | 904 | /* send a uevent + call fbdev */ |
|
- | 905 | drm_sysfs_hotplug_event(dev); |
|
- | 906 | if (dev->mode_config.funcs->output_poll_changed) |
|
- | 907 | dev->mode_config.funcs->output_poll_changed(dev); |
|
- | 908 | } |
|
- | 909 | ||
- | 910 | if (repoll) |
|
- | 911 | queue_delayed_work(system_nrt_wq, delayed_work, DRM_OUTPUT_POLL_PERIOD); |
|
- | 912 | } |
|
- | 913 | ||
- | 914 | void drm_kms_helper_poll_disable(struct drm_device *dev) |
|
- | 915 | { |
|
- | 916 | if (!dev->mode_config.poll_enabled) |
|
- | 917 | return; |
|
- | 918 | cancel_delayed_work_sync(&dev->mode_config.output_poll_work); |
|
- | 919 | } |
|
- | 920 | EXPORT_SYMBOL(drm_kms_helper_poll_disable); |
|
- | 921 | ||
- | 922 | void drm_kms_helper_poll_enable(struct drm_device *dev) |
|
- | 923 | { |
|
- | 924 | bool poll = false; |
|
- | 925 | struct drm_connector *connector; |
|
- | 926 | ||
- | 927 | if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll) |
|
- | 928 | return; |
|
- | 929 | ||
- | 930 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
|
- | 931 | if (connector->polled) |
|
- | 932 | poll = true; |
|
- | 933 | } |
|
- | 934 | ||
- | 935 | if (poll) |
|
- | 936 | queue_delayed_work(system_nrt_wq, &dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); |
|
- | 937 | } |
|
- | 938 | EXPORT_SYMBOL(drm_kms_helper_poll_enable); |
|
- | 939 | ||
- | 940 | void drm_kms_helper_poll_init(struct drm_device *dev) |
|
- | 941 | { |
|
- | 942 | INIT_DELAYED_WORK(&dev->mode_config.output_poll_work, output_poll_execute); |
|
- | 943 | dev->mode_config.poll_enabled = true; |
|
- | 944 | ||
- | 945 | drm_kms_helper_poll_enable(dev); |
|
- | 946 | } |
|
- | 947 | EXPORT_SYMBOL(drm_kms_helper_poll_init); |
|
- | 948 | ||
- | 949 | void drm_kms_helper_poll_fini(struct drm_device *dev) |
|
- | 950 | { |
|
- | 951 | drm_kms_helper_poll_disable(dev); |
|
- | 952 | } |
|
- | 953 | EXPORT_SYMBOL(drm_kms_helper_poll_fini); |
|
- | 954 | ||
- | 955 | void drm_helper_hpd_irq_event(struct drm_device *dev) |
|
- | 956 | { |
|
- | 957 | if (!dev->mode_config.poll_enabled) |
|
- | 958 | return; |
|
- | 959 | ||
- | 960 | /* kill timer and schedule immediate execution, this doesn't block */ |
|
- | 961 | cancel_delayed_work(&dev->mode_config.output_poll_work); |
|
- | 962 | if (drm_kms_helper_poll) |
|
- | 963 | queue_delayed_work(system_nrt_wq, &dev->mode_config.output_poll_work, 0); |
|
- | 964 | } |
|
- | 965 | EXPORT_SYMBOL(drm_helper_hpd_irq_event); |
|
- | 966 |