1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
37#define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65)
38
39#define RENDER_TIMES_MAX_COUNT 10
40
41#define BTR_MAX_MARGIN 2500
42
43#define BTR_DRIFT_MARGIN 2000
44
45#define FIXED_REFRESH_EXIT_MARGIN_IN_HZ 1
46
47#define FIXED_REFRESH_ENTER_FRAME_COUNT 5
48#define FIXED_REFRESH_EXIT_FRAME_COUNT 10
49
50struct 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
58struct 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
72fail_construct:
73 kfree(core_freesync);
74
75fail_alloc_context:
76 return NULL;
77}
78
79void 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
89static 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
99static 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
108static 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
121unsigned 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
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
145static 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 v_total = div64_u64(div64_u64(((unsigned long long)(
159 duration_in_us) * (stream->timing.pix_clk_100hz / 10)),
160 stream->timing.h_total), 1000);
161
162
163 if (v_total < stream->timing.v_total) {
164 ASSERT(v_total < stream->timing.v_total);
165 v_total = stream->timing.v_total;
166 }
167
168 return v_total;
169}
170
171static void update_v_total_for_static_ramp(
172 struct core_freesync *core_freesync,
173 const struct dc_stream_state *stream,
174 struct mod_vrr_params *in_out_vrr)
175{
176 unsigned int v_total = 0;
177 unsigned int current_duration_in_us =
178 calc_duration_in_us_from_v_total(
179 stream, in_out_vrr,
180 in_out_vrr->adjust.v_total_max);
181 unsigned int target_duration_in_us =
182 calc_duration_in_us_from_refresh_in_uhz(
183 in_out_vrr->fixed.target_refresh_in_uhz);
184 bool ramp_direction_is_up = (current_duration_in_us >
185 target_duration_in_us) ? true : false;
186
187
188 unsigned int frame_duration_ratio = div64_u64(1000000,
189 (1000 + div64_u64(((unsigned long long)(
190 STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME) *
191 current_duration_in_us),
192 1000000)));
193
194
195 unsigned int frame_duration_delta = div64_u64(((unsigned long long)(
196 current_duration_in_us) *
197 (1000 - frame_duration_ratio)), 1000);
198
199
200
201
202 unsigned int ramp_rate_interpolated = div64_u64(((unsigned long long)(
203 frame_duration_delta) * current_duration_in_us), 16666);
204
205
206 if (ramp_direction_is_up) {
207
208 current_duration_in_us -= ramp_rate_interpolated;
209
210
211 if (current_duration_in_us <= target_duration_in_us) {
212 in_out_vrr->fixed.ramping_active = false;
213 in_out_vrr->fixed.ramping_done = true;
214 current_duration_in_us =
215 calc_duration_in_us_from_refresh_in_uhz(
216 in_out_vrr->fixed.target_refresh_in_uhz);
217 }
218
219 } else {
220
221 current_duration_in_us += ramp_rate_interpolated;
222
223
224 if (current_duration_in_us >= target_duration_in_us) {
225 in_out_vrr->fixed.ramping_active = false;
226 in_out_vrr->fixed.ramping_done = true;
227 current_duration_in_us =
228 calc_duration_in_us_from_refresh_in_uhz(
229 in_out_vrr->fixed.target_refresh_in_uhz);
230 }
231 }
232
233 v_total = div64_u64(div64_u64(((unsigned long long)(
234 current_duration_in_us) * (stream->timing.pix_clk_100hz / 10)),
235 stream->timing.h_total), 1000);
236
237
238 if (v_total < stream->timing.v_total)
239 v_total = stream->timing.v_total;
240
241 in_out_vrr->adjust.v_total_min = v_total;
242 in_out_vrr->adjust.v_total_max = v_total;
243}
244
245static void apply_below_the_range(struct core_freesync *core_freesync,
246 const struct dc_stream_state *stream,
247 unsigned int last_render_time_in_us,
248 struct mod_vrr_params *in_out_vrr)
249{
250 unsigned int inserted_frame_duration_in_us = 0;
251 unsigned int mid_point_frames_ceil = 0;
252 unsigned int mid_point_frames_floor = 0;
253 unsigned int frame_time_in_us = 0;
254 unsigned int delta_from_mid_point_in_us_1 = 0xFFFFFFFF;
255 unsigned int delta_from_mid_point_in_us_2 = 0xFFFFFFFF;
256 unsigned int frames_to_insert = 0;
257 unsigned int delta_from_mid_point_delta_in_us;
258 unsigned int max_render_time_in_us =
259 in_out_vrr->max_duration_in_us - in_out_vrr->btr.margin_in_us;
260
261
262 if ((last_render_time_in_us + in_out_vrr->btr.margin_in_us / 2) < max_render_time_in_us) {
263
264 if (in_out_vrr->btr.btr_active) {
265 in_out_vrr->btr.frame_counter = 0;
266 in_out_vrr->btr.btr_active = false;
267 }
268 } else if (last_render_time_in_us > (max_render_time_in_us + in_out_vrr->btr.margin_in_us / 2)) {
269
270 if (!in_out_vrr->btr.btr_active) {
271 in_out_vrr->btr.btr_active = true;
272 }
273 }
274
275
276 if (!in_out_vrr->btr.btr_active) {
277 in_out_vrr->btr.inserted_duration_in_us = 0;
278 in_out_vrr->btr.frames_to_insert = 0;
279 in_out_vrr->btr.frame_counter = 0;
280
281
282 in_out_vrr->adjust.v_total_min =
283 mod_freesync_calc_v_total_from_refresh(stream,
284 in_out_vrr->max_refresh_in_uhz);
285 in_out_vrr->adjust.v_total_max =
286 mod_freesync_calc_v_total_from_refresh(stream,
287 in_out_vrr->min_refresh_in_uhz);
288
289 } else {
290
291
292
293
294 mid_point_frames_ceil = (last_render_time_in_us +
295 in_out_vrr->btr.mid_point_in_us - 1) /
296 in_out_vrr->btr.mid_point_in_us;
297
298 if (mid_point_frames_ceil > 0) {
299 frame_time_in_us = last_render_time_in_us /
300 mid_point_frames_ceil;
301 delta_from_mid_point_in_us_1 =
302 (in_out_vrr->btr.mid_point_in_us >
303 frame_time_in_us) ?
304 (in_out_vrr->btr.mid_point_in_us - frame_time_in_us) :
305 (frame_time_in_us - in_out_vrr->btr.mid_point_in_us);
306 }
307
308
309
310
311 mid_point_frames_floor = last_render_time_in_us /
312 in_out_vrr->btr.mid_point_in_us;
313
314 if (mid_point_frames_floor > 0) {
315
316 frame_time_in_us = last_render_time_in_us /
317 mid_point_frames_floor;
318 delta_from_mid_point_in_us_2 =
319 (in_out_vrr->btr.mid_point_in_us >
320 frame_time_in_us) ?
321 (in_out_vrr->btr.mid_point_in_us - frame_time_in_us) :
322 (frame_time_in_us - in_out_vrr->btr.mid_point_in_us);
323 }
324
325
326
327
328
329
330 if ((last_render_time_in_us / mid_point_frames_ceil) < in_out_vrr->min_duration_in_us) {
331
332
333
334
335 frames_to_insert = mid_point_frames_floor;
336 } else if (mid_point_frames_floor < 2) {
337
338
339
340 frames_to_insert = mid_point_frames_ceil;
341 } else if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) {
342
343
344
345
346 frames_to_insert = mid_point_frames_ceil;
347 } else {
348
349
350
351
352 frames_to_insert = mid_point_frames_floor;
353 }
354
355
356
357
358 if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) {
359 delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_2 -
360 delta_from_mid_point_in_us_1;
361 } else {
362 delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_1 -
363 delta_from_mid_point_in_us_2;
364 }
365 if (in_out_vrr->btr.frames_to_insert != 0 &&
366 delta_from_mid_point_delta_in_us < BTR_DRIFT_MARGIN) {
367 if (((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) <
368 max_render_time_in_us) &&
369 ((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) >
370 in_out_vrr->min_duration_in_us))
371 frames_to_insert = in_out_vrr->btr.frames_to_insert;
372 }
373
374
375
376
377 if (last_render_time_in_us / frames_to_insert <
378 in_out_vrr->min_duration_in_us){
379 frames_to_insert -= (frames_to_insert > 1) ?
380 1 : 0;
381 }
382
383 if (frames_to_insert > 0)
384 inserted_frame_duration_in_us = last_render_time_in_us /
385 frames_to_insert;
386
387 if (inserted_frame_duration_in_us < in_out_vrr->min_duration_in_us)
388 inserted_frame_duration_in_us = in_out_vrr->min_duration_in_us;
389
390
391 in_out_vrr->btr.inserted_duration_in_us =
392 inserted_frame_duration_in_us;
393 in_out_vrr->btr.frames_to_insert = frames_to_insert;
394 in_out_vrr->btr.frame_counter = frames_to_insert;
395 }
396}
397
398static void apply_fixed_refresh(struct core_freesync *core_freesync,
399 const struct dc_stream_state *stream,
400 unsigned int last_render_time_in_us,
401 struct mod_vrr_params *in_out_vrr)
402{
403 bool update = false;
404 unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us;
405
406
407 unsigned int exit_refresh_rate_in_milli_hz = ((1000000000/max_render_time_in_us)
408 + (1000*FIXED_REFRESH_EXIT_MARGIN_IN_HZ));
409 unsigned int exit_frame_duration_in_us = 1000000000/exit_refresh_rate_in_milli_hz;
410
411 if (last_render_time_in_us < exit_frame_duration_in_us) {
412
413 if (in_out_vrr->fixed.fixed_active) {
414 in_out_vrr->fixed.frame_counter++;
415
416 if (in_out_vrr->fixed.frame_counter >
417 FIXED_REFRESH_EXIT_FRAME_COUNT) {
418 in_out_vrr->fixed.frame_counter = 0;
419 in_out_vrr->fixed.fixed_active = false;
420 in_out_vrr->fixed.target_refresh_in_uhz = 0;
421 update = true;
422 }
423 } else
424 in_out_vrr->fixed.frame_counter = 0;
425 } else if (last_render_time_in_us > max_render_time_in_us) {
426
427 if (!in_out_vrr->fixed.fixed_active) {
428 in_out_vrr->fixed.frame_counter++;
429
430 if (in_out_vrr->fixed.frame_counter >
431 FIXED_REFRESH_ENTER_FRAME_COUNT) {
432 in_out_vrr->fixed.frame_counter = 0;
433 in_out_vrr->fixed.fixed_active = true;
434 in_out_vrr->fixed.target_refresh_in_uhz =
435 in_out_vrr->max_refresh_in_uhz;
436 update = true;
437 }
438 } else
439 in_out_vrr->fixed.frame_counter = 0;
440 }
441
442 if (update) {
443 if (in_out_vrr->fixed.fixed_active) {
444 in_out_vrr->adjust.v_total_min =
445 mod_freesync_calc_v_total_from_refresh(
446 stream, in_out_vrr->max_refresh_in_uhz);
447 in_out_vrr->adjust.v_total_max =
448 in_out_vrr->adjust.v_total_min;
449 } else {
450 in_out_vrr->adjust.v_total_min =
451 mod_freesync_calc_v_total_from_refresh(stream,
452 in_out_vrr->max_refresh_in_uhz);
453 in_out_vrr->adjust.v_total_max =
454 mod_freesync_calc_v_total_from_refresh(stream,
455 in_out_vrr->min_refresh_in_uhz);
456 }
457 }
458}
459
460static bool vrr_settings_require_update(struct core_freesync *core_freesync,
461 struct mod_freesync_config *in_config,
462 unsigned int min_refresh_in_uhz,
463 unsigned int max_refresh_in_uhz,
464 struct mod_vrr_params *in_vrr)
465{
466 if (in_vrr->state != in_config->state) {
467 return true;
468 } else if (in_vrr->state == VRR_STATE_ACTIVE_FIXED &&
469 in_vrr->fixed.target_refresh_in_uhz !=
470 in_config->fixed_refresh_in_uhz) {
471 return true;
472 } else if (in_vrr->min_refresh_in_uhz != min_refresh_in_uhz) {
473 return true;
474 } else if (in_vrr->max_refresh_in_uhz != max_refresh_in_uhz) {
475 return true;
476 }
477
478 return false;
479}
480
481bool mod_freesync_get_vmin_vmax(struct mod_freesync *mod_freesync,
482 const struct dc_stream_state *stream,
483 unsigned int *vmin,
484 unsigned int *vmax)
485{
486 *vmin = stream->adjust.v_total_min;
487 *vmax = stream->adjust.v_total_max;
488
489 return true;
490}
491
492bool mod_freesync_get_v_position(struct mod_freesync *mod_freesync,
493 struct dc_stream_state *stream,
494 unsigned int *nom_v_pos,
495 unsigned int *v_pos)
496{
497 struct core_freesync *core_freesync = NULL;
498 struct crtc_position position;
499
500 if (mod_freesync == NULL)
501 return false;
502
503 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
504
505 if (dc_stream_get_crtc_position(core_freesync->dc, &stream, 1,
506 &position.vertical_count,
507 &position.nominal_vcount)) {
508
509 *nom_v_pos = position.nominal_vcount;
510 *v_pos = position.vertical_count;
511
512 return true;
513 }
514
515 return false;
516}
517
518static void build_vrr_infopacket_data_v1(const struct mod_vrr_params *vrr,
519 struct dc_info_packet *infopacket,
520 bool freesync_on_desktop)
521{
522
523 infopacket->sb[1] = 0x1A;
524
525
526 infopacket->sb[2] = 0x00;
527
528
529 infopacket->sb[3] = 0x00;
530
531
532
533
534
535
536
537
538 if (vrr->state != VRR_STATE_UNSUPPORTED)
539 infopacket->sb[6] |= 0x01;
540
541
542 if (vrr->state != VRR_STATE_DISABLED &&
543 vrr->state != VRR_STATE_UNSUPPORTED)
544 infopacket->sb[6] |= 0x02;
545
546 if (freesync_on_desktop) {
547
548 if (vrr->state != VRR_STATE_DISABLED &&
549 vrr->state != VRR_STATE_UNSUPPORTED)
550 infopacket->sb[6] |= 0x04;
551 } else {
552 if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
553 vrr->state == VRR_STATE_ACTIVE_FIXED)
554 infopacket->sb[6] |= 0x04;
555 }
556
557
558
559 if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
560 vrr->state == VRR_STATE_ACTIVE_FIXED) {
561 infopacket->sb[7] = (unsigned char)((vrr->min_refresh_in_uhz + 500000) / 1000000);
562 } else {
563 infopacket->sb[7] = (unsigned char)((vrr->max_refresh_in_uhz + 500000) / 1000000);
564 }
565
566
567
568
569 infopacket->sb[8] = (unsigned char)((vrr->max_refresh_in_uhz + 500000) / 1000000);
570
571
572 infopacket->sb[9] = 0;
573 infopacket->sb[10] = 0;
574}
575
576static void build_vrr_infopacket_data_v3(const struct mod_vrr_params *vrr,
577 struct dc_info_packet *infopacket)
578{
579 unsigned int min_refresh;
580 unsigned int max_refresh;
581 unsigned int fixed_refresh;
582 unsigned int min_programmed;
583 unsigned int max_programmed;
584
585
586 infopacket->sb[1] = 0x1A;
587
588
589 infopacket->sb[2] = 0x00;
590
591
592 infopacket->sb[3] = 0x00;
593
594
595
596
597
598
599
600
601 if (vrr->state != VRR_STATE_UNSUPPORTED)
602 infopacket->sb[6] |= 0x01;
603
604
605 if (vrr->state != VRR_STATE_DISABLED &&
606 vrr->state != VRR_STATE_UNSUPPORTED)
607 infopacket->sb[6] |= 0x02;
608
609
610 if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
611 vrr->state == VRR_STATE_ACTIVE_FIXED)
612 infopacket->sb[6] |= 0x04;
613
614 min_refresh = (vrr->min_refresh_in_uhz + 500000) / 1000000;
615 max_refresh = (vrr->max_refresh_in_uhz + 500000) / 1000000;
616 fixed_refresh = (vrr->fixed_refresh_in_uhz + 500000) / 1000000;
617
618 min_programmed = (vrr->state == VRR_STATE_ACTIVE_FIXED) ? fixed_refresh :
619 (vrr->state == VRR_STATE_ACTIVE_VARIABLE) ? min_refresh :
620 (vrr->state == VRR_STATE_INACTIVE) ? min_refresh :
621 max_refresh;
622
623 max_programmed = (vrr->state == VRR_STATE_ACTIVE_FIXED) ? fixed_refresh :
624 (vrr->state == VRR_STATE_ACTIVE_VARIABLE) ? max_refresh :
625 max_refresh;
626
627
628 infopacket->sb[7] = min_programmed & 0xFF;
629
630
631 infopacket->sb[8] = max_programmed & 0xFF;
632
633
634 infopacket->sb[11] = (min_programmed >> 8) & 0x03;
635
636
637 infopacket->sb[12] = (max_programmed >> 8) & 0x03;
638
639
640 infopacket->sb[16] = (vrr->state == VRR_STATE_ACTIVE_FIXED) ? 1 : 0;
641
642
643 infopacket->sb[9] = 0;
644 infopacket->sb[10] = 0;
645}
646
647static void build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf,
648 struct dc_info_packet *infopacket)
649{
650 if (app_tf != TRANSFER_FUNC_UNKNOWN) {
651 infopacket->valid = true;
652
653 infopacket->sb[6] |= 0x08;
654
655 if (app_tf == TRANSFER_FUNC_GAMMA_22) {
656 infopacket->sb[9] |= 0x04;
657 }
658 }
659}
660
661static void build_vrr_infopacket_header_v1(enum signal_type signal,
662 struct dc_info_packet *infopacket,
663 unsigned int *payload_size)
664{
665 if (dc_is_hdmi_signal(signal)) {
666
667
668
669
670
671
672 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
673
674
675 infopacket->hb1 = 0x01;
676
677
678 infopacket->hb2 = 0x08;
679
680 *payload_size = 0x08;
681
682 } else if (dc_is_dp_signal(signal)) {
683
684
685
686
687
688
689 infopacket->hb0 = 0x00;
690
691
692
693
694 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
695
696
697
698
699 infopacket->hb2 = 0x1B;
700
701
702
703
704 infopacket->hb3 = 0x04;
705
706 *payload_size = 0x1B;
707 }
708}
709
710static void build_vrr_infopacket_header_v2(enum signal_type signal,
711 struct dc_info_packet *infopacket,
712 unsigned int *payload_size)
713{
714 if (dc_is_hdmi_signal(signal)) {
715
716
717
718
719
720
721 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
722
723
724 infopacket->hb1 = 0x02;
725
726
727 infopacket->hb2 = 0x09;
728
729 *payload_size = 0x0A;
730
731 } else if (dc_is_dp_signal(signal)) {
732
733
734
735
736
737
738 infopacket->hb0 = 0x00;
739
740
741
742
743 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
744
745
746
747
748 infopacket->hb2 = 0x1B;
749
750
751
752
753 infopacket->hb3 = 0x08;
754
755 *payload_size = 0x1B;
756 }
757}
758
759static void build_vrr_infopacket_header_v3(enum signal_type signal,
760 struct dc_info_packet *infopacket,
761 unsigned int *payload_size)
762{
763 unsigned char version;
764
765 version = 3;
766 if (dc_is_hdmi_signal(signal)) {
767
768
769
770
771
772
773 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
774
775
776 infopacket->hb1 = version;
777
778
779 *payload_size = 0x10;
780 infopacket->hb2 = *payload_size - 1;
781
782 } else if (dc_is_dp_signal(signal)) {
783
784
785
786
787
788
789 infopacket->hb0 = 0x00;
790
791
792
793
794 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
795
796
797
798
799 infopacket->hb2 = 0x1B;
800
801
802
803
804
805 infopacket->hb3 = (version & 0x3F) << 2;
806
807 *payload_size = 0x1B;
808 }
809}
810
811static void build_vrr_infopacket_checksum(unsigned int *payload_size,
812 struct dc_info_packet *infopacket)
813{
814
815 unsigned int idx = 0;
816 unsigned char checksum = 0;
817
818 checksum += infopacket->hb0;
819 checksum += infopacket->hb1;
820 checksum += infopacket->hb2;
821 checksum += infopacket->hb3;
822
823 for (idx = 1; idx <= *payload_size; idx++)
824 checksum += infopacket->sb[idx];
825
826
827 infopacket->sb[0] = (unsigned char)(0x100 - checksum);
828
829 infopacket->valid = true;
830}
831
832static void build_vrr_infopacket_v1(enum signal_type signal,
833 const struct mod_vrr_params *vrr,
834 struct dc_info_packet *infopacket,
835 bool freesync_on_desktop)
836{
837
838 unsigned int payload_size = 0;
839
840 build_vrr_infopacket_header_v1(signal, infopacket, &payload_size);
841 build_vrr_infopacket_data_v1(vrr, infopacket, freesync_on_desktop);
842 build_vrr_infopacket_checksum(&payload_size, infopacket);
843
844 infopacket->valid = true;
845}
846
847static void build_vrr_infopacket_v2(enum signal_type signal,
848 const struct mod_vrr_params *vrr,
849 enum color_transfer_func app_tf,
850 struct dc_info_packet *infopacket,
851 bool freesync_on_desktop)
852{
853 unsigned int payload_size = 0;
854
855 build_vrr_infopacket_header_v2(signal, infopacket, &payload_size);
856 build_vrr_infopacket_data_v1(vrr, infopacket, freesync_on_desktop);
857
858 build_vrr_infopacket_fs2_data(app_tf, infopacket);
859
860 build_vrr_infopacket_checksum(&payload_size, infopacket);
861
862 infopacket->valid = true;
863}
864#ifndef TRIM_FSFT
865static void build_vrr_infopacket_fast_transport_data(
866 bool ftActive,
867 unsigned int ftOutputRate,
868 struct dc_info_packet *infopacket)
869{
870
871 unsigned char activeBit = (ftActive) ? 1 << 7 : 0;
872
873 infopacket->sb[1] &= ~activeBit;
874 infopacket->sb[1] |= activeBit;
875
876
877 infopacket->sb[13] = ftOutputRate & 0xFF;
878
879
880 infopacket->sb[14] = (ftOutputRate >> 8) & 0xFF;
881
882
883 infopacket->sb[15] = (ftOutputRate >> 16) & 0xFF;
884
885}
886#endif
887
888static void build_vrr_infopacket_v3(enum signal_type signal,
889 const struct mod_vrr_params *vrr,
890#ifndef TRIM_FSFT
891 bool ftActive, unsigned int ftOutputRate,
892#endif
893 enum color_transfer_func app_tf,
894 struct dc_info_packet *infopacket)
895{
896 unsigned int payload_size = 0;
897
898 build_vrr_infopacket_header_v3(signal, infopacket, &payload_size);
899 build_vrr_infopacket_data_v3(vrr, infopacket);
900
901 build_vrr_infopacket_fs2_data(app_tf, infopacket);
902
903#ifndef TRIM_FSFT
904 build_vrr_infopacket_fast_transport_data(
905 ftActive,
906 ftOutputRate,
907 infopacket);
908#endif
909
910 build_vrr_infopacket_checksum(&payload_size, infopacket);
911
912 infopacket->valid = true;
913}
914
915static void build_vrr_infopacket_sdp_v1_3(enum vrr_packet_type packet_type,
916 struct dc_info_packet *infopacket)
917{
918 uint8_t idx = 0, size = 0;
919
920 size = ((packet_type == PACKET_TYPE_FS_V1) ? 0x08 :
921 (packet_type == PACKET_TYPE_FS_V3) ? 0x10 :
922 0x09);
923
924 for (idx = infopacket->hb2; idx > 1; idx--)
925 infopacket->sb[idx] = infopacket->sb[idx-1];
926
927 infopacket->sb[1] = size;
928 infopacket->sb[0] = (infopacket->hb3 >> 2) & 0x3F;
929 infopacket->hb3 = (0x13 << 2);
930 infopacket->hb2 = 0x1D;
931}
932
933void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync,
934 const struct dc_stream_state *stream,
935 const struct mod_vrr_params *vrr,
936 enum vrr_packet_type packet_type,
937 enum color_transfer_func app_tf,
938 struct dc_info_packet *infopacket,
939 bool pack_sdp_v1_3)
940{
941
942
943
944
945
946 if (!vrr->send_info_frame)
947 return;
948
949 switch (packet_type) {
950 case PACKET_TYPE_FS_V3:
951#ifndef TRIM_FSFT
952
953 build_vrr_infopacket_v3(
954 stream->signal, vrr,
955 stream->timing.flags.FAST_TRANSPORT,
956 (stream->timing.flags.FAST_TRANSPORT) ?
957 stream->timing.fast_transport_output_rate_100hz :
958 stream->timing.pix_clk_100hz,
959 app_tf, infopacket);
960#else
961 build_vrr_infopacket_v3(stream->signal, vrr, app_tf, infopacket);
962#endif
963 break;
964 case PACKET_TYPE_FS_V2:
965 build_vrr_infopacket_v2(stream->signal, vrr, app_tf, infopacket, stream->freesync_on_desktop);
966 break;
967 case PACKET_TYPE_VRR:
968 case PACKET_TYPE_FS_V1:
969 default:
970 build_vrr_infopacket_v1(stream->signal, vrr, infopacket, stream->freesync_on_desktop);
971 }
972
973 if (true == pack_sdp_v1_3 &&
974 true == dc_is_dp_signal(stream->signal) &&
975 packet_type != PACKET_TYPE_VRR &&
976 packet_type != PACKET_TYPE_VTEM)
977 build_vrr_infopacket_sdp_v1_3(packet_type, infopacket);
978}
979
980void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync,
981 const struct dc_stream_state *stream,
982 struct mod_freesync_config *in_config,
983 struct mod_vrr_params *in_out_vrr)
984{
985 struct core_freesync *core_freesync = NULL;
986 unsigned long long nominal_field_rate_in_uhz = 0;
987 unsigned long long rounded_nominal_in_uhz = 0;
988 unsigned int refresh_range = 0;
989 unsigned long long min_refresh_in_uhz = 0;
990 unsigned long long max_refresh_in_uhz = 0;
991
992 if (mod_freesync == NULL)
993 return;
994
995 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
996
997
998 nominal_field_rate_in_uhz =
999 mod_freesync_calc_nominal_field_rate(stream);
1000
1001 min_refresh_in_uhz = in_config->min_refresh_in_uhz;
1002 max_refresh_in_uhz = in_config->max_refresh_in_uhz;
1003
1004
1005 if (max_refresh_in_uhz > nominal_field_rate_in_uhz)
1006 max_refresh_in_uhz = nominal_field_rate_in_uhz;
1007
1008
1009 if (min_refresh_in_uhz > max_refresh_in_uhz)
1010 min_refresh_in_uhz = max_refresh_in_uhz;
1011
1012
1013 rounded_nominal_in_uhz =
1014 div_u64(nominal_field_rate_in_uhz + 50000, 100000) * 100000;
1015 if (in_config->max_refresh_in_uhz == (2 * in_config->min_refresh_in_uhz) &&
1016 in_config->max_refresh_in_uhz == rounded_nominal_in_uhz)
1017 min_refresh_in_uhz = div_u64(nominal_field_rate_in_uhz, 2);
1018
1019 if (!vrr_settings_require_update(core_freesync,
1020 in_config, (unsigned int)min_refresh_in_uhz, (unsigned int)max_refresh_in_uhz,
1021 in_out_vrr))
1022 return;
1023
1024 in_out_vrr->state = in_config->state;
1025 in_out_vrr->send_info_frame = in_config->vsif_supported;
1026
1027 if (in_config->state == VRR_STATE_UNSUPPORTED) {
1028 in_out_vrr->state = VRR_STATE_UNSUPPORTED;
1029 in_out_vrr->supported = false;
1030 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1031 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1032
1033 return;
1034
1035 } else {
1036 in_out_vrr->min_refresh_in_uhz = (unsigned int)min_refresh_in_uhz;
1037 in_out_vrr->max_duration_in_us =
1038 calc_duration_in_us_from_refresh_in_uhz(
1039 (unsigned int)min_refresh_in_uhz);
1040
1041 in_out_vrr->max_refresh_in_uhz = (unsigned int)max_refresh_in_uhz;
1042 in_out_vrr->min_duration_in_us =
1043 calc_duration_in_us_from_refresh_in_uhz(
1044 (unsigned int)max_refresh_in_uhz);
1045
1046 if (in_config->state == VRR_STATE_ACTIVE_FIXED)
1047 in_out_vrr->fixed_refresh_in_uhz = in_config->fixed_refresh_in_uhz;
1048 else
1049 in_out_vrr->fixed_refresh_in_uhz = 0;
1050
1051 refresh_range = div_u64(in_out_vrr->max_refresh_in_uhz + 500000, 1000000) -
1052+ div_u64(in_out_vrr->min_refresh_in_uhz + 500000, 1000000);
1053
1054 in_out_vrr->supported = true;
1055 }
1056
1057 in_out_vrr->fixed.ramping_active = in_config->ramping;
1058
1059 in_out_vrr->btr.btr_enabled = in_config->btr;
1060
1061 if (in_out_vrr->max_refresh_in_uhz < (2 * in_out_vrr->min_refresh_in_uhz))
1062 in_out_vrr->btr.btr_enabled = false;
1063 else {
1064 in_out_vrr->btr.margin_in_us = in_out_vrr->max_duration_in_us -
1065 2 * in_out_vrr->min_duration_in_us;
1066 if (in_out_vrr->btr.margin_in_us > BTR_MAX_MARGIN)
1067 in_out_vrr->btr.margin_in_us = BTR_MAX_MARGIN;
1068 }
1069
1070 in_out_vrr->btr.btr_active = false;
1071 in_out_vrr->btr.inserted_duration_in_us = 0;
1072 in_out_vrr->btr.frames_to_insert = 0;
1073 in_out_vrr->btr.frame_counter = 0;
1074 in_out_vrr->fixed.fixed_active = false;
1075 in_out_vrr->fixed.target_refresh_in_uhz = 0;
1076
1077 in_out_vrr->btr.mid_point_in_us =
1078 (in_out_vrr->min_duration_in_us +
1079 in_out_vrr->max_duration_in_us) / 2;
1080
1081 if (in_out_vrr->state == VRR_STATE_UNSUPPORTED) {
1082 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1083 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1084 } else if (in_out_vrr->state == VRR_STATE_DISABLED) {
1085 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1086 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1087 } else if (in_out_vrr->state == VRR_STATE_INACTIVE) {
1088 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1089 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1090 } else if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE &&
1091 refresh_range >= MIN_REFRESH_RANGE) {
1092
1093 in_out_vrr->adjust.v_total_min =
1094 mod_freesync_calc_v_total_from_refresh(stream,
1095 in_out_vrr->max_refresh_in_uhz);
1096 in_out_vrr->adjust.v_total_max =
1097 mod_freesync_calc_v_total_from_refresh(stream,
1098 in_out_vrr->min_refresh_in_uhz);
1099 } else if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED) {
1100 in_out_vrr->fixed.target_refresh_in_uhz =
1101 in_out_vrr->fixed_refresh_in_uhz;
1102 if (in_out_vrr->fixed.ramping_active &&
1103 in_out_vrr->fixed.fixed_active) {
1104
1105
1106
1107 in_out_vrr->fixed.fixed_active = true;
1108 } else {
1109 in_out_vrr->fixed.fixed_active = true;
1110 in_out_vrr->adjust.v_total_min =
1111 mod_freesync_calc_v_total_from_refresh(stream,
1112 in_out_vrr->fixed.target_refresh_in_uhz);
1113 in_out_vrr->adjust.v_total_max =
1114 in_out_vrr->adjust.v_total_min;
1115 }
1116 } else {
1117 in_out_vrr->state = VRR_STATE_INACTIVE;
1118 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1119 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1120 }
1121}
1122
1123void mod_freesync_handle_preflip(struct mod_freesync *mod_freesync,
1124 const struct dc_plane_state *plane,
1125 const struct dc_stream_state *stream,
1126 unsigned int curr_time_stamp_in_us,
1127 struct mod_vrr_params *in_out_vrr)
1128{
1129 struct core_freesync *core_freesync = NULL;
1130 unsigned int last_render_time_in_us = 0;
1131 unsigned int average_render_time_in_us = 0;
1132
1133 if (mod_freesync == NULL)
1134 return;
1135
1136 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1137
1138 if (in_out_vrr->supported &&
1139 in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE) {
1140 unsigned int i = 0;
1141 unsigned int oldest_index = plane->time.index + 1;
1142
1143 if (oldest_index >= DC_PLANE_UPDATE_TIMES_MAX)
1144 oldest_index = 0;
1145
1146 last_render_time_in_us = curr_time_stamp_in_us -
1147 plane->time.prev_update_time_in_us;
1148
1149
1150 for (i = 0; i < DC_PLANE_UPDATE_TIMES_MAX; i++) {
1151 average_render_time_in_us +=
1152 plane->time.time_elapsed_in_us[i];
1153 }
1154 average_render_time_in_us -=
1155 plane->time.time_elapsed_in_us[oldest_index];
1156
1157
1158 average_render_time_in_us += last_render_time_in_us;
1159 average_render_time_in_us /= DC_PLANE_UPDATE_TIMES_MAX;
1160
1161 if (in_out_vrr->btr.btr_enabled) {
1162 apply_below_the_range(core_freesync,
1163 stream,
1164 last_render_time_in_us,
1165 in_out_vrr);
1166 } else {
1167 apply_fixed_refresh(core_freesync,
1168 stream,
1169 last_render_time_in_us,
1170 in_out_vrr);
1171 }
1172
1173 }
1174}
1175
1176void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync,
1177 const struct dc_stream_state *stream,
1178 struct mod_vrr_params *in_out_vrr)
1179{
1180 struct core_freesync *core_freesync = NULL;
1181
1182 if ((mod_freesync == NULL) || (stream == NULL) || (in_out_vrr == NULL))
1183 return;
1184
1185 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1186
1187 if (in_out_vrr->supported == false)
1188 return;
1189
1190
1191
1192
1193 if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE &&
1194 in_out_vrr->btr.btr_active) {
1195
1196
1197
1198
1199
1200
1201
1202 if (in_out_vrr->btr.frames_to_insert ==
1203 in_out_vrr->btr.frame_counter) {
1204 in_out_vrr->adjust.v_total_min =
1205 calc_v_total_from_duration(stream,
1206 in_out_vrr,
1207 in_out_vrr->btr.inserted_duration_in_us);
1208 in_out_vrr->adjust.v_total_max =
1209 in_out_vrr->adjust.v_total_min;
1210 }
1211
1212 if (in_out_vrr->btr.frame_counter > 0)
1213 in_out_vrr->btr.frame_counter--;
1214
1215
1216 if (in_out_vrr->btr.frame_counter == 0) {
1217 in_out_vrr->adjust.v_total_min =
1218 mod_freesync_calc_v_total_from_refresh(stream,
1219 in_out_vrr->max_refresh_in_uhz);
1220 in_out_vrr->adjust.v_total_max =
1221 mod_freesync_calc_v_total_from_refresh(stream,
1222 in_out_vrr->min_refresh_in_uhz);
1223 }
1224 }
1225
1226
1227
1228
1229 if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE)
1230 in_out_vrr->fixed.ramping_active = false;
1231
1232
1233
1234
1235 if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED &&
1236 in_out_vrr->fixed.ramping_active) {
1237 update_v_total_for_static_ramp(
1238 core_freesync, stream, in_out_vrr);
1239 }
1240}
1241
1242void mod_freesync_get_settings(struct mod_freesync *mod_freesync,
1243 const struct mod_vrr_params *vrr,
1244 unsigned int *v_total_min, unsigned int *v_total_max,
1245 unsigned int *event_triggers,
1246 unsigned int *window_min, unsigned int *window_max,
1247 unsigned int *lfc_mid_point_in_us,
1248 unsigned int *inserted_frames,
1249 unsigned int *inserted_duration_in_us)
1250{
1251 if (mod_freesync == NULL)
1252 return;
1253
1254 if (vrr->supported) {
1255 *v_total_min = vrr->adjust.v_total_min;
1256 *v_total_max = vrr->adjust.v_total_max;
1257 *event_triggers = 0;
1258 *lfc_mid_point_in_us = vrr->btr.mid_point_in_us;
1259 *inserted_frames = vrr->btr.frames_to_insert;
1260 *inserted_duration_in_us = vrr->btr.inserted_duration_in_us;
1261 }
1262}
1263
1264unsigned long long mod_freesync_calc_nominal_field_rate(
1265 const struct dc_stream_state *stream)
1266{
1267 unsigned long long nominal_field_rate_in_uhz = 0;
1268 unsigned int total = stream->timing.h_total * stream->timing.v_total;
1269
1270
1271 nominal_field_rate_in_uhz = stream->timing.pix_clk_100hz;
1272 nominal_field_rate_in_uhz *= 100000000ULL;
1273
1274 nominal_field_rate_in_uhz = div_u64(nominal_field_rate_in_uhz, total);
1275
1276 return nominal_field_rate_in_uhz;
1277}
1278
1279unsigned long long mod_freesync_calc_field_rate_from_timing(
1280 unsigned int vtotal, unsigned int htotal, unsigned int pix_clk)
1281{
1282 unsigned long long field_rate_in_uhz = 0;
1283 unsigned int total = htotal * vtotal;
1284
1285
1286 field_rate_in_uhz = pix_clk;
1287 field_rate_in_uhz *= 1000000ULL;
1288
1289 field_rate_in_uhz = div_u64(field_rate_in_uhz, total);
1290
1291 return field_rate_in_uhz;
1292}
1293
1294bool mod_freesync_is_valid_range(uint32_t min_refresh_cap_in_uhz,
1295 uint32_t max_refresh_cap_in_uhz,
1296 uint32_t nominal_field_rate_in_uhz)
1297{
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332 nominal_field_rate_in_uhz =
1333 div_u64(nominal_field_rate_in_uhz + 500000, 1000000);
1334 min_refresh_cap_in_uhz /= 1000000;
1335 max_refresh_cap_in_uhz /= 1000000;
1336
1337
1338 if (nominal_field_rate_in_uhz > max_refresh_cap_in_uhz ||
1339 nominal_field_rate_in_uhz < min_refresh_cap_in_uhz)
1340 return false;
1341
1342
1343 if (nominal_field_rate_in_uhz < max_refresh_cap_in_uhz)
1344 max_refresh_cap_in_uhz = nominal_field_rate_in_uhz;
1345
1346
1347 if (min_refresh_cap_in_uhz > max_refresh_cap_in_uhz)
1348 return false;
1349
1350
1351 if (nominal_field_rate_in_uhz - min_refresh_cap_in_uhz < 10)
1352 return false;
1353
1354 return true;
1355}
1356