why:
HDMI 2.1 Auto Low-Latency Mode (ALLM) lets a Source request the Sink's
low-latency mode through the HF-VSIF. amdgpu never set ALLM_Mode in the
HF-VSIF, so ALLM was never signalled to the sink.

how:
- Add an allm capability flag to struct dc_edid_caps and populate it in
  dm_helpers_parse_edid_caps() from the HF-VSDB ALLM bit parsed by DRM
  core (connector->display_info.hdmi.allm).
- In create_stream_for_sink(), build the HF-VSIF with ALLM_Mode set when
  the sink advertises ALLM and the content type is Game (content-type =
  Game is how userspace requests low-latency mode, HDMI GCTS HF1-56).
- In update_freesync_state_on_stream(), also set ALLM_Mode when
  Gaming-VRR is active (VRR_EN=1, HDMI GCTS HF1-58 step 8.3.1), and push
  the updated HF-VSIF (vsp_infopacket) as a stream update.

Signed-off-by: Fangzhi Zuo <[email protected]>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 35 ++++++++++++++++++-
 .../display/amdgpu_dm/amdgpu_dm_connector.c   | 18 ++++++++--
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  5 ++-
 drivers/gpu/drm/amd/display/dc/dc_types.h     |  3 ++
 4 files changed, 57 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 223b562f7005..fc3005ecc681 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3895,6 +3895,36 @@ static void update_freesync_state_on_stream(
        new_stream->vrr_infopacket = vrr_infopacket;
        new_stream->allow_freesync = 
mod_freesync_get_freesync_enabled(&vrr_params);
 
+       /*
+        * HDMI ALLM: transmit the HF-VSIF with ALLM_Mode=1 when the sink
+        * advertises ALLM in the SCDS and either the content type is Game
+        * (HF1-56) or Gaming-VRR is active (VRR_EN=1, HF1-58 step 8.3.1).
+        * HDMI 2.1 7.6.6.
+        */
+       if (new_stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
+           new_stream->signal == SIGNAL_TYPE_HDMI_FRL) {
+               struct dc_info_packet vsp_infopacket = {0};
+               bool allm = new_stream->sink->edid_caps.allm &&
+                       (new_stream->content_type == DISPLAY_CONTENT_TYPE_GAME 
||
+                        vrr_params.state == VRR_STATE_ACTIVE_VARIABLE ||
+                        vrr_params.state == VRR_STATE_ACTIVE_FIXED);
+               bool allm_changed;
+
+               mod_build_hf_vsif_infopacket(new_stream, &vsp_infopacket, allm, 
allm);
+
+               allm_changed = memcmp(&new_stream->vsp_infopacket, 
&vsp_infopacket,
+                                     sizeof(vsp_infopacket)) != 0;
+               new_crtc_state->freesync_vrr_info_changed |= allm_changed;
+               new_stream->vsp_infopacket = vsp_infopacket;
+
+               if (allm_changed)
+                       drm_dbg_driver(adev_to_drm(adev),
+                                      "ALLM: flip on crtc=%u: sink_allm=%d 
content_type=%d vrr_state=%d -> ALLM_Mode=%d\n",
+                                   new_crtc_state->base.crtc->base.id,
+                                   new_stream->sink->edid_caps.allm,
+                                   new_stream->content_type, vrr_params.state, 
allm);
+       }
+
        if (new_crtc_state->freesync_vrr_info_changed)
                drm_dbg_kms(adev_to_drm(adev), "VRR packet update: crtc=%u 
enabled=%d state=%d",
                              new_crtc_state->base.crtc->base.id,
@@ -4429,9 +4459,12 @@ static void amdgpu_dm_commit_planes(struct 
drm_atomic_state *state,
                }
 
                if (acrtc_state->stream) {
-                       if (acrtc_state->freesync_vrr_info_changed)
+                       if (acrtc_state->freesync_vrr_info_changed) {
                                bundle->stream_update.vrr_infopacket =
                                        &acrtc_state->stream->vrr_infopacket;
+                               bundle->stream_update.vsp_infopacket =
+                                       &acrtc_state->stream->vsp_infopacket;
+                       }
                }
        }
 
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 ebead39939a6..430f1628ced0 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
@@ -1511,8 +1511,22 @@ create_stream_for_sink(struct drm_connector *connector,
        update_stream_signal(stream, sink);
 
        if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
-           stream->signal == SIGNAL_TYPE_HDMI_FRL)
-               mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, 
false, false);
+           stream->signal == SIGNAL_TYPE_HDMI_FRL) {
+               /*
+                * Enable HDMI ALLM (Auto Low-Latency Mode) when the sink
+                * advertises ALLM in the SCDS and the content type is Game.
+                * Setting content-type = Game is how userspace requests the
+                * Sink's low-latency mode (HDMI GCTS HF1-56).
+                */
+               bool allm = sink->edid_caps.allm &&
+                       stream->content_type == DISPLAY_CONTENT_TYPE_GAME;
+
+               drm_dbg_driver(dev,
+                              "ALLM: set mode: sink_allm=%d content_type=%d -> 
ALLM_Mode=%d\n",
+                           sink->edid_caps.allm, stream->content_type, allm);
+
+               mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, 
allm, allm);
+       }
 
        if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
            stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index 42f5673acb4d..e69ce0a1b4b4 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -197,7 +197,10 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
                                  edid_caps->display_name,
                                  AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS);
 
-       edid_caps->edid_hdmi = connector->display_info.is_hdmi;
+       if (connector->display_info.is_hdmi) {
+               edid_caps->edid_hdmi = true;
+               edid_caps->allm = connector->display_info.hdmi.allm;
+       }
 
        if (edid_caps->edid_hdmi) {
                populate_hdmi_info_from_connector(link->dc->config.enable_frl, 
&connector->display_info.hdmi, edid_caps);
diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h 
b/drivers/gpu/drm/amd/display/dc/dc_types.h
index 3edeb94fba23..ae409cc59ae4 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_types.h
@@ -226,6 +226,9 @@ struct dc_edid_caps {
        /*HDMI 2.0 caps*/
        bool lte_340mcsc_scramble;
 
+       /* HDMI 2.1 caps */
+       bool allm;
+
        bool edid_hdmi;
        bool hdr_supported;
        bool rr_capable;
-- 
2.53.0

Reply via email to