From 5bddd6497a5af727263b51c791c55563a1686156 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Tue, 1 Sep 2026 15:12:49 -0400 Subject: [PATCH 1/3] [FROM-ML] drm: Add passive_vrr properties for passive/desktop VRR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the PASSIVE_VRR_DISABLED atomic CRTC property (drm_crtc_state. passive_vrr_disabled) and the immutable passive_vrr_capable connector property, together with drm_connector_attach_passive_vrr_capable_property() and drm_connector_set_passive_vrr_capable_property() helpers. Passive VRR keeps a sink in its variable-refresh state during fixed refresh (desktop) use, avoiding blanking/flicker on VRR entry/exit for HDMI sinks that lack seamless VRR transitions. The property is opt-out (default enabled where the connector advertises passive_vrr_capable); lacking hardware support is not treated as failure. Not useful for DP/eDP where seamless VRR transitions are enforced by the standard. Signed-off-by: Tomasz Pakuła Signed-off-by: Fangzhi Zuo Link: https://lore.kernel.org/r/20260901191251.2653684-2-jerry.zuo@amd.com --- drivers/gpu/drm/drm_atomic_uapi.c | 4 ++ drivers/gpu/drm/drm_connector.c | 73 +++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_crtc.c | 2 + drivers/gpu/drm/drm_mode_config.c | 6 +++ include/drm/drm_connector.h | 15 +++++++ include/drm/drm_crtc.h | 9 ++++ include/drm/drm_mode_config.h | 6 +++ 7 files changed, 115 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index e997917819e8e..c50c83360ba2f 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -420,6 +420,8 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, return ret; } else if (property == config->prop_vrr_enabled) { state->vrr_enabled = val; + } else if (property == config->prop_passive_vrr_disabled) { + state->passive_vrr_disabled = val; } else if (property == config->degamma_lut_property) { const size_t elem_size = sizeof(struct drm_color_lut); u64 lut_size; @@ -505,6 +507,8 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc, *val = (state->mode_blob) ? state->mode_blob->base.id : 0; else if (property == config->prop_vrr_enabled) *val = state->vrr_enabled; + else if (property == config->prop_passive_vrr_disabled) + *val = state->passive_vrr_disabled; else if (property == config->degamma_lut_property) *val = (state->degamma_lut) ? state->degamma_lut->base.id : 0; else if (property == config->ctm_property) diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 11646453aaac9..f2f45674fa47f 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -2367,6 +2367,16 @@ EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); * * Absence of the property should indicate absence of support. * + * "passive_vrr_capable": + * Optional &drm_connector boolean property that drivers should attach + * with drm_connector_attach_passive_vrr_capable_property() on + * connectors that could support keeping variable refresh rate signalling + * in fixed-refresh rate scenarios like desktop work. Drivers should update + * the property value by calling + * drm_connector_set_passive_vrr_capable_property(). + * + * Absence of the property should indicate absence of support. + * * "VRR_ENABLED": * Default &drm_crtc boolean property that notifies the driver that the * content on the CRTC is suitable for variable refresh rate presentation. @@ -2385,6 +2395,17 @@ EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); * * The driver may place further restrictions within these minimum * and maximum bounds. + * + * "PASSIVE_VRR_DISABLED": + * Default &drm_crtc boolean property that notifies the driver that the + * VRR singalling should be disabled in fixed refresh rate scenarios. + * Functionally, psssive vrr works the same as VRR_ENABLED == false + * but works around displays blanking (mainly HDMI) that do not support + * seamless VRR transitions. Also helps with brightness flickering during + * VRR transitions. + * + * Passive VRR mode is not that useful for DP/eDP sinks where seamless VRR + * transitions are enforced by the standard. */ /** @@ -2418,6 +2439,37 @@ int drm_connector_attach_vrr_capable_property( } EXPORT_SYMBOL(drm_connector_attach_vrr_capable_property); +/** + * drm_connector_attach_passive_vrr_capable_property - creates the + * passive_vrr_capable property + * @connector: connector to create the passive_vrr_capable property on. + * + * This is used by atomic drivers to add support for querying + * variable refresh rate on desktop capability for a connector. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_connector_attach_passive_vrr_capable_property( + struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct drm_property *prop; + + if (!connector->passive_vrr_capable_property) { + prop = drm_property_create_bool(dev, DRM_MODE_PROP_IMMUTABLE, + "passive_vrr_capable"); + if (!prop) + return -ENOMEM; + + connector->passive_vrr_capable_property = prop; + drm_object_attach_property(&connector->base, prop, 0); + } + + return 0; +} +EXPORT_SYMBOL(drm_connector_attach_passive_vrr_capable_property); + /** * drm_connector_attach_scaling_mode_property - attach atomic scaling mode property * @connector: connector to attach scaling mode property on. @@ -2984,6 +3036,27 @@ void drm_connector_set_vrr_capable_property( } EXPORT_SYMBOL(drm_connector_set_vrr_capable_property); +/** + * drm_connector_set_passive_vrr_capable_property - sets the variable refresh + * rate on desktop capable property for a connector + * @connector: drm connector + * @capable: True if the connector is variable refresh rate on desktop capable + * + * Should be used by atomic drivers to update the indicated support for + * variable refresh rate on desktop over a connector. + */ +void drm_connector_set_passive_vrr_capable_property( + struct drm_connector *connector, bool capable) +{ + if (!connector->passive_vrr_capable_property) + return; + + drm_object_property_set_value(&connector->base, + connector->passive_vrr_capable_property, + capable); +} +EXPORT_SYMBOL(drm_connector_set_passive_vrr_capable_property); + /** * drm_connector_set_panel_orientation - sets the connector's panel_orientation * @connector: connector for which to set the panel-orientation property. diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 63ead8ba67564..bd666dbc30f29 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -322,6 +322,8 @@ static int __drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc * config->prop_out_fence_ptr, 0); drm_object_attach_property(&crtc->base, config->prop_vrr_enabled, 0); + drm_object_attach_property(&crtc->base, + config->prop_passive_vrr_disabled, 0); } return 0; diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index 66f7dc37b5970..dc1ca08655ca6 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -345,6 +345,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev) return -ENOMEM; dev->mode_config.prop_vrr_enabled = prop; + prop = drm_property_create_bool(dev, 0, + "PASSIVE_VRR_DISABLED"); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_passive_vrr_disabled = prop; + prop = drm_property_create(dev, DRM_MODE_PROP_BLOB, "DEGAMMA_LUT", 0); diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 78d117d4de991..2a64297d97c53 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -2206,6 +2206,17 @@ struct drm_connector { */ struct drm_property *vrr_capable_property; + /** + * @passive_vrr_capable_property: Optional property to help userspace + * query hardware support for passive variable refresh rate on a + * connector. Drivers can add the property to a connector by + * calling drm_connector_attach_passive_vrr_capable_property(). + * + * This should be updated only by calling + * drm_connector_set_passive_vrr_capable_property(). + */ + struct drm_property *passive_vrr_capable_property; + /** * @colorspace_property: Connector property to set the suitable * colorspace supported by the sink. @@ -2600,6 +2611,8 @@ int drm_connector_attach_scaling_mode_property(struct drm_connector *connector, u32 scaling_mode_mask); int drm_connector_attach_vrr_capable_property( struct drm_connector *connector); +int drm_connector_attach_passive_vrr_capable_property( + struct drm_connector *connector); void drm_connector_attach_panel_type_property(struct drm_connector *connector); int drm_connector_attach_broadcast_rgb_property(struct drm_connector *connector); int drm_connector_attach_colorspace_property(struct drm_connector *connector); @@ -2623,6 +2636,8 @@ void drm_connector_set_link_status_property(struct drm_connector *connector, uint64_t link_status); void drm_connector_set_vrr_capable_property( struct drm_connector *connector, bool capable); +void drm_connector_set_passive_vrr_capable_property( + struct drm_connector *connector, bool capable); int drm_connector_set_panel_orientation( struct drm_connector *connector, enum drm_panel_orientation panel_orientation); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index c6dbe8b7db9ee..642a374f403e6 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -311,6 +311,15 @@ struct drm_crtc_state { */ bool vrr_enabled; + /** + * @passive_vrr_disabled: + * + * Indicates if variable refresh rate on desktop should be enabled for + * the CRTC. Support for the requested state will depend on driver and + * hardware capabiltiy - lacking support is not treated as failure. + */ + bool passive_vrr_disabled; + /** * @self_refresh_active: * diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index e584652ddf676..e312e6ae4d7ee 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -701,6 +701,12 @@ struct drm_mode_config { * whether variable refresh rate should be enabled on the CRTC. */ struct drm_property *prop_vrr_enabled; + /** + * @prop_passive_vrr_disabled: Default atomic CRTC property to indicate + * whether passive variable refresh rate should be disabled + * on the CRTC. + */ + struct drm_property *prop_passive_vrr_disabled; /** * @dvi_i_subconnector_property: Optional DVI-I property to From c42b59c1fe3631a16f2599ae53bb9a036651f560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Tue, 1 Sep 2026 15:12:50 -0400 Subject: [PATCH 2/3] [FROM-ML] drm/amd/display: Use passive_vrr properties in amdgpu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wire the passive_vrr DRM properties into amdgpu for HDMI/DP/eDP sinks: - Add dm_connector_state.freesync_on_desktop_capable and copy it in amdgpu_dm_connector_atomic_duplicate_state(). - Attach the passive_vrr_capable connector property alongside vrr_capable for non-MST connectors. - In amdgpu_dm_update_freesync_caps(), record freesync_on_desktop_capable and update the passive_vrr_capable property from freesync_capable. - In amdgpu_dm_get_freesync_config_for_crtc(), drive stream->freesync_on_desktop from the inverse of passive_vrr_disabled when capable, hooking into the existing DC freesync_on_desktop logic that keeps the FreeSync-Active bit set during fixed-refresh (desktop) use. Signed-off-by: Tomasz Pakuła Signed-off-by: Fangzhi Zuo Link: https://lore.kernel.org/r/20260901191251.2653684-3-jerry.zuo@amd.com --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 19 +++++++++++++++++-- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 1 + 2 files changed, 18 insertions(+), 2 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 6a4dc90cb2801..47e19081c405b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -8205,6 +8205,7 @@ amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector) __drm_atomic_helper_connector_duplicate_state(connector, &new_state->base); new_state->freesync_capable = state->freesync_capable; + new_state->freesync_on_desktop_capable = state->freesync_on_desktop_capable; new_state->abm_level = state->abm_level; new_state->scaling = state->scaling; new_state->underscan_enable = state->underscan_enable; @@ -9418,8 +9419,10 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, connector_type == DRM_MODE_CONNECTOR_eDP) { drm_connector_attach_hdr_output_metadata_property(&aconnector->base); - if (!aconnector->mst_root) + if (!aconnector->mst_root) { drm_connector_attach_vrr_capable_property(&aconnector->base); + drm_connector_attach_passive_vrr_capable_property(&aconnector->base); + } if (adev->dm.hdcp_workqueue) drm_connector_attach_content_protection_property(&aconnector->base, true); @@ -11985,6 +11988,12 @@ static void get_freesync_config_for_crtc( config.vsif_supported = true; config.btr = true; + if (new_con_state->freesync_on_desktop_capable) + new_crtc_state->stream->freesync_on_desktop = + !new_crtc_state->base.passive_vrr_disabled; + else + new_crtc_state->stream->freesync_on_desktop = false; + if (fs_vid_mode) { config.state = VRR_STATE_ACTIVE_FIXED; config.fixed_refresh_in_uhz = new_crtc_state->freesync_config.fixed_refresh_in_uhz; @@ -11996,6 +12005,7 @@ static void get_freesync_config_for_crtc( } } else { config.state = VRR_STATE_UNSUPPORTED; + new_crtc_state->stream->freesync_on_desktop = false; } out: new_crtc_state->freesync_config = config; @@ -14124,8 +14134,10 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, } update: - if (dm_con_state) + if (dm_con_state) { dm_con_state->freesync_capable = freesync_capable; + dm_con_state->freesync_on_desktop_capable = freesync_capable; + } drm_dbg_driver(adev_to_drm(adev), "VRR: caps result: freesync_capable=%d min_vfreq=%d max_vfreq=%d\n", @@ -14141,6 +14153,9 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, if (connector->vrr_capable_property) drm_connector_set_vrr_capable_property(connector, freesync_capable); + + if (connector->passive_vrr_capable_property) + drm_connector_set_passive_vrr_capable_property(connector, freesync_capable); } void amdgpu_dm_trigger_timing_sync(struct drm_device *dev) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index dd199e0b79226..8acde054d7e90 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -1051,6 +1051,7 @@ struct dm_connector_state { uint8_t underscan_hborder; bool underscan_enable; bool freesync_capable; + bool freesync_on_desktop_capable; bool update_hdcp; bool abm_sysfs_forbidden; uint8_t abm_level; From 7e1b4daf78c92ee2b0bab4c20cb6396894b367d9 Mon Sep 17 00:00:00 2001 From: Fangzhi Zuo Date: Tue, 1 Sep 2026 15:12:51 -0400 Subject: [PATCH 3/3] [FROM-ML] drm/amd/display: Keep FreeSync for HF-VSDB VRR sinks in MCCS fallback amdgpu_dm_update_freesync_caps() clears freesync_capable for any SIGNAL_TYPE_HDMI_TYPE_A sink that lacks an AMD FreeSync MCCS VCP code. HDMI-Forum VRR (HF-VSDB) sinks advertise VRR without such a VCP code, so the HF-VSDB fallback that set freesync_capable was immediately undone, leaving VRR and passive VRR disabled on those sinks. Skip the MCCS clear when the sink reports HF-VSDB VRR capability, so freesync_capable survives for HDMI-Forum VRR sinks. Signed-off-by: Fangzhi Zuo Link: https://lore.kernel.org/r/20260901191251.2653684-4-jerry.zuo@amd.com --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 47e19081c405b..3967bc19366b0 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -14126,7 +14126,8 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, if (do_mccs) { dm_helpers_read_mccs_caps(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink); - if (sink->edid_caps.freesync_vcp_code && !sink->mccs_caps.freesync_supported) + if (!connector->display_info.hdmi.vrr_cap.supported && + sink->edid_caps.freesync_vcp_code && !sink->mccs_caps.freesync_supported) freesync_capable = false; if (sink->mccs_caps.freesync_supported && freesync_capable)