diff options
| -rw-r--r-- | drivers/gpu/drm/drm_edid.c | 48 | ||||
| -rw-r--r-- | include/drm/drm_edid.h | 5 |
2 files changed, 53 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index cc8e69682714..30af8f3e6427 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
| @@ -897,6 +897,51 @@ static int drm_gtf_modes_for_range(struct drm_connector *connector, | |||
| 897 | return modes; | 897 | return modes; |
| 898 | } | 898 | } |
| 899 | 899 | ||
| 900 | static int drm_cvt_modes(struct drm_connector *connector, | ||
| 901 | struct detailed_timing *timing) | ||
| 902 | { | ||
| 903 | int i, j, modes = 0; | ||
| 904 | struct drm_display_mode *newmode; | ||
| 905 | struct drm_device *dev = connector->dev; | ||
| 906 | struct cvt_timing *cvt; | ||
| 907 | const int rates[] = { 60, 85, 75, 60, 50 }; | ||
| 908 | |||
| 909 | for (i = 0; i < 4; i++) { | ||
| 910 | int width, height; | ||
| 911 | cvt = &(timing->data.other_data.data.cvt[i]); | ||
| 912 | |||
| 913 | height = (cvt->code[0] + ((cvt->code[1] & 0xf0) << 8) + 1) * 2; | ||
| 914 | switch (cvt->code[1] & 0xc0) { | ||
| 915 | case 0x00: | ||
| 916 | width = height * 4 / 3; | ||
| 917 | break; | ||
| 918 | case 0x40: | ||
| 919 | width = height * 16 / 9; | ||
| 920 | break; | ||
| 921 | case 0x80: | ||
| 922 | width = height * 16 / 10; | ||
| 923 | break; | ||
| 924 | case 0xc0: | ||
| 925 | width = height * 15 / 9; | ||
| 926 | break; | ||
| 927 | } | ||
| 928 | |||
| 929 | for (j = 1; j < 5; j++) { | ||
| 930 | if (cvt->code[2] & (1 << j)) { | ||
| 931 | newmode = drm_cvt_mode(dev, width, height, | ||
| 932 | rates[j], j == 0, | ||
| 933 | false, false); | ||
| 934 | if (newmode) { | ||
| 935 | drm_mode_probed_add(connector, newmode); | ||
| 936 | modes++; | ||
| 937 | } | ||
| 938 | } | ||
| 939 | } | ||
| 940 | } | ||
| 941 | |||
| 942 | return modes; | ||
| 943 | } | ||
| 944 | |||
| 900 | static int add_detailed_modes(struct drm_connector *connector, | 945 | static int add_detailed_modes(struct drm_connector *connector, |
| 901 | struct detailed_timing *timing, | 946 | struct detailed_timing *timing, |
| 902 | struct edid *edid, u32 quirks, int preferred) | 947 | struct edid *edid, u32 quirks, int preferred) |
| @@ -941,6 +986,9 @@ static int add_detailed_modes(struct drm_connector *connector, | |||
| 941 | } | 986 | } |
| 942 | } | 987 | } |
| 943 | break; | 988 | break; |
| 989 | case EDID_DETAIL_CVT_3BYTE: | ||
| 990 | modes += drm_cvt_modes(connector, timing); | ||
| 991 | break; | ||
| 944 | default: | 992 | default: |
| 945 | break; | 993 | break; |
| 946 | } | 994 | } |
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 9087557fd83d..d33c3e038606 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h | |||
| @@ -106,6 +106,10 @@ struct detailed_data_color_point { | |||
| 106 | u8 wpindex2[3]; | 106 | u8 wpindex2[3]; |
| 107 | } __attribute__((packed)); | 107 | } __attribute__((packed)); |
| 108 | 108 | ||
| 109 | struct cvt_timing { | ||
| 110 | u8 code[3]; | ||
| 111 | } __attribute__((packed)); | ||
| 112 | |||
| 109 | struct detailed_non_pixel { | 113 | struct detailed_non_pixel { |
| 110 | u8 pad1; | 114 | u8 pad1; |
| 111 | u8 type; /* ff=serial, fe=string, fd=monitor range, fc=monitor name | 115 | u8 type; /* ff=serial, fe=string, fd=monitor range, fc=monitor name |
| @@ -117,6 +121,7 @@ struct detailed_non_pixel { | |||
| 117 | struct detailed_data_monitor_range range; | 121 | struct detailed_data_monitor_range range; |
| 118 | struct detailed_data_wpindex color; | 122 | struct detailed_data_wpindex color; |
| 119 | struct std_timing timings[5]; | 123 | struct std_timing timings[5]; |
| 124 | struct cvt_timing cvt[4]; | ||
| 120 | } data; | 125 | } data; |
| 121 | } __attribute__((packed)); | 126 | } __attribute__((packed)); |
| 122 | 127 | ||
