From 461ac547bb959118a40320f05198f5ba852e7d82 Mon Sep 17 00:00:00 2001 From: Ryan Murray Date: Thu, 29 Oct 2026 11:43:36 +1100 Subject: [PATCH] drm/apple: Keep sink primaries as reported in firmware-derived EDIDs An MSI MPG 325CQRXF on the second external processor of the M4 Pro came up with an empty EDID: no monitor name and no HDR capability in userspace. Its DisplayAttributes report the red primary as x 0.6904, y 0.3203, the 10-bit values 707 and 328 of its own EDID. Their sum is above 1, and the parser refused any chromaticity whose coordinates sum above 1, so the whole of DisplayAttributes was dropped and no EDID was built. Primaries are the sink's description of itself, and real EDIDs carry such values. Pass them on as reported. The EDID builder still requires each coordinate to be representable, the primaries to span a triangle and the white point to lie inside it; the white point, which the gamma belongs to, must still be a chromaticity. The same sink reports its luminance without a minimum. Read a missing minimum as 0 and a missing frame-average maximum as the maximum, rather than dropping the luminance range. Assisted-by: LLM Signed-off-by: Ryan Murray --- drivers/gpu/drm/apple/dcp-display-metadata.c | 2 +- drivers/gpu/drm/apple/parser.c | 11 ++++++++-- .../selftests/drivers/gpu/apple-dcp/rate.py | 21 ++++++++++++++++++- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp-display-metadata.c b/drivers/gpu/drm/apple/dcp-display-metadata.c index 851407005ee70..3a40d288b024c 100644 --- a/drivers/gpu/drm/apple/dcp-display-metadata.c +++ b/drivers/gpu/drm/apple/dcp-display-metadata.c @@ -117,7 +117,7 @@ static int dcp_metadata_block(struct edid *edid, const struct dcp_display_metada coordinate[i] = DIV_ROUND_CLOSEST(value, 64); if (!coordinate[i] || coordinate[i] > 1023) return -EINVAL; - if ((i & 1) && coordinate[i - 1] + coordinate[i] > 1024) + if (i == 7 && coordinate[6] + coordinate[7] > 1024) return -EINVAL; } /* Degenerate primaries or a white point outside their triangle are not usable. */ diff --git a/drivers/gpu/drm/apple/parser.c b/drivers/gpu/drm/apple/parser.c index 9dc6b0eb27b3b..ca45d777a159d 100644 --- a/drivers/gpu/drm/apple/parser.c +++ b/drivers/gpu/drm/apple/parser.c @@ -1340,7 +1340,11 @@ static int parse_metadata_point(struct dcp_parse_ctx *handle, u32 point[2], u32 if (ret) return ret; } - if (seen != (gamma ? 7 : 3) || point[0] + point[1] > 65536) + /* + * A white point is a chromaticity. A primary is passed on as the + * sink reports it: real EDIDs carry primaries with x + y above 1. + */ + if (seen != (gamma ? 7 : 3) || (gamma && point[0] + point[1] > 65536)) return -EINVAL; return 0; } @@ -1525,7 +1529,10 @@ static int parse_metadata_luminance(struct dcp_parse_ctx *handle, ret = parse_metadata_number(handle, &values[i], 0, U32_MAX); } } - if (!ret && seen == 7 && values[0] && values[1] <= values[0] && + /* A sink may leave out its frame-average or minimum luminance. */ + if (!(seen & 2)) + values[1] = values[0]; + if (!ret && (seen & 1) && values[0] && values[1] <= values[0] && values[2] < values[0]) { out->max_luminance = values[0]; out->max_fall = values[1]; diff --git a/tools/testing/selftests/drivers/gpu/apple-dcp/rate.py b/tools/testing/selftests/drivers/gpu/apple-dcp/rate.py index 9ca6841c74755..f92ef124c75b7 100644 --- a/tools/testing/selftests/drivers/gpu/apple-dcp/rate.py +++ b/tools/testing/selftests/drivers/gpu/apple-dcp/rate.py @@ -66,9 +66,15 @@ def wire(value, out): "Colorimetry": 10, "Depth": 10, "DynamicRange": 0, "EOTF": 0}], "ID": 62, "Score": 16224, "IsPreferred": True, "IsInterlaced": False, "IsVirtual": False, }] + sink = copy.deepcopy(fixture) + sink['Chromaticity']['Red'] = {'X': 45248, 'Y': 20992} + del sink['Luminance']['Min'] + sink_raw = bytearray(struct.pack('raw; + assert((r[27] << 2 | (r[25] >> 6 & 3)) == 707 && (r[28] << 2 | (r[25] >> 4 & 3)) == 328); + drm_edid_free(e); + } const struct drm_edid *edid = dcp_metadata_edid(&metadata, &mode); assert(!IS_ERR(edid) && edid->size == 256); f = fopen(argv[3], "wb"); assert(f); @@ -1172,7 +1191,7 @@ def metadata(root, output): for path, value in [ (('MaxHorizontalImageSize',), 256), (('MaxVerticalImageSize',), '33'), (('Chromaticity', 'Red', 'X'), True), (('Chromaticity', 'Blue', 'Y'), 65536), - (('Chromaticity', 'Green', 'Y'), 64000), (('DefaultWhitePoint', 'Gamma'), 65535), + (('DefaultWhitePoint', 'Y'), 64000), (('DefaultWhitePoint', 'Gamma'), 65535), (('DefaultWhitePoint', 'Gamma'), 240000), (('ProductAttributes', 'ManufacturerID'), 'AC'), (('ProductAttributes', 'ManufacturerID'), 'A\0R'), (('ProductAttributes', 'LegacyManufacturerID'), 1), (('ProductAttributes', 'ProductName'), 'x' * 14), (('ProductAttributes', 'ProductID'), 65536),