aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_crtc_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/drm_crtc_helper.c')
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c490
1 files changed, 96 insertions, 394 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 51103aa469f8..764401951041 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -55,7 +55,7 @@ static void drm_mode_validate_flag(struct drm_connector *connector,
55} 55}
56 56
57/** 57/**
58 * drm_helper_probe_connector_modes - get complete set of display modes 58 * drm_helper_probe_single_connector_modes - get complete set of display modes
59 * @dev: DRM device 59 * @dev: DRM device
60 * @maxX: max width for modes 60 * @maxX: max width for modes
61 * @maxY: max height for modes 61 * @maxY: max height for modes
@@ -154,21 +154,6 @@ prune:
154} 154}
155EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); 155EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);
156 156
157int drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX,
158 uint32_t maxY)
159{
160 struct drm_connector *connector;
161 int count = 0;
162
163 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
164 count += drm_helper_probe_single_connector_modes(connector,
165 maxX, maxY);
166 }
167
168 return count;
169}
170EXPORT_SYMBOL(drm_helper_probe_connector_modes);
171
172/** 157/**
173 * drm_helper_encoder_in_use - check if a given encoder is in use 158 * drm_helper_encoder_in_use - check if a given encoder is in use
174 * @encoder: encoder to check 159 * @encoder: encoder to check
@@ -263,302 +248,6 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
263} 248}
264EXPORT_SYMBOL(drm_helper_disable_unused_functions); 249EXPORT_SYMBOL(drm_helper_disable_unused_functions);
265 250
266static struct drm_display_mode *drm_has_preferred_mode(struct drm_connector *connector, int width, int height)
267{
268 struct drm_display_mode *mode;
269
270 list_for_each_entry(mode, &connector->modes, head) {
271 if (drm_mode_width(mode) > width ||
272 drm_mode_height(mode) > height)
273 continue;
274 if (mode->type & DRM_MODE_TYPE_PREFERRED)
275 return mode;
276 }
277 return NULL;
278}
279
280static bool drm_has_cmdline_mode(struct drm_connector *connector)
281{
282 struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
283 struct drm_fb_helper_cmdline_mode *cmdline_mode;
284
285 if (!fb_help_conn)
286 return false;
287
288 cmdline_mode = &fb_help_conn->cmdline_mode;
289 return cmdline_mode->specified;
290}
291
292static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_connector *connector, int width, int height)
293{
294 struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
295 struct drm_fb_helper_cmdline_mode *cmdline_mode;
296 struct drm_display_mode *mode = NULL;
297
298 if (!fb_help_conn)
299 return mode;
300
301 cmdline_mode = &fb_help_conn->cmdline_mode;
302 if (cmdline_mode->specified == false)
303 return mode;
304
305 /* attempt to find a matching mode in the list of modes
306 * we have gotten so far, if not add a CVT mode that conforms
307 */
308 if (cmdline_mode->rb || cmdline_mode->margins)
309 goto create_mode;
310
311 list_for_each_entry(mode, &connector->modes, head) {
312 /* check width/height */
313 if (mode->hdisplay != cmdline_mode->xres ||
314 mode->vdisplay != cmdline_mode->yres)
315 continue;
316
317 if (cmdline_mode->refresh_specified) {
318 if (mode->vrefresh != cmdline_mode->refresh)
319 continue;
320 }
321
322 if (cmdline_mode->interlace) {
323 if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
324 continue;
325 }
326 return mode;
327 }
328
329create_mode:
330 mode = drm_cvt_mode(connector->dev, cmdline_mode->xres,
331 cmdline_mode->yres,
332 cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
333 cmdline_mode->rb, cmdline_mode->interlace,
334 cmdline_mode->margins);
335 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
336 list_add(&mode->head, &connector->modes);
337 return mode;
338}
339
340static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
341{
342 bool enable;
343
344 if (strict) {
345 enable = connector->status == connector_status_connected;
346 } else {
347 enable = connector->status != connector_status_disconnected;
348 }
349 return enable;
350}
351
352static void drm_enable_connectors(struct drm_device *dev, bool *enabled)
353{
354 bool any_enabled = false;
355 struct drm_connector *connector;
356 int i = 0;
357
358 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
359 enabled[i] = drm_connector_enabled(connector, true);
360 DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
361 enabled[i] ? "yes" : "no");
362 any_enabled |= enabled[i];
363 i++;
364 }
365
366 if (any_enabled)
367 return;
368
369 i = 0;
370 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
371 enabled[i] = drm_connector_enabled(connector, false);
372 i++;
373 }
374}
375
376static bool drm_target_preferred(struct drm_device *dev,
377 struct drm_display_mode **modes,
378 bool *enabled, int width, int height)
379{
380 struct drm_connector *connector;
381 int i = 0;
382
383 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
384
385 if (enabled[i] == false) {
386 i++;
387 continue;
388 }
389
390 DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
391 connector->base.id);
392
393 /* got for command line mode first */
394 modes[i] = drm_pick_cmdline_mode(connector, width, height);
395 if (!modes[i]) {
396 DRM_DEBUG_KMS("looking for preferred mode on connector %d\n",
397 connector->base.id);
398 modes[i] = drm_has_preferred_mode(connector, width, height);
399 }
400 /* No preferred modes, pick one off the list */
401 if (!modes[i] && !list_empty(&connector->modes)) {
402 list_for_each_entry(modes[i], &connector->modes, head)
403 break;
404 }
405 DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
406 "none");
407 i++;
408 }
409 return true;
410}
411
412static int drm_pick_crtcs(struct drm_device *dev,
413 struct drm_crtc **best_crtcs,
414 struct drm_display_mode **modes,
415 int n, int width, int height)
416{
417 int c, o;
418 struct drm_connector *connector;
419 struct drm_connector_helper_funcs *connector_funcs;
420 struct drm_encoder *encoder;
421 struct drm_crtc *best_crtc;
422 int my_score, best_score, score;
423 struct drm_crtc **crtcs, *crtc;
424
425 if (n == dev->mode_config.num_connector)
426 return 0;
427 c = 0;
428 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
429 if (c == n)
430 break;
431 c++;
432 }
433
434 best_crtcs[n] = NULL;
435 best_crtc = NULL;
436 best_score = drm_pick_crtcs(dev, best_crtcs, modes, n+1, width, height);
437 if (modes[n] == NULL)
438 return best_score;
439
440 crtcs = kmalloc(dev->mode_config.num_connector *
441 sizeof(struct drm_crtc *), GFP_KERNEL);
442 if (!crtcs)
443 return best_score;
444
445 my_score = 1;
446 if (connector->status == connector_status_connected)
447 my_score++;
448 if (drm_has_cmdline_mode(connector))
449 my_score++;
450 if (drm_has_preferred_mode(connector, width, height))
451 my_score++;
452
453 connector_funcs = connector->helper_private;
454 encoder = connector_funcs->best_encoder(connector);
455 if (!encoder)
456 goto out;
457
458 connector->encoder = encoder;
459
460 /* select a crtc for this connector and then attempt to configure
461 remaining connectors */
462 c = 0;
463 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
464
465 if ((encoder->possible_crtcs & (1 << c)) == 0) {
466 c++;
467 continue;
468 }
469
470 for (o = 0; o < n; o++)
471 if (best_crtcs[o] == crtc)
472 break;
473
474 if (o < n) {
475 /* ignore cloning for now */
476 c++;
477 continue;
478 }
479
480 crtcs[n] = crtc;
481 memcpy(crtcs, best_crtcs, n * sizeof(struct drm_crtc *));
482 score = my_score + drm_pick_crtcs(dev, crtcs, modes, n + 1,
483 width, height);
484 if (score > best_score) {
485 best_crtc = crtc;
486 best_score = score;
487 memcpy(best_crtcs, crtcs,
488 dev->mode_config.num_connector *
489 sizeof(struct drm_crtc *));
490 }
491 c++;
492 }
493out:
494 kfree(crtcs);
495 return best_score;
496}
497
498static void drm_setup_crtcs(struct drm_device *dev)
499{
500 struct drm_crtc **crtcs;
501 struct drm_display_mode **modes;
502 struct drm_encoder *encoder;
503 struct drm_connector *connector;
504 bool *enabled;
505 int width, height;
506 int i, ret;
507
508 DRM_DEBUG_KMS("\n");
509
510 width = dev->mode_config.max_width;
511 height = dev->mode_config.max_height;
512
513 /* clean out all the encoder/crtc combos */
514 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
515 encoder->crtc = NULL;
516 }
517
518 crtcs = kcalloc(dev->mode_config.num_connector,
519 sizeof(struct drm_crtc *), GFP_KERNEL);
520 modes = kcalloc(dev->mode_config.num_connector,
521 sizeof(struct drm_display_mode *), GFP_KERNEL);
522 enabled = kcalloc(dev->mode_config.num_connector,
523 sizeof(bool), GFP_KERNEL);
524
525 drm_enable_connectors(dev, enabled);
526
527 ret = drm_target_preferred(dev, modes, enabled, width, height);
528 if (!ret)
529 DRM_ERROR("Unable to find initial modes\n");
530
531 DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height);
532
533 drm_pick_crtcs(dev, crtcs, modes, 0, width, height);
534
535 i = 0;
536 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
537 struct drm_display_mode *mode = modes[i];
538 struct drm_crtc *crtc = crtcs[i];
539
540 if (connector->encoder == NULL) {
541 i++;
542 continue;
543 }
544
545 if (mode && crtc) {
546 DRM_DEBUG_KMS("desired mode %s set on crtc %d\n",
547 mode->name, crtc->base.id);
548 crtc->desired_mode = mode;
549 connector->encoder->crtc = crtc;
550 } else {
551 connector->encoder->crtc = NULL;
552 connector->encoder = NULL;
553 }
554 i++;
555 }
556
557 kfree(crtcs);
558 kfree(modes);
559 kfree(enabled);
560}
561
562/** 251/**
563 * drm_encoder_crtc_ok - can a given crtc drive a given encoder? 252 * drm_encoder_crtc_ok - can a given crtc drive a given encoder?
564 * @encoder: encoder to test 253 * @encoder: encoder to test
@@ -936,10 +625,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
936 ret = -EINVAL; 625 ret = -EINVAL;
937 goto fail; 626 goto fail;
938 } 627 }
939 /* TODO are these needed? */
940 set->crtc->desired_x = set->x;
941 set->crtc->desired_y = set->y;
942 set->crtc->desired_mode = set->mode;
943 } 628 }
944 drm_helper_disable_unused_functions(dev); 629 drm_helper_disable_unused_functions(dev);
945 } else if (fb_changed) { 630 } else if (fb_changed) {
@@ -984,63 +669,6 @@ fail:
984} 669}
985EXPORT_SYMBOL(drm_crtc_helper_set_config); 670EXPORT_SYMBOL(drm_crtc_helper_set_config);
986 671
987bool drm_helper_plugged_event(struct drm_device *dev)
988{
989 DRM_DEBUG_KMS("\n");
990
991 drm_helper_probe_connector_modes(dev, dev->mode_config.max_width,
992 dev->mode_config.max_height);
993
994 drm_setup_crtcs(dev);
995
996 /* alert the driver fb layer */
997 dev->mode_config.funcs->fb_changed(dev);
998
999 /* FIXME: send hotplug event */
1000 return true;
1001}
1002/**
1003 * drm_initial_config - setup a sane initial connector configuration
1004 * @dev: DRM device
1005 *
1006 * LOCKING:
1007 * Called at init time, must take mode config lock.
1008 *
1009 * Scan the CRTCs and connectors and try to put together an initial setup.
1010 * At the moment, this is a cloned configuration across all heads with
1011 * a new framebuffer object as the backing store.
1012 *
1013 * RETURNS:
1014 * Zero if everything went ok, nonzero otherwise.
1015 */
1016bool drm_helper_initial_config(struct drm_device *dev)
1017{
1018 int count = 0;
1019
1020 /* disable all the possible outputs/crtcs before entering KMS mode */
1021 drm_helper_disable_unused_functions(dev);
1022
1023 drm_fb_helper_parse_command_line(dev);
1024
1025 count = drm_helper_probe_connector_modes(dev,
1026 dev->mode_config.max_width,
1027 dev->mode_config.max_height);
1028
1029 /*
1030 * we shouldn't end up with no modes here.
1031 */
1032 if (count == 0)
1033 printk(KERN_INFO "No connectors reported connected with modes\n");
1034
1035 drm_setup_crtcs(dev);
1036
1037 /* alert the driver fb layer */
1038 dev->mode_config.funcs->fb_changed(dev);
1039
1040 return 0;
1041}
1042EXPORT_SYMBOL(drm_helper_initial_config);
1043
1044static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder) 672static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder)
1045{ 673{
1046 int dpms = DRM_MODE_DPMS_OFF; 674 int dpms = DRM_MODE_DPMS_OFF;
@@ -1123,27 +751,6 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
1123} 751}
1124EXPORT_SYMBOL(drm_helper_connector_dpms); 752EXPORT_SYMBOL(drm_helper_connector_dpms);
1125 753
1126/**
1127 * drm_hotplug_stage_two
1128 * @dev DRM device
1129 * @connector hotpluged connector
1130 *
1131 * LOCKING.
1132 * Caller must hold mode config lock, function might grab struct lock.
1133 *
1134 * Stage two of a hotplug.
1135 *
1136 * RETURNS:
1137 * Zero on success, errno on failure.
1138 */
1139int drm_helper_hotplug_stage_two(struct drm_device *dev)
1140{
1141 drm_helper_plugged_event(dev);
1142
1143 return 0;
1144}
1145EXPORT_SYMBOL(drm_helper_hotplug_stage_two);
1146
1147int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, 754int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
1148 struct drm_mode_fb_cmd *mode_cmd) 755 struct drm_mode_fb_cmd *mode_cmd)
1149{ 756{
@@ -1200,3 +807,98 @@ int drm_helper_resume_force_mode(struct drm_device *dev)
1200 return 0; 807 return 0;
1201} 808}
1202EXPORT_SYMBOL(drm_helper_resume_force_mode); 809EXPORT_SYMBOL(drm_helper_resume_force_mode);
810
811static struct slow_work_ops output_poll_ops;
812
813#define DRM_OUTPUT_POLL_PERIOD (10*HZ)
814static void output_poll_execute(struct slow_work *work)
815{
816 struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work);
817 struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_slow_work);
818 struct drm_connector *connector;
819 enum drm_connector_status old_status, status;
820 bool repoll = false, changed = false;
821 int ret;
822
823 mutex_lock(&dev->mode_config.mutex);
824 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
825
826 /* if this is HPD or polled don't check it -
827 TV out for instance */
828 if (!connector->polled)
829 continue;
830
831 else if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT))
832 repoll = true;
833
834 old_status = connector->status;
835 /* if we are connected and don't want to poll for disconnect
836 skip it */
837 if (old_status == connector_status_connected &&
838 !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT) &&
839 !(connector->polled & DRM_CONNECTOR_POLL_HPD))
840 continue;
841
842 status = connector->funcs->detect(connector);
843 if (old_status != status)
844 changed = true;
845 }
846
847 mutex_unlock(&dev->mode_config.mutex);
848
849 if (changed) {
850 /* send a uevent + call fbdev */
851 drm_sysfs_hotplug_event(dev);
852 if (dev->mode_config.funcs->output_poll_changed)
853 dev->mode_config.funcs->output_poll_changed(dev);
854 }
855
856 if (repoll) {
857 ret = delayed_slow_work_enqueue(delayed_work, DRM_OUTPUT_POLL_PERIOD);
858 if (ret)
859 DRM_ERROR("delayed enqueue failed %d\n", ret);
860 }
861}
862
863void drm_kms_helper_poll_init(struct drm_device *dev)
864{
865 struct drm_connector *connector;
866 bool poll = false;
867 int ret;
868
869 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
870 if (connector->polled)
871 poll = true;
872 }
873 slow_work_register_user(THIS_MODULE);
874 delayed_slow_work_init(&dev->mode_config.output_poll_slow_work,
875 &output_poll_ops);
876
877 if (poll) {
878 ret = delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, DRM_OUTPUT_POLL_PERIOD);
879 if (ret)
880 DRM_ERROR("delayed enqueue failed %d\n", ret);
881 }
882}
883EXPORT_SYMBOL(drm_kms_helper_poll_init);
884
885void drm_kms_helper_poll_fini(struct drm_device *dev)
886{
887 delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work);
888 slow_work_unregister_user(THIS_MODULE);
889}
890EXPORT_SYMBOL(drm_kms_helper_poll_fini);
891
892void drm_helper_hpd_irq_event(struct drm_device *dev)
893{
894 if (!dev->mode_config.poll_enabled)
895 return;
896 delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work);
897 /* schedule a slow work asap */
898 delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, 0);
899}
900EXPORT_SYMBOL(drm_helper_hpd_irq_event);
901
902static struct slow_work_ops output_poll_ops = {
903 .execute = output_poll_execute,
904};