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