projects/linux·blob master · refs

362 lines · 12.1 KiB

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
41bool 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}
53EXPORT_IF_KUNIT(amdgpu_dm_is_dc_timing_adjust_needed);
54
55bool
56amdgpu_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}
84EXPORT_IF_KUNIT(amdgpu_dm_is_timing_unchanged_for_freesync);
85
86void 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}
100EXPORT_IF_KUNIT(amdgpu_dm_set_freesync_fixed_config);
101
102void 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}
110EXPORT_IF_KUNIT(amdgpu_dm_reset_freesync_config_for_crtc);
111
112void 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 }
152out:
153 new_crtc_state->freesync_config = config;
154}
155EXPORT_IF_KUNIT(amdgpu_dm_get_freesync_config_for_crtc);
156
157void 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
252void 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
311void 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}