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