0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026 #include "dm_services.h"
0027 #include "dc.h"
0028 #include "mod_freesync.h"
0029 #include "core_types.h"
0030
0031 #define MOD_FREESYNC_MAX_CONCURRENT_STREAMS 32
0032
0033 #define MIN_REFRESH_RANGE 10
0034
0035 #define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65)
0036
0037 #define RENDER_TIMES_MAX_COUNT 10
0038
0039 #define BTR_MAX_MARGIN 2500
0040
0041 #define BTR_DRIFT_MARGIN 2000
0042
0043 #define FIXED_REFRESH_EXIT_MARGIN_IN_HZ 1
0044
0045 #define FIXED_REFRESH_ENTER_FRAME_COUNT 5
0046 #define FIXED_REFRESH_EXIT_FRAME_COUNT 10
0047
0048 #define VSYNCS_BETWEEN_FLIP_THRESHOLD 2
0049 #define FREESYNC_CONSEC_FLIP_AFTER_VSYNC 5
0050 #define FREESYNC_VSYNC_TO_FLIP_DELTA_IN_US 500
0051
0052 struct core_freesync {
0053 struct mod_freesync public;
0054 struct dc *dc;
0055 };
0056
0057 #define MOD_FREESYNC_TO_CORE(mod_freesync)\
0058 container_of(mod_freesync, struct core_freesync, public)
0059
0060 struct mod_freesync *mod_freesync_create(struct dc *dc)
0061 {
0062 struct core_freesync *core_freesync =
0063 kzalloc(sizeof(struct core_freesync), GFP_KERNEL);
0064
0065 if (core_freesync == NULL)
0066 goto fail_alloc_context;
0067
0068 if (dc == NULL)
0069 goto fail_construct;
0070
0071 core_freesync->dc = dc;
0072 return &core_freesync->public;
0073
0074 fail_construct:
0075 kfree(core_freesync);
0076
0077 fail_alloc_context:
0078 return NULL;
0079 }
0080
0081 void mod_freesync_destroy(struct mod_freesync *mod_freesync)
0082 {
0083 struct core_freesync *core_freesync = NULL;
0084 if (mod_freesync == NULL)
0085 return;
0086 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
0087 kfree(core_freesync);
0088 }
0089
0090 #if 0
0091 static unsigned int calc_refresh_in_uhz_from_duration(
0092 unsigned int duration_in_ns)
0093 {
0094 unsigned int refresh_in_uhz =
0095 ((unsigned int)(div64_u64((1000000000ULL * 1000000),
0096 duration_in_ns)));
0097 return refresh_in_uhz;
0098 }
0099 #endif
0100
0101 static unsigned int calc_duration_in_us_from_refresh_in_uhz(
0102 unsigned int refresh_in_uhz)
0103 {
0104 unsigned int duration_in_us =
0105 ((unsigned int)(div64_u64((1000000000ULL * 1000),
0106 refresh_in_uhz)));
0107 return duration_in_us;
0108 }
0109
0110 static unsigned int calc_duration_in_us_from_v_total(
0111 const struct dc_stream_state *stream,
0112 const struct mod_vrr_params *in_vrr,
0113 unsigned int v_total)
0114 {
0115 unsigned int duration_in_us =
0116 (unsigned int)(div64_u64(((unsigned long long)(v_total)
0117 * 10000) * stream->timing.h_total,
0118 stream->timing.pix_clk_100hz));
0119
0120 return duration_in_us;
0121 }
0122
0123 unsigned int mod_freesync_calc_v_total_from_refresh(
0124 const struct dc_stream_state *stream,
0125 unsigned int refresh_in_uhz)
0126 {
0127 unsigned int v_total;
0128 unsigned int frame_duration_in_ns;
0129
0130 frame_duration_in_ns =
0131 ((unsigned int)(div64_u64((1000000000ULL * 1000000),
0132 refresh_in_uhz)));
0133
0134 v_total = div64_u64(div64_u64(((unsigned long long)(
0135 frame_duration_in_ns) * (stream->timing.pix_clk_100hz / 10)),
0136 stream->timing.h_total), 1000000);
0137
0138
0139 if (v_total < stream->timing.v_total) {
0140 ASSERT(v_total < stream->timing.v_total);
0141 v_total = stream->timing.v_total;
0142 }
0143
0144 return v_total;
0145 }
0146
0147 static unsigned int calc_v_total_from_duration(
0148 const struct dc_stream_state *stream,
0149 const struct mod_vrr_params *vrr,
0150 unsigned int duration_in_us)
0151 {
0152 unsigned int v_total = 0;
0153
0154 if (duration_in_us < vrr->min_duration_in_us)
0155 duration_in_us = vrr->min_duration_in_us;
0156
0157 if (duration_in_us > vrr->max_duration_in_us)
0158 duration_in_us = vrr->max_duration_in_us;
0159
0160 if (dc_is_hdmi_signal(stream->signal)) {
0161 uint32_t h_total_up_scaled;
0162
0163 h_total_up_scaled = stream->timing.h_total * 10000;
0164 v_total = div_u64((unsigned long long)duration_in_us
0165 * stream->timing.pix_clk_100hz + (h_total_up_scaled - 1),
0166 h_total_up_scaled);
0167 } else {
0168 v_total = div64_u64(div64_u64(((unsigned long long)(
0169 duration_in_us) * (stream->timing.pix_clk_100hz / 10)),
0170 stream->timing.h_total), 1000);
0171 }
0172
0173
0174 if (v_total < stream->timing.v_total) {
0175 ASSERT(v_total < stream->timing.v_total);
0176 v_total = stream->timing.v_total;
0177 }
0178
0179 return v_total;
0180 }
0181
0182 static void update_v_total_for_static_ramp(
0183 struct core_freesync *core_freesync,
0184 const struct dc_stream_state *stream,
0185 struct mod_vrr_params *in_out_vrr)
0186 {
0187 unsigned int v_total = 0;
0188 unsigned int current_duration_in_us =
0189 calc_duration_in_us_from_v_total(
0190 stream, in_out_vrr,
0191 in_out_vrr->adjust.v_total_max);
0192 unsigned int target_duration_in_us =
0193 calc_duration_in_us_from_refresh_in_uhz(
0194 in_out_vrr->fixed.target_refresh_in_uhz);
0195 bool ramp_direction_is_up = (current_duration_in_us >
0196 target_duration_in_us) ? true : false;
0197
0198
0199 unsigned int frame_duration_ratio = div64_u64(1000000,
0200 (1000 + div64_u64(((unsigned long long)(
0201 STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME) *
0202 current_duration_in_us),
0203 1000000)));
0204
0205
0206 unsigned int frame_duration_delta = div64_u64(((unsigned long long)(
0207 current_duration_in_us) *
0208 (1000 - frame_duration_ratio)), 1000);
0209
0210
0211
0212
0213 unsigned int ramp_rate_interpolated = div64_u64(((unsigned long long)(
0214 frame_duration_delta) * current_duration_in_us), 16666);
0215
0216
0217 if (ramp_direction_is_up) {
0218
0219 current_duration_in_us -= ramp_rate_interpolated;
0220
0221
0222 if (current_duration_in_us <= target_duration_in_us) {
0223 in_out_vrr->fixed.ramping_active = false;
0224 in_out_vrr->fixed.ramping_done = true;
0225 current_duration_in_us =
0226 calc_duration_in_us_from_refresh_in_uhz(
0227 in_out_vrr->fixed.target_refresh_in_uhz);
0228 }
0229
0230 } else {
0231
0232 current_duration_in_us += ramp_rate_interpolated;
0233
0234
0235 if (current_duration_in_us >= target_duration_in_us) {
0236 in_out_vrr->fixed.ramping_active = false;
0237 in_out_vrr->fixed.ramping_done = true;
0238 current_duration_in_us =
0239 calc_duration_in_us_from_refresh_in_uhz(
0240 in_out_vrr->fixed.target_refresh_in_uhz);
0241 }
0242 }
0243
0244 v_total = div64_u64(div64_u64(((unsigned long long)(
0245 current_duration_in_us) * (stream->timing.pix_clk_100hz / 10)),
0246 stream->timing.h_total), 1000);
0247
0248
0249 if (v_total < stream->timing.v_total)
0250 v_total = stream->timing.v_total;
0251
0252 in_out_vrr->adjust.v_total_min = v_total;
0253 in_out_vrr->adjust.v_total_max = v_total;
0254 }
0255
0256 static void apply_below_the_range(struct core_freesync *core_freesync,
0257 const struct dc_stream_state *stream,
0258 unsigned int last_render_time_in_us,
0259 struct mod_vrr_params *in_out_vrr)
0260 {
0261 unsigned int inserted_frame_duration_in_us = 0;
0262 unsigned int mid_point_frames_ceil = 0;
0263 unsigned int mid_point_frames_floor = 0;
0264 unsigned int frame_time_in_us = 0;
0265 unsigned int delta_from_mid_point_in_us_1 = 0xFFFFFFFF;
0266 unsigned int delta_from_mid_point_in_us_2 = 0xFFFFFFFF;
0267 unsigned int frames_to_insert = 0;
0268 unsigned int delta_from_mid_point_delta_in_us;
0269 unsigned int max_render_time_in_us =
0270 in_out_vrr->max_duration_in_us - in_out_vrr->btr.margin_in_us;
0271
0272
0273 if ((last_render_time_in_us + in_out_vrr->btr.margin_in_us / 2) < max_render_time_in_us) {
0274
0275 if (in_out_vrr->btr.btr_active) {
0276 in_out_vrr->btr.frame_counter = 0;
0277 in_out_vrr->btr.btr_active = false;
0278 }
0279 } else if (last_render_time_in_us > (max_render_time_in_us + in_out_vrr->btr.margin_in_us / 2)) {
0280
0281 if (!in_out_vrr->btr.btr_active) {
0282 in_out_vrr->btr.btr_active = true;
0283 }
0284 }
0285
0286
0287 if (!in_out_vrr->btr.btr_active) {
0288 in_out_vrr->btr.inserted_duration_in_us = 0;
0289 in_out_vrr->btr.frames_to_insert = 0;
0290 in_out_vrr->btr.frame_counter = 0;
0291
0292
0293 in_out_vrr->adjust.v_total_min =
0294 mod_freesync_calc_v_total_from_refresh(stream,
0295 in_out_vrr->max_refresh_in_uhz);
0296 in_out_vrr->adjust.v_total_max =
0297 mod_freesync_calc_v_total_from_refresh(stream,
0298 in_out_vrr->min_refresh_in_uhz);
0299
0300 } else {
0301
0302
0303
0304
0305 mid_point_frames_ceil = (last_render_time_in_us +
0306 in_out_vrr->btr.mid_point_in_us - 1) /
0307 in_out_vrr->btr.mid_point_in_us;
0308
0309 if (mid_point_frames_ceil > 0) {
0310 frame_time_in_us = last_render_time_in_us /
0311 mid_point_frames_ceil;
0312 delta_from_mid_point_in_us_1 =
0313 (in_out_vrr->btr.mid_point_in_us >
0314 frame_time_in_us) ?
0315 (in_out_vrr->btr.mid_point_in_us - frame_time_in_us) :
0316 (frame_time_in_us - in_out_vrr->btr.mid_point_in_us);
0317 }
0318
0319
0320
0321
0322 mid_point_frames_floor = last_render_time_in_us /
0323 in_out_vrr->btr.mid_point_in_us;
0324
0325 if (mid_point_frames_floor > 0) {
0326
0327 frame_time_in_us = last_render_time_in_us /
0328 mid_point_frames_floor;
0329 delta_from_mid_point_in_us_2 =
0330 (in_out_vrr->btr.mid_point_in_us >
0331 frame_time_in_us) ?
0332 (in_out_vrr->btr.mid_point_in_us - frame_time_in_us) :
0333 (frame_time_in_us - in_out_vrr->btr.mid_point_in_us);
0334 }
0335
0336
0337
0338
0339
0340
0341 if ((last_render_time_in_us / mid_point_frames_ceil) < in_out_vrr->min_duration_in_us) {
0342
0343
0344
0345
0346 frames_to_insert = mid_point_frames_floor;
0347 } else if (mid_point_frames_floor < 2) {
0348
0349
0350
0351 frames_to_insert = mid_point_frames_ceil;
0352 } else if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) {
0353
0354
0355
0356
0357 frames_to_insert = mid_point_frames_ceil;
0358 } else {
0359
0360
0361
0362
0363 frames_to_insert = mid_point_frames_floor;
0364 }
0365
0366
0367
0368
0369 if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) {
0370 delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_2 -
0371 delta_from_mid_point_in_us_1;
0372 } else {
0373 delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_1 -
0374 delta_from_mid_point_in_us_2;
0375 }
0376 if (in_out_vrr->btr.frames_to_insert != 0 &&
0377 delta_from_mid_point_delta_in_us < BTR_DRIFT_MARGIN) {
0378 if (((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) <
0379 max_render_time_in_us) &&
0380 ((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) >
0381 in_out_vrr->min_duration_in_us))
0382 frames_to_insert = in_out_vrr->btr.frames_to_insert;
0383 }
0384
0385
0386
0387
0388 if (last_render_time_in_us / frames_to_insert <
0389 in_out_vrr->min_duration_in_us){
0390 frames_to_insert -= (frames_to_insert > 1) ?
0391 1 : 0;
0392 }
0393
0394 if (frames_to_insert > 0)
0395 inserted_frame_duration_in_us = last_render_time_in_us /
0396 frames_to_insert;
0397
0398 if (inserted_frame_duration_in_us < in_out_vrr->min_duration_in_us)
0399 inserted_frame_duration_in_us = in_out_vrr->min_duration_in_us;
0400
0401
0402 in_out_vrr->btr.inserted_duration_in_us =
0403 inserted_frame_duration_in_us;
0404 in_out_vrr->btr.frames_to_insert = frames_to_insert;
0405 in_out_vrr->btr.frame_counter = frames_to_insert;
0406 }
0407 }
0408
0409 static void apply_fixed_refresh(struct core_freesync *core_freesync,
0410 const struct dc_stream_state *stream,
0411 unsigned int last_render_time_in_us,
0412 struct mod_vrr_params *in_out_vrr)
0413 {
0414 bool update = false;
0415 unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us;
0416
0417
0418 unsigned int exit_refresh_rate_in_milli_hz = ((1000000000/max_render_time_in_us)
0419 + (1000*FIXED_REFRESH_EXIT_MARGIN_IN_HZ));
0420 unsigned int exit_frame_duration_in_us = 1000000000/exit_refresh_rate_in_milli_hz;
0421
0422 if (last_render_time_in_us < exit_frame_duration_in_us) {
0423
0424 if (in_out_vrr->fixed.fixed_active) {
0425 in_out_vrr->fixed.frame_counter++;
0426
0427 if (in_out_vrr->fixed.frame_counter >
0428 FIXED_REFRESH_EXIT_FRAME_COUNT) {
0429 in_out_vrr->fixed.frame_counter = 0;
0430 in_out_vrr->fixed.fixed_active = false;
0431 in_out_vrr->fixed.target_refresh_in_uhz = 0;
0432 update = true;
0433 }
0434 } else
0435 in_out_vrr->fixed.frame_counter = 0;
0436 } else if (last_render_time_in_us > max_render_time_in_us) {
0437
0438 if (!in_out_vrr->fixed.fixed_active) {
0439 in_out_vrr->fixed.frame_counter++;
0440
0441 if (in_out_vrr->fixed.frame_counter >
0442 FIXED_REFRESH_ENTER_FRAME_COUNT) {
0443 in_out_vrr->fixed.frame_counter = 0;
0444 in_out_vrr->fixed.fixed_active = true;
0445 in_out_vrr->fixed.target_refresh_in_uhz =
0446 in_out_vrr->max_refresh_in_uhz;
0447 update = true;
0448 }
0449 } else
0450 in_out_vrr->fixed.frame_counter = 0;
0451 }
0452
0453 if (update) {
0454 if (in_out_vrr->fixed.fixed_active) {
0455 in_out_vrr->adjust.v_total_min =
0456 mod_freesync_calc_v_total_from_refresh(
0457 stream, in_out_vrr->max_refresh_in_uhz);
0458 in_out_vrr->adjust.v_total_max =
0459 in_out_vrr->adjust.v_total_min;
0460 } else {
0461 in_out_vrr->adjust.v_total_min =
0462 mod_freesync_calc_v_total_from_refresh(stream,
0463 in_out_vrr->max_refresh_in_uhz);
0464 in_out_vrr->adjust.v_total_max =
0465 mod_freesync_calc_v_total_from_refresh(stream,
0466 in_out_vrr->min_refresh_in_uhz);
0467 }
0468 }
0469 }
0470
0471 static void determine_flip_interval_workaround_req(struct mod_vrr_params *in_vrr,
0472 unsigned int curr_time_stamp_in_us)
0473 {
0474 in_vrr->flip_interval.vsync_to_flip_in_us = curr_time_stamp_in_us -
0475 in_vrr->flip_interval.v_update_timestamp_in_us;
0476
0477
0478 if (in_vrr->flip_interval.flip_interval_workaround_active &&
0479 in_vrr->flip_interval.vsyncs_between_flip < VSYNCS_BETWEEN_FLIP_THRESHOLD &&
0480 in_vrr->flip_interval.vsync_to_flip_in_us > FREESYNC_VSYNC_TO_FLIP_DELTA_IN_US) {
0481 in_vrr->flip_interval.flip_interval_detect_counter = 0;
0482 in_vrr->flip_interval.program_flip_interval_workaround = true;
0483 in_vrr->flip_interval.flip_interval_workaround_active = false;
0484 } else {
0485
0486 if (in_vrr->flip_interval.vsyncs_between_flip >= VSYNCS_BETWEEN_FLIP_THRESHOLD &&
0487 in_vrr->flip_interval.vsync_to_flip_in_us < FREESYNC_VSYNC_TO_FLIP_DELTA_IN_US) {
0488
0489
0490
0491 in_vrr->flip_interval.flip_interval_detect_counter++;
0492 if (in_vrr->flip_interval.flip_interval_detect_counter > FREESYNC_CONSEC_FLIP_AFTER_VSYNC) {
0493
0494 in_vrr->flip_interval.program_flip_interval_workaround = true;
0495 in_vrr->flip_interval.flip_interval_workaround_active = true;
0496 }
0497 } else {
0498
0499 in_vrr->flip_interval.flip_interval_detect_counter = 0;
0500 }
0501 }
0502
0503 in_vrr->flip_interval.vsyncs_between_flip = 0;
0504 }
0505
0506 static bool vrr_settings_require_update(struct core_freesync *core_freesync,
0507 struct mod_freesync_config *in_config,
0508 unsigned int min_refresh_in_uhz,
0509 unsigned int max_refresh_in_uhz,
0510 struct mod_vrr_params *in_vrr)
0511 {
0512 if (in_vrr->state != in_config->state) {
0513 return true;
0514 } else if (in_vrr->state == VRR_STATE_ACTIVE_FIXED &&
0515 in_vrr->fixed.target_refresh_in_uhz !=
0516 in_config->fixed_refresh_in_uhz) {
0517 return true;
0518 } else if (in_vrr->min_refresh_in_uhz != min_refresh_in_uhz) {
0519 return true;
0520 } else if (in_vrr->max_refresh_in_uhz != max_refresh_in_uhz) {
0521 return true;
0522 }
0523
0524 return false;
0525 }
0526
0527 bool mod_freesync_get_vmin_vmax(struct mod_freesync *mod_freesync,
0528 const struct dc_stream_state *stream,
0529 unsigned int *vmin,
0530 unsigned int *vmax)
0531 {
0532 *vmin = stream->adjust.v_total_min;
0533 *vmax = stream->adjust.v_total_max;
0534
0535 return true;
0536 }
0537
0538 bool mod_freesync_get_v_position(struct mod_freesync *mod_freesync,
0539 struct dc_stream_state *stream,
0540 unsigned int *nom_v_pos,
0541 unsigned int *v_pos)
0542 {
0543 struct core_freesync *core_freesync = NULL;
0544 struct crtc_position position;
0545
0546 if (mod_freesync == NULL)
0547 return false;
0548
0549 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
0550
0551 if (dc_stream_get_crtc_position(core_freesync->dc, &stream, 1,
0552 &position.vertical_count,
0553 &position.nominal_vcount)) {
0554
0555 *nom_v_pos = position.nominal_vcount;
0556 *v_pos = position.vertical_count;
0557
0558 return true;
0559 }
0560
0561 return false;
0562 }
0563
0564 static void build_vrr_infopacket_data_v1(const struct mod_vrr_params *vrr,
0565 struct dc_info_packet *infopacket,
0566 bool freesync_on_desktop)
0567 {
0568
0569 infopacket->sb[1] = 0x1A;
0570
0571
0572 infopacket->sb[2] = 0x00;
0573
0574
0575 infopacket->sb[3] = 0x00;
0576
0577
0578
0579
0580
0581
0582
0583
0584 if (vrr->state != VRR_STATE_UNSUPPORTED)
0585 infopacket->sb[6] |= 0x01;
0586
0587
0588 if (vrr->state != VRR_STATE_DISABLED &&
0589 vrr->state != VRR_STATE_UNSUPPORTED)
0590 infopacket->sb[6] |= 0x02;
0591
0592 if (freesync_on_desktop) {
0593
0594 if (vrr->state != VRR_STATE_DISABLED &&
0595 vrr->state != VRR_STATE_UNSUPPORTED)
0596 infopacket->sb[6] |= 0x04;
0597 } else {
0598 if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
0599 vrr->state == VRR_STATE_ACTIVE_FIXED)
0600 infopacket->sb[6] |= 0x04;
0601 }
0602
0603
0604
0605 if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
0606 vrr->state == VRR_STATE_ACTIVE_FIXED) {
0607 infopacket->sb[7] = (unsigned char)((vrr->min_refresh_in_uhz + 500000) / 1000000);
0608 } else {
0609 infopacket->sb[7] = (unsigned char)((vrr->max_refresh_in_uhz + 500000) / 1000000);
0610 }
0611
0612
0613
0614
0615 infopacket->sb[8] = (unsigned char)((vrr->max_refresh_in_uhz + 500000) / 1000000);
0616 }
0617
0618 static void build_vrr_infopacket_data_v3(const struct mod_vrr_params *vrr,
0619 struct dc_info_packet *infopacket)
0620 {
0621 unsigned int min_refresh;
0622 unsigned int max_refresh;
0623 unsigned int fixed_refresh;
0624 unsigned int min_programmed;
0625 unsigned int max_programmed;
0626
0627
0628 infopacket->sb[1] = 0x1A;
0629
0630
0631 infopacket->sb[2] = 0x00;
0632
0633
0634 infopacket->sb[3] = 0x00;
0635
0636
0637
0638
0639
0640
0641
0642
0643 if (vrr->state != VRR_STATE_UNSUPPORTED)
0644 infopacket->sb[6] |= 0x01;
0645
0646
0647 if (vrr->state != VRR_STATE_DISABLED &&
0648 vrr->state != VRR_STATE_UNSUPPORTED)
0649 infopacket->sb[6] |= 0x02;
0650
0651
0652 if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
0653 vrr->state == VRR_STATE_ACTIVE_FIXED)
0654 infopacket->sb[6] |= 0x04;
0655
0656 min_refresh = (vrr->min_refresh_in_uhz + 500000) / 1000000;
0657 max_refresh = (vrr->max_refresh_in_uhz + 500000) / 1000000;
0658 fixed_refresh = (vrr->fixed_refresh_in_uhz + 500000) / 1000000;
0659
0660 min_programmed = (vrr->state == VRR_STATE_ACTIVE_FIXED) ? fixed_refresh :
0661 (vrr->state == VRR_STATE_ACTIVE_VARIABLE) ? min_refresh :
0662 (vrr->state == VRR_STATE_INACTIVE) ? min_refresh :
0663 max_refresh;
0664
0665 max_programmed = (vrr->state == VRR_STATE_ACTIVE_FIXED) ? fixed_refresh :
0666 (vrr->state == VRR_STATE_ACTIVE_VARIABLE) ? max_refresh :
0667 max_refresh;
0668
0669
0670 infopacket->sb[7] = min_programmed & 0xFF;
0671
0672
0673 infopacket->sb[8] = max_programmed & 0xFF;
0674
0675
0676 infopacket->sb[11] = (min_programmed >> 8) & 0x03;
0677
0678
0679 infopacket->sb[12] = (max_programmed >> 8) & 0x03;
0680
0681
0682 infopacket->sb[16] = (vrr->state == VRR_STATE_ACTIVE_FIXED) ? 1 : 0;
0683 }
0684
0685 static void build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf,
0686 struct dc_info_packet *infopacket)
0687 {
0688 if (app_tf != TRANSFER_FUNC_UNKNOWN) {
0689 infopacket->valid = true;
0690
0691 infopacket->sb[6] |= 0x08;
0692
0693 if (app_tf == TRANSFER_FUNC_GAMMA_22) {
0694 infopacket->sb[9] |= 0x04;
0695 }
0696 }
0697 }
0698
0699 static void build_vrr_infopacket_header_v1(enum signal_type signal,
0700 struct dc_info_packet *infopacket,
0701 unsigned int *payload_size)
0702 {
0703 if (dc_is_hdmi_signal(signal)) {
0704
0705
0706
0707
0708
0709
0710 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
0711
0712
0713 infopacket->hb1 = 0x01;
0714
0715
0716 infopacket->hb2 = 0x08;
0717
0718 *payload_size = 0x08;
0719
0720 } else if (dc_is_dp_signal(signal)) {
0721
0722
0723
0724
0725
0726
0727 infopacket->hb0 = 0x00;
0728
0729
0730
0731
0732 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
0733
0734
0735
0736
0737 infopacket->hb2 = 0x1B;
0738
0739
0740
0741
0742 infopacket->hb3 = 0x04;
0743
0744 *payload_size = 0x1B;
0745 }
0746 }
0747
0748 static void build_vrr_infopacket_header_v2(enum signal_type signal,
0749 struct dc_info_packet *infopacket,
0750 unsigned int *payload_size)
0751 {
0752 if (dc_is_hdmi_signal(signal)) {
0753
0754
0755
0756
0757
0758
0759 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
0760
0761
0762 infopacket->hb1 = 0x02;
0763
0764
0765 infopacket->hb2 = 0x09;
0766
0767 *payload_size = 0x09;
0768 } else if (dc_is_dp_signal(signal)) {
0769
0770
0771
0772
0773
0774
0775 infopacket->hb0 = 0x00;
0776
0777
0778
0779
0780 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
0781
0782
0783
0784
0785 infopacket->hb2 = 0x1B;
0786
0787
0788
0789
0790 infopacket->hb3 = 0x08;
0791
0792 *payload_size = 0x1B;
0793 }
0794 }
0795
0796 static void build_vrr_infopacket_header_v3(enum signal_type signal,
0797 struct dc_info_packet *infopacket,
0798 unsigned int *payload_size)
0799 {
0800 unsigned char version;
0801
0802 version = 3;
0803 if (dc_is_hdmi_signal(signal)) {
0804
0805
0806
0807
0808
0809
0810 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
0811
0812
0813 infopacket->hb1 = version;
0814
0815
0816 infopacket->hb2 = 0x10;
0817
0818 *payload_size = 0x10;
0819 } else if (dc_is_dp_signal(signal)) {
0820
0821
0822
0823
0824
0825
0826 infopacket->hb0 = 0x00;
0827
0828
0829
0830
0831 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
0832
0833
0834
0835
0836 infopacket->hb2 = 0x1B;
0837
0838
0839
0840
0841
0842 infopacket->hb3 = (version & 0x3F) << 2;
0843
0844 *payload_size = 0x1B;
0845 }
0846 }
0847
0848 static void build_vrr_infopacket_checksum(unsigned int *payload_size,
0849 struct dc_info_packet *infopacket)
0850 {
0851
0852 unsigned int idx = 0;
0853 unsigned char checksum = 0;
0854
0855 checksum += infopacket->hb0;
0856 checksum += infopacket->hb1;
0857 checksum += infopacket->hb2;
0858 checksum += infopacket->hb3;
0859
0860 for (idx = 1; idx <= *payload_size; idx++)
0861 checksum += infopacket->sb[idx];
0862
0863
0864 infopacket->sb[0] = (unsigned char)(0x100 - checksum);
0865
0866 infopacket->valid = true;
0867 }
0868
0869 static void build_vrr_infopacket_v1(enum signal_type signal,
0870 const struct mod_vrr_params *vrr,
0871 struct dc_info_packet *infopacket,
0872 bool freesync_on_desktop)
0873 {
0874
0875 unsigned int payload_size = 0;
0876
0877 build_vrr_infopacket_header_v1(signal, infopacket, &payload_size);
0878 build_vrr_infopacket_data_v1(vrr, infopacket, freesync_on_desktop);
0879 build_vrr_infopacket_checksum(&payload_size, infopacket);
0880
0881 infopacket->valid = true;
0882 }
0883
0884 static void build_vrr_infopacket_v2(enum signal_type signal,
0885 const struct mod_vrr_params *vrr,
0886 enum color_transfer_func app_tf,
0887 struct dc_info_packet *infopacket,
0888 bool freesync_on_desktop)
0889 {
0890 unsigned int payload_size = 0;
0891
0892 build_vrr_infopacket_header_v2(signal, infopacket, &payload_size);
0893 build_vrr_infopacket_data_v1(vrr, infopacket, freesync_on_desktop);
0894
0895 build_vrr_infopacket_fs2_data(app_tf, infopacket);
0896
0897 build_vrr_infopacket_checksum(&payload_size, infopacket);
0898
0899 infopacket->valid = true;
0900 }
0901 #ifndef TRIM_FSFT
0902 static void build_vrr_infopacket_fast_transport_data(
0903 bool ftActive,
0904 unsigned int ftOutputRate,
0905 struct dc_info_packet *infopacket)
0906 {
0907
0908 unsigned char activeBit = (ftActive) ? 1 << 7 : 0;
0909
0910 infopacket->sb[1] &= ~activeBit;
0911 infopacket->sb[1] |= activeBit;
0912
0913
0914 infopacket->sb[13] = ftOutputRate & 0xFF;
0915
0916
0917 infopacket->sb[14] = (ftOutputRate >> 8) & 0xFF;
0918
0919
0920 infopacket->sb[15] = (ftOutputRate >> 16) & 0xFF;
0921
0922 }
0923 #endif
0924
0925 static void build_vrr_infopacket_v3(enum signal_type signal,
0926 const struct mod_vrr_params *vrr,
0927 #ifndef TRIM_FSFT
0928 bool ftActive, unsigned int ftOutputRate,
0929 #endif
0930 enum color_transfer_func app_tf,
0931 struct dc_info_packet *infopacket)
0932 {
0933 unsigned int payload_size = 0;
0934
0935 build_vrr_infopacket_header_v3(signal, infopacket, &payload_size);
0936 build_vrr_infopacket_data_v3(vrr, infopacket);
0937
0938 build_vrr_infopacket_fs2_data(app_tf, infopacket);
0939
0940 #ifndef TRIM_FSFT
0941 build_vrr_infopacket_fast_transport_data(
0942 ftActive,
0943 ftOutputRate,
0944 infopacket);
0945 #endif
0946
0947 build_vrr_infopacket_checksum(&payload_size, infopacket);
0948
0949 infopacket->valid = true;
0950 }
0951
0952 static void build_vrr_infopacket_sdp_v1_3(enum vrr_packet_type packet_type,
0953 struct dc_info_packet *infopacket)
0954 {
0955 uint8_t idx = 0, size = 0;
0956
0957 size = ((packet_type == PACKET_TYPE_FS_V1) ? 0x08 :
0958 (packet_type == PACKET_TYPE_FS_V3) ? 0x10 :
0959 0x09);
0960
0961 for (idx = infopacket->hb2; idx > 1; idx--)
0962 infopacket->sb[idx] = infopacket->sb[idx-1];
0963
0964 infopacket->sb[1] = size;
0965 infopacket->sb[0] = (infopacket->hb3 >> 2) & 0x3F;
0966 infopacket->hb3 = (0x13 << 2);
0967 infopacket->hb2 = 0x1D;
0968 }
0969
0970 void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync,
0971 const struct dc_stream_state *stream,
0972 const struct mod_vrr_params *vrr,
0973 enum vrr_packet_type packet_type,
0974 enum color_transfer_func app_tf,
0975 struct dc_info_packet *infopacket,
0976 bool pack_sdp_v1_3)
0977 {
0978
0979
0980
0981
0982
0983 if (!vrr->send_info_frame)
0984 return;
0985
0986 switch (packet_type) {
0987 case PACKET_TYPE_FS_V3:
0988 #ifndef TRIM_FSFT
0989
0990 build_vrr_infopacket_v3(
0991 stream->signal, vrr,
0992 stream->timing.flags.FAST_TRANSPORT,
0993 (stream->timing.flags.FAST_TRANSPORT) ?
0994 stream->timing.fast_transport_output_rate_100hz :
0995 stream->timing.pix_clk_100hz,
0996 app_tf, infopacket);
0997 #else
0998 build_vrr_infopacket_v3(stream->signal, vrr, app_tf, infopacket);
0999 #endif
1000 break;
1001 case PACKET_TYPE_FS_V2:
1002 build_vrr_infopacket_v2(stream->signal, vrr, app_tf, infopacket, stream->freesync_on_desktop);
1003 break;
1004 case PACKET_TYPE_VRR:
1005 case PACKET_TYPE_FS_V1:
1006 default:
1007 build_vrr_infopacket_v1(stream->signal, vrr, infopacket, stream->freesync_on_desktop);
1008 }
1009
1010 if (true == pack_sdp_v1_3 &&
1011 true == dc_is_dp_signal(stream->signal) &&
1012 packet_type != PACKET_TYPE_VRR &&
1013 packet_type != PACKET_TYPE_VTEM)
1014 build_vrr_infopacket_sdp_v1_3(packet_type, infopacket);
1015 }
1016
1017 void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync,
1018 const struct dc_stream_state *stream,
1019 struct mod_freesync_config *in_config,
1020 struct mod_vrr_params *in_out_vrr)
1021 {
1022 struct core_freesync *core_freesync = NULL;
1023 unsigned long long nominal_field_rate_in_uhz = 0;
1024 unsigned long long rounded_nominal_in_uhz = 0;
1025 unsigned int refresh_range = 0;
1026 unsigned long long min_refresh_in_uhz = 0;
1027 unsigned long long max_refresh_in_uhz = 0;
1028
1029 if (mod_freesync == NULL)
1030 return;
1031
1032 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1033
1034
1035 nominal_field_rate_in_uhz =
1036 mod_freesync_calc_nominal_field_rate(stream);
1037
1038 min_refresh_in_uhz = in_config->min_refresh_in_uhz;
1039 max_refresh_in_uhz = in_config->max_refresh_in_uhz;
1040
1041
1042 if (max_refresh_in_uhz > nominal_field_rate_in_uhz)
1043 max_refresh_in_uhz = nominal_field_rate_in_uhz;
1044
1045
1046 if (min_refresh_in_uhz > max_refresh_in_uhz)
1047 min_refresh_in_uhz = max_refresh_in_uhz;
1048
1049
1050 rounded_nominal_in_uhz =
1051 div_u64(nominal_field_rate_in_uhz + 50000, 100000) * 100000;
1052 if (in_config->max_refresh_in_uhz == (2 * in_config->min_refresh_in_uhz) &&
1053 in_config->max_refresh_in_uhz == rounded_nominal_in_uhz)
1054 min_refresh_in_uhz = div_u64(nominal_field_rate_in_uhz, 2);
1055
1056 if (!vrr_settings_require_update(core_freesync,
1057 in_config, (unsigned int)min_refresh_in_uhz, (unsigned int)max_refresh_in_uhz,
1058 in_out_vrr))
1059 return;
1060
1061 in_out_vrr->state = in_config->state;
1062 in_out_vrr->send_info_frame = in_config->vsif_supported;
1063
1064 if (in_config->state == VRR_STATE_UNSUPPORTED) {
1065 in_out_vrr->state = VRR_STATE_UNSUPPORTED;
1066 in_out_vrr->supported = false;
1067 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1068 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1069
1070 return;
1071
1072 } else {
1073 in_out_vrr->min_refresh_in_uhz = (unsigned int)min_refresh_in_uhz;
1074 in_out_vrr->max_duration_in_us =
1075 calc_duration_in_us_from_refresh_in_uhz(
1076 (unsigned int)min_refresh_in_uhz);
1077
1078 in_out_vrr->max_refresh_in_uhz = (unsigned int)max_refresh_in_uhz;
1079 in_out_vrr->min_duration_in_us =
1080 calc_duration_in_us_from_refresh_in_uhz(
1081 (unsigned int)max_refresh_in_uhz);
1082
1083 if (in_config->state == VRR_STATE_ACTIVE_FIXED)
1084 in_out_vrr->fixed_refresh_in_uhz = in_config->fixed_refresh_in_uhz;
1085 else
1086 in_out_vrr->fixed_refresh_in_uhz = 0;
1087
1088 refresh_range = div_u64(in_out_vrr->max_refresh_in_uhz + 500000, 1000000) -
1089 + div_u64(in_out_vrr->min_refresh_in_uhz + 500000, 1000000);
1090
1091 in_out_vrr->supported = true;
1092 }
1093
1094 in_out_vrr->fixed.ramping_active = in_config->ramping;
1095
1096 in_out_vrr->btr.btr_enabled = in_config->btr;
1097
1098 if (in_out_vrr->max_refresh_in_uhz < (2 * in_out_vrr->min_refresh_in_uhz))
1099 in_out_vrr->btr.btr_enabled = false;
1100 else {
1101 in_out_vrr->btr.margin_in_us = in_out_vrr->max_duration_in_us -
1102 2 * in_out_vrr->min_duration_in_us;
1103 if (in_out_vrr->btr.margin_in_us > BTR_MAX_MARGIN)
1104 in_out_vrr->btr.margin_in_us = BTR_MAX_MARGIN;
1105 }
1106
1107 in_out_vrr->btr.btr_active = false;
1108 in_out_vrr->btr.inserted_duration_in_us = 0;
1109 in_out_vrr->btr.frames_to_insert = 0;
1110 in_out_vrr->btr.frame_counter = 0;
1111 in_out_vrr->fixed.fixed_active = false;
1112 in_out_vrr->fixed.target_refresh_in_uhz = 0;
1113
1114 in_out_vrr->btr.mid_point_in_us =
1115 (in_out_vrr->min_duration_in_us +
1116 in_out_vrr->max_duration_in_us) / 2;
1117
1118 if (in_out_vrr->state == VRR_STATE_UNSUPPORTED) {
1119 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1120 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1121 } else if (in_out_vrr->state == VRR_STATE_DISABLED) {
1122 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1123 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1124 } else if (in_out_vrr->state == VRR_STATE_INACTIVE) {
1125 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1126 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1127 } else if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE &&
1128 refresh_range >= MIN_REFRESH_RANGE) {
1129
1130 in_out_vrr->adjust.v_total_min =
1131 mod_freesync_calc_v_total_from_refresh(stream,
1132 in_out_vrr->max_refresh_in_uhz);
1133 in_out_vrr->adjust.v_total_max =
1134 mod_freesync_calc_v_total_from_refresh(stream,
1135 in_out_vrr->min_refresh_in_uhz);
1136 } else if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED) {
1137 in_out_vrr->fixed.target_refresh_in_uhz =
1138 in_out_vrr->fixed_refresh_in_uhz;
1139 if (in_out_vrr->fixed.ramping_active &&
1140 in_out_vrr->fixed.fixed_active) {
1141
1142
1143
1144 in_out_vrr->fixed.fixed_active = true;
1145 } else {
1146 in_out_vrr->fixed.fixed_active = true;
1147 in_out_vrr->adjust.v_total_min =
1148 mod_freesync_calc_v_total_from_refresh(stream,
1149 in_out_vrr->fixed.target_refresh_in_uhz);
1150 in_out_vrr->adjust.v_total_max =
1151 in_out_vrr->adjust.v_total_min;
1152 }
1153 } else {
1154 in_out_vrr->state = VRR_STATE_INACTIVE;
1155 in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1156 in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1157 }
1158 }
1159
1160 void mod_freesync_handle_preflip(struct mod_freesync *mod_freesync,
1161 const struct dc_plane_state *plane,
1162 const struct dc_stream_state *stream,
1163 unsigned int curr_time_stamp_in_us,
1164 struct mod_vrr_params *in_out_vrr)
1165 {
1166 struct core_freesync *core_freesync = NULL;
1167 unsigned int last_render_time_in_us = 0;
1168 unsigned int average_render_time_in_us = 0;
1169
1170 if (mod_freesync == NULL)
1171 return;
1172
1173 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1174
1175 if (in_out_vrr->supported &&
1176 in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE) {
1177 unsigned int i = 0;
1178 unsigned int oldest_index = plane->time.index + 1;
1179
1180 if (oldest_index >= DC_PLANE_UPDATE_TIMES_MAX)
1181 oldest_index = 0;
1182
1183 last_render_time_in_us = curr_time_stamp_in_us -
1184 plane->time.prev_update_time_in_us;
1185
1186
1187 for (i = 0; i < DC_PLANE_UPDATE_TIMES_MAX; i++) {
1188 average_render_time_in_us +=
1189 plane->time.time_elapsed_in_us[i];
1190 }
1191 average_render_time_in_us -=
1192 plane->time.time_elapsed_in_us[oldest_index];
1193
1194
1195 average_render_time_in_us += last_render_time_in_us;
1196 average_render_time_in_us /= DC_PLANE_UPDATE_TIMES_MAX;
1197
1198 if (in_out_vrr->btr.btr_enabled) {
1199 apply_below_the_range(core_freesync,
1200 stream,
1201 last_render_time_in_us,
1202 in_out_vrr);
1203 } else {
1204 apply_fixed_refresh(core_freesync,
1205 stream,
1206 last_render_time_in_us,
1207 in_out_vrr);
1208 }
1209
1210 determine_flip_interval_workaround_req(in_out_vrr,
1211 curr_time_stamp_in_us);
1212
1213 }
1214 }
1215
1216 void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync,
1217 const struct dc_stream_state *stream,
1218 struct mod_vrr_params *in_out_vrr)
1219 {
1220 struct core_freesync *core_freesync = NULL;
1221 unsigned int cur_timestamp_in_us;
1222 unsigned long long cur_tick;
1223
1224 if ((mod_freesync == NULL) || (stream == NULL) || (in_out_vrr == NULL))
1225 return;
1226
1227 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1228
1229 if (in_out_vrr->supported == false)
1230 return;
1231
1232 cur_tick = dm_get_timestamp(core_freesync->dc->ctx);
1233 cur_timestamp_in_us = (unsigned int)
1234 div_u64(dm_get_elapse_time_in_ns(core_freesync->dc->ctx, cur_tick, 0), 1000);
1235
1236 in_out_vrr->flip_interval.vsyncs_between_flip++;
1237 in_out_vrr->flip_interval.v_update_timestamp_in_us = cur_timestamp_in_us;
1238
1239 if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE &&
1240 (in_out_vrr->flip_interval.flip_interval_workaround_active ||
1241 (!in_out_vrr->flip_interval.flip_interval_workaround_active &&
1242 in_out_vrr->flip_interval.program_flip_interval_workaround))) {
1243
1244 in_out_vrr->adjust.v_total_min =
1245 mod_freesync_calc_v_total_from_refresh(
1246 stream, in_out_vrr->max_refresh_in_uhz);
1247 in_out_vrr->adjust.v_total_max =
1248 in_out_vrr->adjust.v_total_min;
1249 in_out_vrr->flip_interval.program_flip_interval_workaround = false;
1250 in_out_vrr->flip_interval.do_flip_interval_workaround_cleanup = true;
1251 return;
1252 }
1253
1254 if (in_out_vrr->state != VRR_STATE_ACTIVE_VARIABLE &&
1255 in_out_vrr->flip_interval.do_flip_interval_workaround_cleanup) {
1256 in_out_vrr->flip_interval.do_flip_interval_workaround_cleanup = false;
1257 in_out_vrr->flip_interval.flip_interval_detect_counter = 0;
1258 in_out_vrr->flip_interval.vsyncs_between_flip = 0;
1259 in_out_vrr->flip_interval.vsync_to_flip_in_us = 0;
1260 }
1261
1262
1263
1264
1265 if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE &&
1266 in_out_vrr->btr.btr_active) {
1267
1268
1269
1270
1271
1272
1273
1274 if (in_out_vrr->btr.frames_to_insert ==
1275 in_out_vrr->btr.frame_counter) {
1276 in_out_vrr->adjust.v_total_min =
1277 calc_v_total_from_duration(stream,
1278 in_out_vrr,
1279 in_out_vrr->btr.inserted_duration_in_us);
1280 in_out_vrr->adjust.v_total_max =
1281 in_out_vrr->adjust.v_total_min;
1282 }
1283
1284 if (in_out_vrr->btr.frame_counter > 0)
1285 in_out_vrr->btr.frame_counter--;
1286
1287
1288 if (in_out_vrr->btr.frame_counter == 0) {
1289 in_out_vrr->adjust.v_total_min =
1290 mod_freesync_calc_v_total_from_refresh(stream,
1291 in_out_vrr->max_refresh_in_uhz);
1292 in_out_vrr->adjust.v_total_max =
1293 mod_freesync_calc_v_total_from_refresh(stream,
1294 in_out_vrr->min_refresh_in_uhz);
1295 }
1296 }
1297
1298
1299
1300
1301 if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE)
1302 in_out_vrr->fixed.ramping_active = false;
1303
1304
1305
1306
1307 if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED &&
1308 in_out_vrr->fixed.ramping_active) {
1309 update_v_total_for_static_ramp(
1310 core_freesync, stream, in_out_vrr);
1311 }
1312 }
1313
1314 void mod_freesync_get_settings(struct mod_freesync *mod_freesync,
1315 const struct mod_vrr_params *vrr,
1316 unsigned int *v_total_min, unsigned int *v_total_max,
1317 unsigned int *event_triggers,
1318 unsigned int *window_min, unsigned int *window_max,
1319 unsigned int *lfc_mid_point_in_us,
1320 unsigned int *inserted_frames,
1321 unsigned int *inserted_duration_in_us)
1322 {
1323 if (mod_freesync == NULL)
1324 return;
1325
1326 if (vrr->supported) {
1327 *v_total_min = vrr->adjust.v_total_min;
1328 *v_total_max = vrr->adjust.v_total_max;
1329 *event_triggers = 0;
1330 *lfc_mid_point_in_us = vrr->btr.mid_point_in_us;
1331 *inserted_frames = vrr->btr.frames_to_insert;
1332 *inserted_duration_in_us = vrr->btr.inserted_duration_in_us;
1333 }
1334 }
1335
1336 unsigned long long mod_freesync_calc_nominal_field_rate(
1337 const struct dc_stream_state *stream)
1338 {
1339 unsigned long long nominal_field_rate_in_uhz = 0;
1340 unsigned int total = stream->timing.h_total * stream->timing.v_total;
1341
1342
1343 nominal_field_rate_in_uhz = stream->timing.pix_clk_100hz;
1344 nominal_field_rate_in_uhz *= 100000000ULL;
1345
1346 nominal_field_rate_in_uhz = div_u64(nominal_field_rate_in_uhz, total);
1347
1348 return nominal_field_rate_in_uhz;
1349 }
1350
1351 unsigned long long mod_freesync_calc_field_rate_from_timing(
1352 unsigned int vtotal, unsigned int htotal, unsigned int pix_clk)
1353 {
1354 unsigned long long field_rate_in_uhz = 0;
1355 unsigned int total = htotal * vtotal;
1356
1357
1358 field_rate_in_uhz = pix_clk;
1359 field_rate_in_uhz *= 1000000ULL;
1360
1361 field_rate_in_uhz = div_u64(field_rate_in_uhz, total);
1362
1363 return field_rate_in_uhz;
1364 }
1365
1366 bool mod_freesync_get_freesync_enabled(struct mod_vrr_params *pVrr)
1367 {
1368 return (pVrr->state != VRR_STATE_UNSUPPORTED) && (pVrr->state != VRR_STATE_DISABLED);
1369 }
1370
1371 bool mod_freesync_is_valid_range(uint32_t min_refresh_cap_in_uhz,
1372 uint32_t max_refresh_cap_in_uhz,
1373 uint32_t nominal_field_rate_in_uhz)
1374 {
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409 nominal_field_rate_in_uhz =
1410 div_u64(nominal_field_rate_in_uhz + 500000, 1000000);
1411 min_refresh_cap_in_uhz /= 1000000;
1412 max_refresh_cap_in_uhz /= 1000000;
1413
1414
1415 if (nominal_field_rate_in_uhz > max_refresh_cap_in_uhz ||
1416 nominal_field_rate_in_uhz < min_refresh_cap_in_uhz)
1417 return false;
1418
1419
1420 if (nominal_field_rate_in_uhz < max_refresh_cap_in_uhz)
1421 max_refresh_cap_in_uhz = nominal_field_rate_in_uhz;
1422
1423
1424 if (min_refresh_cap_in_uhz > max_refresh_cap_in_uhz)
1425 return false;
1426
1427
1428 if (nominal_field_rate_in_uhz - min_refresh_cap_in_uhz < 10)
1429 return false;
1430
1431 return true;
1432 }