2 * Copyright 2016 Advanced Micro Devices, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
26 #include "dm_services.h"
28 #include "mod_freesync.h"
29 #include "core_types.h"
31 #define MOD_FREESYNC_MAX_CONCURRENT_STREAMS 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
43 #define FREESYNC_REGISTRY_NAME "freesync_v1"
45 #define FREESYNC_NO_STATIC_FOR_EXTERNAL_DP_REGKEY "DalFreeSyncNoStaticForExternalDp"
47 #define FREESYNC_NO_STATIC_FOR_INTERNAL_REGKEY "DalFreeSyncNoStaticForInternal"
49 struct gradual_static_ramp {
51 bool ramp_direction_is_up;
52 unsigned int ramp_current_frame_duration_in_ns;
56 /* video (48Hz feature) related */
57 unsigned int update_duration_in_ns;
59 /* BTR/fixed refresh related */
60 unsigned int prev_time_stamp_in_us;
62 unsigned int min_render_time_in_us;
63 unsigned int max_render_time_in_us;
65 unsigned int render_times_index;
66 unsigned int render_times[RENDER_TIMES_MAX_COUNT];
69 struct below_the_range {
73 unsigned int mid_point_in_us;
75 unsigned int inserted_frame_duration_in_us;
76 unsigned int frames_to_insert;
77 unsigned int frame_counter;
80 struct fixed_refresh {
83 unsigned int frame_counter;
86 struct freesync_range {
87 unsigned int min_refresh;
88 unsigned int max_frame_duration;
91 unsigned int max_refresh;
92 unsigned int min_frame_duration;
96 struct freesync_state {
101 unsigned int nominal_refresh_rate_in_micro_hz;
102 bool windowed_fullscreen;
104 struct time_cache time;
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;
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;
119 struct freesync_registry_options {
120 bool drr_external_supported;
121 bool drr_internal_supported;
124 struct core_freesync {
125 struct mod_freesync public;
127 struct freesync_entity *map;
129 struct freesync_registry_options opts;
132 #define MOD_FREESYNC_TO_CORE(mod_freesync)\
133 container_of(mod_freesync, struct core_freesync, public)
135 static bool check_dc_support(const struct dc *dc)
137 if (dc->stream_funcs.adjust_vmin_vmax == NULL)
143 struct mod_freesync *mod_freesync_create(struct dc *dc)
145 struct core_freesync *core_freesync =
146 kzalloc(sizeof(struct core_freesync), GFP_KERNEL);
149 struct persistent_data_flag flag;
153 if (core_freesync == NULL)
154 goto fail_alloc_context;
156 core_freesync->map = kzalloc(sizeof(struct freesync_entity) * MOD_FREESYNC_MAX_CONCURRENT_STREAMS,
159 if (core_freesync->map == NULL)
162 for (i = 0; i < MOD_FREESYNC_MAX_CONCURRENT_STREAMS; i++)
163 core_freesync->map[i].stream = NULL;
165 core_freesync->num_entities = 0;
170 core_freesync->dc = dc;
172 if (!check_dc_support(dc))
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;
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;
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;
197 return &core_freesync->public;
200 kfree(core_freesync->map);
203 kfree(core_freesync);
209 void mod_freesync_destroy(struct mod_freesync *mod_freesync)
211 if (mod_freesync != NULL) {
213 struct core_freesync *core_freesync =
214 MOD_FREESYNC_TO_CORE(mod_freesync);
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);
220 kfree(core_freesync->map);
222 kfree(core_freesync);
226 /* Given a specific dc_stream* this function finds its equivalent
227 * on the core_freesync->map and returns the corresponding index
229 static unsigned int map_index_from_stream(struct core_freesync *core_freesync,
230 struct dc_stream_state *stream)
232 unsigned int index = 0;
234 for (index = 0; index < core_freesync->num_entities; index++) {
235 if (core_freesync->map[index].stream == stream) {
239 /* Could not find stream requested */
244 bool mod_freesync_add_stream(struct mod_freesync *mod_freesync,
245 struct dc_stream_state *stream, struct mod_freesync_caps *caps)
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;
254 if (mod_freesync == NULL)
257 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
258 dc = core_freesync->dc;
260 flag.save_per_edid = true;
261 flag.save_per_link = false;
263 if (core_freesync->num_entities < MOD_FREESYNC_MAX_CONCURRENT_STREAMS) {
265 dc_stream_retain(stream);
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);
272 nom_refresh_rate_uhz = (unsigned int) temp;
274 core_freesync->map[core_freesync->num_entities].stream = stream;
275 core_freesync->map[core_freesync->num_entities].caps = caps;
277 core_freesync->map[core_freesync->num_entities].state.
279 core_freesync->map[core_freesync->num_entities].state.
280 static_screen = false;
281 core_freesync->map[core_freesync->num_entities].state.
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;
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.
295 (persistent_freesync_enable & 1) ? true : false;
296 core_freesync->map[core_freesync->num_entities].user_enable.
298 (persistent_freesync_enable & 2) ? true : false;
299 core_freesync->map[core_freesync->num_entities].user_enable.
301 (persistent_freesync_enable & 4) ? true : false;
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;
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;
316 core_freesync->num_entities++;
322 bool mod_freesync_remove_stream(struct mod_freesync *mod_freesync,
323 struct dc_stream_state *stream)
326 struct core_freesync *core_freesync = NULL;
327 unsigned int index = 0;
329 if (mod_freesync == NULL)
332 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
333 index = map_index_from_stream(core_freesync, stream);
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--;
344 static void update_stream_freesync_context(struct core_freesync *core_freesync,
345 struct dc_stream_state *stream)
348 struct freesync_context *ctx;
350 ctx = &stream->freesync_ctx;
352 index = map_index_from_stream(core_freesync, stream);
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;
368 static void update_stream(struct core_freesync *core_freesync,
369 struct dc_stream_state *stream)
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);
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)
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;
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;
394 state->freesync_range.max_frame_duration = 0;
395 state->freesync_range.min_frame_duration = 0;
397 state->freesync_range.vmax = vtotal;
398 state->freesync_range.vmin = vtotal;
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)));
410 state->freesync_range.min_refresh = min_refresh_in_uhz;
411 state->freesync_range.max_refresh = max_refresh_in_uhz;
413 state->freesync_range.max_frame_duration = max_frame_duration_in_ns;
414 state->freesync_range.min_frame_duration = min_frame_duration_in_ns;
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);
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;
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;
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;
441 core_freesync->map[index].caps->btr_supported = false;
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;
453 static void calc_v_total_from_duration(struct dc_stream_state *stream,
454 unsigned int duration_in_ns, int *v_total_nominal)
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);
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)
465 unsigned int frame_duration = 0;
467 struct gradual_static_ramp *static_ramp_variables =
468 &core_freesync->map[index].state.static_ramp;
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),
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);
482 /* Adjust frame duration delta based on ratio between current and
483 * standard frame duration (frame duration at 60 Hz refresh rate).
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);
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;
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)));
501 /* adjust for frame duration below min */
502 if (static_ramp_variables->ramp_current_frame_duration_in_ns <=
505 static_ramp_variables->ramp_is_active = false;
506 static_ramp_variables->
507 ramp_current_frame_duration_in_ns =
510 /* Going to a lower refresh rate (larger frame duration) */
512 /* increase frame duration */
513 static_ramp_variables->ramp_current_frame_duration_in_ns +=
514 ramp_rate_interpolated;
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)));
521 /* adjust for frame duration above max */
522 if (static_ramp_variables->ramp_current_frame_duration_in_ns >=
525 static_ramp_variables->ramp_is_active = false;
526 static_ramp_variables->
527 ramp_current_frame_duration_in_ns =
532 calc_v_total_from_duration(stream, static_ramp_variables->
533 ramp_current_frame_duration_in_ns, v_total);
536 static void reset_freesync_state_variables(struct freesync_state* state)
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)));
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;
551 state->fixed_refresh.fixed_active = false;
552 state->fixed_refresh.program_fixed = false;
555 * Sets freesync mode on a stream depending on current freesync state.
557 static bool set_freesync_on_streams(struct core_freesync *core_freesync,
558 struct dc_stream_state **streams, int num_streams)
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;
564 if (num_streams == 0 || streams == NULL || num_streams > 1)
567 for (stream_idx = 0; stream_idx < num_streams; stream_idx++) {
569 map_index = map_index_from_stream(core_freesync,
570 streams[stream_idx]);
572 state = &core_freesync->map[map_index].state;
574 if (core_freesync->map[map_index].caps->supported) {
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
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.
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 */
595 v_total_min = state->freesync_range.vmin;
596 v_total_max = state->freesync_range.vmax;
598 /* Update the freesync context for the stream */
599 update_stream_freesync_context(core_freesync,
600 streams[stream_idx]);
602 core_freesync->dc->stream_funcs.
603 adjust_vmin_vmax(core_freesync->dc, streams,
604 num_streams, v_total_min,
609 } else if (core_freesync->map[map_index].user_enable.
610 enable_for_video && state->video == true) {
611 /* Enable 48Hz feature */
613 calc_v_total_from_duration(streams[stream_idx],
614 state->time.update_duration_in_ns,
617 /* Program only if v_total_nominal is in range*/
618 if (v_total_nominal >=
619 streams[stream_idx]->timing.v_total) {
621 /* Update the freesync context for
624 update_stream_freesync_context(
626 streams[stream_idx]);
628 core_freesync->dc->stream_funcs.
630 core_freesync->dc, streams,
631 num_streams, v_total_nominal,
637 /* Disable freesync */
638 v_total_nominal = streams[stream_idx]->
641 /* Update the freesync context for
644 update_stream_freesync_context(
646 streams[stream_idx]);
648 core_freesync->dc->stream_funcs.
650 core_freesync->dc, streams,
651 num_streams, v_total_nominal,
654 /* Reset the cached variables */
655 reset_freesync_state_variables(state);
660 /* Disable freesync */
661 v_total_nominal = streams[stream_idx]->
664 * we have to reset drr always even sink does
665 * not support freesync because a former stream has
668 core_freesync->dc->stream_funcs.
670 core_freesync->dc, streams,
671 num_streams, v_total_nominal,
673 /* Reset the cached variables */
674 reset_freesync_state_variables(state);
682 static void set_static_ramp_variables(struct core_freesync *core_freesync,
683 unsigned int index, bool enable_static_screen)
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;
693 /* If we are ENABLING static screen, refresh rate should go DOWN.
694 * If we are DISABLING static screen, refresh rate should go UP.
696 if (enable_static_screen)
697 static_ramp_variables->ramp_direction_is_up = false;
699 static_ramp_variables->ramp_direction_is_up = true;
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
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)
711 frame_duration = ((unsigned int) (div64_u64(
712 (1000000000ULL * 1000000),
713 nominal_refresh_rate)));
715 /* Going to higher refresh rate, so start from min
716 * refresh rate (max frame duration)
718 frame_duration = ((unsigned int) (div64_u64(
719 (1000000000ULL * 1000000),
722 static_ramp_variables->
723 ramp_current_frame_duration_in_ns = frame_duration;
725 static_ramp_variables->ramp_is_active = true;
729 void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync,
730 struct dc_stream_state **streams, int num_streams)
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};
738 if (mod_freesync == NULL)
741 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
743 if (core_freesync->num_entities == 0)
746 index = map_index_from_stream(core_freesync,
749 if (core_freesync->map[index].caps->supported == false)
752 state = &core_freesync->map[index].state;
754 /* Below the Range Logic */
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) {
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
766 * For DCE12 and newer updates to V_TOTAL_MIN/MAX
767 * will take affect on current frame
769 if (state->btr.frames_to_insert == state->btr.frame_counter) {
771 min_frame_duration_in_ns = ((unsigned int) (div64_u64(
772 (1000000000ULL * 1000000),
773 state->nominal_refresh_rate_in_micro_hz)));
775 vmin = state->freesync_range.vmin;
777 inserted_frame_v_total = vmin;
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);
784 /* Set length of inserted frames as v_total_max*/
785 vmax = inserted_frame_v_total;
786 vmin = inserted_frame_v_total;
788 /* Program V_TOTAL */
789 core_freesync->dc->stream_funcs.adjust_vmin_vmax(
790 core_freesync->dc, streams,
791 num_streams, vmin, vmax);
794 if (state->btr.frame_counter > 0)
795 state->btr.frame_counter--;
797 /* Restore FreeSync */
798 if (state->btr.frame_counter == 0)
799 set_freesync_on_streams(core_freesync, streams, num_streams);
802 /* If in fullscreen freesync mode or in video, do not program
803 * static screen ramp values
805 if (state->fullscreen == true || state->video == true) {
807 state->static_ramp.ramp_is_active = false;
812 /* Gradual Static Screen Ramping Logic */
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) {
818 calc_v_total_for_static_ramp(core_freesync, streams[0],
821 /* Update the freesync context for the stream */
822 update_stream_freesync_context(core_freesync, streams[0]);
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,
830 triggers.overlay_update = true;
831 triggers.surface_update = true;
833 core_freesync->dc->stream_funcs.set_static_screen_events(
834 core_freesync->dc, streams, num_streams,
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)
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};
849 if (mod_freesync == NULL)
852 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
854 if (core_freesync->num_entities == 0)
857 for(stream_index = 0; stream_index < num_streams; stream_index++) {
859 unsigned int map_index = map_index_from_stream(core_freesync,
860 streams[stream_index]);
862 bool is_embedded = dc_is_embedded_signal(
863 streams[stream_index]->sink->sink_signal);
865 struct freesync_registry_options *opts = &core_freesync->opts;
867 state = &core_freesync->map[map_index].state;
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;
876 case FREESYNC_STATE_STATIC_SCREEN:
877 /* Static screen ramp is disabled by default, but can
878 * be enabled through regkey.
880 if ((is_embedded && opts->drr_internal_supported) ||
881 (!is_embedded && opts->drr_external_supported))
883 if (state->static_screen !=
884 freesync_params->enable) {
886 /* Change the state flag */
887 state->static_screen =
888 freesync_params->enable;
890 /* Update static screen ramp */
891 set_static_ramp_variables(core_freesync,
893 freesync_params->enable);
895 /* We program the ramp starting next VUpdate */
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) {
902 state->video = freesync_params->enable;
903 state->time.update_duration_in_ns =
904 freesync_params->update_duration_in_ns;
906 freesync_program_required = true;
909 case FREESYNC_STATE_NONE:
910 /* handle here to avoid warning */
916 triggers.overlay_update = true;
917 triggers.surface_update = true;
919 core_freesync->dc->stream_funcs.set_static_screen_events(
920 core_freesync->dc, streams, num_streams,
923 if (freesync_program_required)
924 /* Program freesync according to current state*/
925 set_freesync_on_streams(core_freesync, streams, num_streams);
929 bool mod_freesync_get_state(struct mod_freesync *mod_freesync,
930 struct dc_stream_state *stream,
931 struct mod_freesync_params *freesync_params)
933 unsigned int index = 0;
934 struct core_freesync *core_freesync = NULL;
936 if (mod_freesync == NULL)
939 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
940 index = map_index_from_stream(core_freesync, stream);
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;
952 freesync_params->state = FREESYNC_STATE_NONE;
953 freesync_params->enable = false;
956 freesync_params->update_duration_in_ns =
957 core_freesync->map[index].state.time.update_duration_in_ns;
959 freesync_params->windowed_fullscreen =
960 core_freesync->map[index].state.windowed_fullscreen;
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)
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;
975 if (mod_freesync == NULL)
978 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
979 dc = core_freesync->dc;
981 flag.save_per_edid = true;
982 flag.save_per_link = false;
984 for(stream_index = 0; stream_index < num_streams;
987 map_index = map_index_from_stream(core_freesync,
988 streams[stream_index]);
990 core_freesync->map[map_index].user_enable = *user_enable;
992 /* Write persistent data in registry*/
993 if (core_freesync->map[map_index].user_enable.
995 persistent_data = persistent_data | 1;
996 if (core_freesync->map[map_index].user_enable.
998 persistent_data = persistent_data | 2;
999 if (core_freesync->map[map_index].user_enable.
1001 persistent_data = persistent_data | 4;
1003 dm_write_persistent_data(dc->ctx,
1004 streams[stream_index]->sink,
1005 FREESYNC_REGISTRY_NAME,
1012 set_freesync_on_streams(core_freesync, streams, num_streams);
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)
1021 unsigned int index = 0;
1022 struct core_freesync *core_freesync = NULL;
1024 if (mod_freesync == NULL)
1027 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1028 index = map_index_from_stream(core_freesync, stream);
1030 *user_enable = core_freesync->map[index].user_enable;
1035 bool mod_freesync_get_static_ramp_active(struct mod_freesync *mod_freesync,
1036 struct dc_stream_state *stream,
1037 bool *is_ramp_active)
1039 unsigned int index = 0;
1040 struct core_freesync *core_freesync = NULL;
1042 if (mod_freesync == NULL)
1045 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1046 index = map_index_from_stream(core_freesync, stream);
1049 core_freesync->map[index].state.static_ramp.ramp_is_active;
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)
1060 unsigned int index = 0;
1061 struct core_freesync *core_freesync;
1062 struct freesync_state *state;
1064 if (mod_freesync == NULL)
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;
1071 if (max_refresh == 0)
1072 max_refresh = state->nominal_refresh_rate_in_micro_hz;
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);
1081 calc_freesync_range(core_freesync, streams,
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);
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;
1101 /* Update the stream */
1102 update_stream(core_freesync, streams);
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)
1112 unsigned int index = 0;
1113 struct core_freesync *core_freesync = NULL;
1115 if (mod_freesync == NULL)
1118 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1119 index = map_index_from_stream(core_freesync, stream);
1122 core_freesync->map[index].state.freesync_range.min_refresh;
1124 core_freesync->map[index].state.freesync_range.max_refresh;
1129 bool mod_freesync_get_vmin_vmax(struct mod_freesync *mod_freesync,
1130 struct dc_stream_state *stream,
1134 unsigned int index = 0;
1135 struct core_freesync *core_freesync = NULL;
1137 if (mod_freesync == NULL)
1140 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1141 index = map_index_from_stream(core_freesync, stream);
1144 core_freesync->map[index].state.freesync_range.vmin;
1146 core_freesync->map[index].state.freesync_range.vmax;
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)
1156 unsigned int index = 0;
1157 struct core_freesync *core_freesync = NULL;
1158 struct crtc_position position;
1160 if (mod_freesync == NULL)
1163 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1164 index = map_index_from_stream(core_freesync, stream);
1166 if (core_freesync->dc->stream_funcs.get_crtc_position(
1167 core_freesync->dc, &stream, 1,
1168 &position.vertical_count, &position.nominal_vcount)) {
1170 *nom_v_pos = position.nominal_vcount;
1171 *v_pos = position.vertical_count;
1179 void mod_freesync_notify_mode_change(struct mod_freesync *mod_freesync,
1180 struct dc_stream_state **streams, int num_streams)
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;
1188 if (mod_freesync == NULL)
1191 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1193 for (stream_index = 0; stream_index < num_streams; stream_index++) {
1194 map_index = map_index_from_stream(core_freesync,
1195 streams[stream_index]);
1197 state = &core_freesync->map[map_index].state;
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;
1209 if (core_freesync->map[map_index].caps->supported) {
1211 /* Update the stream */
1212 update_stream(core_freesync, streams[stream_index]);
1214 /* Calculate vmin/vmax and refresh rate for
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);
1223 triggers.overlay_update = true;
1224 triggers.surface_update = true;
1226 core_freesync->dc->stream_funcs.set_static_screen_events(
1227 core_freesync->dc, streams, num_streams,
1232 /* Program freesync according to current state*/
1233 set_freesync_on_streams(core_freesync, streams, num_streams);
1236 /* Add the timestamps to the cache and determine whether BTR programming
1237 * is required, depending on the times calculated
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)
1243 struct freesync_state *state = &core_freesync->map[map_index].state;
1245 state->time.render_times[state->time.render_times_index] =
1246 last_render_time_in_us;
1247 state->time.render_times_index++;
1249 if (state->time.render_times_index >= RENDER_TIMES_MAX_COUNT)
1250 state->time.render_times_index = 0;
1252 if (last_render_time_in_us + BTR_EXIT_MARGIN <
1253 state->time.max_render_time_in_us) {
1255 /* Exit Below the Range */
1256 if (state->btr.btr_active) {
1258 state->btr.program_btr = true;
1259 state->btr.btr_active = false;
1260 state->btr.frame_counter = 0;
1262 /* Exit Fixed Refresh mode */
1263 } else if (state->fixed_refresh.fixed_active) {
1265 state->fixed_refresh.frame_counter++;
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;
1275 } else if (last_render_time_in_us > state->time.max_render_time_in_us) {
1277 /* Enter Below the Range */
1278 if (!state->btr.btr_active &&
1279 core_freesync->map[map_index].caps->btr_supported) {
1281 state->btr.program_btr = true;
1282 state->btr.btr_active = true;
1284 /* Enter Fixed Refresh mode */
1285 } else if (!state->fixed_refresh.fixed_active &&
1286 !core_freesync->map[map_index].caps->btr_supported) {
1288 state->fixed_refresh.frame_counter++;
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;
1299 /* When Below the Range is active, must react on every frame */
1300 if (state->btr.btr_active)
1301 state->btr.program_btr = true;
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)
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;
1318 if (!state->btr.program_btr)
1321 state->btr.program_btr = false;
1323 min_frame_duration_in_ns = ((unsigned int) (div64_u64(
1324 (1000000000ULL * 1000000),
1325 state->nominal_refresh_rate_in_micro_hz)));
1329 /* BTR set to "not active" so disengage */
1330 if (!state->btr.btr_active)
1332 /* Restore FreeSync */
1333 set_freesync_on_streams(core_freesync, &stream, 1);
1335 /* BTR set to "active" so engage */
1338 /* Calculate number of midPoint frames that could fit within
1339 * the render time interval- take ceil of this value
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;
1345 if (mid_point_frames_ceil > 0) {
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 >
1352 (state->btr.mid_point_in_us - frame_time_in_us):
1353 (frame_time_in_us - state->btr.mid_point_in_us);
1356 /* Calculate number of midPoint frames that could fit within
1357 * the render time interval- take floor of this value
1359 mid_point_frames_floor = last_render_time_in_us /
1360 state->btr.mid_point_in_us;
1362 if (mid_point_frames_floor > 0) {
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 >
1369 (state->btr.mid_point_in_us - frame_time_in_us):
1370 (frame_time_in_us - state->btr.mid_point_in_us);
1373 /* Choose number of frames to insert based on how close it
1374 * can get to the mid point of the variable range.
1376 if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2)
1377 frames_to_insert = mid_point_frames_ceil;
1379 frames_to_insert = mid_point_frames_floor;
1381 /* Either we've calculated the number of frames to insert,
1382 * or we need to insert min duration frames
1384 if (frames_to_insert > 0)
1385 inserted_frame_duration_in_us = last_render_time_in_us /
1388 if (inserted_frame_duration_in_us <
1389 state->time.min_render_time_in_us)
1391 inserted_frame_duration_in_us =
1392 state->time.min_render_time_in_us;
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;
1403 static void apply_fixed_refresh(struct core_freesync *core_freesync,
1404 struct dc_stream_state *stream, unsigned int map_index)
1406 unsigned int vmin = 0, vmax = 0;
1407 struct freesync_state *state = &core_freesync->map[map_index].state;
1409 if (!state->fixed_refresh.program_fixed)
1412 state->fixed_refresh.program_fixed = false;
1414 /* Program Fixed Refresh */
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);
1420 /* Fixed Refresh set to "active" so engage (fix to max) */
1423 vmin = state->freesync_range.vmin;
1427 core_freesync->dc->stream_funcs.adjust_vmin_vmax(
1428 core_freesync->dc, &stream,
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)
1438 unsigned int stream_index, map_index, last_render_time_in_us = 0;
1439 struct core_freesync *core_freesync = NULL;
1441 if (mod_freesync == NULL)
1444 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1446 for (stream_index = 0; stream_index < num_streams; stream_index++) {
1448 map_index = map_index_from_stream(core_freesync,
1449 streams[stream_index]);
1451 if (core_freesync->map[map_index].caps->supported) {
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;
1457 /* Add the timestamps to the cache and determine
1458 * whether BTR program is required
1460 update_timestamps(core_freesync, streams[stream_index],
1461 map_index, last_render_time_in_us);
1463 if (core_freesync->map[map_index].state.fullscreen &&
1464 core_freesync->map[map_index].user_enable.
1465 enable_for_gaming) {
1467 if (core_freesync->map[map_index].caps->btr_supported) {
1469 apply_below_the_range(core_freesync,
1470 streams[stream_index], map_index,
1471 last_render_time_in_us);
1473 apply_fixed_refresh(core_freesync,
1474 streams[stream_index], map_index);
1478 core_freesync->map[map_index].state.time.
1479 prev_time_stamp_in_us = curr_time_stamp_in_us;