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