diff options
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 314 |
1 files changed, 281 insertions, 33 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 830f7501cb4d..fb7cf0e796f6 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -458,6 +458,15 @@ static const struct drm_display_mode drm_dmt_modes[] = { | |||
458 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 458 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
459 | }; | 459 | }; |
460 | 460 | ||
461 | /* | ||
462 | * These more or less come from the DMT spec. The 720x400 modes are | ||
463 | * inferred from historical 80x25 practice. The 640x480@67 and 832x624@75 | ||
464 | * modes are old-school Mac modes. The EDID spec says the 1152x864@75 mode | ||
465 | * should be 1152x870, again for the Mac, but instead we use the x864 DMT | ||
466 | * mode. | ||
467 | * | ||
468 | * The DMT modes have been fact-checked; the rest are mild guesses. | ||
469 | */ | ||
461 | static const struct drm_display_mode edid_est_modes[] = { | 470 | static const struct drm_display_mode edid_est_modes[] = { |
462 | { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840, | 471 | { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840, |
463 | 968, 1056, 0, 600, 601, 605, 628, 0, | 472 | 968, 1056, 0, 600, 601, 605, 628, 0, |
@@ -560,7 +569,7 @@ static const struct minimode est3_modes[] = { | |||
560 | { 1600, 1200, 75, 0 }, | 569 | { 1600, 1200, 75, 0 }, |
561 | { 1600, 1200, 85, 0 }, | 570 | { 1600, 1200, 85, 0 }, |
562 | { 1792, 1344, 60, 0 }, | 571 | { 1792, 1344, 60, 0 }, |
563 | { 1792, 1344, 85, 0 }, | 572 | { 1792, 1344, 75, 0 }, |
564 | { 1856, 1392, 60, 0 }, | 573 | { 1856, 1392, 60, 0 }, |
565 | { 1856, 1392, 75, 0 }, | 574 | { 1856, 1392, 75, 0 }, |
566 | { 1920, 1200, 60, 1 }, | 575 | { 1920, 1200, 60, 1 }, |
@@ -1264,6 +1273,18 @@ struct edid *drm_get_edid(struct drm_connector *connector, | |||
1264 | } | 1273 | } |
1265 | EXPORT_SYMBOL(drm_get_edid); | 1274 | EXPORT_SYMBOL(drm_get_edid); |
1266 | 1275 | ||
1276 | /** | ||
1277 | * drm_edid_duplicate - duplicate an EDID and the extensions | ||
1278 | * @edid: EDID to duplicate | ||
1279 | * | ||
1280 | * Return duplicate edid or NULL on allocation failure. | ||
1281 | */ | ||
1282 | struct edid *drm_edid_duplicate(const struct edid *edid) | ||
1283 | { | ||
1284 | return kmemdup(edid, (edid->extensions + 1) * EDID_LENGTH, GFP_KERNEL); | ||
1285 | } | ||
1286 | EXPORT_SYMBOL(drm_edid_duplicate); | ||
1287 | |||
1267 | /*** EDID parsing ***/ | 1288 | /*** EDID parsing ***/ |
1268 | 1289 | ||
1269 | /** | 1290 | /** |
@@ -1308,7 +1329,7 @@ static u32 edid_get_quirks(struct edid *edid) | |||
1308 | } | 1329 | } |
1309 | 1330 | ||
1310 | #define MODE_SIZE(m) ((m)->hdisplay * (m)->vdisplay) | 1331 | #define MODE_SIZE(m) ((m)->hdisplay * (m)->vdisplay) |
1311 | #define MODE_REFRESH_DIFF(m,r) (abs((m)->vrefresh - target_refresh)) | 1332 | #define MODE_REFRESH_DIFF(c,t) (abs((c) - (t))) |
1312 | 1333 | ||
1313 | /** | 1334 | /** |
1314 | * edid_fixup_preferred - set preferred modes based on quirk list | 1335 | * edid_fixup_preferred - set preferred modes based on quirk list |
@@ -1323,6 +1344,7 @@ static void edid_fixup_preferred(struct drm_connector *connector, | |||
1323 | { | 1344 | { |
1324 | struct drm_display_mode *t, *cur_mode, *preferred_mode; | 1345 | struct drm_display_mode *t, *cur_mode, *preferred_mode; |
1325 | int target_refresh = 0; | 1346 | int target_refresh = 0; |
1347 | int cur_vrefresh, preferred_vrefresh; | ||
1326 | 1348 | ||
1327 | if (list_empty(&connector->probed_modes)) | 1349 | if (list_empty(&connector->probed_modes)) |
1328 | return; | 1350 | return; |
@@ -1345,10 +1367,14 @@ static void edid_fixup_preferred(struct drm_connector *connector, | |||
1345 | if (MODE_SIZE(cur_mode) > MODE_SIZE(preferred_mode)) | 1367 | if (MODE_SIZE(cur_mode) > MODE_SIZE(preferred_mode)) |
1346 | preferred_mode = cur_mode; | 1368 | preferred_mode = cur_mode; |
1347 | 1369 | ||
1370 | cur_vrefresh = cur_mode->vrefresh ? | ||
1371 | cur_mode->vrefresh : drm_mode_vrefresh(cur_mode); | ||
1372 | preferred_vrefresh = preferred_mode->vrefresh ? | ||
1373 | preferred_mode->vrefresh : drm_mode_vrefresh(preferred_mode); | ||
1348 | /* At a given size, try to get closest to target refresh */ | 1374 | /* At a given size, try to get closest to target refresh */ |
1349 | if ((MODE_SIZE(cur_mode) == MODE_SIZE(preferred_mode)) && | 1375 | if ((MODE_SIZE(cur_mode) == MODE_SIZE(preferred_mode)) && |
1350 | MODE_REFRESH_DIFF(cur_mode, target_refresh) < | 1376 | MODE_REFRESH_DIFF(cur_vrefresh, target_refresh) < |
1351 | MODE_REFRESH_DIFF(preferred_mode, target_refresh)) { | 1377 | MODE_REFRESH_DIFF(preferred_vrefresh, target_refresh)) { |
1352 | preferred_mode = cur_mode; | 1378 | preferred_mode = cur_mode; |
1353 | } | 1379 | } |
1354 | } | 1380 | } |
@@ -2068,7 +2094,7 @@ drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing) | |||
2068 | u8 *est = ((u8 *)timing) + 5; | 2094 | u8 *est = ((u8 *)timing) + 5; |
2069 | 2095 | ||
2070 | for (i = 0; i < 6; i++) { | 2096 | for (i = 0; i < 6; i++) { |
2071 | for (j = 7; j > 0; j--) { | 2097 | for (j = 7; j >= 0; j--) { |
2072 | m = (i * 8) + (7 - j); | 2098 | m = (i * 8) + (7 - j); |
2073 | if (m >= ARRAY_SIZE(est3_modes)) | 2099 | if (m >= ARRAY_SIZE(est3_modes)) |
2074 | break; | 2100 | break; |
@@ -2404,7 +2430,7 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match) | |||
2404 | 2430 | ||
2405 | if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) || | 2431 | if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) || |
2406 | KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) && | 2432 | KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) && |
2407 | drm_mode_equal_no_clocks(to_match, cea_mode)) | 2433 | drm_mode_equal_no_clocks_no_stereo(to_match, cea_mode)) |
2408 | return mode + 1; | 2434 | return mode + 1; |
2409 | } | 2435 | } |
2410 | return 0; | 2436 | return 0; |
@@ -2453,7 +2479,7 @@ static u8 drm_match_hdmi_mode(const struct drm_display_mode *to_match) | |||
2453 | 2479 | ||
2454 | if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) || | 2480 | if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) || |
2455 | KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) && | 2481 | KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) && |
2456 | drm_mode_equal_no_clocks(to_match, hdmi_mode)) | 2482 | drm_mode_equal_no_clocks_no_stereo(to_match, hdmi_mode)) |
2457 | return mode + 1; | 2483 | return mode + 1; |
2458 | } | 2484 | } |
2459 | return 0; | 2485 | return 0; |
@@ -2507,6 +2533,9 @@ add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid) | |||
2507 | if (!newmode) | 2533 | if (!newmode) |
2508 | continue; | 2534 | continue; |
2509 | 2535 | ||
2536 | /* Carry over the stereo flags */ | ||
2537 | newmode->flags |= mode->flags & DRM_MODE_FLAG_3D_MASK; | ||
2538 | |||
2510 | /* | 2539 | /* |
2511 | * The current mode could be either variant. Make | 2540 | * The current mode could be either variant. Make |
2512 | * sure to pick the "other" clock for the new mode. | 2541 | * sure to pick the "other" clock for the new mode. |
@@ -2553,20 +2582,151 @@ do_cea_modes(struct drm_connector *connector, const u8 *db, u8 len) | |||
2553 | return modes; | 2582 | return modes; |
2554 | } | 2583 | } |
2555 | 2584 | ||
2585 | struct stereo_mandatory_mode { | ||
2586 | int width, height, vrefresh; | ||
2587 | unsigned int flags; | ||
2588 | }; | ||
2589 | |||
2590 | static const struct stereo_mandatory_mode stereo_mandatory_modes[] = { | ||
2591 | { 1920, 1080, 24, DRM_MODE_FLAG_3D_TOP_AND_BOTTOM }, | ||
2592 | { 1920, 1080, 24, DRM_MODE_FLAG_3D_FRAME_PACKING }, | ||
2593 | { 1920, 1080, 50, | ||
2594 | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF }, | ||
2595 | { 1920, 1080, 60, | ||
2596 | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF }, | ||
2597 | { 1280, 720, 50, DRM_MODE_FLAG_3D_TOP_AND_BOTTOM }, | ||
2598 | { 1280, 720, 50, DRM_MODE_FLAG_3D_FRAME_PACKING }, | ||
2599 | { 1280, 720, 60, DRM_MODE_FLAG_3D_TOP_AND_BOTTOM }, | ||
2600 | { 1280, 720, 60, DRM_MODE_FLAG_3D_FRAME_PACKING } | ||
2601 | }; | ||
2602 | |||
2603 | static bool | ||
2604 | stereo_match_mandatory(const struct drm_display_mode *mode, | ||
2605 | const struct stereo_mandatory_mode *stereo_mode) | ||
2606 | { | ||
2607 | unsigned int interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE; | ||
2608 | |||
2609 | return mode->hdisplay == stereo_mode->width && | ||
2610 | mode->vdisplay == stereo_mode->height && | ||
2611 | interlaced == (stereo_mode->flags & DRM_MODE_FLAG_INTERLACE) && | ||
2612 | drm_mode_vrefresh(mode) == stereo_mode->vrefresh; | ||
2613 | } | ||
2614 | |||
2615 | static int add_hdmi_mandatory_stereo_modes(struct drm_connector *connector) | ||
2616 | { | ||
2617 | struct drm_device *dev = connector->dev; | ||
2618 | const struct drm_display_mode *mode; | ||
2619 | struct list_head stereo_modes; | ||
2620 | int modes = 0, i; | ||
2621 | |||
2622 | INIT_LIST_HEAD(&stereo_modes); | ||
2623 | |||
2624 | list_for_each_entry(mode, &connector->probed_modes, head) { | ||
2625 | for (i = 0; i < ARRAY_SIZE(stereo_mandatory_modes); i++) { | ||
2626 | const struct stereo_mandatory_mode *mandatory; | ||
2627 | struct drm_display_mode *new_mode; | ||
2628 | |||
2629 | if (!stereo_match_mandatory(mode, | ||
2630 | &stereo_mandatory_modes[i])) | ||
2631 | continue; | ||
2632 | |||
2633 | mandatory = &stereo_mandatory_modes[i]; | ||
2634 | new_mode = drm_mode_duplicate(dev, mode); | ||
2635 | if (!new_mode) | ||
2636 | continue; | ||
2637 | |||
2638 | new_mode->flags |= mandatory->flags; | ||
2639 | list_add_tail(&new_mode->head, &stereo_modes); | ||
2640 | modes++; | ||
2641 | } | ||
2642 | } | ||
2643 | |||
2644 | list_splice_tail(&stereo_modes, &connector->probed_modes); | ||
2645 | |||
2646 | return modes; | ||
2647 | } | ||
2648 | |||
2649 | static int add_hdmi_mode(struct drm_connector *connector, u8 vic) | ||
2650 | { | ||
2651 | struct drm_device *dev = connector->dev; | ||
2652 | struct drm_display_mode *newmode; | ||
2653 | |||
2654 | vic--; /* VICs start at 1 */ | ||
2655 | if (vic >= ARRAY_SIZE(edid_4k_modes)) { | ||
2656 | DRM_ERROR("Unknown HDMI VIC: %d\n", vic); | ||
2657 | return 0; | ||
2658 | } | ||
2659 | |||
2660 | newmode = drm_mode_duplicate(dev, &edid_4k_modes[vic]); | ||
2661 | if (!newmode) | ||
2662 | return 0; | ||
2663 | |||
2664 | drm_mode_probed_add(connector, newmode); | ||
2665 | |||
2666 | return 1; | ||
2667 | } | ||
2668 | |||
2669 | static int add_3d_struct_modes(struct drm_connector *connector, u16 structure, | ||
2670 | const u8 *video_db, u8 video_len, u8 video_index) | ||
2671 | { | ||
2672 | struct drm_device *dev = connector->dev; | ||
2673 | struct drm_display_mode *newmode; | ||
2674 | int modes = 0; | ||
2675 | u8 cea_mode; | ||
2676 | |||
2677 | if (video_db == NULL || video_index > video_len) | ||
2678 | return 0; | ||
2679 | |||
2680 | /* CEA modes are numbered 1..127 */ | ||
2681 | cea_mode = (video_db[video_index] & 127) - 1; | ||
2682 | if (cea_mode >= ARRAY_SIZE(edid_cea_modes)) | ||
2683 | return 0; | ||
2684 | |||
2685 | if (structure & (1 << 0)) { | ||
2686 | newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]); | ||
2687 | if (newmode) { | ||
2688 | newmode->flags |= DRM_MODE_FLAG_3D_FRAME_PACKING; | ||
2689 | drm_mode_probed_add(connector, newmode); | ||
2690 | modes++; | ||
2691 | } | ||
2692 | } | ||
2693 | if (structure & (1 << 6)) { | ||
2694 | newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]); | ||
2695 | if (newmode) { | ||
2696 | newmode->flags |= DRM_MODE_FLAG_3D_TOP_AND_BOTTOM; | ||
2697 | drm_mode_probed_add(connector, newmode); | ||
2698 | modes++; | ||
2699 | } | ||
2700 | } | ||
2701 | if (structure & (1 << 8)) { | ||
2702 | newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]); | ||
2703 | if (newmode) { | ||
2704 | newmode->flags = DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF; | ||
2705 | drm_mode_probed_add(connector, newmode); | ||
2706 | modes++; | ||
2707 | } | ||
2708 | } | ||
2709 | |||
2710 | return modes; | ||
2711 | } | ||
2712 | |||
2556 | /* | 2713 | /* |
2557 | * do_hdmi_vsdb_modes - Parse the HDMI Vendor Specific data block | 2714 | * do_hdmi_vsdb_modes - Parse the HDMI Vendor Specific data block |
2558 | * @connector: connector corresponding to the HDMI sink | 2715 | * @connector: connector corresponding to the HDMI sink |
2559 | * @db: start of the CEA vendor specific block | 2716 | * @db: start of the CEA vendor specific block |
2560 | * @len: length of the CEA block payload, ie. one can access up to db[len] | 2717 | * @len: length of the CEA block payload, ie. one can access up to db[len] |
2561 | * | 2718 | * |
2562 | * Parses the HDMI VSDB looking for modes to add to @connector. | 2719 | * Parses the HDMI VSDB looking for modes to add to @connector. This function |
2720 | * also adds the stereo 3d modes when applicable. | ||
2563 | */ | 2721 | */ |
2564 | static int | 2722 | static int |
2565 | do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len) | 2723 | do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len, |
2724 | const u8 *video_db, u8 video_len) | ||
2566 | { | 2725 | { |
2567 | struct drm_device *dev = connector->dev; | 2726 | int modes = 0, offset = 0, i, multi_present = 0; |
2568 | int modes = 0, offset = 0, i; | 2727 | u8 vic_len, hdmi_3d_len = 0; |
2569 | u8 vic_len; | 2728 | u16 mask; |
2729 | u16 structure_all; | ||
2570 | 2730 | ||
2571 | if (len < 8) | 2731 | if (len < 8) |
2572 | goto out; | 2732 | goto out; |
@@ -2585,30 +2745,56 @@ do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len) | |||
2585 | 2745 | ||
2586 | /* the declared length is not long enough for the 2 first bytes | 2746 | /* the declared length is not long enough for the 2 first bytes |
2587 | * of additional video format capabilities */ | 2747 | * of additional video format capabilities */ |
2588 | offset += 2; | 2748 | if (len < (8 + offset + 2)) |
2589 | if (len < (8 + offset)) | ||
2590 | goto out; | 2749 | goto out; |
2591 | 2750 | ||
2751 | /* 3D_Present */ | ||
2752 | offset++; | ||
2753 | if (db[8 + offset] & (1 << 7)) { | ||
2754 | modes += add_hdmi_mandatory_stereo_modes(connector); | ||
2755 | |||
2756 | /* 3D_Multi_present */ | ||
2757 | multi_present = (db[8 + offset] & 0x60) >> 5; | ||
2758 | } | ||
2759 | |||
2760 | offset++; | ||
2592 | vic_len = db[8 + offset] >> 5; | 2761 | vic_len = db[8 + offset] >> 5; |
2762 | hdmi_3d_len = db[8 + offset] & 0x1f; | ||
2593 | 2763 | ||
2594 | for (i = 0; i < vic_len && len >= (9 + offset + i); i++) { | 2764 | for (i = 0; i < vic_len && len >= (9 + offset + i); i++) { |
2595 | struct drm_display_mode *newmode; | ||
2596 | u8 vic; | 2765 | u8 vic; |
2597 | 2766 | ||
2598 | vic = db[9 + offset + i]; | 2767 | vic = db[9 + offset + i]; |
2768 | modes += add_hdmi_mode(connector, vic); | ||
2769 | } | ||
2770 | offset += 1 + vic_len; | ||
2599 | 2771 | ||
2600 | vic--; /* VICs start at 1 */ | 2772 | if (!(multi_present == 1 || multi_present == 2)) |
2601 | if (vic >= ARRAY_SIZE(edid_4k_modes)) { | 2773 | goto out; |
2602 | DRM_ERROR("Unknown HDMI VIC: %d\n", vic); | ||
2603 | continue; | ||
2604 | } | ||
2605 | 2774 | ||
2606 | newmode = drm_mode_duplicate(dev, &edid_4k_modes[vic]); | 2775 | if ((multi_present == 1 && len < (9 + offset)) || |
2607 | if (!newmode) | 2776 | (multi_present == 2 && len < (11 + offset))) |
2608 | continue; | 2777 | goto out; |
2609 | 2778 | ||
2610 | drm_mode_probed_add(connector, newmode); | 2779 | if ((multi_present == 1 && hdmi_3d_len < 2) || |
2611 | modes++; | 2780 | (multi_present == 2 && hdmi_3d_len < 4)) |
2781 | goto out; | ||
2782 | |||
2783 | /* 3D_Structure_ALL */ | ||
2784 | structure_all = (db[8 + offset] << 8) | db[9 + offset]; | ||
2785 | |||
2786 | /* check if 3D_MASK is present */ | ||
2787 | if (multi_present == 2) | ||
2788 | mask = (db[10 + offset] << 8) | db[11 + offset]; | ||
2789 | else | ||
2790 | mask = 0xffff; | ||
2791 | |||
2792 | for (i = 0; i < 16; i++) { | ||
2793 | if (mask & (1 << i)) | ||
2794 | modes += add_3d_struct_modes(connector, | ||
2795 | structure_all, | ||
2796 | video_db, | ||
2797 | video_len, i); | ||
2612 | } | 2798 | } |
2613 | 2799 | ||
2614 | out: | 2800 | out: |
@@ -2668,8 +2854,8 @@ static int | |||
2668 | add_cea_modes(struct drm_connector *connector, struct edid *edid) | 2854 | add_cea_modes(struct drm_connector *connector, struct edid *edid) |
2669 | { | 2855 | { |
2670 | const u8 *cea = drm_find_cea_extension(edid); | 2856 | const u8 *cea = drm_find_cea_extension(edid); |
2671 | const u8 *db; | 2857 | const u8 *db, *hdmi = NULL, *video = NULL; |
2672 | u8 dbl; | 2858 | u8 dbl, hdmi_len, video_len = 0; |
2673 | int modes = 0; | 2859 | int modes = 0; |
2674 | 2860 | ||
2675 | if (cea && cea_revision(cea) >= 3) { | 2861 | if (cea && cea_revision(cea) >= 3) { |
@@ -2682,13 +2868,26 @@ add_cea_modes(struct drm_connector *connector, struct edid *edid) | |||
2682 | db = &cea[i]; | 2868 | db = &cea[i]; |
2683 | dbl = cea_db_payload_len(db); | 2869 | dbl = cea_db_payload_len(db); |
2684 | 2870 | ||
2685 | if (cea_db_tag(db) == VIDEO_BLOCK) | 2871 | if (cea_db_tag(db) == VIDEO_BLOCK) { |
2686 | modes += do_cea_modes(connector, db + 1, dbl); | 2872 | video = db + 1; |
2687 | else if (cea_db_is_hdmi_vsdb(db)) | 2873 | video_len = dbl; |
2688 | modes += do_hdmi_vsdb_modes(connector, db, dbl); | 2874 | modes += do_cea_modes(connector, video, dbl); |
2875 | } | ||
2876 | else if (cea_db_is_hdmi_vsdb(db)) { | ||
2877 | hdmi = db; | ||
2878 | hdmi_len = dbl; | ||
2879 | } | ||
2689 | } | 2880 | } |
2690 | } | 2881 | } |
2691 | 2882 | ||
2883 | /* | ||
2884 | * We parse the HDMI VSDB after having added the cea modes as we will | ||
2885 | * be patching their flags when the sink supports stereo 3D. | ||
2886 | */ | ||
2887 | if (hdmi) | ||
2888 | modes += do_hdmi_vsdb_modes(connector, hdmi, hdmi_len, video, | ||
2889 | video_len); | ||
2890 | |||
2692 | return modes; | 2891 | return modes; |
2693 | } | 2892 | } |
2694 | 2893 | ||
@@ -3288,6 +3487,19 @@ int drm_add_modes_noedid(struct drm_connector *connector, | |||
3288 | } | 3487 | } |
3289 | EXPORT_SYMBOL(drm_add_modes_noedid); | 3488 | EXPORT_SYMBOL(drm_add_modes_noedid); |
3290 | 3489 | ||
3490 | void drm_set_preferred_mode(struct drm_connector *connector, | ||
3491 | int hpref, int vpref) | ||
3492 | { | ||
3493 | struct drm_display_mode *mode; | ||
3494 | |||
3495 | list_for_each_entry(mode, &connector->probed_modes, head) { | ||
3496 | if (drm_mode_width(mode) == hpref && | ||
3497 | drm_mode_height(mode) == vpref) | ||
3498 | mode->type |= DRM_MODE_TYPE_PREFERRED; | ||
3499 | } | ||
3500 | } | ||
3501 | EXPORT_SYMBOL(drm_set_preferred_mode); | ||
3502 | |||
3291 | /** | 3503 | /** |
3292 | * drm_hdmi_avi_infoframe_from_display_mode() - fill an HDMI AVI infoframe with | 3504 | * drm_hdmi_avi_infoframe_from_display_mode() - fill an HDMI AVI infoframe with |
3293 | * data from a DRM display mode | 3505 | * data from a DRM display mode |
@@ -3321,6 +3533,33 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, | |||
3321 | } | 3533 | } |
3322 | EXPORT_SYMBOL(drm_hdmi_avi_infoframe_from_display_mode); | 3534 | EXPORT_SYMBOL(drm_hdmi_avi_infoframe_from_display_mode); |
3323 | 3535 | ||
3536 | static enum hdmi_3d_structure | ||
3537 | s3d_structure_from_display_mode(const struct drm_display_mode *mode) | ||
3538 | { | ||
3539 | u32 layout = mode->flags & DRM_MODE_FLAG_3D_MASK; | ||
3540 | |||
3541 | switch (layout) { | ||
3542 | case DRM_MODE_FLAG_3D_FRAME_PACKING: | ||
3543 | return HDMI_3D_STRUCTURE_FRAME_PACKING; | ||
3544 | case DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE: | ||
3545 | return HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE; | ||
3546 | case DRM_MODE_FLAG_3D_LINE_ALTERNATIVE: | ||
3547 | return HDMI_3D_STRUCTURE_LINE_ALTERNATIVE; | ||
3548 | case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL: | ||
3549 | return HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL; | ||
3550 | case DRM_MODE_FLAG_3D_L_DEPTH: | ||
3551 | return HDMI_3D_STRUCTURE_L_DEPTH; | ||
3552 | case DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH: | ||
3553 | return HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH; | ||
3554 | case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM: | ||
3555 | return HDMI_3D_STRUCTURE_TOP_AND_BOTTOM; | ||
3556 | case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF: | ||
3557 | return HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF; | ||
3558 | default: | ||
3559 | return HDMI_3D_STRUCTURE_INVALID; | ||
3560 | } | ||
3561 | } | ||
3562 | |||
3324 | /** | 3563 | /** |
3325 | * drm_hdmi_vendor_infoframe_from_display_mode() - fill an HDMI infoframe with | 3564 | * drm_hdmi_vendor_infoframe_from_display_mode() - fill an HDMI infoframe with |
3326 | * data from a DRM display mode | 3565 | * data from a DRM display mode |
@@ -3338,20 +3577,29 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, | |||
3338 | const struct drm_display_mode *mode) | 3577 | const struct drm_display_mode *mode) |
3339 | { | 3578 | { |
3340 | int err; | 3579 | int err; |
3580 | u32 s3d_flags; | ||
3341 | u8 vic; | 3581 | u8 vic; |
3342 | 3582 | ||
3343 | if (!frame || !mode) | 3583 | if (!frame || !mode) |
3344 | return -EINVAL; | 3584 | return -EINVAL; |
3345 | 3585 | ||
3346 | vic = drm_match_hdmi_mode(mode); | 3586 | vic = drm_match_hdmi_mode(mode); |
3347 | if (!vic) | 3587 | s3d_flags = mode->flags & DRM_MODE_FLAG_3D_MASK; |
3588 | |||
3589 | if (!vic && !s3d_flags) | ||
3590 | return -EINVAL; | ||
3591 | |||
3592 | if (vic && s3d_flags) | ||
3348 | return -EINVAL; | 3593 | return -EINVAL; |
3349 | 3594 | ||
3350 | err = hdmi_vendor_infoframe_init(frame); | 3595 | err = hdmi_vendor_infoframe_init(frame); |
3351 | if (err < 0) | 3596 | if (err < 0) |
3352 | return err; | 3597 | return err; |
3353 | 3598 | ||
3354 | frame->vic = vic; | 3599 | if (vic) |
3600 | frame->vic = vic; | ||
3601 | else | ||
3602 | frame->s3d_struct = s3d_structure_from_display_mode(mode); | ||
3355 | 3603 | ||
3356 | return 0; | 3604 | return 0; |
3357 | } | 3605 | } |