aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_edid.c
diff options
context:
space:
mode:
authorLespiau, Damien <damien.lespiau@intel.com>2013-08-19 11:58:54 -0400
committerDave Airlie <airlied@gmail.com>2013-08-29 18:40:06 -0400
commit7ebe1963a063daf30f95752c35244c5d49550aa9 (patch)
tree8e74c2a950e3858c0a21c80acb30bd080150596c /drivers/gpu/drm/drm_edid.c
parent13ac3f5593cf0964cdb239864829e57cc6981dac (diff)
drm/edid: Parse the HDMI CEA block and look for 4k modes
HDMI 1.4 adds 4 "4k x 2k" modes in the the CEA vendor specific block. With this commit, we now parse this block and expose the 4k modes that we find there. v2: Fix the "4096x2160" string (nice catch!), add comments about do_hdmi_vsdb_modes() arguments and make it clearer that offset is relative to the end of the required fields of the HDMI VSDB (Ville Syrjälä) v3: Fix 'Unknow' typo (Simon Farnsworth) Signed-off-by: Damien Lespiau <damien.lespiau@intel.com> Tested-by: Cancan Feng <cancan.feng@intel.com> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=67030 Reviewed-by: Simon Farnsworth <simon.farnsworth@onelan.co.uk> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Thierry Reding <treding@nvidia.com> Signed-off-by: Dave Airlie <airlied@gmail.com>
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r--drivers/gpu/drm/drm_edid.c124
1 files changed, 109 insertions, 15 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index bb25ee2f9f25..9de573cd3683 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -931,6 +931,36 @@ static const struct drm_display_mode edid_cea_modes[] = {
931 .vrefresh = 100, }, 931 .vrefresh = 100, },
932}; 932};
933 933
934/*
935 * HDMI 1.4 4k modes.
936 */
937static const struct drm_display_mode edid_4k_modes[] = {
938 /* 1 - 3840x2160@30Hz */
939 { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000,
940 3840, 4016, 4104, 4400, 0,
941 2160, 2168, 2178, 2250, 0,
942 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
943 .vrefresh = 30, },
944 /* 2 - 3840x2160@25Hz */
945 { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000,
946 3840, 4896, 4984, 5280, 0,
947 2160, 2168, 2178, 2250, 0,
948 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
949 .vrefresh = 25, },
950 /* 3 - 3840x2160@24Hz */
951 { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000,
952 3840, 5116, 5204, 5500, 0,
953 2160, 2168, 2178, 2250, 0,
954 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
955 .vrefresh = 24, },
956 /* 4 - 4096x2160@24Hz (SMPTE) */
957 { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 297000,
958 4096, 5116, 5204, 5500, 0,
959 2160, 2168, 2178, 2250, 0,
960 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
961 .vrefresh = 24, },
962};
963
934/*** DDC fetch and block validation ***/ 964/*** DDC fetch and block validation ***/
935 965
936static const u8 edid_header[] = { 966static const u8 edid_header[] = {
@@ -2465,6 +2495,68 @@ do_cea_modes(struct drm_connector *connector, const u8 *db, u8 len)
2465 return modes; 2495 return modes;
2466} 2496}
2467 2497
2498/*
2499 * do_hdmi_vsdb_modes - Parse the HDMI Vendor Specific data block
2500 * @connector: connector corresponding to the HDMI sink
2501 * @db: start of the CEA vendor specific block
2502 * @len: length of the CEA block payload, ie. one can access up to db[len]
2503 *
2504 * Parses the HDMI VSDB looking for modes to add to @connector.
2505 */
2506static int
2507do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len)
2508{
2509 struct drm_device *dev = connector->dev;
2510 int modes = 0, offset = 0, i;
2511 u8 vic_len;
2512
2513 if (len < 8)
2514 goto out;
2515
2516 /* no HDMI_Video_Present */
2517 if (!(db[8] & (1 << 5)))
2518 goto out;
2519
2520 /* Latency_Fields_Present */
2521 if (db[8] & (1 << 7))
2522 offset += 2;
2523
2524 /* I_Latency_Fields_Present */
2525 if (db[8] & (1 << 6))
2526 offset += 2;
2527
2528 /* the declared length is not long enough for the 2 first bytes
2529 * of additional video format capabilities */
2530 offset += 2;
2531 if (len < (8 + offset))
2532 goto out;
2533
2534 vic_len = db[8 + offset] >> 5;
2535
2536 for (i = 0; i < vic_len && len >= (9 + offset + i); i++) {
2537 struct drm_display_mode *newmode;
2538 u8 vic;
2539
2540 vic = db[9 + offset + i];
2541
2542 vic--; /* VICs start at 1 */
2543 if (vic >= ARRAY_SIZE(edid_4k_modes)) {
2544 DRM_ERROR("Unknown HDMI VIC: %d\n", vic);
2545 continue;
2546 }
2547
2548 newmode = drm_mode_duplicate(dev, &edid_4k_modes[vic]);
2549 if (!newmode)
2550 continue;
2551
2552 drm_mode_probed_add(connector, newmode);
2553 modes++;
2554 }
2555
2556out:
2557 return modes;
2558}
2559
2468static int 2560static int
2469cea_db_payload_len(const u8 *db) 2561cea_db_payload_len(const u8 *db)
2470{ 2562{
@@ -2496,6 +2588,21 @@ cea_db_offsets(const u8 *cea, int *start, int *end)
2496 return 0; 2588 return 0;
2497} 2589}
2498 2590
2591static bool cea_db_is_hdmi_vsdb(const u8 *db)
2592{
2593 int hdmi_id;
2594
2595 if (cea_db_tag(db) != VENDOR_BLOCK)
2596 return false;
2597
2598 if (cea_db_payload_len(db) < 5)
2599 return false;
2600
2601 hdmi_id = db[1] | (db[2] << 8) | (db[3] << 16);
2602
2603 return hdmi_id == HDMI_IDENTIFIER;
2604}
2605
2499#define for_each_cea_db(cea, i, start, end) \ 2606#define for_each_cea_db(cea, i, start, end) \
2500 for ((i) = (start); (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); (i) += cea_db_payload_len(&(cea)[(i)]) + 1) 2607 for ((i) = (start); (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); (i) += cea_db_payload_len(&(cea)[(i)]) + 1)
2501 2608
@@ -2519,6 +2626,8 @@ add_cea_modes(struct drm_connector *connector, struct edid *edid)
2519 2626
2520 if (cea_db_tag(db) == VIDEO_BLOCK) 2627 if (cea_db_tag(db) == VIDEO_BLOCK)
2521 modes += do_cea_modes(connector, db + 1, dbl); 2628 modes += do_cea_modes(connector, db + 1, dbl);
2629 else if (cea_db_is_hdmi_vsdb(db))
2630 modes += do_hdmi_vsdb_modes(connector, db, dbl);
2522 } 2631 }
2523 } 2632 }
2524 2633
@@ -2571,21 +2680,6 @@ monitor_name(struct detailed_timing *t, void *data)
2571 *(u8 **)data = t->data.other_data.data.str.str; 2680 *(u8 **)data = t->data.other_data.data.str.str;
2572} 2681}
2573 2682
2574static bool cea_db_is_hdmi_vsdb(const u8 *db)
2575{
2576 int hdmi_id;
2577
2578 if (cea_db_tag(db) != VENDOR_BLOCK)
2579 return false;
2580
2581 if (cea_db_payload_len(db) < 5)
2582 return false;
2583
2584 hdmi_id = db[1] | (db[2] << 8) | (db[3] << 16);
2585
2586 return hdmi_id == HDMI_IDENTIFIER;
2587}
2588
2589/** 2683/**
2590 * drm_edid_to_eld - build ELD from EDID 2684 * drm_edid_to_eld - build ELD from EDID
2591 * @connector: connector corresponding to the HDMI/DP sink 2685 * @connector: connector corresponding to the HDMI/DP sink