xref: /linux/drivers/gpu/drm/amd/display/modules/freesync/freesync.c (revision 9e1e9d660255d7216067193d774f338d08d8528d)
1 /*
2  * Copyright 2016-2023 Advanced Micro Devices, Inc.
3  *
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:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
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.
21  *
22  * Authors: AMD
23  *
24  */
25 
26 #include "dm_services.h"
27 #include "dc.h"
28 #include "mod_freesync.h"
29 #include "core_types.h"
30 
31 #define MOD_FREESYNC_MAX_CONCURRENT_STREAMS  32
32 
33 #define MIN_REFRESH_RANGE 10
34 /* Refresh rate ramp at a fixed rate of 65 Hz/second */
35 #define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65)
36 /* Number of elements in the render times cache array */
37 #define RENDER_TIMES_MAX_COUNT 10
38 /* Threshold to exit/exit BTR (to avoid frequent enter-exits at the lower limit) */
39 #define BTR_MAX_MARGIN 2500
40 /* Threshold to change BTR multiplier (to avoid frequent changes) */
41 #define BTR_DRIFT_MARGIN 2000
42 /* Threshold to exit fixed refresh rate */
43 #define FIXED_REFRESH_EXIT_MARGIN_IN_HZ 1
44 /* Number of consecutive frames to check before entering/exiting fixed refresh */
45 #define FIXED_REFRESH_ENTER_FRAME_COUNT 5
46 #define FIXED_REFRESH_EXIT_FRAME_COUNT 10
47 /* Flip interval workaround constants */
48 #define VSYNCS_BETWEEN_FLIP_THRESHOLD 2
49 #define FREESYNC_CONSEC_FLIP_AFTER_VSYNC 5
50 #define FREESYNC_VSYNC_TO_FLIP_DELTA_IN_US 500
51 #define MICRO_HZ_TO_HZ(x) (x / 1000000)
52 
53 struct core_freesync {
54 	struct mod_freesync public;
55 	struct dc *dc;
56 };
57 
58 #define MOD_FREESYNC_TO_CORE(mod_freesync)\
59 		container_of(mod_freesync, struct core_freesync, public)
60 
61 struct mod_freesync *mod_freesync_create(struct dc *dc)
62 {
63 	struct core_freesync *core_freesync =
64 			kzalloc_obj(struct core_freesync);
65 
66 	if (core_freesync == NULL)
67 		goto fail_alloc_context;
68 
69 	if (dc == NULL)
70 		goto fail_construct;
71 
72 	core_freesync->dc = dc;
73 	return &core_freesync->public;
74 
75 fail_construct:
76 	kfree(core_freesync);
77 
78 fail_alloc_context:
79 	return NULL;
80 }
81 
82 void mod_freesync_destroy(struct mod_freesync *mod_freesync)
83 {
84 	struct core_freesync *core_freesync = NULL;
85 
86 	if (mod_freesync == NULL)
87 		return;
88 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
89 	kfree(core_freesync);
90 }
91 
92 #if 0 /* Unused currently */
93 static unsigned int calc_refresh_in_uhz_from_duration(
94 		unsigned int duration_in_ns)
95 {
96 	unsigned int refresh_in_uhz =
97 			((unsigned int)(div64_u64((1000000000ULL * 1000000),
98 					duration_in_ns)));
99 	return refresh_in_uhz;
100 }
101 #endif
102 
103 static unsigned int calc_duration_in_us_from_refresh_in_uhz(
104 		unsigned int refresh_in_uhz)
105 {
106 	unsigned int duration_in_us =
107 			((unsigned int)(div64_u64((1000000000ULL * 1000),
108 					refresh_in_uhz)));
109 	return duration_in_us;
110 }
111 
112 static unsigned int calc_duration_in_us_from_v_total(
113 		const struct dc_stream_state *stream,
114 		const struct mod_vrr_params *in_vrr,
115 		unsigned int v_total)
116 {
117 	(void)in_vrr;
118 	unsigned int duration_in_us =
119 			(unsigned int)(div64_u64(((unsigned long long)(v_total)
120 				* 10000) * stream->timing.h_total,
121 					stream->timing.pix_clk_100hz));
122 
123 	return duration_in_us;
124 }
125 
126 static unsigned int calc_max_hardware_v_total(const struct dc_stream_state *stream)
127 {
128 	unsigned int max_hw_v_total = stream->ctx->dc->caps.max_v_total;
129 
130 	if (stream->ctx->dc->caps.vtotal_limited_by_fp2) {
131 		max_hw_v_total -= stream->timing.v_front_porch + 1;
132 	}
133 
134 	return max_hw_v_total;
135 }
136 
137 unsigned int mod_freesync_calc_v_total_from_refresh(
138 		const struct dc_stream_state *stream,
139 		unsigned int refresh_in_uhz)
140 {
141 	unsigned int v_total;
142 	unsigned int frame_duration_in_ns;
143 
144 	if (refresh_in_uhz == 0)
145 		return stream->timing.v_total;
146 
147 	frame_duration_in_ns =
148 			((unsigned int)(div64_u64((1000000000ULL * 1000000),
149 					refresh_in_uhz)));
150 
151 	if (refresh_in_uhz <= stream->timing.min_refresh_in_uhz) {
152 		/* When the target refresh rate is the minimum panel refresh rate,
153 		 * round down the vtotal value to avoid stretching vblank over
154 		 * panel's vtotal boundary.
155 		 */
156 		v_total = div64_u64(div64_u64(((unsigned long long)(
157 				frame_duration_in_ns) * (stream->timing.pix_clk_100hz / 10)),
158 				stream->timing.h_total), 1000000);
159 	} else if (refresh_in_uhz >= stream->timing.max_refresh_in_uhz) {
160 		/* When the target refresh rate is the maximum panel refresh rate
161 		 * round up the vtotal value to prevent off-by-one error causing
162 		 * v_total_min to be below the panel's lower bound
163 		 */
164 		v_total = div64_u64(div64_u64(((unsigned long long)(
165 				frame_duration_in_ns) * (stream->timing.pix_clk_100hz / 10)),
166 				stream->timing.h_total) + (1000000 - 1), 1000000);
167 	} else {
168 		v_total = div64_u64(div64_u64(((unsigned long long)(
169 				frame_duration_in_ns) * (stream->timing.pix_clk_100hz / 10)),
170 				stream->timing.h_total) + 500000, 1000000);
171 	}
172 
173 	/* v_total cannot be less than nominal */
174 	if (v_total < stream->timing.v_total) {
175 		ASSERT(v_total < stream->timing.v_total);
176 		v_total = stream->timing.v_total;
177 	}
178 
179 	return v_total;
180 }
181 
182 static unsigned int calc_v_total_from_duration(
183 		const struct dc_stream_state *stream,
184 		const struct mod_vrr_params *vrr,
185 		unsigned int duration_in_us)
186 {
187 	unsigned int v_total = 0;
188 
189 	if (duration_in_us < vrr->min_duration_in_us)
190 		duration_in_us = vrr->min_duration_in_us;
191 
192 	if (duration_in_us > vrr->max_duration_in_us)
193 		duration_in_us = vrr->max_duration_in_us;
194 
195 	if (dc_is_hdmi_signal(stream->signal)) { // change for HDMI to comply with spec
196 		uint32_t h_total_up_scaled;
197 
198 		h_total_up_scaled = stream->timing.h_total * 10000;
199 		v_total = div_u64((unsigned long long)duration_in_us
200 					* stream->timing.pix_clk_100hz + (h_total_up_scaled - 1),
201 					h_total_up_scaled); //ceiling for MMax and MMin for MVRR
202 	} else {
203 		v_total = div64_u64(div64_u64(((unsigned long long)(
204 					duration_in_us) * (stream->timing.pix_clk_100hz / 10)),
205 					stream->timing.h_total), 1000);
206 	}
207 
208 	/* v_total cannot be less than nominal */
209 	if (v_total < stream->timing.v_total) {
210 		ASSERT(v_total < stream->timing.v_total);
211 		v_total = stream->timing.v_total;
212 	}
213 
214 	return v_total;
215 }
216 
217 static void update_v_total_for_static_ramp(
218 		struct core_freesync *core_freesync,
219 		const struct dc_stream_state *stream,
220 		struct mod_vrr_params *in_out_vrr)
221 {
222 	(void)core_freesync;
223 	unsigned int v_total = 0;
224 	unsigned int current_duration_in_us =
225 			calc_duration_in_us_from_v_total(
226 				stream, in_out_vrr,
227 				in_out_vrr->adjust.v_total_max);
228 	unsigned int target_duration_in_us =
229 			calc_duration_in_us_from_refresh_in_uhz(
230 				in_out_vrr->fixed.target_refresh_in_uhz);
231 	bool ramp_direction_is_up = current_duration_in_us >
232 				target_duration_in_us;
233 
234 	/* Calculate ratio between new and current frame duration with 3 digit */
235 	unsigned int frame_duration_ratio = div64_u64(1000000,
236 		(1000 +  div64_u64(((unsigned long long)(
237 		STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME) *
238 		current_duration_in_us),
239 		1000000)));
240 
241 	/* Calculate delta between new and current frame duration in us */
242 	unsigned int frame_duration_delta = div64_u64(((unsigned long long)(
243 		current_duration_in_us) *
244 		(1000 - frame_duration_ratio)), 1000);
245 
246 	/* Adjust frame duration delta based on ratio between current and
247 	 * standard frame duration (frame duration at 60 Hz refresh rate).
248 	 */
249 	unsigned int ramp_rate_interpolated = div64_u64(((unsigned long long)(
250 		frame_duration_delta) * current_duration_in_us), 16666);
251 
252 	/* Going to a higher refresh rate (lower frame duration) */
253 	if (ramp_direction_is_up) {
254 		/* Reduce frame duration */
255 		current_duration_in_us -= ramp_rate_interpolated;
256 
257 		/* Adjust for frame duration below min */
258 		if (current_duration_in_us <= target_duration_in_us) {
259 			in_out_vrr->fixed.ramping_active = false;
260 			in_out_vrr->fixed.ramping_done = true;
261 			current_duration_in_us =
262 				calc_duration_in_us_from_refresh_in_uhz(
263 				in_out_vrr->fixed.target_refresh_in_uhz);
264 		}
265 	/* Going to a lower refresh rate (larger frame duration) */
266 	} else {
267 		/* Increase frame duration */
268 		current_duration_in_us += ramp_rate_interpolated;
269 
270 		/* Adjust for frame duration above max */
271 		if (current_duration_in_us >= target_duration_in_us) {
272 			in_out_vrr->fixed.ramping_active = false;
273 			in_out_vrr->fixed.ramping_done = true;
274 			current_duration_in_us =
275 				calc_duration_in_us_from_refresh_in_uhz(
276 				in_out_vrr->fixed.target_refresh_in_uhz);
277 		}
278 	}
279 
280 	v_total = div64_u64(div64_u64(((unsigned long long)(
281 			current_duration_in_us) * (stream->timing.pix_clk_100hz / 10)),
282 				stream->timing.h_total), 1000);
283 
284 	/* v_total cannot be less than nominal */
285 	if (v_total < stream->timing.v_total)
286 		v_total = stream->timing.v_total;
287 
288 	in_out_vrr->adjust.v_total_min = v_total;
289 	in_out_vrr->adjust.v_total_max = v_total;
290 }
291 
292 static void apply_below_the_range(struct core_freesync *core_freesync,
293 		const struct dc_stream_state *stream,
294 		unsigned int last_render_time_in_us,
295 		struct mod_vrr_params *in_out_vrr)
296 {
297 	(void)core_freesync;
298 	unsigned int inserted_frame_duration_in_us = 0;
299 	unsigned int mid_point_frames_ceil = 0;
300 	unsigned int mid_point_frames_floor = 0;
301 	unsigned int frame_time_in_us = 0;
302 	unsigned int delta_from_mid_point_in_us_1 = 0xFFFFFFFF;
303 	unsigned int delta_from_mid_point_in_us_2 = 0xFFFFFFFF;
304 	unsigned int frames_to_insert = 0;
305 	unsigned int delta_from_mid_point_delta_in_us;
306 	unsigned int max_render_time_in_us =
307 			in_out_vrr->max_duration_in_us - in_out_vrr->btr.margin_in_us;
308 
309 	/* Program BTR */
310 	if ((last_render_time_in_us + in_out_vrr->btr.margin_in_us / 2) < max_render_time_in_us) {
311 		/* Exit Below the Range */
312 		if (in_out_vrr->btr.btr_active) {
313 			in_out_vrr->btr.frame_counter = 0;
314 			in_out_vrr->btr.btr_active = false;
315 		}
316 	} else if (last_render_time_in_us > (max_render_time_in_us + in_out_vrr->btr.margin_in_us / 2)) {
317 		/* Enter Below the Range */
318 		if (!in_out_vrr->btr.btr_active)
319 			in_out_vrr->btr.btr_active = true;
320 	}
321 
322 	/* BTR set to "not active" so disengage */
323 	if (!in_out_vrr->btr.btr_active) {
324 		in_out_vrr->btr.inserted_duration_in_us = 0;
325 		in_out_vrr->btr.frames_to_insert = 0;
326 		in_out_vrr->btr.frame_counter = 0;
327 
328 		/* Restore FreeSync */
329 		in_out_vrr->adjust.v_total_min =
330 			mod_freesync_calc_v_total_from_refresh(stream,
331 				in_out_vrr->max_refresh_in_uhz);
332 		in_out_vrr->adjust.v_total_max =
333 			mod_freesync_calc_v_total_from_refresh(stream,
334 				in_out_vrr->min_refresh_in_uhz);
335 	/* BTR set to "active" so engage */
336 	} else {
337 
338 		/* Calculate number of midPoint frames that could fit within
339 		 * the render time interval - take ceil of this value
340 		 */
341 		mid_point_frames_ceil = (last_render_time_in_us +
342 				in_out_vrr->btr.mid_point_in_us - 1) /
343 					in_out_vrr->btr.mid_point_in_us;
344 
345 		if (mid_point_frames_ceil > 0) {
346 			frame_time_in_us = last_render_time_in_us /
347 				mid_point_frames_ceil;
348 			delta_from_mid_point_in_us_1 =
349 				(in_out_vrr->btr.mid_point_in_us >
350 				frame_time_in_us) ?
351 				(in_out_vrr->btr.mid_point_in_us - frame_time_in_us) :
352 				(frame_time_in_us - in_out_vrr->btr.mid_point_in_us);
353 		}
354 
355 		/* Calculate number of midPoint frames that could fit within
356 		 * the render time interval - take floor of this value
357 		 */
358 		mid_point_frames_floor = last_render_time_in_us /
359 				in_out_vrr->btr.mid_point_in_us;
360 
361 		if (mid_point_frames_floor > 0) {
362 
363 			frame_time_in_us = last_render_time_in_us /
364 				mid_point_frames_floor;
365 			delta_from_mid_point_in_us_2 =
366 				(in_out_vrr->btr.mid_point_in_us >
367 				frame_time_in_us) ?
368 				(in_out_vrr->btr.mid_point_in_us - frame_time_in_us) :
369 				(frame_time_in_us - in_out_vrr->btr.mid_point_in_us);
370 		}
371 
372 		/* Choose number of frames to insert based on how close it
373 		 * can get to the mid point of the variable range.
374 		 *  - Delta for CEIL: delta_from_mid_point_in_us_1
375 		 *  - Delta for FLOOR: delta_from_mid_point_in_us_2
376 		 */
377 		if (mid_point_frames_ceil &&
378 		    (last_render_time_in_us / mid_point_frames_ceil) <
379 		    in_out_vrr->min_duration_in_us) {
380 			/* Check for out of range.
381 			 * If using CEIL produces a value that is out of range,
382 			 * then we are forced to use FLOOR.
383 			 */
384 			frames_to_insert = mid_point_frames_floor;
385 		} else if (mid_point_frames_floor < 2) {
386 			/* Check if FLOOR would result in non-LFC. In this case
387 			 * choose to use CEIL
388 			 */
389 			frames_to_insert = mid_point_frames_ceil;
390 		} else if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) {
391 			/* If choosing CEIL results in a frame duration that is
392 			 * closer to the mid point of the range.
393 			 * Choose CEIL
394 			 */
395 			frames_to_insert = mid_point_frames_ceil;
396 		} else {
397 			/* If choosing FLOOR results in a frame duration that is
398 			 * closer to the mid point of the range.
399 			 * Choose FLOOR
400 			 */
401 			frames_to_insert = mid_point_frames_floor;
402 		}
403 
404 		/* Prefer current frame multiplier when BTR is enabled unless it drifts
405 		 * too far from the midpoint
406 		 */
407 		if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) {
408 			delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_2 -
409 					delta_from_mid_point_in_us_1;
410 		} else {
411 			delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_1 -
412 					delta_from_mid_point_in_us_2;
413 		}
414 		if (in_out_vrr->btr.frames_to_insert != 0 &&
415 				delta_from_mid_point_delta_in_us < BTR_DRIFT_MARGIN) {
416 			if (((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) <
417 					max_render_time_in_us) &&
418 				((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) >
419 					in_out_vrr->min_duration_in_us))
420 				frames_to_insert = in_out_vrr->btr.frames_to_insert;
421 		}
422 
423 		/* Either we've calculated the number of frames to insert,
424 		 * or we need to insert min duration frames
425 		 */
426 		if (frames_to_insert &&
427 		    (last_render_time_in_us / frames_to_insert) <
428 		    in_out_vrr->min_duration_in_us){
429 			frames_to_insert -= (frames_to_insert > 1) ?
430 					1 : 0;
431 		}
432 
433 		if (frames_to_insert > 0)
434 			inserted_frame_duration_in_us = last_render_time_in_us /
435 							frames_to_insert;
436 
437 		if (inserted_frame_duration_in_us < in_out_vrr->min_duration_in_us)
438 			inserted_frame_duration_in_us = in_out_vrr->min_duration_in_us;
439 
440 		/* Cache the calculated variables */
441 		in_out_vrr->btr.inserted_duration_in_us =
442 			inserted_frame_duration_in_us;
443 		in_out_vrr->btr.frames_to_insert = frames_to_insert;
444 		in_out_vrr->btr.frame_counter = frames_to_insert;
445 	}
446 }
447 
448 static void apply_fixed_refresh(struct core_freesync *core_freesync,
449 		const struct dc_stream_state *stream,
450 		unsigned int last_render_time_in_us,
451 		struct mod_vrr_params *in_out_vrr)
452 {
453 	(void)core_freesync;
454 	bool update = false;
455 	unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us;
456 
457 	/* Compute the exit refresh rate and exit frame duration */
458 	unsigned int exit_refresh_rate_in_milli_hz = ((1000000000/max_render_time_in_us)
459 			+ (1000*FIXED_REFRESH_EXIT_MARGIN_IN_HZ));
460 	unsigned int exit_frame_duration_in_us = 1000000000/exit_refresh_rate_in_milli_hz;
461 
462 	if (last_render_time_in_us < exit_frame_duration_in_us) {
463 		/* Exit Fixed Refresh mode */
464 		if (in_out_vrr->fixed.fixed_active) {
465 			in_out_vrr->fixed.frame_counter++;
466 
467 			if (in_out_vrr->fixed.frame_counter >
468 					FIXED_REFRESH_EXIT_FRAME_COUNT) {
469 				in_out_vrr->fixed.frame_counter = 0;
470 				in_out_vrr->fixed.fixed_active = false;
471 				in_out_vrr->fixed.target_refresh_in_uhz = 0;
472 				update = true;
473 			}
474 		} else
475 			in_out_vrr->fixed.frame_counter = 0;
476 	} else if (last_render_time_in_us > max_render_time_in_us) {
477 		/* Enter Fixed Refresh mode */
478 		if (!in_out_vrr->fixed.fixed_active) {
479 			in_out_vrr->fixed.frame_counter++;
480 
481 			if (in_out_vrr->fixed.frame_counter >
482 					FIXED_REFRESH_ENTER_FRAME_COUNT) {
483 				in_out_vrr->fixed.frame_counter = 0;
484 				in_out_vrr->fixed.fixed_active = true;
485 				in_out_vrr->fixed.target_refresh_in_uhz =
486 						in_out_vrr->max_refresh_in_uhz;
487 				update = true;
488 			}
489 		} else
490 			in_out_vrr->fixed.frame_counter = 0;
491 	}
492 
493 	if (update) {
494 		if (in_out_vrr->fixed.fixed_active) {
495 			in_out_vrr->adjust.v_total_min =
496 				mod_freesync_calc_v_total_from_refresh(
497 				stream, in_out_vrr->max_refresh_in_uhz);
498 			in_out_vrr->adjust.v_total_max =
499 					in_out_vrr->adjust.v_total_min;
500 		} else {
501 			in_out_vrr->adjust.v_total_min =
502 				mod_freesync_calc_v_total_from_refresh(stream,
503 					in_out_vrr->max_refresh_in_uhz);
504 			in_out_vrr->adjust.v_total_max =
505 				mod_freesync_calc_v_total_from_refresh(stream,
506 					in_out_vrr->min_refresh_in_uhz);
507 		}
508 	}
509 }
510 
511 static void determine_flip_interval_workaround_req(struct mod_vrr_params *in_vrr,
512 		unsigned int curr_time_stamp_in_us)
513 {
514 	in_vrr->flip_interval.vsync_to_flip_in_us = curr_time_stamp_in_us -
515 			in_vrr->flip_interval.v_update_timestamp_in_us;
516 
517 	/* Determine conditions for stopping workaround */
518 	if (in_vrr->flip_interval.flip_interval_workaround_active &&
519 			in_vrr->flip_interval.vsyncs_between_flip < VSYNCS_BETWEEN_FLIP_THRESHOLD &&
520 			in_vrr->flip_interval.vsync_to_flip_in_us > FREESYNC_VSYNC_TO_FLIP_DELTA_IN_US) {
521 		in_vrr->flip_interval.flip_interval_detect_counter = 0;
522 		in_vrr->flip_interval.program_flip_interval_workaround = true;
523 		in_vrr->flip_interval.flip_interval_workaround_active = false;
524 	} else {
525 		/* Determine conditions for starting workaround */
526 		if (in_vrr->flip_interval.vsyncs_between_flip >= VSYNCS_BETWEEN_FLIP_THRESHOLD &&
527 				in_vrr->flip_interval.vsync_to_flip_in_us < FREESYNC_VSYNC_TO_FLIP_DELTA_IN_US) {
528 			/* Increase flip interval counter we have 2 vsyncs between flips and
529 			 * vsync to flip interval is less than 500us
530 			 */
531 			in_vrr->flip_interval.flip_interval_detect_counter++;
532 			if (in_vrr->flip_interval.flip_interval_detect_counter > FREESYNC_CONSEC_FLIP_AFTER_VSYNC) {
533 				/* Start workaround if we detect 5 consecutive instances of the above case */
534 				in_vrr->flip_interval.program_flip_interval_workaround = true;
535 				in_vrr->flip_interval.flip_interval_workaround_active = true;
536 			}
537 		} else {
538 			/* Reset the flip interval counter if we condition is no longer met */
539 			in_vrr->flip_interval.flip_interval_detect_counter = 0;
540 		}
541 	}
542 
543 	in_vrr->flip_interval.vsyncs_between_flip = 0;
544 }
545 
546 static bool vrr_settings_require_update(struct core_freesync *core_freesync,
547 		struct mod_freesync_config *in_config,
548 		unsigned int min_refresh_in_uhz,
549 		unsigned int max_refresh_in_uhz,
550 		struct mod_vrr_params *in_vrr)
551 {
552 	(void)core_freesync;
553 	if (in_vrr->state != in_config->state) {
554 		return true;
555 	} else if (in_vrr->state == VRR_STATE_ACTIVE_FIXED &&
556 			in_vrr->fixed.target_refresh_in_uhz !=
557 					in_config->fixed_refresh_in_uhz) {
558 		return true;
559 	} else if (in_vrr->min_refresh_in_uhz != min_refresh_in_uhz) {
560 		return true;
561 	} else if (in_vrr->max_refresh_in_uhz != max_refresh_in_uhz) {
562 		return true;
563 	}
564 
565 	return false;
566 }
567 
568 static void build_vrr_infopacket_data_v1(const struct mod_vrr_params *vrr,
569 		struct dc_info_packet *infopacket,
570 		bool freesync_on_desktop)
571 {
572 	/* PB1 = 0x1A (24bit AMD IEEE OUI (0x00001A) - Byte 0) */
573 	infopacket->sb[1] = 0x1A;
574 
575 	/* PB2 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 1) */
576 	infopacket->sb[2] = 0x00;
577 
578 	/* PB3 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 2) */
579 	infopacket->sb[3] = 0x00;
580 
581 	/* PB4 = Reserved */
582 
583 	/* PB5 = Reserved */
584 
585 	/* PB6 = [Bits 7:3 = Reserved] */
586 
587 	/* PB6 = [Bit 0 = FreeSync Supported] */
588 	if (vrr->state != VRR_STATE_UNSUPPORTED)
589 		infopacket->sb[6] |= 0x01;
590 
591 	/* PB6 = [Bit 1 = FreeSync Enabled] */
592 	if (vrr->state != VRR_STATE_DISABLED &&
593 			vrr->state != VRR_STATE_UNSUPPORTED)
594 		infopacket->sb[6] |= 0x02;
595 
596 	if (freesync_on_desktop) {
597 		/* PB6 = [Bit 2 = FreeSync Active] */
598 		if (vrr->state != VRR_STATE_DISABLED &&
599 			vrr->state != VRR_STATE_UNSUPPORTED)
600 			infopacket->sb[6] |= 0x04;
601 	} else {
602 		if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
603 			vrr->state == VRR_STATE_ACTIVE_FIXED)
604 			infopacket->sb[6] |= 0x04;
605 	}
606 
607 	// For v1 & 2 infoframes program nominal if non-fs mode, otherwise full range
608 	/* PB7 = FreeSync Minimum refresh rate (Hz) */
609 	if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
610 			vrr->state == VRR_STATE_ACTIVE_FIXED) {
611 		infopacket->sb[7] = (unsigned char)((vrr->min_refresh_in_uhz + 500000) / 1000000);
612 	} else {
613 		infopacket->sb[7] = (unsigned char)((vrr->max_refresh_in_uhz + 500000) / 1000000);
614 	}
615 
616 	/* PB8 = FreeSync Maximum refresh rate (Hz)
617 	 * Note: We should never go above the field rate of the mode timing set.
618 	 */
619 	infopacket->sb[8] = (unsigned char)((vrr->max_refresh_in_uhz + 500000) / 1000000);
620 }
621 
622 static void build_vrr_infopacket_data_v3(const struct mod_vrr_params *vrr,
623 		struct dc_info_packet *infopacket,
624 		bool freesync_on_desktop)
625 {
626 	unsigned int min_refresh;
627 	unsigned int max_refresh;
628 	unsigned int fixed_refresh;
629 	unsigned int min_programmed;
630 
631 	/* PB1 = 0x1A (24bit AMD IEEE OUI (0x00001A) - Byte 0) */
632 	infopacket->sb[1] = 0x1A;
633 
634 	/* PB2 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 1) */
635 	infopacket->sb[2] = 0x00;
636 
637 	/* PB3 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 2) */
638 	infopacket->sb[3] = 0x00;
639 
640 	/* PB4 = Reserved */
641 
642 	/* PB5 = Reserved */
643 
644 	/* PB6 = [Bits 7:3 = Reserved] */
645 
646 	/* PB6 = [Bit 0 = FreeSync Supported] */
647 	if (vrr->state != VRR_STATE_UNSUPPORTED)
648 		infopacket->sb[6] |= 0x01;
649 
650 	/* PB6 = [Bit 1 = FreeSync Enabled] */
651 	if (vrr->state != VRR_STATE_DISABLED &&
652 			vrr->state != VRR_STATE_UNSUPPORTED)
653 		infopacket->sb[6] |= 0x02;
654 
655 	/* PB6 = [Bit 2 = FreeSync Active] */
656 	if (freesync_on_desktop) {
657 		if (vrr->state != VRR_STATE_DISABLED &&
658 			vrr->state != VRR_STATE_UNSUPPORTED)
659 			infopacket->sb[6] |= 0x04;
660 	} else {
661 		if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
662 			vrr->state == VRR_STATE_ACTIVE_FIXED)
663 			infopacket->sb[6] |= 0x04;
664 	}
665 
666 	min_refresh = (vrr->min_refresh_in_uhz + 500000) / 1000000;
667 	max_refresh = (vrr->max_refresh_in_uhz + 500000) / 1000000;
668 	fixed_refresh = (vrr->fixed_refresh_in_uhz + 500000) / 1000000;
669 
670 	min_programmed = (vrr->state == VRR_STATE_ACTIVE_FIXED) ? fixed_refresh :
671 			(vrr->state == VRR_STATE_ACTIVE_VARIABLE) ? min_refresh :
672 			(vrr->state == VRR_STATE_INACTIVE) ? min_refresh :
673 			max_refresh; // Non-fs case, program nominal range
674 
675 	/* PB7 = FreeSync Minimum refresh rate (Hz) */
676 	infopacket->sb[7] = min_programmed & 0xFF;
677 
678 	/* PB8 = FreeSync Maximum refresh rate (Hz) */
679 	infopacket->sb[8] = max_refresh & 0xFF;
680 
681 	/* PB11 : MSB FreeSync Minimum refresh rate [Hz] - bits 9:8 */
682 	infopacket->sb[11] = (min_programmed >> 8) & 0x03;
683 
684 	/* PB12 : MSB FreeSync Maximum refresh rate [Hz] - bits 9:8 */
685 	infopacket->sb[12] = (max_refresh >> 8) & 0x03;
686 
687 	/* PB16 : Reserved bits 7:1, FixedRate bit 0 */
688 	infopacket->sb[16] = (vrr->state == VRR_STATE_ACTIVE_FIXED) ? 1 : 0;
689 }
690 
691 static void build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf,
692 		struct dc_info_packet *infopacket)
693 {
694 	if (app_tf != TRANSFER_FUNC_UNKNOWN) {
695 		infopacket->valid = true;
696 
697 		if (app_tf == TRANSFER_FUNC_PQ2084)
698 			infopacket->sb[9] |= 0x20; // PB9 = [Bit 5 = PQ EOTF Active]
699 		else {
700 			infopacket->sb[6] |= 0x08;  // PB6 = [Bit 3 = Native Color Active]
701 			if (app_tf == TRANSFER_FUNC_GAMMA_22)
702 				infopacket->sb[9] |= 0x04;  // PB9 = [Bit 2 = Gamma 2.2 EOTF Active]
703 		}
704 	}
705 }
706 
707 static void build_vrr_infopacket_header_v1(enum signal_type signal,
708 		struct dc_info_packet *infopacket,
709 		unsigned int *payload_size)
710 {
711 	if (dc_is_hdmi_signal(signal)) {
712 
713 		/* HEADER */
714 
715 		/* HB0  = Packet Type = 0x83 (Source Product
716 		 *	  Descriptor InfoFrame)
717 		 */
718 		infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
719 
720 		/* HB1  = Version = 0x01 */
721 		infopacket->hb1 = 0x01;
722 
723 		/* HB2  = [Bits 7:5 = 0] [Bits 4:0 = Length = 0x08] */
724 		infopacket->hb2 = 0x08;
725 
726 		*payload_size = 0x08;
727 
728 	} else if (dc_is_dp_signal(signal)) {
729 
730 		/* HEADER */
731 
732 		/* HB0  = Secondary-data Packet ID = 0 - Only non-zero
733 		 *	  when used to associate audio related info packets
734 		 */
735 		infopacket->hb0 = 0x00;
736 
737 		/* HB1  = Packet Type = 0x83 (Source Product
738 		 *	  Descriptor InfoFrame)
739 		 */
740 		infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
741 
742 		/* HB2  = [Bits 7:0 = Least significant eight bits -
743 		 *	  For INFOFRAME, the value must be 1Bh]
744 		 */
745 		infopacket->hb2 = 0x1B;
746 
747 		/* HB3  = [Bits 7:2 = INFOFRAME SDP Version Number = 0x1]
748 		 *	  [Bits 1:0 = Most significant two bits = 0x00]
749 		 */
750 		infopacket->hb3 = 0x04;
751 
752 		*payload_size = 0x1B;
753 	}
754 }
755 
756 static void build_vrr_infopacket_header_v2(enum signal_type signal,
757 		struct dc_info_packet *infopacket,
758 		unsigned int *payload_size)
759 {
760 	if (dc_is_hdmi_signal(signal)) {
761 
762 		/* HEADER */
763 
764 		/* HB0  = Packet Type = 0x83 (Source Product
765 		 *	  Descriptor InfoFrame)
766 		 */
767 		infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
768 
769 		/* HB1  = Version = 0x02 */
770 		infopacket->hb1 = 0x02;
771 
772 		/* HB2  = [Bits 7:5 = 0] [Bits 4:0 = Length = 0x09] */
773 		infopacket->hb2 = 0x09;
774 
775 		*payload_size = 0x09;
776 	} else if (dc_is_dp_signal(signal)) {
777 
778 		/* HEADER */
779 
780 		/* HB0  = Secondary-data Packet ID = 0 - Only non-zero
781 		 *	  when used to associate audio related info packets
782 		 */
783 		infopacket->hb0 = 0x00;
784 
785 		/* HB1  = Packet Type = 0x83 (Source Product
786 		 *	  Descriptor InfoFrame)
787 		 */
788 		infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
789 
790 		/* HB2  = [Bits 7:0 = Least significant eight bits -
791 		 *	  For INFOFRAME, the value must be 1Bh]
792 		 */
793 		infopacket->hb2 = 0x1B;
794 
795 		/* HB3  = [Bits 7:2 = INFOFRAME SDP Version Number = 0x2]
796 		 *	  [Bits 1:0 = Most significant two bits = 0x00]
797 		 */
798 		infopacket->hb3 = 0x08;
799 
800 		*payload_size = 0x1B;
801 	}
802 }
803 
804 static void build_vrr_infopacket_header_v3(enum signal_type signal,
805 		struct dc_info_packet *infopacket,
806 		unsigned int *payload_size)
807 {
808 	unsigned char version;
809 
810 	version = 3;
811 	if (dc_is_hdmi_signal(signal)) {
812 
813 		/* HEADER */
814 
815 		/* HB0  = Packet Type = 0x83 (Source Product
816 		 *	  Descriptor InfoFrame)
817 		 */
818 		infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
819 
820 		/* HB1  = Version = 0x03 */
821 		infopacket->hb1 = version;
822 
823 		/* HB2  = [Bits 7:5 = 0] [Bits 4:0 = Length] */
824 		infopacket->hb2 = 0x10;
825 
826 		*payload_size = 0x10;
827 	} else if (dc_is_dp_signal(signal)) {
828 
829 		/* HEADER */
830 
831 		/* HB0  = Secondary-data Packet ID = 0 - Only non-zero
832 		 *	  when used to associate audio related info packets
833 		 */
834 		infopacket->hb0 = 0x00;
835 
836 		/* HB1  = Packet Type = 0x83 (Source Product
837 		 *	  Descriptor InfoFrame)
838 		 */
839 		infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
840 
841 		/* HB2  = [Bits 7:0 = Least significant eight bits -
842 		 *	  For INFOFRAME, the value must be 1Bh]
843 		 */
844 		infopacket->hb2 = 0x1B;
845 
846 		/* HB3  = [Bits 7:2 = INFOFRAME SDP Version Number = 0x2]
847 		 *	  [Bits 1:0 = Most significant two bits = 0x00]
848 		 */
849 
850 		infopacket->hb3 = (version & 0x3F) << 2;
851 
852 		*payload_size = 0x1B;
853 	}
854 }
855 
856 static void build_vrr_infopacket_checksum(unsigned int *payload_size,
857 		struct dc_info_packet *infopacket)
858 {
859 	/* Calculate checksum */
860 	unsigned int idx = 0;
861 	unsigned char checksum = 0;
862 
863 	checksum += infopacket->hb0;
864 	checksum += infopacket->hb1;
865 	checksum += infopacket->hb2;
866 	checksum += infopacket->hb3;
867 
868 	for (idx = 1; idx <= *payload_size; idx++)
869 		checksum += infopacket->sb[idx];
870 
871 	/* PB0 = Checksum (one byte complement) */
872 	infopacket->sb[0] = (unsigned char)(0x100 - checksum);
873 
874 	infopacket->valid = true;
875 }
876 
877 static void build_vrr_infopacket_v1(enum signal_type signal,
878 		const struct mod_vrr_params *vrr,
879 		struct dc_info_packet *infopacket,
880 		bool freesync_on_desktop)
881 {
882 	/* SPD info packet for FreeSync */
883 	unsigned int payload_size = 0;
884 
885 	build_vrr_infopacket_header_v1(signal, infopacket, &payload_size);
886 	build_vrr_infopacket_data_v1(vrr, infopacket, freesync_on_desktop);
887 	build_vrr_infopacket_checksum(&payload_size, infopacket);
888 
889 	infopacket->valid = true;
890 }
891 
892 static void build_vrr_infopacket_v2(enum signal_type signal,
893 		const struct mod_vrr_params *vrr,
894 		enum color_transfer_func app_tf,
895 		struct dc_info_packet *infopacket,
896 		bool freesync_on_desktop)
897 {
898 	unsigned int payload_size = 0;
899 
900 	build_vrr_infopacket_header_v2(signal, infopacket, &payload_size);
901 	build_vrr_infopacket_data_v1(vrr, infopacket, freesync_on_desktop);
902 
903 	build_vrr_infopacket_fs2_data(app_tf, infopacket);
904 
905 	build_vrr_infopacket_checksum(&payload_size, infopacket);
906 
907 	infopacket->valid = true;
908 }
909 
910 static void build_vrr_infopacket_v3(enum signal_type signal,
911 		const struct mod_vrr_params *vrr,
912 		enum color_transfer_func app_tf,
913 		struct dc_info_packet *infopacket,
914 		bool freesync_on_desktop)
915 {
916 	unsigned int payload_size = 0;
917 
918 	build_vrr_infopacket_header_v3(signal, infopacket, &payload_size);
919 	build_vrr_infopacket_data_v3(vrr, infopacket, freesync_on_desktop);
920 
921 	build_vrr_infopacket_fs2_data(app_tf, infopacket);
922 
923 	build_vrr_infopacket_checksum(&payload_size, infopacket);
924 
925 	infopacket->valid = true;
926 }
927 
928 static void build_vrr_infopacket_sdp_v1_3(enum vrr_packet_type packet_type,
929 										struct dc_info_packet *infopacket)
930 {
931 	uint8_t idx = 0, size = 0;
932 
933 	size = ((packet_type == PACKET_TYPE_FS_V1) ? 0x08 :
934 			(packet_type == PACKET_TYPE_FS_V3) ? 0x10 :
935 												0x09);
936 
937 	for (idx = infopacket->hb2; idx > 1; idx--) // Data Byte Count: 0x1B
938 		infopacket->sb[idx] = infopacket->sb[idx-1];
939 
940 	infopacket->sb[1] = size;                         // Length
941 	infopacket->sb[0] = (infopacket->hb3 >> 2) & 0x3F;//Version
942 	infopacket->hb3   = (0x13 << 2);                  // Header,SDP 1.3
943 	infopacket->hb2   = 0x1D;
944 }
945 
946 void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync,
947 		const struct dc_stream_state *stream,
948 		const struct mod_vrr_params *vrr,
949 		enum vrr_packet_type packet_type,
950 		enum color_transfer_func app_tf,
951 		struct dc_info_packet *infopacket,
952 		bool pack_sdp_v1_3)
953 {
954 	(void)mod_freesync;
955 	/* SPD info packet for FreeSync
956 	 * VTEM info packet for HdmiVRR
957 	 * Check if Freesync is supported. Return if false. If true,
958 	 * set the corresponding bit in the info packet
959 	 */
960 	if (!vrr->send_info_frame)
961 		return;
962 
963 	switch (packet_type) {
964 	case PACKET_TYPE_FS_V3:
965 		build_vrr_infopacket_v3(stream->signal, vrr, app_tf, infopacket, stream->freesync_on_desktop);
966 		break;
967 	case PACKET_TYPE_FS_V2:
968 		build_vrr_infopacket_v2(stream->signal, vrr, app_tf, infopacket, stream->freesync_on_desktop);
969 		break;
970 	case PACKET_TYPE_VRR:
971 	case PACKET_TYPE_FS_V1:
972 	default:
973 		build_vrr_infopacket_v1(stream->signal, vrr, infopacket, stream->freesync_on_desktop);
974 	}
975 
976 	if (true == pack_sdp_v1_3 &&
977 		true == dc_is_dp_signal(stream->signal) &&
978 		packet_type != PACKET_TYPE_VRR &&
979 		packet_type != PACKET_TYPE_VTEM)
980 		build_vrr_infopacket_sdp_v1_3(packet_type, infopacket);
981 }
982 
983 void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync,
984 		const struct dc_stream_state *stream,
985 		struct mod_freesync_config *in_config,
986 		struct mod_vrr_params *in_out_vrr)
987 {
988 	struct core_freesync *core_freesync = NULL;
989 	unsigned long long nominal_field_rate_in_uhz = 0;
990 	unsigned long long rounded_nominal_in_uhz = 0;
991 	unsigned int refresh_range = 0;
992 	unsigned long long min_refresh_in_uhz = 0;
993 	unsigned long long max_refresh_in_uhz = 0;
994 	unsigned long long min_hardware_refresh_in_uhz = 0;
995 
996 	if (mod_freesync == NULL)
997 		return;
998 
999 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1000 
1001 	/* Calculate nominal field rate for stream */
1002 	nominal_field_rate_in_uhz =
1003 			mod_freesync_calc_nominal_field_rate(stream);
1004 
1005 	if (stream->ctx->dc->caps.max_v_total != 0 && stream->timing.h_total != 0) {
1006 		min_hardware_refresh_in_uhz = div64_u64((stream->timing.pix_clk_100hz * 100000000ULL),
1007 			(stream->timing.h_total * (long long)calc_max_hardware_v_total(stream)));
1008 	}
1009 	/* Limit minimum refresh rate to what can be supported by hardware */
1010 	min_refresh_in_uhz = min_hardware_refresh_in_uhz > in_config->min_refresh_in_uhz ?
1011 		min_hardware_refresh_in_uhz : in_config->min_refresh_in_uhz;
1012 	max_refresh_in_uhz = in_config->max_refresh_in_uhz;
1013 
1014 	/* Full range may be larger than current video timing, so cap at nominal */
1015 	if (max_refresh_in_uhz > nominal_field_rate_in_uhz)
1016 		max_refresh_in_uhz = nominal_field_rate_in_uhz;
1017 
1018 	/* Full range may be larger than current video timing, so cap at nominal */
1019 	if (min_refresh_in_uhz > max_refresh_in_uhz)
1020 		min_refresh_in_uhz = max_refresh_in_uhz;
1021 
1022 	/* If a monitor reports exactly max refresh of 2x of min, enforce it on nominal */
1023 	rounded_nominal_in_uhz =
1024 			div_u64(nominal_field_rate_in_uhz + 50000, 100000) * 100000;
1025 	if (in_config->max_refresh_in_uhz == (2 * in_config->min_refresh_in_uhz) &&
1026 		in_config->max_refresh_in_uhz == rounded_nominal_in_uhz)
1027 		min_refresh_in_uhz = div_u64(nominal_field_rate_in_uhz, 2);
1028 
1029 	if (!vrr_settings_require_update(core_freesync,
1030 			in_config, (unsigned int)min_refresh_in_uhz, (unsigned int)max_refresh_in_uhz,
1031 			in_out_vrr))
1032 		return;
1033 
1034 	in_out_vrr->state = in_config->state;
1035 	in_out_vrr->send_info_frame = in_config->vsif_supported;
1036 
1037 	if (in_config->state == VRR_STATE_UNSUPPORTED) {
1038 		in_out_vrr->state = VRR_STATE_UNSUPPORTED;
1039 		in_out_vrr->supported = false;
1040 		in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1041 		in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1042 
1043 		return;
1044 
1045 	} else {
1046 		in_out_vrr->min_refresh_in_uhz = (unsigned int)min_refresh_in_uhz;
1047 		in_out_vrr->max_duration_in_us =
1048 				calc_duration_in_us_from_refresh_in_uhz(
1049 						(unsigned int)min_refresh_in_uhz);
1050 
1051 		in_out_vrr->max_refresh_in_uhz = (unsigned int)max_refresh_in_uhz;
1052 		in_out_vrr->min_duration_in_us =
1053 				calc_duration_in_us_from_refresh_in_uhz(
1054 						(unsigned int)max_refresh_in_uhz);
1055 
1056 		if (in_config->state == VRR_STATE_ACTIVE_FIXED)
1057 			in_out_vrr->fixed_refresh_in_uhz = in_config->fixed_refresh_in_uhz;
1058 		else
1059 			in_out_vrr->fixed_refresh_in_uhz = 0;
1060 
1061 		refresh_range = div_u64(in_out_vrr->max_refresh_in_uhz + 500000, 1000000) -
1062 				div_u64(in_out_vrr->min_refresh_in_uhz + 500000, 1000000);
1063 
1064 		in_out_vrr->supported = true;
1065 	}
1066 
1067 	in_out_vrr->fixed.ramping_active = in_config->ramping;
1068 
1069 	in_out_vrr->btr.btr_enabled = in_config->btr;
1070 
1071 	if (in_out_vrr->max_refresh_in_uhz < (2 * in_out_vrr->min_refresh_in_uhz))
1072 		in_out_vrr->btr.btr_enabled = false;
1073 	else {
1074 		in_out_vrr->btr.margin_in_us = in_out_vrr->max_duration_in_us -
1075 				2 * in_out_vrr->min_duration_in_us;
1076 		if (in_out_vrr->btr.margin_in_us > BTR_MAX_MARGIN)
1077 			in_out_vrr->btr.margin_in_us = BTR_MAX_MARGIN;
1078 	}
1079 
1080 	in_out_vrr->btr.btr_active = false;
1081 	in_out_vrr->btr.inserted_duration_in_us = 0;
1082 	in_out_vrr->btr.frames_to_insert = 0;
1083 	in_out_vrr->btr.frame_counter = 0;
1084 	in_out_vrr->fixed.fixed_active = false;
1085 	in_out_vrr->fixed.target_refresh_in_uhz = 0;
1086 
1087 	in_out_vrr->btr.mid_point_in_us =
1088 				(in_out_vrr->min_duration_in_us +
1089 				 in_out_vrr->max_duration_in_us) / 2;
1090 
1091 	if (in_out_vrr->state == VRR_STATE_UNSUPPORTED) {
1092 		in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1093 		in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1094 	} else if (in_out_vrr->state == VRR_STATE_DISABLED) {
1095 		in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1096 		in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1097 	} else if (in_out_vrr->state == VRR_STATE_INACTIVE) {
1098 		in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1099 		in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1100 	} else if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE &&
1101 			refresh_range >= MIN_REFRESH_RANGE) {
1102 
1103 		in_out_vrr->adjust.v_total_min =
1104 			mod_freesync_calc_v_total_from_refresh(stream,
1105 				in_out_vrr->max_refresh_in_uhz);
1106 		in_out_vrr->adjust.v_total_max =
1107 			mod_freesync_calc_v_total_from_refresh(stream,
1108 				in_out_vrr->min_refresh_in_uhz);
1109 	} else if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED) {
1110 		in_out_vrr->fixed.target_refresh_in_uhz =
1111 				in_out_vrr->fixed_refresh_in_uhz;
1112 		if (in_out_vrr->fixed.ramping_active &&
1113 				in_out_vrr->fixed.fixed_active) {
1114 			/* Do not update vtotals if ramping is already active
1115 			 * in order to continue ramp from current refresh.
1116 			 */
1117 			in_out_vrr->fixed.fixed_active = true;
1118 		} else {
1119 			in_out_vrr->fixed.fixed_active = true;
1120 			in_out_vrr->adjust.v_total_min =
1121 				mod_freesync_calc_v_total_from_refresh(stream,
1122 					in_out_vrr->fixed.target_refresh_in_uhz);
1123 			in_out_vrr->adjust.v_total_max =
1124 				in_out_vrr->adjust.v_total_min;
1125 		}
1126 	} else {
1127 		in_out_vrr->state = VRR_STATE_INACTIVE;
1128 		in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1129 		in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1130 	}
1131 
1132 	in_out_vrr->adjust.allow_otg_v_count_halt = (in_config->state == VRR_STATE_ACTIVE_FIXED) ? true : false;
1133 }
1134 
1135 void mod_freesync_handle_preflip(struct mod_freesync *mod_freesync,
1136 		const struct dc_plane_state *plane,
1137 		const struct dc_stream_state *stream,
1138 		unsigned int curr_time_stamp_in_us,
1139 		struct mod_vrr_params *in_out_vrr)
1140 {
1141 	struct core_freesync *core_freesync = NULL;
1142 	unsigned int last_render_time_in_us = 0;
1143 
1144 	if (mod_freesync == NULL)
1145 		return;
1146 
1147 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1148 
1149 	if (in_out_vrr->supported &&
1150 			in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE) {
1151 
1152 		last_render_time_in_us = curr_time_stamp_in_us -
1153 				plane->time.prev_update_time_in_us;
1154 
1155 		if (in_out_vrr->btr.btr_enabled) {
1156 			apply_below_the_range(core_freesync,
1157 					stream,
1158 					last_render_time_in_us,
1159 					in_out_vrr);
1160 		} else {
1161 			apply_fixed_refresh(core_freesync,
1162 				stream,
1163 				last_render_time_in_us,
1164 				in_out_vrr);
1165 		}
1166 
1167 		determine_flip_interval_workaround_req(in_out_vrr,
1168 				curr_time_stamp_in_us);
1169 
1170 	}
1171 }
1172 
1173 void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync,
1174 		const struct dc_stream_state *stream,
1175 		struct mod_vrr_params *in_out_vrr)
1176 {
1177 	struct core_freesync *core_freesync = NULL;
1178 	unsigned int cur_timestamp_in_us;
1179 	unsigned long long cur_tick;
1180 
1181 	if ((mod_freesync == NULL) || (stream == NULL) || (in_out_vrr == NULL))
1182 		return;
1183 
1184 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1185 
1186 	if (in_out_vrr->supported == false)
1187 		return;
1188 
1189 	cur_tick = dm_get_timestamp(core_freesync->dc->ctx);
1190 	cur_timestamp_in_us = (unsigned int)
1191 			div_u64(dm_get_elapse_time_in_ns(core_freesync->dc->ctx, cur_tick, 0), 1000);
1192 
1193 	in_out_vrr->flip_interval.vsyncs_between_flip++;
1194 	in_out_vrr->flip_interval.v_update_timestamp_in_us = cur_timestamp_in_us;
1195 
1196 	if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE &&
1197 			(in_out_vrr->flip_interval.flip_interval_workaround_active ||
1198 			(!in_out_vrr->flip_interval.flip_interval_workaround_active &&
1199 			in_out_vrr->flip_interval.program_flip_interval_workaround))) {
1200 		// set freesync vmin vmax to nominal for workaround
1201 		in_out_vrr->adjust.v_total_min =
1202 			mod_freesync_calc_v_total_from_refresh(
1203 			stream, in_out_vrr->max_refresh_in_uhz);
1204 		in_out_vrr->adjust.v_total_max =
1205 				in_out_vrr->adjust.v_total_min;
1206 		in_out_vrr->flip_interval.program_flip_interval_workaround = false;
1207 		in_out_vrr->flip_interval.do_flip_interval_workaround_cleanup = true;
1208 		return;
1209 	}
1210 
1211 	if (in_out_vrr->state != VRR_STATE_ACTIVE_VARIABLE &&
1212 			in_out_vrr->flip_interval.do_flip_interval_workaround_cleanup) {
1213 		in_out_vrr->flip_interval.do_flip_interval_workaround_cleanup = false;
1214 		in_out_vrr->flip_interval.flip_interval_detect_counter = 0;
1215 		in_out_vrr->flip_interval.vsyncs_between_flip = 0;
1216 		in_out_vrr->flip_interval.vsync_to_flip_in_us = 0;
1217 	}
1218 
1219 	/* Below the Range Logic */
1220 
1221 	/* Only execute if in fullscreen mode */
1222 	if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE &&
1223 					in_out_vrr->btr.btr_active) {
1224 		/* TODO: pass in flag for Pre-DCE12 ASIC
1225 		 * in order for frame variable duration to take affect,
1226 		 * it needs to be done one VSYNC early, which is at
1227 		 * frameCounter == 1.
1228 		 * For DCE12 and newer updates to V_TOTAL_MIN/MAX
1229 		 * will take affect on current frame
1230 		 */
1231 		if (in_out_vrr->btr.frames_to_insert ==
1232 				in_out_vrr->btr.frame_counter) {
1233 			in_out_vrr->adjust.v_total_min =
1234 				calc_v_total_from_duration(stream,
1235 				in_out_vrr,
1236 				in_out_vrr->btr.inserted_duration_in_us);
1237 			in_out_vrr->adjust.v_total_max =
1238 				in_out_vrr->adjust.v_total_min;
1239 		}
1240 
1241 		if (in_out_vrr->btr.frame_counter > 0)
1242 			in_out_vrr->btr.frame_counter--;
1243 
1244 		/* Restore FreeSync */
1245 		if (in_out_vrr->btr.frame_counter == 0) {
1246 			in_out_vrr->adjust.v_total_min =
1247 				mod_freesync_calc_v_total_from_refresh(stream,
1248 				in_out_vrr->max_refresh_in_uhz);
1249 			in_out_vrr->adjust.v_total_max =
1250 				mod_freesync_calc_v_total_from_refresh(stream,
1251 				in_out_vrr->min_refresh_in_uhz);
1252 		}
1253 	}
1254 
1255 	/* If in fullscreen freesync mode or in video, do not program
1256 	 * static screen ramp values
1257 	 */
1258 	if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE)
1259 		in_out_vrr->fixed.ramping_active = false;
1260 
1261 	/* Gradual Static Screen Ramping Logic
1262 	 * Execute if ramp is active and user enabled freesync static screen
1263 	 */
1264 	if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED &&
1265 				in_out_vrr->fixed.ramping_active) {
1266 		update_v_total_for_static_ramp(
1267 				core_freesync, stream, in_out_vrr);
1268 	}
1269 
1270 	/*
1271 	 * If VRR is inactive, set vtotal min and max to nominal vtotal
1272 	 */
1273 	 if (in_out_vrr->state == VRR_STATE_INACTIVE) {
1274 		in_out_vrr->adjust.v_total_min =
1275 			mod_freesync_calc_v_total_from_refresh(stream,
1276 				in_out_vrr->max_refresh_in_uhz);
1277 		in_out_vrr->adjust.v_total_max = in_out_vrr->adjust.v_total_min;
1278 		return;
1279 	}
1280 }
1281 
1282 unsigned long long mod_freesync_calc_nominal_field_rate(
1283 			const struct dc_stream_state *stream)
1284 {
1285 	unsigned long long nominal_field_rate_in_uhz = 0;
1286 	unsigned int total = stream->timing.h_total * stream->timing.v_total;
1287 
1288 	/* Calculate nominal field rate for stream, rounded up to nearest integer */
1289 	nominal_field_rate_in_uhz = stream->timing.pix_clk_100hz;
1290 	nominal_field_rate_in_uhz *= 100000000ULL;
1291 
1292 	nominal_field_rate_in_uhz =	div_u64(nominal_field_rate_in_uhz, total);
1293 
1294 	return nominal_field_rate_in_uhz;
1295 }
1296 
1297 bool mod_freesync_get_freesync_enabled(struct mod_vrr_params *pVrr)
1298 {
1299 	return (pVrr->state != VRR_STATE_UNSUPPORTED) && (pVrr->state != VRR_STATE_DISABLED);
1300 }
1301