diff --git a/packages/x11/xserver/xorg-server/patches/xorg-server-4k_support.patch b/packages/x11/xserver/xorg-server/patches/xorg-server-4k_support.patch new file mode 100644 index 0000000000..f845318263 --- /dev/null +++ b/packages/x11/xserver/xorg-server/patches/xorg-server-4k_support.patch @@ -0,0 +1,266 @@ +From a279fb3ff3f3cfc41530aff1d9ff5620279348f6 Mon Sep 17 00:00:00 2001 +From: Damien Lespiau +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 +Signed-off-by: Damien Lespiau +--- + 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 +Date: Wed, 7 Aug 2013 15:16:21 +0100 +Subject: [PATCH 2/3] xfree86: Refactor xf86MonitorIsHDMI() using + xf86MonitorFindHDMIBlock() + +Reviewed-by: Chris Wilson +Signed-off-by: Damien Lespiau +--- + 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 +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 +Signed-off-by: Damien Lespiau +--- + 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 +