2 * Copyright 2016 Advanced Micro Devices, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
26 #include <linux/slab.h>
28 #include "dm_services.h"
30 #include "mod_freesync.h"
31 #include "core_types.h"
33 #define MOD_FREESYNC_MAX_CONCURRENT_STREAMS 32
35 #define MIN_REFRESH_RANGE 10
36 /* Refresh rate ramp at a fixed rate of 65 Hz/second */
37 #define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65)
38 /* Number of elements in the render times cache array */
39 #define RENDER_TIMES_MAX_COUNT 10
40 /* Threshold to exit/exit BTR (to avoid frequent enter-exits at the lower limit) */
41 #define BTR_MAX_MARGIN 2500
42 /* Threshold to change BTR multiplier (to avoid frequent changes) */
43 #define BTR_DRIFT_MARGIN 2000
44 /* Threshold to exit fixed refresh rate */
45 #define FIXED_REFRESH_EXIT_MARGIN_IN_HZ 1
46 /* Number of consecutive frames to check before entering/exiting fixed refresh */
47 #define FIXED_REFRESH_ENTER_FRAME_COUNT 5
48 #define FIXED_REFRESH_EXIT_FRAME_COUNT 10
50 struct core_freesync
{
51 struct mod_freesync
public;
55 #define MOD_FREESYNC_TO_CORE(mod_freesync)\
56 container_of(mod_freesync, struct core_freesync, public)
58 struct mod_freesync
*mod_freesync_create(struct dc
*dc
)
60 struct core_freesync
*core_freesync
=
61 kzalloc(sizeof(struct core_freesync
), GFP_KERNEL
);
63 if (core_freesync
== NULL
)
64 goto fail_alloc_context
;
69 core_freesync
->dc
= dc
;
70 return &core_freesync
->public;
79 void mod_freesync_destroy(struct mod_freesync
*mod_freesync
)
81 struct core_freesync
*core_freesync
= NULL
;
82 if (mod_freesync
== NULL
)
84 core_freesync
= MOD_FREESYNC_TO_CORE(mod_freesync
);
88 #if 0 /* Unused currently */
89 static unsigned int calc_refresh_in_uhz_from_duration(
90 unsigned int duration_in_ns
)
92 unsigned int refresh_in_uhz
=
93 ((unsigned int)(div64_u64((1000000000ULL * 1000000),
95 return refresh_in_uhz
;
99 static unsigned int calc_duration_in_us_from_refresh_in_uhz(
100 unsigned int refresh_in_uhz
)
102 unsigned int duration_in_us
=
103 ((unsigned int)(div64_u64((1000000000ULL * 1000),
105 return duration_in_us
;
108 static unsigned int calc_duration_in_us_from_v_total(
109 const struct dc_stream_state
*stream
,
110 const struct mod_vrr_params
*in_vrr
,
111 unsigned int v_total
)
113 unsigned int duration_in_us
=
114 (unsigned int)(div64_u64(((unsigned long long)(v_total
)
115 * 10000) * stream
->timing
.h_total
,
116 stream
->timing
.pix_clk_100hz
));
118 return duration_in_us
;
121 static unsigned int calc_v_total_from_refresh(
122 const struct dc_stream_state
*stream
,
123 unsigned int refresh_in_uhz
)
125 unsigned int v_total
;
126 unsigned int frame_duration_in_ns
;
128 frame_duration_in_ns
=
129 ((unsigned int)(div64_u64((1000000000ULL * 1000000),
132 v_total
= div64_u64(div64_u64(((unsigned long long)(
133 frame_duration_in_ns
) * (stream
->timing
.pix_clk_100hz
/ 10)),
134 stream
->timing
.h_total
), 1000000);
136 /* v_total cannot be less than nominal */
137 if (v_total
< stream
->timing
.v_total
) {
138 ASSERT(v_total
< stream
->timing
.v_total
);
139 v_total
= stream
->timing
.v_total
;
145 static unsigned int calc_v_total_from_duration(
146 const struct dc_stream_state
*stream
,
147 const struct mod_vrr_params
*vrr
,
148 unsigned int duration_in_us
)
150 unsigned int v_total
= 0;
152 if (duration_in_us
< vrr
->min_duration_in_us
)
153 duration_in_us
= vrr
->min_duration_in_us
;
155 if (duration_in_us
> vrr
->max_duration_in_us
)
156 duration_in_us
= vrr
->max_duration_in_us
;
158 v_total
= div64_u64(div64_u64(((unsigned long long)(
159 duration_in_us
) * (stream
->timing
.pix_clk_100hz
/ 10)),
160 stream
->timing
.h_total
), 1000);
162 /* v_total cannot be less than nominal */
163 if (v_total
< stream
->timing
.v_total
) {
164 ASSERT(v_total
< stream
->timing
.v_total
);
165 v_total
= stream
->timing
.v_total
;
171 static void update_v_total_for_static_ramp(
172 struct core_freesync
*core_freesync
,
173 const struct dc_stream_state
*stream
,
174 struct mod_vrr_params
*in_out_vrr
)
176 unsigned int v_total
= 0;
177 unsigned int current_duration_in_us
=
178 calc_duration_in_us_from_v_total(
180 in_out_vrr
->adjust
.v_total_max
);
181 unsigned int target_duration_in_us
=
182 calc_duration_in_us_from_refresh_in_uhz(
183 in_out_vrr
->fixed
.target_refresh_in_uhz
);
184 bool ramp_direction_is_up
= (current_duration_in_us
>
185 target_duration_in_us
) ? true : false;
187 /* Calculate ratio between new and current frame duration with 3 digit */
188 unsigned int frame_duration_ratio
= div64_u64(1000000,
189 (1000 + div64_u64(((unsigned long long)(
190 STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME
) *
191 current_duration_in_us
),
194 /* Calculate delta between new and current frame duration in us */
195 unsigned int frame_duration_delta
= div64_u64(((unsigned long long)(
196 current_duration_in_us
) *
197 (1000 - frame_duration_ratio
)), 1000);
199 /* Adjust frame duration delta based on ratio between current and
200 * standard frame duration (frame duration at 60 Hz refresh rate).
202 unsigned int ramp_rate_interpolated
= div64_u64(((unsigned long long)(
203 frame_duration_delta
) * current_duration_in_us
), 16666);
205 /* Going to a higher refresh rate (lower frame duration) */
206 if (ramp_direction_is_up
) {
207 /* Reduce frame duration */
208 current_duration_in_us
-= ramp_rate_interpolated
;
210 /* Adjust for frame duration below min */
211 if (current_duration_in_us
<= target_duration_in_us
) {
212 in_out_vrr
->fixed
.ramping_active
= false;
213 in_out_vrr
->fixed
.ramping_done
= true;
214 current_duration_in_us
=
215 calc_duration_in_us_from_refresh_in_uhz(
216 in_out_vrr
->fixed
.target_refresh_in_uhz
);
218 /* Going to a lower refresh rate (larger frame duration) */
220 /* Increase frame duration */
221 current_duration_in_us
+= ramp_rate_interpolated
;
223 /* Adjust for frame duration above max */
224 if (current_duration_in_us
>= target_duration_in_us
) {
225 in_out_vrr
->fixed
.ramping_active
= false;
226 in_out_vrr
->fixed
.ramping_done
= true;
227 current_duration_in_us
=
228 calc_duration_in_us_from_refresh_in_uhz(
229 in_out_vrr
->fixed
.target_refresh_in_uhz
);
233 v_total
= div64_u64(div64_u64(((unsigned long long)(
234 current_duration_in_us
) * (stream
->timing
.pix_clk_100hz
/ 10)),
235 stream
->timing
.h_total
), 1000);
237 /* v_total cannot be less than nominal */
238 if (v_total
< stream
->timing
.v_total
)
239 v_total
= stream
->timing
.v_total
;
241 in_out_vrr
->adjust
.v_total_min
= v_total
;
242 in_out_vrr
->adjust
.v_total_max
= v_total
;
245 static void apply_below_the_range(struct core_freesync
*core_freesync
,
246 const struct dc_stream_state
*stream
,
247 unsigned int last_render_time_in_us
,
248 struct mod_vrr_params
*in_out_vrr
)
250 unsigned int inserted_frame_duration_in_us
= 0;
251 unsigned int mid_point_frames_ceil
= 0;
252 unsigned int mid_point_frames_floor
= 0;
253 unsigned int frame_time_in_us
= 0;
254 unsigned int delta_from_mid_point_in_us_1
= 0xFFFFFFFF;
255 unsigned int delta_from_mid_point_in_us_2
= 0xFFFFFFFF;
256 unsigned int frames_to_insert
= 0;
257 unsigned int delta_from_mid_point_delta_in_us
;
258 unsigned int max_render_time_in_us
=
259 in_out_vrr
->max_duration_in_us
- in_out_vrr
->btr
.margin_in_us
;
262 if ((last_render_time_in_us
+ in_out_vrr
->btr
.margin_in_us
/ 2) < max_render_time_in_us
) {
263 /* Exit Below the Range */
264 if (in_out_vrr
->btr
.btr_active
) {
265 in_out_vrr
->btr
.frame_counter
= 0;
266 in_out_vrr
->btr
.btr_active
= false;
268 } else if (last_render_time_in_us
> (max_render_time_in_us
+ in_out_vrr
->btr
.margin_in_us
/ 2)) {
269 /* Enter Below the Range */
270 if (!in_out_vrr
->btr
.btr_active
) {
271 in_out_vrr
->btr
.btr_active
= true;
275 /* BTR set to "not active" so disengage */
276 if (!in_out_vrr
->btr
.btr_active
) {
277 in_out_vrr
->btr
.inserted_duration_in_us
= 0;
278 in_out_vrr
->btr
.frames_to_insert
= 0;
279 in_out_vrr
->btr
.frame_counter
= 0;
281 /* Restore FreeSync */
282 in_out_vrr
->adjust
.v_total_min
=
283 calc_v_total_from_refresh(stream
,
284 in_out_vrr
->max_refresh_in_uhz
);
285 in_out_vrr
->adjust
.v_total_max
=
286 calc_v_total_from_refresh(stream
,
287 in_out_vrr
->min_refresh_in_uhz
);
288 /* BTR set to "active" so engage */
291 /* Calculate number of midPoint frames that could fit within
292 * the render time interval - take ceil of this value
294 mid_point_frames_ceil
= (last_render_time_in_us
+
295 in_out_vrr
->btr
.mid_point_in_us
- 1) /
296 in_out_vrr
->btr
.mid_point_in_us
;
298 if (mid_point_frames_ceil
> 0) {
299 frame_time_in_us
= last_render_time_in_us
/
300 mid_point_frames_ceil
;
301 delta_from_mid_point_in_us_1
=
302 (in_out_vrr
->btr
.mid_point_in_us
>
304 (in_out_vrr
->btr
.mid_point_in_us
- frame_time_in_us
) :
305 (frame_time_in_us
- in_out_vrr
->btr
.mid_point_in_us
);
308 /* Calculate number of midPoint frames that could fit within
309 * the render time interval - take floor of this value
311 mid_point_frames_floor
= last_render_time_in_us
/
312 in_out_vrr
->btr
.mid_point_in_us
;
314 if (mid_point_frames_floor
> 0) {
316 frame_time_in_us
= last_render_time_in_us
/
317 mid_point_frames_floor
;
318 delta_from_mid_point_in_us_2
=
319 (in_out_vrr
->btr
.mid_point_in_us
>
321 (in_out_vrr
->btr
.mid_point_in_us
- frame_time_in_us
) :
322 (frame_time_in_us
- in_out_vrr
->btr
.mid_point_in_us
);
325 /* Choose number of frames to insert based on how close it
326 * can get to the mid point of the variable range.
327 * - Delta for CEIL: delta_from_mid_point_in_us_1
328 * - Delta for FLOOR: delta_from_mid_point_in_us_2
330 if ((last_render_time_in_us
/ mid_point_frames_ceil
) < in_out_vrr
->min_duration_in_us
) {
331 /* Check for out of range.
332 * If using CEIL produces a value that is out of range,
333 * then we are forced to use FLOOR.
335 frames_to_insert
= mid_point_frames_floor
;
336 } else if (mid_point_frames_floor
< 2) {
337 /* Check if FLOOR would result in non-LFC. In this case
340 frames_to_insert
= mid_point_frames_ceil
;
341 } else if (delta_from_mid_point_in_us_1
< delta_from_mid_point_in_us_2
) {
342 /* If choosing CEIL results in a frame duration that is
343 * closer to the mid point of the range.
346 frames_to_insert
= mid_point_frames_ceil
;
348 /* If choosing FLOOR results in a frame duration that is
349 * closer to the mid point of the range.
352 frames_to_insert
= mid_point_frames_floor
;
355 /* Prefer current frame multiplier when BTR is enabled unless it drifts
356 * too far from the midpoint
358 if (delta_from_mid_point_in_us_1
< delta_from_mid_point_in_us_2
) {
359 delta_from_mid_point_delta_in_us
= delta_from_mid_point_in_us_2
-
360 delta_from_mid_point_in_us_1
;
362 delta_from_mid_point_delta_in_us
= delta_from_mid_point_in_us_1
-
363 delta_from_mid_point_in_us_2
;
365 if (in_out_vrr
->btr
.frames_to_insert
!= 0 &&
366 delta_from_mid_point_delta_in_us
< BTR_DRIFT_MARGIN
) {
367 if (((last_render_time_in_us
/ in_out_vrr
->btr
.frames_to_insert
) <
368 max_render_time_in_us
) &&
369 ((last_render_time_in_us
/ in_out_vrr
->btr
.frames_to_insert
) >
370 in_out_vrr
->min_duration_in_us
))
371 frames_to_insert
= in_out_vrr
->btr
.frames_to_insert
;
374 /* Either we've calculated the number of frames to insert,
375 * or we need to insert min duration frames
377 if (last_render_time_in_us
/ frames_to_insert
<
378 in_out_vrr
->min_duration_in_us
){
379 frames_to_insert
-= (frames_to_insert
> 1) ?
383 if (frames_to_insert
> 0)
384 inserted_frame_duration_in_us
= last_render_time_in_us
/
387 if (inserted_frame_duration_in_us
< in_out_vrr
->min_duration_in_us
)
388 inserted_frame_duration_in_us
= in_out_vrr
->min_duration_in_us
;
390 /* Cache the calculated variables */
391 in_out_vrr
->btr
.inserted_duration_in_us
=
392 inserted_frame_duration_in_us
;
393 in_out_vrr
->btr
.frames_to_insert
= frames_to_insert
;
394 in_out_vrr
->btr
.frame_counter
= frames_to_insert
;
398 static void apply_fixed_refresh(struct core_freesync
*core_freesync
,
399 const struct dc_stream_state
*stream
,
400 unsigned int last_render_time_in_us
,
401 struct mod_vrr_params
*in_out_vrr
)
404 unsigned int max_render_time_in_us
= in_out_vrr
->max_duration_in_us
;
406 /* Compute the exit refresh rate and exit frame duration */
407 unsigned int exit_refresh_rate_in_milli_hz
= ((1000000000/max_render_time_in_us
)
408 + (1000*FIXED_REFRESH_EXIT_MARGIN_IN_HZ
));
409 unsigned int exit_frame_duration_in_us
= 1000000000/exit_refresh_rate_in_milli_hz
;
411 if (last_render_time_in_us
< exit_frame_duration_in_us
) {
412 /* Exit Fixed Refresh mode */
413 if (in_out_vrr
->fixed
.fixed_active
) {
414 in_out_vrr
->fixed
.frame_counter
++;
416 if (in_out_vrr
->fixed
.frame_counter
>
417 FIXED_REFRESH_EXIT_FRAME_COUNT
) {
418 in_out_vrr
->fixed
.frame_counter
= 0;
419 in_out_vrr
->fixed
.fixed_active
= false;
420 in_out_vrr
->fixed
.target_refresh_in_uhz
= 0;
424 in_out_vrr
->fixed
.frame_counter
= 0;
425 } else if (last_render_time_in_us
> max_render_time_in_us
) {
426 /* Enter Fixed Refresh mode */
427 if (!in_out_vrr
->fixed
.fixed_active
) {
428 in_out_vrr
->fixed
.frame_counter
++;
430 if (in_out_vrr
->fixed
.frame_counter
>
431 FIXED_REFRESH_ENTER_FRAME_COUNT
) {
432 in_out_vrr
->fixed
.frame_counter
= 0;
433 in_out_vrr
->fixed
.fixed_active
= true;
434 in_out_vrr
->fixed
.target_refresh_in_uhz
=
435 in_out_vrr
->max_refresh_in_uhz
;
439 in_out_vrr
->fixed
.frame_counter
= 0;
443 if (in_out_vrr
->fixed
.fixed_active
) {
444 in_out_vrr
->adjust
.v_total_min
=
445 calc_v_total_from_refresh(
446 stream
, in_out_vrr
->max_refresh_in_uhz
);
447 in_out_vrr
->adjust
.v_total_max
=
448 in_out_vrr
->adjust
.v_total_min
;
450 in_out_vrr
->adjust
.v_total_min
=
451 calc_v_total_from_refresh(stream
,
452 in_out_vrr
->max_refresh_in_uhz
);
453 in_out_vrr
->adjust
.v_total_max
=
454 calc_v_total_from_refresh(stream
,
455 in_out_vrr
->min_refresh_in_uhz
);
460 static bool vrr_settings_require_update(struct core_freesync
*core_freesync
,
461 struct mod_freesync_config
*in_config
,
462 unsigned int min_refresh_in_uhz
,
463 unsigned int max_refresh_in_uhz
,
464 struct mod_vrr_params
*in_vrr
)
466 if (in_vrr
->state
!= in_config
->state
) {
468 } else if (in_vrr
->state
== VRR_STATE_ACTIVE_FIXED
&&
469 in_vrr
->fixed
.target_refresh_in_uhz
!=
470 in_config
->fixed_refresh_in_uhz
) {
472 } else if (in_vrr
->min_refresh_in_uhz
!= min_refresh_in_uhz
) {
474 } else if (in_vrr
->max_refresh_in_uhz
!= max_refresh_in_uhz
) {
481 bool mod_freesync_get_vmin_vmax(struct mod_freesync
*mod_freesync
,
482 const struct dc_stream_state
*stream
,
486 *vmin
= stream
->adjust
.v_total_min
;
487 *vmax
= stream
->adjust
.v_total_max
;
492 bool mod_freesync_get_v_position(struct mod_freesync
*mod_freesync
,
493 struct dc_stream_state
*stream
,
494 unsigned int *nom_v_pos
,
497 struct core_freesync
*core_freesync
= NULL
;
498 struct crtc_position position
;
500 if (mod_freesync
== NULL
)
503 core_freesync
= MOD_FREESYNC_TO_CORE(mod_freesync
);
505 if (dc_stream_get_crtc_position(core_freesync
->dc
, &stream
, 1,
506 &position
.vertical_count
,
507 &position
.nominal_vcount
)) {
509 *nom_v_pos
= position
.nominal_vcount
;
510 *v_pos
= position
.vertical_count
;
518 static void build_vrr_infopacket_data_v1(const struct mod_vrr_params
*vrr
,
519 struct dc_info_packet
*infopacket
)
521 /* PB1 = 0x1A (24bit AMD IEEE OUI (0x00001A) - Byte 0) */
522 infopacket
->sb
[1] = 0x1A;
524 /* PB2 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 1) */
525 infopacket
->sb
[2] = 0x00;
527 /* PB3 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 2) */
528 infopacket
->sb
[3] = 0x00;
534 /* PB6 = [Bits 7:3 = Reserved] */
536 /* PB6 = [Bit 0 = FreeSync Supported] */
537 if (vrr
->state
!= VRR_STATE_UNSUPPORTED
)
538 infopacket
->sb
[6] |= 0x01;
540 /* PB6 = [Bit 1 = FreeSync Enabled] */
541 if (vrr
->state
!= VRR_STATE_DISABLED
&&
542 vrr
->state
!= VRR_STATE_UNSUPPORTED
)
543 infopacket
->sb
[6] |= 0x02;
545 /* PB6 = [Bit 2 = FreeSync Active] */
546 if (vrr
->state
== VRR_STATE_ACTIVE_VARIABLE
||
547 vrr
->state
== VRR_STATE_ACTIVE_FIXED
)
548 infopacket
->sb
[6] |= 0x04;
550 // For v1 & 2 infoframes program nominal if non-fs mode, otherwise full range
551 /* PB7 = FreeSync Minimum refresh rate (Hz) */
552 if (vrr
->state
== VRR_STATE_ACTIVE_VARIABLE
||
553 vrr
->state
== VRR_STATE_ACTIVE_FIXED
) {
554 infopacket
->sb
[7] = (unsigned char)((vrr
->min_refresh_in_uhz
+ 500000) / 1000000);
556 infopacket
->sb
[7] = (unsigned char)((vrr
->max_refresh_in_uhz
+ 500000) / 1000000);
559 /* PB8 = FreeSync Maximum refresh rate (Hz)
560 * Note: We should never go above the field rate of the mode timing set.
562 infopacket
->sb
[8] = (unsigned char)((vrr
->max_refresh_in_uhz
+ 500000) / 1000000);
565 infopacket
->sb
[9] = 0;
566 infopacket
->sb
[10] = 0;
569 static void build_vrr_infopacket_data_v3(const struct mod_vrr_params
*vrr
,
570 struct dc_info_packet
*infopacket
)
572 unsigned int min_refresh
;
573 unsigned int max_refresh
;
574 unsigned int fixed_refresh
;
575 unsigned int min_programmed
;
576 unsigned int max_programmed
;
578 /* PB1 = 0x1A (24bit AMD IEEE OUI (0x00001A) - Byte 0) */
579 infopacket
->sb
[1] = 0x1A;
581 /* PB2 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 1) */
582 infopacket
->sb
[2] = 0x00;
584 /* PB3 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 2) */
585 infopacket
->sb
[3] = 0x00;
591 /* PB6 = [Bits 7:3 = Reserved] */
593 /* PB6 = [Bit 0 = FreeSync Supported] */
594 if (vrr
->state
!= VRR_STATE_UNSUPPORTED
)
595 infopacket
->sb
[6] |= 0x01;
597 /* PB6 = [Bit 1 = FreeSync Enabled] */
598 if (vrr
->state
!= VRR_STATE_DISABLED
&&
599 vrr
->state
!= VRR_STATE_UNSUPPORTED
)
600 infopacket
->sb
[6] |= 0x02;
602 /* PB6 = [Bit 2 = FreeSync Active] */
603 if (vrr
->state
== VRR_STATE_ACTIVE_VARIABLE
||
604 vrr
->state
== VRR_STATE_ACTIVE_FIXED
)
605 infopacket
->sb
[6] |= 0x04;
607 min_refresh
= (vrr
->min_refresh_in_uhz
+ 500000) / 1000000;
608 max_refresh
= (vrr
->max_refresh_in_uhz
+ 500000) / 1000000;
609 fixed_refresh
= (vrr
->fixed_refresh_in_uhz
+ 500000) / 1000000;
611 min_programmed
= (vrr
->state
== VRR_STATE_ACTIVE_FIXED
) ? fixed_refresh
:
612 (vrr
->state
== VRR_STATE_ACTIVE_VARIABLE
) ? min_refresh
:
613 (vrr
->state
== VRR_STATE_INACTIVE
) ? min_refresh
:
614 max_refresh
; // Non-fs case, program nominal range
616 max_programmed
= (vrr
->state
== VRR_STATE_ACTIVE_FIXED
) ? fixed_refresh
:
617 (vrr
->state
== VRR_STATE_ACTIVE_VARIABLE
) ? max_refresh
:
618 max_refresh
;// Non-fs case, program nominal range
620 /* PB7 = FreeSync Minimum refresh rate (Hz) */
621 infopacket
->sb
[7] = min_programmed
& 0xFF;
623 /* PB8 = FreeSync Maximum refresh rate (Hz) */
624 infopacket
->sb
[8] = max_programmed
& 0xFF;
626 /* PB11 : MSB FreeSync Minimum refresh rate [Hz] - bits 9:8 */
627 infopacket
->sb
[11] = (min_programmed
>> 8) & 0x03;
629 /* PB12 : MSB FreeSync Maximum refresh rate [Hz] - bits 9:8 */
630 infopacket
->sb
[12] = (max_programmed
>> 8) & 0x03;
632 /* PB16 : Reserved bits 7:1, FixedRate bit 0 */
633 infopacket
->sb
[16] = (vrr
->state
== VRR_STATE_ACTIVE_FIXED
) ? 1 : 0;
636 infopacket
->sb
[9] = 0;
637 infopacket
->sb
[10] = 0;
640 static void build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf
,
641 struct dc_info_packet
*infopacket
)
643 if (app_tf
!= TRANSFER_FUNC_UNKNOWN
) {
644 infopacket
->valid
= true;
646 infopacket
->sb
[6] |= 0x08; // PB6 = [Bit 3 = Native Color Active]
648 if (app_tf
== TRANSFER_FUNC_GAMMA_22
) {
649 infopacket
->sb
[9] |= 0x04; // PB6 = [Bit 2 = Gamma 2.2 EOTF Active]
654 static void build_vrr_infopacket_header_v1(enum signal_type signal
,
655 struct dc_info_packet
*infopacket
,
656 unsigned int *payload_size
)
658 if (dc_is_hdmi_signal(signal
)) {
662 /* HB0 = Packet Type = 0x83 (Source Product
663 * Descriptor InfoFrame)
665 infopacket
->hb0
= DC_HDMI_INFOFRAME_TYPE_SPD
;
667 /* HB1 = Version = 0x01 */
668 infopacket
->hb1
= 0x01;
670 /* HB2 = [Bits 7:5 = 0] [Bits 4:0 = Length = 0x08] */
671 infopacket
->hb2
= 0x08;
673 *payload_size
= 0x08;
675 } else if (dc_is_dp_signal(signal
)) {
679 /* HB0 = Secondary-data Packet ID = 0 - Only non-zero
680 * when used to associate audio related info packets
682 infopacket
->hb0
= 0x00;
684 /* HB1 = Packet Type = 0x83 (Source Product
685 * Descriptor InfoFrame)
687 infopacket
->hb1
= DC_HDMI_INFOFRAME_TYPE_SPD
;
689 /* HB2 = [Bits 7:0 = Least significant eight bits -
690 * For INFOFRAME, the value must be 1Bh]
692 infopacket
->hb2
= 0x1B;
694 /* HB3 = [Bits 7:2 = INFOFRAME SDP Version Number = 0x1]
695 * [Bits 1:0 = Most significant two bits = 0x00]
697 infopacket
->hb3
= 0x04;
699 *payload_size
= 0x1B;
703 static void build_vrr_infopacket_header_v2(enum signal_type signal
,
704 struct dc_info_packet
*infopacket
,
705 unsigned int *payload_size
)
707 if (dc_is_hdmi_signal(signal
)) {
711 /* HB0 = Packet Type = 0x83 (Source Product
712 * Descriptor InfoFrame)
714 infopacket
->hb0
= DC_HDMI_INFOFRAME_TYPE_SPD
;
716 /* HB1 = Version = 0x02 */
717 infopacket
->hb1
= 0x02;
719 /* HB2 = [Bits 7:5 = 0] [Bits 4:0 = Length = 0x09] */
720 infopacket
->hb2
= 0x09;
722 *payload_size
= 0x0A;
724 } else if (dc_is_dp_signal(signal
)) {
728 /* HB0 = Secondary-data Packet ID = 0 - Only non-zero
729 * when used to associate audio related info packets
731 infopacket
->hb0
= 0x00;
733 /* HB1 = Packet Type = 0x83 (Source Product
734 * Descriptor InfoFrame)
736 infopacket
->hb1
= DC_HDMI_INFOFRAME_TYPE_SPD
;
738 /* HB2 = [Bits 7:0 = Least significant eight bits -
739 * For INFOFRAME, the value must be 1Bh]
741 infopacket
->hb2
= 0x1B;
743 /* HB3 = [Bits 7:2 = INFOFRAME SDP Version Number = 0x2]
744 * [Bits 1:0 = Most significant two bits = 0x00]
746 infopacket
->hb3
= 0x08;
748 *payload_size
= 0x1B;
752 static void build_vrr_infopacket_header_v3(enum signal_type signal
,
753 struct dc_info_packet
*infopacket
,
754 unsigned int *payload_size
)
756 unsigned char version
;
759 if (dc_is_hdmi_signal(signal
)) {
763 /* HB0 = Packet Type = 0x83 (Source Product
764 * Descriptor InfoFrame)
766 infopacket
->hb0
= DC_HDMI_INFOFRAME_TYPE_SPD
;
768 /* HB1 = Version = 0x03 */
769 infopacket
->hb1
= version
;
771 /* HB2 = [Bits 7:5 = 0] [Bits 4:0 = Length] */
772 *payload_size
= 0x10;
773 infopacket
->hb2
= *payload_size
- 1; //-1 for checksum
775 } else if (dc_is_dp_signal(signal
)) {
779 /* HB0 = Secondary-data Packet ID = 0 - Only non-zero
780 * when used to associate audio related info packets
782 infopacket
->hb0
= 0x00;
784 /* HB1 = Packet Type = 0x83 (Source Product
785 * Descriptor InfoFrame)
787 infopacket
->hb1
= DC_HDMI_INFOFRAME_TYPE_SPD
;
789 /* HB2 = [Bits 7:0 = Least significant eight bits -
790 * For INFOFRAME, the value must be 1Bh]
792 infopacket
->hb2
= 0x1B;
794 /* HB3 = [Bits 7:2 = INFOFRAME SDP Version Number = 0x2]
795 * [Bits 1:0 = Most significant two bits = 0x00]
798 infopacket
->hb3
= (version
& 0x3F) << 2;
800 *payload_size
= 0x1B;
804 static void build_vrr_infopacket_checksum(unsigned int *payload_size
,
805 struct dc_info_packet
*infopacket
)
807 /* Calculate checksum */
808 unsigned int idx
= 0;
809 unsigned char checksum
= 0;
811 checksum
+= infopacket
->hb0
;
812 checksum
+= infopacket
->hb1
;
813 checksum
+= infopacket
->hb2
;
814 checksum
+= infopacket
->hb3
;
816 for (idx
= 1; idx
<= *payload_size
; idx
++)
817 checksum
+= infopacket
->sb
[idx
];
819 /* PB0 = Checksum (one byte complement) */
820 infopacket
->sb
[0] = (unsigned char)(0x100 - checksum
);
822 infopacket
->valid
= true;
825 static void build_vrr_infopacket_v1(enum signal_type signal
,
826 const struct mod_vrr_params
*vrr
,
827 struct dc_info_packet
*infopacket
)
829 /* SPD info packet for FreeSync */
830 unsigned int payload_size
= 0;
832 build_vrr_infopacket_header_v1(signal
, infopacket
, &payload_size
);
833 build_vrr_infopacket_data_v1(vrr
, infopacket
);
834 build_vrr_infopacket_checksum(&payload_size
, infopacket
);
836 infopacket
->valid
= true;
839 static void build_vrr_infopacket_v2(enum signal_type signal
,
840 const struct mod_vrr_params
*vrr
,
841 enum color_transfer_func app_tf
,
842 struct dc_info_packet
*infopacket
)
844 unsigned int payload_size
= 0;
846 build_vrr_infopacket_header_v2(signal
, infopacket
, &payload_size
);
847 build_vrr_infopacket_data_v1(vrr
, infopacket
);
849 build_vrr_infopacket_fs2_data(app_tf
, infopacket
);
851 build_vrr_infopacket_checksum(&payload_size
, infopacket
);
853 infopacket
->valid
= true;
856 static void build_vrr_infopacket_fast_transport_data(
858 unsigned int ftOutputRate
,
859 struct dc_info_packet
*infopacket
)
861 /* PB9 : bit7 - fast transport Active*/
862 unsigned char activeBit
= (ftActive
) ? 1 << 7 : 0;
864 infopacket
->sb
[1] &= ~activeBit
; //clear bit
865 infopacket
->sb
[1] |= activeBit
; //set bit
867 /* PB13 : Target Output Pixel Rate [kHz] - bits 7:0 */
868 infopacket
->sb
[13] = ftOutputRate
& 0xFF;
870 /* PB14 : Target Output Pixel Rate [kHz] - bits 15:8 */
871 infopacket
->sb
[14] = (ftOutputRate
>> 8) & 0xFF;
873 /* PB15 : Target Output Pixel Rate [kHz] - bits 23:16 */
874 infopacket
->sb
[15] = (ftOutputRate
>> 16) & 0xFF;
879 static void build_vrr_infopacket_v3(enum signal_type signal
,
880 const struct mod_vrr_params
*vrr
,
882 bool ftActive
, unsigned int ftOutputRate
,
884 enum color_transfer_func app_tf
,
885 struct dc_info_packet
*infopacket
)
887 unsigned int payload_size
= 0;
889 build_vrr_infopacket_header_v3(signal
, infopacket
, &payload_size
);
890 build_vrr_infopacket_data_v3(vrr
, infopacket
);
892 build_vrr_infopacket_fs2_data(app_tf
, infopacket
);
895 build_vrr_infopacket_fast_transport_data(
901 build_vrr_infopacket_checksum(&payload_size
, infopacket
);
903 infopacket
->valid
= true;
906 void mod_freesync_build_vrr_infopacket(struct mod_freesync
*mod_freesync
,
907 const struct dc_stream_state
*stream
,
908 const struct mod_vrr_params
*vrr
,
909 enum vrr_packet_type packet_type
,
910 enum color_transfer_func app_tf
,
911 struct dc_info_packet
*infopacket
)
913 /* SPD info packet for FreeSync
914 * VTEM info packet for HdmiVRR
915 * Check if Freesync is supported. Return if false. If true,
916 * set the corresponding bit in the info packet
918 if (!vrr
->send_info_frame
)
921 switch (packet_type
) {
922 case PACKET_TYPE_FS_V3
:
924 // always populate with pixel rate.
925 build_vrr_infopacket_v3(
927 stream
->timing
.flags
.FAST_TRANSPORT
,
928 (stream
->timing
.flags
.FAST_TRANSPORT
) ?
929 stream
->timing
.fast_transport_output_rate_100hz
:
930 stream
->timing
.pix_clk_100hz
,
933 build_vrr_infopacket_v3(stream
->signal
, vrr
, app_tf
, infopacket
);
936 case PACKET_TYPE_FS_V2
:
937 build_vrr_infopacket_v2(stream
->signal
, vrr
, app_tf
, infopacket
);
939 case PACKET_TYPE_VRR
:
940 case PACKET_TYPE_FS_V1
:
942 build_vrr_infopacket_v1(stream
->signal
, vrr
, infopacket
);
946 void mod_freesync_build_vrr_params(struct mod_freesync
*mod_freesync
,
947 const struct dc_stream_state
*stream
,
948 struct mod_freesync_config
*in_config
,
949 struct mod_vrr_params
*in_out_vrr
)
951 struct core_freesync
*core_freesync
= NULL
;
952 unsigned long long nominal_field_rate_in_uhz
= 0;
953 unsigned long long rounded_nominal_in_uhz
= 0;
954 unsigned int refresh_range
= 0;
955 unsigned long long min_refresh_in_uhz
= 0;
956 unsigned long long max_refresh_in_uhz
= 0;
958 if (mod_freesync
== NULL
)
961 core_freesync
= MOD_FREESYNC_TO_CORE(mod_freesync
);
963 /* Calculate nominal field rate for stream */
964 nominal_field_rate_in_uhz
=
965 mod_freesync_calc_nominal_field_rate(stream
);
967 min_refresh_in_uhz
= in_config
->min_refresh_in_uhz
;
968 max_refresh_in_uhz
= in_config
->max_refresh_in_uhz
;
970 /* Full range may be larger than current video timing, so cap at nominal */
971 if (max_refresh_in_uhz
> nominal_field_rate_in_uhz
)
972 max_refresh_in_uhz
= nominal_field_rate_in_uhz
;
974 /* Full range may be larger than current video timing, so cap at nominal */
975 if (min_refresh_in_uhz
> max_refresh_in_uhz
)
976 min_refresh_in_uhz
= max_refresh_in_uhz
;
978 /* If a monitor reports exactly max refresh of 2x of min, enforce it on nominal */
979 rounded_nominal_in_uhz
=
980 div_u64(nominal_field_rate_in_uhz
+ 50000, 100000) * 100000;
981 if (in_config
->max_refresh_in_uhz
== (2 * in_config
->min_refresh_in_uhz
) &&
982 in_config
->max_refresh_in_uhz
== rounded_nominal_in_uhz
)
983 min_refresh_in_uhz
= div_u64(nominal_field_rate_in_uhz
, 2);
985 if (!vrr_settings_require_update(core_freesync
,
986 in_config
, (unsigned int)min_refresh_in_uhz
, (unsigned int)max_refresh_in_uhz
,
990 in_out_vrr
->state
= in_config
->state
;
991 in_out_vrr
->send_info_frame
= in_config
->vsif_supported
;
993 if (in_config
->state
== VRR_STATE_UNSUPPORTED
) {
994 in_out_vrr
->state
= VRR_STATE_UNSUPPORTED
;
995 in_out_vrr
->supported
= false;
996 in_out_vrr
->adjust
.v_total_min
= stream
->timing
.v_total
;
997 in_out_vrr
->adjust
.v_total_max
= stream
->timing
.v_total
;
1002 in_out_vrr
->min_refresh_in_uhz
= (unsigned int)min_refresh_in_uhz
;
1003 in_out_vrr
->max_duration_in_us
=
1004 calc_duration_in_us_from_refresh_in_uhz(
1005 (unsigned int)min_refresh_in_uhz
);
1007 in_out_vrr
->max_refresh_in_uhz
= (unsigned int)max_refresh_in_uhz
;
1008 in_out_vrr
->min_duration_in_us
=
1009 calc_duration_in_us_from_refresh_in_uhz(
1010 (unsigned int)max_refresh_in_uhz
);
1012 if (in_config
->state
== VRR_STATE_ACTIVE_FIXED
)
1013 in_out_vrr
->fixed_refresh_in_uhz
= in_config
->fixed_refresh_in_uhz
;
1015 in_out_vrr
->fixed_refresh_in_uhz
= 0;
1017 refresh_range
= div_u64(in_out_vrr
->max_refresh_in_uhz
+ 500000, 1000000) -
1018 + div_u64(in_out_vrr
->min_refresh_in_uhz
+ 500000, 1000000);
1020 in_out_vrr
->supported
= true;
1023 in_out_vrr
->fixed
.ramping_active
= in_config
->ramping
;
1025 in_out_vrr
->btr
.btr_enabled
= in_config
->btr
;
1027 if (in_out_vrr
->max_refresh_in_uhz
< (2 * in_out_vrr
->min_refresh_in_uhz
))
1028 in_out_vrr
->btr
.btr_enabled
= false;
1030 in_out_vrr
->btr
.margin_in_us
= in_out_vrr
->max_duration_in_us
-
1031 2 * in_out_vrr
->min_duration_in_us
;
1032 if (in_out_vrr
->btr
.margin_in_us
> BTR_MAX_MARGIN
)
1033 in_out_vrr
->btr
.margin_in_us
= BTR_MAX_MARGIN
;
1036 in_out_vrr
->btr
.btr_active
= false;
1037 in_out_vrr
->btr
.inserted_duration_in_us
= 0;
1038 in_out_vrr
->btr
.frames_to_insert
= 0;
1039 in_out_vrr
->btr
.frame_counter
= 0;
1040 in_out_vrr
->fixed
.fixed_active
= false;
1041 in_out_vrr
->fixed
.target_refresh_in_uhz
= 0;
1043 in_out_vrr
->btr
.mid_point_in_us
=
1044 (in_out_vrr
->min_duration_in_us
+
1045 in_out_vrr
->max_duration_in_us
) / 2;
1047 if (in_out_vrr
->state
== VRR_STATE_UNSUPPORTED
) {
1048 in_out_vrr
->adjust
.v_total_min
= stream
->timing
.v_total
;
1049 in_out_vrr
->adjust
.v_total_max
= stream
->timing
.v_total
;
1050 } else if (in_out_vrr
->state
== VRR_STATE_DISABLED
) {
1051 in_out_vrr
->adjust
.v_total_min
= stream
->timing
.v_total
;
1052 in_out_vrr
->adjust
.v_total_max
= stream
->timing
.v_total
;
1053 } else if (in_out_vrr
->state
== VRR_STATE_INACTIVE
) {
1054 in_out_vrr
->adjust
.v_total_min
= stream
->timing
.v_total
;
1055 in_out_vrr
->adjust
.v_total_max
= stream
->timing
.v_total
;
1056 } else if (in_out_vrr
->state
== VRR_STATE_ACTIVE_VARIABLE
&&
1057 refresh_range
>= MIN_REFRESH_RANGE
) {
1059 in_out_vrr
->adjust
.v_total_min
=
1060 calc_v_total_from_refresh(stream
,
1061 in_out_vrr
->max_refresh_in_uhz
);
1062 in_out_vrr
->adjust
.v_total_max
=
1063 calc_v_total_from_refresh(stream
,
1064 in_out_vrr
->min_refresh_in_uhz
);
1065 } else if (in_out_vrr
->state
== VRR_STATE_ACTIVE_FIXED
) {
1066 in_out_vrr
->fixed
.target_refresh_in_uhz
=
1067 in_out_vrr
->fixed_refresh_in_uhz
;
1068 if (in_out_vrr
->fixed
.ramping_active
&&
1069 in_out_vrr
->fixed
.fixed_active
) {
1070 /* Do not update vtotals if ramping is already active
1071 * in order to continue ramp from current refresh.
1073 in_out_vrr
->fixed
.fixed_active
= true;
1075 in_out_vrr
->fixed
.fixed_active
= true;
1076 in_out_vrr
->adjust
.v_total_min
=
1077 calc_v_total_from_refresh(stream
,
1078 in_out_vrr
->fixed
.target_refresh_in_uhz
);
1079 in_out_vrr
->adjust
.v_total_max
=
1080 in_out_vrr
->adjust
.v_total_min
;
1083 in_out_vrr
->state
= VRR_STATE_INACTIVE
;
1084 in_out_vrr
->adjust
.v_total_min
= stream
->timing
.v_total
;
1085 in_out_vrr
->adjust
.v_total_max
= stream
->timing
.v_total
;
1089 void mod_freesync_handle_preflip(struct mod_freesync
*mod_freesync
,
1090 const struct dc_plane_state
*plane
,
1091 const struct dc_stream_state
*stream
,
1092 unsigned int curr_time_stamp_in_us
,
1093 struct mod_vrr_params
*in_out_vrr
)
1095 struct core_freesync
*core_freesync
= NULL
;
1096 unsigned int last_render_time_in_us
= 0;
1097 unsigned int average_render_time_in_us
= 0;
1099 if (mod_freesync
== NULL
)
1102 core_freesync
= MOD_FREESYNC_TO_CORE(mod_freesync
);
1104 if (in_out_vrr
->supported
&&
1105 in_out_vrr
->state
== VRR_STATE_ACTIVE_VARIABLE
) {
1107 unsigned int oldest_index
= plane
->time
.index
+ 1;
1109 if (oldest_index
>= DC_PLANE_UPDATE_TIMES_MAX
)
1112 last_render_time_in_us
= curr_time_stamp_in_us
-
1113 plane
->time
.prev_update_time_in_us
;
1115 /* Sum off all entries except oldest one */
1116 for (i
= 0; i
< DC_PLANE_UPDATE_TIMES_MAX
; i
++) {
1117 average_render_time_in_us
+=
1118 plane
->time
.time_elapsed_in_us
[i
];
1120 average_render_time_in_us
-=
1121 plane
->time
.time_elapsed_in_us
[oldest_index
];
1123 /* Add render time for current flip */
1124 average_render_time_in_us
+= last_render_time_in_us
;
1125 average_render_time_in_us
/= DC_PLANE_UPDATE_TIMES_MAX
;
1127 if (in_out_vrr
->btr
.btr_enabled
) {
1128 apply_below_the_range(core_freesync
,
1130 last_render_time_in_us
,
1133 apply_fixed_refresh(core_freesync
,
1135 last_render_time_in_us
,
1142 void mod_freesync_handle_v_update(struct mod_freesync
*mod_freesync
,
1143 const struct dc_stream_state
*stream
,
1144 struct mod_vrr_params
*in_out_vrr
)
1146 struct core_freesync
*core_freesync
= NULL
;
1148 if ((mod_freesync
== NULL
) || (stream
== NULL
) || (in_out_vrr
== NULL
))
1151 core_freesync
= MOD_FREESYNC_TO_CORE(mod_freesync
);
1153 if (in_out_vrr
->supported
== false)
1156 /* Below the Range Logic */
1158 /* Only execute if in fullscreen mode */
1159 if (in_out_vrr
->state
== VRR_STATE_ACTIVE_VARIABLE
&&
1160 in_out_vrr
->btr
.btr_active
) {
1161 /* TODO: pass in flag for Pre-DCE12 ASIC
1162 * in order for frame variable duration to take affect,
1163 * it needs to be done one VSYNC early, which is at
1164 * frameCounter == 1.
1165 * For DCE12 and newer updates to V_TOTAL_MIN/MAX
1166 * will take affect on current frame
1168 if (in_out_vrr
->btr
.frames_to_insert
==
1169 in_out_vrr
->btr
.frame_counter
) {
1170 in_out_vrr
->adjust
.v_total_min
=
1171 calc_v_total_from_duration(stream
,
1173 in_out_vrr
->btr
.inserted_duration_in_us
);
1174 in_out_vrr
->adjust
.v_total_max
=
1175 in_out_vrr
->adjust
.v_total_min
;
1178 if (in_out_vrr
->btr
.frame_counter
> 0)
1179 in_out_vrr
->btr
.frame_counter
--;
1181 /* Restore FreeSync */
1182 if (in_out_vrr
->btr
.frame_counter
== 0) {
1183 in_out_vrr
->adjust
.v_total_min
=
1184 calc_v_total_from_refresh(stream
,
1185 in_out_vrr
->max_refresh_in_uhz
);
1186 in_out_vrr
->adjust
.v_total_max
=
1187 calc_v_total_from_refresh(stream
,
1188 in_out_vrr
->min_refresh_in_uhz
);
1192 /* If in fullscreen freesync mode or in video, do not program
1193 * static screen ramp values
1195 if (in_out_vrr
->state
== VRR_STATE_ACTIVE_VARIABLE
)
1196 in_out_vrr
->fixed
.ramping_active
= false;
1198 /* Gradual Static Screen Ramping Logic
1199 * Execute if ramp is active and user enabled freesync static screen
1201 if (in_out_vrr
->state
== VRR_STATE_ACTIVE_FIXED
&&
1202 in_out_vrr
->fixed
.ramping_active
) {
1203 update_v_total_for_static_ramp(
1204 core_freesync
, stream
, in_out_vrr
);
1208 void mod_freesync_get_settings(struct mod_freesync
*mod_freesync
,
1209 const struct mod_vrr_params
*vrr
,
1210 unsigned int *v_total_min
, unsigned int *v_total_max
,
1211 unsigned int *event_triggers
,
1212 unsigned int *window_min
, unsigned int *window_max
,
1213 unsigned int *lfc_mid_point_in_us
,
1214 unsigned int *inserted_frames
,
1215 unsigned int *inserted_duration_in_us
)
1217 if (mod_freesync
== NULL
)
1220 if (vrr
->supported
) {
1221 *v_total_min
= vrr
->adjust
.v_total_min
;
1222 *v_total_max
= vrr
->adjust
.v_total_max
;
1223 *event_triggers
= 0;
1224 *lfc_mid_point_in_us
= vrr
->btr
.mid_point_in_us
;
1225 *inserted_frames
= vrr
->btr
.frames_to_insert
;
1226 *inserted_duration_in_us
= vrr
->btr
.inserted_duration_in_us
;
1230 unsigned long long mod_freesync_calc_nominal_field_rate(
1231 const struct dc_stream_state
*stream
)
1233 unsigned long long nominal_field_rate_in_uhz
= 0;
1234 unsigned int total
= stream
->timing
.h_total
* stream
->timing
.v_total
;
1236 /* Calculate nominal field rate for stream, rounded up to nearest integer */
1237 nominal_field_rate_in_uhz
= stream
->timing
.pix_clk_100hz
;
1238 nominal_field_rate_in_uhz
*= 100000000ULL;
1240 nominal_field_rate_in_uhz
= div_u64(nominal_field_rate_in_uhz
, total
);
1242 return nominal_field_rate_in_uhz
;
1245 bool mod_freesync_is_valid_range(uint32_t min_refresh_cap_in_uhz
,
1246 uint32_t max_refresh_cap_in_uhz
,
1247 uint32_t nominal_field_rate_in_uhz
)
1250 /* Typically nominal refresh calculated can have some fractional part.
1251 * Allow for some rounding error of actual video timing by taking floor
1252 * of caps and request. Round the nominal refresh rate.
1254 * Dividing will convert everything to units in Hz although input
1255 * variable name is in uHz!
1257 * Also note, this takes care of rounding error on the nominal refresh
1258 * so by rounding error we only expect it to be off by a small amount,
1259 * such as < 0.1 Hz. i.e. 143.9xxx or 144.1xxx.
1261 * Example 1. Caps Min = 40 Hz, Max = 144 Hz
1262 * Request Min = 40 Hz, Max = 144 Hz
1263 * Nominal = 143.5x Hz rounded to 144 Hz
1264 * This function should allow this as valid request
1266 * Example 2. Caps Min = 40 Hz, Max = 144 Hz
1267 * Request Min = 40 Hz, Max = 144 Hz
1268 * Nominal = 144.4x Hz rounded to 144 Hz
1269 * This function should allow this as valid request
1271 * Example 3. Caps Min = 40 Hz, Max = 144 Hz
1272 * Request Min = 40 Hz, Max = 144 Hz
1273 * Nominal = 120.xx Hz rounded to 120 Hz
1274 * This function should return NOT valid since the requested
1275 * max is greater than current timing's nominal
1277 * Example 4. Caps Min = 40 Hz, Max = 120 Hz
1278 * Request Min = 40 Hz, Max = 120 Hz
1279 * Nominal = 144.xx Hz rounded to 144 Hz
1280 * This function should return NOT valid since the nominal
1281 * is greater than the capability's max refresh
1283 nominal_field_rate_in_uhz
=
1284 div_u64(nominal_field_rate_in_uhz
+ 500000, 1000000);
1285 min_refresh_cap_in_uhz
/= 1000000;
1286 max_refresh_cap_in_uhz
/= 1000000;
1288 /* Check nominal is within range */
1289 if (nominal_field_rate_in_uhz
> max_refresh_cap_in_uhz
||
1290 nominal_field_rate_in_uhz
< min_refresh_cap_in_uhz
)
1293 /* If nominal is less than max, limit the max allowed refresh rate */
1294 if (nominal_field_rate_in_uhz
< max_refresh_cap_in_uhz
)
1295 max_refresh_cap_in_uhz
= nominal_field_rate_in_uhz
;
1297 /* Check min is within range */
1298 if (min_refresh_cap_in_uhz
> max_refresh_cap_in_uhz
)
1301 /* For variable range, check for at least 10 Hz range */
1302 if (nominal_field_rate_in_uhz
- min_refresh_cap_in_uhz
< 10)