1 /* 2 * Copyright 2016-2023 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 10 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/exit BTR (to avoid frequent enter-exits at the lower limit) */ 39 #define BTR_MAX_MARGIN 2500 40 /* Threshold to change BTR multiplier (to avoid frequent changes) */ 41 #define BTR_DRIFT_MARGIN 2000 42 /* Threshold to exit fixed refresh rate */ 43 #define FIXED_REFRESH_EXIT_MARGIN_IN_HZ 1 44 /* Number of consecutive frames to check before entering/exiting fixed refresh */ 45 #define FIXED_REFRESH_ENTER_FRAME_COUNT 5 46 #define FIXED_REFRESH_EXIT_FRAME_COUNT 10 47 /* Flip interval workaround constants */ 48 #define VSYNCS_BETWEEN_FLIP_THRESHOLD 2 49 #define FREESYNC_CONSEC_FLIP_AFTER_VSYNC 5 50 #define FREESYNC_VSYNC_TO_FLIP_DELTA_IN_US 500 51 #define MICRO_HZ_TO_HZ(x) (x / 1000000) 52 53 struct core_freesync { 54 struct mod_freesync public; 55 struct dc *dc; 56 }; 57 58 #define MOD_FREESYNC_TO_CORE(mod_freesync)\ 59 container_of(mod_freesync, struct core_freesync, public) 60 61 struct mod_freesync *mod_freesync_create(struct dc *dc) 62 { 63 struct core_freesync *core_freesync = 64 kzalloc(sizeof(struct core_freesync), GFP_KERNEL); 65 66 if (core_freesync == NULL) 67 goto fail_alloc_context; 68 69 if (dc == NULL) 70 goto fail_construct; 71 72 core_freesync->dc = dc; 73 return &core_freesync->public; 74 75 fail_construct: 76 kfree(core_freesync); 77 78 fail_alloc_context: 79 return NULL; 80 } 81 82 void mod_freesync_destroy(struct mod_freesync *mod_freesync) 83 { 84 struct core_freesync *core_freesync = NULL; 85 86 if (mod_freesync == NULL) 87 return; 88 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 89 kfree(core_freesync); 90 } 91 92 #if 0 /* Unused currently */ 93 static unsigned int calc_refresh_in_uhz_from_duration( 94 unsigned int duration_in_ns) 95 { 96 unsigned int refresh_in_uhz = 97 ((unsigned int)(div64_u64((1000000000ULL * 1000000), 98 duration_in_ns))); 99 return refresh_in_uhz; 100 } 101 #endif 102 103 static unsigned int calc_duration_in_us_from_refresh_in_uhz( 104 unsigned int refresh_in_uhz) 105 { 106 unsigned int duration_in_us = 107 ((unsigned int)(div64_u64((1000000000ULL * 1000), 108 refresh_in_uhz))); 109 return duration_in_us; 110 } 111 112 static unsigned int calc_duration_in_us_from_v_total( 113 const struct dc_stream_state *stream, 114 const struct mod_vrr_params *in_vrr, 115 unsigned int v_total) 116 { 117 unsigned int duration_in_us = 118 (unsigned int)(div64_u64(((unsigned long long)(v_total) 119 * 10000) * stream->timing.h_total, 120 stream->timing.pix_clk_100hz)); 121 122 return duration_in_us; 123 } 124 125 unsigned int mod_freesync_calc_v_total_from_refresh( 126 const struct dc_stream_state *stream, 127 unsigned int refresh_in_uhz) 128 { 129 unsigned int v_total; 130 unsigned int frame_duration_in_ns; 131 132 if (refresh_in_uhz == 0) 133 return stream->timing.v_total; 134 135 frame_duration_in_ns = 136 ((unsigned int)(div64_u64((1000000000ULL * 1000000), 137 refresh_in_uhz))); 138 139 if (MICRO_HZ_TO_HZ(refresh_in_uhz) <= stream->timing.min_refresh_in_uhz) { 140 /* When the target refresh rate is the minimum panel refresh rate, 141 * round down the vtotal value to avoid stretching vblank over 142 * panel's vtotal boundary. 143 */ 144 v_total = div64_u64(div64_u64(((unsigned long long)( 145 frame_duration_in_ns) * (stream->timing.pix_clk_100hz / 10)), 146 stream->timing.h_total), 1000000); 147 } else { 148 v_total = div64_u64(div64_u64(((unsigned long long)( 149 frame_duration_in_ns) * (stream->timing.pix_clk_100hz / 10)), 150 stream->timing.h_total) + 500000, 1000000); 151 } 152 153 /* v_total cannot be less than nominal */ 154 if (v_total < stream->timing.v_total) { 155 ASSERT(v_total < stream->timing.v_total); 156 v_total = stream->timing.v_total; 157 } 158 159 return v_total; 160 } 161 162 static unsigned int calc_v_total_from_duration( 163 const struct dc_stream_state *stream, 164 const struct mod_vrr_params *vrr, 165 unsigned int duration_in_us) 166 { 167 unsigned int v_total = 0; 168 169 if (duration_in_us < vrr->min_duration_in_us) 170 duration_in_us = vrr->min_duration_in_us; 171 172 if (duration_in_us > vrr->max_duration_in_us) 173 duration_in_us = vrr->max_duration_in_us; 174 175 if (dc_is_hdmi_signal(stream->signal)) { // change for HDMI to comply with spec 176 uint32_t h_total_up_scaled; 177 178 h_total_up_scaled = stream->timing.h_total * 10000; 179 v_total = div_u64((unsigned long long)duration_in_us 180 * stream->timing.pix_clk_100hz + (h_total_up_scaled - 1), 181 h_total_up_scaled); //ceiling for MMax and MMin for MVRR 182 } else { 183 v_total = div64_u64(div64_u64(((unsigned long long)( 184 duration_in_us) * (stream->timing.pix_clk_100hz / 10)), 185 stream->timing.h_total), 1000); 186 } 187 188 /* v_total cannot be less than nominal */ 189 if (v_total < stream->timing.v_total) { 190 ASSERT(v_total < stream->timing.v_total); 191 v_total = stream->timing.v_total; 192 } 193 194 return v_total; 195 } 196 197 static void update_v_total_for_static_ramp( 198 struct core_freesync *core_freesync, 199 const struct dc_stream_state *stream, 200 struct mod_vrr_params *in_out_vrr) 201 { 202 unsigned int v_total = 0; 203 unsigned int current_duration_in_us = 204 calc_duration_in_us_from_v_total( 205 stream, in_out_vrr, 206 in_out_vrr->adjust.v_total_max); 207 unsigned int target_duration_in_us = 208 calc_duration_in_us_from_refresh_in_uhz( 209 in_out_vrr->fixed.target_refresh_in_uhz); 210 bool ramp_direction_is_up = (current_duration_in_us > 211 target_duration_in_us) ? true : false; 212 213 /* Calculate ratio between new and current frame duration with 3 digit */ 214 unsigned int frame_duration_ratio = div64_u64(1000000, 215 (1000 + div64_u64(((unsigned long long)( 216 STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME) * 217 current_duration_in_us), 218 1000000))); 219 220 /* Calculate delta between new and current frame duration in us */ 221 unsigned int frame_duration_delta = div64_u64(((unsigned long long)( 222 current_duration_in_us) * 223 (1000 - frame_duration_ratio)), 1000); 224 225 /* Adjust frame duration delta based on ratio between current and 226 * standard frame duration (frame duration at 60 Hz refresh rate). 227 */ 228 unsigned int ramp_rate_interpolated = div64_u64(((unsigned long long)( 229 frame_duration_delta) * current_duration_in_us), 16666); 230 231 /* Going to a higher refresh rate (lower frame duration) */ 232 if (ramp_direction_is_up) { 233 /* Reduce frame duration */ 234 current_duration_in_us -= ramp_rate_interpolated; 235 236 /* Adjust for frame duration below min */ 237 if (current_duration_in_us <= target_duration_in_us) { 238 in_out_vrr->fixed.ramping_active = false; 239 in_out_vrr->fixed.ramping_done = true; 240 current_duration_in_us = 241 calc_duration_in_us_from_refresh_in_uhz( 242 in_out_vrr->fixed.target_refresh_in_uhz); 243 } 244 /* Going to a lower refresh rate (larger frame duration) */ 245 } else { 246 /* Increase frame duration */ 247 current_duration_in_us += ramp_rate_interpolated; 248 249 /* Adjust for frame duration above max */ 250 if (current_duration_in_us >= target_duration_in_us) { 251 in_out_vrr->fixed.ramping_active = false; 252 in_out_vrr->fixed.ramping_done = true; 253 current_duration_in_us = 254 calc_duration_in_us_from_refresh_in_uhz( 255 in_out_vrr->fixed.target_refresh_in_uhz); 256 } 257 } 258 259 v_total = div64_u64(div64_u64(((unsigned long long)( 260 current_duration_in_us) * (stream->timing.pix_clk_100hz / 10)), 261 stream->timing.h_total), 1000); 262 263 /* v_total cannot be less than nominal */ 264 if (v_total < stream->timing.v_total) 265 v_total = stream->timing.v_total; 266 267 in_out_vrr->adjust.v_total_min = v_total; 268 in_out_vrr->adjust.v_total_max = v_total; 269 } 270 271 static void apply_below_the_range(struct core_freesync *core_freesync, 272 const struct dc_stream_state *stream, 273 unsigned int last_render_time_in_us, 274 struct mod_vrr_params *in_out_vrr) 275 { 276 unsigned int inserted_frame_duration_in_us = 0; 277 unsigned int mid_point_frames_ceil = 0; 278 unsigned int mid_point_frames_floor = 0; 279 unsigned int frame_time_in_us = 0; 280 unsigned int delta_from_mid_point_in_us_1 = 0xFFFFFFFF; 281 unsigned int delta_from_mid_point_in_us_2 = 0xFFFFFFFF; 282 unsigned int frames_to_insert = 0; 283 unsigned int delta_from_mid_point_delta_in_us; 284 unsigned int max_render_time_in_us = 285 in_out_vrr->max_duration_in_us - in_out_vrr->btr.margin_in_us; 286 287 /* Program BTR */ 288 if ((last_render_time_in_us + in_out_vrr->btr.margin_in_us / 2) < max_render_time_in_us) { 289 /* Exit Below the Range */ 290 if (in_out_vrr->btr.btr_active) { 291 in_out_vrr->btr.frame_counter = 0; 292 in_out_vrr->btr.btr_active = false; 293 } 294 } else if (last_render_time_in_us > (max_render_time_in_us + in_out_vrr->btr.margin_in_us / 2)) { 295 /* Enter Below the Range */ 296 if (!in_out_vrr->btr.btr_active) 297 in_out_vrr->btr.btr_active = true; 298 } 299 300 /* BTR set to "not active" so disengage */ 301 if (!in_out_vrr->btr.btr_active) { 302 in_out_vrr->btr.inserted_duration_in_us = 0; 303 in_out_vrr->btr.frames_to_insert = 0; 304 in_out_vrr->btr.frame_counter = 0; 305 306 /* Restore FreeSync */ 307 in_out_vrr->adjust.v_total_min = 308 mod_freesync_calc_v_total_from_refresh(stream, 309 in_out_vrr->max_refresh_in_uhz); 310 in_out_vrr->adjust.v_total_max = 311 mod_freesync_calc_v_total_from_refresh(stream, 312 in_out_vrr->min_refresh_in_uhz); 313 /* BTR set to "active" so engage */ 314 } else { 315 316 /* Calculate number of midPoint frames that could fit within 317 * the render time interval - take ceil of this value 318 */ 319 mid_point_frames_ceil = (last_render_time_in_us + 320 in_out_vrr->btr.mid_point_in_us - 1) / 321 in_out_vrr->btr.mid_point_in_us; 322 323 if (mid_point_frames_ceil > 0) { 324 frame_time_in_us = last_render_time_in_us / 325 mid_point_frames_ceil; 326 delta_from_mid_point_in_us_1 = 327 (in_out_vrr->btr.mid_point_in_us > 328 frame_time_in_us) ? 329 (in_out_vrr->btr.mid_point_in_us - frame_time_in_us) : 330 (frame_time_in_us - in_out_vrr->btr.mid_point_in_us); 331 } 332 333 /* Calculate number of midPoint frames that could fit within 334 * the render time interval - take floor of this value 335 */ 336 mid_point_frames_floor = last_render_time_in_us / 337 in_out_vrr->btr.mid_point_in_us; 338 339 if (mid_point_frames_floor > 0) { 340 341 frame_time_in_us = last_render_time_in_us / 342 mid_point_frames_floor; 343 delta_from_mid_point_in_us_2 = 344 (in_out_vrr->btr.mid_point_in_us > 345 frame_time_in_us) ? 346 (in_out_vrr->btr.mid_point_in_us - frame_time_in_us) : 347 (frame_time_in_us - in_out_vrr->btr.mid_point_in_us); 348 } 349 350 /* Choose number of frames to insert based on how close it 351 * can get to the mid point of the variable range. 352 * - Delta for CEIL: delta_from_mid_point_in_us_1 353 * - Delta for FLOOR: delta_from_mid_point_in_us_2 354 */ 355 if (mid_point_frames_ceil && 356 (last_render_time_in_us / mid_point_frames_ceil) < 357 in_out_vrr->min_duration_in_us) { 358 /* Check for out of range. 359 * If using CEIL produces a value that is out of range, 360 * then we are forced to use FLOOR. 361 */ 362 frames_to_insert = mid_point_frames_floor; 363 } else if (mid_point_frames_floor < 2) { 364 /* Check if FLOOR would result in non-LFC. In this case 365 * choose to use CEIL 366 */ 367 frames_to_insert = mid_point_frames_ceil; 368 } else if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) { 369 /* If choosing CEIL results in a frame duration that is 370 * closer to the mid point of the range. 371 * Choose CEIL 372 */ 373 frames_to_insert = mid_point_frames_ceil; 374 } else { 375 /* If choosing FLOOR results in a frame duration that is 376 * closer to the mid point of the range. 377 * Choose FLOOR 378 */ 379 frames_to_insert = mid_point_frames_floor; 380 } 381 382 /* Prefer current frame multiplier when BTR is enabled unless it drifts 383 * too far from the midpoint 384 */ 385 if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) { 386 delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_2 - 387 delta_from_mid_point_in_us_1; 388 } else { 389 delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_1 - 390 delta_from_mid_point_in_us_2; 391 } 392 if (in_out_vrr->btr.frames_to_insert != 0 && 393 delta_from_mid_point_delta_in_us < BTR_DRIFT_MARGIN) { 394 if (((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) < 395 max_render_time_in_us) && 396 ((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) > 397 in_out_vrr->min_duration_in_us)) 398 frames_to_insert = in_out_vrr->btr.frames_to_insert; 399 } 400 401 /* Either we've calculated the number of frames to insert, 402 * or we need to insert min duration frames 403 */ 404 if (frames_to_insert && 405 (last_render_time_in_us / frames_to_insert) < 406 in_out_vrr->min_duration_in_us){ 407 frames_to_insert -= (frames_to_insert > 1) ? 408 1 : 0; 409 } 410 411 if (frames_to_insert > 0) 412 inserted_frame_duration_in_us = last_render_time_in_us / 413 frames_to_insert; 414 415 if (inserted_frame_duration_in_us < in_out_vrr->min_duration_in_us) 416 inserted_frame_duration_in_us = in_out_vrr->min_duration_in_us; 417 418 /* Cache the calculated variables */ 419 in_out_vrr->btr.inserted_duration_in_us = 420 inserted_frame_duration_in_us; 421 in_out_vrr->btr.frames_to_insert = frames_to_insert; 422 in_out_vrr->btr.frame_counter = frames_to_insert; 423 } 424 } 425 426 static void apply_fixed_refresh(struct core_freesync *core_freesync, 427 const struct dc_stream_state *stream, 428 unsigned int last_render_time_in_us, 429 struct mod_vrr_params *in_out_vrr) 430 { 431 bool update = false; 432 unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us; 433 434 /* Compute the exit refresh rate and exit frame duration */ 435 unsigned int exit_refresh_rate_in_milli_hz = ((1000000000/max_render_time_in_us) 436 + (1000*FIXED_REFRESH_EXIT_MARGIN_IN_HZ)); 437 unsigned int exit_frame_duration_in_us = 1000000000/exit_refresh_rate_in_milli_hz; 438 439 if (last_render_time_in_us < exit_frame_duration_in_us) { 440 /* Exit Fixed Refresh mode */ 441 if (in_out_vrr->fixed.fixed_active) { 442 in_out_vrr->fixed.frame_counter++; 443 444 if (in_out_vrr->fixed.frame_counter > 445 FIXED_REFRESH_EXIT_FRAME_COUNT) { 446 in_out_vrr->fixed.frame_counter = 0; 447 in_out_vrr->fixed.fixed_active = false; 448 in_out_vrr->fixed.target_refresh_in_uhz = 0; 449 update = true; 450 } 451 } else 452 in_out_vrr->fixed.frame_counter = 0; 453 } else if (last_render_time_in_us > max_render_time_in_us) { 454 /* Enter Fixed Refresh mode */ 455 if (!in_out_vrr->fixed.fixed_active) { 456 in_out_vrr->fixed.frame_counter++; 457 458 if (in_out_vrr->fixed.frame_counter > 459 FIXED_REFRESH_ENTER_FRAME_COUNT) { 460 in_out_vrr->fixed.frame_counter = 0; 461 in_out_vrr->fixed.fixed_active = true; 462 in_out_vrr->fixed.target_refresh_in_uhz = 463 in_out_vrr->max_refresh_in_uhz; 464 update = true; 465 } 466 } else 467 in_out_vrr->fixed.frame_counter = 0; 468 } 469 470 if (update) { 471 if (in_out_vrr->fixed.fixed_active) { 472 in_out_vrr->adjust.v_total_min = 473 mod_freesync_calc_v_total_from_refresh( 474 stream, in_out_vrr->max_refresh_in_uhz); 475 in_out_vrr->adjust.v_total_max = 476 in_out_vrr->adjust.v_total_min; 477 } else { 478 in_out_vrr->adjust.v_total_min = 479 mod_freesync_calc_v_total_from_refresh(stream, 480 in_out_vrr->max_refresh_in_uhz); 481 in_out_vrr->adjust.v_total_max = 482 mod_freesync_calc_v_total_from_refresh(stream, 483 in_out_vrr->min_refresh_in_uhz); 484 } 485 } 486 } 487 488 static void determine_flip_interval_workaround_req(struct mod_vrr_params *in_vrr, 489 unsigned int curr_time_stamp_in_us) 490 { 491 in_vrr->flip_interval.vsync_to_flip_in_us = curr_time_stamp_in_us - 492 in_vrr->flip_interval.v_update_timestamp_in_us; 493 494 /* Determine conditions for stopping workaround */ 495 if (in_vrr->flip_interval.flip_interval_workaround_active && 496 in_vrr->flip_interval.vsyncs_between_flip < VSYNCS_BETWEEN_FLIP_THRESHOLD && 497 in_vrr->flip_interval.vsync_to_flip_in_us > FREESYNC_VSYNC_TO_FLIP_DELTA_IN_US) { 498 in_vrr->flip_interval.flip_interval_detect_counter = 0; 499 in_vrr->flip_interval.program_flip_interval_workaround = true; 500 in_vrr->flip_interval.flip_interval_workaround_active = false; 501 } else { 502 /* Determine conditions for starting workaround */ 503 if (in_vrr->flip_interval.vsyncs_between_flip >= VSYNCS_BETWEEN_FLIP_THRESHOLD && 504 in_vrr->flip_interval.vsync_to_flip_in_us < FREESYNC_VSYNC_TO_FLIP_DELTA_IN_US) { 505 /* Increase flip interval counter we have 2 vsyncs between flips and 506 * vsync to flip interval is less than 500us 507 */ 508 in_vrr->flip_interval.flip_interval_detect_counter++; 509 if (in_vrr->flip_interval.flip_interval_detect_counter > FREESYNC_CONSEC_FLIP_AFTER_VSYNC) { 510 /* Start workaround if we detect 5 consecutive instances of the above case */ 511 in_vrr->flip_interval.program_flip_interval_workaround = true; 512 in_vrr->flip_interval.flip_interval_workaround_active = true; 513 } 514 } else { 515 /* Reset the flip interval counter if we condition is no longer met */ 516 in_vrr->flip_interval.flip_interval_detect_counter = 0; 517 } 518 } 519 520 in_vrr->flip_interval.vsyncs_between_flip = 0; 521 } 522 523 static bool vrr_settings_require_update(struct core_freesync *core_freesync, 524 struct mod_freesync_config *in_config, 525 unsigned int min_refresh_in_uhz, 526 unsigned int max_refresh_in_uhz, 527 struct mod_vrr_params *in_vrr) 528 { 529 if (in_vrr->state != in_config->state) { 530 return true; 531 } else if (in_vrr->state == VRR_STATE_ACTIVE_FIXED && 532 in_vrr->fixed.target_refresh_in_uhz != 533 in_config->fixed_refresh_in_uhz) { 534 return true; 535 } else if (in_vrr->min_refresh_in_uhz != min_refresh_in_uhz) { 536 return true; 537 } else if (in_vrr->max_refresh_in_uhz != max_refresh_in_uhz) { 538 return true; 539 } 540 541 return false; 542 } 543 544 bool mod_freesync_get_vmin_vmax(struct mod_freesync *mod_freesync, 545 const struct dc_stream_state *stream, 546 unsigned int *vmin, 547 unsigned int *vmax) 548 { 549 *vmin = stream->adjust.v_total_min; 550 *vmax = stream->adjust.v_total_max; 551 552 return true; 553 } 554 555 bool mod_freesync_get_v_position(struct mod_freesync *mod_freesync, 556 struct dc_stream_state *stream, 557 unsigned int *nom_v_pos, 558 unsigned int *v_pos) 559 { 560 struct core_freesync *core_freesync = NULL; 561 struct crtc_position position; 562 563 if (mod_freesync == NULL) 564 return false; 565 566 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 567 568 if (dc_stream_get_crtc_position(core_freesync->dc, &stream, 1, 569 &position.vertical_count, 570 &position.nominal_vcount)) { 571 572 *nom_v_pos = position.nominal_vcount; 573 *v_pos = position.vertical_count; 574 575 return true; 576 } 577 578 return false; 579 } 580 581 static void build_vrr_infopacket_data_v1(const struct mod_vrr_params *vrr, 582 struct dc_info_packet *infopacket, 583 bool freesync_on_desktop) 584 { 585 /* PB1 = 0x1A (24bit AMD IEEE OUI (0x00001A) - Byte 0) */ 586 infopacket->sb[1] = 0x1A; 587 588 /* PB2 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 1) */ 589 infopacket->sb[2] = 0x00; 590 591 /* PB3 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 2) */ 592 infopacket->sb[3] = 0x00; 593 594 /* PB4 = Reserved */ 595 596 /* PB5 = Reserved */ 597 598 /* PB6 = [Bits 7:3 = Reserved] */ 599 600 /* PB6 = [Bit 0 = FreeSync Supported] */ 601 if (vrr->state != VRR_STATE_UNSUPPORTED) 602 infopacket->sb[6] |= 0x01; 603 604 /* PB6 = [Bit 1 = FreeSync Enabled] */ 605 if (vrr->state != VRR_STATE_DISABLED && 606 vrr->state != VRR_STATE_UNSUPPORTED) 607 infopacket->sb[6] |= 0x02; 608 609 if (freesync_on_desktop) { 610 /* PB6 = [Bit 2 = FreeSync Active] */ 611 if (vrr->state != VRR_STATE_DISABLED && 612 vrr->state != VRR_STATE_UNSUPPORTED) 613 infopacket->sb[6] |= 0x04; 614 } else { 615 if (vrr->state == VRR_STATE_ACTIVE_VARIABLE || 616 vrr->state == VRR_STATE_ACTIVE_FIXED) 617 infopacket->sb[6] |= 0x04; 618 } 619 620 // For v1 & 2 infoframes program nominal if non-fs mode, otherwise full range 621 /* PB7 = FreeSync Minimum refresh rate (Hz) */ 622 if (vrr->state == VRR_STATE_ACTIVE_VARIABLE || 623 vrr->state == VRR_STATE_ACTIVE_FIXED) { 624 infopacket->sb[7] = (unsigned char)((vrr->min_refresh_in_uhz + 500000) / 1000000); 625 } else { 626 infopacket->sb[7] = (unsigned char)((vrr->max_refresh_in_uhz + 500000) / 1000000); 627 } 628 629 /* PB8 = FreeSync Maximum refresh rate (Hz) 630 * Note: We should never go above the field rate of the mode timing set. 631 */ 632 infopacket->sb[8] = (unsigned char)((vrr->max_refresh_in_uhz + 500000) / 1000000); 633 } 634 635 static void build_vrr_infopacket_data_v3(const struct mod_vrr_params *vrr, 636 struct dc_info_packet *infopacket, 637 bool freesync_on_desktop) 638 { 639 unsigned int min_refresh; 640 unsigned int max_refresh; 641 unsigned int fixed_refresh; 642 unsigned int min_programmed; 643 644 /* PB1 = 0x1A (24bit AMD IEEE OUI (0x00001A) - Byte 0) */ 645 infopacket->sb[1] = 0x1A; 646 647 /* PB2 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 1) */ 648 infopacket->sb[2] = 0x00; 649 650 /* PB3 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 2) */ 651 infopacket->sb[3] = 0x00; 652 653 /* PB4 = Reserved */ 654 655 /* PB5 = Reserved */ 656 657 /* PB6 = [Bits 7:3 = Reserved] */ 658 659 /* PB6 = [Bit 0 = FreeSync Supported] */ 660 if (vrr->state != VRR_STATE_UNSUPPORTED) 661 infopacket->sb[6] |= 0x01; 662 663 /* PB6 = [Bit 1 = FreeSync Enabled] */ 664 if (vrr->state != VRR_STATE_DISABLED && 665 vrr->state != VRR_STATE_UNSUPPORTED) 666 infopacket->sb[6] |= 0x02; 667 668 /* PB6 = [Bit 2 = FreeSync Active] */ 669 if (freesync_on_desktop) { 670 if (vrr->state != VRR_STATE_DISABLED && 671 vrr->state != VRR_STATE_UNSUPPORTED) 672 infopacket->sb[6] |= 0x04; 673 } else { 674 if (vrr->state == VRR_STATE_ACTIVE_VARIABLE || 675 vrr->state == VRR_STATE_ACTIVE_FIXED) 676 infopacket->sb[6] |= 0x04; 677 } 678 679 min_refresh = (vrr->min_refresh_in_uhz + 500000) / 1000000; 680 max_refresh = (vrr->max_refresh_in_uhz + 500000) / 1000000; 681 fixed_refresh = (vrr->fixed_refresh_in_uhz + 500000) / 1000000; 682 683 min_programmed = (vrr->state == VRR_STATE_ACTIVE_FIXED) ? fixed_refresh : 684 (vrr->state == VRR_STATE_ACTIVE_VARIABLE) ? min_refresh : 685 (vrr->state == VRR_STATE_INACTIVE) ? min_refresh : 686 max_refresh; // Non-fs case, program nominal range 687 688 /* PB7 = FreeSync Minimum refresh rate (Hz) */ 689 infopacket->sb[7] = min_programmed & 0xFF; 690 691 /* PB8 = FreeSync Maximum refresh rate (Hz) */ 692 infopacket->sb[8] = max_refresh & 0xFF; 693 694 /* PB11 : MSB FreeSync Minimum refresh rate [Hz] - bits 9:8 */ 695 infopacket->sb[11] = (min_programmed >> 8) & 0x03; 696 697 /* PB12 : MSB FreeSync Maximum refresh rate [Hz] - bits 9:8 */ 698 infopacket->sb[12] = (max_refresh >> 8) & 0x03; 699 700 /* PB16 : Reserved bits 7:1, FixedRate bit 0 */ 701 infopacket->sb[16] = (vrr->state == VRR_STATE_ACTIVE_FIXED) ? 1 : 0; 702 } 703 704 static void build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf, 705 struct dc_info_packet *infopacket) 706 { 707 if (app_tf != TRANSFER_FUNC_UNKNOWN) { 708 infopacket->valid = true; 709 710 if (app_tf == TRANSFER_FUNC_PQ2084) 711 infopacket->sb[9] |= 0x20; // PB9 = [Bit 5 = PQ EOTF Active] 712 else { 713 infopacket->sb[6] |= 0x08; // PB6 = [Bit 3 = Native Color Active] 714 if (app_tf == TRANSFER_FUNC_GAMMA_22) 715 infopacket->sb[9] |= 0x04; // PB9 = [Bit 2 = Gamma 2.2 EOTF Active] 716 } 717 } 718 } 719 720 static void build_vrr_infopacket_header_v1(enum signal_type signal, 721 struct dc_info_packet *infopacket, 722 unsigned int *payload_size) 723 { 724 if (dc_is_hdmi_signal(signal)) { 725 726 /* HEADER */ 727 728 /* HB0 = Packet Type = 0x83 (Source Product 729 * Descriptor InfoFrame) 730 */ 731 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD; 732 733 /* HB1 = Version = 0x01 */ 734 infopacket->hb1 = 0x01; 735 736 /* HB2 = [Bits 7:5 = 0] [Bits 4:0 = Length = 0x08] */ 737 infopacket->hb2 = 0x08; 738 739 *payload_size = 0x08; 740 741 } else if (dc_is_dp_signal(signal)) { 742 743 /* HEADER */ 744 745 /* HB0 = Secondary-data Packet ID = 0 - Only non-zero 746 * when used to associate audio related info packets 747 */ 748 infopacket->hb0 = 0x00; 749 750 /* HB1 = Packet Type = 0x83 (Source Product 751 * Descriptor InfoFrame) 752 */ 753 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD; 754 755 /* HB2 = [Bits 7:0 = Least significant eight bits - 756 * For INFOFRAME, the value must be 1Bh] 757 */ 758 infopacket->hb2 = 0x1B; 759 760 /* HB3 = [Bits 7:2 = INFOFRAME SDP Version Number = 0x1] 761 * [Bits 1:0 = Most significant two bits = 0x00] 762 */ 763 infopacket->hb3 = 0x04; 764 765 *payload_size = 0x1B; 766 } 767 } 768 769 static void build_vrr_infopacket_header_v2(enum signal_type signal, 770 struct dc_info_packet *infopacket, 771 unsigned int *payload_size) 772 { 773 if (dc_is_hdmi_signal(signal)) { 774 775 /* HEADER */ 776 777 /* HB0 = Packet Type = 0x83 (Source Product 778 * Descriptor InfoFrame) 779 */ 780 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD; 781 782 /* HB1 = Version = 0x02 */ 783 infopacket->hb1 = 0x02; 784 785 /* HB2 = [Bits 7:5 = 0] [Bits 4:0 = Length = 0x09] */ 786 infopacket->hb2 = 0x09; 787 788 *payload_size = 0x09; 789 } else if (dc_is_dp_signal(signal)) { 790 791 /* HEADER */ 792 793 /* HB0 = Secondary-data Packet ID = 0 - Only non-zero 794 * when used to associate audio related info packets 795 */ 796 infopacket->hb0 = 0x00; 797 798 /* HB1 = Packet Type = 0x83 (Source Product 799 * Descriptor InfoFrame) 800 */ 801 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD; 802 803 /* HB2 = [Bits 7:0 = Least significant eight bits - 804 * For INFOFRAME, the value must be 1Bh] 805 */ 806 infopacket->hb2 = 0x1B; 807 808 /* HB3 = [Bits 7:2 = INFOFRAME SDP Version Number = 0x2] 809 * [Bits 1:0 = Most significant two bits = 0x00] 810 */ 811 infopacket->hb3 = 0x08; 812 813 *payload_size = 0x1B; 814 } 815 } 816 817 static void build_vrr_infopacket_header_v3(enum signal_type signal, 818 struct dc_info_packet *infopacket, 819 unsigned int *payload_size) 820 { 821 unsigned char version; 822 823 version = 3; 824 if (dc_is_hdmi_signal(signal)) { 825 826 /* HEADER */ 827 828 /* HB0 = Packet Type = 0x83 (Source Product 829 * Descriptor InfoFrame) 830 */ 831 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD; 832 833 /* HB1 = Version = 0x03 */ 834 infopacket->hb1 = version; 835 836 /* HB2 = [Bits 7:5 = 0] [Bits 4:0 = Length] */ 837 infopacket->hb2 = 0x10; 838 839 *payload_size = 0x10; 840 } else if (dc_is_dp_signal(signal)) { 841 842 /* HEADER */ 843 844 /* HB0 = Secondary-data Packet ID = 0 - Only non-zero 845 * when used to associate audio related info packets 846 */ 847 infopacket->hb0 = 0x00; 848 849 /* HB1 = Packet Type = 0x83 (Source Product 850 * Descriptor InfoFrame) 851 */ 852 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD; 853 854 /* HB2 = [Bits 7:0 = Least significant eight bits - 855 * For INFOFRAME, the value must be 1Bh] 856 */ 857 infopacket->hb2 = 0x1B; 858 859 /* HB3 = [Bits 7:2 = INFOFRAME SDP Version Number = 0x2] 860 * [Bits 1:0 = Most significant two bits = 0x00] 861 */ 862 863 infopacket->hb3 = (version & 0x3F) << 2; 864 865 *payload_size = 0x1B; 866 } 867 } 868 869 static void build_vrr_infopacket_checksum(unsigned int *payload_size, 870 struct dc_info_packet *infopacket) 871 { 872 /* Calculate checksum */ 873 unsigned int idx = 0; 874 unsigned char checksum = 0; 875 876 checksum += infopacket->hb0; 877 checksum += infopacket->hb1; 878 checksum += infopacket->hb2; 879 checksum += infopacket->hb3; 880 881 for (idx = 1; idx <= *payload_size; idx++) 882 checksum += infopacket->sb[idx]; 883 884 /* PB0 = Checksum (one byte complement) */ 885 infopacket->sb[0] = (unsigned char)(0x100 - checksum); 886 887 infopacket->valid = true; 888 } 889 890 static void build_vrr_infopacket_v1(enum signal_type signal, 891 const struct mod_vrr_params *vrr, 892 struct dc_info_packet *infopacket, 893 bool freesync_on_desktop) 894 { 895 /* SPD info packet for FreeSync */ 896 unsigned int payload_size = 0; 897 898 build_vrr_infopacket_header_v1(signal, infopacket, &payload_size); 899 build_vrr_infopacket_data_v1(vrr, infopacket, freesync_on_desktop); 900 build_vrr_infopacket_checksum(&payload_size, infopacket); 901 902 infopacket->valid = true; 903 } 904 905 static void build_vrr_infopacket_v2(enum signal_type signal, 906 const struct mod_vrr_params *vrr, 907 enum color_transfer_func app_tf, 908 struct dc_info_packet *infopacket, 909 bool freesync_on_desktop) 910 { 911 unsigned int payload_size = 0; 912 913 build_vrr_infopacket_header_v2(signal, infopacket, &payload_size); 914 build_vrr_infopacket_data_v1(vrr, infopacket, freesync_on_desktop); 915 916 build_vrr_infopacket_fs2_data(app_tf, infopacket); 917 918 build_vrr_infopacket_checksum(&payload_size, infopacket); 919 920 infopacket->valid = true; 921 } 922 923 static void build_vrr_infopacket_v3(enum signal_type signal, 924 const struct mod_vrr_params *vrr, 925 enum color_transfer_func app_tf, 926 struct dc_info_packet *infopacket, 927 bool freesync_on_desktop) 928 { 929 unsigned int payload_size = 0; 930 931 build_vrr_infopacket_header_v3(signal, infopacket, &payload_size); 932 build_vrr_infopacket_data_v3(vrr, infopacket, freesync_on_desktop); 933 934 build_vrr_infopacket_fs2_data(app_tf, infopacket); 935 936 build_vrr_infopacket_checksum(&payload_size, infopacket); 937 938 infopacket->valid = true; 939 } 940 941 static void build_vrr_infopacket_sdp_v1_3(enum vrr_packet_type packet_type, 942 struct dc_info_packet *infopacket) 943 { 944 uint8_t idx = 0, size = 0; 945 946 size = ((packet_type == PACKET_TYPE_FS_V1) ? 0x08 : 947 (packet_type == PACKET_TYPE_FS_V3) ? 0x10 : 948 0x09); 949 950 for (idx = infopacket->hb2; idx > 1; idx--) // Data Byte Count: 0x1B 951 infopacket->sb[idx] = infopacket->sb[idx-1]; 952 953 infopacket->sb[1] = size; // Length 954 infopacket->sb[0] = (infopacket->hb3 >> 2) & 0x3F;//Version 955 infopacket->hb3 = (0x13 << 2); // Header,SDP 1.3 956 infopacket->hb2 = 0x1D; 957 } 958 959 void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync, 960 const struct dc_stream_state *stream, 961 const struct mod_vrr_params *vrr, 962 enum vrr_packet_type packet_type, 963 enum color_transfer_func app_tf, 964 struct dc_info_packet *infopacket, 965 bool pack_sdp_v1_3) 966 { 967 /* SPD info packet for FreeSync 968 * VTEM info packet for HdmiVRR 969 * Check if Freesync is supported. Return if false. If true, 970 * set the corresponding bit in the info packet 971 */ 972 if (!vrr->send_info_frame) 973 return; 974 975 switch (packet_type) { 976 case PACKET_TYPE_FS_V3: 977 build_vrr_infopacket_v3(stream->signal, vrr, app_tf, infopacket, stream->freesync_on_desktop); 978 break; 979 case PACKET_TYPE_FS_V2: 980 build_vrr_infopacket_v2(stream->signal, vrr, app_tf, infopacket, stream->freesync_on_desktop); 981 break; 982 case PACKET_TYPE_VRR: 983 case PACKET_TYPE_FS_V1: 984 default: 985 build_vrr_infopacket_v1(stream->signal, vrr, infopacket, stream->freesync_on_desktop); 986 } 987 988 if (true == pack_sdp_v1_3 && 989 true == dc_is_dp_signal(stream->signal) && 990 packet_type != PACKET_TYPE_VRR && 991 packet_type != PACKET_TYPE_VTEM) 992 build_vrr_infopacket_sdp_v1_3(packet_type, infopacket); 993 } 994 995 void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync, 996 const struct dc_stream_state *stream, 997 struct mod_freesync_config *in_config, 998 struct mod_vrr_params *in_out_vrr) 999 { 1000 struct core_freesync *core_freesync = NULL; 1001 unsigned long long nominal_field_rate_in_uhz = 0; 1002 unsigned long long rounded_nominal_in_uhz = 0; 1003 unsigned int refresh_range = 0; 1004 unsigned long long min_refresh_in_uhz = 0; 1005 unsigned long long max_refresh_in_uhz = 0; 1006 unsigned long long min_hardware_refresh_in_uhz = 0; 1007 1008 if (mod_freesync == NULL) 1009 return; 1010 1011 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1012 1013 /* Calculate nominal field rate for stream */ 1014 nominal_field_rate_in_uhz = 1015 mod_freesync_calc_nominal_field_rate(stream); 1016 1017 if (stream->ctx->dc->caps.max_v_total != 0 && stream->timing.h_total != 0) { 1018 min_hardware_refresh_in_uhz = div64_u64((stream->timing.pix_clk_100hz * 100000000ULL), 1019 (stream->timing.h_total * (long long)stream->ctx->dc->caps.max_v_total)); 1020 } 1021 /* Limit minimum refresh rate to what can be supported by hardware */ 1022 min_refresh_in_uhz = min_hardware_refresh_in_uhz > in_config->min_refresh_in_uhz ? 1023 min_hardware_refresh_in_uhz : in_config->min_refresh_in_uhz; 1024 max_refresh_in_uhz = in_config->max_refresh_in_uhz; 1025 1026 /* Full range may be larger than current video timing, so cap at nominal */ 1027 if (max_refresh_in_uhz > nominal_field_rate_in_uhz) 1028 max_refresh_in_uhz = nominal_field_rate_in_uhz; 1029 1030 /* Full range may be larger than current video timing, so cap at nominal */ 1031 if (min_refresh_in_uhz > max_refresh_in_uhz) 1032 min_refresh_in_uhz = max_refresh_in_uhz; 1033 1034 /* If a monitor reports exactly max refresh of 2x of min, enforce it on nominal */ 1035 rounded_nominal_in_uhz = 1036 div_u64(nominal_field_rate_in_uhz + 50000, 100000) * 100000; 1037 if (in_config->max_refresh_in_uhz == (2 * in_config->min_refresh_in_uhz) && 1038 in_config->max_refresh_in_uhz == rounded_nominal_in_uhz) 1039 min_refresh_in_uhz = div_u64(nominal_field_rate_in_uhz, 2); 1040 1041 if (!vrr_settings_require_update(core_freesync, 1042 in_config, (unsigned int)min_refresh_in_uhz, (unsigned int)max_refresh_in_uhz, 1043 in_out_vrr)) 1044 return; 1045 1046 in_out_vrr->state = in_config->state; 1047 in_out_vrr->send_info_frame = in_config->vsif_supported; 1048 1049 if (in_config->state == VRR_STATE_UNSUPPORTED) { 1050 in_out_vrr->state = VRR_STATE_UNSUPPORTED; 1051 in_out_vrr->supported = false; 1052 in_out_vrr->adjust.v_total_min = stream->timing.v_total; 1053 in_out_vrr->adjust.v_total_max = stream->timing.v_total; 1054 1055 return; 1056 1057 } else { 1058 in_out_vrr->min_refresh_in_uhz = (unsigned int)min_refresh_in_uhz; 1059 in_out_vrr->max_duration_in_us = 1060 calc_duration_in_us_from_refresh_in_uhz( 1061 (unsigned int)min_refresh_in_uhz); 1062 1063 in_out_vrr->max_refresh_in_uhz = (unsigned int)max_refresh_in_uhz; 1064 in_out_vrr->min_duration_in_us = 1065 calc_duration_in_us_from_refresh_in_uhz( 1066 (unsigned int)max_refresh_in_uhz); 1067 1068 if (in_config->state == VRR_STATE_ACTIVE_FIXED) 1069 in_out_vrr->fixed_refresh_in_uhz = in_config->fixed_refresh_in_uhz; 1070 else 1071 in_out_vrr->fixed_refresh_in_uhz = 0; 1072 1073 refresh_range = div_u64(in_out_vrr->max_refresh_in_uhz + 500000, 1000000) - 1074 div_u64(in_out_vrr->min_refresh_in_uhz + 500000, 1000000); 1075 1076 in_out_vrr->supported = true; 1077 } 1078 1079 in_out_vrr->fixed.ramping_active = in_config->ramping; 1080 1081 in_out_vrr->btr.btr_enabled = in_config->btr; 1082 1083 if (in_out_vrr->max_refresh_in_uhz < (2 * in_out_vrr->min_refresh_in_uhz)) 1084 in_out_vrr->btr.btr_enabled = false; 1085 else { 1086 in_out_vrr->btr.margin_in_us = in_out_vrr->max_duration_in_us - 1087 2 * in_out_vrr->min_duration_in_us; 1088 if (in_out_vrr->btr.margin_in_us > BTR_MAX_MARGIN) 1089 in_out_vrr->btr.margin_in_us = BTR_MAX_MARGIN; 1090 } 1091 1092 in_out_vrr->btr.btr_active = false; 1093 in_out_vrr->btr.inserted_duration_in_us = 0; 1094 in_out_vrr->btr.frames_to_insert = 0; 1095 in_out_vrr->btr.frame_counter = 0; 1096 in_out_vrr->fixed.fixed_active = false; 1097 in_out_vrr->fixed.target_refresh_in_uhz = 0; 1098 1099 in_out_vrr->btr.mid_point_in_us = 1100 (in_out_vrr->min_duration_in_us + 1101 in_out_vrr->max_duration_in_us) / 2; 1102 1103 if (in_out_vrr->state == VRR_STATE_UNSUPPORTED) { 1104 in_out_vrr->adjust.v_total_min = stream->timing.v_total; 1105 in_out_vrr->adjust.v_total_max = stream->timing.v_total; 1106 } else if (in_out_vrr->state == VRR_STATE_DISABLED) { 1107 in_out_vrr->adjust.v_total_min = stream->timing.v_total; 1108 in_out_vrr->adjust.v_total_max = stream->timing.v_total; 1109 } else if (in_out_vrr->state == VRR_STATE_INACTIVE) { 1110 in_out_vrr->adjust.v_total_min = stream->timing.v_total; 1111 in_out_vrr->adjust.v_total_max = stream->timing.v_total; 1112 } else if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE && 1113 refresh_range >= MIN_REFRESH_RANGE) { 1114 1115 in_out_vrr->adjust.v_total_min = 1116 mod_freesync_calc_v_total_from_refresh(stream, 1117 in_out_vrr->max_refresh_in_uhz); 1118 in_out_vrr->adjust.v_total_max = 1119 mod_freesync_calc_v_total_from_refresh(stream, 1120 in_out_vrr->min_refresh_in_uhz); 1121 } else if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED) { 1122 in_out_vrr->fixed.target_refresh_in_uhz = 1123 in_out_vrr->fixed_refresh_in_uhz; 1124 if (in_out_vrr->fixed.ramping_active && 1125 in_out_vrr->fixed.fixed_active) { 1126 /* Do not update vtotals if ramping is already active 1127 * in order to continue ramp from current refresh. 1128 */ 1129 in_out_vrr->fixed.fixed_active = true; 1130 } else { 1131 in_out_vrr->fixed.fixed_active = true; 1132 in_out_vrr->adjust.v_total_min = 1133 mod_freesync_calc_v_total_from_refresh(stream, 1134 in_out_vrr->fixed.target_refresh_in_uhz); 1135 in_out_vrr->adjust.v_total_max = 1136 in_out_vrr->adjust.v_total_min; 1137 } 1138 } else { 1139 in_out_vrr->state = VRR_STATE_INACTIVE; 1140 in_out_vrr->adjust.v_total_min = stream->timing.v_total; 1141 in_out_vrr->adjust.v_total_max = stream->timing.v_total; 1142 } 1143 1144 in_out_vrr->adjust.allow_otg_v_count_halt = (in_config->state == VRR_STATE_ACTIVE_FIXED) ? true : false; 1145 } 1146 1147 void mod_freesync_handle_preflip(struct mod_freesync *mod_freesync, 1148 const struct dc_plane_state *plane, 1149 const struct dc_stream_state *stream, 1150 unsigned int curr_time_stamp_in_us, 1151 struct mod_vrr_params *in_out_vrr) 1152 { 1153 struct core_freesync *core_freesync = NULL; 1154 unsigned int last_render_time_in_us = 0; 1155 1156 if (mod_freesync == NULL) 1157 return; 1158 1159 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1160 1161 if (in_out_vrr->supported && 1162 in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE) { 1163 1164 last_render_time_in_us = curr_time_stamp_in_us - 1165 plane->time.prev_update_time_in_us; 1166 1167 if (in_out_vrr->btr.btr_enabled) { 1168 apply_below_the_range(core_freesync, 1169 stream, 1170 last_render_time_in_us, 1171 in_out_vrr); 1172 } else { 1173 apply_fixed_refresh(core_freesync, 1174 stream, 1175 last_render_time_in_us, 1176 in_out_vrr); 1177 } 1178 1179 determine_flip_interval_workaround_req(in_out_vrr, 1180 curr_time_stamp_in_us); 1181 1182 } 1183 } 1184 1185 void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync, 1186 const struct dc_stream_state *stream, 1187 struct mod_vrr_params *in_out_vrr) 1188 { 1189 struct core_freesync *core_freesync = NULL; 1190 unsigned int cur_timestamp_in_us; 1191 unsigned long long cur_tick; 1192 1193 if ((mod_freesync == NULL) || (stream == NULL) || (in_out_vrr == NULL)) 1194 return; 1195 1196 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1197 1198 if (in_out_vrr->supported == false) 1199 return; 1200 1201 cur_tick = dm_get_timestamp(core_freesync->dc->ctx); 1202 cur_timestamp_in_us = (unsigned int) 1203 div_u64(dm_get_elapse_time_in_ns(core_freesync->dc->ctx, cur_tick, 0), 1000); 1204 1205 in_out_vrr->flip_interval.vsyncs_between_flip++; 1206 in_out_vrr->flip_interval.v_update_timestamp_in_us = cur_timestamp_in_us; 1207 1208 if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE && 1209 (in_out_vrr->flip_interval.flip_interval_workaround_active || 1210 (!in_out_vrr->flip_interval.flip_interval_workaround_active && 1211 in_out_vrr->flip_interval.program_flip_interval_workaround))) { 1212 // set freesync vmin vmax to nominal for workaround 1213 in_out_vrr->adjust.v_total_min = 1214 mod_freesync_calc_v_total_from_refresh( 1215 stream, in_out_vrr->max_refresh_in_uhz); 1216 in_out_vrr->adjust.v_total_max = 1217 in_out_vrr->adjust.v_total_min; 1218 in_out_vrr->flip_interval.program_flip_interval_workaround = false; 1219 in_out_vrr->flip_interval.do_flip_interval_workaround_cleanup = true; 1220 return; 1221 } 1222 1223 if (in_out_vrr->state != VRR_STATE_ACTIVE_VARIABLE && 1224 in_out_vrr->flip_interval.do_flip_interval_workaround_cleanup) { 1225 in_out_vrr->flip_interval.do_flip_interval_workaround_cleanup = false; 1226 in_out_vrr->flip_interval.flip_interval_detect_counter = 0; 1227 in_out_vrr->flip_interval.vsyncs_between_flip = 0; 1228 in_out_vrr->flip_interval.vsync_to_flip_in_us = 0; 1229 } 1230 1231 /* Below the Range Logic */ 1232 1233 /* Only execute if in fullscreen mode */ 1234 if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE && 1235 in_out_vrr->btr.btr_active) { 1236 /* TODO: pass in flag for Pre-DCE12 ASIC 1237 * in order for frame variable duration to take affect, 1238 * it needs to be done one VSYNC early, which is at 1239 * frameCounter == 1. 1240 * For DCE12 and newer updates to V_TOTAL_MIN/MAX 1241 * will take affect on current frame 1242 */ 1243 if (in_out_vrr->btr.frames_to_insert == 1244 in_out_vrr->btr.frame_counter) { 1245 in_out_vrr->adjust.v_total_min = 1246 calc_v_total_from_duration(stream, 1247 in_out_vrr, 1248 in_out_vrr->btr.inserted_duration_in_us); 1249 in_out_vrr->adjust.v_total_max = 1250 in_out_vrr->adjust.v_total_min; 1251 } 1252 1253 if (in_out_vrr->btr.frame_counter > 0) 1254 in_out_vrr->btr.frame_counter--; 1255 1256 /* Restore FreeSync */ 1257 if (in_out_vrr->btr.frame_counter == 0) { 1258 in_out_vrr->adjust.v_total_min = 1259 mod_freesync_calc_v_total_from_refresh(stream, 1260 in_out_vrr->max_refresh_in_uhz); 1261 in_out_vrr->adjust.v_total_max = 1262 mod_freesync_calc_v_total_from_refresh(stream, 1263 in_out_vrr->min_refresh_in_uhz); 1264 } 1265 } 1266 1267 /* If in fullscreen freesync mode or in video, do not program 1268 * static screen ramp values 1269 */ 1270 if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE) 1271 in_out_vrr->fixed.ramping_active = false; 1272 1273 /* Gradual Static Screen Ramping Logic 1274 * Execute if ramp is active and user enabled freesync static screen 1275 */ 1276 if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED && 1277 in_out_vrr->fixed.ramping_active) { 1278 update_v_total_for_static_ramp( 1279 core_freesync, stream, in_out_vrr); 1280 } 1281 } 1282 1283 void mod_freesync_get_settings(struct mod_freesync *mod_freesync, 1284 const struct mod_vrr_params *vrr, 1285 unsigned int *v_total_min, unsigned int *v_total_max, 1286 unsigned int *event_triggers, 1287 unsigned int *window_min, unsigned int *window_max, 1288 unsigned int *lfc_mid_point_in_us, 1289 unsigned int *inserted_frames, 1290 unsigned int *inserted_duration_in_us) 1291 { 1292 if (mod_freesync == NULL) 1293 return; 1294 1295 if (vrr->supported) { 1296 *v_total_min = vrr->adjust.v_total_min; 1297 *v_total_max = vrr->adjust.v_total_max; 1298 *event_triggers = 0; 1299 *lfc_mid_point_in_us = vrr->btr.mid_point_in_us; 1300 *inserted_frames = vrr->btr.frames_to_insert; 1301 *inserted_duration_in_us = vrr->btr.inserted_duration_in_us; 1302 } 1303 } 1304 1305 unsigned long long mod_freesync_calc_nominal_field_rate( 1306 const struct dc_stream_state *stream) 1307 { 1308 unsigned long long nominal_field_rate_in_uhz = 0; 1309 unsigned int total = stream->timing.h_total * stream->timing.v_total; 1310 1311 /* Calculate nominal field rate for stream, rounded up to nearest integer */ 1312 nominal_field_rate_in_uhz = stream->timing.pix_clk_100hz; 1313 nominal_field_rate_in_uhz *= 100000000ULL; 1314 1315 nominal_field_rate_in_uhz = div_u64(nominal_field_rate_in_uhz, total); 1316 1317 return nominal_field_rate_in_uhz; 1318 } 1319 1320 unsigned long long mod_freesync_calc_field_rate_from_timing( 1321 unsigned int vtotal, unsigned int htotal, unsigned int pix_clk) 1322 { 1323 unsigned long long field_rate_in_uhz = 0; 1324 unsigned int total = htotal * vtotal; 1325 1326 /* Calculate nominal field rate for stream, rounded up to nearest integer */ 1327 field_rate_in_uhz = pix_clk; 1328 field_rate_in_uhz *= 1000000ULL; 1329 1330 field_rate_in_uhz = div_u64(field_rate_in_uhz, total); 1331 1332 return field_rate_in_uhz; 1333 } 1334 1335 bool mod_freesync_get_freesync_enabled(struct mod_vrr_params *pVrr) 1336 { 1337 return (pVrr->state != VRR_STATE_UNSUPPORTED) && (pVrr->state != VRR_STATE_DISABLED); 1338 } 1339 1340 bool mod_freesync_is_valid_range(uint32_t min_refresh_cap_in_uhz, 1341 uint32_t max_refresh_cap_in_uhz, 1342 uint32_t nominal_field_rate_in_uhz) 1343 { 1344 1345 /* Typically nominal refresh calculated can have some fractional part. 1346 * Allow for some rounding error of actual video timing by taking floor 1347 * of caps and request. Round the nominal refresh rate. 1348 * 1349 * Dividing will convert everything to units in Hz although input 1350 * variable name is in uHz! 1351 * 1352 * Also note, this takes care of rounding error on the nominal refresh 1353 * so by rounding error we only expect it to be off by a small amount, 1354 * such as < 0.1 Hz. i.e. 143.9xxx or 144.1xxx. 1355 * 1356 * Example 1. Caps Min = 40 Hz, Max = 144 Hz 1357 * Request Min = 40 Hz, Max = 144 Hz 1358 * Nominal = 143.5x Hz rounded to 144 Hz 1359 * This function should allow this as valid request 1360 * 1361 * Example 2. Caps Min = 40 Hz, Max = 144 Hz 1362 * Request Min = 40 Hz, Max = 144 Hz 1363 * Nominal = 144.4x Hz rounded to 144 Hz 1364 * This function should allow this as valid request 1365 * 1366 * Example 3. Caps Min = 40 Hz, Max = 144 Hz 1367 * Request Min = 40 Hz, Max = 144 Hz 1368 * Nominal = 120.xx Hz rounded to 120 Hz 1369 * This function should return NOT valid since the requested 1370 * max is greater than current timing's nominal 1371 * 1372 * Example 4. Caps Min = 40 Hz, Max = 120 Hz 1373 * Request Min = 40 Hz, Max = 120 Hz 1374 * Nominal = 144.xx Hz rounded to 144 Hz 1375 * This function should return NOT valid since the nominal 1376 * is greater than the capability's max refresh 1377 */ 1378 nominal_field_rate_in_uhz = 1379 div_u64(nominal_field_rate_in_uhz + 500000, 1000000); 1380 min_refresh_cap_in_uhz /= 1000000; 1381 max_refresh_cap_in_uhz /= 1000000; 1382 1383 /* Check nominal is within range */ 1384 if (nominal_field_rate_in_uhz > max_refresh_cap_in_uhz || 1385 nominal_field_rate_in_uhz < min_refresh_cap_in_uhz) 1386 return false; 1387 1388 /* If nominal is less than max, limit the max allowed refresh rate */ 1389 if (nominal_field_rate_in_uhz < max_refresh_cap_in_uhz) 1390 max_refresh_cap_in_uhz = nominal_field_rate_in_uhz; 1391 1392 /* Check min is within range */ 1393 if (min_refresh_cap_in_uhz > max_refresh_cap_in_uhz) 1394 return false; 1395 1396 /* For variable range, check for at least 10 Hz range */ 1397 if (nominal_field_rate_in_uhz - min_refresh_cap_in_uhz < 10) 1398 return false; 1399 1400 return true; 1401 } 1402