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
50struct core_freesync {
51 struct mod_freesync public;
52 struct dc *dc;
53};
54
55void setFieldWithMask(unsigned char *dest, unsigned int mask, unsigned int value)
56{
57 unsigned int shift = 0;
58
59 if (!mask || !dest)
60 return;
61
62 while (!((mask >> shift) & 1))
63 shift++;
64
65
66 *dest = *dest & ~mask;
67
68
69 value = value & (mask >> shift);
70
71 *dest = *dest | (value << shift);
72}
73
74
75#define VRR_VTEM_PB0 0
76#define VRR_VTEM_PB1 1
77#define VRR_VTEM_PB2 2
78#define VRR_VTEM_PB3 3
79#define VRR_VTEM_PB4 4
80#define VRR_VTEM_PB5 5
81#define VRR_VTEM_PB6 6
82
83#define VRR_VTEM_MD0 7
84#define VRR_VTEM_MD1 8
85#define VRR_VTEM_MD2 9
86#define VRR_VTEM_MD3 10
87
88
89
90
91#define MASK__VRR_VTEM_PB0__RESERVED0 0x01
92#define MASK__VRR_VTEM_PB0__SYNC 0x02
93#define MASK__VRR_VTEM_PB0__VFR 0x04
94#define MASK__VRR_VTEM_PB0__AFR 0x08
95#define MASK__VRR_VTEM_PB0__DS_TYPE 0x30
96
97
98
99
100#define MASK__VRR_VTEM_PB0__END 0x40
101#define MASK__VRR_VTEM_PB0__NEW 0x80
102
103
104#define MASK__VRR_VTEM_PB1__RESERVED1 0xFF
105
106
107#define MASK__VRR_VTEM_PB2__ORGANIZATION_ID 0xFF
108
109
110
111
112
113#define MASK__VRR_VTEM_PB3__DATA_SET_TAG_MSB 0xFF
114
115#define MASK__VRR_VTEM_PB4__DATA_SET_TAG_LSB 0xFF
116
117#define MASK__VRR_VTEM_PB5__DATA_SET_LENGTH_MSB 0xFF
118
119#define MASK__VRR_VTEM_PB6__DATA_SET_LENGTH_LSB 0xFF
120
121
122
123
124
125#define MASK__VRR_VTEM_MD0__VRR_EN 0x01
126#define MASK__VRR_VTEM_MD0__M_CONST 0x02
127#define MASK__VRR_VTEM_MD0__RESERVED2 0x0C
128#define MASK__VRR_VTEM_MD0__FVA_FACTOR_M1 0xF0
129
130
131#define MASK__VRR_VTEM_MD1__BASE_VFRONT 0xFF
132
133
134#define MASK__VRR_VTEM_MD2__BASE_REFRESH_RATE_98 0x03
135#define MASK__VRR_VTEM_MD2__RB 0x04
136#define MASK__VRR_VTEM_MD2__RESERVED3 0xF8
137
138
139#define MASK__VRR_VTEM_MD3__BASE_REFRESH_RATE_07 0xFF
140
141
142#define MOD_FREESYNC_TO_CORE(mod_freesync)\
143 container_of(mod_freesync, struct core_freesync, public)
144
145struct mod_freesync *mod_freesync_create(struct dc *dc)
146{
147 struct core_freesync *core_freesync =
148 kzalloc(sizeof(struct core_freesync), GFP_KERNEL);
149
150 if (core_freesync == NULL)
151 goto fail_alloc_context;
152
153 if (dc == NULL)
154 goto fail_construct;
155
156 core_freesync->dc = dc;
157 return &core_freesync->public;
158
159fail_construct:
160 kfree(core_freesync);
161
162fail_alloc_context:
163 return NULL;
164}
165
166void mod_freesync_destroy(struct mod_freesync *mod_freesync)
167{
168 struct core_freesync *core_freesync = NULL;
169 if (mod_freesync == NULL)
170 return;
171 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
172 kfree(core_freesync);
173}
174
175#if 0
176static unsigned int calc_refresh_in_uhz_from_duration(
177 unsigned int duration_in_ns)
178{
179 unsigned int refresh_in_uhz =
180 ((unsigned int)(div64_u64((1000000000ULL * 1000000),
181 duration_in_ns)));
182 return refresh_in_uhz;
183}
184#endif
185
186static unsigned int calc_duration_in_us_from_refresh_in_uhz(
187 unsigned int refresh_in_uhz)
188{
189 unsigned int duration_in_us =
190 ((unsigned int)(div64_u64((1000000000ULL * 1000),
191 refresh_in_uhz)));
192 return duration_in_us;
193}
194
195static unsigned int calc_duration_in_us_from_v_total(
196 const struct dc_stream_state *stream,
197 const struct mod_vrr_params *in_vrr,
198 unsigned int v_total)
199{
200 unsigned int duration_in_us =
201 (unsigned int)(div64_u64(((unsigned long long)(v_total)
202 * 10000) * stream->timing.h_total,
203 stream->timing.pix_clk_100hz));
204
205 return duration_in_us;
206}
207
208static unsigned int calc_v_total_from_refresh(
209 const struct dc_stream_state *stream,
210 unsigned int refresh_in_uhz)
211{
212 unsigned int v_total = stream->timing.v_total;
213 unsigned int frame_duration_in_ns;
214
215 frame_duration_in_ns =
216 ((unsigned int)(div64_u64((1000000000ULL * 1000000),
217 refresh_in_uhz)));
218
219 v_total = div64_u64(div64_u64(((unsigned long long)(
220 frame_duration_in_ns) * (stream->timing.pix_clk_100hz / 10)),
221 stream->timing.h_total), 1000000);
222
223
224 if (v_total < stream->timing.v_total) {
225 ASSERT(v_total < stream->timing.v_total);
226 v_total = stream->timing.v_total;
227 }
228
229 return v_total;
230}
231
232static unsigned int calc_v_total_from_duration(
233 const struct dc_stream_state *stream,
234 const struct mod_vrr_params *vrr,
235 unsigned int duration_in_us)
236{
237 unsigned int v_total = 0;
238
239 if (duration_in_us < vrr->min_duration_in_us)
240 duration_in_us = vrr->min_duration_in_us;
241
242 if (duration_in_us > vrr->max_duration_in_us)
243 duration_in_us = vrr->max_duration_in_us;
244
245 v_total = div64_u64(div64_u64(((unsigned long long)(
246 duration_in_us) * (stream->timing.pix_clk_100hz / 10)),
247 stream->timing.h_total), 1000);
248
249
250 if (v_total < stream->timing.v_total) {
251 ASSERT(v_total < stream->timing.v_total);
252 v_total = stream->timing.v_total;
253 }
254
255 return v_total;
256}
257
258static void update_v_total_for_static_ramp(
259 struct core_freesync *core_freesync,
260 const struct dc_stream_state *stream,
261 struct mod_vrr_params *in_out_vrr)
262{
263 unsigned int v_total = 0;
264 unsigned int current_duration_in_us =
265 calc_duration_in_us_from_v_total(
266 stream, in_out_vrr,
267 in_out_vrr->adjust.v_total_max);
268 unsigned int target_duration_in_us =
269 calc_duration_in_us_from_refresh_in_uhz(
270 in_out_vrr->fixed.target_refresh_in_uhz);
271 bool ramp_direction_is_up = (current_duration_in_us >
272 target_duration_in_us) ? true : false;
273
274
275 unsigned int frame_duration_ratio = div64_u64(1000000,
276 (1000 + div64_u64(((unsigned long long)(
277 STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME) *
278 current_duration_in_us),
279 1000000)));
280
281
282 unsigned int frame_duration_delta = div64_u64(((unsigned long long)(
283 current_duration_in_us) *
284 (1000 - frame_duration_ratio)), 1000);
285
286
287
288
289 unsigned int ramp_rate_interpolated = div64_u64(((unsigned long long)(
290 frame_duration_delta) * current_duration_in_us), 16666);
291
292
293 if (ramp_direction_is_up) {
294
295 current_duration_in_us -= ramp_rate_interpolated;
296
297
298 if (current_duration_in_us <= target_duration_in_us) {
299 in_out_vrr->fixed.ramping_active = false;
300 in_out_vrr->fixed.ramping_done = true;
301 current_duration_in_us =
302 calc_duration_in_us_from_refresh_in_uhz(
303 in_out_vrr->fixed.target_refresh_in_uhz);
304 }
305
306 } else {
307
308 current_duration_in_us += ramp_rate_interpolated;
309
310
311 if (current_duration_in_us >= target_duration_in_us) {
312 in_out_vrr->fixed.ramping_active = false;
313 in_out_vrr->fixed.ramping_done = true;
314 current_duration_in_us =
315 calc_duration_in_us_from_refresh_in_uhz(
316 in_out_vrr->fixed.target_refresh_in_uhz);
317 }
318 }
319
320 v_total = div64_u64(div64_u64(((unsigned long long)(
321 current_duration_in_us) * (stream->timing.pix_clk_100hz / 10)),
322 stream->timing.h_total), 1000);
323
324 in_out_vrr->adjust.v_total_min = v_total;
325 in_out_vrr->adjust.v_total_max = v_total;
326}
327
328static void apply_below_the_range(struct core_freesync *core_freesync,
329 const struct dc_stream_state *stream,
330 unsigned int last_render_time_in_us,
331 struct mod_vrr_params *in_out_vrr)
332{
333 unsigned int inserted_frame_duration_in_us = 0;
334 unsigned int mid_point_frames_ceil = 0;
335 unsigned int mid_point_frames_floor = 0;
336 unsigned int frame_time_in_us = 0;
337 unsigned int delta_from_mid_point_in_us_1 = 0xFFFFFFFF;
338 unsigned int delta_from_mid_point_in_us_2 = 0xFFFFFFFF;
339 unsigned int frames_to_insert = 0;
340 unsigned int min_frame_duration_in_ns = 0;
341 unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us;
342 unsigned int delta_from_mid_point_delta_in_us;
343
344 min_frame_duration_in_ns = ((unsigned int) (div64_u64(
345 (1000000000ULL * 1000000),
346 in_out_vrr->max_refresh_in_uhz)));
347
348
349 if (last_render_time_in_us + BTR_EXIT_MARGIN < max_render_time_in_us) {
350
351 if (in_out_vrr->btr.btr_active) {
352 in_out_vrr->btr.frame_counter = 0;
353 in_out_vrr->btr.btr_active = false;
354 }
355 } else if (last_render_time_in_us > max_render_time_in_us) {
356
357 in_out_vrr->btr.btr_active = true;
358 }
359
360
361 if (!in_out_vrr->btr.btr_active) {
362 in_out_vrr->btr.inserted_duration_in_us = 0;
363 in_out_vrr->btr.frames_to_insert = 0;
364 in_out_vrr->btr.frame_counter = 0;
365
366
367 in_out_vrr->adjust.v_total_min =
368 calc_v_total_from_refresh(stream,
369 in_out_vrr->max_refresh_in_uhz);
370 in_out_vrr->adjust.v_total_max =
371 calc_v_total_from_refresh(stream,
372 in_out_vrr->min_refresh_in_uhz);
373
374 } else {
375
376
377
378
379 mid_point_frames_ceil = (last_render_time_in_us +
380 in_out_vrr->btr.mid_point_in_us - 1) /
381 in_out_vrr->btr.mid_point_in_us;
382
383 if (mid_point_frames_ceil > 0) {
384 frame_time_in_us = last_render_time_in_us /
385 mid_point_frames_ceil;
386 delta_from_mid_point_in_us_1 =
387 (in_out_vrr->btr.mid_point_in_us >
388 frame_time_in_us) ?
389 (in_out_vrr->btr.mid_point_in_us - frame_time_in_us) :
390 (frame_time_in_us - in_out_vrr->btr.mid_point_in_us);
391 }
392
393
394
395
396 mid_point_frames_floor = last_render_time_in_us /
397 in_out_vrr->btr.mid_point_in_us;
398
399 if (mid_point_frames_floor > 0) {
400
401 frame_time_in_us = last_render_time_in_us /
402 mid_point_frames_floor;
403 delta_from_mid_point_in_us_2 =
404 (in_out_vrr->btr.mid_point_in_us >
405 frame_time_in_us) ?
406 (in_out_vrr->btr.mid_point_in_us - frame_time_in_us) :
407 (frame_time_in_us - in_out_vrr->btr.mid_point_in_us);
408 }
409
410
411
412
413 if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) {
414 frames_to_insert = mid_point_frames_ceil;
415 delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_2 -
416 delta_from_mid_point_in_us_1;
417 } else {
418 frames_to_insert = mid_point_frames_floor;
419 delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_1 -
420 delta_from_mid_point_in_us_2;
421 }
422
423
424
425
426 if (in_out_vrr->btr.frames_to_insert != 0 &&
427 delta_from_mid_point_delta_in_us < BTR_DRIFT_MARGIN) {
428 if (((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) <
429 in_out_vrr->max_duration_in_us) &&
430 ((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) >
431 in_out_vrr->min_duration_in_us))
432 frames_to_insert = in_out_vrr->btr.frames_to_insert;
433 }
434
435
436
437
438 if (frames_to_insert > 0)
439 inserted_frame_duration_in_us = last_render_time_in_us /
440 frames_to_insert;
441
442 if (inserted_frame_duration_in_us < in_out_vrr->min_duration_in_us)
443 inserted_frame_duration_in_us = in_out_vrr->min_duration_in_us;
444
445
446 in_out_vrr->btr.inserted_duration_in_us =
447 inserted_frame_duration_in_us;
448 in_out_vrr->btr.frames_to_insert = frames_to_insert;
449 in_out_vrr->btr.frame_counter = frames_to_insert;
450 }
451}
452
453static void apply_fixed_refresh(struct core_freesync *core_freesync,
454 const struct dc_stream_state *stream,
455 unsigned int last_render_time_in_us,
456 struct mod_vrr_params *in_out_vrr)
457{
458 bool update = false;
459 unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us;
460
461
462 unsigned int exit_refresh_rate_in_milli_hz = ((1000000000/max_render_time_in_us)
463 + (1000*FIXED_REFRESH_EXIT_MARGIN_IN_HZ));
464 unsigned int exit_frame_duration_in_us = 1000000000/exit_refresh_rate_in_milli_hz;
465
466 if (last_render_time_in_us < exit_frame_duration_in_us) {
467
468 if (in_out_vrr->fixed.fixed_active) {
469 in_out_vrr->fixed.frame_counter++;
470
471 if (in_out_vrr->fixed.frame_counter >
472 FIXED_REFRESH_EXIT_FRAME_COUNT) {
473 in_out_vrr->fixed.frame_counter = 0;
474 in_out_vrr->fixed.fixed_active = false;
475 in_out_vrr->fixed.target_refresh_in_uhz = 0;
476 update = true;
477 }
478 }
479 } else if (last_render_time_in_us > max_render_time_in_us) {
480
481 if (!in_out_vrr->fixed.fixed_active) {
482 in_out_vrr->fixed.frame_counter++;
483
484 if (in_out_vrr->fixed.frame_counter >
485 FIXED_REFRESH_ENTER_FRAME_COUNT) {
486 in_out_vrr->fixed.frame_counter = 0;
487 in_out_vrr->fixed.fixed_active = true;
488 in_out_vrr->fixed.target_refresh_in_uhz =
489 in_out_vrr->max_refresh_in_uhz;
490 update = true;
491 }
492 }
493 }
494
495 if (update) {
496 if (in_out_vrr->fixed.fixed_active) {
497 in_out_vrr->adjust.v_total_min =
498 calc_v_total_from_refresh(
499 stream, in_out_vrr->max_refresh_in_uhz);
500 in_out_vrr->adjust.v_total_max =
501 in_out_vrr->adjust.v_total_min;
502 } else {
503 in_out_vrr->adjust.v_total_min =
504 calc_v_total_from_refresh(stream,
505 in_out_vrr->max_refresh_in_uhz);
506 in_out_vrr->adjust.v_total_max =
507 calc_v_total_from_refresh(stream,
508 in_out_vrr->min_refresh_in_uhz);
509 }
510 }
511}
512
513static bool vrr_settings_require_update(struct core_freesync *core_freesync,
514 struct mod_freesync_config *in_config,
515 unsigned int min_refresh_in_uhz,
516 unsigned int max_refresh_in_uhz,
517 struct mod_vrr_params *in_vrr)
518{
519 if (in_vrr->state != in_config->state) {
520 return true;
521 } else if (in_vrr->state == VRR_STATE_ACTIVE_FIXED &&
522 in_vrr->fixed.target_refresh_in_uhz !=
523 in_config->min_refresh_in_uhz) {
524 return true;
525 } else if (in_vrr->min_refresh_in_uhz != min_refresh_in_uhz) {
526 return true;
527 } else if (in_vrr->max_refresh_in_uhz != max_refresh_in_uhz) {
528 return true;
529 }
530
531 return false;
532}
533
534bool mod_freesync_get_vmin_vmax(struct mod_freesync *mod_freesync,
535 const struct dc_stream_state *stream,
536 unsigned int *vmin,
537 unsigned int *vmax)
538{
539 *vmin = stream->adjust.v_total_min;
540 *vmax = stream->adjust.v_total_max;
541
542 return true;
543}
544
545bool mod_freesync_get_v_position(struct mod_freesync *mod_freesync,
546 struct dc_stream_state *stream,
547 unsigned int *nom_v_pos,
548 unsigned int *v_pos)
549{
550 struct core_freesync *core_freesync = NULL;
551 struct crtc_position position;
552
553 if (mod_freesync == NULL)
554 return false;
555
556 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
557
558 if (dc_stream_get_crtc_position(core_freesync->dc, &stream, 1,
559 &position.vertical_count,
560 &position.nominal_vcount)) {
561
562 *nom_v_pos = position.nominal_vcount;
563 *v_pos = position.vertical_count;
564
565 return true;
566 }
567
568 return false;
569}
570
571static void build_vrr_infopacket_header_vtem(enum signal_type signal,
572 struct dc_info_packet *infopacket)
573{
574
575
576
577 infopacket->hb0 = 0x7F;
578 infopacket->hb1 = 0xC0;
579 infopacket->hb2 = 0x00;
580
581 setFieldWithMask(&infopacket->sb[VRR_VTEM_PB0], MASK__VRR_VTEM_PB0__VFR, 1);
582 setFieldWithMask(&infopacket->sb[VRR_VTEM_PB2], MASK__VRR_VTEM_PB2__ORGANIZATION_ID, 1);
583 setFieldWithMask(&infopacket->sb[VRR_VTEM_PB3], MASK__VRR_VTEM_PB3__DATA_SET_TAG_MSB, 0);
584 setFieldWithMask(&infopacket->sb[VRR_VTEM_PB4], MASK__VRR_VTEM_PB4__DATA_SET_TAG_LSB, 1);
585 setFieldWithMask(&infopacket->sb[VRR_VTEM_PB5], MASK__VRR_VTEM_PB5__DATA_SET_LENGTH_MSB, 0);
586 setFieldWithMask(&infopacket->sb[VRR_VTEM_PB6], MASK__VRR_VTEM_PB6__DATA_SET_LENGTH_LSB, 4);
587}
588
589static void build_vrr_infopacket_header_v1(enum signal_type signal,
590 struct dc_info_packet *infopacket,
591 unsigned int *payload_size)
592{
593 if (dc_is_hdmi_signal(signal)) {
594
595
596
597
598
599
600 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
601
602
603 infopacket->hb1 = 0x01;
604
605
606 infopacket->hb2 = 0x08;
607
608 *payload_size = 0x08;
609
610 } else if (dc_is_dp_signal(signal)) {
611
612
613
614
615
616
617 infopacket->hb0 = 0x00;
618
619
620
621
622 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
623
624
625
626
627 infopacket->hb2 = 0x1B;
628
629
630
631
632 infopacket->hb3 = 0x04;
633
634 *payload_size = 0x1B;
635 }
636}
637
638static void build_vrr_infopacket_header_v2(enum signal_type signal,
639 struct dc_info_packet *infopacket,
640 unsigned int *payload_size)
641{
642 if (dc_is_hdmi_signal(signal)) {
643
644
645
646
647
648
649 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
650
651
652 infopacket->hb1 = 0x02;
653
654
655 infopacket->hb2 = 0x09;
656
657 *payload_size = 0x0A;
658
659 } else if (dc_is_dp_signal(signal)) {
660
661
662
663
664
665
666 infopacket->hb0 = 0x00;
667
668
669
670
671 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
672
673
674
675
676 infopacket->hb2 = 0x1B;
677
678
679
680
681 infopacket->hb3 = 0x08;
682
683 *payload_size = 0x1B;
684 }
685}
686
687static void build_vrr_vtem_infopacket_data(const struct dc_stream_state *stream,
688 const struct mod_vrr_params *vrr,
689 struct dc_info_packet *infopacket)
690{
691 unsigned int fieldRateInHz;
692
693 if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
694 vrr->state == VRR_STATE_ACTIVE_FIXED) {
695 setFieldWithMask(&infopacket->sb[VRR_VTEM_MD0], MASK__VRR_VTEM_MD0__VRR_EN, 1);
696 } else {
697 setFieldWithMask(&infopacket->sb[VRR_VTEM_MD0], MASK__VRR_VTEM_MD0__VRR_EN, 0);
698 }
699
700 if (!stream->timing.vic) {
701 setFieldWithMask(&infopacket->sb[VRR_VTEM_MD1], MASK__VRR_VTEM_MD1__BASE_VFRONT,
702 stream->timing.v_front_porch);
703
704
705
706
707
708
709
710
711
712
713
714 fieldRateInHz = (stream->timing.pix_clk_100hz * 100)/
715 (stream->timing.h_total * stream->timing.v_total);
716
717 setFieldWithMask(&infopacket->sb[VRR_VTEM_MD2], MASK__VRR_VTEM_MD2__BASE_REFRESH_RATE_98,
718 fieldRateInHz >> 8);
719 setFieldWithMask(&infopacket->sb[VRR_VTEM_MD3], MASK__VRR_VTEM_MD3__BASE_REFRESH_RATE_07,
720 fieldRateInHz);
721
722 }
723 infopacket->valid = true;
724}
725
726static void build_vrr_infopacket_data(const struct mod_vrr_params *vrr,
727 struct dc_info_packet *infopacket)
728{
729
730 infopacket->sb[1] = 0x1A;
731
732
733 infopacket->sb[2] = 0x00;
734
735
736 infopacket->sb[3] = 0x00;
737
738
739
740
741
742
743
744
745 if (vrr->state != VRR_STATE_UNSUPPORTED)
746 infopacket->sb[6] |= 0x01;
747
748
749 if (vrr->state != VRR_STATE_DISABLED &&
750 vrr->state != VRR_STATE_UNSUPPORTED)
751 infopacket->sb[6] |= 0x02;
752
753
754 if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
755 vrr->state == VRR_STATE_ACTIVE_FIXED)
756 infopacket->sb[6] |= 0x04;
757
758
759 infopacket->sb[7] = (unsigned char)(vrr->min_refresh_in_uhz / 1000000);
760
761
762
763
764 infopacket->sb[8] = (unsigned char)(vrr->max_refresh_in_uhz / 1000000);
765
766
767
768 infopacket->sb[9] = 0;
769 infopacket->sb[10] = 0;
770}
771
772static void build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf,
773 struct dc_info_packet *infopacket)
774{
775 if (app_tf != TRANSFER_FUNC_UNKNOWN) {
776 infopacket->valid = true;
777
778 infopacket->sb[6] |= 0x08;
779
780 if (app_tf == TRANSFER_FUNC_GAMMA_22) {
781 infopacket->sb[9] |= 0x04;
782 }
783 }
784}
785
786static void build_vrr_infopacket_checksum(unsigned int *payload_size,
787 struct dc_info_packet *infopacket)
788{
789
790 unsigned int idx = 0;
791 unsigned char checksum = 0;
792
793 checksum += infopacket->hb0;
794 checksum += infopacket->hb1;
795 checksum += infopacket->hb2;
796 checksum += infopacket->hb3;
797
798 for (idx = 1; idx <= *payload_size; idx++)
799 checksum += infopacket->sb[idx];
800
801
802 infopacket->sb[0] = (unsigned char)(0x100 - checksum);
803
804 infopacket->valid = true;
805}
806
807static void build_vrr_infopacket_v1(enum signal_type signal,
808 const struct mod_vrr_params *vrr,
809 struct dc_info_packet *infopacket)
810{
811
812 unsigned int payload_size = 0;
813
814 build_vrr_infopacket_header_v1(signal, infopacket, &payload_size);
815 build_vrr_infopacket_data(vrr, infopacket);
816 build_vrr_infopacket_checksum(&payload_size, infopacket);
817
818 infopacket->valid = true;
819}
820
821static void build_vrr_infopacket_v2(enum signal_type signal,
822 const struct mod_vrr_params *vrr,
823 enum color_transfer_func app_tf,
824 struct dc_info_packet *infopacket)
825{
826 unsigned int payload_size = 0;
827
828 build_vrr_infopacket_header_v2(signal, infopacket, &payload_size);
829 build_vrr_infopacket_data(vrr, infopacket);
830
831 build_vrr_infopacket_fs2_data(app_tf, infopacket);
832
833 build_vrr_infopacket_checksum(&payload_size, infopacket);
834
835 infopacket->valid = true;
836}
837
838static void build_vrr_infopacket_vtem(const struct dc_stream_state *stream,
839 const struct mod_vrr_params *vrr,
840 struct dc_info_packet *infopacket)
841{
842
843
844 memset(infopacket, 0, sizeof(struct dc_info_packet));
845
846
847 build_vrr_infopacket_header_vtem(stream->signal, infopacket);
848 build_vrr_vtem_infopacket_data(stream, vrr, infopacket);
849
850 infopacket->valid = true;
851}
852
853void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync,
854 const struct dc_stream_state *stream,
855 const struct mod_vrr_params *vrr,
856 enum vrr_packet_type packet_type,
857 enum color_transfer_func app_tf,
858 struct dc_info_packet *infopacket)
859{
860
861
862
863
864
865 if (!vrr->supported || (!vrr->send_info_frame && packet_type != PACKET_TYPE_VTEM))
866 return;
867
868 switch (packet_type) {
869 case PACKET_TYPE_FS2:
870 build_vrr_infopacket_v2(stream->signal, vrr, app_tf, infopacket);
871 break;
872 case PACKET_TYPE_VTEM:
873 build_vrr_infopacket_vtem(stream, vrr, infopacket);
874 break;
875 case PACKET_TYPE_VRR:
876 case PACKET_TYPE_FS1:
877 default:
878 build_vrr_infopacket_v1(stream->signal, vrr, infopacket);
879 }
880}
881
882void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync,
883 const struct dc_stream_state *stream,
884 struct mod_freesync_config *in_config,
885 struct mod_vrr_params *in_out_vrr)
886{
887 struct core_freesync *core_freesync = NULL;
888 unsigned long long nominal_field_rate_in_uhz = 0;
889 unsigned int refresh_range = 0;
890 unsigned int min_refresh_in_uhz = 0;
891 unsigned int max_refresh_in_uhz = 0;
892
893 if (mod_freesync == NULL)
894 return;
895
896 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
897
898
899 nominal_field_rate_in_uhz =
900 mod_freesync_calc_nominal_field_rate(stream);
901
902 min_refresh_in_uhz = in_config->min_refresh_in_uhz;
903 max_refresh_in_uhz = in_config->max_refresh_in_uhz;
904
905
906 if (min_refresh_in_uhz > max_refresh_in_uhz)
907 min_refresh_in_uhz = max_refresh_in_uhz;
908
909
910 if (max_refresh_in_uhz > nominal_field_rate_in_uhz)
911 max_refresh_in_uhz = nominal_field_rate_in_uhz;
912
913
914 if (min_refresh_in_uhz > nominal_field_rate_in_uhz)
915 min_refresh_in_uhz = nominal_field_rate_in_uhz;
916
917 if (!vrr_settings_require_update(core_freesync,
918 in_config, min_refresh_in_uhz, max_refresh_in_uhz,
919 in_out_vrr))
920 return;
921
922 in_out_vrr->state = in_config->state;
923 in_out_vrr->send_info_frame = in_config->vsif_supported;
924
925 if (in_config->state == VRR_STATE_UNSUPPORTED) {
926 in_out_vrr->state = VRR_STATE_UNSUPPORTED;
927 in_out_vrr->supported = false;
928 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
929 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
930
931 return;
932
933 } else {
934 in_out_vrr->min_refresh_in_uhz = min_refresh_in_uhz;
935 in_out_vrr->max_duration_in_us =
936 calc_duration_in_us_from_refresh_in_uhz(
937 min_refresh_in_uhz);
938
939 in_out_vrr->max_refresh_in_uhz = max_refresh_in_uhz;
940 in_out_vrr->min_duration_in_us =
941 calc_duration_in_us_from_refresh_in_uhz(
942 max_refresh_in_uhz);
943
944 refresh_range = in_out_vrr->max_refresh_in_uhz -
945 in_out_vrr->min_refresh_in_uhz;
946
947 in_out_vrr->supported = true;
948 }
949
950 in_out_vrr->fixed.ramping_active = in_config->ramping;
951
952 in_out_vrr->btr.btr_enabled = in_config->btr;
953 if (in_out_vrr->max_refresh_in_uhz <
954 2 * in_out_vrr->min_refresh_in_uhz)
955 in_out_vrr->btr.btr_enabled = false;
956 in_out_vrr->btr.btr_active = false;
957 in_out_vrr->btr.inserted_duration_in_us = 0;
958 in_out_vrr->btr.frames_to_insert = 0;
959 in_out_vrr->btr.frame_counter = 0;
960 in_out_vrr->btr.mid_point_in_us =
961 in_out_vrr->min_duration_in_us +
962 (in_out_vrr->max_duration_in_us -
963 in_out_vrr->min_duration_in_us) / 2;
964
965 if (in_out_vrr->state == VRR_STATE_UNSUPPORTED) {
966 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
967 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
968 } else if (in_out_vrr->state == VRR_STATE_DISABLED) {
969 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
970 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
971 } else if (in_out_vrr->state == VRR_STATE_INACTIVE) {
972 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
973 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
974 } else if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE &&
975 refresh_range >= MIN_REFRESH_RANGE_IN_US) {
976 in_out_vrr->adjust.v_total_min =
977 calc_v_total_from_refresh(stream,
978 in_out_vrr->max_refresh_in_uhz);
979 in_out_vrr->adjust.v_total_max =
980 calc_v_total_from_refresh(stream,
981 in_out_vrr->min_refresh_in_uhz);
982 } else if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED) {
983 in_out_vrr->fixed.target_refresh_in_uhz =
984 in_out_vrr->min_refresh_in_uhz;
985 if (in_out_vrr->fixed.ramping_active &&
986 in_out_vrr->fixed.fixed_active) {
987
988
989
990 in_out_vrr->fixed.fixed_active = true;
991 } else {
992 in_out_vrr->fixed.fixed_active = true;
993 in_out_vrr->adjust.v_total_min =
994 calc_v_total_from_refresh(stream,
995 in_out_vrr->fixed.target_refresh_in_uhz);
996 in_out_vrr->adjust.v_total_max =
997 in_out_vrr->adjust.v_total_min;
998 }
999 } else {
1000 in_out_vrr->state = VRR_STATE_INACTIVE;
1001 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1002 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1003 }
1004}
1005
1006void mod_freesync_handle_preflip(struct mod_freesync *mod_freesync,
1007 const struct dc_plane_state *plane,
1008 const struct dc_stream_state *stream,
1009 unsigned int curr_time_stamp_in_us,
1010 struct mod_vrr_params *in_out_vrr)
1011{
1012 struct core_freesync *core_freesync = NULL;
1013 unsigned int last_render_time_in_us = 0;
1014 unsigned int average_render_time_in_us = 0;
1015
1016 if (mod_freesync == NULL)
1017 return;
1018
1019 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1020
1021 if (in_out_vrr->supported &&
1022 in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE) {
1023 unsigned int i = 0;
1024 unsigned int oldest_index = plane->time.index + 1;
1025
1026 if (oldest_index >= DC_PLANE_UPDATE_TIMES_MAX)
1027 oldest_index = 0;
1028
1029 last_render_time_in_us = curr_time_stamp_in_us -
1030 plane->time.prev_update_time_in_us;
1031
1032
1033 for (i = 0; i < DC_PLANE_UPDATE_TIMES_MAX; i++) {
1034 average_render_time_in_us +=
1035 plane->time.time_elapsed_in_us[i];
1036 }
1037 average_render_time_in_us -=
1038 plane->time.time_elapsed_in_us[oldest_index];
1039
1040
1041 average_render_time_in_us += last_render_time_in_us;
1042 average_render_time_in_us /= DC_PLANE_UPDATE_TIMES_MAX;
1043
1044 if (in_out_vrr->btr.btr_enabled) {
1045 apply_below_the_range(core_freesync,
1046 stream,
1047 last_render_time_in_us,
1048 in_out_vrr);
1049 } else {
1050 apply_fixed_refresh(core_freesync,
1051 stream,
1052 last_render_time_in_us,
1053 in_out_vrr);
1054 }
1055
1056 }
1057}
1058
1059void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync,
1060 const struct dc_stream_state *stream,
1061 struct mod_vrr_params *in_out_vrr)
1062{
1063 struct core_freesync *core_freesync = NULL;
1064
1065 if ((mod_freesync == NULL) || (stream == NULL) || (in_out_vrr == NULL))
1066 return;
1067
1068 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1069
1070 if (in_out_vrr->supported == false)
1071 return;
1072
1073
1074
1075
1076 if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE &&
1077 in_out_vrr->btr.btr_active) {
1078
1079
1080
1081
1082
1083
1084
1085 if (in_out_vrr->btr.frames_to_insert ==
1086 in_out_vrr->btr.frame_counter) {
1087 in_out_vrr->adjust.v_total_min =
1088 calc_v_total_from_duration(stream,
1089 in_out_vrr,
1090 in_out_vrr->btr.inserted_duration_in_us);
1091 in_out_vrr->adjust.v_total_max =
1092 in_out_vrr->adjust.v_total_min;
1093 }
1094
1095 if (in_out_vrr->btr.frame_counter > 0)
1096 in_out_vrr->btr.frame_counter--;
1097
1098
1099 if (in_out_vrr->btr.frame_counter == 0) {
1100 in_out_vrr->adjust.v_total_min =
1101 calc_v_total_from_refresh(stream,
1102 in_out_vrr->max_refresh_in_uhz);
1103 in_out_vrr->adjust.v_total_max =
1104 calc_v_total_from_refresh(stream,
1105 in_out_vrr->min_refresh_in_uhz);
1106 }
1107 }
1108
1109
1110
1111
1112 if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE)
1113 in_out_vrr->fixed.ramping_active = false;
1114
1115
1116
1117 if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED &&
1118 in_out_vrr->fixed.ramping_active) {
1119 update_v_total_for_static_ramp(
1120 core_freesync, stream, in_out_vrr);
1121 }
1122}
1123
1124void mod_freesync_get_settings(struct mod_freesync *mod_freesync,
1125 const struct mod_vrr_params *vrr,
1126 unsigned int *v_total_min, unsigned int *v_total_max,
1127 unsigned int *event_triggers,
1128 unsigned int *window_min, unsigned int *window_max,
1129 unsigned int *lfc_mid_point_in_us,
1130 unsigned int *inserted_frames,
1131 unsigned int *inserted_duration_in_us)
1132{
1133 struct core_freesync *core_freesync = NULL;
1134
1135 if (mod_freesync == NULL)
1136 return;
1137
1138 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1139
1140 if (vrr->supported) {
1141 *v_total_min = vrr->adjust.v_total_min;
1142 *v_total_max = vrr->adjust.v_total_max;
1143 *event_triggers = 0;
1144 *lfc_mid_point_in_us = vrr->btr.mid_point_in_us;
1145 *inserted_frames = vrr->btr.frames_to_insert;
1146 *inserted_duration_in_us = vrr->btr.inserted_duration_in_us;
1147 }
1148}
1149
1150unsigned long long mod_freesync_calc_nominal_field_rate(
1151 const struct dc_stream_state *stream)
1152{
1153 unsigned long long nominal_field_rate_in_uhz = 0;
1154
1155
1156 nominal_field_rate_in_uhz = stream->timing.pix_clk_100hz / 10;
1157 nominal_field_rate_in_uhz *= 1000ULL * 1000ULL * 1000ULL;
1158 nominal_field_rate_in_uhz = div_u64(nominal_field_rate_in_uhz,
1159 stream->timing.h_total);
1160 nominal_field_rate_in_uhz = div_u64(nominal_field_rate_in_uhz,
1161 stream->timing.v_total);
1162
1163 return nominal_field_rate_in_uhz;
1164}
1165
1166bool mod_freesync_is_valid_range(struct mod_freesync *mod_freesync,
1167 const struct dc_stream_state *stream,
1168 uint32_t min_refresh_cap_in_uhz,
1169 uint32_t max_refresh_cap_in_uhz,
1170 uint32_t min_refresh_request_in_uhz,
1171 uint32_t max_refresh_request_in_uhz)
1172{
1173
1174 unsigned long long nominal_field_rate_in_uhz =
1175 mod_freesync_calc_nominal_field_rate(stream);
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210 nominal_field_rate_in_uhz =
1211 div_u64(nominal_field_rate_in_uhz + 500000, 1000000);
1212 min_refresh_cap_in_uhz /= 1000000;
1213 max_refresh_cap_in_uhz /= 1000000;
1214 min_refresh_request_in_uhz /= 1000000;
1215 max_refresh_request_in_uhz /= 1000000;
1216
1217
1218 if (nominal_field_rate_in_uhz > max_refresh_cap_in_uhz ||
1219 nominal_field_rate_in_uhz < min_refresh_cap_in_uhz)
1220 return false;
1221
1222
1223 if (nominal_field_rate_in_uhz < max_refresh_cap_in_uhz)
1224 max_refresh_cap_in_uhz = nominal_field_rate_in_uhz;
1225
1226
1227 if (min_refresh_request_in_uhz > max_refresh_request_in_uhz)
1228 return false;
1229
1230
1231 if (min_refresh_request_in_uhz > max_refresh_cap_in_uhz ||
1232 min_refresh_request_in_uhz < min_refresh_cap_in_uhz)
1233 return false;
1234
1235
1236 if (max_refresh_request_in_uhz > max_refresh_cap_in_uhz ||
1237 max_refresh_request_in_uhz < min_refresh_cap_in_uhz)
1238 return false;
1239
1240
1241 if ((max_refresh_request_in_uhz != min_refresh_request_in_uhz) &&
1242 (max_refresh_request_in_uhz - min_refresh_request_in_uhz < 10))
1243 return false;
1244
1245 return true;
1246}
1247
1248