aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_edid.c
diff options
context:
space:
mode:
authorAdam Jackson <ajax@redhat.com>2010-03-29 17:43:27 -0400
committerDave Airlie <airlied@redhat.com>2010-04-05 20:40:23 -0400
commitb17e52ef7e7961f02baec98872781386218558bc (patch)
tree702ea1af46001c8bbf34aca156f2d18e40422499 /drivers/gpu/drm/drm_edid.c
parentd1ff6409b1cd2cd2a65df415648fa38b9fdf4cd8 (diff)
drm/edid: Extend range-based mode addition for EDID 1.4
1.4 adds better pixel clock precision, explicit reduced blanking awareness, and extended sync ranges. It's almost like a real spec. Signed-off-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r--drivers/gpu/drm/drm_edid.c101
1 files changed, 78 insertions, 23 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index a1b6b433e5bc..e746dd56658a 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -1066,36 +1066,89 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid
1066 return modes; 1066 return modes;
1067} 1067}
1068 1068
1069/*
1070 * XXX fix this for:
1071 * - GTF secondary curve formula
1072 * - EDID 1.4 range offsets
1073 * - CVT extended bits
1074 */
1075static bool 1069static bool
1076mode_in_range(struct drm_display_mode *mode, struct detailed_timing *timing) 1070mode_is_rb(struct drm_display_mode *mode)
1077{ 1071{
1078 struct detailed_data_monitor_range *range; 1072 return (mode->htotal - mode->hdisplay == 160) &&
1079 int hsync, vrefresh; 1073 (mode->hsync_end - mode->hdisplay == 80) &&
1080 1074 (mode->hsync_end - mode->hsync_start == 32) &&
1081 range = &timing->data.other_data.data.range; 1075 (mode->vsync_start - mode->vdisplay == 3);
1076}
1082 1077
1078static bool
1079mode_in_hsync_range(struct drm_display_mode *mode, struct edid *edid, u8 *t)
1080{
1081 int hsync, hmin, hmax;
1082
1083 hmin = t[7];
1084 if (edid->revision >= 4)
1085 hmin += ((t[4] & 0x04) ? 255 : 0);
1086 hmax = t[8];
1087 if (edid->revision >= 4)
1088 hmax += ((t[4] & 0x08) ? 255 : 0);
1083 hsync = drm_mode_hsync(mode); 1089 hsync = drm_mode_hsync(mode);
1084 vrefresh = drm_mode_vrefresh(mode);
1085 1090
1086 if (hsync < range->min_hfreq_khz || hsync > range->max_hfreq_khz) 1091 return (hsync <= hmax && hsync >= hmin);
1092}
1093
1094static bool
1095mode_in_vsync_range(struct drm_display_mode *mode, struct edid *edid, u8 *t)
1096{
1097 int vsync, vmin, vmax;
1098
1099 vmin = t[5];
1100 if (edid->revision >= 4)
1101 vmin += ((t[4] & 0x01) ? 255 : 0);
1102 vmax = t[6];
1103 if (edid->revision >= 4)
1104 vmax += ((t[4] & 0x02) ? 255 : 0);
1105 vsync = drm_mode_vrefresh(mode);
1106
1107 return (vsync <= vmax && vsync >= vmin);
1108}
1109
1110static u32
1111range_pixel_clock(struct edid *edid, u8 *t)
1112{
1113 /* unspecified */
1114 if (t[9] == 0 || t[9] == 255)
1115 return 0;
1116
1117 /* 1.4 with CVT support gives us real precision, yay */
1118 if (edid->revision >= 4 && t[10] == 0x04)
1119 return (t[9] * 10000) - ((t[12] >> 2) * 250);
1120
1121 /* 1.3 is pathetic, so fuzz up a bit */
1122 return t[9] * 10000 + 5001;
1123}
1124
1125/*
1126 * XXX fix this for GTF secondary curve formula
1127 */
1128static bool
1129mode_in_range(struct drm_display_mode *mode, struct edid *edid,
1130 struct detailed_timing *timing)
1131{
1132 u32 max_clock;
1133 u8 *t = (u8 *)timing;
1134
1135 if (!mode_in_hsync_range(mode, edid, t))
1087 return false; 1136 return false;
1088 1137
1089 if (vrefresh < range->min_vfreq || vrefresh > range->max_vfreq) 1138 if (!mode_in_vsync_range(mode, edid, t))
1090 return false; 1139 return false;
1091 1140
1092 if (range->pixel_clock_mhz && range->pixel_clock_mhz != 0xff) { 1141 if ((max_clock = range_pixel_clock(edid, t)))
1093 /* be forgiving since it's in units of 10MHz */
1094 int max_clock = range->pixel_clock_mhz * 10 + 9;
1095 max_clock *= 1000;
1096 if (mode->clock > max_clock) 1142 if (mode->clock > max_clock)
1097 return false; 1143 return false;
1098 } 1144
1145 /* 1.4 max horizontal check */
1146 if (edid->revision >= 4 && t[10] == 0x04)
1147 if (t[13] && mode->hdisplay > 8 * (t[13] + (256 * (t[12]&0x3))))
1148 return false;
1149
1150 if (mode_is_rb(mode) && !drm_monitor_supports_rb(edid))
1151 return false;
1099 1152
1100 return true; 1153 return true;
1101} 1154}
@@ -1104,15 +1157,16 @@ mode_in_range(struct drm_display_mode *mode, struct detailed_timing *timing)
1104 * XXX If drm_dmt_modes ever regrows the CVT-R modes (and it will) this will 1157 * XXX If drm_dmt_modes ever regrows the CVT-R modes (and it will) this will
1105 * need to account for them. 1158 * need to account for them.
1106 */ 1159 */
1107static int drm_gtf_modes_for_range(struct drm_connector *connector, 1160static int
1108 struct detailed_timing *timing) 1161drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid,
1162 struct detailed_timing *timing)
1109{ 1163{
1110 int i, modes = 0; 1164 int i, modes = 0;
1111 struct drm_display_mode *newmode; 1165 struct drm_display_mode *newmode;
1112 struct drm_device *dev = connector->dev; 1166 struct drm_device *dev = connector->dev;
1113 1167
1114 for (i = 0; i < drm_num_dmt_modes; i++) { 1168 for (i = 0; i < drm_num_dmt_modes; i++) {
1115 if (mode_in_range(drm_dmt_modes + i, timing)) { 1169 if (mode_in_range(drm_dmt_modes + i, edid, timing)) {
1116 newmode = drm_mode_duplicate(dev, &drm_dmt_modes[i]); 1170 newmode = drm_mode_duplicate(dev, &drm_dmt_modes[i]);
1117 if (newmode) { 1171 if (newmode) {
1118 drm_mode_probed_add(connector, newmode); 1172 drm_mode_probed_add(connector, newmode);
@@ -1288,7 +1342,8 @@ static int add_detailed_modes(struct drm_connector *connector,
1288 switch (data->type) { 1342 switch (data->type) {
1289 case EDID_DETAIL_MONITOR_RANGE: 1343 case EDID_DETAIL_MONITOR_RANGE:
1290 if (gtf) 1344 if (gtf)
1291 modes += drm_gtf_modes_for_range(connector, timing); 1345 modes += drm_gtf_modes_for_range(connector, edid,
1346 timing);
1292 break; 1347 break;
1293 case EDID_DETAIL_STD_MODES: 1348 case EDID_DETAIL_STD_MODES:
1294 /* Six modes per detailed section */ 1349 /* Six modes per detailed section */