1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright 2026 Advanced Micro Devices, Inc. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 * OTHER DEALINGS IN THE SOFTWARE. 22 * 23 * Authors: AMD 24 * 25 */ 26 27 #include <drm/drm_atomic.h> 28 #include <drm/drm_modes.h> 29 #include <drm/drm_vblank.h> 30 31 #include "dc.h" 32 #include "amdgpu.h" 33 #include "amdgpu_dm.h" 34 #include "amdgpu_dm_crtc.h" 35 #include "amdgpu_dm_psr.h" 36 #include "amdgpu_dm_replay.h" 37 #include "amdgpu_dm_freesync.h" 38 #include "dm_helpers.h" 39 #include "modules/inc/mod_freesync.h" 40 41 bool amdgpu_dm_is_dc_timing_adjust_needed(struct dm_crtc_state *old_state, 42 struct dm_crtc_state *new_state) 43 { 44 if (new_state->stream->adjust.timing_adjust_pending) 45 return true; 46 if (new_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED) 47 return true; 48 else if (amdgpu_dm_crtc_vrr_active(old_state) != amdgpu_dm_crtc_vrr_active(new_state)) 49 return true; 50 else 51 return false; 52 } 53 EXPORT_IF_KUNIT(amdgpu_dm_is_dc_timing_adjust_needed); 54 55 bool 56 amdgpu_dm_is_timing_unchanged_for_freesync(struct drm_crtc_state *old_crtc_state, 57 struct drm_crtc_state *new_crtc_state) 58 { 59 const struct drm_display_mode *old_mode, *new_mode; 60 61 if (!old_crtc_state || !new_crtc_state) 62 return false; 63 64 old_mode = &old_crtc_state->mode; 65 new_mode = &new_crtc_state->mode; 66 67 if (old_mode->clock == new_mode->clock && 68 old_mode->hdisplay == new_mode->hdisplay && 69 old_mode->vdisplay == new_mode->vdisplay && 70 old_mode->htotal == new_mode->htotal && 71 old_mode->vtotal != new_mode->vtotal && 72 old_mode->hsync_start == new_mode->hsync_start && 73 old_mode->vsync_start != new_mode->vsync_start && 74 old_mode->hsync_end == new_mode->hsync_end && 75 old_mode->vsync_end != new_mode->vsync_end && 76 old_mode->hskew == new_mode->hskew && 77 old_mode->vscan == new_mode->vscan && 78 (old_mode->vsync_end - old_mode->vsync_start) == 79 (new_mode->vsync_end - new_mode->vsync_start)) 80 return true; 81 82 return false; 83 } 84 EXPORT_IF_KUNIT(amdgpu_dm_is_timing_unchanged_for_freesync); 85 86 void amdgpu_dm_set_freesync_fixed_config(struct dm_crtc_state *dm_new_crtc_state) 87 { 88 u64 num, den, res; 89 struct drm_crtc_state *new_crtc_state = &dm_new_crtc_state->base; 90 91 dm_new_crtc_state->freesync_config.state = VRR_STATE_ACTIVE_FIXED; 92 93 num = (unsigned long long)new_crtc_state->mode.clock * 1000 * 1000000; 94 den = (unsigned long long)new_crtc_state->mode.htotal * 95 (unsigned long long)new_crtc_state->mode.vtotal; 96 97 res = div_u64(num, den); 98 dm_new_crtc_state->freesync_config.fixed_refresh_in_uhz = res; 99 } 100 EXPORT_IF_KUNIT(amdgpu_dm_set_freesync_fixed_config); 101 102 void amdgpu_dm_reset_freesync_config_for_crtc( 103 struct dm_crtc_state *new_crtc_state) 104 { 105 new_crtc_state->vrr_supported = false; 106 107 memset(&new_crtc_state->vrr_infopacket, 0, 108 sizeof(new_crtc_state->vrr_infopacket)); 109 } 110 EXPORT_IF_KUNIT(amdgpu_dm_reset_freesync_config_for_crtc); 111 112 void amdgpu_dm_get_freesync_config_for_crtc( 113 struct dm_crtc_state *new_crtc_state, 114 struct dm_connector_state *new_con_state) 115 { 116 struct mod_freesync_config config = {0}; 117 struct amdgpu_dm_connector *aconnector; 118 struct drm_display_mode *mode = &new_crtc_state->base.mode; 119 int vrefresh = drm_mode_vrefresh(mode); 120 bool fs_vid_mode = false; 121 122 if (new_con_state->base.connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) 123 return; 124 125 aconnector = to_amdgpu_dm_connector(new_con_state->base.connector); 126 127 new_crtc_state->vrr_supported = new_con_state->freesync_capable && 128 vrefresh >= aconnector->min_vfreq && 129 vrefresh <= aconnector->max_vfreq; 130 131 if (new_crtc_state->vrr_supported) { 132 new_crtc_state->stream->ignore_msa_timing_param = true; 133 fs_vid_mode = new_crtc_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED; 134 135 config.min_refresh_in_uhz = aconnector->min_vfreq * 1000000; 136 config.max_refresh_in_uhz = aconnector->max_vfreq * 1000000; 137 config.vsif_supported = true; 138 config.btr = true; 139 140 if (fs_vid_mode) { 141 config.state = VRR_STATE_ACTIVE_FIXED; 142 config.fixed_refresh_in_uhz = new_crtc_state->freesync_config.fixed_refresh_in_uhz; 143 goto out; 144 } else if (new_crtc_state->base.vrr_enabled) { 145 config.state = VRR_STATE_ACTIVE_VARIABLE; 146 } else { 147 config.state = VRR_STATE_INACTIVE; 148 } 149 } else { 150 config.state = VRR_STATE_UNSUPPORTED; 151 } 152 out: 153 new_crtc_state->freesync_config = config; 154 } 155 EXPORT_IF_KUNIT(amdgpu_dm_get_freesync_config_for_crtc); 156 157 void amdgpu_dm_update_freesync_state_on_stream( 158 struct amdgpu_display_manager *dm, 159 struct dm_crtc_state *new_crtc_state, 160 struct dc_stream_state *new_stream, 161 struct dc_plane_state *surface, 162 u32 flip_timestamp_in_us) 163 { 164 struct mod_vrr_params vrr_params; 165 struct dc_info_packet vrr_infopacket = {0}; 166 struct amdgpu_device *adev = dm->adev; 167 struct amdgpu_crtc *acrtc = to_amdgpu_crtc(new_crtc_state->base.crtc); 168 unsigned long flags; 169 bool pack_sdp_v1_3 = false; 170 struct amdgpu_dm_connector *aconn; 171 enum vrr_packet_type packet_type = PACKET_TYPE_VRR; 172 173 if (!new_stream) 174 return; 175 176 /* 177 * TODO: Determine why min/max totals and vrefresh can be 0 here. 178 * For now it's sufficient to just guard against these conditions. 179 */ 180 181 if (!new_stream->timing.h_total || !new_stream->timing.v_total) 182 return; 183 184 spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); 185 vrr_params = acrtc->dm_irq_params.vrr_params; 186 187 if (surface) { 188 mod_freesync_handle_preflip( 189 dm->freesync_module, 190 surface, 191 new_stream, 192 flip_timestamp_in_us, 193 &vrr_params); 194 195 if (adev->family < AMDGPU_FAMILY_AI && 196 amdgpu_dm_crtc_vrr_active(new_crtc_state)) { 197 mod_freesync_handle_v_update(dm->freesync_module, 198 new_stream, &vrr_params); 199 200 /* Need to call this before the frame ends. */ 201 dc_stream_adjust_vmin_vmax(dm->dc, 202 new_crtc_state->stream, 203 &vrr_params.adjust); 204 } 205 } 206 207 aconn = (struct amdgpu_dm_connector *)new_stream->dm_stream_context; 208 209 if (aconn && (aconn->as_type == FREESYNC_TYPE_PCON_IN_WHITELIST || aconn->vsdb_info.replay_mode)) { 210 pack_sdp_v1_3 = aconn->pack_sdp_v1_3; 211 212 if (aconn->vsdb_info.amd_vsdb_version == 1) 213 packet_type = PACKET_TYPE_FS_V1; 214 else if (aconn->vsdb_info.amd_vsdb_version == 2) 215 packet_type = PACKET_TYPE_FS_V2; 216 else if (aconn->vsdb_info.amd_vsdb_version == 3) 217 packet_type = PACKET_TYPE_FS_V3; 218 219 mod_build_adaptive_sync_infopacket(new_stream, aconn->as_type, NULL, 220 &new_stream->adaptive_sync_infopacket); 221 } 222 223 mod_freesync_build_vrr_infopacket( 224 dm->freesync_module, 225 new_stream, 226 &vrr_params, 227 packet_type, 228 TRANSFER_FUNC_UNKNOWN, 229 &vrr_infopacket, 230 pack_sdp_v1_3); 231 232 new_crtc_state->freesync_vrr_info_changed |= 233 (memcmp(&new_crtc_state->vrr_infopacket, 234 &vrr_infopacket, 235 sizeof(vrr_infopacket)) != 0); 236 237 acrtc->dm_irq_params.vrr_params = vrr_params; 238 new_crtc_state->vrr_infopacket = vrr_infopacket; 239 240 new_stream->vrr_infopacket = vrr_infopacket; 241 new_stream->allow_freesync = mod_freesync_get_freesync_enabled(&vrr_params); 242 243 if (new_crtc_state->freesync_vrr_info_changed) 244 drm_dbg_kms(adev_to_drm(adev), "VRR packet update: crtc=%u enabled=%d state=%d", 245 new_crtc_state->base.crtc->base.id, 246 (int)new_crtc_state->base.vrr_enabled, 247 (int)vrr_params.state); 248 249 spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); 250 } 251 252 void amdgpu_dm_update_stream_irq_parameters( 253 struct amdgpu_display_manager *dm, 254 struct dm_crtc_state *new_crtc_state) 255 { 256 struct dc_stream_state *new_stream = new_crtc_state->stream; 257 struct mod_vrr_params vrr_params; 258 struct mod_freesync_config config = new_crtc_state->freesync_config; 259 struct amdgpu_device *adev = dm->adev; 260 struct amdgpu_crtc *acrtc = to_amdgpu_crtc(new_crtc_state->base.crtc); 261 unsigned long flags; 262 263 if (!new_stream) 264 return; 265 266 /* 267 * TODO: Determine why min/max totals and vrefresh can be 0 here. 268 * For now it's sufficient to just guard against these conditions. 269 */ 270 if (!new_stream->timing.h_total || !new_stream->timing.v_total) 271 return; 272 273 spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); 274 vrr_params = acrtc->dm_irq_params.vrr_params; 275 276 if (new_crtc_state->vrr_supported && 277 config.min_refresh_in_uhz && 278 config.max_refresh_in_uhz) { 279 /* 280 * if freesync compatible mode was set, config.state will be set 281 * in atomic check 282 */ 283 if (config.state == VRR_STATE_ACTIVE_FIXED && config.fixed_refresh_in_uhz && 284 (!drm_atomic_crtc_needs_modeset(&new_crtc_state->base) || 285 new_crtc_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED)) { 286 vrr_params.max_refresh_in_uhz = config.max_refresh_in_uhz; 287 vrr_params.min_refresh_in_uhz = config.min_refresh_in_uhz; 288 vrr_params.fixed_refresh_in_uhz = config.fixed_refresh_in_uhz; 289 vrr_params.state = VRR_STATE_ACTIVE_FIXED; 290 } else { 291 config.state = new_crtc_state->base.vrr_enabled ? 292 VRR_STATE_ACTIVE_VARIABLE : 293 VRR_STATE_INACTIVE; 294 } 295 } else { 296 config.state = VRR_STATE_UNSUPPORTED; 297 } 298 299 mod_freesync_build_vrr_params(dm->freesync_module, 300 new_stream, 301 &config, &vrr_params); 302 303 new_crtc_state->freesync_config = config; 304 /* Copy state for access from DM IRQ handler */ 305 acrtc->dm_irq_params.freesync_config = config; 306 acrtc->dm_irq_params.active_planes = new_crtc_state->active_planes; 307 acrtc->dm_irq_params.vrr_params = vrr_params; 308 spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); 309 } 310 311 void amdgpu_dm_handle_vrr_transition(struct amdgpu_display_manager *dm, 312 struct dm_crtc_state *old_state, 313 struct dm_crtc_state *new_state) 314 { 315 struct amdgpu_device *adev = dm->adev; 316 bool old_vrr_active = amdgpu_dm_crtc_vrr_active(old_state); 317 bool new_vrr_active = amdgpu_dm_crtc_vrr_active(new_state); 318 319 /* Only DCE gates vupdate on VRR, keep it enabled for DCN */ 320 bool vrr_gates_vupdate = amdgpu_ip_version(adev, DCE_HWIP, 0) == 0; 321 322 if (!old_vrr_active && new_vrr_active) { 323 /* Transition VRR inactive -> active: 324 * While VRR is active, we must not disable vblank irq, as a 325 * reenable after disable would compute bogus vblank/pflip 326 * timestamps if it likely happened inside display front-porch. 327 * 328 * We also need vupdate irq for the actual core vblank handling 329 * at end of vblank. 330 */ 331 if (vrr_gates_vupdate) 332 WARN_ON(amdgpu_dm_crtc_set_vupdate_irq(new_state->base.crtc, true) != 0); 333 WARN_ON(drm_crtc_vblank_get(new_state->base.crtc) != 0); 334 drm_dbg_driver(new_state->base.crtc->dev, "%s: crtc=%u VRR off->on: Get vblank ref\n", 335 __func__, new_state->base.crtc->base.id); 336 337 scoped_guard(mutex, &dm->dc_lock) { 338 dc_exit_ips_for_hw_access(dm->dc); 339 amdgpu_dm_psr_set_event(dm, new_state->stream, true, 340 psr_event_vrr_transition, true); 341 amdgpu_dm_replay_set_event(dm, new_state->stream, true, 342 replay_event_vrr, true); 343 } 344 } else if (old_vrr_active && !new_vrr_active) { 345 /* Transition VRR active -> inactive: 346 * Allow vblank irq disable again for fixed refresh rate. 347 */ 348 if (vrr_gates_vupdate) 349 WARN_ON(amdgpu_dm_crtc_set_vupdate_irq(new_state->base.crtc, false) != 0); 350 drm_crtc_vblank_put(new_state->base.crtc); 351 drm_dbg_driver(new_state->base.crtc->dev, "%s: crtc=%u VRR on->off: Drop vblank ref\n", 352 __func__, new_state->base.crtc->base.id); 353 354 scoped_guard(mutex, &dm->dc_lock) { 355 dc_exit_ips_for_hw_access(dm->dc); 356 amdgpu_dm_psr_set_event(dm, new_state->stream, false, 357 psr_event_vrr_transition, false); 358 amdgpu_dm_replay_set_event(dm, new_state->stream, false, 359 replay_event_vrr, false); 360 } 361 } 362 } 363