1 /*
2  * Copyright 2016 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 /* Refresh rate ramp at a fixed rate of 65 Hz/second */
34 #define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65)
35 /* Number of elements in the render times cache array */
36 #define RENDER_TIMES_MAX_COUNT 20
37 /* Threshold to exit BTR (to avoid frequent enter-exits at the lower limit) */
38 #define BTR_EXIT_MARGIN 2000
39 /* Number of consecutive frames to check before entering/exiting fixed refresh*/
40 #define FIXED_REFRESH_ENTER_FRAME_COUNT 5
41 #define FIXED_REFRESH_EXIT_FRAME_COUNT 5
42 
43 #define FREESYNC_REGISTRY_NAME "freesync_v1"
44 
45 #define FREESYNC_NO_STATIC_FOR_EXTERNAL_DP_REGKEY "DalFreeSyncNoStaticForExternalDp"
46 
47 #define FREESYNC_NO_STATIC_FOR_INTERNAL_REGKEY "DalFreeSyncNoStaticForInternal"
48 
49 struct gradual_static_ramp {
50 	bool ramp_is_active;
51 	bool ramp_direction_is_up;
52 	unsigned int ramp_current_frame_duration_in_ns;
53 };
54 
55 struct time_cache {
56 	/* video (48Hz feature) related */
57 	unsigned int update_duration_in_ns;
58 
59 	/* BTR/fixed refresh related */
60 	unsigned int prev_time_stamp_in_us;
61 
62 	unsigned int min_render_time_in_us;
63 	unsigned int max_render_time_in_us;
64 
65 	unsigned int render_times_index;
66 	unsigned int render_times[RENDER_TIMES_MAX_COUNT];
67 };
68 
69 struct below_the_range {
70 	bool btr_active;
71 	bool program_btr;
72 
73 	unsigned int mid_point_in_us;
74 
75 	unsigned int inserted_frame_duration_in_us;
76 	unsigned int frames_to_insert;
77 	unsigned int frame_counter;
78 };
79 
80 struct fixed_refresh {
81 	bool fixed_active;
82 	bool program_fixed;
83 	unsigned int frame_counter;
84 };
85 
86 struct freesync_range {
87 	unsigned int min_refresh;
88 	unsigned int max_frame_duration;
89 	unsigned int vmax;
90 
91 	unsigned int max_refresh;
92 	unsigned int min_frame_duration;
93 	unsigned int vmin;
94 };
95 
96 struct freesync_state {
97 	bool fullscreen;
98 	bool static_screen;
99 	bool video;
100 
101 	unsigned int nominal_refresh_rate_in_micro_hz;
102 	bool windowed_fullscreen;
103 
104 	struct time_cache time;
105 
106 	struct gradual_static_ramp static_ramp;
107 	struct below_the_range btr;
108 	struct fixed_refresh fixed_refresh;
109 	struct freesync_range freesync_range;
110 };
111 
112 struct freesync_entity {
113 	struct dc_stream_state *stream;
114 	struct mod_freesync_caps *caps;
115 	struct freesync_state state;
116 	struct mod_freesync_user_enable user_enable;
117 };
118 
119 struct freesync_registry_options {
120 	bool drr_external_supported;
121 	bool drr_internal_supported;
122 };
123 
124 struct core_freesync {
125 	struct mod_freesync public;
126 	struct dc *dc;
127 	struct freesync_entity *map;
128 	int num_entities;
129 	struct freesync_registry_options opts;
130 };
131 
132 #define MOD_FREESYNC_TO_CORE(mod_freesync)\
133 		container_of(mod_freesync, struct core_freesync, public)
134 
135 static bool check_dc_support(const struct dc *dc)
136 {
137 	if (dc->stream_funcs.adjust_vmin_vmax == NULL)
138 		return false;
139 
140 	return true;
141 }
142 
143 struct mod_freesync *mod_freesync_create(struct dc *dc)
144 {
145 	struct core_freesync *core_freesync =
146 			kzalloc(sizeof(struct core_freesync), GFP_KERNEL);
147 
148 
149 	struct persistent_data_flag flag;
150 
151 	int i, data = 0;
152 
153 	if (core_freesync == NULL)
154 		goto fail_alloc_context;
155 
156 	core_freesync->map = kzalloc(sizeof(struct freesync_entity) * MOD_FREESYNC_MAX_CONCURRENT_STREAMS,
157 				     GFP_KERNEL);
158 
159 	if (core_freesync->map == NULL)
160 		goto fail_alloc_map;
161 
162 	for (i = 0; i < MOD_FREESYNC_MAX_CONCURRENT_STREAMS; i++)
163 		core_freesync->map[i].stream = NULL;
164 
165 	core_freesync->num_entities = 0;
166 
167 	if (dc == NULL)
168 		goto fail_construct;
169 
170 	core_freesync->dc = dc;
171 
172 	if (!check_dc_support(dc))
173 		goto fail_construct;
174 
175 	/* Create initial module folder in registry for freesync enable data */
176 	flag.save_per_edid = true;
177 	flag.save_per_link = false;
178 	dm_write_persistent_data(dc->ctx, NULL, FREESYNC_REGISTRY_NAME,
179 			NULL, NULL, 0, &flag);
180 	flag.save_per_edid = false;
181 	flag.save_per_link = false;
182 
183 	if (dm_read_persistent_data(dc->ctx, NULL, NULL,
184 			FREESYNC_NO_STATIC_FOR_INTERNAL_REGKEY,
185 			&data, sizeof(data), &flag)) {
186 		core_freesync->opts.drr_internal_supported =
187 			(data & 1) ? false : true;
188 	}
189 
190 	if (dm_read_persistent_data(dc->ctx, NULL, NULL,
191 			FREESYNC_NO_STATIC_FOR_EXTERNAL_DP_REGKEY,
192 			&data, sizeof(data), &flag)) {
193 		core_freesync->opts.drr_external_supported =
194 				(data & 1) ? false : true;
195 	}
196 
197 	return &core_freesync->public;
198 
199 fail_construct:
200 	kfree(core_freesync->map);
201 
202 fail_alloc_map:
203 	kfree(core_freesync);
204 
205 fail_alloc_context:
206 	return NULL;
207 }
208 
209 void mod_freesync_destroy(struct mod_freesync *mod_freesync)
210 {
211 	if (mod_freesync != NULL) {
212 		int i;
213 		struct core_freesync *core_freesync =
214 				MOD_FREESYNC_TO_CORE(mod_freesync);
215 
216 		for (i = 0; i < core_freesync->num_entities; i++)
217 			if (core_freesync->map[i].stream)
218 				dc_stream_release(core_freesync->map[i].stream);
219 
220 		kfree(core_freesync->map);
221 
222 		kfree(core_freesync);
223 	}
224 }
225 
226 /* Given a specific dc_stream* this function finds its equivalent
227  * on the core_freesync->map and returns the corresponding index
228  */
229 static unsigned int map_index_from_stream(struct core_freesync *core_freesync,
230 		struct dc_stream_state *stream)
231 {
232 	unsigned int index = 0;
233 
234 	for (index = 0; index < core_freesync->num_entities; index++) {
235 		if (core_freesync->map[index].stream == stream) {
236 			return index;
237 		}
238 	}
239 	/* Could not find stream requested */
240 	ASSERT(false);
241 	return index;
242 }
243 
244 bool mod_freesync_add_stream(struct mod_freesync *mod_freesync,
245 		struct dc_stream_state *stream, struct mod_freesync_caps *caps)
246 {
247 	struct dc  *dc = NULL;
248 	struct core_freesync *core_freesync = NULL;
249 	int persistent_freesync_enable = 0;
250 	struct persistent_data_flag flag;
251 	unsigned int nom_refresh_rate_uhz;
252 	unsigned long long temp;
253 
254 	if (mod_freesync == NULL)
255 		return false;
256 
257 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
258 	dc = core_freesync->dc;
259 
260 	flag.save_per_edid = true;
261 	flag.save_per_link = false;
262 
263 	if (core_freesync->num_entities < MOD_FREESYNC_MAX_CONCURRENT_STREAMS) {
264 
265 		dc_stream_retain(stream);
266 
267 		temp = stream->timing.pix_clk_khz;
268 		temp *= 1000ULL * 1000ULL * 1000ULL;
269 		temp = div_u64(temp, stream->timing.h_total);
270 		temp = div_u64(temp, stream->timing.v_total);
271 
272 		nom_refresh_rate_uhz = (unsigned int) temp;
273 
274 		core_freesync->map[core_freesync->num_entities].stream = stream;
275 		core_freesync->map[core_freesync->num_entities].caps = caps;
276 
277 		core_freesync->map[core_freesync->num_entities].state.
278 			fullscreen = false;
279 		core_freesync->map[core_freesync->num_entities].state.
280 			static_screen = false;
281 		core_freesync->map[core_freesync->num_entities].state.
282 			video = false;
283 		core_freesync->map[core_freesync->num_entities].state.time.
284 			update_duration_in_ns = 0;
285 		core_freesync->map[core_freesync->num_entities].state.
286 			static_ramp.ramp_is_active = false;
287 
288 		/* get persistent data from registry */
289 		if (dm_read_persistent_data(dc->ctx, stream->sink,
290 					FREESYNC_REGISTRY_NAME,
291 					"userenable", &persistent_freesync_enable,
292 					sizeof(int), &flag)) {
293 			core_freesync->map[core_freesync->num_entities].user_enable.
294 				enable_for_gaming =
295 				(persistent_freesync_enable & 1) ? true : false;
296 			core_freesync->map[core_freesync->num_entities].user_enable.
297 				enable_for_static =
298 				(persistent_freesync_enable & 2) ? true : false;
299 			core_freesync->map[core_freesync->num_entities].user_enable.
300 				enable_for_video =
301 				(persistent_freesync_enable & 4) ? true : false;
302 		} else {
303 			core_freesync->map[core_freesync->num_entities].user_enable.
304 					enable_for_gaming = false;
305 			core_freesync->map[core_freesync->num_entities].user_enable.
306 					enable_for_static = false;
307 			core_freesync->map[core_freesync->num_entities].user_enable.
308 					enable_for_video = false;
309 		}
310 
311 		if (caps->supported &&
312 			nom_refresh_rate_uhz >= caps->min_refresh_in_micro_hz &&
313 			nom_refresh_rate_uhz <= caps->max_refresh_in_micro_hz)
314 			stream->ignore_msa_timing_param = 1;
315 
316 		core_freesync->num_entities++;
317 		return true;
318 	}
319 	return false;
320 }
321 
322 bool mod_freesync_remove_stream(struct mod_freesync *mod_freesync,
323 		struct dc_stream_state *stream)
324 {
325 	int i = 0;
326 	struct core_freesync *core_freesync = NULL;
327 	unsigned int index = 0;
328 
329 	if (mod_freesync == NULL)
330 		return false;
331 
332 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
333 	index = map_index_from_stream(core_freesync, stream);
334 
335 	dc_stream_release(core_freesync->map[index].stream);
336 	core_freesync->map[index].stream = NULL;
337 	/* To remove this entity, shift everything after down */
338 	for (i = index; i < core_freesync->num_entities - 1; i++)
339 		core_freesync->map[i] = core_freesync->map[i + 1];
340 	core_freesync->num_entities--;
341 	return true;
342 }
343 
344 static void update_stream_freesync_context(struct core_freesync *core_freesync,
345 		struct dc_stream_state *stream)
346 {
347 	unsigned int index;
348 	struct freesync_context *ctx;
349 
350 	ctx = &stream->freesync_ctx;
351 
352 	index = map_index_from_stream(core_freesync, stream);
353 
354 	ctx->supported = core_freesync->map[index].caps->supported;
355 	ctx->enabled = (core_freesync->map[index].user_enable.enable_for_gaming ||
356 		core_freesync->map[index].user_enable.enable_for_video ||
357 		core_freesync->map[index].user_enable.enable_for_static);
358 	ctx->active = (core_freesync->map[index].state.fullscreen ||
359 		core_freesync->map[index].state.video ||
360 		core_freesync->map[index].state.static_ramp.ramp_is_active);
361 	ctx->min_refresh_in_micro_hz =
362 			core_freesync->map[index].caps->min_refresh_in_micro_hz;
363 	ctx->nominal_refresh_in_micro_hz = core_freesync->
364 		map[index].state.nominal_refresh_rate_in_micro_hz;
365 
366 }
367 
368 static void update_stream(struct core_freesync *core_freesync,
369 		struct dc_stream_state *stream)
370 {
371 	unsigned int index = map_index_from_stream(core_freesync, stream);
372 	if (core_freesync->map[index].caps->supported) {
373 		stream->ignore_msa_timing_param = 1;
374 		update_stream_freesync_context(core_freesync, stream);
375 	}
376 }
377 
378 static void calc_freesync_range(struct core_freesync *core_freesync,
379 		struct dc_stream_state *stream,
380 		struct freesync_state *state,
381 		unsigned int min_refresh_in_uhz,
382 		unsigned int max_refresh_in_uhz)
383 {
384 	unsigned int min_frame_duration_in_ns = 0, max_frame_duration_in_ns = 0;
385 	unsigned int index = map_index_from_stream(core_freesync, stream);
386 	uint32_t vtotal = stream->timing.v_total;
387 
388 	if ((min_refresh_in_uhz == 0) || (max_refresh_in_uhz == 0)) {
389 		state->freesync_range.min_refresh =
390 				state->nominal_refresh_rate_in_micro_hz;
391 		state->freesync_range.max_refresh =
392 				state->nominal_refresh_rate_in_micro_hz;
393 
394 		state->freesync_range.max_frame_duration = 0;
395 		state->freesync_range.min_frame_duration = 0;
396 
397 		state->freesync_range.vmax = vtotal;
398 		state->freesync_range.vmin = vtotal;
399 
400 		return;
401 	}
402 
403 	min_frame_duration_in_ns = ((unsigned int) (div64_u64(
404 					(1000000000ULL * 1000000),
405 					max_refresh_in_uhz)));
406 	max_frame_duration_in_ns = ((unsigned int) (div64_u64(
407 		(1000000000ULL * 1000000),
408 		min_refresh_in_uhz)));
409 
410 	state->freesync_range.min_refresh = min_refresh_in_uhz;
411 	state->freesync_range.max_refresh = max_refresh_in_uhz;
412 
413 	state->freesync_range.max_frame_duration = max_frame_duration_in_ns;
414 	state->freesync_range.min_frame_duration = min_frame_duration_in_ns;
415 
416 	state->freesync_range.vmax = div64_u64(div64_u64(((unsigned long long)(
417 		max_frame_duration_in_ns) * stream->timing.pix_clk_khz),
418 		stream->timing.h_total), 1000000);
419 	state->freesync_range.vmin = div64_u64(div64_u64(((unsigned long long)(
420 		min_frame_duration_in_ns) * stream->timing.pix_clk_khz),
421 		stream->timing.h_total), 1000000);
422 
423 	/* vmin/vmax cannot be less than vtotal */
424 	if (state->freesync_range.vmin < vtotal) {
425 		/* Error of 1 is permissible */
426 		ASSERT((state->freesync_range.vmin + 1) >= vtotal);
427 		state->freesync_range.vmin = vtotal;
428 	}
429 
430 	if (state->freesync_range.vmax < vtotal) {
431 		/* Error of 1 is permissible */
432 		ASSERT((state->freesync_range.vmax + 1) >= vtotal);
433 		state->freesync_range.vmax = vtotal;
434 	}
435 
436 	/* Determine whether BTR can be supported */
437 	if (max_frame_duration_in_ns >=
438 			2 * min_frame_duration_in_ns)
439 		core_freesync->map[index].caps->btr_supported = true;
440 	else
441 		core_freesync->map[index].caps->btr_supported = false;
442 
443 	/* Cache the time variables */
444 	state->time.max_render_time_in_us =
445 		max_frame_duration_in_ns / 1000;
446 	state->time.min_render_time_in_us =
447 		min_frame_duration_in_ns / 1000;
448 	state->btr.mid_point_in_us =
449 		(max_frame_duration_in_ns +
450 		min_frame_duration_in_ns) / 2000;
451 }
452 
453 static void calc_v_total_from_duration(struct dc_stream_state *stream,
454 		unsigned int duration_in_ns, int *v_total_nominal)
455 {
456 	*v_total_nominal = div64_u64(div64_u64(((unsigned long long)(
457 				duration_in_ns) * stream->timing.pix_clk_khz),
458 				stream->timing.h_total), 1000000);
459 }
460 
461 static void calc_v_total_for_static_ramp(struct core_freesync *core_freesync,
462 		struct dc_stream_state *stream,
463 		unsigned int index, int *v_total)
464 {
465 	unsigned int frame_duration = 0;
466 
467 	struct gradual_static_ramp *static_ramp_variables =
468 				&core_freesync->map[index].state.static_ramp;
469 
470 	/* Calc ratio between new and current frame duration with 3 digit */
471 	unsigned int frame_duration_ratio = div64_u64(1000000,
472 		(1000 +  div64_u64(((unsigned long long)(
473 		STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME) *
474 		static_ramp_variables->ramp_current_frame_duration_in_ns),
475 		1000000000)));
476 
477 	/* Calculate delta between new and current frame duration in ns */
478 	unsigned int frame_duration_delta = div64_u64(((unsigned long long)(
479 		static_ramp_variables->ramp_current_frame_duration_in_ns) *
480 		(1000 - frame_duration_ratio)), 1000);
481 
482 	/* Adjust frame duration delta based on ratio between current and
483 	 * standard frame duration (frame duration at 60 Hz refresh rate).
484 	 */
485 	unsigned int ramp_rate_interpolated = div64_u64(((unsigned long long)(
486 		frame_duration_delta) * static_ramp_variables->
487 		ramp_current_frame_duration_in_ns), 16666666);
488 
489 	/* Going to a higher refresh rate (lower frame duration) */
490 	if (static_ramp_variables->ramp_direction_is_up) {
491 		/* reduce frame duration */
492 		static_ramp_variables->ramp_current_frame_duration_in_ns -=
493 			ramp_rate_interpolated;
494 
495 		/* min frame duration */
496 		frame_duration = ((unsigned int) (div64_u64(
497 			(1000000000ULL * 1000000),
498 			core_freesync->map[index].state.
499 			nominal_refresh_rate_in_micro_hz)));
500 
501 		/* adjust for frame duration below min */
502 		if (static_ramp_variables->ramp_current_frame_duration_in_ns <=
503 			frame_duration) {
504 
505 			static_ramp_variables->ramp_is_active = false;
506 			static_ramp_variables->
507 				ramp_current_frame_duration_in_ns =
508 				frame_duration;
509 		}
510 	/* Going to a lower refresh rate (larger frame duration) */
511 	} else {
512 		/* increase frame duration */
513 		static_ramp_variables->ramp_current_frame_duration_in_ns +=
514 			ramp_rate_interpolated;
515 
516 		/* max frame duration */
517 		frame_duration = ((unsigned int) (div64_u64(
518 			(1000000000ULL * 1000000),
519 			core_freesync->map[index].caps->min_refresh_in_micro_hz)));
520 
521 		/* adjust for frame duration above max */
522 		if (static_ramp_variables->ramp_current_frame_duration_in_ns >=
523 			frame_duration) {
524 
525 			static_ramp_variables->ramp_is_active = false;
526 			static_ramp_variables->
527 				ramp_current_frame_duration_in_ns =
528 				frame_duration;
529 		}
530 	}
531 
532 	calc_v_total_from_duration(stream, static_ramp_variables->
533 		ramp_current_frame_duration_in_ns, v_total);
534 }
535 
536 static void reset_freesync_state_variables(struct freesync_state* state)
537 {
538 	state->static_ramp.ramp_is_active = false;
539 	if (state->nominal_refresh_rate_in_micro_hz)
540 		state->static_ramp.ramp_current_frame_duration_in_ns =
541 			((unsigned int) (div64_u64(
542 			(1000000000ULL * 1000000),
543 			state->nominal_refresh_rate_in_micro_hz)));
544 
545 	state->btr.btr_active = false;
546 	state->btr.frame_counter = 0;
547 	state->btr.frames_to_insert = 0;
548 	state->btr.inserted_frame_duration_in_us = 0;
549 	state->btr.program_btr = false;
550 
551 	state->fixed_refresh.fixed_active = false;
552 	state->fixed_refresh.program_fixed = false;
553 }
554 /*
555  * Sets freesync mode on a stream depending on current freesync state.
556  */
557 static bool set_freesync_on_streams(struct core_freesync *core_freesync,
558 		struct dc_stream_state **streams, int num_streams)
559 {
560 	int v_total_nominal = 0, v_total_min = 0, v_total_max = 0;
561 	unsigned int stream_idx, map_index = 0;
562 	struct freesync_state *state;
563 
564 	if (num_streams == 0 || streams == NULL || num_streams > 1)
565 		return false;
566 
567 	for (stream_idx = 0; stream_idx < num_streams; stream_idx++) {
568 
569 		map_index = map_index_from_stream(core_freesync,
570 				streams[stream_idx]);
571 
572 		state = &core_freesync->map[map_index].state;
573 
574 		if (core_freesync->map[map_index].caps->supported) {
575 
576 			/* Fullscreen has the topmost priority. If the
577 			 * fullscreen bit is set, we are in a fullscreen
578 			 * application where it should not matter if it is
579 			 * static screen. We should not check the static_screen
580 			 * or video bit.
581 			 *
582 			 * Special cases of fullscreen include btr and fixed
583 			 * refresh. We program btr on every flip and involves
584 			 * programming full range right before the last inserted frame.
585 			 * However, we do not want to program the full freesync range
586 			 * when fixed refresh is active, because we only program
587 			 * that logic once and this will override it.
588 			 */
589 			if (core_freesync->map[map_index].user_enable.
590 				enable_for_gaming == true &&
591 				state->fullscreen == true &&
592 				state->fixed_refresh.fixed_active == false) {
593 				/* Enable freesync */
594 
595 				v_total_min = state->freesync_range.vmin;
596 				v_total_max = state->freesync_range.vmax;
597 
598 				/* Update the freesync context for the stream */
599 				update_stream_freesync_context(core_freesync,
600 						streams[stream_idx]);
601 
602 				core_freesync->dc->stream_funcs.
603 				adjust_vmin_vmax(core_freesync->dc, streams,
604 						num_streams, v_total_min,
605 						v_total_max);
606 
607 				return true;
608 
609 			} else if (core_freesync->map[map_index].user_enable.
610 				enable_for_video && state->video == true) {
611 				/* Enable 48Hz feature */
612 
613 				calc_v_total_from_duration(streams[stream_idx],
614 					state->time.update_duration_in_ns,
615 					&v_total_nominal);
616 
617 				/* Program only if v_total_nominal is in range*/
618 				if (v_total_nominal >=
619 					streams[stream_idx]->timing.v_total) {
620 
621 					/* Update the freesync context for
622 					 * the stream
623 					 */
624 					update_stream_freesync_context(
625 						core_freesync,
626 						streams[stream_idx]);
627 
628 					core_freesync->dc->stream_funcs.
629 					adjust_vmin_vmax(
630 						core_freesync->dc, streams,
631 						num_streams, v_total_nominal,
632 						v_total_nominal);
633 				}
634 				return true;
635 
636 			} else {
637 				/* Disable freesync */
638 				v_total_nominal = streams[stream_idx]->
639 					timing.v_total;
640 
641 				/* Update the freesync context for
642 				 * the stream
643 				 */
644 				update_stream_freesync_context(
645 					core_freesync,
646 					streams[stream_idx]);
647 
648 				core_freesync->dc->stream_funcs.
649 						adjust_vmin_vmax(
650 						core_freesync->dc, streams,
651 						num_streams, v_total_nominal,
652 						v_total_nominal);
653 
654 				/* Reset the cached variables */
655 				reset_freesync_state_variables(state);
656 
657 				return true;
658 			}
659 		} else {
660 			/* Disable freesync */
661 			v_total_nominal = streams[stream_idx]->
662 				timing.v_total;
663 			/*
664 			 * we have to reset drr always even sink does
665 			 * not support freesync because a former stream has
666 			 * be programmed
667 			 */
668 			core_freesync->dc->stream_funcs.
669 					adjust_vmin_vmax(
670 					core_freesync->dc, streams,
671 					num_streams, v_total_nominal,
672 					v_total_nominal);
673 			/* Reset the cached variables */
674 			reset_freesync_state_variables(state);
675 		}
676 
677 	}
678 
679 	return false;
680 }
681 
682 static void set_static_ramp_variables(struct core_freesync *core_freesync,
683 		unsigned int index, bool enable_static_screen)
684 {
685 	unsigned int frame_duration = 0;
686 	unsigned int nominal_refresh_rate = core_freesync->map[index].state.
687 			nominal_refresh_rate_in_micro_hz;
688 	unsigned int min_refresh_rate= core_freesync->map[index].caps->
689 			min_refresh_in_micro_hz;
690 	struct gradual_static_ramp *static_ramp_variables =
691 			&core_freesync->map[index].state.static_ramp;
692 
693 	/* If we are ENABLING static screen, refresh rate should go DOWN.
694 	 * If we are DISABLING static screen, refresh rate should go UP.
695 	 */
696 	if (enable_static_screen)
697 		static_ramp_variables->ramp_direction_is_up = false;
698 	else
699 		static_ramp_variables->ramp_direction_is_up = true;
700 
701 	/* If ramp is not active, set initial frame duration depending on
702 	 * whether we are enabling/disabling static screen mode. If the ramp is
703 	 * already active, ramp should continue in the opposite direction
704 	 * starting with the current frame duration
705 	 */
706 	if (!static_ramp_variables->ramp_is_active) {
707 		if (enable_static_screen == true) {
708 			/* Going to lower refresh rate, so start from max
709 			 * refresh rate (min frame duration)
710 			 */
711 			frame_duration = ((unsigned int) (div64_u64(
712 				(1000000000ULL * 1000000),
713 				nominal_refresh_rate)));
714 		} else {
715 			/* Going to higher refresh rate, so start from min
716 			 * refresh rate (max frame duration)
717 			 */
718 			frame_duration = ((unsigned int) (div64_u64(
719 				(1000000000ULL * 1000000),
720 				min_refresh_rate)));
721 		}
722 		static_ramp_variables->
723 			ramp_current_frame_duration_in_ns = frame_duration;
724 
725 		static_ramp_variables->ramp_is_active = true;
726 	}
727 }
728 
729 void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync,
730 		struct dc_stream_state **streams, int num_streams)
731 {
732 	unsigned int index, v_total, inserted_frame_v_total = 0;
733 	unsigned int min_frame_duration_in_ns, vmax, vmin = 0;
734 	struct freesync_state *state;
735 	struct core_freesync *core_freesync = NULL;
736 	struct dc_static_screen_events triggers = {0};
737 
738 	if (mod_freesync == NULL)
739 		return;
740 
741 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
742 
743 	if (core_freesync->num_entities == 0)
744 		return;
745 
746 	index = map_index_from_stream(core_freesync,
747 		streams[0]);
748 
749 	if (core_freesync->map[index].caps->supported == false)
750 		return;
751 
752 	state = &core_freesync->map[index].state;
753 
754 	/* Below the Range Logic */
755 
756 	/* Only execute if in fullscreen mode */
757 	if (state->fullscreen == true &&
758 		core_freesync->map[index].user_enable.enable_for_gaming &&
759 		core_freesync->map[index].caps->btr_supported &&
760 		state->btr.btr_active) {
761 
762 		/* TODO: pass in flag for Pre-DCE12 ASIC
763 		 * in order for frame variable duration to take affect,
764 		 * it needs to be done one VSYNC early, which is at
765 		 * frameCounter == 1.
766 		 * For DCE12 and newer updates to V_TOTAL_MIN/MAX
767 		 * will take affect on current frame
768 		 */
769 		if (state->btr.frames_to_insert == state->btr.frame_counter) {
770 
771 			min_frame_duration_in_ns = ((unsigned int) (div64_u64(
772 					(1000000000ULL * 1000000),
773 					state->nominal_refresh_rate_in_micro_hz)));
774 
775 			vmin = state->freesync_range.vmin;
776 
777 			inserted_frame_v_total = vmin;
778 
779 			if (min_frame_duration_in_ns / 1000)
780 				inserted_frame_v_total =
781 					state->btr.inserted_frame_duration_in_us *
782 					vmin / (min_frame_duration_in_ns / 1000);
783 
784 			/* Set length of inserted frames as v_total_max*/
785 			vmax = inserted_frame_v_total;
786 			vmin = inserted_frame_v_total;
787 
788 			/* Program V_TOTAL */
789 			core_freesync->dc->stream_funcs.adjust_vmin_vmax(
790 				core_freesync->dc, streams,
791 				num_streams, vmin, vmax);
792 		}
793 
794 		if (state->btr.frame_counter > 0)
795 			state->btr.frame_counter--;
796 
797 		/* Restore FreeSync */
798 		if (state->btr.frame_counter == 0)
799 			set_freesync_on_streams(core_freesync, streams, num_streams);
800 	}
801 
802 	/* If in fullscreen freesync mode or in video, do not program
803 	 * static screen ramp values
804 	 */
805 	if (state->fullscreen == true || state->video == true) {
806 
807 		state->static_ramp.ramp_is_active = false;
808 
809 		return;
810 	}
811 
812 	/* Gradual Static Screen Ramping Logic */
813 
814 	/* Execute if ramp is active and user enabled freesync static screen*/
815 	if (state->static_ramp.ramp_is_active &&
816 		core_freesync->map[index].user_enable.enable_for_static) {
817 
818 		calc_v_total_for_static_ramp(core_freesync, streams[0],
819 				index, &v_total);
820 
821 		/* Update the freesync context for the stream */
822 		update_stream_freesync_context(core_freesync, streams[0]);
823 
824 		/* Program static screen ramp values */
825 		core_freesync->dc->stream_funcs.adjust_vmin_vmax(
826 					core_freesync->dc, streams,
827 					num_streams, v_total,
828 					v_total);
829 
830 		triggers.overlay_update = true;
831 		triggers.surface_update = true;
832 
833 		core_freesync->dc->stream_funcs.set_static_screen_events(
834 					core_freesync->dc, streams,	num_streams,
835 					&triggers);
836 	}
837 }
838 
839 void mod_freesync_update_state(struct mod_freesync *mod_freesync,
840 		struct dc_stream_state **streams, int num_streams,
841 		struct mod_freesync_params *freesync_params)
842 {
843 	bool freesync_program_required = false;
844 	unsigned int stream_index;
845 	struct freesync_state *state;
846 	struct core_freesync *core_freesync = NULL;
847 	struct dc_static_screen_events triggers = {0};
848 
849 	if (mod_freesync == NULL)
850 		return;
851 
852 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
853 
854 	if (core_freesync->num_entities == 0)
855 		return;
856 
857 	for(stream_index = 0; stream_index < num_streams; stream_index++) {
858 
859 		unsigned int map_index = map_index_from_stream(core_freesync,
860 				streams[stream_index]);
861 
862 		bool is_embedded = dc_is_embedded_signal(
863 				streams[stream_index]->sink->sink_signal);
864 
865 		struct freesync_registry_options *opts = &core_freesync->opts;
866 
867 		state = &core_freesync->map[map_index].state;
868 
869 		switch (freesync_params->state){
870 		case FREESYNC_STATE_FULLSCREEN:
871 			state->fullscreen = freesync_params->enable;
872 			freesync_program_required = true;
873 			state->windowed_fullscreen =
874 					freesync_params->windowed_fullscreen;
875 			break;
876 		case FREESYNC_STATE_STATIC_SCREEN:
877 			/* Static screen ramp is disabled by default, but can
878 			 * be enabled through regkey.
879 			 */
880 			if ((is_embedded && opts->drr_internal_supported) ||
881 				(!is_embedded && opts->drr_external_supported))
882 
883 				if (state->static_screen !=
884 						freesync_params->enable) {
885 
886 					/* Change the state flag */
887 					state->static_screen =
888 							freesync_params->enable;
889 
890 					/* Update static screen ramp */
891 					set_static_ramp_variables(core_freesync,
892 						map_index,
893 						freesync_params->enable);
894 				}
895 			/* We program the ramp starting next VUpdate */
896 			break;
897 		case FREESYNC_STATE_VIDEO:
898 			/* Change core variables only if there is a change*/
899 			if(freesync_params->update_duration_in_ns !=
900 				state->time.update_duration_in_ns) {
901 
902 				state->video = freesync_params->enable;
903 				state->time.update_duration_in_ns =
904 					freesync_params->update_duration_in_ns;
905 
906 				freesync_program_required = true;
907 			}
908 			break;
909 		case FREESYNC_STATE_NONE:
910 			/* handle here to avoid warning */
911 			break;
912 		}
913 	}
914 
915 	/* Update mask */
916 	triggers.overlay_update = true;
917 	triggers.surface_update = true;
918 
919 	core_freesync->dc->stream_funcs.set_static_screen_events(
920 		core_freesync->dc, streams, num_streams,
921 		&triggers);
922 
923 	if (freesync_program_required)
924 		/* Program freesync according to current state*/
925 		set_freesync_on_streams(core_freesync, streams, num_streams);
926 }
927 
928 
929 bool mod_freesync_get_state(struct mod_freesync *mod_freesync,
930 		struct dc_stream_state *stream,
931 		struct mod_freesync_params *freesync_params)
932 {
933 	unsigned int index = 0;
934 	struct core_freesync *core_freesync = NULL;
935 
936 	if (mod_freesync == NULL)
937 		return false;
938 
939 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
940 	index = map_index_from_stream(core_freesync, stream);
941 
942 	if (core_freesync->map[index].state.fullscreen) {
943 		freesync_params->state = FREESYNC_STATE_FULLSCREEN;
944 		freesync_params->enable = true;
945 	} else if (core_freesync->map[index].state.static_screen) {
946 		freesync_params->state = FREESYNC_STATE_STATIC_SCREEN;
947 		freesync_params->enable = true;
948 	} else if (core_freesync->map[index].state.video) {
949 		freesync_params->state = FREESYNC_STATE_VIDEO;
950 		freesync_params->enable = true;
951 	} else {
952 		freesync_params->state = FREESYNC_STATE_NONE;
953 		freesync_params->enable = false;
954 	}
955 
956 	freesync_params->update_duration_in_ns =
957 		core_freesync->map[index].state.time.update_duration_in_ns;
958 
959 	freesync_params->windowed_fullscreen =
960 			core_freesync->map[index].state.windowed_fullscreen;
961 
962 	return true;
963 }
964 
965 bool mod_freesync_set_user_enable(struct mod_freesync *mod_freesync,
966 		struct dc_stream_state **streams, int num_streams,
967 		struct mod_freesync_user_enable *user_enable)
968 {
969 	unsigned int stream_index, map_index;
970 	int persistent_data = 0;
971 	struct persistent_data_flag flag;
972 	struct dc  *dc = NULL;
973 	struct core_freesync *core_freesync = NULL;
974 
975 	if (mod_freesync == NULL)
976 		return false;
977 
978 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
979 	dc = core_freesync->dc;
980 
981 	flag.save_per_edid = true;
982 	flag.save_per_link = false;
983 
984 	for(stream_index = 0; stream_index < num_streams;
985 			stream_index++){
986 
987 		map_index = map_index_from_stream(core_freesync,
988 				streams[stream_index]);
989 
990 		core_freesync->map[map_index].user_enable = *user_enable;
991 
992 		/* Write persistent data in registry*/
993 		if (core_freesync->map[map_index].user_enable.
994 				enable_for_gaming)
995 			persistent_data = persistent_data | 1;
996 		if (core_freesync->map[map_index].user_enable.
997 				enable_for_static)
998 			persistent_data = persistent_data | 2;
999 		if (core_freesync->map[map_index].user_enable.
1000 				enable_for_video)
1001 			persistent_data = persistent_data | 4;
1002 
1003 		dm_write_persistent_data(dc->ctx,
1004 					streams[stream_index]->sink,
1005 					FREESYNC_REGISTRY_NAME,
1006 					"userenable",
1007 					&persistent_data,
1008 					sizeof(int),
1009 					&flag);
1010 	}
1011 
1012 	set_freesync_on_streams(core_freesync, streams, num_streams);
1013 
1014 	return true;
1015 }
1016 
1017 bool mod_freesync_get_user_enable(struct mod_freesync *mod_freesync,
1018 		struct dc_stream_state *stream,
1019 		struct mod_freesync_user_enable *user_enable)
1020 {
1021 	unsigned int index = 0;
1022 	struct core_freesync *core_freesync = NULL;
1023 
1024 	if (mod_freesync == NULL)
1025 		return false;
1026 
1027 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1028 	index = map_index_from_stream(core_freesync, stream);
1029 
1030 	*user_enable = core_freesync->map[index].user_enable;
1031 
1032 	return true;
1033 }
1034 
1035 bool mod_freesync_get_static_ramp_active(struct mod_freesync *mod_freesync,
1036 		struct dc_stream_state *stream,
1037 		bool *is_ramp_active)
1038 {
1039 	unsigned int index = 0;
1040 	struct core_freesync *core_freesync = NULL;
1041 
1042 	if (mod_freesync == NULL)
1043 		return false;
1044 
1045 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1046 	index = map_index_from_stream(core_freesync, stream);
1047 
1048 	*is_ramp_active =
1049 		core_freesync->map[index].state.static_ramp.ramp_is_active;
1050 
1051 	return true;
1052 }
1053 
1054 bool mod_freesync_override_min_max(struct mod_freesync *mod_freesync,
1055 		struct dc_stream_state *streams,
1056 		unsigned int min_refresh,
1057 		unsigned int max_refresh,
1058 		struct mod_freesync_caps *caps)
1059 {
1060 	unsigned int index = 0;
1061 	struct core_freesync *core_freesync;
1062 	struct freesync_state *state;
1063 
1064 	if (mod_freesync == NULL)
1065 		return false;
1066 
1067 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1068 	index = map_index_from_stream(core_freesync, streams);
1069 	state = &core_freesync->map[index].state;
1070 
1071 	if (max_refresh == 0)
1072 		max_refresh = state->nominal_refresh_rate_in_micro_hz;
1073 
1074 	if (min_refresh == 0) {
1075 		/* Restore defaults */
1076 		calc_freesync_range(core_freesync, streams, state,
1077 			core_freesync->map[index].caps->
1078 			min_refresh_in_micro_hz,
1079 			state->nominal_refresh_rate_in_micro_hz);
1080 	} else {
1081 		calc_freesync_range(core_freesync, streams,
1082 				state,
1083 				min_refresh,
1084 				max_refresh);
1085 
1086 		/* Program vtotal min/max */
1087 		core_freesync->dc->stream_funcs.adjust_vmin_vmax(
1088 			core_freesync->dc, &streams, 1,
1089 			state->freesync_range.vmin,
1090 			state->freesync_range.vmax);
1091 	}
1092 
1093 	if (min_refresh != 0 &&
1094 			dc_is_embedded_signal(streams->sink->sink_signal) &&
1095 			(max_refresh - min_refresh >= 10000000)) {
1096 		caps->supported = true;
1097 		caps->min_refresh_in_micro_hz = min_refresh;
1098 		caps->max_refresh_in_micro_hz = max_refresh;
1099 	}
1100 
1101 	/* Update the stream */
1102 	update_stream(core_freesync, streams);
1103 
1104 	return true;
1105 }
1106 
1107 bool mod_freesync_get_min_max(struct mod_freesync *mod_freesync,
1108 		struct dc_stream_state *stream,
1109 		unsigned int *min_refresh,
1110 		unsigned int *max_refresh)
1111 {
1112 	unsigned int index = 0;
1113 	struct core_freesync *core_freesync = NULL;
1114 
1115 	if (mod_freesync == NULL)
1116 		return false;
1117 
1118 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1119 	index = map_index_from_stream(core_freesync, stream);
1120 
1121 	*min_refresh =
1122 		core_freesync->map[index].state.freesync_range.min_refresh;
1123 	*max_refresh =
1124 		core_freesync->map[index].state.freesync_range.max_refresh;
1125 
1126 	return true;
1127 }
1128 
1129 bool mod_freesync_get_vmin_vmax(struct mod_freesync *mod_freesync,
1130 		struct dc_stream_state *stream,
1131 		unsigned int *vmin,
1132 		unsigned int *vmax)
1133 {
1134 	unsigned int index = 0;
1135 	struct core_freesync *core_freesync = NULL;
1136 
1137 	if (mod_freesync == NULL)
1138 		return false;
1139 
1140 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1141 	index = map_index_from_stream(core_freesync, stream);
1142 
1143 	*vmin =
1144 		core_freesync->map[index].state.freesync_range.vmin;
1145 	*vmax =
1146 		core_freesync->map[index].state.freesync_range.vmax;
1147 
1148 	return true;
1149 }
1150 
1151 bool mod_freesync_get_v_position(struct mod_freesync *mod_freesync,
1152 		struct dc_stream_state *stream,
1153 		unsigned int *nom_v_pos,
1154 		unsigned int *v_pos)
1155 {
1156 	unsigned int index = 0;
1157 	struct core_freesync *core_freesync = NULL;
1158 	struct crtc_position position;
1159 
1160 	if (mod_freesync == NULL)
1161 		return false;
1162 
1163 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1164 	index = map_index_from_stream(core_freesync, stream);
1165 
1166 	if (core_freesync->dc->stream_funcs.get_crtc_position(
1167 			core_freesync->dc, &stream, 1,
1168 			&position.vertical_count, &position.nominal_vcount)) {
1169 
1170 		*nom_v_pos = position.nominal_vcount;
1171 		*v_pos = position.vertical_count;
1172 
1173 		return true;
1174 	}
1175 
1176 	return false;
1177 }
1178 
1179 void mod_freesync_notify_mode_change(struct mod_freesync *mod_freesync,
1180 		struct dc_stream_state **streams, int num_streams)
1181 {
1182 	unsigned int stream_index, map_index;
1183 	struct freesync_state *state;
1184 	struct core_freesync *core_freesync = NULL;
1185 	struct dc_static_screen_events triggers = {0};
1186 	unsigned long long temp = 0;
1187 
1188 	if (mod_freesync == NULL)
1189 		return;
1190 
1191 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1192 
1193 	for (stream_index = 0; stream_index < num_streams; stream_index++) {
1194 		map_index = map_index_from_stream(core_freesync,
1195 				streams[stream_index]);
1196 
1197 		state = &core_freesync->map[map_index].state;
1198 
1199 		/* Update the field rate for new timing */
1200 		temp = streams[stream_index]->timing.pix_clk_khz;
1201 		temp *= 1000ULL * 1000ULL * 1000ULL;
1202 		temp = div_u64(temp,
1203 				streams[stream_index]->timing.h_total);
1204 		temp = div_u64(temp,
1205 				streams[stream_index]->timing.v_total);
1206 		state->nominal_refresh_rate_in_micro_hz =
1207 				(unsigned int) temp;
1208 
1209 		if (core_freesync->map[map_index].caps->supported) {
1210 
1211 			/* Update the stream */
1212 			update_stream(core_freesync, streams[stream_index]);
1213 
1214 			/* Calculate vmin/vmax and refresh rate for
1215 			 * current mode
1216 			 */
1217 			calc_freesync_range(core_freesync, *streams, state,
1218 				core_freesync->map[map_index].caps->
1219 				min_refresh_in_micro_hz,
1220 				state->nominal_refresh_rate_in_micro_hz);
1221 
1222 			/* Update mask */
1223 			triggers.overlay_update = true;
1224 			triggers.surface_update = true;
1225 
1226 			core_freesync->dc->stream_funcs.set_static_screen_events(
1227 				core_freesync->dc, streams, num_streams,
1228 				&triggers);
1229 		}
1230 	}
1231 
1232 	/* Program freesync according to current state*/
1233 	set_freesync_on_streams(core_freesync, streams, num_streams);
1234 }
1235 
1236 /* Add the timestamps to the cache and determine whether BTR programming
1237  * is required, depending on the times calculated
1238  */
1239 static void update_timestamps(struct core_freesync *core_freesync,
1240 		const struct dc_stream_state *stream, unsigned int map_index,
1241 		unsigned int last_render_time_in_us)
1242 {
1243 	struct freesync_state *state = &core_freesync->map[map_index].state;
1244 
1245 	state->time.render_times[state->time.render_times_index] =
1246 			last_render_time_in_us;
1247 	state->time.render_times_index++;
1248 
1249 	if (state->time.render_times_index >= RENDER_TIMES_MAX_COUNT)
1250 		state->time.render_times_index = 0;
1251 
1252 	if (last_render_time_in_us + BTR_EXIT_MARGIN <
1253 		state->time.max_render_time_in_us) {
1254 
1255 		/* Exit Below the Range */
1256 		if (state->btr.btr_active) {
1257 
1258 			state->btr.program_btr = true;
1259 			state->btr.btr_active = false;
1260 			state->btr.frame_counter = 0;
1261 
1262 		/* Exit Fixed Refresh mode */
1263 		} else if (state->fixed_refresh.fixed_active) {
1264 
1265 			state->fixed_refresh.frame_counter++;
1266 
1267 			if (state->fixed_refresh.frame_counter >
1268 					FIXED_REFRESH_EXIT_FRAME_COUNT) {
1269 				state->fixed_refresh.frame_counter = 0;
1270 				state->fixed_refresh.program_fixed = true;
1271 				state->fixed_refresh.fixed_active = false;
1272 			}
1273 		}
1274 
1275 	} else if (last_render_time_in_us > state->time.max_render_time_in_us) {
1276 
1277 		/* Enter Below the Range */
1278 		if (!state->btr.btr_active &&
1279 			core_freesync->map[map_index].caps->btr_supported) {
1280 
1281 			state->btr.program_btr = true;
1282 			state->btr.btr_active = true;
1283 
1284 		/* Enter Fixed Refresh mode */
1285 		} else if (!state->fixed_refresh.fixed_active &&
1286 			!core_freesync->map[map_index].caps->btr_supported) {
1287 
1288 			state->fixed_refresh.frame_counter++;
1289 
1290 			if (state->fixed_refresh.frame_counter >
1291 					FIXED_REFRESH_ENTER_FRAME_COUNT) {
1292 				state->fixed_refresh.frame_counter = 0;
1293 				state->fixed_refresh.program_fixed = true;
1294 				state->fixed_refresh.fixed_active = true;
1295 			}
1296 		}
1297 	}
1298 
1299 	/* When Below the Range is active, must react on every frame */
1300 	if (state->btr.btr_active)
1301 		state->btr.program_btr = true;
1302 }
1303 
1304 static void apply_below_the_range(struct core_freesync *core_freesync,
1305 		struct dc_stream_state *stream, unsigned int map_index,
1306 		unsigned int last_render_time_in_us)
1307 {
1308 	unsigned int inserted_frame_duration_in_us = 0;
1309 	unsigned int mid_point_frames_ceil = 0;
1310 	unsigned int mid_point_frames_floor = 0;
1311 	unsigned int frame_time_in_us = 0;
1312 	unsigned int delta_from_mid_point_in_us_1 = 0xFFFFFFFF;
1313 	unsigned int delta_from_mid_point_in_us_2 = 0xFFFFFFFF;
1314 	unsigned int frames_to_insert = 0;
1315 	unsigned int min_frame_duration_in_ns = 0;
1316 	struct freesync_state *state = &core_freesync->map[map_index].state;
1317 
1318 	if (!state->btr.program_btr)
1319 		return;
1320 
1321 	state->btr.program_btr = false;
1322 
1323 	min_frame_duration_in_ns = ((unsigned int) (div64_u64(
1324 		(1000000000ULL * 1000000),
1325 		state->nominal_refresh_rate_in_micro_hz)));
1326 
1327 	/* Program BTR */
1328 
1329 	/* BTR set to "not active" so disengage */
1330 	if (!state->btr.btr_active)
1331 
1332 		/* Restore FreeSync */
1333 		set_freesync_on_streams(core_freesync, &stream, 1);
1334 
1335 	/* BTR set to "active" so engage */
1336 	else {
1337 
1338 		/* Calculate number of midPoint frames that could fit within
1339 		 * the render time interval- take ceil of this value
1340 		 */
1341 		mid_point_frames_ceil = (last_render_time_in_us +
1342 			state->btr.mid_point_in_us- 1) /
1343 			state->btr.mid_point_in_us;
1344 
1345 		if (mid_point_frames_ceil > 0) {
1346 
1347 			frame_time_in_us = last_render_time_in_us /
1348 				mid_point_frames_ceil;
1349 			delta_from_mid_point_in_us_1 =
1350 				(state->btr.mid_point_in_us >
1351 				frame_time_in_us) ?
1352 				(state->btr.mid_point_in_us - frame_time_in_us):
1353 				(frame_time_in_us - state->btr.mid_point_in_us);
1354 		}
1355 
1356 		/* Calculate number of midPoint frames that could fit within
1357 		 * the render time interval- take floor of this value
1358 		 */
1359 		mid_point_frames_floor = last_render_time_in_us /
1360 			state->btr.mid_point_in_us;
1361 
1362 		if (mid_point_frames_floor > 0) {
1363 
1364 			frame_time_in_us = last_render_time_in_us /
1365 				mid_point_frames_floor;
1366 			delta_from_mid_point_in_us_2 =
1367 				(state->btr.mid_point_in_us >
1368 				frame_time_in_us) ?
1369 				(state->btr.mid_point_in_us - frame_time_in_us):
1370 				(frame_time_in_us - state->btr.mid_point_in_us);
1371 		}
1372 
1373 		/* Choose number of frames to insert based on how close it
1374 		 * can get to the mid point of the variable range.
1375 		 */
1376 		if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2)
1377 			frames_to_insert = mid_point_frames_ceil;
1378 		else
1379 			frames_to_insert = mid_point_frames_floor;
1380 
1381 		/* Either we've calculated the number of frames to insert,
1382 		 * or we need to insert min duration frames
1383 		 */
1384 		if (frames_to_insert > 0)
1385 			inserted_frame_duration_in_us = last_render_time_in_us /
1386 							frames_to_insert;
1387 
1388 		if (inserted_frame_duration_in_us <
1389 			state->time.min_render_time_in_us)
1390 
1391 			inserted_frame_duration_in_us =
1392 				state->time.min_render_time_in_us;
1393 
1394 		/* Cache the calculated variables */
1395 		state->btr.inserted_frame_duration_in_us =
1396 			inserted_frame_duration_in_us;
1397 		state->btr.frames_to_insert = frames_to_insert;
1398 		state->btr.frame_counter = frames_to_insert;
1399 
1400 	}
1401 }
1402 
1403 static void apply_fixed_refresh(struct core_freesync *core_freesync,
1404 		struct dc_stream_state *stream, unsigned int map_index)
1405 {
1406 	unsigned int vmin = 0, vmax = 0;
1407 	struct freesync_state *state = &core_freesync->map[map_index].state;
1408 
1409 	if (!state->fixed_refresh.program_fixed)
1410 		return;
1411 
1412 	state->fixed_refresh.program_fixed = false;
1413 
1414 	/* Program Fixed Refresh */
1415 
1416 	/* Fixed Refresh set to "not active" so disengage */
1417 	if (!state->fixed_refresh.fixed_active) {
1418 		set_freesync_on_streams(core_freesync, &stream, 1);
1419 
1420 	/* Fixed Refresh set to "active" so engage (fix to max) */
1421 	} else {
1422 
1423 		vmin = state->freesync_range.vmin;
1424 
1425 		vmax = vmin;
1426 
1427 		core_freesync->dc->stream_funcs.adjust_vmin_vmax(
1428 				core_freesync->dc, &stream,
1429 				1, vmin,
1430 				vmax);
1431 	}
1432 }
1433 
1434 void mod_freesync_pre_update_plane_addresses(struct mod_freesync *mod_freesync,
1435 		struct dc_stream_state **streams, int num_streams,
1436 		unsigned int curr_time_stamp_in_us)
1437 {
1438 	unsigned int stream_index, map_index, last_render_time_in_us = 0;
1439 	struct core_freesync *core_freesync = NULL;
1440 
1441 	if (mod_freesync == NULL)
1442 		return;
1443 
1444 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1445 
1446 	for (stream_index = 0; stream_index < num_streams; stream_index++) {
1447 
1448 		map_index = map_index_from_stream(core_freesync,
1449 						streams[stream_index]);
1450 
1451 		if (core_freesync->map[map_index].caps->supported) {
1452 
1453 			last_render_time_in_us = curr_time_stamp_in_us -
1454 					core_freesync->map[map_index].state.time.
1455 					prev_time_stamp_in_us;
1456 
1457 			/* Add the timestamps to the cache and determine
1458 			 * whether BTR program is required
1459 			 */
1460 			update_timestamps(core_freesync, streams[stream_index],
1461 					map_index, last_render_time_in_us);
1462 
1463 			if (core_freesync->map[map_index].state.fullscreen &&
1464 				core_freesync->map[map_index].user_enable.
1465 				enable_for_gaming) {
1466 
1467 				if (core_freesync->map[map_index].caps->btr_supported) {
1468 
1469 					apply_below_the_range(core_freesync,
1470 						streams[stream_index], map_index,
1471 						last_render_time_in_us);
1472 				} else {
1473 					apply_fixed_refresh(core_freesync,
1474 						streams[stream_index], map_index);
1475 				}
1476 			}
1477 
1478 			core_freesync->map[map_index].state.time.
1479 				prev_time_stamp_in_us = curr_time_stamp_in_us;
1480 		}
1481 
1482 	}
1483 }
1484