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
121static unsigned int 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 calc_v_total_from_refresh(stream,
284 in_out_vrr->max_refresh_in_uhz);
285 in_out_vrr->adjust.v_total_max =
286 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 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 calc_v_total_from_refresh(stream,
452 in_out_vrr->max_refresh_in_uhz);
453 in_out_vrr->adjust.v_total_max =
454 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{
521
522 infopacket->sb[1] = 0x1A;
523
524
525 infopacket->sb[2] = 0x00;
526
527
528 infopacket->sb[3] = 0x00;
529
530
531
532
533
534
535
536
537 if (vrr->state != VRR_STATE_UNSUPPORTED)
538 infopacket->sb[6] |= 0x01;
539
540
541 if (vrr->state != VRR_STATE_DISABLED &&
542 vrr->state != VRR_STATE_UNSUPPORTED)
543 infopacket->sb[6] |= 0x02;
544
545
546 if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
547 vrr->state == VRR_STATE_ACTIVE_FIXED)
548 infopacket->sb[6] |= 0x04;
549
550
551
552 if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
553 vrr->state == VRR_STATE_ACTIVE_FIXED) {
554 infopacket->sb[7] = (unsigned char)((vrr->min_refresh_in_uhz + 500000) / 1000000);
555 } else {
556 infopacket->sb[7] = (unsigned char)((vrr->max_refresh_in_uhz + 500000) / 1000000);
557 }
558
559
560
561
562 infopacket->sb[8] = (unsigned char)((vrr->max_refresh_in_uhz + 500000) / 1000000);
563
564
565 infopacket->sb[9] = 0;
566 infopacket->sb[10] = 0;
567}
568
569static void build_vrr_infopacket_data_v3(const struct mod_vrr_params *vrr,
570 struct dc_info_packet *infopacket)
571{
572 unsigned int min_refresh;
573 unsigned int max_refresh;
574 unsigned int fixed_refresh;
575 unsigned int min_programmed;
576 unsigned int max_programmed;
577
578
579 infopacket->sb[1] = 0x1A;
580
581
582 infopacket->sb[2] = 0x00;
583
584
585 infopacket->sb[3] = 0x00;
586
587
588
589
590
591
592
593
594 if (vrr->state != VRR_STATE_UNSUPPORTED)
595 infopacket->sb[6] |= 0x01;
596
597
598 if (vrr->state != VRR_STATE_DISABLED &&
599 vrr->state != VRR_STATE_UNSUPPORTED)
600 infopacket->sb[6] |= 0x02;
601
602
603 if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
604 vrr->state == VRR_STATE_ACTIVE_FIXED)
605 infopacket->sb[6] |= 0x04;
606
607 min_refresh = (vrr->min_refresh_in_uhz + 500000) / 1000000;
608 max_refresh = (vrr->max_refresh_in_uhz + 500000) / 1000000;
609 fixed_refresh = (vrr->fixed_refresh_in_uhz + 500000) / 1000000;
610
611 min_programmed = (vrr->state == VRR_STATE_ACTIVE_FIXED) ? fixed_refresh :
612 (vrr->state == VRR_STATE_ACTIVE_VARIABLE) ? min_refresh :
613 (vrr->state == VRR_STATE_INACTIVE) ? min_refresh :
614 max_refresh;
615
616 max_programmed = (vrr->state == VRR_STATE_ACTIVE_FIXED) ? fixed_refresh :
617 (vrr->state == VRR_STATE_ACTIVE_VARIABLE) ? max_refresh :
618 max_refresh;
619
620
621 infopacket->sb[7] = min_programmed & 0xFF;
622
623
624 infopacket->sb[8] = max_programmed & 0xFF;
625
626
627 infopacket->sb[11] = (min_programmed >> 8) & 0x03;
628
629
630 infopacket->sb[12] = (max_programmed >> 8) & 0x03;
631
632
633 infopacket->sb[16] = (vrr->state == VRR_STATE_ACTIVE_FIXED) ? 1 : 0;
634
635
636 infopacket->sb[9] = 0;
637 infopacket->sb[10] = 0;
638}
639
640static void build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf,
641 struct dc_info_packet *infopacket)
642{
643 if (app_tf != TRANSFER_FUNC_UNKNOWN) {
644 infopacket->valid = true;
645
646 infopacket->sb[6] |= 0x08;
647
648 if (app_tf == TRANSFER_FUNC_GAMMA_22) {
649 infopacket->sb[9] |= 0x04;
650 }
651 }
652}
653
654static void build_vrr_infopacket_header_v1(enum signal_type signal,
655 struct dc_info_packet *infopacket,
656 unsigned int *payload_size)
657{
658 if (dc_is_hdmi_signal(signal)) {
659
660
661
662
663
664
665 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
666
667
668 infopacket->hb1 = 0x01;
669
670
671 infopacket->hb2 = 0x08;
672
673 *payload_size = 0x08;
674
675 } else if (dc_is_dp_signal(signal)) {
676
677
678
679
680
681
682 infopacket->hb0 = 0x00;
683
684
685
686
687 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
688
689
690
691
692 infopacket->hb2 = 0x1B;
693
694
695
696
697 infopacket->hb3 = 0x04;
698
699 *payload_size = 0x1B;
700 }
701}
702
703static void build_vrr_infopacket_header_v2(enum signal_type signal,
704 struct dc_info_packet *infopacket,
705 unsigned int *payload_size)
706{
707 if (dc_is_hdmi_signal(signal)) {
708
709
710
711
712
713
714 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
715
716
717 infopacket->hb1 = 0x02;
718
719
720 infopacket->hb2 = 0x09;
721
722 *payload_size = 0x0A;
723
724 } else if (dc_is_dp_signal(signal)) {
725
726
727
728
729
730
731 infopacket->hb0 = 0x00;
732
733
734
735
736 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
737
738
739
740
741 infopacket->hb2 = 0x1B;
742
743
744
745
746 infopacket->hb3 = 0x08;
747
748 *payload_size = 0x1B;
749 }
750}
751
752static void build_vrr_infopacket_header_v3(enum signal_type signal,
753 struct dc_info_packet *infopacket,
754 unsigned int *payload_size)
755{
756 unsigned char version;
757
758 version = 3;
759 if (dc_is_hdmi_signal(signal)) {
760
761
762
763
764
765
766 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
767
768
769 infopacket->hb1 = version;
770
771
772 *payload_size = 0x10;
773 infopacket->hb2 = *payload_size - 1;
774
775 } else if (dc_is_dp_signal(signal)) {
776
777
778
779
780
781
782 infopacket->hb0 = 0x00;
783
784
785
786
787 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
788
789
790
791
792 infopacket->hb2 = 0x1B;
793
794
795
796
797
798 infopacket->hb3 = (version & 0x3F) << 2;
799
800 *payload_size = 0x1B;
801 }
802}
803
804static void build_vrr_infopacket_checksum(unsigned int *payload_size,
805 struct dc_info_packet *infopacket)
806{
807
808 unsigned int idx = 0;
809 unsigned char checksum = 0;
810
811 checksum += infopacket->hb0;
812 checksum += infopacket->hb1;
813 checksum += infopacket->hb2;
814 checksum += infopacket->hb3;
815
816 for (idx = 1; idx <= *payload_size; idx++)
817 checksum += infopacket->sb[idx];
818
819
820 infopacket->sb[0] = (unsigned char)(0x100 - checksum);
821
822 infopacket->valid = true;
823}
824
825static void build_vrr_infopacket_v1(enum signal_type signal,
826 const struct mod_vrr_params *vrr,
827 struct dc_info_packet *infopacket)
828{
829
830 unsigned int payload_size = 0;
831
832 build_vrr_infopacket_header_v1(signal, infopacket, &payload_size);
833 build_vrr_infopacket_data_v1(vrr, infopacket);
834 build_vrr_infopacket_checksum(&payload_size, infopacket);
835
836 infopacket->valid = true;
837}
838
839static void build_vrr_infopacket_v2(enum signal_type signal,
840 const struct mod_vrr_params *vrr,
841 enum color_transfer_func app_tf,
842 struct dc_info_packet *infopacket)
843{
844 unsigned int payload_size = 0;
845
846 build_vrr_infopacket_header_v2(signal, infopacket, &payload_size);
847 build_vrr_infopacket_data_v1(vrr, infopacket);
848
849 build_vrr_infopacket_fs2_data(app_tf, infopacket);
850
851 build_vrr_infopacket_checksum(&payload_size, infopacket);
852
853 infopacket->valid = true;
854}
855#ifndef TRIM_FSFT
856static void build_vrr_infopacket_fast_transport_data(
857 bool ftActive,
858 unsigned int ftOutputRate,
859 struct dc_info_packet *infopacket)
860{
861
862 unsigned char activeBit = (ftActive) ? 1 << 7 : 0;
863
864 infopacket->sb[1] &= ~activeBit;
865 infopacket->sb[1] |= activeBit;
866
867
868 infopacket->sb[13] = ftOutputRate & 0xFF;
869
870
871 infopacket->sb[14] = (ftOutputRate >> 8) & 0xFF;
872
873
874 infopacket->sb[15] = (ftOutputRate >> 16) & 0xFF;
875
876}
877#endif
878
879static void build_vrr_infopacket_v3(enum signal_type signal,
880 const struct mod_vrr_params *vrr,
881#ifndef TRIM_FSFT
882 bool ftActive, unsigned int ftOutputRate,
883#endif
884 enum color_transfer_func app_tf,
885 struct dc_info_packet *infopacket)
886{
887 unsigned int payload_size = 0;
888
889 build_vrr_infopacket_header_v3(signal, infopacket, &payload_size);
890 build_vrr_infopacket_data_v3(vrr, infopacket);
891
892 build_vrr_infopacket_fs2_data(app_tf, infopacket);
893
894#ifndef TRIM_FSFT
895 build_vrr_infopacket_fast_transport_data(
896 ftActive,
897 ftOutputRate,
898 infopacket);
899#endif
900
901 build_vrr_infopacket_checksum(&payload_size, infopacket);
902
903 infopacket->valid = true;
904}
905
906void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync,
907 const struct dc_stream_state *stream,
908 const struct mod_vrr_params *vrr,
909 enum vrr_packet_type packet_type,
910 enum color_transfer_func app_tf,
911 struct dc_info_packet *infopacket)
912{
913
914
915
916
917
918 if (!vrr->send_info_frame)
919 return;
920
921 switch (packet_type) {
922 case PACKET_TYPE_FS_V3:
923#ifndef TRIM_FSFT
924
925 build_vrr_infopacket_v3(
926 stream->signal, vrr,
927 stream->timing.flags.FAST_TRANSPORT,
928 (stream->timing.flags.FAST_TRANSPORT) ?
929 stream->timing.fast_transport_output_rate_100hz :
930 stream->timing.pix_clk_100hz,
931 app_tf, infopacket);
932#else
933 build_vrr_infopacket_v3(stream->signal, vrr, app_tf, infopacket);
934#endif
935 break;
936 case PACKET_TYPE_FS_V2:
937 build_vrr_infopacket_v2(stream->signal, vrr, app_tf, infopacket);
938 break;
939 case PACKET_TYPE_VRR:
940 case PACKET_TYPE_FS_V1:
941 default:
942 build_vrr_infopacket_v1(stream->signal, vrr, infopacket);
943 }
944}
945
946void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync,
947 const struct dc_stream_state *stream,
948 struct mod_freesync_config *in_config,
949 struct mod_vrr_params *in_out_vrr)
950{
951 struct core_freesync *core_freesync = NULL;
952 unsigned long long nominal_field_rate_in_uhz = 0;
953 unsigned long long rounded_nominal_in_uhz = 0;
954 unsigned int refresh_range = 0;
955 unsigned long long min_refresh_in_uhz = 0;
956 unsigned long long max_refresh_in_uhz = 0;
957
958 if (mod_freesync == NULL)
959 return;
960
961 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
962
963
964 nominal_field_rate_in_uhz =
965 mod_freesync_calc_nominal_field_rate(stream);
966
967 min_refresh_in_uhz = in_config->min_refresh_in_uhz;
968 max_refresh_in_uhz = in_config->max_refresh_in_uhz;
969
970
971 if (max_refresh_in_uhz > nominal_field_rate_in_uhz)
972 max_refresh_in_uhz = nominal_field_rate_in_uhz;
973
974
975 if (min_refresh_in_uhz > max_refresh_in_uhz)
976 min_refresh_in_uhz = max_refresh_in_uhz;
977
978
979 rounded_nominal_in_uhz =
980 div_u64(nominal_field_rate_in_uhz + 50000, 100000) * 100000;
981 if (in_config->max_refresh_in_uhz == (2 * in_config->min_refresh_in_uhz) &&
982 in_config->max_refresh_in_uhz == rounded_nominal_in_uhz)
983 min_refresh_in_uhz = div_u64(nominal_field_rate_in_uhz, 2);
984
985 if (!vrr_settings_require_update(core_freesync,
986 in_config, (unsigned int)min_refresh_in_uhz, (unsigned int)max_refresh_in_uhz,
987 in_out_vrr))
988 return;
989
990 in_out_vrr->state = in_config->state;
991 in_out_vrr->send_info_frame = in_config->vsif_supported;
992
993 if (in_config->state == VRR_STATE_UNSUPPORTED) {
994 in_out_vrr->state = VRR_STATE_UNSUPPORTED;
995 in_out_vrr->supported = false;
996 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
997 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
998
999 return;
1000
1001 } else {
1002 in_out_vrr->min_refresh_in_uhz = (unsigned int)min_refresh_in_uhz;
1003 in_out_vrr->max_duration_in_us =
1004 calc_duration_in_us_from_refresh_in_uhz(
1005 (unsigned int)min_refresh_in_uhz);
1006
1007 in_out_vrr->max_refresh_in_uhz = (unsigned int)max_refresh_in_uhz;
1008 in_out_vrr->min_duration_in_us =
1009 calc_duration_in_us_from_refresh_in_uhz(
1010 (unsigned int)max_refresh_in_uhz);
1011
1012 if (in_config->state == VRR_STATE_ACTIVE_FIXED)
1013 in_out_vrr->fixed_refresh_in_uhz = in_config->fixed_refresh_in_uhz;
1014 else
1015 in_out_vrr->fixed_refresh_in_uhz = 0;
1016
1017 refresh_range = div_u64(in_out_vrr->max_refresh_in_uhz + 500000, 1000000) -
1018+ div_u64(in_out_vrr->min_refresh_in_uhz + 500000, 1000000);
1019
1020 in_out_vrr->supported = true;
1021 }
1022
1023 in_out_vrr->fixed.ramping_active = in_config->ramping;
1024
1025 in_out_vrr->btr.btr_enabled = in_config->btr;
1026
1027 if (in_out_vrr->max_refresh_in_uhz < (2 * in_out_vrr->min_refresh_in_uhz))
1028 in_out_vrr->btr.btr_enabled = false;
1029 else {
1030 in_out_vrr->btr.margin_in_us = in_out_vrr->max_duration_in_us -
1031 2 * in_out_vrr->min_duration_in_us;
1032 if (in_out_vrr->btr.margin_in_us > BTR_MAX_MARGIN)
1033 in_out_vrr->btr.margin_in_us = BTR_MAX_MARGIN;
1034 }
1035
1036 in_out_vrr->btr.btr_active = false;
1037 in_out_vrr->btr.inserted_duration_in_us = 0;
1038 in_out_vrr->btr.frames_to_insert = 0;
1039 in_out_vrr->btr.frame_counter = 0;
1040 in_out_vrr->fixed.fixed_active = false;
1041 in_out_vrr->fixed.target_refresh_in_uhz = 0;
1042
1043 in_out_vrr->btr.mid_point_in_us =
1044 (in_out_vrr->min_duration_in_us +
1045 in_out_vrr->max_duration_in_us) / 2;
1046
1047 if (in_out_vrr->state == VRR_STATE_UNSUPPORTED) {
1048 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1049 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1050 } else if (in_out_vrr->state == VRR_STATE_DISABLED) {
1051 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1052 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1053 } else if (in_out_vrr->state == VRR_STATE_INACTIVE) {
1054 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1055 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1056 } else if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE &&
1057 refresh_range >= MIN_REFRESH_RANGE) {
1058
1059 in_out_vrr->adjust.v_total_min =
1060 calc_v_total_from_refresh(stream,
1061 in_out_vrr->max_refresh_in_uhz);
1062 in_out_vrr->adjust.v_total_max =
1063 calc_v_total_from_refresh(stream,
1064 in_out_vrr->min_refresh_in_uhz);
1065 } else if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED) {
1066 in_out_vrr->fixed.target_refresh_in_uhz =
1067 in_out_vrr->fixed_refresh_in_uhz;
1068 if (in_out_vrr->fixed.ramping_active &&
1069 in_out_vrr->fixed.fixed_active) {
1070
1071
1072
1073 in_out_vrr->fixed.fixed_active = true;
1074 } else {
1075 in_out_vrr->fixed.fixed_active = true;
1076 in_out_vrr->adjust.v_total_min =
1077 calc_v_total_from_refresh(stream,
1078 in_out_vrr->fixed.target_refresh_in_uhz);
1079 in_out_vrr->adjust.v_total_max =
1080 in_out_vrr->adjust.v_total_min;
1081 }
1082 } else {
1083 in_out_vrr->state = VRR_STATE_INACTIVE;
1084 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1085 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1086 }
1087}
1088
1089void mod_freesync_handle_preflip(struct mod_freesync *mod_freesync,
1090 const struct dc_plane_state *plane,
1091 const struct dc_stream_state *stream,
1092 unsigned int curr_time_stamp_in_us,
1093 struct mod_vrr_params *in_out_vrr)
1094{
1095 struct core_freesync *core_freesync = NULL;
1096 unsigned int last_render_time_in_us = 0;
1097 unsigned int average_render_time_in_us = 0;
1098
1099 if (mod_freesync == NULL)
1100 return;
1101
1102 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1103
1104 if (in_out_vrr->supported &&
1105 in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE) {
1106 unsigned int i = 0;
1107 unsigned int oldest_index = plane->time.index + 1;
1108
1109 if (oldest_index >= DC_PLANE_UPDATE_TIMES_MAX)
1110 oldest_index = 0;
1111
1112 last_render_time_in_us = curr_time_stamp_in_us -
1113 plane->time.prev_update_time_in_us;
1114
1115
1116 for (i = 0; i < DC_PLANE_UPDATE_TIMES_MAX; i++) {
1117 average_render_time_in_us +=
1118 plane->time.time_elapsed_in_us[i];
1119 }
1120 average_render_time_in_us -=
1121 plane->time.time_elapsed_in_us[oldest_index];
1122
1123
1124 average_render_time_in_us += last_render_time_in_us;
1125 average_render_time_in_us /= DC_PLANE_UPDATE_TIMES_MAX;
1126
1127 if (in_out_vrr->btr.btr_enabled) {
1128 apply_below_the_range(core_freesync,
1129 stream,
1130 last_render_time_in_us,
1131 in_out_vrr);
1132 } else {
1133 apply_fixed_refresh(core_freesync,
1134 stream,
1135 last_render_time_in_us,
1136 in_out_vrr);
1137 }
1138
1139 }
1140}
1141
1142void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync,
1143 const struct dc_stream_state *stream,
1144 struct mod_vrr_params *in_out_vrr)
1145{
1146 struct core_freesync *core_freesync = NULL;
1147
1148 if ((mod_freesync == NULL) || (stream == NULL) || (in_out_vrr == NULL))
1149 return;
1150
1151 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1152
1153 if (in_out_vrr->supported == false)
1154 return;
1155
1156
1157
1158
1159 if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE &&
1160 in_out_vrr->btr.btr_active) {
1161
1162
1163
1164
1165
1166
1167
1168 if (in_out_vrr->btr.frames_to_insert ==
1169 in_out_vrr->btr.frame_counter) {
1170 in_out_vrr->adjust.v_total_min =
1171 calc_v_total_from_duration(stream,
1172 in_out_vrr,
1173 in_out_vrr->btr.inserted_duration_in_us);
1174 in_out_vrr->adjust.v_total_max =
1175 in_out_vrr->adjust.v_total_min;
1176 }
1177
1178 if (in_out_vrr->btr.frame_counter > 0)
1179 in_out_vrr->btr.frame_counter--;
1180
1181
1182 if (in_out_vrr->btr.frame_counter == 0) {
1183 in_out_vrr->adjust.v_total_min =
1184 calc_v_total_from_refresh(stream,
1185 in_out_vrr->max_refresh_in_uhz);
1186 in_out_vrr->adjust.v_total_max =
1187 calc_v_total_from_refresh(stream,
1188 in_out_vrr->min_refresh_in_uhz);
1189 }
1190 }
1191
1192
1193
1194
1195 if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE)
1196 in_out_vrr->fixed.ramping_active = false;
1197
1198
1199
1200
1201 if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED &&
1202 in_out_vrr->fixed.ramping_active) {
1203 update_v_total_for_static_ramp(
1204 core_freesync, stream, in_out_vrr);
1205 }
1206}
1207
1208void mod_freesync_get_settings(struct mod_freesync *mod_freesync,
1209 const struct mod_vrr_params *vrr,
1210 unsigned int *v_total_min, unsigned int *v_total_max,
1211 unsigned int *event_triggers,
1212 unsigned int *window_min, unsigned int *window_max,
1213 unsigned int *lfc_mid_point_in_us,
1214 unsigned int *inserted_frames,
1215 unsigned int *inserted_duration_in_us)
1216{
1217 if (mod_freesync == NULL)
1218 return;
1219
1220 if (vrr->supported) {
1221 *v_total_min = vrr->adjust.v_total_min;
1222 *v_total_max = vrr->adjust.v_total_max;
1223 *event_triggers = 0;
1224 *lfc_mid_point_in_us = vrr->btr.mid_point_in_us;
1225 *inserted_frames = vrr->btr.frames_to_insert;
1226 *inserted_duration_in_us = vrr->btr.inserted_duration_in_us;
1227 }
1228}
1229
1230unsigned long long mod_freesync_calc_nominal_field_rate(
1231 const struct dc_stream_state *stream)
1232{
1233 unsigned long long nominal_field_rate_in_uhz = 0;
1234 unsigned int total = stream->timing.h_total * stream->timing.v_total;
1235
1236
1237 nominal_field_rate_in_uhz = stream->timing.pix_clk_100hz;
1238 nominal_field_rate_in_uhz *= 100000000ULL;
1239
1240 nominal_field_rate_in_uhz = div_u64(nominal_field_rate_in_uhz, total);
1241
1242 return nominal_field_rate_in_uhz;
1243}
1244
1245bool mod_freesync_is_valid_range(uint32_t min_refresh_cap_in_uhz,
1246 uint32_t max_refresh_cap_in_uhz,
1247 uint32_t nominal_field_rate_in_uhz)
1248{
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283 nominal_field_rate_in_uhz =
1284 div_u64(nominal_field_rate_in_uhz + 500000, 1000000);
1285 min_refresh_cap_in_uhz /= 1000000;
1286 max_refresh_cap_in_uhz /= 1000000;
1287
1288
1289 if (nominal_field_rate_in_uhz > max_refresh_cap_in_uhz ||
1290 nominal_field_rate_in_uhz < min_refresh_cap_in_uhz)
1291 return false;
1292
1293
1294 if (nominal_field_rate_in_uhz < max_refresh_cap_in_uhz)
1295 max_refresh_cap_in_uhz = nominal_field_rate_in_uhz;
1296
1297
1298 if (min_refresh_cap_in_uhz > max_refresh_cap_in_uhz)
1299 return false;
1300
1301
1302 if (nominal_field_rate_in_uhz - min_refresh_cap_in_uhz < 10)
1303 return false;
1304
1305 return true;
1306}
1307
1308