]> Git Repo - linux.git/blob - drivers/gpu/drm/amd/display/modules/freesync/freesync.c
Merge branch 'x86-pti-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux.git] / drivers / gpu / drm / amd / display / modules / freesync / freesync.c
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
49 struct 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
55 struct 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
69 struct 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
80 struct fixed_refresh {
81         bool fixed_active;
82         bool program_fixed;
83         unsigned int frame_counter;
84 };
85
86 struct 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
96 struct 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
112 struct freesync_entity {
113         struct dc_stream_state *stream;
114         struct mod_freesync_caps *caps;
115         struct freesync_state state;
116         struct mod_freesync_user_enable user_enable;
117 };
118
119 struct freesync_registry_options {
120         bool drr_external_supported;
121         bool drr_internal_supported;
122 };
123
124 struct 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
135 static 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
143 struct mod_freesync *mod_freesync_create(struct dc *dc)
144 {
145         struct core_freesync *core_freesync =
146                         kzalloc(sizeof(struct core_freesync), GFP_KERNEL);
147
148
149         struct persistent_data_flag flag;
150
151         int i, data = 0;
152
153         if (core_freesync == NULL)
154                 goto fail_alloc_context;
155
156         core_freesync->map = kzalloc(sizeof(struct freesync_entity) * MOD_FREESYNC_MAX_CONCURRENT_STREAMS,
157                                      GFP_KERNEL);
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;
178         dm_write_persistent_data(dc->ctx, NULL, FREESYNC_REGISTRY_NAME,
179                         NULL, NULL, 0, &flag);
180         flag.save_per_edid = false;
181         flag.save_per_link = false;
182
183         if (dm_read_persistent_data(dc->ctx, NULL, NULL,
184                         FREESYNC_NO_STATIC_FOR_INTERNAL_REGKEY,
185                         &data, sizeof(data), &flag)) {
186                 core_freesync->opts.drr_internal_supported =
187                         (data & 1) ? false : true;
188         }
189
190         if (dm_read_persistent_data(dc->ctx, NULL, NULL,
191                         FREESYNC_NO_STATIC_FOR_EXTERNAL_DP_REGKEY,
192                         &data, sizeof(data), &flag)) {
193                 core_freesync->opts.drr_external_supported =
194                                 (data & 1) ? false : true;
195         }
196
197         return &core_freesync->public;
198
199 fail_construct:
200         kfree(core_freesync->map);
201
202 fail_alloc_map:
203         kfree(core_freesync);
204
205 fail_alloc_context:
206         return NULL;
207 }
208
209 void 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
220                 kfree(core_freesync->map);
221
222                 kfree(core_freesync);
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  */
229 static unsigned int map_index_from_stream(struct core_freesync *core_freesync,
230                 struct dc_stream_state *stream)
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
244 bool mod_freesync_add_stream(struct mod_freesync *mod_freesync,
245                 struct dc_stream_state *stream, struct mod_freesync_caps *caps)
246 {
247         struct dc  *dc = NULL;
248         struct core_freesync *core_freesync = NULL;
249         int persistent_freesync_enable = 0;
250         struct persistent_data_flag flag;
251         unsigned int nom_refresh_rate_uhz;
252         unsigned long long temp;
253
254         if (mod_freesync == NULL)
255                 return false;
256
257         core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
258         dc = core_freesync->dc;
259
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
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
272                 nom_refresh_rate_uhz = (unsigned int) temp;
273
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 */
289                 if (dm_read_persistent_data(dc->ctx, stream->sink,
290                                         FREESYNC_REGISTRY_NAME,
291                                         "userenable", &persistent_freesync_enable,
292                                         sizeof(int), &flag)) {
293                         core_freesync->map[core_freesync->num_entities].user_enable.
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
311                 if (caps->supported &&
312                         nom_refresh_rate_uhz >= caps->min_refresh_in_micro_hz &&
313                         nom_refresh_rate_uhz <= caps->max_refresh_in_micro_hz)
314                         stream->ignore_msa_timing_param = 1;
315
316                 core_freesync->num_entities++;
317                 return true;
318         }
319         return false;
320 }
321
322 bool mod_freesync_remove_stream(struct mod_freesync *mod_freesync,
323                 struct dc_stream_state *stream)
324 {
325         int i = 0;
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
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
344 static void update_stream_freesync_context(struct core_freesync *core_freesync,
345                 struct dc_stream_state *stream)
346 {
347         unsigned int index;
348         struct freesync_context *ctx;
349
350         ctx = &stream->freesync_ctx;
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
368 static void update_stream(struct core_freesync *core_freesync,
369                 struct dc_stream_state *stream)
370 {
371         unsigned int index = map_index_from_stream(core_freesync, stream);
372         if (core_freesync->map[index].caps->supported) {
373                 stream->ignore_msa_timing_param = 1;
374                 update_stream_freesync_context(core_freesync, stream);
375         }
376 }
377
378 static void calc_freesync_range(struct core_freesync *core_freesync,
379                 struct dc_stream_state *stream,
380                 struct freesync_state *state,
381                 unsigned int min_refresh_in_uhz,
382                 unsigned int max_refresh_in_uhz)
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);
386         uint32_t vtotal = stream->timing.v_total;
387
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
403         min_frame_duration_in_ns = ((unsigned int) (div64_u64(
404                                         (1000000000ULL * 1000000),
405                                         max_refresh_in_uhz)));
406         max_frame_duration_in_ns = ((unsigned int) (div64_u64(
407                 (1000000000ULL * 1000000),
408                 min_refresh_in_uhz)));
409
410         state->freesync_range.min_refresh = min_refresh_in_uhz;
411         state->freesync_range.max_refresh = max_refresh_in_uhz;
412
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);
422
423         /* vmin/vmax cannot be less than vtotal */
424         if (state->freesync_range.vmin < vtotal) {
425                 /* Error of 1 is permissible */
426                 ASSERT((state->freesync_range.vmin + 1) >= vtotal);
427                 state->freesync_range.vmin = vtotal;
428         }
429
430         if (state->freesync_range.vmax < vtotal) {
431                 /* Error of 1 is permissible */
432                 ASSERT((state->freesync_range.vmax + 1) >= vtotal);
433                 state->freesync_range.vmax = vtotal;
434         }
435
436         /* Determine whether BTR can be supported */
437         if (max_frame_duration_in_ns >=
438                         2 * min_frame_duration_in_ns)
439                 core_freesync->map[index].caps->btr_supported = true;
440         else
441                 core_freesync->map[index].caps->btr_supported = false;
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;
451 }
452
453 static void calc_v_total_from_duration(struct dc_stream_state *stream,
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
461 static void calc_v_total_for_static_ramp(struct core_freesync *core_freesync,
462                 struct dc_stream_state *stream,
463                 unsigned int index, int *v_total)
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
536 static 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
551         state->fixed_refresh.fixed_active = false;
552         state->fixed_refresh.program_fixed = false;
553 }
554 /*
555  * Sets freesync mode on a stream depending on current freesync state.
556  */
557 static bool set_freesync_on_streams(struct core_freesync *core_freesync,
558                 struct dc_stream_state **streams, int num_streams)
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 &&
592                                 state->fixed_refresh.fixed_active == false) {
593                                 /* Enable freesync */
594
595                                 v_total_min = state->freesync_range.vmin;
596                                 v_total_max = state->freesync_range.vmax;
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
682 static 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;
686         unsigned int nominal_refresh_rate = core_freesync->map[index].state.
687                         nominal_refresh_rate_in_micro_hz;
688         unsigned int min_refresh_rate= core_freesync->map[index].caps->
689                         min_refresh_in_micro_hz;
690         struct gradual_static_ramp *static_ramp_variables =
691                         &core_freesync->map[index].state.static_ramp;
692
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
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) {
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),
713                                 nominal_refresh_rate)));
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),
720                                 min_refresh_rate)));
721                 }
722                 static_ramp_variables->
723                         ramp_current_frame_duration_in_ns = frame_duration;
724
725                 static_ramp_variables->ramp_is_active = true;
726         }
727 }
728
729 void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync,
730                 struct dc_stream_state **streams, int num_streams)
731 {
732         unsigned int index, v_total, inserted_frame_v_total = 0;
733         unsigned int min_frame_duration_in_ns, vmax, vmin = 0;
734         struct freesync_state *state;
735         struct core_freesync *core_freesync = NULL;
736         struct dc_static_screen_events triggers = {0};
737
738         if (mod_freesync == NULL)
739                 return;
740
741         core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
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 &&
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
775                         vmin = state->freesync_range.vmin;
776
777                         inserted_frame_v_total = vmin;
778
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);
783
784                         /* Set length of inserted frames as v_total_max*/
785                         vmax = inserted_frame_v_total;
786                         vmin = inserted_frame_v_total;
787
788                         /* Program V_TOTAL */
789                         core_freesync->dc->stream_funcs.adjust_vmin_vmax(
790                                 core_freesync->dc, streams,
791                                 num_streams, vmin, vmax);
792                 }
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);
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);
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);
836         }
837 }
838
839 void mod_freesync_update_state(struct mod_freesync *mod_freesync,
840                 struct dc_stream_state **streams, int num_streams,
841                 struct mod_freesync_params *freesync_params)
842 {
843         bool freesync_program_required = false;
844         unsigned int stream_index;
845         struct freesync_state *state;
846         struct core_freesync *core_freesync = NULL;
847         struct dc_static_screen_events triggers = {0};
848
849         if (mod_freesync == NULL)
850                 return;
851
852         core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
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
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
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:
877                         /* Static screen ramp is disabled by default, but can
878                          * be enabled through regkey.
879                          */
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,
892                                                 map_index,
893                                                 freesync_params->enable);
894                                 }
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;
909                 case FREESYNC_STATE_NONE:
910                         /* handle here to avoid warning */
911                         break;
912                 }
913         }
914
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
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
929 bool mod_freesync_get_state(struct mod_freesync *mod_freesync,
930                 struct dc_stream_state *stream,
931                 struct mod_freesync_params *freesync_params)
932 {
933         unsigned int index = 0;
934         struct core_freesync *core_freesync = NULL;
935
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);
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
959         freesync_params->windowed_fullscreen =
960                         core_freesync->map[index].state.windowed_fullscreen;
961
962         return true;
963 }
964
965 bool mod_freesync_set_user_enable(struct mod_freesync *mod_freesync,
966                 struct dc_stream_state **streams, int num_streams,
967                 struct mod_freesync_user_enable *user_enable)
968 {
969         unsigned int stream_index, map_index;
970         int persistent_data = 0;
971         struct persistent_data_flag flag;
972         struct dc  *dc = NULL;
973         struct core_freesync *core_freesync = NULL;
974
975         if (mod_freesync == NULL)
976                 return false;
977
978         core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
979         dc = core_freesync->dc;
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
1003                 dm_write_persistent_data(dc->ctx,
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
1017 bool mod_freesync_get_user_enable(struct mod_freesync *mod_freesync,
1018                 struct dc_stream_state *stream,
1019                 struct mod_freesync_user_enable *user_enable)
1020 {
1021         unsigned int index = 0;
1022         struct core_freesync *core_freesync = NULL;
1023
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);
1029
1030         *user_enable = core_freesync->map[index].user_enable;
1031
1032         return true;
1033 }
1034
1035 bool mod_freesync_get_static_ramp_active(struct mod_freesync *mod_freesync,
1036                 struct dc_stream_state *stream,
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
1054 bool mod_freesync_override_min_max(struct mod_freesync *mod_freesync,
1055                 struct dc_stream_state *streams,
1056                 unsigned int min_refresh,
1057                 unsigned int max_refresh,
1058                 struct mod_freesync_caps *caps)
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
1071         if (max_refresh == 0)
1072                 max_refresh = state->nominal_refresh_rate_in_micro_hz;
1073
1074         if (min_refresh == 0) {
1075                 /* Restore defaults */
1076                 calc_freesync_range(core_freesync, streams, state,
1077                         core_freesync->map[index].caps->
1078                         min_refresh_in_micro_hz,
1079                         state->nominal_refresh_rate_in_micro_hz);
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
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
1104         return true;
1105 }
1106
1107 bool mod_freesync_get_min_max(struct mod_freesync *mod_freesync,
1108                 struct dc_stream_state *stream,
1109                 unsigned int *min_refresh,
1110                 unsigned int *max_refresh)
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
1129 bool mod_freesync_get_vmin_vmax(struct mod_freesync *mod_freesync,
1130                 struct dc_stream_state *stream,
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
1151 bool mod_freesync_get_v_position(struct mod_freesync *mod_freesync,
1152                 struct dc_stream_state *stream,
1153                 unsigned int *nom_v_pos,
1154                 unsigned int *v_pos)
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
1170                 *nom_v_pos = position.nominal_vcount;
1171                 *v_pos = position.vertical_count;
1172
1173                 return true;
1174         }
1175
1176         return false;
1177 }
1178
1179 void mod_freesync_notify_mode_change(struct mod_freesync *mod_freesync,
1180                 struct dc_stream_state **streams, int num_streams)
1181 {
1182         unsigned int stream_index, map_index;
1183         struct freesync_state *state;
1184         struct core_freesync *core_freesync = NULL;
1185         struct dc_static_screen_events triggers = {0};
1186         unsigned long long temp = 0;
1187
1188         if (mod_freesync == NULL)
1189                 return;
1190
1191         core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1192
1193         for (stream_index = 0; stream_index < num_streams; stream_index++) {
1194                 map_index = map_index_from_stream(core_freesync,
1195                                 streams[stream_index]);
1196
1197                 state = &core_freesync->map[map_index].state;
1198
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
1209                 if (core_freesync->map[map_index].caps->supported) {
1210
1211                         /* Update the stream */
1212                         update_stream(core_freesync, streams[stream_index]);
1213
1214                         /* Calculate vmin/vmax and refresh rate for
1215                          * current mode
1216                          */
1217                         calc_freesync_range(core_freesync, *streams, state,
1218                                 core_freesync->map[map_index].caps->
1219                                 min_refresh_in_micro_hz,
1220                                 state->nominal_refresh_rate_in_micro_hz);
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);
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  */
1239 static void update_timestamps(struct core_freesync *core_freesync,
1240                 const struct dc_stream_state *stream, unsigned int map_index,
1241                 unsigned int last_render_time_in_us)
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 */
1263                 } else if (state->fixed_refresh.fixed_active) {
1264
1265                         state->fixed_refresh.frame_counter++;
1266
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                         }
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 &&
1279                         core_freesync->map[map_index].caps->btr_supported) {
1280
1281                         state->btr.program_btr = true;
1282                         state->btr.btr_active = true;
1283
1284                 /* Enter Fixed Refresh mode */
1285                 } else if (!state->fixed_refresh.fixed_active &&
1286                         !core_freesync->map[map_index].caps->btr_supported) {
1287
1288                         state->fixed_refresh.frame_counter++;
1289
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                         }
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
1304 static void apply_below_the_range(struct core_freesync *core_freesync,
1305                 struct dc_stream_state *stream, unsigned int map_index,
1306                 unsigned int last_render_time_in_us)
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;
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;
1349                         delta_from_mid_point_in_us_1 =
1350                                 (state->btr.mid_point_in_us >
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;
1366                         delta_from_mid_point_in_us_2 =
1367                                 (state->btr.mid_point_in_us >
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
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
1403 static void apply_fixed_refresh(struct core_freesync *core_freesync,
1404                 struct dc_stream_state *stream, unsigned int map_index)
1405 {
1406         unsigned int vmin = 0, vmax = 0;
1407         struct freesync_state *state = &core_freesync->map[map_index].state;
1408
1409         if (!state->fixed_refresh.program_fixed)
1410                 return;
1411
1412         state->fixed_refresh.program_fixed = false;
1413
1414         /* Program Fixed Refresh */
1415
1416         /* Fixed Refresh set to "not active" so disengage */
1417         if (!state->fixed_refresh.fixed_active) {
1418                 set_freesync_on_streams(core_freesync, &stream, 1);
1419
1420         /* Fixed Refresh set to "active" so engage (fix to max) */
1421         } else {
1422
1423                 vmin = state->freesync_range.vmin;
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
1434 void mod_freesync_pre_update_plane_addresses(struct mod_freesync *mod_freesync,
1435                 struct dc_stream_state **streams, int num_streams,
1436                 unsigned int curr_time_stamp_in_us)
1437 {
1438         unsigned int stream_index, map_index, last_render_time_in_us = 0;
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);
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 }
This page took 0.128284 seconds and 4 git commands to generate.