[PATCH 4/4] drm/amd/display: Add HDMI ALLM support
Fangzhi Zuo <[email protected]> Thu, 30 Jul 2026 13:17:54 -0400
| Newsgroups | org.freedesktop.lists.amd-gfx |
|---|---|
| Message-ID | <[email protected]> |
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