xserver: Branch 'master' - 4 commits

Keith Packard keithp at kemper.freedesktop.org
Wed Jan 22 11:32:58 PST 2014


 hw/xfree86/ddc/interpret_edid.c |  137 ++++++++++++++++++++++++++--------------
 hw/xfree86/ddc/xf86DDC.h        |    2 
 hw/xfree86/modes/xf86Crtc.c     |   11 +++
 3 files changed, 105 insertions(+), 45 deletions(-)

New commits:
commit 409e8e29fbe16122ba5a4249256fc56e2e68ea93
Merge: 457bc83 d6c8d75
Author: Keith Packard <keithp at keithp.com>
Date:   Wed Jan 22 11:32:35 2014 -0800

    Merge remote-tracking branch 'dlespiau/20131216-4k'

commit d6c8d7509727060b8e2358b9ed1c0e17b2ec3401
Author: Damien Lespiau <damien.lespiau at intel.com>
Date:   Wed Jul 31 19:16:45 2013 +0100

    xfree86: Use the TMDS maximum frequency to prune modes
    
    Instead of only relying on the Range section, we can do better on
    HDMI to find out what is the max dot clock the monitor supports. The
    HDMI CEA vendor block adds a TMDS max freq we can use.
    
    This makes X not prune 4k resolutions on HDMI.
    
    v2: Replace X_INFO by X_PROBED in the message that prints the max
        TMDS frequency (Chris Wilson)
    
    Reviewed-by: Chris Wilson <chris at chris-wilson.co.uk>
    Signed-off-by: Damien Lespiau <damien.lespiau at intel.com>

diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c
index a441fd1..42fdad9 100644
--- a/hw/xfree86/modes/xf86Crtc.c
+++ b/hw/xfree86/modes/xf86Crtc.c
@@ -1676,6 +1676,7 @@ xf86ProbeOutputModes(ScrnInfoPtr scrn, int maxX, int maxY)
         if (edid_monitor) {
             struct det_monrec_parameter p;
             struct disp_features *features = &edid_monitor->features;
+            struct cea_data_block *hdmi_db;
 
             /* if display is not continuous-frequency, don't add default modes */
             if (!GTF_SUPPORTED(features->msc))
@@ -1688,6 +1689,16 @@ xf86ProbeOutputModes(ScrnInfoPtr scrn, int maxX, int maxY)
             p.sync_source = &sync_source;
 
             xf86ForEachDetailedBlock(edid_monitor, handle_detailed_monrec, &p);
+
+            /* Look at the CEA HDMI vendor block for the max TMDS freq */
+            hdmi_db = xf86MonitorFindHDMIBlock(edid_monitor);
+            if (hdmi_db && hdmi_db->len >= 7) {
+                int tmds_freq = hdmi_db->u.vendor.hdmi.max_tmds_clock * 5000;
+                xf86DrvMsg(scrn->scrnIndex, X_PROBED,
+                           "HDMI max TMDS frequency %dKHz\n", tmds_freq);
+                if (tmds_freq > max_clock)
+                    max_clock = tmds_freq;
+            }
         }
 
         if (xf86GetOptValFreq(output->options, OPTION_MIN_CLOCK,
commit 95c2287465138ac251bf792f354cee3626e76b44
Author: Damien Lespiau <damien.lespiau at intel.com>
Date:   Wed Aug 7 15:16:21 2013 +0100

    xfree86: Refactor xf86MonitorIsHDMI() using xf86MonitorFindHDMIBlock()
    
    Reviewed-by: Chris Wilson <chris at chris-wilson.co.uk>
    Signed-off-by: Damien Lespiau <damien.lespiau at intel.com>

diff --git a/hw/xfree86/ddc/interpret_edid.c b/hw/xfree86/ddc/interpret_edid.c
index 6c531b4..17a8f81 100644
--- a/hw/xfree86/ddc/interpret_edid.c
+++ b/hw/xfree86/ddc/interpret_edid.c
@@ -757,49 +757,5 @@ validate_version(int scrnIndex, struct edid_version *r)
 Bool
 xf86MonitorIsHDMI(xf86MonPtr mon)
 {
-    int i = 0, version, offset;
-    char *edid = NULL;
-
-    if (!mon)
-        return FALSE;
-
-    if (!(mon->flags & EDID_COMPLETE_RAWDATA))
-        return FALSE;
-
-    if (!mon->no_sections)
-        return FALSE;
-
-    edid = (char *) mon->rawData;
-    if (!edid)
-        return FALSE;
-
-    /* find the CEA extension block */
-    for (i = 1; i <= mon->no_sections; i++)
-        if (edid[i * 128] == 0x02)
-            break;
-    if (i == mon->no_sections + 1)
-        return FALSE;
-    edid += (i * 128);
-
-    version = edid[1];
-    offset = edid[2];
-    if (version < 3 || offset < 4)
-        return FALSE;
-
-    /* walk the cea data blocks */
-    for (i = 4; i < offset; i += (edid[i] & 0x1f) + 1) {
-        char *x = edid + i;
-
-        /* find a vendor specific block */
-        if ((x[0] & 0xe0) >> 5 == 0x03) {
-            int oui = (x[3] << 16) + (x[2] << 8) + x[1];
-
-            /* find the HDMI vendor OUI */
-            if (oui == 0x000c03)
-                return TRUE;
-        }
-    }
-
-    /* guess it's not HDMI after all */
-    return FALSE;
+    return xf86MonitorFindHDMIBlock(mon) != NULL;
 }
commit a279fb3ff3f3cfc41530aff1d9ff5620279348f6
Author: Damien Lespiau <damien.lespiau at intel.com>
Date:   Wed Jul 31 19:11:45 2013 +0100

    xfree86: Add a xf86MonitorFindHDMIBlock()
    
    The HDMI CEA vendor specific block has some interesting information,
    such as the maximum TMDS dot clock.
    
    v2: Don't parse CEA blocks with invalid offsets, remove spurious
        brackets (Chris Wilson)
    
    v3: Fix the looping through the CEA data blocks, it had a typo using the
        wrong variable coming from the code it was ported from.
        Replace x << 16 + y << 8 + z by x << 16 | y << 8 | z
        (Chris Wilson)
    
    v4: Remove the stray ';' at the end of "if (*end == 0)".
        (Dominik Behr on IRC)
    
    Reviewed-by: Chris Wilson <chris at chris-wilson.co.uk>
    Signed-off-by: Damien Lespiau <damien.lespiau at intel.com>

diff --git a/hw/xfree86/ddc/interpret_edid.c b/hw/xfree86/ddc/interpret_edid.c
index 882a6b2..6c531b4 100644
--- a/hw/xfree86/ddc/interpret_edid.c
+++ b/hw/xfree86/ddc/interpret_edid.c
@@ -332,6 +332,97 @@ xf86ForEachVideoBlock(xf86MonPtr mon, handle_video_fn fn, void *data)
     }
 }
 
+static Bool
+cea_db_offsets(Uchar *cea, int *start, int *end)
+{
+    /* Data block offset in CEA extension block */
+    *start = CEA_EXT_MIN_DATA_OFFSET;
+    *end = cea[2];
+    if (*end == 0)
+        *end = CEA_EXT_MAX_DATA_OFFSET;
+    if (*end < CEA_EXT_MIN_DATA_OFFSET || *end > CEA_EXT_MAX_DATA_OFFSET)
+        return FALSE;
+    return TRUE;
+}
+
+static int
+cea_db_len(Uchar *db)
+{
+    return db[0] & 0x1f;
+}
+
+static int
+cea_db_tag(Uchar *db)
+{
+    return db[0] >> 5;
+}
+
+typedef void (*handle_cea_db_fn) (Uchar *, void *);
+
+static void
+cea_for_each_db(xf86MonPtr mon, handle_cea_db_fn fn, void *data)
+{
+    int i;
+
+    if (!mon)
+        return;
+
+    if (!(mon->flags & EDID_COMPLETE_RAWDATA))
+        return;
+
+    if (!mon->no_sections)
+        return;
+
+    if (!mon->rawData)
+        return;
+
+    for (i = 0; i < mon->no_sections; i++) {
+        int start, end, offset;
+        Uchar *ext;
+
+        ext = mon->rawData + EDID1_LEN * (i + 1);
+        if (ext[EXT_TAG] != CEA_EXT)
+            continue;
+
+        if (!cea_db_offsets(ext, &start, &end))
+            continue;
+
+        for (offset = start;
+             offset < end && offset + cea_db_len(&ext[offset]) < end;
+             offset += cea_db_len(&ext[offset]) + 1)
+                fn(&ext[offset], data);
+    }
+}
+
+struct find_hdmi_block_data {
+    struct cea_data_block *hdmi;
+};
+
+static void find_hdmi_block(Uchar *db, void *data)
+{
+    struct find_hdmi_block_data *result = data;
+    int oui;
+
+    if (cea_db_tag(db) != CEA_VENDOR_BLK)
+        return;
+
+    if (cea_db_len(db) < 5)
+        return;
+
+    oui = (db[3] << 16) | (db[2] << 8) | db[1];
+    if (oui == IEEE_ID_HDMI)
+        result->hdmi = (struct cea_data_block *)db;
+}
+
+struct cea_data_block *xf86MonitorFindHDMIBlock(xf86MonPtr mon)
+{
+    struct find_hdmi_block_data result = { NULL };
+
+    cea_for_each_db(mon, find_hdmi_block, &result);
+
+    return result.hdmi;
+}
+
 xf86MonPtr
 xf86InterpretEEDID(int scrnIndex, Uchar * block)
 {
diff --git a/hw/xfree86/ddc/xf86DDC.h b/hw/xfree86/ddc/xf86DDC.h
index bdc7648..de8e718 100644
--- a/hw/xfree86/ddc/xf86DDC.h
+++ b/hw/xfree86/ddc/xf86DDC.h
@@ -98,4 +98,6 @@ typedef void (*handle_video_fn) (struct cea_video_block *, void *);
 
 void xf86ForEachVideoBlock(xf86MonPtr, handle_video_fn, void *);
 
+struct cea_data_block *xf86MonitorFindHDMIBlock(xf86MonPtr mon);
+
 #endif


More information about the xorg-commit mailing list