diff options
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 103 |
1 files changed, 67 insertions, 36 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 3e927ce7557d..ece03fc2d386 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -508,25 +508,10 @@ static void | |||
508 | cea_for_each_detailed_block(u8 *ext, detailed_cb *cb, void *closure) | 508 | cea_for_each_detailed_block(u8 *ext, detailed_cb *cb, void *closure) |
509 | { | 509 | { |
510 | int i, n = 0; | 510 | int i, n = 0; |
511 | u8 rev = ext[0x01], d = ext[0x02]; | 511 | u8 d = ext[0x02]; |
512 | u8 *det_base = ext + d; | 512 | u8 *det_base = ext + d; |
513 | 513 | ||
514 | switch (rev) { | 514 | n = (127 - d) / 18; |
515 | case 0: | ||
516 | /* can't happen */ | ||
517 | return; | ||
518 | case 1: | ||
519 | /* have to infer how many blocks we have, check pixel clock */ | ||
520 | for (i = 0; i < 6; i++) | ||
521 | if (det_base[18*i] || det_base[18*i+1]) | ||
522 | n++; | ||
523 | break; | ||
524 | default: | ||
525 | /* explicit count */ | ||
526 | n = min(ext[0x03] & 0x0f, 6); | ||
527 | break; | ||
528 | } | ||
529 | |||
530 | for (i = 0; i < n; i++) | 515 | for (i = 0; i < n; i++) |
531 | cb((struct detailed_timing *)(det_base + 18 * i), closure); | 516 | cb((struct detailed_timing *)(det_base + 18 * i), closure); |
532 | } | 517 | } |
@@ -1319,6 +1304,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid, | |||
1319 | 1304 | ||
1320 | #define HDMI_IDENTIFIER 0x000C03 | 1305 | #define HDMI_IDENTIFIER 0x000C03 |
1321 | #define AUDIO_BLOCK 0x01 | 1306 | #define AUDIO_BLOCK 0x01 |
1307 | #define VIDEO_BLOCK 0x02 | ||
1322 | #define VENDOR_BLOCK 0x03 | 1308 | #define VENDOR_BLOCK 0x03 |
1323 | #define SPEAKER_BLOCK 0x04 | 1309 | #define SPEAKER_BLOCK 0x04 |
1324 | #define EDID_BASIC_AUDIO (1 << 6) | 1310 | #define EDID_BASIC_AUDIO (1 << 6) |
@@ -1349,6 +1335,47 @@ u8 *drm_find_cea_extension(struct edid *edid) | |||
1349 | } | 1335 | } |
1350 | EXPORT_SYMBOL(drm_find_cea_extension); | 1336 | EXPORT_SYMBOL(drm_find_cea_extension); |
1351 | 1337 | ||
1338 | static int | ||
1339 | do_cea_modes (struct drm_connector *connector, u8 *db, u8 len) | ||
1340 | { | ||
1341 | struct drm_device *dev = connector->dev; | ||
1342 | u8 * mode, cea_mode; | ||
1343 | int modes = 0; | ||
1344 | |||
1345 | for (mode = db; mode < db + len; mode++) { | ||
1346 | cea_mode = (*mode & 127) - 1; /* CEA modes are numbered 1..127 */ | ||
1347 | if (cea_mode < drm_num_cea_modes) { | ||
1348 | struct drm_display_mode *newmode; | ||
1349 | newmode = drm_mode_duplicate(dev, | ||
1350 | &edid_cea_modes[cea_mode]); | ||
1351 | if (newmode) { | ||
1352 | drm_mode_probed_add(connector, newmode); | ||
1353 | modes++; | ||
1354 | } | ||
1355 | } | ||
1356 | } | ||
1357 | |||
1358 | return modes; | ||
1359 | } | ||
1360 | |||
1361 | static int | ||
1362 | add_cea_modes(struct drm_connector *connector, struct edid *edid) | ||
1363 | { | ||
1364 | u8 * cea = drm_find_cea_extension(edid); | ||
1365 | u8 * db, dbl; | ||
1366 | int modes = 0; | ||
1367 | |||
1368 | if (cea && cea[1] >= 3) { | ||
1369 | for (db = cea + 4; db < cea + cea[2]; db += dbl + 1) { | ||
1370 | dbl = db[0] & 0x1f; | ||
1371 | if (((db[0] & 0xe0) >> 5) == VIDEO_BLOCK) | ||
1372 | modes += do_cea_modes (connector, db+1, dbl); | ||
1373 | } | ||
1374 | } | ||
1375 | |||
1376 | return modes; | ||
1377 | } | ||
1378 | |||
1352 | static void | 1379 | static void |
1353 | parse_hdmi_vsdb(struct drm_connector *connector, uint8_t *db) | 1380 | parse_hdmi_vsdb(struct drm_connector *connector, uint8_t *db) |
1354 | { | 1381 | { |
@@ -1432,26 +1459,29 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) | |||
1432 | eld[18] = edid->prod_code[0]; | 1459 | eld[18] = edid->prod_code[0]; |
1433 | eld[19] = edid->prod_code[1]; | 1460 | eld[19] = edid->prod_code[1]; |
1434 | 1461 | ||
1435 | for (db = cea + 4; db < cea + cea[2]; db += dbl + 1) { | 1462 | if (cea[1] >= 3) |
1436 | dbl = db[0] & 0x1f; | 1463 | for (db = cea + 4; db < cea + cea[2]; db += dbl + 1) { |
1437 | 1464 | dbl = db[0] & 0x1f; | |
1438 | switch ((db[0] & 0xe0) >> 5) { | 1465 | |
1439 | case AUDIO_BLOCK: /* Audio Data Block, contains SADs */ | 1466 | switch ((db[0] & 0xe0) >> 5) { |
1440 | sad_count = dbl / 3; | 1467 | case AUDIO_BLOCK: |
1441 | memcpy(eld + 20 + mnl, &db[1], dbl); | 1468 | /* Audio Data Block, contains SADs */ |
1442 | break; | 1469 | sad_count = dbl / 3; |
1443 | case SPEAKER_BLOCK: /* Speaker Allocation Data Block */ | 1470 | memcpy(eld + 20 + mnl, &db[1], dbl); |
1444 | eld[7] = db[1]; | 1471 | break; |
1445 | break; | 1472 | case SPEAKER_BLOCK: |
1446 | case VENDOR_BLOCK: | 1473 | /* Speaker Allocation Data Block */ |
1447 | /* HDMI Vendor-Specific Data Block */ | 1474 | eld[7] = db[1]; |
1448 | if (db[1] == 0x03 && db[2] == 0x0c && db[3] == 0) | 1475 | break; |
1449 | parse_hdmi_vsdb(connector, db); | 1476 | case VENDOR_BLOCK: |
1450 | break; | 1477 | /* HDMI Vendor-Specific Data Block */ |
1451 | default: | 1478 | if (db[1] == 0x03 && db[2] == 0x0c && db[3] == 0) |
1452 | break; | 1479 | parse_hdmi_vsdb(connector, db); |
1480 | break; | ||
1481 | default: | ||
1482 | break; | ||
1483 | } | ||
1453 | } | 1484 | } |
1454 | } | ||
1455 | eld[5] |= sad_count << 4; | 1485 | eld[5] |= sad_count << 4; |
1456 | eld[2] = (20 + mnl + sad_count * 3 + 3) / 4; | 1486 | eld[2] = (20 + mnl + sad_count * 3 + 3) / 4; |
1457 | 1487 | ||
@@ -1722,6 +1752,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) | |||
1722 | num_modes += add_standard_modes(connector, edid); | 1752 | num_modes += add_standard_modes(connector, edid); |
1723 | num_modes += add_established_modes(connector, edid); | 1753 | num_modes += add_established_modes(connector, edid); |
1724 | num_modes += add_inferred_modes(connector, edid); | 1754 | num_modes += add_inferred_modes(connector, edid); |
1755 | num_modes += add_cea_modes(connector, edid); | ||
1725 | 1756 | ||
1726 | if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) | 1757 | if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) |
1727 | edid_fixup_preferred(connector, quirks); | 1758 | edid_fixup_preferred(connector, quirks); |