This source file includes following definitions.
- mod_freesync_create
- mod_freesync_destroy
- calc_refresh_in_uhz_from_duration
- calc_duration_in_us_from_refresh_in_uhz
- calc_duration_in_us_from_v_total
- calc_v_total_from_refresh
- calc_v_total_from_duration
- update_v_total_for_static_ramp
- apply_below_the_range
- apply_fixed_refresh
- vrr_settings_require_update
- mod_freesync_get_vmin_vmax
- mod_freesync_get_v_position
- build_vrr_infopacket_data
- build_vrr_infopacket_fs2_data
- build_vrr_infopacket_header_v1
- build_vrr_infopacket_header_v2
- build_vrr_infopacket_checksum
- build_vrr_infopacket_v1
- build_vrr_infopacket_v2
- mod_freesync_build_vrr_infopacket
- mod_freesync_build_vrr_params
- mod_freesync_handle_preflip
- mod_freesync_handle_v_update
- mod_freesync_get_settings
- mod_freesync_calc_nominal_field_rate
- mod_freesync_is_valid_range
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_IN_US 10000000
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_EXIT_MARGIN 2000
42
43 #define BTR_DRIFT_MARGIN 2000
44
45 #define FIXED_REFRESH_EXIT_MARGIN_IN_HZ 4
46
47 #define FIXED_REFRESH_ENTER_FRAME_COUNT 5
48 #define FIXED_REFRESH_EXIT_FRAME_COUNT 5
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
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 static 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 = stream->timing.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
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 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
171 static 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 in_out_vrr->adjust.v_total_min = v_total;
238 in_out_vrr->adjust.v_total_max = v_total;
239 }
240
241 static void apply_below_the_range(struct core_freesync *core_freesync,
242 const struct dc_stream_state *stream,
243 unsigned int last_render_time_in_us,
244 struct mod_vrr_params *in_out_vrr)
245 {
246 unsigned int inserted_frame_duration_in_us = 0;
247 unsigned int mid_point_frames_ceil = 0;
248 unsigned int mid_point_frames_floor = 0;
249 unsigned int frame_time_in_us = 0;
250 unsigned int delta_from_mid_point_in_us_1 = 0xFFFFFFFF;
251 unsigned int delta_from_mid_point_in_us_2 = 0xFFFFFFFF;
252 unsigned int frames_to_insert = 0;
253 unsigned int min_frame_duration_in_ns = 0;
254 unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us;
255 unsigned int delta_from_mid_point_delta_in_us;
256
257 min_frame_duration_in_ns = ((unsigned int) (div64_u64(
258 (1000000000ULL * 1000000),
259 in_out_vrr->max_refresh_in_uhz)));
260
261
262 if (last_render_time_in_us + BTR_EXIT_MARGIN < 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) {
269
270 in_out_vrr->btr.btr_active = true;
271 }
272
273
274 if (!in_out_vrr->btr.btr_active) {
275 in_out_vrr->btr.inserted_duration_in_us = 0;
276 in_out_vrr->btr.frames_to_insert = 0;
277 in_out_vrr->btr.frame_counter = 0;
278
279
280 in_out_vrr->adjust.v_total_min =
281 calc_v_total_from_refresh(stream,
282 in_out_vrr->max_refresh_in_uhz);
283 in_out_vrr->adjust.v_total_max =
284 calc_v_total_from_refresh(stream,
285 in_out_vrr->min_refresh_in_uhz);
286
287 } else {
288
289
290
291
292 mid_point_frames_ceil = (last_render_time_in_us +
293 in_out_vrr->btr.mid_point_in_us - 1) /
294 in_out_vrr->btr.mid_point_in_us;
295
296 if (mid_point_frames_ceil > 0) {
297 frame_time_in_us = last_render_time_in_us /
298 mid_point_frames_ceil;
299 delta_from_mid_point_in_us_1 =
300 (in_out_vrr->btr.mid_point_in_us >
301 frame_time_in_us) ?
302 (in_out_vrr->btr.mid_point_in_us - frame_time_in_us) :
303 (frame_time_in_us - in_out_vrr->btr.mid_point_in_us);
304 }
305
306
307
308
309 mid_point_frames_floor = last_render_time_in_us /
310 in_out_vrr->btr.mid_point_in_us;
311
312 if (mid_point_frames_floor > 0) {
313
314 frame_time_in_us = last_render_time_in_us /
315 mid_point_frames_floor;
316 delta_from_mid_point_in_us_2 =
317 (in_out_vrr->btr.mid_point_in_us >
318 frame_time_in_us) ?
319 (in_out_vrr->btr.mid_point_in_us - frame_time_in_us) :
320 (frame_time_in_us - in_out_vrr->btr.mid_point_in_us);
321 }
322
323
324
325
326 if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) {
327 frames_to_insert = mid_point_frames_ceil;
328 delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_2 -
329 delta_from_mid_point_in_us_1;
330 } else {
331 frames_to_insert = mid_point_frames_floor;
332 delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_1 -
333 delta_from_mid_point_in_us_2;
334 }
335
336
337
338
339 if (in_out_vrr->btr.frames_to_insert != 0 &&
340 delta_from_mid_point_delta_in_us < BTR_DRIFT_MARGIN) {
341 if (((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) <
342 in_out_vrr->max_duration_in_us) &&
343 ((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) >
344 in_out_vrr->min_duration_in_us))
345 frames_to_insert = in_out_vrr->btr.frames_to_insert;
346 }
347
348
349
350
351 if (last_render_time_in_us / frames_to_insert <
352 in_out_vrr->min_duration_in_us){
353 frames_to_insert -= (frames_to_insert > 1) ?
354 1 : 0;
355 }
356
357 if (frames_to_insert > 0)
358 inserted_frame_duration_in_us = last_render_time_in_us /
359 frames_to_insert;
360
361 if (inserted_frame_duration_in_us < in_out_vrr->min_duration_in_us)
362 inserted_frame_duration_in_us = in_out_vrr->min_duration_in_us;
363
364
365 in_out_vrr->btr.inserted_duration_in_us =
366 inserted_frame_duration_in_us;
367 in_out_vrr->btr.frames_to_insert = frames_to_insert;
368 in_out_vrr->btr.frame_counter = frames_to_insert;
369 }
370 }
371
372 static void apply_fixed_refresh(struct core_freesync *core_freesync,
373 const struct dc_stream_state *stream,
374 unsigned int last_render_time_in_us,
375 struct mod_vrr_params *in_out_vrr)
376 {
377 bool update = false;
378 unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us;
379
380
381 unsigned int exit_refresh_rate_in_milli_hz = ((1000000000/max_render_time_in_us)
382 + (1000*FIXED_REFRESH_EXIT_MARGIN_IN_HZ));
383 unsigned int exit_frame_duration_in_us = 1000000000/exit_refresh_rate_in_milli_hz;
384
385 if (last_render_time_in_us < exit_frame_duration_in_us) {
386
387 if (in_out_vrr->fixed.fixed_active) {
388 in_out_vrr->fixed.frame_counter++;
389
390 if (in_out_vrr->fixed.frame_counter >
391 FIXED_REFRESH_EXIT_FRAME_COUNT) {
392 in_out_vrr->fixed.frame_counter = 0;
393 in_out_vrr->fixed.fixed_active = false;
394 in_out_vrr->fixed.target_refresh_in_uhz = 0;
395 update = true;
396 }
397 }
398 } else if (last_render_time_in_us > max_render_time_in_us) {
399
400 if (!in_out_vrr->fixed.fixed_active) {
401 in_out_vrr->fixed.frame_counter++;
402
403 if (in_out_vrr->fixed.frame_counter >
404 FIXED_REFRESH_ENTER_FRAME_COUNT) {
405 in_out_vrr->fixed.frame_counter = 0;
406 in_out_vrr->fixed.fixed_active = true;
407 in_out_vrr->fixed.target_refresh_in_uhz =
408 in_out_vrr->max_refresh_in_uhz;
409 update = true;
410 }
411 }
412 }
413
414 if (update) {
415 if (in_out_vrr->fixed.fixed_active) {
416 in_out_vrr->adjust.v_total_min =
417 calc_v_total_from_refresh(
418 stream, in_out_vrr->max_refresh_in_uhz);
419 in_out_vrr->adjust.v_total_max =
420 in_out_vrr->adjust.v_total_min;
421 } else {
422 in_out_vrr->adjust.v_total_min =
423 calc_v_total_from_refresh(stream,
424 in_out_vrr->max_refresh_in_uhz);
425 in_out_vrr->adjust.v_total_max =
426 calc_v_total_from_refresh(stream,
427 in_out_vrr->min_refresh_in_uhz);
428 }
429 }
430 }
431
432 static bool vrr_settings_require_update(struct core_freesync *core_freesync,
433 struct mod_freesync_config *in_config,
434 unsigned int min_refresh_in_uhz,
435 unsigned int max_refresh_in_uhz,
436 struct mod_vrr_params *in_vrr)
437 {
438 if (in_vrr->state != in_config->state) {
439 return true;
440 } else if (in_vrr->state == VRR_STATE_ACTIVE_FIXED &&
441 in_vrr->fixed.target_refresh_in_uhz !=
442 in_config->min_refresh_in_uhz) {
443 return true;
444 } else if (in_vrr->min_refresh_in_uhz != min_refresh_in_uhz) {
445 return true;
446 } else if (in_vrr->max_refresh_in_uhz != max_refresh_in_uhz) {
447 return true;
448 }
449
450 return false;
451 }
452
453 bool mod_freesync_get_vmin_vmax(struct mod_freesync *mod_freesync,
454 const struct dc_stream_state *stream,
455 unsigned int *vmin,
456 unsigned int *vmax)
457 {
458 *vmin = stream->adjust.v_total_min;
459 *vmax = stream->adjust.v_total_max;
460
461 return true;
462 }
463
464 bool mod_freesync_get_v_position(struct mod_freesync *mod_freesync,
465 struct dc_stream_state *stream,
466 unsigned int *nom_v_pos,
467 unsigned int *v_pos)
468 {
469 struct core_freesync *core_freesync = NULL;
470 struct crtc_position position;
471
472 if (mod_freesync == NULL)
473 return false;
474
475 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
476
477 if (dc_stream_get_crtc_position(core_freesync->dc, &stream, 1,
478 &position.vertical_count,
479 &position.nominal_vcount)) {
480
481 *nom_v_pos = position.nominal_vcount;
482 *v_pos = position.vertical_count;
483
484 return true;
485 }
486
487 return false;
488 }
489
490 static void build_vrr_infopacket_data(const struct mod_vrr_params *vrr,
491 struct dc_info_packet *infopacket)
492 {
493
494 infopacket->sb[1] = 0x1A;
495
496
497 infopacket->sb[2] = 0x00;
498
499
500 infopacket->sb[3] = 0x00;
501
502
503
504
505
506
507
508
509 if (vrr->state != VRR_STATE_UNSUPPORTED)
510 infopacket->sb[6] |= 0x01;
511
512
513 if (vrr->state != VRR_STATE_DISABLED &&
514 vrr->state != VRR_STATE_UNSUPPORTED)
515 infopacket->sb[6] |= 0x02;
516
517
518 if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
519 vrr->state == VRR_STATE_ACTIVE_FIXED)
520 infopacket->sb[6] |= 0x04;
521
522
523 infopacket->sb[7] = (unsigned char)(vrr->min_refresh_in_uhz / 1000000);
524
525
526
527
528 infopacket->sb[8] = (unsigned char)(vrr->max_refresh_in_uhz / 1000000);
529
530
531
532 infopacket->sb[9] = 0;
533 infopacket->sb[10] = 0;
534 }
535
536 static void build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf,
537 struct dc_info_packet *infopacket)
538 {
539 if (app_tf != TRANSFER_FUNC_UNKNOWN) {
540 infopacket->valid = true;
541
542 infopacket->sb[6] |= 0x08;
543
544 if (app_tf == TRANSFER_FUNC_GAMMA_22) {
545 infopacket->sb[9] |= 0x04;
546 }
547 }
548 }
549
550 static void build_vrr_infopacket_header_v1(enum signal_type signal,
551 struct dc_info_packet *infopacket,
552 unsigned int *payload_size)
553 {
554 if (dc_is_hdmi_signal(signal)) {
555
556
557
558
559
560
561 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
562
563
564 infopacket->hb1 = 0x01;
565
566
567 infopacket->hb2 = 0x08;
568
569 *payload_size = 0x08;
570
571 } else if (dc_is_dp_signal(signal)) {
572
573
574
575
576
577
578 infopacket->hb0 = 0x00;
579
580
581
582
583 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
584
585
586
587
588 infopacket->hb2 = 0x1B;
589
590
591
592
593 infopacket->hb3 = 0x04;
594
595 *payload_size = 0x1B;
596 }
597 }
598
599 static void build_vrr_infopacket_header_v2(enum signal_type signal,
600 struct dc_info_packet *infopacket,
601 unsigned int *payload_size)
602 {
603 if (dc_is_hdmi_signal(signal)) {
604
605
606
607
608
609
610 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
611
612
613 infopacket->hb1 = 0x02;
614
615
616 infopacket->hb2 = 0x09;
617
618 *payload_size = 0x0A;
619
620 } else if (dc_is_dp_signal(signal)) {
621
622
623
624
625
626
627 infopacket->hb0 = 0x00;
628
629
630
631
632 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
633
634
635
636
637 infopacket->hb2 = 0x1B;
638
639
640
641
642 infopacket->hb3 = 0x08;
643
644 *payload_size = 0x1B;
645 }
646 }
647
648 static void build_vrr_infopacket_checksum(unsigned int *payload_size,
649 struct dc_info_packet *infopacket)
650 {
651
652 unsigned int idx = 0;
653 unsigned char checksum = 0;
654
655 checksum += infopacket->hb0;
656 checksum += infopacket->hb1;
657 checksum += infopacket->hb2;
658 checksum += infopacket->hb3;
659
660 for (idx = 1; idx <= *payload_size; idx++)
661 checksum += infopacket->sb[idx];
662
663
664 infopacket->sb[0] = (unsigned char)(0x100 - checksum);
665
666 infopacket->valid = true;
667 }
668
669 static void build_vrr_infopacket_v1(enum signal_type signal,
670 const struct mod_vrr_params *vrr,
671 struct dc_info_packet *infopacket)
672 {
673
674 unsigned int payload_size = 0;
675
676 build_vrr_infopacket_header_v1(signal, infopacket, &payload_size);
677 build_vrr_infopacket_data(vrr, infopacket);
678 build_vrr_infopacket_checksum(&payload_size, infopacket);
679
680 infopacket->valid = true;
681 }
682
683 static void build_vrr_infopacket_v2(enum signal_type signal,
684 const struct mod_vrr_params *vrr,
685 enum color_transfer_func app_tf,
686 struct dc_info_packet *infopacket)
687 {
688 unsigned int payload_size = 0;
689
690 build_vrr_infopacket_header_v2(signal, infopacket, &payload_size);
691 build_vrr_infopacket_data(vrr, infopacket);
692
693 build_vrr_infopacket_fs2_data(app_tf, infopacket);
694
695 build_vrr_infopacket_checksum(&payload_size, infopacket);
696
697 infopacket->valid = true;
698 }
699
700 void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync,
701 const struct dc_stream_state *stream,
702 const struct mod_vrr_params *vrr,
703 enum vrr_packet_type packet_type,
704 enum color_transfer_func app_tf,
705 struct dc_info_packet *infopacket)
706 {
707
708
709
710
711
712 if (!vrr->supported || (!vrr->send_info_frame))
713 return;
714
715 switch (packet_type) {
716 case PACKET_TYPE_FS2:
717 build_vrr_infopacket_v2(stream->signal, vrr, app_tf, infopacket);
718 break;
719 case PACKET_TYPE_VRR:
720 case PACKET_TYPE_FS1:
721 default:
722 build_vrr_infopacket_v1(stream->signal, vrr, infopacket);
723 }
724 }
725
726 void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync,
727 const struct dc_stream_state *stream,
728 struct mod_freesync_config *in_config,
729 struct mod_vrr_params *in_out_vrr)
730 {
731 struct core_freesync *core_freesync = NULL;
732 unsigned long long nominal_field_rate_in_uhz = 0;
733 unsigned int refresh_range = 0;
734 unsigned long long min_refresh_in_uhz = 0;
735 unsigned long long max_refresh_in_uhz = 0;
736
737 if (mod_freesync == NULL)
738 return;
739
740 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
741
742
743 nominal_field_rate_in_uhz =
744 mod_freesync_calc_nominal_field_rate(stream);
745
746
747 nominal_field_rate_in_uhz = 1000000ULL *
748 div_u64(nominal_field_rate_in_uhz + 500000, 1000000);
749
750 min_refresh_in_uhz = in_config->min_refresh_in_uhz;
751 max_refresh_in_uhz = in_config->max_refresh_in_uhz;
752
753
754 if (min_refresh_in_uhz > max_refresh_in_uhz)
755 min_refresh_in_uhz = max_refresh_in_uhz;
756
757
758 if (max_refresh_in_uhz > nominal_field_rate_in_uhz)
759 max_refresh_in_uhz = nominal_field_rate_in_uhz;
760
761
762 if (min_refresh_in_uhz > nominal_field_rate_in_uhz)
763 min_refresh_in_uhz = nominal_field_rate_in_uhz;
764
765 if (!vrr_settings_require_update(core_freesync,
766 in_config, (unsigned int)min_refresh_in_uhz, (unsigned int)max_refresh_in_uhz,
767 in_out_vrr))
768 return;
769
770 in_out_vrr->state = in_config->state;
771 in_out_vrr->send_info_frame = in_config->vsif_supported;
772
773 if (in_config->state == VRR_STATE_UNSUPPORTED) {
774 in_out_vrr->state = VRR_STATE_UNSUPPORTED;
775 in_out_vrr->supported = false;
776 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
777 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
778
779 return;
780
781 } else {
782 in_out_vrr->min_refresh_in_uhz = (unsigned int)min_refresh_in_uhz;
783 in_out_vrr->max_duration_in_us =
784 calc_duration_in_us_from_refresh_in_uhz(
785 (unsigned int)min_refresh_in_uhz);
786
787 in_out_vrr->max_refresh_in_uhz = (unsigned int)max_refresh_in_uhz;
788 in_out_vrr->min_duration_in_us =
789 calc_duration_in_us_from_refresh_in_uhz(
790 (unsigned int)max_refresh_in_uhz);
791
792 refresh_range = in_out_vrr->max_refresh_in_uhz -
793 in_out_vrr->min_refresh_in_uhz;
794
795 in_out_vrr->supported = true;
796 }
797
798 in_out_vrr->fixed.ramping_active = in_config->ramping;
799
800 in_out_vrr->btr.btr_enabled = in_config->btr;
801
802 if (in_out_vrr->max_refresh_in_uhz <
803 2 * in_out_vrr->min_refresh_in_uhz)
804 in_out_vrr->btr.btr_enabled = false;
805
806 in_out_vrr->fixed.fixed_active = false;
807 in_out_vrr->btr.btr_active = false;
808 in_out_vrr->btr.inserted_duration_in_us = 0;
809 in_out_vrr->btr.frames_to_insert = 0;
810 in_out_vrr->btr.frame_counter = 0;
811 in_out_vrr->btr.mid_point_in_us =
812 (in_out_vrr->min_duration_in_us +
813 in_out_vrr->max_duration_in_us) / 2;
814
815 if (in_out_vrr->state == VRR_STATE_UNSUPPORTED) {
816 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
817 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
818 } else if (in_out_vrr->state == VRR_STATE_DISABLED) {
819 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
820 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
821 } else if (in_out_vrr->state == VRR_STATE_INACTIVE) {
822 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
823 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
824 } else if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE &&
825 refresh_range >= MIN_REFRESH_RANGE_IN_US) {
826
827 in_out_vrr->adjust.v_total_min =
828 calc_v_total_from_refresh(stream,
829 in_out_vrr->max_refresh_in_uhz);
830 in_out_vrr->adjust.v_total_max =
831 calc_v_total_from_refresh(stream,
832 in_out_vrr->min_refresh_in_uhz);
833 } else if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED) {
834 in_out_vrr->fixed.target_refresh_in_uhz =
835 in_out_vrr->min_refresh_in_uhz;
836 if (in_out_vrr->fixed.ramping_active &&
837 in_out_vrr->fixed.fixed_active) {
838
839
840
841 in_out_vrr->fixed.fixed_active = true;
842 } else {
843 in_out_vrr->fixed.fixed_active = true;
844 in_out_vrr->adjust.v_total_min =
845 calc_v_total_from_refresh(stream,
846 in_out_vrr->fixed.target_refresh_in_uhz);
847 in_out_vrr->adjust.v_total_max =
848 in_out_vrr->adjust.v_total_min;
849 }
850 } else {
851 in_out_vrr->state = VRR_STATE_INACTIVE;
852 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
853 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
854 }
855 }
856
857 void mod_freesync_handle_preflip(struct mod_freesync *mod_freesync,
858 const struct dc_plane_state *plane,
859 const struct dc_stream_state *stream,
860 unsigned int curr_time_stamp_in_us,
861 struct mod_vrr_params *in_out_vrr)
862 {
863 struct core_freesync *core_freesync = NULL;
864 unsigned int last_render_time_in_us = 0;
865 unsigned int average_render_time_in_us = 0;
866
867 if (mod_freesync == NULL)
868 return;
869
870 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
871
872 if (in_out_vrr->supported &&
873 in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE) {
874 unsigned int i = 0;
875 unsigned int oldest_index = plane->time.index + 1;
876
877 if (oldest_index >= DC_PLANE_UPDATE_TIMES_MAX)
878 oldest_index = 0;
879
880 last_render_time_in_us = curr_time_stamp_in_us -
881 plane->time.prev_update_time_in_us;
882
883
884 for (i = 0; i < DC_PLANE_UPDATE_TIMES_MAX; i++) {
885 average_render_time_in_us +=
886 plane->time.time_elapsed_in_us[i];
887 }
888 average_render_time_in_us -=
889 plane->time.time_elapsed_in_us[oldest_index];
890
891
892 average_render_time_in_us += last_render_time_in_us;
893 average_render_time_in_us /= DC_PLANE_UPDATE_TIMES_MAX;
894
895 if (in_out_vrr->btr.btr_enabled) {
896 apply_below_the_range(core_freesync,
897 stream,
898 last_render_time_in_us,
899 in_out_vrr);
900 } else {
901 apply_fixed_refresh(core_freesync,
902 stream,
903 last_render_time_in_us,
904 in_out_vrr);
905 }
906
907 }
908 }
909
910 void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync,
911 const struct dc_stream_state *stream,
912 struct mod_vrr_params *in_out_vrr)
913 {
914 struct core_freesync *core_freesync = NULL;
915
916 if ((mod_freesync == NULL) || (stream == NULL) || (in_out_vrr == NULL))
917 return;
918
919 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
920
921 if (in_out_vrr->supported == false)
922 return;
923
924
925
926
927 if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE &&
928 in_out_vrr->btr.btr_active) {
929
930
931
932
933
934
935
936 if (in_out_vrr->btr.frames_to_insert ==
937 in_out_vrr->btr.frame_counter) {
938 in_out_vrr->adjust.v_total_min =
939 calc_v_total_from_duration(stream,
940 in_out_vrr,
941 in_out_vrr->btr.inserted_duration_in_us);
942 in_out_vrr->adjust.v_total_max =
943 in_out_vrr->adjust.v_total_min;
944 }
945
946 if (in_out_vrr->btr.frame_counter > 0)
947 in_out_vrr->btr.frame_counter--;
948
949
950 if (in_out_vrr->btr.frame_counter == 0) {
951 in_out_vrr->adjust.v_total_min =
952 calc_v_total_from_refresh(stream,
953 in_out_vrr->max_refresh_in_uhz);
954 in_out_vrr->adjust.v_total_max =
955 calc_v_total_from_refresh(stream,
956 in_out_vrr->min_refresh_in_uhz);
957 }
958 }
959
960
961
962
963 if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE)
964 in_out_vrr->fixed.ramping_active = false;
965
966
967
968 if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED &&
969 in_out_vrr->fixed.ramping_active) {
970 update_v_total_for_static_ramp(
971 core_freesync, stream, in_out_vrr);
972 }
973 }
974
975 void mod_freesync_get_settings(struct mod_freesync *mod_freesync,
976 const struct mod_vrr_params *vrr,
977 unsigned int *v_total_min, unsigned int *v_total_max,
978 unsigned int *event_triggers,
979 unsigned int *window_min, unsigned int *window_max,
980 unsigned int *lfc_mid_point_in_us,
981 unsigned int *inserted_frames,
982 unsigned int *inserted_duration_in_us)
983 {
984 struct core_freesync *core_freesync = NULL;
985
986 if (mod_freesync == NULL)
987 return;
988
989 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
990
991 if (vrr->supported) {
992 *v_total_min = vrr->adjust.v_total_min;
993 *v_total_max = vrr->adjust.v_total_max;
994 *event_triggers = 0;
995 *lfc_mid_point_in_us = vrr->btr.mid_point_in_us;
996 *inserted_frames = vrr->btr.frames_to_insert;
997 *inserted_duration_in_us = vrr->btr.inserted_duration_in_us;
998 }
999 }
1000
1001 unsigned long long mod_freesync_calc_nominal_field_rate(
1002 const struct dc_stream_state *stream)
1003 {
1004 unsigned long long nominal_field_rate_in_uhz = 0;
1005 unsigned int total = stream->timing.h_total * stream->timing.v_total;
1006
1007
1008 nominal_field_rate_in_uhz = stream->timing.pix_clk_100hz / 10;
1009 nominal_field_rate_in_uhz *= 1000ULL * 1000ULL * 1000ULL;
1010
1011 nominal_field_rate_in_uhz = div_u64(nominal_field_rate_in_uhz, total);
1012
1013 return nominal_field_rate_in_uhz;
1014 }
1015
1016 bool mod_freesync_is_valid_range(struct mod_freesync *mod_freesync,
1017 const struct dc_stream_state *stream,
1018 uint32_t min_refresh_cap_in_uhz,
1019 uint32_t max_refresh_cap_in_uhz,
1020 uint32_t min_refresh_request_in_uhz,
1021 uint32_t max_refresh_request_in_uhz)
1022 {
1023
1024 unsigned long long nominal_field_rate_in_uhz =
1025 mod_freesync_calc_nominal_field_rate(stream);
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060 nominal_field_rate_in_uhz =
1061 div_u64(nominal_field_rate_in_uhz + 500000, 1000000);
1062 min_refresh_cap_in_uhz /= 1000000;
1063 max_refresh_cap_in_uhz /= 1000000;
1064 min_refresh_request_in_uhz /= 1000000;
1065 max_refresh_request_in_uhz /= 1000000;
1066
1067
1068 if (nominal_field_rate_in_uhz > max_refresh_cap_in_uhz ||
1069 nominal_field_rate_in_uhz < min_refresh_cap_in_uhz)
1070 return false;
1071
1072
1073 if (nominal_field_rate_in_uhz < max_refresh_cap_in_uhz)
1074 max_refresh_cap_in_uhz = nominal_field_rate_in_uhz;
1075
1076
1077 if (min_refresh_request_in_uhz > max_refresh_request_in_uhz)
1078 return false;
1079
1080
1081 if (min_refresh_request_in_uhz > max_refresh_cap_in_uhz ||
1082 min_refresh_request_in_uhz < min_refresh_cap_in_uhz)
1083 return false;
1084
1085
1086 if (max_refresh_request_in_uhz > max_refresh_cap_in_uhz ||
1087 max_refresh_request_in_uhz < min_refresh_cap_in_uhz)
1088 return false;
1089
1090
1091 if ((max_refresh_request_in_uhz != min_refresh_request_in_uhz) &&
1092 (max_refresh_request_in_uhz - min_refresh_request_in_uhz < 10))
1093 return false;
1094
1095 return true;
1096 }
1097