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.c391
1 files changed, 1 insertions, 390 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 51103aa469f8..9d23f54673d3 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
@@ -984,63 +673,6 @@ fail:
984} 673}
985EXPORT_SYMBOL(drm_crtc_helper_set_config); 674EXPORT_SYMBOL(drm_crtc_helper_set_config);
986 675
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) 676static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder)
1045{ 677{
1046 int dpms = DRM_MODE_DPMS_OFF; 678 int dpms = DRM_MODE_DPMS_OFF;
@@ -1123,27 +755,6 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
1123} 755}
1124EXPORT_SYMBOL(drm_helper_connector_dpms); 756EXPORT_SYMBOL(drm_helper_connector_dpms);
1125 757
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, 758int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
1148 struct drm_mode_fb_cmd *mode_cmd) 759 struct drm_mode_fb_cmd *mode_cmd)
1149{ 760{