[PATCH] drm/amd/display: Default HDMI RGB output to limited range on CTA modes
From: Adrian Betschart
Date: Thu Sep 10 2026 - 14:43:40 EST
With the Broadcast RGB property at Automatic, amdgpu_dm_get_output_color_space()
selects COLOR_SPACE_SRGB for RGB output, so DC neither compresses the pixels
nor, without a QS-capable sink, signals full range in the AVI InfoFrame. A sink
that follows CTA-861 treats the default quantization of a CTA video format as
limited and expands 16-235 to 0-255: everything below 16 is crushed to black,
everything above 235 clips.
Follow the CTA-861 default for Automatic instead, as the DRM HDMI state helper
(hdmi_is_limited_range()) and i915 do: limited range on an HDMI sink for CTA
modes other than 640x480, full range elsewhere. Full and Limited keep their
explicit meaning. The same rule applies to the BT.2020 RGB branch. With
commit a56a50074 ("drm/amd/display: Propagate HDMI RGB quantization
selectability") the AVI InfoFrame then carries the matching Q value on
sinks that support selection.
Measured on a Radeon RX 7600 (DCN 3.2.1) driving a JVC DLA-RS4100 at
1920x1080p24 RGB 12 bpc: the sink reports the signal as limited range while
the picture shows crushed shadows; rendering limited range in the client makes
it match a reference source.
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/5796
Signed-off-by: Adrian Betschart <adrian.betschart@xxxxxxxxxxxx>
Assisted-by: Claude Code:claude-fable-5-1
---
.../display/amdgpu_dm/amdgpu_dm_connector.c | 22 +++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index 0b446133e..13cbe099c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -734,6 +734,24 @@ get_aspect_ratio(const struct drm_display_mode *mode_in)
}
EXPORT_IF_KUNIT(get_aspect_ratio);
+/*
+ * CTA-861 5.1: RGB video formats default to limited range except 640x480 (VIC 1).
+ * With Broadcast RGB left at Automatic follow that default, as i915 does.
+ */
+static bool rgb_output_is_limited_range(const struct dc_crtc_timing *dc_crtc_timing,
+ const struct drm_connector_state *connector_state)
+{
+ switch (connector_state->hdmi.broadcast_rgb) {
+ case DRM_HDMI_BROADCAST_RGB_FULL:
+ return false;
+ case DRM_HDMI_BROADCAST_RGB_LIMITED:
+ return true;
+ default:
+ return connector_state->connector->display_info.is_hdmi &&
+ dc_crtc_timing->vic > 1;
+ }
+}
+
enum dc_color_space
amdgpu_dm_get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing,
const struct drm_connector_state *connector_state)
@@ -759,7 +777,7 @@ amdgpu_dm_get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing,
case DRM_MODE_COLORIMETRY_BT2020_RGB:
case DRM_MODE_COLORIMETRY_BT2020_YCC:
if (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB) {
- if (connector_state->hdmi.broadcast_rgb == DRM_HDMI_BROADCAST_RGB_LIMITED)
+ if (rgb_output_is_limited_range(dc_crtc_timing, connector_state))
color_space = COLOR_SPACE_2020_RGB_LIMITEDRANGE;
else
color_space = COLOR_SPACE_2020_RGB_FULLRANGE;
@@ -771,7 +789,7 @@ amdgpu_dm_get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing,
default:
if (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB) {
color_space = COLOR_SPACE_SRGB;
- if (connector_state->hdmi.broadcast_rgb == DRM_HDMI_BROADCAST_RGB_LIMITED)
+ if (rgb_output_is_limited_range(dc_crtc_timing, connector_state))
color_space = COLOR_SPACE_SRGB_LIMITED;
/*
* 27030khz is the separation point between HDTV and SDTV
--
2.55.0