]> Git Repo - linux.git/blob - drivers/gpu/drm/amd/display/modules/freesync/freesync.c
Merge tag 'drm-misc-next-fixes-2021-11-05' of git://anongit.freedesktop.org/drm/drm...
[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 <linux/slab.h>
27
28 #include "dm_services.h"
29 #include "dc.h"
30 #include "mod_freesync.h"
31 #include "core_types.h"
32
33 #define MOD_FREESYNC_MAX_CONCURRENT_STREAMS  32
34
35 #define MIN_REFRESH_RANGE 10
36 /* Refresh rate ramp at a fixed rate of 65 Hz/second */
37 #define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65)
38 /* Number of elements in the render times cache array */
39 #define RENDER_TIMES_MAX_COUNT 10
40 /* Threshold to exit/exit BTR (to avoid frequent enter-exits at the lower limit) */
41 #define BTR_MAX_MARGIN 2500
42 /* Threshold to change BTR multiplier (to avoid frequent changes) */
43 #define BTR_DRIFT_MARGIN 2000
44 /* Threshold to exit fixed refresh rate */
45 #define FIXED_REFRESH_EXIT_MARGIN_IN_HZ 1
46 /* Number of consecutive frames to check before entering/exiting fixed refresh */
47 #define FIXED_REFRESH_ENTER_FRAME_COUNT 5
48 #define FIXED_REFRESH_EXIT_FRAME_COUNT 10
49
50 struct core_freesync {
51         struct mod_freesync public;
52         struct dc *dc;
53 };
54
55 #define MOD_FREESYNC_TO_CORE(mod_freesync)\
56                 container_of(mod_freesync, struct core_freesync, public)
57
58 struct mod_freesync *mod_freesync_create(struct dc *dc)
59 {
60         struct core_freesync *core_freesync =
61                         kzalloc(sizeof(struct core_freesync), GFP_KERNEL);
62
63         if (core_freesync == NULL)
64                 goto fail_alloc_context;
65
66         if (dc == NULL)
67                 goto fail_construct;
68
69         core_freesync->dc = dc;
70         return &core_freesync->public;
71
72 fail_construct:
73         kfree(core_freesync);
74
75 fail_alloc_context:
76         return NULL;
77 }
78
79 void mod_freesync_destroy(struct mod_freesync *mod_freesync)
80 {
81         struct core_freesync *core_freesync = NULL;
82         if (mod_freesync == NULL)
83                 return;
84         core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
85         kfree(core_freesync);
86 }
87
88 #if 0 /* Unused currently */
89 static unsigned int calc_refresh_in_uhz_from_duration(
90                 unsigned int duration_in_ns)
91 {
92         unsigned int refresh_in_uhz =
93                         ((unsigned int)(div64_u64((1000000000ULL * 1000000),
94                                         duration_in_ns)));
95         return refresh_in_uhz;
96 }
97 #endif
98
99 static unsigned int calc_duration_in_us_from_refresh_in_uhz(
100                 unsigned int refresh_in_uhz)
101 {
102         unsigned int duration_in_us =
103                         ((unsigned int)(div64_u64((1000000000ULL * 1000),
104                                         refresh_in_uhz)));
105         return duration_in_us;
106 }
107
108 static unsigned int calc_duration_in_us_from_v_total(
109                 const struct dc_stream_state *stream,
110                 const struct mod_vrr_params *in_vrr,
111                 unsigned int v_total)
112 {
113         unsigned int duration_in_us =
114                         (unsigned int)(div64_u64(((unsigned long long)(v_total)
115                                 * 10000) * stream->timing.h_total,
116                                         stream->timing.pix_clk_100hz));
117
118         return duration_in_us;
119 }
120
121 unsigned int mod_freesync_calc_v_total_from_refresh(
122                 const struct dc_stream_state *stream,
123                 unsigned int refresh_in_uhz)
124 {
125         unsigned int v_total;
126         unsigned int frame_duration_in_ns;
127
128         frame_duration_in_ns =
129                         ((unsigned int)(div64_u64((1000000000ULL * 1000000),
130                                         refresh_in_uhz)));
131
132         v_total = div64_u64(div64_u64(((unsigned long long)(
133                         frame_duration_in_ns) * (stream->timing.pix_clk_100hz / 10)),
134                         stream->timing.h_total), 1000000);
135
136         /* v_total cannot be less than nominal */
137         if (v_total < stream->timing.v_total) {
138                 ASSERT(v_total < stream->timing.v_total);
139                 v_total = stream->timing.v_total;
140         }
141
142         return v_total;
143 }
144
145 static unsigned int calc_v_total_from_duration(
146                 const struct dc_stream_state *stream,
147                 const struct mod_vrr_params *vrr,
148                 unsigned int duration_in_us)
149 {
150         unsigned int v_total = 0;
151
152         if (duration_in_us < vrr->min_duration_in_us)
153                 duration_in_us = vrr->min_duration_in_us;
154
155         if (duration_in_us > vrr->max_duration_in_us)
156                 duration_in_us = vrr->max_duration_in_us;
157
158         if (dc_is_hdmi_signal(stream->signal)) {
159                 uint32_t h_total_up_scaled;
160
161                 h_total_up_scaled = stream->timing.h_total * 10000;
162                 v_total = div_u64((unsigned long long)duration_in_us
163                                         * stream->timing.pix_clk_100hz + (h_total_up_scaled - 1),
164                                         h_total_up_scaled);
165         } else {
166                 v_total = div64_u64(div64_u64(((unsigned long long)(
167                                         duration_in_us) * (stream->timing.pix_clk_100hz / 10)),
168                                         stream->timing.h_total), 1000);
169         }
170
171         /* v_total cannot be less than nominal */
172         if (v_total < stream->timing.v_total) {
173                 ASSERT(v_total < stream->timing.v_total);
174                 v_total = stream->timing.v_total;
175         }
176
177         return v_total;
178 }
179
180 static void update_v_total_for_static_ramp(
181                 struct core_freesync *core_freesync,
182                 const struct dc_stream_state *stream,
183                 struct mod_vrr_params *in_out_vrr)
184 {
185         unsigned int v_total = 0;
186         unsigned int current_duration_in_us =
187                         calc_duration_in_us_from_v_total(
188                                 stream, in_out_vrr,
189                                 in_out_vrr->adjust.v_total_max);
190         unsigned int target_duration_in_us =
191                         calc_duration_in_us_from_refresh_in_uhz(
192                                 in_out_vrr->fixed.target_refresh_in_uhz);
193         bool ramp_direction_is_up = (current_duration_in_us >
194                                 target_duration_in_us) ? true : false;
195
196         /* Calculate ratio between new and current frame duration with 3 digit */
197         unsigned int frame_duration_ratio = div64_u64(1000000,
198                 (1000 +  div64_u64(((unsigned long long)(
199                 STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME) *
200                 current_duration_in_us),
201                 1000000)));
202
203         /* Calculate delta between new and current frame duration in us */
204         unsigned int frame_duration_delta = div64_u64(((unsigned long long)(
205                 current_duration_in_us) *
206                 (1000 - frame_duration_ratio)), 1000);
207
208         /* Adjust frame duration delta based on ratio between current and
209          * standard frame duration (frame duration at 60 Hz refresh rate).
210          */
211         unsigned int ramp_rate_interpolated = div64_u64(((unsigned long long)(
212                 frame_duration_delta) * current_duration_in_us), 16666);
213
214         /* Going to a higher refresh rate (lower frame duration) */
215         if (ramp_direction_is_up) {
216                 /* Reduce frame duration */
217                 current_duration_in_us -= ramp_rate_interpolated;
218
219                 /* Adjust for frame duration below min */
220                 if (current_duration_in_us <= target_duration_in_us) {
221                         in_out_vrr->fixed.ramping_active = false;
222                         in_out_vrr->fixed.ramping_done = true;
223                         current_duration_in_us =
224                                 calc_duration_in_us_from_refresh_in_uhz(
225                                 in_out_vrr->fixed.target_refresh_in_uhz);
226                 }
227         /* Going to a lower refresh rate (larger frame duration) */
228         } else {
229                 /* Increase frame duration */
230                 current_duration_in_us += ramp_rate_interpolated;
231
232                 /* Adjust for frame duration above max */
233                 if (current_duration_in_us >= target_duration_in_us) {
234                         in_out_vrr->fixed.ramping_active = false;
235                         in_out_vrr->fixed.ramping_done = true;
236                         current_duration_in_us =
237                                 calc_duration_in_us_from_refresh_in_uhz(
238                                 in_out_vrr->fixed.target_refresh_in_uhz);
239                 }
240         }
241
242         v_total = div64_u64(div64_u64(((unsigned long long)(
243                         current_duration_in_us) * (stream->timing.pix_clk_100hz / 10)),
244                                 stream->timing.h_total), 1000);
245
246         /* v_total cannot be less than nominal */
247         if (v_total < stream->timing.v_total)
248                 v_total = stream->timing.v_total;
249
250         in_out_vrr->adjust.v_total_min = v_total;
251         in_out_vrr->adjust.v_total_max = v_total;
252 }
253
254 static void apply_below_the_range(struct core_freesync *core_freesync,
255                 const struct dc_stream_state *stream,
256                 unsigned int last_render_time_in_us,
257                 struct mod_vrr_params *in_out_vrr)
258 {
259         unsigned int inserted_frame_duration_in_us = 0;
260         unsigned int mid_point_frames_ceil = 0;
261         unsigned int mid_point_frames_floor = 0;
262         unsigned int frame_time_in_us = 0;
263         unsigned int delta_from_mid_point_in_us_1 = 0xFFFFFFFF;
264         unsigned int delta_from_mid_point_in_us_2 = 0xFFFFFFFF;
265         unsigned int frames_to_insert = 0;
266         unsigned int delta_from_mid_point_delta_in_us;
267         unsigned int max_render_time_in_us =
268                         in_out_vrr->max_duration_in_us - in_out_vrr->btr.margin_in_us;
269
270         /* Program BTR */
271         if ((last_render_time_in_us + in_out_vrr->btr.margin_in_us / 2) < max_render_time_in_us) {
272                 /* Exit Below the Range */
273                 if (in_out_vrr->btr.btr_active) {
274                         in_out_vrr->btr.frame_counter = 0;
275                         in_out_vrr->btr.btr_active = false;
276                 }
277         } else if (last_render_time_in_us > (max_render_time_in_us + in_out_vrr->btr.margin_in_us / 2)) {
278                 /* Enter Below the Range */
279                 if (!in_out_vrr->btr.btr_active) {
280                         in_out_vrr->btr.btr_active = true;
281                 }
282         }
283
284         /* BTR set to "not active" so disengage */
285         if (!in_out_vrr->btr.btr_active) {
286                 in_out_vrr->btr.inserted_duration_in_us = 0;
287                 in_out_vrr->btr.frames_to_insert = 0;
288                 in_out_vrr->btr.frame_counter = 0;
289
290                 /* Restore FreeSync */
291                 in_out_vrr->adjust.v_total_min =
292                         mod_freesync_calc_v_total_from_refresh(stream,
293                                 in_out_vrr->max_refresh_in_uhz);
294                 in_out_vrr->adjust.v_total_max =
295                         mod_freesync_calc_v_total_from_refresh(stream,
296                                 in_out_vrr->min_refresh_in_uhz);
297         /* BTR set to "active" so engage */
298         } else {
299
300                 /* Calculate number of midPoint frames that could fit within
301                  * the render time interval - take ceil of this value
302                  */
303                 mid_point_frames_ceil = (last_render_time_in_us +
304                                 in_out_vrr->btr.mid_point_in_us - 1) /
305                                         in_out_vrr->btr.mid_point_in_us;
306
307                 if (mid_point_frames_ceil > 0) {
308                         frame_time_in_us = last_render_time_in_us /
309                                 mid_point_frames_ceil;
310                         delta_from_mid_point_in_us_1 =
311                                 (in_out_vrr->btr.mid_point_in_us >
312                                 frame_time_in_us) ?
313                                 (in_out_vrr->btr.mid_point_in_us - frame_time_in_us) :
314                                 (frame_time_in_us - in_out_vrr->btr.mid_point_in_us);
315                 }
316
317                 /* Calculate number of midPoint frames that could fit within
318                  * the render time interval - take floor of this value
319                  */
320                 mid_point_frames_floor = last_render_time_in_us /
321                                 in_out_vrr->btr.mid_point_in_us;
322
323                 if (mid_point_frames_floor > 0) {
324
325                         frame_time_in_us = last_render_time_in_us /
326                                 mid_point_frames_floor;
327                         delta_from_mid_point_in_us_2 =
328                                 (in_out_vrr->btr.mid_point_in_us >
329                                 frame_time_in_us) ?
330                                 (in_out_vrr->btr.mid_point_in_us - frame_time_in_us) :
331                                 (frame_time_in_us - in_out_vrr->btr.mid_point_in_us);
332                 }
333
334                 /* Choose number of frames to insert based on how close it
335                  * can get to the mid point of the variable range.
336                  *  - Delta for CEIL: delta_from_mid_point_in_us_1
337                  *  - Delta for FLOOR: delta_from_mid_point_in_us_2
338                  */
339                 if ((last_render_time_in_us / mid_point_frames_ceil) < in_out_vrr->min_duration_in_us) {
340                         /* Check for out of range.
341                          * If using CEIL produces a value that is out of range,
342                          * then we are forced to use FLOOR.
343                          */
344                         frames_to_insert = mid_point_frames_floor;
345                 } else if (mid_point_frames_floor < 2) {
346                         /* Check if FLOOR would result in non-LFC. In this case
347                          * choose to use CEIL
348                          */
349                         frames_to_insert = mid_point_frames_ceil;
350                 } else if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) {
351                         /* If choosing CEIL results in a frame duration that is
352                          * closer to the mid point of the range.
353                          * Choose CEIL
354                          */
355                         frames_to_insert = mid_point_frames_ceil;
356                 } else {
357                         /* If choosing FLOOR results in a frame duration that is
358                          * closer to the mid point of the range.
359                          * Choose FLOOR
360                          */
361                         frames_to_insert = mid_point_frames_floor;
362                 }
363
364                 /* Prefer current frame multiplier when BTR is enabled unless it drifts
365                  * too far from the midpoint
366                  */
367                 if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) {
368                         delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_2 -
369                                         delta_from_mid_point_in_us_1;
370                 } else {
371                         delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_1 -
372                                         delta_from_mid_point_in_us_2;
373                 }
374                 if (in_out_vrr->btr.frames_to_insert != 0 &&
375                                 delta_from_mid_point_delta_in_us < BTR_DRIFT_MARGIN) {
376                         if (((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) <
377                                         max_render_time_in_us) &&
378                                 ((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) >
379                                         in_out_vrr->min_duration_in_us))
380                                 frames_to_insert = in_out_vrr->btr.frames_to_insert;
381                 }
382
383                 /* Either we've calculated the number of frames to insert,
384                  * or we need to insert min duration frames
385                  */
386                 if (last_render_time_in_us / frames_to_insert <
387                                 in_out_vrr->min_duration_in_us){
388                         frames_to_insert -= (frames_to_insert > 1) ?
389                                         1 : 0;
390                 }
391
392                 if (frames_to_insert > 0)
393                         inserted_frame_duration_in_us = last_render_time_in_us /
394                                                         frames_to_insert;
395
396                 if (inserted_frame_duration_in_us < in_out_vrr->min_duration_in_us)
397                         inserted_frame_duration_in_us = in_out_vrr->min_duration_in_us;
398
399                 /* Cache the calculated variables */
400                 in_out_vrr->btr.inserted_duration_in_us =
401                         inserted_frame_duration_in_us;
402                 in_out_vrr->btr.frames_to_insert = frames_to_insert;
403                 in_out_vrr->btr.frame_counter = frames_to_insert;
404         }
405 }
406
407 static void apply_fixed_refresh(struct core_freesync *core_freesync,
408                 const struct dc_stream_state *stream,
409                 unsigned int last_render_time_in_us,
410                 struct mod_vrr_params *in_out_vrr)
411 {
412         bool update = false;
413         unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us;
414
415         /* Compute the exit refresh rate and exit frame duration */
416         unsigned int exit_refresh_rate_in_milli_hz = ((1000000000/max_render_time_in_us)
417                         + (1000*FIXED_REFRESH_EXIT_MARGIN_IN_HZ));
418         unsigned int exit_frame_duration_in_us = 1000000000/exit_refresh_rate_in_milli_hz;
419
420         if (last_render_time_in_us < exit_frame_duration_in_us) {
421                 /* Exit Fixed Refresh mode */
422                 if (in_out_vrr->fixed.fixed_active) {
423                         in_out_vrr->fixed.frame_counter++;
424
425                         if (in_out_vrr->fixed.frame_counter >
426                                         FIXED_REFRESH_EXIT_FRAME_COUNT) {
427                                 in_out_vrr->fixed.frame_counter = 0;
428                                 in_out_vrr->fixed.fixed_active = false;
429                                 in_out_vrr->fixed.target_refresh_in_uhz = 0;
430                                 update = true;
431                         }
432                 } else
433                         in_out_vrr->fixed.frame_counter = 0;
434         } else if (last_render_time_in_us > max_render_time_in_us) {
435                 /* Enter Fixed Refresh mode */
436                 if (!in_out_vrr->fixed.fixed_active) {
437                         in_out_vrr->fixed.frame_counter++;
438
439                         if (in_out_vrr->fixed.frame_counter >
440                                         FIXED_REFRESH_ENTER_FRAME_COUNT) {
441                                 in_out_vrr->fixed.frame_counter = 0;
442                                 in_out_vrr->fixed.fixed_active = true;
443                                 in_out_vrr->fixed.target_refresh_in_uhz =
444                                                 in_out_vrr->max_refresh_in_uhz;
445                                 update = true;
446                         }
447                 } else
448                         in_out_vrr->fixed.frame_counter = 0;
449         }
450
451         if (update) {
452                 if (in_out_vrr->fixed.fixed_active) {
453                         in_out_vrr->adjust.v_total_min =
454                                 mod_freesync_calc_v_total_from_refresh(
455                                 stream, in_out_vrr->max_refresh_in_uhz);
456                         in_out_vrr->adjust.v_total_max =
457                                         in_out_vrr->adjust.v_total_min;
458                 } else {
459                         in_out_vrr->adjust.v_total_min =
460                                 mod_freesync_calc_v_total_from_refresh(stream,
461                                         in_out_vrr->max_refresh_in_uhz);
462                         in_out_vrr->adjust.v_total_max =
463                                 mod_freesync_calc_v_total_from_refresh(stream,
464                                         in_out_vrr->min_refresh_in_uhz);
465                 }
466         }
467 }
468
469 static bool vrr_settings_require_update(struct core_freesync *core_freesync,
470                 struct mod_freesync_config *in_config,
471                 unsigned int min_refresh_in_uhz,
472                 unsigned int max_refresh_in_uhz,
473                 struct mod_vrr_params *in_vrr)
474 {
475         if (in_vrr->state != in_config->state) {
476                 return true;
477         } else if (in_vrr->state == VRR_STATE_ACTIVE_FIXED &&
478                         in_vrr->fixed.target_refresh_in_uhz !=
479                                         in_config->fixed_refresh_in_uhz) {
480                 return true;
481         } else if (in_vrr->min_refresh_in_uhz != min_refresh_in_uhz) {
482                 return true;
483         } else if (in_vrr->max_refresh_in_uhz != max_refresh_in_uhz) {
484                 return true;
485         }
486
487         return false;
488 }
489
490 bool mod_freesync_get_vmin_vmax(struct mod_freesync *mod_freesync,
491                 const struct dc_stream_state *stream,
492                 unsigned int *vmin,
493                 unsigned int *vmax)
494 {
495         *vmin = stream->adjust.v_total_min;
496         *vmax = stream->adjust.v_total_max;
497
498         return true;
499 }
500
501 bool mod_freesync_get_v_position(struct mod_freesync *mod_freesync,
502                 struct dc_stream_state *stream,
503                 unsigned int *nom_v_pos,
504                 unsigned int *v_pos)
505 {
506         struct core_freesync *core_freesync = NULL;
507         struct crtc_position position;
508
509         if (mod_freesync == NULL)
510                 return false;
511
512         core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
513
514         if (dc_stream_get_crtc_position(core_freesync->dc, &stream, 1,
515                                         &position.vertical_count,
516                                         &position.nominal_vcount)) {
517
518                 *nom_v_pos = position.nominal_vcount;
519                 *v_pos = position.vertical_count;
520
521                 return true;
522         }
523
524         return false;
525 }
526
527 static void build_vrr_infopacket_data_v1(const struct mod_vrr_params *vrr,
528                 struct dc_info_packet *infopacket,
529                 bool freesync_on_desktop)
530 {
531         /* PB1 = 0x1A (24bit AMD IEEE OUI (0x00001A) - Byte 0) */
532         infopacket->sb[1] = 0x1A;
533
534         /* PB2 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 1) */
535         infopacket->sb[2] = 0x00;
536
537         /* PB3 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 2) */
538         infopacket->sb[3] = 0x00;
539
540         /* PB4 = Reserved */
541
542         /* PB5 = Reserved */
543
544         /* PB6 = [Bits 7:3 = Reserved] */
545
546         /* PB6 = [Bit 0 = FreeSync Supported] */
547         if (vrr->state != VRR_STATE_UNSUPPORTED)
548                 infopacket->sb[6] |= 0x01;
549
550         /* PB6 = [Bit 1 = FreeSync Enabled] */
551         if (vrr->state != VRR_STATE_DISABLED &&
552                         vrr->state != VRR_STATE_UNSUPPORTED)
553                 infopacket->sb[6] |= 0x02;
554
555         if (freesync_on_desktop) {
556                 /* PB6 = [Bit 2 = FreeSync Active] */
557                 if (vrr->state != VRR_STATE_DISABLED &&
558                         vrr->state != VRR_STATE_UNSUPPORTED)
559                         infopacket->sb[6] |= 0x04;
560         } else {
561                 if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
562                         vrr->state == VRR_STATE_ACTIVE_FIXED)
563                         infopacket->sb[6] |= 0x04;
564         }
565
566         // For v1 & 2 infoframes program nominal if non-fs mode, otherwise full range
567         /* PB7 = FreeSync Minimum refresh rate (Hz) */
568         if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
569                         vrr->state == VRR_STATE_ACTIVE_FIXED) {
570                 infopacket->sb[7] = (unsigned char)((vrr->min_refresh_in_uhz + 500000) / 1000000);
571         } else {
572                 infopacket->sb[7] = (unsigned char)((vrr->max_refresh_in_uhz + 500000) / 1000000);
573         }
574
575         /* PB8 = FreeSync Maximum refresh rate (Hz)
576          * Note: We should never go above the field rate of the mode timing set.
577          */
578         infopacket->sb[8] = (unsigned char)((vrr->max_refresh_in_uhz + 500000) / 1000000);
579
580         /* FreeSync HDR */
581         infopacket->sb[9] = 0;
582         infopacket->sb[10] = 0;
583 }
584
585 static void build_vrr_infopacket_data_v3(const struct mod_vrr_params *vrr,
586                 struct dc_info_packet *infopacket)
587 {
588         unsigned int min_refresh;
589         unsigned int max_refresh;
590         unsigned int fixed_refresh;
591         unsigned int min_programmed;
592         unsigned int max_programmed;
593
594         /* PB1 = 0x1A (24bit AMD IEEE OUI (0x00001A) - Byte 0) */
595         infopacket->sb[1] = 0x1A;
596
597         /* PB2 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 1) */
598         infopacket->sb[2] = 0x00;
599
600         /* PB3 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 2) */
601         infopacket->sb[3] = 0x00;
602
603         /* PB4 = Reserved */
604
605         /* PB5 = Reserved */
606
607         /* PB6 = [Bits 7:3 = Reserved] */
608
609         /* PB6 = [Bit 0 = FreeSync Supported] */
610         if (vrr->state != VRR_STATE_UNSUPPORTED)
611                 infopacket->sb[6] |= 0x01;
612
613         /* PB6 = [Bit 1 = FreeSync Enabled] */
614         if (vrr->state != VRR_STATE_DISABLED &&
615                         vrr->state != VRR_STATE_UNSUPPORTED)
616                 infopacket->sb[6] |= 0x02;
617
618         /* PB6 = [Bit 2 = FreeSync Active] */
619         if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
620                         vrr->state == VRR_STATE_ACTIVE_FIXED)
621                 infopacket->sb[6] |= 0x04;
622
623         min_refresh = (vrr->min_refresh_in_uhz + 500000) / 1000000;
624         max_refresh = (vrr->max_refresh_in_uhz + 500000) / 1000000;
625         fixed_refresh = (vrr->fixed_refresh_in_uhz + 500000) / 1000000;
626
627         min_programmed = (vrr->state == VRR_STATE_ACTIVE_FIXED) ? fixed_refresh :
628                         (vrr->state == VRR_STATE_ACTIVE_VARIABLE) ? min_refresh :
629                         (vrr->state == VRR_STATE_INACTIVE) ? min_refresh :
630                         max_refresh; // Non-fs case, program nominal range
631
632         max_programmed = (vrr->state == VRR_STATE_ACTIVE_FIXED) ? fixed_refresh :
633                         (vrr->state == VRR_STATE_ACTIVE_VARIABLE) ? max_refresh :
634                         max_refresh;// Non-fs case, program nominal range
635
636         /* PB7 = FreeSync Minimum refresh rate (Hz) */
637         infopacket->sb[7] = min_programmed & 0xFF;
638
639         /* PB8 = FreeSync Maximum refresh rate (Hz) */
640         infopacket->sb[8] = max_programmed & 0xFF;
641
642         /* PB11 : MSB FreeSync Minimum refresh rate [Hz] - bits 9:8 */
643         infopacket->sb[11] = (min_programmed >> 8) & 0x03;
644
645         /* PB12 : MSB FreeSync Maximum refresh rate [Hz] - bits 9:8 */
646         infopacket->sb[12] = (max_programmed >> 8) & 0x03;
647
648         /* PB16 : Reserved bits 7:1, FixedRate bit 0 */
649         infopacket->sb[16] = (vrr->state == VRR_STATE_ACTIVE_FIXED) ? 1 : 0;
650
651         //FreeSync HDR
652         infopacket->sb[9] = 0;
653         infopacket->sb[10] = 0;
654 }
655
656 static void build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf,
657                 struct dc_info_packet *infopacket)
658 {
659         if (app_tf != TRANSFER_FUNC_UNKNOWN) {
660                 infopacket->valid = true;
661
662                 infopacket->sb[6] |= 0x08;  // PB6 = [Bit 3 = Native Color Active]
663
664                 if (app_tf == TRANSFER_FUNC_GAMMA_22) {
665                         infopacket->sb[9] |= 0x04;  // PB6 = [Bit 2 = Gamma 2.2 EOTF Active]
666                 }
667         }
668 }
669
670 static void build_vrr_infopacket_header_v1(enum signal_type signal,
671                 struct dc_info_packet *infopacket,
672                 unsigned int *payload_size)
673 {
674         if (dc_is_hdmi_signal(signal)) {
675
676                 /* HEADER */
677
678                 /* HB0  = Packet Type = 0x83 (Source Product
679                  *        Descriptor InfoFrame)
680                  */
681                 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
682
683                 /* HB1  = Version = 0x01 */
684                 infopacket->hb1 = 0x01;
685
686                 /* HB2  = [Bits 7:5 = 0] [Bits 4:0 = Length = 0x08] */
687                 infopacket->hb2 = 0x08;
688
689                 *payload_size = 0x08;
690
691         } else if (dc_is_dp_signal(signal)) {
692
693                 /* HEADER */
694
695                 /* HB0  = Secondary-data Packet ID = 0 - Only non-zero
696                  *        when used to associate audio related info packets
697                  */
698                 infopacket->hb0 = 0x00;
699
700                 /* HB1  = Packet Type = 0x83 (Source Product
701                  *        Descriptor InfoFrame)
702                  */
703                 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
704
705                 /* HB2  = [Bits 7:0 = Least significant eight bits -
706                  *        For INFOFRAME, the value must be 1Bh]
707                  */
708                 infopacket->hb2 = 0x1B;
709
710                 /* HB3  = [Bits 7:2 = INFOFRAME SDP Version Number = 0x1]
711                  *        [Bits 1:0 = Most significant two bits = 0x00]
712                  */
713                 infopacket->hb3 = 0x04;
714
715                 *payload_size = 0x1B;
716         }
717 }
718
719 static void build_vrr_infopacket_header_v2(enum signal_type signal,
720                 struct dc_info_packet *infopacket,
721                 unsigned int *payload_size)
722 {
723         if (dc_is_hdmi_signal(signal)) {
724
725                 /* HEADER */
726
727                 /* HB0  = Packet Type = 0x83 (Source Product
728                  *        Descriptor InfoFrame)
729                  */
730                 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
731
732                 /* HB1  = Version = 0x02 */
733                 infopacket->hb1 = 0x02;
734
735                 /* HB2  = [Bits 7:5 = 0] [Bits 4:0 = Length = 0x09] */
736                 infopacket->hb2 = 0x09;
737
738                 *payload_size = 0x0A;
739
740         } else if (dc_is_dp_signal(signal)) {
741
742                 /* HEADER */
743
744                 /* HB0  = Secondary-data Packet ID = 0 - Only non-zero
745                  *        when used to associate audio related info packets
746                  */
747                 infopacket->hb0 = 0x00;
748
749                 /* HB1  = Packet Type = 0x83 (Source Product
750                  *        Descriptor InfoFrame)
751                  */
752                 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
753
754                 /* HB2  = [Bits 7:0 = Least significant eight bits -
755                  *        For INFOFRAME, the value must be 1Bh]
756                  */
757                 infopacket->hb2 = 0x1B;
758
759                 /* HB3  = [Bits 7:2 = INFOFRAME SDP Version Number = 0x2]
760                  *        [Bits 1:0 = Most significant two bits = 0x00]
761                  */
762                 infopacket->hb3 = 0x08;
763
764                 *payload_size = 0x1B;
765         }
766 }
767
768 static void build_vrr_infopacket_header_v3(enum signal_type signal,
769                 struct dc_info_packet *infopacket,
770                 unsigned int *payload_size)
771 {
772         unsigned char version;
773
774         version = 3;
775         if (dc_is_hdmi_signal(signal)) {
776
777                 /* HEADER */
778
779                 /* HB0  = Packet Type = 0x83 (Source Product
780                  *        Descriptor InfoFrame)
781                  */
782                 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
783
784                 /* HB1  = Version = 0x03 */
785                 infopacket->hb1 = version;
786
787                 /* HB2  = [Bits 7:5 = 0] [Bits 4:0 = Length] */
788                 *payload_size = 0x10;
789                 infopacket->hb2 = *payload_size - 1; //-1 for checksum
790
791         } else if (dc_is_dp_signal(signal)) {
792
793                 /* HEADER */
794
795                 /* HB0  = Secondary-data Packet ID = 0 - Only non-zero
796                  *        when used to associate audio related info packets
797                  */
798                 infopacket->hb0 = 0x00;
799
800                 /* HB1  = Packet Type = 0x83 (Source Product
801                  *        Descriptor InfoFrame)
802                  */
803                 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
804
805                 /* HB2  = [Bits 7:0 = Least significant eight bits -
806                  *        For INFOFRAME, the value must be 1Bh]
807                  */
808                 infopacket->hb2 = 0x1B;
809
810                 /* HB3  = [Bits 7:2 = INFOFRAME SDP Version Number = 0x2]
811                  *        [Bits 1:0 = Most significant two bits = 0x00]
812                  */
813
814                 infopacket->hb3 = (version & 0x3F) << 2;
815
816                 *payload_size = 0x1B;
817         }
818 }
819
820 static void build_vrr_infopacket_checksum(unsigned int *payload_size,
821                 struct dc_info_packet *infopacket)
822 {
823         /* Calculate checksum */
824         unsigned int idx = 0;
825         unsigned char checksum = 0;
826
827         checksum += infopacket->hb0;
828         checksum += infopacket->hb1;
829         checksum += infopacket->hb2;
830         checksum += infopacket->hb3;
831
832         for (idx = 1; idx <= *payload_size; idx++)
833                 checksum += infopacket->sb[idx];
834
835         /* PB0 = Checksum (one byte complement) */
836         infopacket->sb[0] = (unsigned char)(0x100 - checksum);
837
838         infopacket->valid = true;
839 }
840
841 static void build_vrr_infopacket_v1(enum signal_type signal,
842                 const struct mod_vrr_params *vrr,
843                 struct dc_info_packet *infopacket,
844                 bool freesync_on_desktop)
845 {
846         /* SPD info packet for FreeSync */
847         unsigned int payload_size = 0;
848
849         build_vrr_infopacket_header_v1(signal, infopacket, &payload_size);
850         build_vrr_infopacket_data_v1(vrr, infopacket, freesync_on_desktop);
851         build_vrr_infopacket_checksum(&payload_size, infopacket);
852
853         infopacket->valid = true;
854 }
855
856 static void build_vrr_infopacket_v2(enum signal_type signal,
857                 const struct mod_vrr_params *vrr,
858                 enum color_transfer_func app_tf,
859                 struct dc_info_packet *infopacket,
860                 bool freesync_on_desktop)
861 {
862         unsigned int payload_size = 0;
863
864         build_vrr_infopacket_header_v2(signal, infopacket, &payload_size);
865         build_vrr_infopacket_data_v1(vrr, infopacket, freesync_on_desktop);
866
867         build_vrr_infopacket_fs2_data(app_tf, infopacket);
868
869         build_vrr_infopacket_checksum(&payload_size, infopacket);
870
871         infopacket->valid = true;
872 }
873 #ifndef TRIM_FSFT
874 static void build_vrr_infopacket_fast_transport_data(
875         bool ftActive,
876         unsigned int ftOutputRate,
877         struct dc_info_packet *infopacket)
878 {
879         /* PB9 : bit7 - fast transport Active*/
880         unsigned char activeBit = (ftActive) ? 1 << 7 : 0;
881
882         infopacket->sb[1] &= ~activeBit;  //clear bit
883         infopacket->sb[1] |=  activeBit;  //set bit
884
885         /* PB13 : Target Output Pixel Rate [kHz] - bits 7:0  */
886         infopacket->sb[13] = ftOutputRate & 0xFF;
887
888         /* PB14 : Target Output Pixel Rate [kHz] - bits 15:8  */
889         infopacket->sb[14] = (ftOutputRate >> 8) & 0xFF;
890
891         /* PB15 : Target Output Pixel Rate [kHz] - bits 23:16  */
892         infopacket->sb[15] = (ftOutputRate >> 16) & 0xFF;
893
894 }
895 #endif
896
897 static void build_vrr_infopacket_v3(enum signal_type signal,
898                 const struct mod_vrr_params *vrr,
899 #ifndef TRIM_FSFT
900                 bool ftActive, unsigned int ftOutputRate,
901 #endif
902                 enum color_transfer_func app_tf,
903                 struct dc_info_packet *infopacket)
904 {
905         unsigned int payload_size = 0;
906
907         build_vrr_infopacket_header_v3(signal, infopacket, &payload_size);
908         build_vrr_infopacket_data_v3(vrr, infopacket);
909
910         build_vrr_infopacket_fs2_data(app_tf, infopacket);
911
912 #ifndef TRIM_FSFT
913         build_vrr_infopacket_fast_transport_data(
914                         ftActive,
915                         ftOutputRate,
916                         infopacket);
917 #endif
918
919         build_vrr_infopacket_checksum(&payload_size, infopacket);
920
921         infopacket->valid = true;
922 }
923
924 static void build_vrr_infopacket_sdp_v1_3(enum vrr_packet_type packet_type,
925                                                                                 struct dc_info_packet *infopacket)
926 {
927         uint8_t idx = 0, size = 0;
928
929         size = ((packet_type == PACKET_TYPE_FS_V1) ? 0x08 :
930                         (packet_type == PACKET_TYPE_FS_V3) ? 0x10 :
931                                                                                                 0x09);
932
933         for (idx = infopacket->hb2; idx > 1; idx--) // Data Byte Count: 0x1B
934                 infopacket->sb[idx] = infopacket->sb[idx-1];
935
936         infopacket->sb[1] = size;                         // Length
937         infopacket->sb[0] = (infopacket->hb3 >> 2) & 0x3F;//Version
938         infopacket->hb3   = (0x13 << 2);                  // Header,SDP 1.3
939         infopacket->hb2   = 0x1D;
940 }
941
942 void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync,
943                 const struct dc_stream_state *stream,
944                 const struct mod_vrr_params *vrr,
945                 enum vrr_packet_type packet_type,
946                 enum color_transfer_func app_tf,
947                 struct dc_info_packet *infopacket,
948                 bool pack_sdp_v1_3)
949 {
950         /* SPD info packet for FreeSync
951          * VTEM info packet for HdmiVRR
952          * Check if Freesync is supported. Return if false. If true,
953          * set the corresponding bit in the info packet
954          */
955         if (!vrr->send_info_frame)
956                 return;
957
958         switch (packet_type) {
959         case PACKET_TYPE_FS_V3:
960 #ifndef TRIM_FSFT
961                 // always populate with pixel rate.
962                 build_vrr_infopacket_v3(
963                                 stream->signal, vrr,
964                                 stream->timing.flags.FAST_TRANSPORT,
965                                 (stream->timing.flags.FAST_TRANSPORT) ?
966                                                 stream->timing.fast_transport_output_rate_100hz :
967                                                 stream->timing.pix_clk_100hz,
968                                 app_tf, infopacket);
969 #else
970                 build_vrr_infopacket_v3(stream->signal, vrr, app_tf, infopacket);
971 #endif
972                 break;
973         case PACKET_TYPE_FS_V2:
974                 build_vrr_infopacket_v2(stream->signal, vrr, app_tf, infopacket, stream->freesync_on_desktop);
975                 break;
976         case PACKET_TYPE_VRR:
977         case PACKET_TYPE_FS_V1:
978         default:
979                 build_vrr_infopacket_v1(stream->signal, vrr, infopacket, stream->freesync_on_desktop);
980         }
981
982         if (true == pack_sdp_v1_3 &&
983                 true == dc_is_dp_signal(stream->signal) &&
984                 packet_type != PACKET_TYPE_VRR &&
985                 packet_type != PACKET_TYPE_VTEM)
986                 build_vrr_infopacket_sdp_v1_3(packet_type, infopacket);
987 }
988
989 void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync,
990                 const struct dc_stream_state *stream,
991                 struct mod_freesync_config *in_config,
992                 struct mod_vrr_params *in_out_vrr)
993 {
994         struct core_freesync *core_freesync = NULL;
995         unsigned long long nominal_field_rate_in_uhz = 0;
996         unsigned long long rounded_nominal_in_uhz = 0;
997         unsigned int refresh_range = 0;
998         unsigned long long min_refresh_in_uhz = 0;
999         unsigned long long max_refresh_in_uhz = 0;
1000
1001         if (mod_freesync == NULL)
1002                 return;
1003
1004         core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1005
1006         /* Calculate nominal field rate for stream */
1007         nominal_field_rate_in_uhz =
1008                         mod_freesync_calc_nominal_field_rate(stream);
1009
1010         min_refresh_in_uhz = in_config->min_refresh_in_uhz;
1011         max_refresh_in_uhz = in_config->max_refresh_in_uhz;
1012
1013         /* Full range may be larger than current video timing, so cap at nominal */
1014         if (max_refresh_in_uhz > nominal_field_rate_in_uhz)
1015                 max_refresh_in_uhz = nominal_field_rate_in_uhz;
1016
1017         /* Full range may be larger than current video timing, so cap at nominal */
1018         if (min_refresh_in_uhz > max_refresh_in_uhz)
1019                 min_refresh_in_uhz = max_refresh_in_uhz;
1020
1021         /* If a monitor reports exactly max refresh of 2x of min, enforce it on nominal */
1022         rounded_nominal_in_uhz =
1023                         div_u64(nominal_field_rate_in_uhz + 50000, 100000) * 100000;
1024         if (in_config->max_refresh_in_uhz == (2 * in_config->min_refresh_in_uhz) &&
1025                 in_config->max_refresh_in_uhz == rounded_nominal_in_uhz)
1026                 min_refresh_in_uhz = div_u64(nominal_field_rate_in_uhz, 2);
1027
1028         if (!vrr_settings_require_update(core_freesync,
1029                         in_config, (unsigned int)min_refresh_in_uhz, (unsigned int)max_refresh_in_uhz,
1030                         in_out_vrr))
1031                 return;
1032
1033         in_out_vrr->state = in_config->state;
1034         in_out_vrr->send_info_frame = in_config->vsif_supported;
1035
1036         if (in_config->state == VRR_STATE_UNSUPPORTED) {
1037                 in_out_vrr->state = VRR_STATE_UNSUPPORTED;
1038                 in_out_vrr->supported = false;
1039                 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1040                 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1041
1042                 return;
1043
1044         } else {
1045                 in_out_vrr->min_refresh_in_uhz = (unsigned int)min_refresh_in_uhz;
1046                 in_out_vrr->max_duration_in_us =
1047                                 calc_duration_in_us_from_refresh_in_uhz(
1048                                                 (unsigned int)min_refresh_in_uhz);
1049
1050                 in_out_vrr->max_refresh_in_uhz = (unsigned int)max_refresh_in_uhz;
1051                 in_out_vrr->min_duration_in_us =
1052                                 calc_duration_in_us_from_refresh_in_uhz(
1053                                                 (unsigned int)max_refresh_in_uhz);
1054
1055                 if (in_config->state == VRR_STATE_ACTIVE_FIXED)
1056                         in_out_vrr->fixed_refresh_in_uhz = in_config->fixed_refresh_in_uhz;
1057                 else
1058                         in_out_vrr->fixed_refresh_in_uhz = 0;
1059
1060                 refresh_range = div_u64(in_out_vrr->max_refresh_in_uhz + 500000, 1000000) -
1061 +                               div_u64(in_out_vrr->min_refresh_in_uhz + 500000, 1000000);
1062
1063                 in_out_vrr->supported = true;
1064         }
1065
1066         in_out_vrr->fixed.ramping_active = in_config->ramping;
1067
1068         in_out_vrr->btr.btr_enabled = in_config->btr;
1069
1070         if (in_out_vrr->max_refresh_in_uhz < (2 * in_out_vrr->min_refresh_in_uhz))
1071                 in_out_vrr->btr.btr_enabled = false;
1072         else {
1073                 in_out_vrr->btr.margin_in_us = in_out_vrr->max_duration_in_us -
1074                                 2 * in_out_vrr->min_duration_in_us;
1075                 if (in_out_vrr->btr.margin_in_us > BTR_MAX_MARGIN)
1076                         in_out_vrr->btr.margin_in_us = BTR_MAX_MARGIN;
1077         }
1078
1079         in_out_vrr->btr.btr_active = false;
1080         in_out_vrr->btr.inserted_duration_in_us = 0;
1081         in_out_vrr->btr.frames_to_insert = 0;
1082         in_out_vrr->btr.frame_counter = 0;
1083         in_out_vrr->fixed.fixed_active = false;
1084         in_out_vrr->fixed.target_refresh_in_uhz = 0;
1085
1086         in_out_vrr->btr.mid_point_in_us =
1087                                 (in_out_vrr->min_duration_in_us +
1088                                  in_out_vrr->max_duration_in_us) / 2;
1089
1090         if (in_out_vrr->state == VRR_STATE_UNSUPPORTED) {
1091                 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1092                 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1093         } else if (in_out_vrr->state == VRR_STATE_DISABLED) {
1094                 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1095                 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1096         } else if (in_out_vrr->state == VRR_STATE_INACTIVE) {
1097                 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1098                 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1099         } else if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE &&
1100                         refresh_range >= MIN_REFRESH_RANGE) {
1101
1102                 in_out_vrr->adjust.v_total_min =
1103                         mod_freesync_calc_v_total_from_refresh(stream,
1104                                 in_out_vrr->max_refresh_in_uhz);
1105                 in_out_vrr->adjust.v_total_max =
1106                         mod_freesync_calc_v_total_from_refresh(stream,
1107                                 in_out_vrr->min_refresh_in_uhz);
1108         } else if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED) {
1109                 in_out_vrr->fixed.target_refresh_in_uhz =
1110                                 in_out_vrr->fixed_refresh_in_uhz;
1111                 if (in_out_vrr->fixed.ramping_active &&
1112                                 in_out_vrr->fixed.fixed_active) {
1113                         /* Do not update vtotals if ramping is already active
1114                          * in order to continue ramp from current refresh.
1115                          */
1116                         in_out_vrr->fixed.fixed_active = true;
1117                 } else {
1118                         in_out_vrr->fixed.fixed_active = true;
1119                         in_out_vrr->adjust.v_total_min =
1120                                 mod_freesync_calc_v_total_from_refresh(stream,
1121                                         in_out_vrr->fixed.target_refresh_in_uhz);
1122                         in_out_vrr->adjust.v_total_max =
1123                                 in_out_vrr->adjust.v_total_min;
1124                 }
1125         } else {
1126                 in_out_vrr->state = VRR_STATE_INACTIVE;
1127                 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1128                 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1129         }
1130 }
1131
1132 void mod_freesync_handle_preflip(struct mod_freesync *mod_freesync,
1133                 const struct dc_plane_state *plane,
1134                 const struct dc_stream_state *stream,
1135                 unsigned int curr_time_stamp_in_us,
1136                 struct mod_vrr_params *in_out_vrr)
1137 {
1138         struct core_freesync *core_freesync = NULL;
1139         unsigned int last_render_time_in_us = 0;
1140         unsigned int average_render_time_in_us = 0;
1141
1142         if (mod_freesync == NULL)
1143                 return;
1144
1145         core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1146
1147         if (in_out_vrr->supported &&
1148                         in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE) {
1149                 unsigned int i = 0;
1150                 unsigned int oldest_index = plane->time.index + 1;
1151
1152                 if (oldest_index >= DC_PLANE_UPDATE_TIMES_MAX)
1153                         oldest_index = 0;
1154
1155                 last_render_time_in_us = curr_time_stamp_in_us -
1156                                 plane->time.prev_update_time_in_us;
1157
1158                 /* Sum off all entries except oldest one */
1159                 for (i = 0; i < DC_PLANE_UPDATE_TIMES_MAX; i++) {
1160                         average_render_time_in_us +=
1161                                         plane->time.time_elapsed_in_us[i];
1162                 }
1163                 average_render_time_in_us -=
1164                                 plane->time.time_elapsed_in_us[oldest_index];
1165
1166                 /* Add render time for current flip */
1167                 average_render_time_in_us += last_render_time_in_us;
1168                 average_render_time_in_us /= DC_PLANE_UPDATE_TIMES_MAX;
1169
1170                 if (in_out_vrr->btr.btr_enabled) {
1171                         apply_below_the_range(core_freesync,
1172                                         stream,
1173                                         last_render_time_in_us,
1174                                         in_out_vrr);
1175                 } else {
1176                         apply_fixed_refresh(core_freesync,
1177                                 stream,
1178                                 last_render_time_in_us,
1179                                 in_out_vrr);
1180                 }
1181
1182         }
1183 }
1184
1185 void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync,
1186                 const struct dc_stream_state *stream,
1187                 struct mod_vrr_params *in_out_vrr)
1188 {
1189         struct core_freesync *core_freesync = NULL;
1190
1191         if ((mod_freesync == NULL) || (stream == NULL) || (in_out_vrr == NULL))
1192                 return;
1193
1194         core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1195
1196         if (in_out_vrr->supported == false)
1197                 return;
1198
1199         /* Below the Range Logic */
1200
1201         /* Only execute if in fullscreen mode */
1202         if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE &&
1203                                         in_out_vrr->btr.btr_active) {
1204                 /* TODO: pass in flag for Pre-DCE12 ASIC
1205                  * in order for frame variable duration to take affect,
1206                  * it needs to be done one VSYNC early, which is at
1207                  * frameCounter == 1.
1208                  * For DCE12 and newer updates to V_TOTAL_MIN/MAX
1209                  * will take affect on current frame
1210                  */
1211                 if (in_out_vrr->btr.frames_to_insert ==
1212                                 in_out_vrr->btr.frame_counter) {
1213                         in_out_vrr->adjust.v_total_min =
1214                                 calc_v_total_from_duration(stream,
1215                                 in_out_vrr,
1216                                 in_out_vrr->btr.inserted_duration_in_us);
1217                         in_out_vrr->adjust.v_total_max =
1218                                 in_out_vrr->adjust.v_total_min;
1219                 }
1220
1221                 if (in_out_vrr->btr.frame_counter > 0)
1222                         in_out_vrr->btr.frame_counter--;
1223
1224                 /* Restore FreeSync */
1225                 if (in_out_vrr->btr.frame_counter == 0) {
1226                         in_out_vrr->adjust.v_total_min =
1227                                 mod_freesync_calc_v_total_from_refresh(stream,
1228                                 in_out_vrr->max_refresh_in_uhz);
1229                         in_out_vrr->adjust.v_total_max =
1230                                 mod_freesync_calc_v_total_from_refresh(stream,
1231                                 in_out_vrr->min_refresh_in_uhz);
1232                 }
1233         }
1234
1235         /* If in fullscreen freesync mode or in video, do not program
1236          * static screen ramp values
1237          */
1238         if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE)
1239                 in_out_vrr->fixed.ramping_active = false;
1240
1241         /* Gradual Static Screen Ramping Logic
1242          * Execute if ramp is active and user enabled freesync static screen
1243          */
1244         if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED &&
1245                                 in_out_vrr->fixed.ramping_active) {
1246                 update_v_total_for_static_ramp(
1247                                 core_freesync, stream, in_out_vrr);
1248         }
1249 }
1250
1251 void mod_freesync_get_settings(struct mod_freesync *mod_freesync,
1252                 const struct mod_vrr_params *vrr,
1253                 unsigned int *v_total_min, unsigned int *v_total_max,
1254                 unsigned int *event_triggers,
1255                 unsigned int *window_min, unsigned int *window_max,
1256                 unsigned int *lfc_mid_point_in_us,
1257                 unsigned int *inserted_frames,
1258                 unsigned int *inserted_duration_in_us)
1259 {
1260         if (mod_freesync == NULL)
1261                 return;
1262
1263         if (vrr->supported) {
1264                 *v_total_min = vrr->adjust.v_total_min;
1265                 *v_total_max = vrr->adjust.v_total_max;
1266                 *event_triggers = 0;
1267                 *lfc_mid_point_in_us = vrr->btr.mid_point_in_us;
1268                 *inserted_frames = vrr->btr.frames_to_insert;
1269                 *inserted_duration_in_us = vrr->btr.inserted_duration_in_us;
1270         }
1271 }
1272
1273 unsigned long long mod_freesync_calc_nominal_field_rate(
1274                         const struct dc_stream_state *stream)
1275 {
1276         unsigned long long nominal_field_rate_in_uhz = 0;
1277         unsigned int total = stream->timing.h_total * stream->timing.v_total;
1278
1279         /* Calculate nominal field rate for stream, rounded up to nearest integer */
1280         nominal_field_rate_in_uhz = stream->timing.pix_clk_100hz;
1281         nominal_field_rate_in_uhz *= 100000000ULL;
1282
1283         nominal_field_rate_in_uhz =     div_u64(nominal_field_rate_in_uhz, total);
1284
1285         return nominal_field_rate_in_uhz;
1286 }
1287
1288 unsigned long long mod_freesync_calc_field_rate_from_timing(
1289                 unsigned int vtotal, unsigned int htotal, unsigned int pix_clk)
1290 {
1291         unsigned long long field_rate_in_uhz = 0;
1292         unsigned int total = htotal * vtotal;
1293
1294         /* Calculate nominal field rate for stream, rounded up to nearest integer */
1295         field_rate_in_uhz = pix_clk;
1296         field_rate_in_uhz *= 1000000ULL;
1297
1298         field_rate_in_uhz =     div_u64(field_rate_in_uhz, total);
1299
1300         return field_rate_in_uhz;
1301 }
1302
1303 bool mod_freesync_is_valid_range(uint32_t min_refresh_cap_in_uhz,
1304                 uint32_t max_refresh_cap_in_uhz,
1305                 uint32_t nominal_field_rate_in_uhz) 
1306 {
1307
1308         /* Typically nominal refresh calculated can have some fractional part.
1309          * Allow for some rounding error of actual video timing by taking floor
1310          * of caps and request. Round the nominal refresh rate.
1311          *
1312          * Dividing will convert everything to units in Hz although input
1313          * variable name is in uHz!
1314          *
1315          * Also note, this takes care of rounding error on the nominal refresh
1316          * so by rounding error we only expect it to be off by a small amount,
1317          * such as < 0.1 Hz. i.e. 143.9xxx or 144.1xxx.
1318          *
1319          * Example 1. Caps    Min = 40 Hz, Max = 144 Hz
1320          *            Request Min = 40 Hz, Max = 144 Hz
1321          *                    Nominal = 143.5x Hz rounded to 144 Hz
1322          *            This function should allow this as valid request
1323          *
1324          * Example 2. Caps    Min = 40 Hz, Max = 144 Hz
1325          *            Request Min = 40 Hz, Max = 144 Hz
1326          *                    Nominal = 144.4x Hz rounded to 144 Hz
1327          *            This function should allow this as valid request
1328          *
1329          * Example 3. Caps    Min = 40 Hz, Max = 144 Hz
1330          *            Request Min = 40 Hz, Max = 144 Hz
1331          *                    Nominal = 120.xx Hz rounded to 120 Hz
1332          *            This function should return NOT valid since the requested
1333          *            max is greater than current timing's nominal
1334          *
1335          * Example 4. Caps    Min = 40 Hz, Max = 120 Hz
1336          *            Request Min = 40 Hz, Max = 120 Hz
1337          *                    Nominal = 144.xx Hz rounded to 144 Hz
1338          *            This function should return NOT valid since the nominal
1339          *            is greater than the capability's max refresh
1340          */
1341         nominal_field_rate_in_uhz =
1342                         div_u64(nominal_field_rate_in_uhz + 500000, 1000000);
1343         min_refresh_cap_in_uhz /= 1000000;
1344         max_refresh_cap_in_uhz /= 1000000;
1345
1346         /* Check nominal is within range */
1347         if (nominal_field_rate_in_uhz > max_refresh_cap_in_uhz ||
1348                 nominal_field_rate_in_uhz < min_refresh_cap_in_uhz)
1349                 return false;
1350
1351         /* If nominal is less than max, limit the max allowed refresh rate */
1352         if (nominal_field_rate_in_uhz < max_refresh_cap_in_uhz)
1353                 max_refresh_cap_in_uhz = nominal_field_rate_in_uhz;
1354
1355         /* Check min is within range */
1356         if (min_refresh_cap_in_uhz > max_refresh_cap_in_uhz)
1357                 return false;
1358
1359         /* For variable range, check for at least 10 Hz range */
1360         if (nominal_field_rate_in_uhz - min_refresh_cap_in_uhz < 10)
1361                 return false;
1362
1363         return true;
1364 }
This page took 0.125248 seconds and 4 git commands to generate.