aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/drm_edid.c94
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
2739do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len, 2739do_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
2816out: 2868out: