diff options
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 94 |
1 files changed, 73 insertions, 21 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 2e678f1540ae..af62ba051501 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -2739,7 +2739,7 @@ static int | |||
2739 | do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len, | 2739 | do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len, |
2740 | const u8 *video_db, u8 video_len) | 2740 | const u8 *video_db, u8 video_len) |
2741 | { | 2741 | { |
2742 | int modes = 0, offset = 0, i, multi_present = 0; | 2742 | int modes = 0, offset = 0, i, multi_present = 0, multi_len; |
2743 | u8 vic_len, hdmi_3d_len = 0; | 2743 | u8 vic_len, hdmi_3d_len = 0; |
2744 | u16 mask; | 2744 | u16 mask; |
2745 | u16 structure_all; | 2745 | u16 structure_all; |
@@ -2785,32 +2785,84 @@ do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len, | |||
2785 | } | 2785 | } |
2786 | offset += 1 + vic_len; | 2786 | offset += 1 + vic_len; |
2787 | 2787 | ||
2788 | if (!(multi_present == 1 || multi_present == 2)) | 2788 | if (multi_present == 1) |
2789 | goto out; | 2789 | multi_len = 2; |
2790 | else if (multi_present == 2) | ||
2791 | multi_len = 4; | ||
2792 | else | ||
2793 | multi_len = 0; | ||
2790 | 2794 | ||
2791 | if ((multi_present == 1 && len < (9 + offset)) || | 2795 | if (len < (8 + offset + hdmi_3d_len - 1)) |
2792 | (multi_present == 2 && len < (11 + offset))) | ||
2793 | goto out; | 2796 | goto out; |
2794 | 2797 | ||
2795 | if ((multi_present == 1 && hdmi_3d_len < 2) || | 2798 | if (hdmi_3d_len < multi_len) |
2796 | (multi_present == 2 && hdmi_3d_len < 4)) | ||
2797 | goto out; | 2799 | goto out; |
2798 | 2800 | ||
2799 | /* 3D_Structure_ALL */ | 2801 | if (multi_present == 1 || multi_present == 2) { |
2800 | structure_all = (db[8 + offset] << 8) | db[9 + offset]; | 2802 | /* 3D_Structure_ALL */ |
2803 | structure_all = (db[8 + offset] << 8) | db[9 + offset]; | ||
2801 | 2804 | ||
2802 | /* check if 3D_MASK is present */ | 2805 | /* check if 3D_MASK is present */ |
2803 | if (multi_present == 2) | 2806 | if (multi_present == 2) |
2804 | mask = (db[10 + offset] << 8) | db[11 + offset]; | 2807 | mask = (db[10 + offset] << 8) | db[11 + offset]; |
2805 | else | 2808 | else |
2806 | mask = 0xffff; | 2809 | mask = 0xffff; |
2807 | 2810 | ||
2808 | for (i = 0; i < 16; i++) { | 2811 | for (i = 0; i < 16; i++) { |
2809 | if (mask & (1 << i)) | 2812 | if (mask & (1 << i)) |
2810 | modes += add_3d_struct_modes(connector, | 2813 | modes += add_3d_struct_modes(connector, |
2811 | structure_all, | 2814 | structure_all, |
2812 | video_db, | 2815 | video_db, |
2813 | video_len, i); | 2816 | video_len, i); |
2817 | } | ||
2818 | } | ||
2819 | |||
2820 | offset += multi_len; | ||
2821 | |||
2822 | for (i = 0; i < (hdmi_3d_len - multi_len); i++) { | ||
2823 | int vic_index; | ||
2824 | struct drm_display_mode *newmode = NULL; | ||
2825 | unsigned int newflag = 0; | ||
2826 | bool detail_present; | ||
2827 | |||
2828 | detail_present = ((db[8 + offset + i] & 0x0f) > 7); | ||
2829 | |||
2830 | if (detail_present && (i + 1 == hdmi_3d_len - multi_len)) | ||
2831 | break; | ||
2832 | |||
2833 | /* 2D_VIC_order_X */ | ||
2834 | vic_index = db[8 + offset + i] >> 4; | ||
2835 | |||
2836 | /* 3D_Structure_X */ | ||
2837 | switch (db[8 + offset + i] & 0x0f) { | ||
2838 | case 0: | ||
2839 | newflag = DRM_MODE_FLAG_3D_FRAME_PACKING; | ||
2840 | break; | ||
2841 | case 6: | ||
2842 | newflag = DRM_MODE_FLAG_3D_TOP_AND_BOTTOM; | ||
2843 | break; | ||
2844 | case 8: | ||
2845 | /* 3D_Detail_X */ | ||
2846 | if ((db[9 + offset + i] >> 4) == 1) | ||
2847 | newflag = DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF; | ||
2848 | break; | ||
2849 | } | ||
2850 | |||
2851 | if (newflag != 0) { | ||
2852 | newmode = drm_display_mode_from_vic_index(connector, | ||
2853 | video_db, | ||
2854 | video_len, | ||
2855 | vic_index); | ||
2856 | |||
2857 | if (newmode) { | ||
2858 | newmode->flags |= newflag; | ||
2859 | drm_mode_probed_add(connector, newmode); | ||
2860 | modes++; | ||
2861 | } | ||
2862 | } | ||
2863 | |||
2864 | if (detail_present) | ||
2865 | i++; | ||
2814 | } | 2866 | } |
2815 | 2867 | ||
2816 | out: | 2868 | out: |