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