aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Jackson <ajax@redhat.com>2010-08-03 14:38:19 -0400
committerDave Airlie <airlied@redhat.com>2010-08-09 20:46:59 -0400
commit139315796778a6d5f67c644e2ff470ddc69efb7b (patch)
treef901f20f48429300ba9c8afec9c6a41430f000a5
parentcbba98f8f651a763fe9fd167efa65cd7b1fa22d9 (diff)
drm/edid: Rewrite mode parse to use the generic detailed block walk
This brings us in line with the EDID spec recommendation for mode priority sorting. We still don't extract all the modes we could from VTB, but VTB is so rare in the wild that I'm not really concerned. Signed-off-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/drm_edid.c526
1 files changed, 273 insertions, 253 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 1bf81b91b70f..4cbf7a587f16 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -34,6 +34,10 @@
34#include "drmP.h" 34#include "drmP.h"
35#include "drm_edid.h" 35#include "drm_edid.h"
36 36
37#define version_greater(edid, maj, min) \
38 (((edid)->version > (maj)) || \
39 ((edid)->version == (maj) && (edid)->revision > (min)))
40
37#define EDID_EST_TIMINGS 16 41#define EDID_EST_TIMINGS 16
38#define EDID_STD_TIMINGS 8 42#define EDID_STD_TIMINGS 8
39#define EDID_DETAILED_TIMINGS 4 43#define EDID_DETAILED_TIMINGS 4
@@ -62,6 +66,13 @@
62/* use +hsync +vsync for detailed mode */ 66/* use +hsync +vsync for detailed mode */
63#define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6) 67#define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6)
64 68
69struct detailed_mode_closure {
70 struct drm_connector *connector;
71 struct edid *edid;
72 bool preferred;
73 u32 quirks;
74 int modes;
75};
65 76
66#define LEVEL_DMT 0 77#define LEVEL_DMT 0
67#define LEVEL_GTF 1 78#define LEVEL_GTF 1
@@ -1101,117 +1112,6 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
1101 return mode; 1112 return mode;
1102} 1113}
1103 1114
1104/*
1105 * Detailed mode info for the EDID "established modes" data to use.
1106 */
1107static struct drm_display_mode edid_est_modes[] = {
1108 { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
1109 968, 1056, 0, 600, 601, 605, 628, 0,
1110 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@60Hz */
1111 { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
1112 896, 1024, 0, 600, 601, 603, 625, 0,
1113 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@56Hz */
1114 { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
1115 720, 840, 0, 480, 481, 484, 500, 0,
1116 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@75Hz */
1117 { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
1118 704, 832, 0, 480, 489, 491, 520, 0,
1119 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@72Hz */
1120 { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 30240, 640, 704,
1121 768, 864, 0, 480, 483, 486, 525, 0,
1122 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@67Hz */
1123 { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656,
1124 752, 800, 0, 480, 490, 492, 525, 0,
1125 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@60Hz */
1126 { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 738,
1127 846, 900, 0, 400, 421, 423, 449, 0,
1128 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 720x400@88Hz */
1129 { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 28320, 720, 738,
1130 846, 900, 0, 400, 412, 414, 449, 0,
1131 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 720x400@70Hz */
1132 { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
1133 1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
1134 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1280x1024@75Hz */
1135 { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78800, 1024, 1040,
1136 1136, 1312, 0, 768, 769, 772, 800, 0,
1137 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1024x768@75Hz */
1138 { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
1139 1184, 1328, 0, 768, 771, 777, 806, 0,
1140 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@70Hz */
1141 { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
1142 1184, 1344, 0, 768, 771, 777, 806, 0,
1143 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@60Hz */
1144 { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032,
1145 1208, 1264, 0, 768, 768, 776, 817, 0,
1146 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 1024x768@43Hz */
1147 { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864,
1148 928, 1152, 0, 624, 625, 628, 667, 0,
1149 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 832x624@75Hz */
1150 { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
1151 896, 1056, 0, 600, 601, 604, 625, 0,
1152 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@75Hz */
1153 { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
1154 976, 1040, 0, 600, 637, 643, 666, 0,
1155 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@72Hz */
1156 { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
1157 1344, 1600, 0, 864, 865, 868, 900, 0,
1158 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1152x864@75Hz */
1159};
1160
1161/**
1162 * add_established_modes - get est. modes from EDID and add them
1163 * @edid: EDID block to scan
1164 *
1165 * Each EDID block contains a bitmap of the supported "established modes" list
1166 * (defined above). Tease them out and add them to the global modes list.
1167 */
1168static int add_established_modes(struct drm_connector *connector, struct edid *edid)
1169{
1170 struct drm_device *dev = connector->dev;
1171 unsigned long est_bits = edid->established_timings.t1 |
1172 (edid->established_timings.t2 << 8) |
1173 ((edid->established_timings.mfg_rsvd & 0x80) << 9);
1174 int i, modes = 0;
1175
1176 for (i = 0; i <= EDID_EST_TIMINGS; i++)
1177 if (est_bits & (1<<i)) {
1178 struct drm_display_mode *newmode;
1179 newmode = drm_mode_duplicate(dev, &edid_est_modes[i]);
1180 if (newmode) {
1181 drm_mode_probed_add(connector, newmode);
1182 modes++;
1183 }
1184 }
1185
1186 return modes;
1187}
1188
1189/**
1190 * add_standard_modes - get std. modes from EDID and add them
1191 * @edid: EDID block to scan
1192 *
1193 * Standard modes can be calculated using the CVT standard. Grab them from
1194 * @edid, calculate them, and add them to the list.
1195 */
1196static int add_standard_modes(struct drm_connector *connector, struct edid *edid)
1197{
1198 int i, modes = 0;
1199
1200 for (i = 0; i < EDID_STD_TIMINGS; i++) {
1201 struct drm_display_mode *newmode;
1202
1203 newmode = drm_mode_std(connector, edid,
1204 &edid->standard_timings[i],
1205 edid->revision);
1206 if (newmode) {
1207 drm_mode_probed_add(connector, newmode);
1208 modes++;
1209 }
1210 }
1211
1212 return modes;
1213}
1214
1215static bool 1115static bool
1216mode_is_rb(struct drm_display_mode *mode) 1116mode_is_rb(struct drm_display_mode *mode)
1217{ 1117{
@@ -1321,55 +1221,87 @@ drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid,
1321 return modes; 1221 return modes;
1322} 1222}
1323 1223
1324static int drm_cvt_modes(struct drm_connector *connector, 1224static void
1325 struct detailed_timing *timing) 1225do_inferred_modes(struct detailed_timing *timing, void *c)
1326{ 1226{
1327 int i, j, modes = 0; 1227 struct detailed_mode_closure *closure = c;
1328 struct drm_display_mode *newmode; 1228 struct detailed_non_pixel *data = &timing->data.other_data;
1329 struct drm_device *dev = connector->dev; 1229 int gtf = (closure->edid->features & DRM_EDID_FEATURE_DEFAULT_GTF);
1330 struct cvt_timing *cvt;
1331 const int rates[] = { 60, 85, 75, 60, 50 };
1332 const u8 empty[3] = { 0, 0, 0 };
1333
1334 for (i = 0; i < 4; i++) {
1335 int uninitialized_var(width), height;
1336 cvt = &(timing->data.other_data.data.cvt[i]);
1337 1230
1338 if (!memcmp(cvt->code, empty, 3)) 1231 if (gtf && data->type == EDID_DETAIL_MONITOR_RANGE)
1339 continue; 1232 closure->modes += drm_gtf_modes_for_range(closure->connector,
1233 closure->edid,
1234 timing);
1235}
1340 1236
1341 height = (cvt->code[0] + ((cvt->code[1] & 0xf0) << 4) + 1) * 2; 1237static int
1342 switch (cvt->code[1] & 0x0c) { 1238add_inferred_modes(struct drm_connector *connector, struct edid *edid)
1343 case 0x00: 1239{
1344 width = height * 4 / 3; 1240 struct detailed_mode_closure closure = {
1345 break; 1241 connector, edid, 0, 0, 0
1346 case 0x04: 1242 };
1347 width = height * 16 / 9;
1348 break;
1349 case 0x08:
1350 width = height * 16 / 10;
1351 break;
1352 case 0x0c:
1353 width = height * 15 / 9;
1354 break;
1355 }
1356 1243
1357 for (j = 1; j < 5; j++) { 1244 if (version_greater(edid, 1, 0))
1358 if (cvt->code[2] & (1 << j)) { 1245 drm_for_each_detailed_block((u8 *)edid, do_inferred_modes,
1359 newmode = drm_cvt_mode(dev, width, height, 1246 &closure);
1360 rates[j], j == 0,
1361 false, false);
1362 if (newmode) {
1363 drm_mode_probed_add(connector, newmode);
1364 modes++;
1365 }
1366 }
1367 }
1368 }
1369 1247
1370 return modes; 1248 return closure.modes;
1371} 1249}
1372 1250
1251static struct drm_display_mode edid_est_modes[] = {
1252 { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
1253 968, 1056, 0, 600, 601, 605, 628, 0,
1254 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@60Hz */
1255 { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
1256 896, 1024, 0, 600, 601, 603, 625, 0,
1257 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@56Hz */
1258 { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
1259 720, 840, 0, 480, 481, 484, 500, 0,
1260 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@75Hz */
1261 { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
1262 704, 832, 0, 480, 489, 491, 520, 0,
1263 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@72Hz */
1264 { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 30240, 640, 704,
1265 768, 864, 0, 480, 483, 486, 525, 0,
1266 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@67Hz */
1267 { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656,
1268 752, 800, 0, 480, 490, 492, 525, 0,
1269 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@60Hz */
1270 { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 738,
1271 846, 900, 0, 400, 421, 423, 449, 0,
1272 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 720x400@88Hz */
1273 { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 28320, 720, 738,
1274 846, 900, 0, 400, 412, 414, 449, 0,
1275 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 720x400@70Hz */
1276 { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
1277 1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
1278 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1280x1024@75Hz */
1279 { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78800, 1024, 1040,
1280 1136, 1312, 0, 768, 769, 772, 800, 0,
1281 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1024x768@75Hz */
1282 { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
1283 1184, 1328, 0, 768, 771, 777, 806, 0,
1284 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@70Hz */
1285 { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
1286 1184, 1344, 0, 768, 771, 777, 806, 0,
1287 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@60Hz */
1288 { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032,
1289 1208, 1264, 0, 768, 768, 776, 817, 0,
1290 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 1024x768@43Hz */
1291 { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864,
1292 928, 1152, 0, 624, 625, 628, 667, 0,
1293 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 832x624@75Hz */
1294 { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
1295 896, 1056, 0, 600, 601, 604, 625, 0,
1296 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@75Hz */
1297 { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
1298 976, 1040, 0, 600, 637, 643, 666, 0,
1299 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@72Hz */
1300 { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
1301 1344, 1600, 0, 864, 865, 868, 900, 0,
1302 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1152x864@75Hz */
1303};
1304
1373static const struct { 1305static const struct {
1374 short w; 1306 short w;
1375 short h; 1307 short h;
@@ -1458,37 +1390,63 @@ drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing)
1458 return modes; 1390 return modes;
1459} 1391}
1460 1392
1461static int add_detailed_modes(struct drm_connector *connector, 1393static void
1462 struct detailed_timing *timing, 1394do_established_modes(struct detailed_timing *timing, void *c)
1463 struct edid *edid, u32 quirks, int preferred)
1464{ 1395{
1465 int i, modes = 0; 1396 struct detailed_mode_closure *closure = c;
1466 struct detailed_non_pixel *data = &timing->data.other_data; 1397 struct detailed_non_pixel *data = &timing->data.other_data;
1467 int gtf = (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF);
1468 struct drm_display_mode *newmode;
1469 struct drm_device *dev = connector->dev;
1470 1398
1471 if (timing->pixel_clock) { 1399 if (data->type == EDID_DETAIL_EST_TIMINGS)
1472 newmode = drm_mode_detailed(dev, edid, timing, quirks); 1400 closure->modes += drm_est3_modes(closure->connector, timing);
1473 if (!newmode) 1401}
1474 return 0;
1475 1402
1476 if (preferred) 1403/**
1477 newmode->type |= DRM_MODE_TYPE_PREFERRED; 1404 * add_established_modes - get est. modes from EDID and add them
1405 * @edid: EDID block to scan
1406 *
1407 * Each EDID block contains a bitmap of the supported "established modes" list
1408 * (defined above). Tease them out and add them to the global modes list.
1409 */
1410static int
1411add_established_modes(struct drm_connector *connector, struct edid *edid)
1412{
1413 struct drm_device *dev = connector->dev;
1414 unsigned long est_bits = edid->established_timings.t1 |
1415 (edid->established_timings.t2 << 8) |
1416 ((edid->established_timings.mfg_rsvd & 0x80) << 9);
1417 int i, modes = 0;
1418 struct detailed_mode_closure closure = {
1419 connector, edid, 0, 0, 0
1420 };
1478 1421
1479 drm_mode_probed_add(connector, newmode); 1422 for (i = 0; i <= EDID_EST_TIMINGS; i++) {
1480 return 1; 1423 if (est_bits & (1<<i)) {
1424 struct drm_display_mode *newmode;
1425 newmode = drm_mode_duplicate(dev, &edid_est_modes[i]);
1426 if (newmode) {
1427 drm_mode_probed_add(connector, newmode);
1428 modes++;
1429 }
1430 }
1481 } 1431 }
1482 1432
1483 /* other timing types */ 1433 if (version_greater(edid, 1, 0))
1484 switch (data->type) { 1434 drm_for_each_detailed_block((u8 *)edid,
1485 case EDID_DETAIL_MONITOR_RANGE: 1435 do_established_modes, &closure);
1486 if (gtf) 1436
1487 modes += drm_gtf_modes_for_range(connector, edid, 1437 return modes + closure.modes;
1488 timing); 1438}
1489 break; 1439
1490 case EDID_DETAIL_STD_MODES: 1440static void
1491 /* Six modes per detailed section */ 1441do_standard_modes(struct detailed_timing *timing, void *c)
1442{
1443 struct detailed_mode_closure *closure = c;
1444 struct detailed_non_pixel *data = &timing->data.other_data;
1445 struct drm_connector *connector = closure->connector;
1446 struct edid *edid = closure->edid;
1447
1448 if (data->type == EDID_DETAIL_STD_MODES) {
1449 int i;
1492 for (i = 0; i < 6; i++) { 1450 for (i = 0; i < 6; i++) {
1493 struct std_timing *std; 1451 struct std_timing *std;
1494 struct drm_display_mode *newmode; 1452 struct drm_display_mode *newmode;
@@ -1498,108 +1456,169 @@ static int add_detailed_modes(struct drm_connector *connector,
1498 edid->revision); 1456 edid->revision);
1499 if (newmode) { 1457 if (newmode) {
1500 drm_mode_probed_add(connector, newmode); 1458 drm_mode_probed_add(connector, newmode);
1501 modes++; 1459 closure->modes++;
1502 } 1460 }
1503 } 1461 }
1504 break;
1505 case EDID_DETAIL_CVT_3BYTE:
1506 modes += drm_cvt_modes(connector, timing);
1507 break;
1508 case EDID_DETAIL_EST_TIMINGS:
1509 modes += drm_est3_modes(connector, timing);
1510 break;
1511 default:
1512 break;
1513 } 1462 }
1514
1515 return modes;
1516} 1463}
1517 1464
1518/** 1465/**
1519 * add_detailed_info - get detailed mode info from EDID data 1466 * add_standard_modes - get std. modes from EDID and add them
1520 * @connector: attached connector
1521 * @edid: EDID block to scan 1467 * @edid: EDID block to scan
1522 * @quirks: quirks to apply
1523 * 1468 *
1524 * Some of the detailed timing sections may contain mode information. Grab 1469 * Standard modes can be calculated using the appropriate standard (DMT,
1525 * it and add it to the list. 1470 * GTF or CVT. Grab them from @edid and add them to the list.
1526 */ 1471 */
1527static int add_detailed_info(struct drm_connector *connector, 1472static int
1528 struct edid *edid, u32 quirks) 1473add_standard_modes(struct drm_connector *connector, struct edid *edid)
1529{ 1474{
1530 int i, modes = 0; 1475 int i, modes = 0;
1476 struct detailed_mode_closure closure = {
1477 connector, edid, 0, 0, 0
1478 };
1479
1480 for (i = 0; i < EDID_STD_TIMINGS; i++) {
1481 struct drm_display_mode *newmode;
1482
1483 newmode = drm_mode_std(connector, edid,
1484 &edid->standard_timings[i],
1485 edid->revision);
1486 if (newmode) {
1487 drm_mode_probed_add(connector, newmode);
1488 modes++;
1489 }
1490 }
1491
1492 if (version_greater(edid, 1, 0))
1493 drm_for_each_detailed_block((u8 *)edid, do_standard_modes,
1494 &closure);
1495
1496 /* XXX should also look for standard codes in VTB blocks */
1497
1498 return modes + closure.modes;
1499}
1531 1500
1532 for (i = 0; i < EDID_DETAILED_TIMINGS; i++) { 1501static int drm_cvt_modes(struct drm_connector *connector,
1533 struct detailed_timing *timing = &edid->detailed_timings[i]; 1502 struct detailed_timing *timing)
1534 int preferred = (i == 0); 1503{
1504 int i, j, modes = 0;
1505 struct drm_display_mode *newmode;
1506 struct drm_device *dev = connector->dev;
1507 struct cvt_timing *cvt;
1508 const int rates[] = { 60, 85, 75, 60, 50 };
1509 const u8 empty[3] = { 0, 0, 0 };
1535 1510
1536 if (preferred && edid->version == 1 && edid->revision < 4) 1511 for (i = 0; i < 4; i++) {
1537 preferred = (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING); 1512 int uninitialized_var(width), height;
1513 cvt = &(timing->data.other_data.data.cvt[i]);
1538 1514
1539 /* In 1.0, only timings are allowed */ 1515 if (!memcmp(cvt->code, empty, 3))
1540 if (!timing->pixel_clock && edid->version == 1 &&
1541 edid->revision == 0)
1542 continue; 1516 continue;
1543 1517
1544 modes += add_detailed_modes(connector, timing, edid, quirks, 1518 height = (cvt->code[0] + ((cvt->code[1] & 0xf0) << 4) + 1) * 2;
1545 preferred); 1519 switch (cvt->code[1] & 0x0c) {
1520 case 0x00:
1521 width = height * 4 / 3;
1522 break;
1523 case 0x04:
1524 width = height * 16 / 9;
1525 break;
1526 case 0x08:
1527 width = height * 16 / 10;
1528 break;
1529 case 0x0c:
1530 width = height * 15 / 9;
1531 break;
1532 }
1533
1534 for (j = 1; j < 5; j++) {
1535 if (cvt->code[2] & (1 << j)) {
1536 newmode = drm_cvt_mode(dev, width, height,
1537 rates[j], j == 0,
1538 false, false);
1539 if (newmode) {
1540 drm_mode_probed_add(connector, newmode);
1541 modes++;
1542 }
1543 }
1544 }
1546 } 1545 }
1547 1546
1548 return modes; 1547 return modes;
1549} 1548}
1550 1549
1551/** 1550static void
1552 * add_detailed_mode_eedid - get detailed mode info from addtional timing 1551do_cvt_mode(struct detailed_timing *timing, void *c)
1553 * EDID block
1554 * @connector: attached connector
1555 * @edid: EDID block to scan(It is only to get addtional timing EDID block)
1556 * @quirks: quirks to apply
1557 *
1558 * Some of the detailed timing sections may contain mode information. Grab
1559 * it and add it to the list.
1560 */
1561static int add_detailed_info_eedid(struct drm_connector *connector,
1562 struct edid *edid, u32 quirks)
1563{ 1552{
1564 int i, modes = 0; 1553 struct detailed_mode_closure *closure = c;
1565 char *edid_ext = NULL; 1554 struct detailed_non_pixel *data = &timing->data.other_data;
1566 struct detailed_timing *timing;
1567 int start_offset, end_offset;
1568 1555
1569 if (edid->version == 1 && edid->revision < 3) 1556 if (data->type == EDID_DETAIL_CVT_3BYTE)
1570 return 0; 1557 closure->modes += drm_cvt_modes(closure->connector, timing);
1571 if (!edid->extensions) 1558}
1572 return 0;
1573 1559
1574 /* Find CEA extension */ 1560static int
1575 for (i = 0; i < edid->extensions; i++) { 1561add_cvt_modes(struct drm_connector *connector, struct edid *edid)
1576 edid_ext = (char *)edid + EDID_LENGTH * (i + 1); 1562{
1577 if (edid_ext[0] == 0x02) 1563 struct detailed_mode_closure closure = {
1578 break; 1564 connector, edid, 0, 0, 0
1579 } 1565 };
1580 1566
1581 if (i == edid->extensions) 1567 if (version_greater(edid, 1, 2))
1582 return 0; 1568 drm_for_each_detailed_block((u8 *)edid, do_cvt_mode, &closure);
1583 1569
1584 /* Get the start offset of detailed timing block */ 1570 /* XXX should also look for CVT codes in VTB blocks */
1585 start_offset = edid_ext[2];
1586 if (start_offset == 0) {
1587 /* If the start_offset is zero, it means that neither detailed
1588 * info nor data block exist. In such case it is also
1589 * unnecessary to parse the detailed timing info.
1590 */
1591 return 0;
1592 }
1593 1571
1594 end_offset = EDID_LENGTH; 1572 return closure.modes;
1595 end_offset -= sizeof(struct detailed_timing); 1573}
1596 for (i = start_offset; i < end_offset; 1574
1597 i += sizeof(struct detailed_timing)) { 1575static void
1598 timing = (struct detailed_timing *)(edid_ext + i); 1576do_detailed_mode(struct detailed_timing *timing, void *c)
1599 modes += add_detailed_modes(connector, timing, edid, quirks, 0); 1577{
1578 struct detailed_mode_closure *closure = c;
1579 struct drm_display_mode *newmode;
1580
1581 if (timing->pixel_clock) {
1582 newmode = drm_mode_detailed(closure->connector->dev,
1583 closure->edid, timing,
1584 closure->quirks);
1585 if (!newmode)
1586 return;
1587
1588 if (closure->preferred)
1589 newmode->type |= DRM_MODE_TYPE_PREFERRED;
1590
1591 drm_mode_probed_add(closure->connector, newmode);
1592 closure->modes++;
1593 closure->preferred = 0;
1600 } 1594 }
1595}
1601 1596
1602 return modes; 1597/*
1598 * add_detailed_modes - Add modes from detailed timings
1599 * @connector: attached connector
1600 * @edid: EDID block to scan
1601 * @quirks: quirks to apply
1602 */
1603static int
1604add_detailed_modes(struct drm_connector *connector, struct edid *edid,
1605 u32 quirks)
1606{
1607 struct detailed_mode_closure closure = {
1608 connector,
1609 edid,
1610 1,
1611 quirks,
1612 0
1613 };
1614
1615 if (closure.preferred && !version_greater(edid, 1, 3))
1616 closure.preferred =
1617 (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING);
1618
1619 drm_for_each_detailed_block((u8 *)edid, do_detailed_mode, &closure);
1620
1621 return closure.modes;
1603} 1622}
1604 1623
1605#define HDMI_IDENTIFIER 0x000C03 1624#define HDMI_IDENTIFIER 0x000C03
@@ -1695,14 +1714,15 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
1695 * - established timing codes 1714 * - established timing codes
1696 * - modes inferred from GTF or CVT range information 1715 * - modes inferred from GTF or CVT range information
1697 * 1716 *
1698 * We don't quite implement this yet, but we're close. 1717 * We get this pretty much right.
1699 * 1718 *
1700 * XXX order for additional mode types in extension blocks? 1719 * XXX order for additional mode types in extension blocks?
1701 */ 1720 */
1702 num_modes += add_detailed_info(connector, edid, quirks); 1721 num_modes += add_detailed_modes(connector, edid, quirks);
1703 num_modes += add_detailed_info_eedid(connector, edid, quirks); 1722 num_modes += add_cvt_modes(connector, edid);
1704 num_modes += add_standard_modes(connector, edid); 1723 num_modes += add_standard_modes(connector, edid);
1705 num_modes += add_established_modes(connector, edid); 1724 num_modes += add_established_modes(connector, edid);
1725 num_modes += add_inferred_modes(connector, edid);
1706 1726
1707 if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) 1727 if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
1708 edid_fixup_preferred(connector, quirks); 1728 edid_fixup_preferred(connector, quirks);