.. | .. |
---|
32 | 32 | #include <linux/export.h> |
---|
33 | 33 | #include <linux/moduleparam.h> |
---|
34 | 34 | |
---|
35 | | -#include <drm/drmP.h> |
---|
| 35 | +#include <drm/drm_bridge.h> |
---|
36 | 36 | #include <drm/drm_client.h> |
---|
37 | 37 | #include <drm/drm_crtc.h> |
---|
38 | | -#include <drm/drm_fourcc.h> |
---|
39 | | -#include <drm/drm_crtc_helper.h> |
---|
40 | | -#include <drm/drm_fb_helper.h> |
---|
41 | 38 | #include <drm/drm_edid.h> |
---|
| 39 | +#include <drm/drm_fb_helper.h> |
---|
| 40 | +#include <drm/drm_fourcc.h> |
---|
42 | 41 | #include <drm/drm_modeset_helper_vtables.h> |
---|
| 42 | +#include <drm/drm_print.h> |
---|
| 43 | +#include <drm/drm_probe_helper.h> |
---|
| 44 | +#include <drm/drm_sysfs.h> |
---|
43 | 45 | |
---|
44 | 46 | #include "drm_crtc_helper_internal.h" |
---|
45 | 47 | |
---|
.. | .. |
---|
84 | 86 | return MODE_OK; |
---|
85 | 87 | } |
---|
86 | 88 | |
---|
87 | | -static enum drm_mode_status |
---|
| 89 | +static int |
---|
88 | 90 | drm_mode_validate_pipeline(struct drm_display_mode *mode, |
---|
89 | | - struct drm_connector *connector) |
---|
| 91 | + struct drm_connector *connector, |
---|
| 92 | + struct drm_modeset_acquire_ctx *ctx, |
---|
| 93 | + enum drm_mode_status *status) |
---|
90 | 94 | { |
---|
91 | 95 | struct drm_device *dev = connector->dev; |
---|
92 | | - enum drm_mode_status ret = MODE_OK; |
---|
93 | 96 | struct drm_encoder *encoder; |
---|
94 | | - int i; |
---|
| 97 | + int ret; |
---|
95 | 98 | |
---|
96 | 99 | /* Step 1: Validate against connector */ |
---|
97 | | - ret = drm_connector_mode_valid(connector, mode); |
---|
98 | | - if (ret != MODE_OK) |
---|
| 100 | + ret = drm_connector_mode_valid(connector, mode, ctx, status); |
---|
| 101 | + if (ret || *status != MODE_OK) |
---|
99 | 102 | return ret; |
---|
100 | 103 | |
---|
101 | 104 | /* Step 2: Validate against encoders and crtcs */ |
---|
102 | | - drm_connector_for_each_possible_encoder(connector, encoder, i) { |
---|
| 105 | + drm_connector_for_each_possible_encoder(connector, encoder) { |
---|
| 106 | + struct drm_bridge *bridge; |
---|
103 | 107 | struct drm_crtc *crtc; |
---|
104 | 108 | |
---|
105 | | - ret = drm_encoder_mode_valid(encoder, mode); |
---|
106 | | - if (ret != MODE_OK) { |
---|
| 109 | + *status = drm_encoder_mode_valid(encoder, mode); |
---|
| 110 | + if (*status != MODE_OK) { |
---|
107 | 111 | /* No point in continuing for crtc check as this encoder |
---|
108 | 112 | * will not accept the mode anyway. If all encoders |
---|
109 | 113 | * reject the mode then, at exit, ret will not be |
---|
.. | .. |
---|
111 | 115 | continue; |
---|
112 | 116 | } |
---|
113 | 117 | |
---|
114 | | - ret = drm_bridge_mode_valid(encoder->bridge, mode); |
---|
115 | | - if (ret != MODE_OK) { |
---|
| 118 | + bridge = drm_bridge_chain_get_first_bridge(encoder); |
---|
| 119 | + *status = drm_bridge_chain_mode_valid(bridge, |
---|
| 120 | + &connector->display_info, |
---|
| 121 | + mode); |
---|
| 122 | + if (*status != MODE_OK) { |
---|
116 | 123 | /* There is also no point in continuing for crtc check |
---|
117 | 124 | * here. */ |
---|
118 | 125 | continue; |
---|
.. | .. |
---|
122 | 129 | if (!drm_encoder_crtc_ok(encoder, crtc)) |
---|
123 | 130 | continue; |
---|
124 | 131 | |
---|
125 | | - ret = drm_crtc_mode_valid(crtc, mode); |
---|
126 | | - if (ret == MODE_OK) { |
---|
| 132 | + *status = drm_crtc_mode_valid(crtc, mode); |
---|
| 133 | + if (*status == MODE_OK) { |
---|
127 | 134 | /* If we get to this point there is at least |
---|
128 | 135 | * one combination of encoder+crtc that works |
---|
129 | 136 | * for this mode. Lets return now. */ |
---|
130 | | - return ret; |
---|
| 137 | + return 0; |
---|
131 | 138 | } |
---|
132 | 139 | } |
---|
133 | 140 | } |
---|
134 | 141 | |
---|
135 | | - return ret; |
---|
| 142 | + return 0; |
---|
136 | 143 | } |
---|
137 | 144 | |
---|
138 | 145 | static int drm_helper_probe_add_cmdline_mode(struct drm_connector *connector) |
---|
.. | .. |
---|
156 | 163 | continue; |
---|
157 | 164 | } |
---|
158 | 165 | |
---|
| 166 | + /* Mark the matching mode as being preferred by the user */ |
---|
| 167 | + mode->type |= DRM_MODE_TYPE_USERDEF; |
---|
159 | 168 | return 0; |
---|
160 | 169 | } |
---|
161 | 170 | |
---|
.. | .. |
---|
191 | 200 | return encoder_funcs->mode_valid(encoder, mode); |
---|
192 | 201 | } |
---|
193 | 202 | |
---|
194 | | -enum drm_mode_status drm_connector_mode_valid(struct drm_connector *connector, |
---|
195 | | - struct drm_display_mode *mode) |
---|
| 203 | +int |
---|
| 204 | +drm_connector_mode_valid(struct drm_connector *connector, |
---|
| 205 | + struct drm_display_mode *mode, |
---|
| 206 | + struct drm_modeset_acquire_ctx *ctx, |
---|
| 207 | + enum drm_mode_status *status) |
---|
196 | 208 | { |
---|
197 | 209 | const struct drm_connector_helper_funcs *connector_funcs = |
---|
198 | 210 | connector->helper_private; |
---|
| 211 | + int ret = 0; |
---|
199 | 212 | |
---|
200 | | - if (!connector_funcs || !connector_funcs->mode_valid) |
---|
201 | | - return MODE_OK; |
---|
| 213 | + if (!connector_funcs) |
---|
| 214 | + *status = MODE_OK; |
---|
| 215 | + else if (connector_funcs->mode_valid_ctx) |
---|
| 216 | + ret = connector_funcs->mode_valid_ctx(connector, mode, ctx, |
---|
| 217 | + status); |
---|
| 218 | + else if (connector_funcs->mode_valid) |
---|
| 219 | + *status = connector_funcs->mode_valid(connector, mode); |
---|
| 220 | + else |
---|
| 221 | + *status = MODE_OK; |
---|
202 | 222 | |
---|
203 | | - return connector_funcs->mode_valid(connector, mode); |
---|
| 223 | + return ret; |
---|
204 | 224 | } |
---|
205 | 225 | |
---|
206 | 226 | #define DRM_OUTPUT_POLL_PERIOD (10*HZ) |
---|
.. | .. |
---|
285 | 305 | if (WARN_ON(ret < 0)) |
---|
286 | 306 | ret = connector_status_unknown; |
---|
287 | 307 | |
---|
| 308 | + if (ret != connector->status) |
---|
| 309 | + connector->epoch_counter += 1; |
---|
| 310 | + |
---|
288 | 311 | drm_modeset_drop_locks(&ctx); |
---|
289 | 312 | drm_modeset_acquire_fini(&ctx); |
---|
290 | 313 | |
---|
.. | .. |
---|
318 | 341 | return ret; |
---|
319 | 342 | |
---|
320 | 343 | if (funcs->detect_ctx) |
---|
321 | | - return funcs->detect_ctx(connector, ctx, force); |
---|
| 344 | + ret = funcs->detect_ctx(connector, ctx, force); |
---|
322 | 345 | else if (connector->funcs->detect) |
---|
323 | | - return connector->funcs->detect(connector, force); |
---|
| 346 | + ret = connector->funcs->detect(connector, force); |
---|
324 | 347 | else |
---|
325 | | - return connector_status_connected; |
---|
| 348 | + ret = connector_status_connected; |
---|
| 349 | + |
---|
| 350 | + if (ret != connector->status) |
---|
| 351 | + connector->epoch_counter += 1; |
---|
| 352 | + |
---|
| 353 | + return ret; |
---|
326 | 354 | } |
---|
327 | 355 | EXPORT_SYMBOL(drm_helper_probe_detect); |
---|
328 | 356 | |
---|
.. | .. |
---|
370 | 398 | * (if specified) |
---|
371 | 399 | * - drm_mode_validate_flag() checks the modes against basic connector |
---|
372 | 400 | * capabilities (interlace_allowed,doublescan_allowed,stereo_allowed) |
---|
373 | | - * - the optional &drm_connector_helper_funcs.mode_valid helper can perform |
---|
374 | | - * driver and/or sink specific checks |
---|
| 401 | + * - the optional &drm_connector_helper_funcs.mode_valid or |
---|
| 402 | + * &drm_connector_helper_funcs.mode_valid_ctx helpers can perform driver |
---|
| 403 | + * and/or sink specific checks |
---|
375 | 404 | * - the optional &drm_crtc_helper_funcs.mode_valid, |
---|
376 | 405 | * &drm_bridge_funcs.mode_valid and &drm_encoder_helper_funcs.mode_valid |
---|
377 | 406 | * helpers can perform driver and/or source specific checks which are also |
---|
.. | .. |
---|
459 | 488 | */ |
---|
460 | 489 | dev->mode_config.delayed_event = true; |
---|
461 | 490 | if (dev->mode_config.poll_enabled) |
---|
462 | | - schedule_delayed_work(&dev->mode_config.output_poll_work, |
---|
463 | | - 0); |
---|
| 491 | + mod_delayed_work(system_wq, |
---|
| 492 | + &dev->mode_config.output_poll_work, |
---|
| 493 | + 0); |
---|
464 | 494 | } |
---|
465 | 495 | |
---|
466 | 496 | /* Re-enable polling in case the global poll config changed. */ |
---|
.. | .. |
---|
502 | 532 | mode_flags |= DRM_MODE_FLAG_3D_MASK; |
---|
503 | 533 | |
---|
504 | 534 | list_for_each_entry(mode, &connector->modes, head) { |
---|
505 | | - if (mode->status == MODE_OK) |
---|
506 | | - mode->status = drm_mode_validate_driver(dev, mode); |
---|
| 535 | + if (mode->status != MODE_OK) |
---|
| 536 | + continue; |
---|
507 | 537 | |
---|
508 | | - if (mode->status == MODE_OK) |
---|
509 | | - mode->status = drm_mode_validate_size(mode, maxX, maxY); |
---|
| 538 | + mode->status = drm_mode_validate_driver(dev, mode); |
---|
| 539 | + if (mode->status != MODE_OK) |
---|
| 540 | + continue; |
---|
510 | 541 | |
---|
511 | | - if (mode->status == MODE_OK) |
---|
512 | | - mode->status = drm_mode_validate_flag(mode, mode_flags); |
---|
| 542 | + mode->status = drm_mode_validate_size(mode, maxX, maxY); |
---|
| 543 | + if (mode->status != MODE_OK) |
---|
| 544 | + continue; |
---|
513 | 545 | |
---|
514 | | - if (mode->status == MODE_OK) |
---|
515 | | - mode->status = drm_mode_validate_pipeline(mode, |
---|
516 | | - connector); |
---|
| 546 | + mode->status = drm_mode_validate_flag(mode, mode_flags); |
---|
| 547 | + if (mode->status != MODE_OK) |
---|
| 548 | + continue; |
---|
517 | 549 | |
---|
518 | | - if (mode->status == MODE_OK) |
---|
519 | | - mode->status = drm_mode_validate_ycbcr420(mode, |
---|
520 | | - connector); |
---|
| 550 | + ret = drm_mode_validate_pipeline(mode, connector, &ctx, |
---|
| 551 | + &mode->status); |
---|
| 552 | + if (ret) { |
---|
| 553 | + drm_dbg_kms(dev, |
---|
| 554 | + "drm_mode_validate_pipeline failed: %d\n", |
---|
| 555 | + ret); |
---|
| 556 | + |
---|
| 557 | + if (drm_WARN_ON_ONCE(dev, ret != -EDEADLK)) { |
---|
| 558 | + mode->status = MODE_ERROR; |
---|
| 559 | + } else { |
---|
| 560 | + drm_modeset_backoff(&ctx); |
---|
| 561 | + goto retry; |
---|
| 562 | + } |
---|
| 563 | + } |
---|
| 564 | + |
---|
| 565 | + if (mode->status != MODE_OK) |
---|
| 566 | + continue; |
---|
| 567 | + mode->status = drm_mode_validate_ycbcr420(mode, connector); |
---|
521 | 568 | } |
---|
522 | 569 | |
---|
523 | 570 | prune: |
---|
.. | .. |
---|
528 | 575 | |
---|
529 | 576 | if (list_empty(&connector->modes)) |
---|
530 | 577 | return 0; |
---|
531 | | - |
---|
532 | | - list_for_each_entry(mode, &connector->modes, head) |
---|
533 | | - mode->vrefresh = drm_mode_vrefresh(mode); |
---|
534 | 578 | |
---|
535 | 579 | drm_mode_sort(&connector->modes); |
---|
536 | 580 | |
---|
.. | .. |
---|
580 | 624 | struct drm_connector_list_iter conn_iter; |
---|
581 | 625 | enum drm_connector_status old_status; |
---|
582 | 626 | bool repoll = false, changed; |
---|
| 627 | + u64 old_epoch_counter; |
---|
583 | 628 | |
---|
584 | 629 | if (!dev->mode_config.poll_enabled) |
---|
585 | 630 | return; |
---|
.. | .. |
---|
616 | 661 | |
---|
617 | 662 | repoll = true; |
---|
618 | 663 | |
---|
| 664 | + old_epoch_counter = connector->epoch_counter; |
---|
619 | 665 | connector->status = drm_helper_probe_detect(connector, NULL, false); |
---|
620 | | - if (old_status != connector->status) { |
---|
| 666 | + if (old_epoch_counter != connector->epoch_counter) { |
---|
621 | 667 | const char *old, *new; |
---|
622 | 668 | |
---|
623 | 669 | /* |
---|
.. | .. |
---|
646 | 692 | connector->base.id, |
---|
647 | 693 | connector->name, |
---|
648 | 694 | old, new); |
---|
| 695 | + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] epoch counter %llu -> %llu\n", |
---|
| 696 | + connector->base.id, connector->name, |
---|
| 697 | + old_epoch_counter, connector->epoch_counter); |
---|
649 | 698 | |
---|
650 | 699 | changed = true; |
---|
651 | 700 | } |
---|
.. | .. |
---|
775 | 824 | struct drm_connector_list_iter conn_iter; |
---|
776 | 825 | enum drm_connector_status old_status; |
---|
777 | 826 | bool changed = false; |
---|
| 827 | + u64 old_epoch_counter; |
---|
778 | 828 | |
---|
779 | 829 | if (!dev->mode_config.poll_enabled) |
---|
780 | 830 | return false; |
---|
.. | .. |
---|
788 | 838 | |
---|
789 | 839 | old_status = connector->status; |
---|
790 | 840 | |
---|
| 841 | + old_epoch_counter = connector->epoch_counter; |
---|
| 842 | + |
---|
| 843 | + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Old epoch counter %llu\n", connector->base.id, |
---|
| 844 | + connector->name, |
---|
| 845 | + old_epoch_counter); |
---|
| 846 | + |
---|
791 | 847 | connector->status = drm_helper_probe_detect(connector, NULL, false); |
---|
792 | 848 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", |
---|
793 | 849 | connector->base.id, |
---|
794 | 850 | connector->name, |
---|
795 | 851 | drm_get_connector_status_name(old_status), |
---|
796 | 852 | drm_get_connector_status_name(connector->status)); |
---|
797 | | - if (old_status != connector->status) |
---|
| 853 | + |
---|
| 854 | + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] New epoch counter %llu\n", |
---|
| 855 | + connector->base.id, |
---|
| 856 | + connector->name, |
---|
| 857 | + connector->epoch_counter); |
---|
| 858 | + |
---|
| 859 | + /* |
---|
| 860 | + * Check if epoch counter had changed, meaning that we need |
---|
| 861 | + * to send a uevent. |
---|
| 862 | + */ |
---|
| 863 | + if (old_epoch_counter != connector->epoch_counter) |
---|
798 | 864 | changed = true; |
---|
| 865 | + |
---|
799 | 866 | } |
---|
800 | 867 | drm_connector_list_iter_end(&conn_iter); |
---|
801 | 868 | mutex_unlock(&dev->mode_config.mutex); |
---|
802 | 869 | |
---|
803 | | - if (changed) |
---|
| 870 | + if (changed) { |
---|
804 | 871 | drm_kms_helper_hotplug_event(dev); |
---|
| 872 | + DRM_DEBUG_KMS("Sent hotplug event\n"); |
---|
| 873 | + } |
---|
805 | 874 | |
---|
806 | 875 | return changed; |
---|
807 | 876 | } |
---|