xorg-server: add support for 4k output

Signed-off-by: Stephan Raue <stephan@openelec.tv>
This commit is contained in:
Stephan Raue 2014-04-18 14:58:53 +02:00
parent e3192302a3
commit 45d67c3e5a

View File

@ -0,0 +1,266 @@
From a279fb3ff3f3cfc41530aff1d9ff5620279348f6 Mon Sep 17 00:00:00 2001
From: Damien Lespiau <damien.lespiau@intel.com>
Date: Wed, 31 Jul 2013 19:11:45 +0100
Subject: [PATCH 1/3] 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@intel.com>
---
hw/xfree86/ddc/interpret_edid.c | 91 +++++++++++++++++++++++++++++++++++++++++
hw/xfree86/ddc/xf86DDC.h | 2 +
2 files changed, 93 insertions(+)
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
--
1.9.1
From 95c2287465138ac251bf792f354cee3626e76b44 Mon Sep 17 00:00:00 2001
From: Damien Lespiau <damien.lespiau@intel.com>
Date: Wed, 7 Aug 2013 15:16:21 +0100
Subject: [PATCH 2/3] xfree86: Refactor xf86MonitorIsHDMI() using
xf86MonitorFindHDMIBlock()
Reviewed-by: Chris Wilson <chris at chris-wilson.co.uk>
Signed-off-by: Damien Lespiau <damien.lespiau@intel.com>
---
hw/xfree86/ddc/interpret_edid.c | 46 +----------------------------------------
1 file changed, 1 insertion(+), 45 deletions(-)
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;
}
--
1.9.1
From d6c8d7509727060b8e2358b9ed1c0e17b2ec3401 Mon Sep 17 00:00:00 2001
From: Damien Lespiau <damien.lespiau@intel.com>
Date: Wed, 31 Jul 2013 19:16:45 +0100
Subject: [PATCH 3/3] 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@intel.com>
---
hw/xfree86/modes/xf86Crtc.c | 11 +++++++++++
1 file changed, 11 insertions(+)
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,
--
1.9.1