Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1/*
2 * Copyright 2016 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: AMD
23 *
24 */
25
26#include "dm_services.h"
27#include "dc.h"
28#include "mod_freesync.h"
29#include "core_types.h"
30
31#define MOD_FREESYNC_MAX_CONCURRENT_STREAMS 32
32
33#define MIN_REFRESH_RANGE_IN_US 10000000
34/* Refresh rate ramp at a fixed rate of 65 Hz/second */
35#define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65)
36/* Number of elements in the render times cache array */
37#define RENDER_TIMES_MAX_COUNT 10
38/* Threshold to exit BTR (to avoid frequent enter-exits at the lower limit) */
39#define BTR_EXIT_MARGIN 2000
40/* Number of consecutive frames to check before entering/exiting fixed refresh*/
41#define FIXED_REFRESH_ENTER_FRAME_COUNT 5
42#define FIXED_REFRESH_EXIT_FRAME_COUNT 5
43
44struct core_freesync {
45 struct mod_freesync public;
46 struct dc *dc;
47};
48
49#define MOD_FREESYNC_TO_CORE(mod_freesync)\
50 container_of(mod_freesync, struct core_freesync, public)
51
52struct mod_freesync *mod_freesync_create(struct dc *dc)
53{
54 struct core_freesync *core_freesync =
55 kzalloc(sizeof(struct core_freesync), GFP_KERNEL);
56
57 if (core_freesync == NULL)
58 goto fail_alloc_context;
59
60 if (dc == NULL)
61 goto fail_construct;
62
63 core_freesync->dc = dc;
64 return &core_freesync->public;
65
66fail_construct:
67 kfree(core_freesync);
68
69fail_alloc_context:
70 return NULL;
71}
72
73void mod_freesync_destroy(struct mod_freesync *mod_freesync)
74{
75 struct core_freesync *core_freesync = NULL;
76 if (mod_freesync == NULL)
77 return;
78 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
79 kfree(core_freesync);
80}
81
82#if 0 /* unused currently */
83static unsigned int calc_refresh_in_uhz_from_duration(
84 unsigned int duration_in_ns)
85{
86 unsigned int refresh_in_uhz =
87 ((unsigned int)(div64_u64((1000000000ULL * 1000000),
88 duration_in_ns)));
89 return refresh_in_uhz;
90}
91#endif
92
93static unsigned int calc_duration_in_us_from_refresh_in_uhz(
94 unsigned int refresh_in_uhz)
95{
96 unsigned int duration_in_us =
97 ((unsigned int)(div64_u64((1000000000ULL * 1000),
98 refresh_in_uhz)));
99 return duration_in_us;
100}
101
102static unsigned int calc_duration_in_us_from_v_total(
103 const struct dc_stream_state *stream,
104 const struct mod_vrr_params *in_vrr,
105 unsigned int v_total)
106{
107 unsigned int duration_in_us =
108 (unsigned int)(div64_u64(((unsigned long long)(v_total)
109 * 1000) * stream->timing.h_total,
110 stream->timing.pix_clk_khz));
111
112 return duration_in_us;
113}
114
115static unsigned int calc_v_total_from_refresh(
116 const struct dc_stream_state *stream,
117 unsigned int refresh_in_uhz)
118{
119 unsigned int v_total = stream->timing.v_total;
120 unsigned int frame_duration_in_ns;
121
122 frame_duration_in_ns =
123 ((unsigned int)(div64_u64((1000000000ULL * 1000000),
124 refresh_in_uhz)));
125
126 v_total = div64_u64(div64_u64(((unsigned long long)(
127 frame_duration_in_ns) * stream->timing.pix_clk_khz),
128 stream->timing.h_total), 1000000);
129
130 /* v_total cannot be less than nominal */
131 if (v_total < stream->timing.v_total) {
132 ASSERT(v_total < stream->timing.v_total);
133 v_total = stream->timing.v_total;
134 }
135
136 return v_total;
137}
138
139static unsigned int calc_v_total_from_duration(
140 const struct dc_stream_state *stream,
141 const struct mod_vrr_params *vrr,
142 unsigned int duration_in_us)
143{
144 unsigned int v_total = 0;
145
146 if (duration_in_us < vrr->min_duration_in_us)
147 duration_in_us = vrr->min_duration_in_us;
148
149 if (duration_in_us > vrr->max_duration_in_us)
150 duration_in_us = vrr->max_duration_in_us;
151
152 v_total = div64_u64(div64_u64(((unsigned long long)(
153 duration_in_us) * stream->timing.pix_clk_khz),
154 stream->timing.h_total), 1000);
155
156 /* v_total cannot be less than nominal */
157 if (v_total < stream->timing.v_total) {
158 ASSERT(v_total < stream->timing.v_total);
159 v_total = stream->timing.v_total;
160 }
161
162 return v_total;
163}
164
165static void update_v_total_for_static_ramp(
166 struct core_freesync *core_freesync,
167 const struct dc_stream_state *stream,
168 struct mod_vrr_params *in_out_vrr)
169{
170 unsigned int v_total = 0;
171 unsigned int current_duration_in_us =
172 calc_duration_in_us_from_v_total(
173 stream, in_out_vrr,
174 in_out_vrr->adjust.v_total_max);
175 unsigned int target_duration_in_us =
176 calc_duration_in_us_from_refresh_in_uhz(
177 in_out_vrr->fixed.target_refresh_in_uhz);
178 bool ramp_direction_is_up = (current_duration_in_us >
179 target_duration_in_us) ? true : false;
180
181 /* Calc ratio between new and current frame duration with 3 digit */
182 unsigned int frame_duration_ratio = div64_u64(1000000,
183 (1000 + div64_u64(((unsigned long long)(
184 STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME) *
185 current_duration_in_us),
186 1000000)));
187
188 /* Calculate delta between new and current frame duration in us */
189 unsigned int frame_duration_delta = div64_u64(((unsigned long long)(
190 current_duration_in_us) *
191 (1000 - frame_duration_ratio)), 1000);
192
193 /* Adjust frame duration delta based on ratio between current and
194 * standard frame duration (frame duration at 60 Hz refresh rate).
195 */
196 unsigned int ramp_rate_interpolated = div64_u64(((unsigned long long)(
197 frame_duration_delta) * current_duration_in_us), 16666);
198
199 /* Going to a higher refresh rate (lower frame duration) */
200 if (ramp_direction_is_up) {
201 /* reduce frame duration */
202 current_duration_in_us -= ramp_rate_interpolated;
203
204 /* adjust for frame duration below min */
205 if (current_duration_in_us <= target_duration_in_us) {
206 in_out_vrr->fixed.ramping_active = false;
207 in_out_vrr->fixed.ramping_done = true;
208 current_duration_in_us =
209 calc_duration_in_us_from_refresh_in_uhz(
210 in_out_vrr->fixed.target_refresh_in_uhz);
211 }
212 /* Going to a lower refresh rate (larger frame duration) */
213 } else {
214 /* increase frame duration */
215 current_duration_in_us += ramp_rate_interpolated;
216
217 /* adjust for frame duration above max */
218 if (current_duration_in_us >= target_duration_in_us) {
219 in_out_vrr->fixed.ramping_active = false;
220 in_out_vrr->fixed.ramping_done = true;
221 current_duration_in_us =
222 calc_duration_in_us_from_refresh_in_uhz(
223 in_out_vrr->fixed.target_refresh_in_uhz);
224 }
225 }
226
227 v_total = div64_u64(div64_u64(((unsigned long long)(
228 current_duration_in_us) * stream->timing.pix_clk_khz),
229 stream->timing.h_total), 1000);
230
231 in_out_vrr->adjust.v_total_min = v_total;
232 in_out_vrr->adjust.v_total_max = v_total;
233}
234
235static void apply_below_the_range(struct core_freesync *core_freesync,
236 const struct dc_stream_state *stream,
237 unsigned int last_render_time_in_us,
238 struct mod_vrr_params *in_out_vrr)
239{
240 unsigned int inserted_frame_duration_in_us = 0;
241 unsigned int mid_point_frames_ceil = 0;
242 unsigned int mid_point_frames_floor = 0;
243 unsigned int frame_time_in_us = 0;
244 unsigned int delta_from_mid_point_in_us_1 = 0xFFFFFFFF;
245 unsigned int delta_from_mid_point_in_us_2 = 0xFFFFFFFF;
246 unsigned int frames_to_insert = 0;
247 unsigned int min_frame_duration_in_ns = 0;
248 unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us;
249
250 min_frame_duration_in_ns = ((unsigned int) (div64_u64(
251 (1000000000ULL * 1000000),
252 in_out_vrr->max_refresh_in_uhz)));
253
254 /* Program BTR */
255 if (last_render_time_in_us + BTR_EXIT_MARGIN < max_render_time_in_us) {
256 /* Exit Below the Range */
257 if (in_out_vrr->btr.btr_active) {
258 in_out_vrr->btr.frame_counter = 0;
259 in_out_vrr->btr.btr_active = false;
260
261 /* Exit Fixed Refresh mode */
262 } else if (in_out_vrr->fixed.fixed_active) {
263
264 in_out_vrr->fixed.frame_counter++;
265
266 if (in_out_vrr->fixed.frame_counter >
267 FIXED_REFRESH_EXIT_FRAME_COUNT) {
268 in_out_vrr->fixed.frame_counter = 0;
269 in_out_vrr->fixed.fixed_active = false;
270 }
271 }
272 } else if (last_render_time_in_us > max_render_time_in_us) {
273 /* Enter Below the Range */
274 if (!in_out_vrr->btr.btr_active &&
275 in_out_vrr->btr.btr_enabled) {
276 in_out_vrr->btr.btr_active = true;
277
278 /* Enter Fixed Refresh mode */
279 } else if (!in_out_vrr->fixed.fixed_active &&
280 !in_out_vrr->btr.btr_enabled) {
281 in_out_vrr->fixed.frame_counter++;
282
283 if (in_out_vrr->fixed.frame_counter >
284 FIXED_REFRESH_ENTER_FRAME_COUNT) {
285 in_out_vrr->fixed.frame_counter = 0;
286 in_out_vrr->fixed.fixed_active = true;
287 }
288 }
289 }
290
291 /* BTR set to "not active" so disengage */
292 if (!in_out_vrr->btr.btr_active) {
293 in_out_vrr->btr.btr_active = false;
294 in_out_vrr->btr.inserted_duration_in_us = 0;
295 in_out_vrr->btr.frames_to_insert = 0;
296 in_out_vrr->btr.frame_counter = 0;
297
298 /* Restore FreeSync */
299 in_out_vrr->adjust.v_total_min =
300 calc_v_total_from_refresh(stream,
301 in_out_vrr->max_refresh_in_uhz);
302 in_out_vrr->adjust.v_total_max =
303 calc_v_total_from_refresh(stream,
304 in_out_vrr->min_refresh_in_uhz);
305 /* BTR set to "active" so engage */
306 } else {
307
308 /* Calculate number of midPoint frames that could fit within
309 * the render time interval- take ceil of this value
310 */
311 mid_point_frames_ceil = (last_render_time_in_us +
312 in_out_vrr->btr.mid_point_in_us - 1) /
313 in_out_vrr->btr.mid_point_in_us;
314
315 if (mid_point_frames_ceil > 0) {
316 frame_time_in_us = last_render_time_in_us /
317 mid_point_frames_ceil;
318 delta_from_mid_point_in_us_1 =
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 /* Calculate number of midPoint frames that could fit within
326 * the render time interval- take floor of this value
327 */
328 mid_point_frames_floor = last_render_time_in_us /
329 in_out_vrr->btr.mid_point_in_us;
330
331 if (mid_point_frames_floor > 0) {
332
333 frame_time_in_us = last_render_time_in_us /
334 mid_point_frames_floor;
335 delta_from_mid_point_in_us_2 =
336 (in_out_vrr->btr.mid_point_in_us >
337 frame_time_in_us) ?
338 (in_out_vrr->btr.mid_point_in_us - frame_time_in_us) :
339 (frame_time_in_us - in_out_vrr->btr.mid_point_in_us);
340 }
341
342 /* Choose number of frames to insert based on how close it
343 * can get to the mid point of the variable range.
344 */
345 if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2)
346 frames_to_insert = mid_point_frames_ceil;
347 else
348 frames_to_insert = mid_point_frames_floor;
349
350 /* Either we've calculated the number of frames to insert,
351 * or we need to insert min duration frames
352 */
353 if (frames_to_insert > 0)
354 inserted_frame_duration_in_us = last_render_time_in_us /
355 frames_to_insert;
356
357 if (inserted_frame_duration_in_us <
358 (1000000 / in_out_vrr->max_refresh_in_uhz))
359 inserted_frame_duration_in_us =
360 (1000000 / in_out_vrr->max_refresh_in_uhz);
361
362 /* Cache the calculated variables */
363 in_out_vrr->btr.inserted_duration_in_us =
364 inserted_frame_duration_in_us;
365 in_out_vrr->btr.frames_to_insert = frames_to_insert;
366 in_out_vrr->btr.frame_counter = frames_to_insert;
367 }
368}
369
370static void apply_fixed_refresh(struct core_freesync *core_freesync,
371 const struct dc_stream_state *stream,
372 unsigned int last_render_time_in_us,
373 struct mod_vrr_params *in_out_vrr)
374{
375 bool update = false;
376 unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us;
377
378 if (last_render_time_in_us + BTR_EXIT_MARGIN < max_render_time_in_us) {
379 /* Exit Fixed Refresh mode */
380 if (in_out_vrr->fixed.fixed_active) {
381 in_out_vrr->fixed.frame_counter++;
382
383 if (in_out_vrr->fixed.frame_counter >
384 FIXED_REFRESH_EXIT_FRAME_COUNT) {
385 in_out_vrr->fixed.frame_counter = 0;
386 in_out_vrr->fixed.fixed_active = false;
387 in_out_vrr->fixed.target_refresh_in_uhz = 0;
388 update = true;
389 }
390 }
391 } else if (last_render_time_in_us > max_render_time_in_us) {
392 /* Enter Fixed Refresh mode */
393 if (!in_out_vrr->fixed.fixed_active) {
394 in_out_vrr->fixed.frame_counter++;
395
396 if (in_out_vrr->fixed.frame_counter >
397 FIXED_REFRESH_ENTER_FRAME_COUNT) {
398 in_out_vrr->fixed.frame_counter = 0;
399 in_out_vrr->fixed.fixed_active = true;
400 in_out_vrr->fixed.target_refresh_in_uhz =
401 in_out_vrr->max_refresh_in_uhz;
402 update = true;
403 }
404 }
405 }
406
407 if (update) {
408 if (in_out_vrr->fixed.fixed_active) {
409 in_out_vrr->adjust.v_total_min =
410 calc_v_total_from_refresh(
411 stream, in_out_vrr->max_refresh_in_uhz);
412 in_out_vrr->adjust.v_total_max =
413 in_out_vrr->adjust.v_total_min;
414 } else {
415 in_out_vrr->adjust.v_total_min =
416 calc_v_total_from_refresh(stream,
417 in_out_vrr->max_refresh_in_uhz);
418 in_out_vrr->adjust.v_total_max =
419 calc_v_total_from_refresh(stream,
420 in_out_vrr->min_refresh_in_uhz);
421 }
422 }
423}
424
425static bool vrr_settings_require_update(struct core_freesync *core_freesync,
426 struct mod_freesync_config *in_config,
427 unsigned int min_refresh_in_uhz,
428 unsigned int max_refresh_in_uhz,
429 struct mod_vrr_params *in_vrr)
430{
431 if (in_vrr->state != in_config->state) {
432 return true;
433 } else if (in_vrr->state == VRR_STATE_ACTIVE_FIXED &&
434 in_vrr->fixed.target_refresh_in_uhz !=
435 in_config->min_refresh_in_uhz) {
436 return true;
437 } else if (in_vrr->min_refresh_in_uhz != min_refresh_in_uhz) {
438 return true;
439 } else if (in_vrr->max_refresh_in_uhz != max_refresh_in_uhz) {
440 return true;
441 }
442
443 return false;
444}
445
446bool mod_freesync_get_vmin_vmax(struct mod_freesync *mod_freesync,
447 const struct dc_stream_state *stream,
448 unsigned int *vmin,
449 unsigned int *vmax)
450{
451 *vmin = stream->adjust.v_total_min;
452 *vmax = stream->adjust.v_total_max;
453
454 return true;
455}
456
457bool mod_freesync_get_v_position(struct mod_freesync *mod_freesync,
458 struct dc_stream_state *stream,
459 unsigned int *nom_v_pos,
460 unsigned int *v_pos)
461{
462 struct core_freesync *core_freesync = NULL;
463 struct crtc_position position;
464
465 if (mod_freesync == NULL)
466 return false;
467
468 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
469
470 if (dc_stream_get_crtc_position(core_freesync->dc, &stream, 1,
471 &position.vertical_count,
472 &position.nominal_vcount)) {
473
474 *nom_v_pos = position.nominal_vcount;
475 *v_pos = position.vertical_count;
476
477 return true;
478 }
479
480 return false;
481}
482
483static void build_vrr_infopacket_header_v1(enum signal_type signal,
484 struct dc_info_packet *infopacket,
485 unsigned int *payload_size)
486{
487 if (dc_is_hdmi_signal(signal)) {
488
489 /* HEADER */
490
491 /* HB0 = Packet Type = 0x83 (Source Product
492 * Descriptor InfoFrame)
493 */
494 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
495
496 /* HB1 = Version = 0x01 */
497 infopacket->hb1 = 0x01;
498
499 /* HB2 = [Bits 7:5 = 0] [Bits 4:0 = Length = 0x08] */
500 infopacket->hb2 = 0x08;
501
502 *payload_size = 0x08;
503
504 } else if (dc_is_dp_signal(signal)) {
505
506 /* HEADER */
507
508 /* HB0 = Secondary-data Packet ID = 0 - Only non-zero
509 * when used to associate audio related info packets
510 */
511 infopacket->hb0 = 0x00;
512
513 /* HB1 = Packet Type = 0x83 (Source Product
514 * Descriptor InfoFrame)
515 */
516 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
517
518 /* HB2 = [Bits 7:0 = Least significant eight bits -
519 * For INFOFRAME, the value must be 1Bh]
520 */
521 infopacket->hb2 = 0x1B;
522
523 /* HB3 = [Bits 7:2 = INFOFRAME SDP Version Number = 0x1]
524 * [Bits 1:0 = Most significant two bits = 0x00]
525 */
526 infopacket->hb3 = 0x04;
527
528 *payload_size = 0x1B;
529 }
530}
531
532static void build_vrr_infopacket_header_v2(enum signal_type signal,
533 struct dc_info_packet *infopacket,
534 unsigned int *payload_size)
535{
536 if (dc_is_hdmi_signal(signal)) {
537
538 /* HEADER */
539
540 /* HB0 = Packet Type = 0x83 (Source Product
541 * Descriptor InfoFrame)
542 */
543 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
544
545 /* HB1 = Version = 0x02 */
546 infopacket->hb1 = 0x02;
547
548 /* HB2 = [Bits 7:5 = 0] [Bits 4:0 = Length = 0x09] */
549 infopacket->hb2 = 0x09;
550
551 *payload_size = 0x0A;
552
553 } else if (dc_is_dp_signal(signal)) {
554
555 /* HEADER */
556
557 /* HB0 = Secondary-data Packet ID = 0 - Only non-zero
558 * when used to associate audio related info packets
559 */
560 infopacket->hb0 = 0x00;
561
562 /* HB1 = Packet Type = 0x83 (Source Product
563 * Descriptor InfoFrame)
564 */
565 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
566
567 /* HB2 = [Bits 7:0 = Least significant eight bits -
568 * For INFOFRAME, the value must be 1Bh]
569 */
570 infopacket->hb2 = 0x1B;
571
572 /* HB3 = [Bits 7:2 = INFOFRAME SDP Version Number = 0x2]
573 * [Bits 1:0 = Most significant two bits = 0x00]
574 */
575 infopacket->hb3 = 0x08;
576
577 *payload_size = 0x1B;
578 }
579}
580
581static void build_vrr_infopacket_data(const struct mod_vrr_params *vrr,
582 struct dc_info_packet *infopacket)
583{
584 /* PB1 = 0x1A (24bit AMD IEEE OUI (0x00001A) - Byte 0) */
585 infopacket->sb[1] = 0x1A;
586
587 /* PB2 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 1) */
588 infopacket->sb[2] = 0x00;
589
590 /* PB3 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 2) */
591 infopacket->sb[3] = 0x00;
592
593 /* PB4 = Reserved */
594
595 /* PB5 = Reserved */
596
597 /* PB6 = [Bits 7:3 = Reserved] */
598
599 /* PB6 = [Bit 0 = FreeSync Supported] */
600 if (vrr->state != VRR_STATE_UNSUPPORTED)
601 infopacket->sb[6] |= 0x01;
602
603 /* PB6 = [Bit 1 = FreeSync Enabled] */
604 if (vrr->state != VRR_STATE_DISABLED &&
605 vrr->state != VRR_STATE_UNSUPPORTED)
606 infopacket->sb[6] |= 0x02;
607
608 /* PB6 = [Bit 2 = FreeSync Active] */
609 if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
610 vrr->state == VRR_STATE_ACTIVE_FIXED)
611 infopacket->sb[6] |= 0x04;
612
613 /* PB7 = FreeSync Minimum refresh rate (Hz) */
614 infopacket->sb[7] = (unsigned char)(vrr->min_refresh_in_uhz / 1000000);
615
616 /* PB8 = FreeSync Maximum refresh rate (Hz)
617 * Note: We should never go above the field rate of the mode timing set.
618 */
619 infopacket->sb[8] = (unsigned char)(vrr->max_refresh_in_uhz / 1000000);
620
621
622 //FreeSync HDR
623 infopacket->sb[9] = 0;
624 infopacket->sb[10] = 0;
625}
626
627static void build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf,
628 struct dc_info_packet *infopacket)
629{
630 if (app_tf != transfer_func_unknown) {
631 infopacket->valid = true;
632
633 infopacket->sb[6] |= 0x08; // PB6 = [Bit 3 = Native Color Active]
634
635 if (app_tf == transfer_func_gamma_22) {
636 infopacket->sb[9] |= 0x04; // PB6 = [Bit 2 = Gamma 2.2 EOTF Active]
637 }
638 }
639}
640
641static void build_vrr_infopacket_checksum(unsigned int *payload_size,
642 struct dc_info_packet *infopacket)
643{
644 /* Calculate checksum */
645 unsigned int idx = 0;
646 unsigned char checksum = 0;
647
648 checksum += infopacket->hb0;
649 checksum += infopacket->hb1;
650 checksum += infopacket->hb2;
651 checksum += infopacket->hb3;
652
653 for (idx = 1; idx <= *payload_size; idx++)
654 checksum += infopacket->sb[idx];
655
656 /* PB0 = Checksum (one byte complement) */
657 infopacket->sb[0] = (unsigned char)(0x100 - checksum);
658
659 infopacket->valid = true;
660}
661
662static void build_vrr_infopacket_v1(enum signal_type signal,
663 const struct mod_vrr_params *vrr,
664 struct dc_info_packet *infopacket)
665{
666 /* SPD info packet for FreeSync */
667 unsigned int payload_size = 0;
668
669 build_vrr_infopacket_header_v1(signal, infopacket, &payload_size);
670 build_vrr_infopacket_data(vrr, infopacket);
671 build_vrr_infopacket_checksum(&payload_size, infopacket);
672
673 infopacket->valid = true;
674}
675
676static void build_vrr_infopacket_v2(enum signal_type signal,
677 const struct mod_vrr_params *vrr,
678 const enum color_transfer_func *app_tf,
679 struct dc_info_packet *infopacket)
680{
681 unsigned int payload_size = 0;
682
683 build_vrr_infopacket_header_v2(signal, infopacket, &payload_size);
684 build_vrr_infopacket_data(vrr, infopacket);
685
686 if (app_tf != NULL)
687 build_vrr_infopacket_fs2_data(*app_tf, infopacket);
688
689 build_vrr_infopacket_checksum(&payload_size, infopacket);
690
691 infopacket->valid = true;
692}
693
694void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync,
695 const struct dc_stream_state *stream,
696 const struct mod_vrr_params *vrr,
697 enum vrr_packet_type packet_type,
698 const enum color_transfer_func *app_tf,
699 struct dc_info_packet *infopacket)
700{
701 /* SPD info packet for FreeSync */
702
703 /* Check if Freesync is supported. Return if false. If true,
704 * set the corresponding bit in the info packet
705 */
706 if (!vrr->supported || !vrr->send_vsif)
707 return;
708
709 switch (packet_type) {
710 case packet_type_fs2:
711 build_vrr_infopacket_v2(stream->signal, vrr, app_tf, infopacket);
712 break;
713 case packet_type_vrr:
714 case packet_type_fs1:
715 default:
716 build_vrr_infopacket_v1(stream->signal, vrr, infopacket);
717 }
718}
719
720void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync,
721 const struct dc_stream_state *stream,
722 struct mod_freesync_config *in_config,
723 struct mod_vrr_params *in_out_vrr)
724{
725 struct core_freesync *core_freesync = NULL;
726 unsigned long long nominal_field_rate_in_uhz = 0;
727 unsigned int refresh_range = 0;
728 unsigned int min_refresh_in_uhz = 0;
729 unsigned int max_refresh_in_uhz = 0;
730
731 if (mod_freesync == NULL)
732 return;
733
734 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
735
736 /* Calculate nominal field rate for stream */
737 nominal_field_rate_in_uhz =
738 mod_freesync_calc_nominal_field_rate(stream);
739
740 min_refresh_in_uhz = in_config->min_refresh_in_uhz;
741 max_refresh_in_uhz = in_config->max_refresh_in_uhz;
742
743 // Don't allow min > max
744 if (min_refresh_in_uhz > max_refresh_in_uhz)
745 min_refresh_in_uhz = max_refresh_in_uhz;
746
747 // Full range may be larger than current video timing, so cap at nominal
748 if (max_refresh_in_uhz > nominal_field_rate_in_uhz)
749 max_refresh_in_uhz = nominal_field_rate_in_uhz;
750
751 // Full range may be larger than current video timing, so cap at nominal
752 if (min_refresh_in_uhz > nominal_field_rate_in_uhz)
753 min_refresh_in_uhz = nominal_field_rate_in_uhz;
754
755 if (!vrr_settings_require_update(core_freesync,
756 in_config, min_refresh_in_uhz, max_refresh_in_uhz,
757 in_out_vrr))
758 return;
759
760 in_out_vrr->state = in_config->state;
761 in_out_vrr->send_vsif = in_config->vsif_supported;
762
763 if (in_config->state == VRR_STATE_UNSUPPORTED) {
764 in_out_vrr->state = VRR_STATE_UNSUPPORTED;
765 in_out_vrr->supported = false;
766 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
767 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
768
769 return;
770
771 } else {
772 in_out_vrr->min_refresh_in_uhz = min_refresh_in_uhz;
773 in_out_vrr->max_duration_in_us =
774 calc_duration_in_us_from_refresh_in_uhz(
775 min_refresh_in_uhz);
776
777 in_out_vrr->max_refresh_in_uhz = max_refresh_in_uhz;
778 in_out_vrr->min_duration_in_us =
779 calc_duration_in_us_from_refresh_in_uhz(
780 max_refresh_in_uhz);
781
782 refresh_range = in_out_vrr->max_refresh_in_uhz -
783 in_out_vrr->min_refresh_in_uhz;
784
785 in_out_vrr->supported = true;
786 }
787
788 in_out_vrr->fixed.ramping_active = in_config->ramping;
789
790 in_out_vrr->btr.btr_enabled = in_config->btr;
791 if (in_out_vrr->max_refresh_in_uhz <
792 2 * in_out_vrr->min_refresh_in_uhz)
793 in_out_vrr->btr.btr_enabled = false;
794 in_out_vrr->btr.btr_active = false;
795 in_out_vrr->btr.inserted_duration_in_us = 0;
796 in_out_vrr->btr.frames_to_insert = 0;
797 in_out_vrr->btr.frame_counter = 0;
798 in_out_vrr->btr.mid_point_in_us =
799 in_out_vrr->min_duration_in_us +
800 (in_out_vrr->max_duration_in_us -
801 in_out_vrr->min_duration_in_us) / 2;
802
803 if (in_out_vrr->state == VRR_STATE_UNSUPPORTED) {
804 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
805 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
806 } else if (in_out_vrr->state == VRR_STATE_DISABLED) {
807 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
808 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
809 } else if (in_out_vrr->state == VRR_STATE_INACTIVE) {
810 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
811 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
812 } else if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE &&
813 refresh_range >= MIN_REFRESH_RANGE_IN_US) {
814 in_out_vrr->adjust.v_total_min =
815 calc_v_total_from_refresh(stream,
816 in_out_vrr->max_refresh_in_uhz);
817 in_out_vrr->adjust.v_total_max =
818 calc_v_total_from_refresh(stream,
819 in_out_vrr->min_refresh_in_uhz);
820 } else if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED) {
821 in_out_vrr->fixed.target_refresh_in_uhz =
822 in_out_vrr->min_refresh_in_uhz;
823 if (in_out_vrr->fixed.ramping_active &&
824 in_out_vrr->fixed.fixed_active) {
825 /* Do not update vtotals if ramping is already active
826 * in order to continue ramp from current refresh.
827 */
828 in_out_vrr->fixed.fixed_active = true;
829 } else {
830 in_out_vrr->fixed.fixed_active = true;
831 in_out_vrr->adjust.v_total_min =
832 calc_v_total_from_refresh(stream,
833 in_out_vrr->fixed.target_refresh_in_uhz);
834 in_out_vrr->adjust.v_total_max =
835 in_out_vrr->adjust.v_total_min;
836 }
837 } else {
838 in_out_vrr->state = VRR_STATE_INACTIVE;
839 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
840 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
841 }
842}
843
844void mod_freesync_handle_preflip(struct mod_freesync *mod_freesync,
845 const struct dc_plane_state *plane,
846 const struct dc_stream_state *stream,
847 unsigned int curr_time_stamp_in_us,
848 struct mod_vrr_params *in_out_vrr)
849{
850 struct core_freesync *core_freesync = NULL;
851 unsigned int last_render_time_in_us = 0;
852 unsigned int average_render_time_in_us = 0;
853
854 if (mod_freesync == NULL)
855 return;
856
857 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
858
859 if (in_out_vrr->supported &&
860 in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE) {
861 unsigned int i = 0;
862 unsigned int oldest_index = plane->time.index + 1;
863
864 if (oldest_index >= DC_PLANE_UPDATE_TIMES_MAX)
865 oldest_index = 0;
866
867 last_render_time_in_us = curr_time_stamp_in_us -
868 plane->time.prev_update_time_in_us;
869
870 // Sum off all entries except oldest one
871 for (i = 0; i < DC_PLANE_UPDATE_TIMES_MAX; i++) {
872 average_render_time_in_us +=
873 plane->time.time_elapsed_in_us[i];
874 }
875 average_render_time_in_us -=
876 plane->time.time_elapsed_in_us[oldest_index];
877
878 // Add render time for current flip
879 average_render_time_in_us += last_render_time_in_us;
880 average_render_time_in_us /= DC_PLANE_UPDATE_TIMES_MAX;
881
882 if (in_out_vrr->btr.btr_enabled) {
883 apply_below_the_range(core_freesync,
884 stream,
885 last_render_time_in_us,
886 in_out_vrr);
887 } else {
888 apply_fixed_refresh(core_freesync,
889 stream,
890 last_render_time_in_us,
891 in_out_vrr);
892 }
893
894 }
895}
896
897void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync,
898 const struct dc_stream_state *stream,
899 struct mod_vrr_params *in_out_vrr)
900{
901 struct core_freesync *core_freesync = NULL;
902
903 if ((mod_freesync == NULL) || (stream == NULL) || (in_out_vrr == NULL))
904 return;
905
906 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
907
908 if (in_out_vrr->supported == false)
909 return;
910
911 /* Below the Range Logic */
912
913 /* Only execute if in fullscreen mode */
914 if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE &&
915 in_out_vrr->btr.btr_active) {
916 /* TODO: pass in flag for Pre-DCE12 ASIC
917 * in order for frame variable duration to take affect,
918 * it needs to be done one VSYNC early, which is at
919 * frameCounter == 1.
920 * For DCE12 and newer updates to V_TOTAL_MIN/MAX
921 * will take affect on current frame
922 */
923 if (in_out_vrr->btr.frames_to_insert ==
924 in_out_vrr->btr.frame_counter) {
925 in_out_vrr->adjust.v_total_min =
926 calc_v_total_from_duration(stream,
927 in_out_vrr,
928 in_out_vrr->btr.inserted_duration_in_us);
929 in_out_vrr->adjust.v_total_max =
930 in_out_vrr->adjust.v_total_min;
931 }
932
933 if (in_out_vrr->btr.frame_counter > 0)
934 in_out_vrr->btr.frame_counter--;
935
936 /* Restore FreeSync */
937 if (in_out_vrr->btr.frame_counter == 0) {
938 in_out_vrr->adjust.v_total_min =
939 calc_v_total_from_refresh(stream,
940 in_out_vrr->max_refresh_in_uhz);
941 in_out_vrr->adjust.v_total_max =
942 calc_v_total_from_refresh(stream,
943 in_out_vrr->min_refresh_in_uhz);
944 }
945 }
946
947 /* If in fullscreen freesync mode or in video, do not program
948 * static screen ramp values
949 */
950 if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE)
951 in_out_vrr->fixed.ramping_active = false;
952
953 /* Gradual Static Screen Ramping Logic */
954 /* Execute if ramp is active and user enabled freesync static screen*/
955 if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED &&
956 in_out_vrr->fixed.ramping_active) {
957 update_v_total_for_static_ramp(
958 core_freesync, stream, in_out_vrr);
959 }
960}
961
962void mod_freesync_get_settings(struct mod_freesync *mod_freesync,
963 const struct mod_vrr_params *vrr,
964 unsigned int *v_total_min, unsigned int *v_total_max,
965 unsigned int *event_triggers,
966 unsigned int *window_min, unsigned int *window_max,
967 unsigned int *lfc_mid_point_in_us,
968 unsigned int *inserted_frames,
969 unsigned int *inserted_duration_in_us)
970{
971 struct core_freesync *core_freesync = NULL;
972
973 if (mod_freesync == NULL)
974 return;
975
976 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
977
978 if (vrr->supported) {
979 *v_total_min = vrr->adjust.v_total_min;
980 *v_total_max = vrr->adjust.v_total_max;
981 *event_triggers = 0;
982 *lfc_mid_point_in_us = vrr->btr.mid_point_in_us;
983 *inserted_frames = vrr->btr.frames_to_insert;
984 *inserted_duration_in_us = vrr->btr.inserted_duration_in_us;
985 }
986}
987
988unsigned long long mod_freesync_calc_nominal_field_rate(
989 const struct dc_stream_state *stream)
990{
991 unsigned long long nominal_field_rate_in_uhz = 0;
992
993 /* Calculate nominal field rate for stream */
994 nominal_field_rate_in_uhz = stream->timing.pix_clk_khz;
995 nominal_field_rate_in_uhz *= 1000ULL * 1000ULL * 1000ULL;
996 nominal_field_rate_in_uhz = div_u64(nominal_field_rate_in_uhz,
997 stream->timing.h_total);
998 nominal_field_rate_in_uhz = div_u64(nominal_field_rate_in_uhz,
999 stream->timing.v_total);
1000
1001 return nominal_field_rate_in_uhz;
1002}
1003
1004bool mod_freesync_is_valid_range(struct mod_freesync *mod_freesync,
1005 const struct dc_stream_state *stream,
1006 uint32_t min_refresh_cap_in_uhz,
1007 uint32_t max_refresh_cap_in_uhz,
1008 uint32_t min_refresh_request_in_uhz,
1009 uint32_t max_refresh_request_in_uhz)
1010{
1011 /* Calculate nominal field rate for stream */
1012 unsigned long long nominal_field_rate_in_uhz =
1013 mod_freesync_calc_nominal_field_rate(stream);
1014
1015 /* Typically nominal refresh calculated can have some fractional part.
1016 * Allow for some rounding error of actual video timing by taking floor
1017 * of caps and request. Round the nominal refresh rate.
1018 *
1019 * Dividing will convert everything to units in Hz although input
1020 * variable name is in uHz!
1021 *
1022 * Also note, this takes care of rounding error on the nominal refresh
1023 * so by rounding error we only expect it to be off by a small amount,
1024 * such as < 0.1 Hz. i.e. 143.9xxx or 144.1xxx.
1025 *
1026 * Example 1. Caps Min = 40 Hz, Max = 144 Hz
1027 * Request Min = 40 Hz, Max = 144 Hz
1028 * Nominal = 143.5x Hz rounded to 144 Hz
1029 * This function should allow this as valid request
1030 *
1031 * Example 2. Caps Min = 40 Hz, Max = 144 Hz
1032 * Request Min = 40 Hz, Max = 144 Hz
1033 * Nominal = 144.4x Hz rounded to 144 Hz
1034 * This function should allow this as valid request
1035 *
1036 * Example 3. Caps Min = 40 Hz, Max = 144 Hz
1037 * Request Min = 40 Hz, Max = 144 Hz
1038 * Nominal = 120.xx Hz rounded to 120 Hz
1039 * This function should return NOT valid since the requested
1040 * max is greater than current timing's nominal
1041 *
1042 * Example 4. Caps Min = 40 Hz, Max = 120 Hz
1043 * Request Min = 40 Hz, Max = 120 Hz
1044 * Nominal = 144.xx Hz rounded to 144 Hz
1045 * This function should return NOT valid since the nominal
1046 * is greater than the capability's max refresh
1047 */
1048 nominal_field_rate_in_uhz =
1049 div_u64(nominal_field_rate_in_uhz + 500000, 1000000);
1050 min_refresh_cap_in_uhz /= 1000000;
1051 max_refresh_cap_in_uhz /= 1000000;
1052 min_refresh_request_in_uhz /= 1000000;
1053 max_refresh_request_in_uhz /= 1000000;
1054
1055 // Check nominal is within range
1056 if (nominal_field_rate_in_uhz > max_refresh_cap_in_uhz ||
1057 nominal_field_rate_in_uhz < min_refresh_cap_in_uhz)
1058 return false;
1059
1060 // If nominal is less than max, limit the max allowed refresh rate
1061 if (nominal_field_rate_in_uhz < max_refresh_cap_in_uhz)
1062 max_refresh_cap_in_uhz = nominal_field_rate_in_uhz;
1063
1064 // Don't allow min > max
1065 if (min_refresh_request_in_uhz > max_refresh_request_in_uhz)
1066 return false;
1067
1068 // Check min is within range
1069 if (min_refresh_request_in_uhz > max_refresh_cap_in_uhz ||
1070 min_refresh_request_in_uhz < min_refresh_cap_in_uhz)
1071 return false;
1072
1073 // Check max is within range
1074 if (max_refresh_request_in_uhz > max_refresh_cap_in_uhz ||
1075 max_refresh_request_in_uhz < min_refresh_cap_in_uhz)
1076 return false;
1077
1078 // For variable range, check for at least 10 Hz range
1079 if ((max_refresh_request_in_uhz != min_refresh_request_in_uhz) &&
1080 (max_refresh_request_in_uhz - min_refresh_request_in_uhz < 10))
1081 return false;
1082
1083 return true;
1084}
1085