CTA-861-H requires that when a source ends Dynamic Range and Mastering
InfoFrame transmission, it shall send a DRM infoframe with EOTF=0 and
all metadata fields set to 0 for at least 2 seconds before stopping.

Currently, when transitioning from HDR to SDR, the driver abruptly
stops sending the DRM metadata SDP/infoframe. This causes DP-to-HDMI
converters to latch the previous HDR metadata and continue forwarding
it to the HDMI sink, resulting in color errors (e.g. oversaturated or
washed-out colors) on SDR content. Windows correctly implements the
null infoframe transition.

Fix both the DP and native HDMI paths to send a zeroed DRM infoframe
(EOTF=Traditional_SDR=0, all luminance and primaries fields zero) when
transitioning from HDR to SDR. The null packet is only sent when the
previous connector state had HDR metadata active, avoiding unnecessary
DRM infoframe transmission during normal SDR operation.

Signed-off-by: Xiao Lu <[email protected]>
---
 drivers/gpu/drm/i915/display/intel_dp.c   | 23 ++++++++++++++++++++---
 drivers/gpu/drm/i915/display/intel_hdmi.c | 19 ++++++++++++++++++-
 2 files changed, 38 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c 
b/drivers/gpu/drm/i915/display/intel_dp.c
index 113d767e62e9..d5ed96ba7e7b 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -3231,14 +3231,29 @@ intel_dp_in_hdr_mode(const struct drm_connector_state 
*conn_state)
 static void
 intel_dp_compute_hdr_metadata_infoframe_sdp(struct intel_dp *intel_dp,
                                            struct intel_crtc_state *crtc_state,
-                                           const struct drm_connector_state 
*conn_state)
+                                           const struct drm_connector_state 
*conn_state,
+                                           const struct drm_connector_state 
*old_conn_state)
 {
        struct intel_display *display = to_intel_display(intel_dp);
        int ret;
        struct hdmi_drm_infoframe *drm_infoframe = 
&crtc_state->infoframes.drm.drm;
 
-       if (!conn_state->hdr_output_metadata)
+       if (!conn_state->hdr_output_metadata) {
+               /*
+                * CTA-861-H requires ending HDR metadata transmission by
+                * sending a DRM infoframe with EOTF=0 and all fields zero
+                * for at least 2 seconds, rather than abruptly stopping.
+                * Abruptly stopping causes DP-to-HDMI converters to latch
+                * the previous HDR metadata and forward it to the HDMI sink,
+                * resulting in color errors on SDR content.
+                */
+               if (old_conn_state && old_conn_state->hdr_output_metadata) {
+                       hdmi_drm_infoframe_init(drm_infoframe);
+                       crtc_state->infoframes.enable |=
+                               
intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GAMUT_METADATA);
+               }
                return;
+       }
 
        ret = drm_hdmi_infoframe_set_hdr_metadata(drm_infoframe, conn_state);
 
@@ -3644,7 +3659,9 @@ intel_dp_compute_config(struct intel_atomic_state *state,
        intel_alpm_lobf_compute_config(intel_dp, pipe_config, conn_state);
        intel_dp_drrs_compute_config(connector, pipe_config, link_bpp_x16);
        intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state);
-       intel_dp_compute_hdr_metadata_infoframe_sdp(intel_dp, pipe_config, 
conn_state);
+       intel_dp_compute_hdr_metadata_infoframe_sdp(intel_dp, pipe_config, 
conn_state,
+                                                   
drm_atomic_get_old_connector_state(&state->base,
+                                                                               
      conn_state->connector));
 
        return intel_dp_tunnel_atomic_compute_stream_bw(state, intel_dp, 
connector,
                                                        pipe_config);
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c 
b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 8a019d3574df..9fb9be302d35 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -856,8 +856,25 @@ intel_hdmi_compute_drm_infoframe(struct intel_encoder 
*encoder,
        if (!crtc_state->has_infoframe)
                return true;
 
-       if (!conn_state->hdr_output_metadata)
+       if (!conn_state->hdr_output_metadata) {
+               const struct drm_connector_state *old_conn_state =
+                       drm_atomic_get_old_connector_state(conn_state->state,
+                                                          
conn_state->connector);
+               /*
+                * CTA-861-H requires ending HDR metadata transmission by
+                * sending a DRM infoframe with EOTF=0 and all fields zero
+                * for at least 2 seconds, rather than abruptly stopping.
+                * Abruptly stopping causes DP-to-HDMI converters to latch
+                * the previous HDR metadata and forward it to the HDMI sink,
+                * resulting in color errors on SDR content.
+                */
+               if (old_conn_state && old_conn_state->hdr_output_metadata) {
+                       hdmi_drm_infoframe_init(frame);
+                       crtc_state->infoframes.enable |=
+                               
intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_DRM);
+               }
                return true;
+       }
 
        crtc_state->infoframes.enable |=
                intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_DRM);
-- 
2.43.0

Reply via email to