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 44 struct 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 52 struct 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 66 fail_construct: 67 kfree(core_freesync); 68 69 fail_alloc_context: 70 return NULL; 71 } 72 73 void 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 */ 83 static 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 93 static 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 102 static 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 115 static 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 139 static 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 165 static 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 235 static 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 370 static 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 425 static 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 446 bool 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 457 bool 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 483 void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync, 484 const struct dc_stream_state *stream, 485 const struct mod_vrr_params *vrr, 486 struct dc_info_packet *infopacket) 487 { 488 /* SPD info packet for FreeSync */ 489 unsigned char checksum = 0; 490 unsigned int idx, payload_size = 0; 491 492 /* Check if Freesync is supported. Return if false. If true, 493 * set the corresponding bit in the info packet 494 */ 495 if (!vrr->supported || !vrr->send_vsif) 496 return; 497 498 if (dc_is_hdmi_signal(stream->signal)) { 499 500 /* HEADER */ 501 502 /* HB0 = Packet Type = 0x83 (Source Product 503 * Descriptor InfoFrame) 504 */ 505 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD; 506 507 /* HB1 = Version = 0x01 */ 508 infopacket->hb1 = 0x01; 509 510 /* HB2 = [Bits 7:5 = 0] [Bits 4:0 = Length = 0x08] */ 511 infopacket->hb2 = 0x08; 512 513 payload_size = 0x08; 514 515 } else if (dc_is_dp_signal(stream->signal)) { 516 517 /* HEADER */ 518 519 /* HB0 = Secondary-data Packet ID = 0 - Only non-zero 520 * when used to associate audio related info packets 521 */ 522 infopacket->hb0 = 0x00; 523 524 /* HB1 = Packet Type = 0x83 (Source Product 525 * Descriptor InfoFrame) 526 */ 527 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD; 528 529 /* HB2 = [Bits 7:0 = Least significant eight bits - 530 * For INFOFRAME, the value must be 1Bh] 531 */ 532 infopacket->hb2 = 0x1B; 533 534 /* HB3 = [Bits 7:2 = INFOFRAME SDP Version Number = 0x1] 535 * [Bits 1:0 = Most significant two bits = 0x00] 536 */ 537 infopacket->hb3 = 0x04; 538 539 payload_size = 0x1B; 540 } 541 542 /* PB1 = 0x1A (24bit AMD IEEE OUI (0x00001A) - Byte 0) */ 543 infopacket->sb[1] = 0x1A; 544 545 /* PB2 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 1) */ 546 infopacket->sb[2] = 0x00; 547 548 /* PB3 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 2) */ 549 infopacket->sb[3] = 0x00; 550 551 /* PB4 = Reserved */ 552 553 /* PB5 = Reserved */ 554 555 /* PB6 = [Bits 7:3 = Reserved] */ 556 557 /* PB6 = [Bit 0 = FreeSync Supported] */ 558 if (vrr->state != VRR_STATE_UNSUPPORTED) 559 infopacket->sb[6] |= 0x01; 560 561 /* PB6 = [Bit 1 = FreeSync Enabled] */ 562 if (vrr->state != VRR_STATE_DISABLED && 563 vrr->state != VRR_STATE_UNSUPPORTED) 564 infopacket->sb[6] |= 0x02; 565 566 /* PB6 = [Bit 2 = FreeSync Active] */ 567 if (vrr->state == VRR_STATE_ACTIVE_VARIABLE || 568 vrr->state == VRR_STATE_ACTIVE_FIXED) 569 infopacket->sb[6] |= 0x04; 570 571 /* PB7 = FreeSync Minimum refresh rate (Hz) */ 572 infopacket->sb[7] = (unsigned char)(vrr->min_refresh_in_uhz / 1000000); 573 574 /* PB8 = FreeSync Maximum refresh rate (Hz) 575 * Note: We should never go above the field rate of the mode timing set. 576 */ 577 infopacket->sb[8] = (unsigned char)(vrr->max_refresh_in_uhz / 1000000); 578 579 /* PB9 - PB27 = Reserved */ 580 581 /* Calculate checksum */ 582 checksum += infopacket->hb0; 583 checksum += infopacket->hb1; 584 checksum += infopacket->hb2; 585 checksum += infopacket->hb3; 586 587 for (idx = 1; idx <= payload_size; idx++) 588 checksum += infopacket->sb[idx]; 589 590 /* PB0 = Checksum (one byte complement) */ 591 infopacket->sb[0] = (unsigned char)(0x100 - checksum); 592 593 infopacket->valid = true; 594 } 595 596 void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync, 597 const struct dc_stream_state *stream, 598 struct mod_freesync_config *in_config, 599 struct mod_vrr_params *in_out_vrr) 600 { 601 struct core_freesync *core_freesync = NULL; 602 unsigned long long nominal_field_rate_in_uhz = 0; 603 unsigned int refresh_range = 0; 604 unsigned int min_refresh_in_uhz = 0; 605 unsigned int max_refresh_in_uhz = 0; 606 607 if (mod_freesync == NULL) 608 return; 609 610 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 611 612 /* Calculate nominal field rate for stream */ 613 nominal_field_rate_in_uhz = 614 mod_freesync_calc_nominal_field_rate(stream); 615 616 min_refresh_in_uhz = in_config->min_refresh_in_uhz; 617 max_refresh_in_uhz = in_config->max_refresh_in_uhz; 618 619 // Don't allow min > max 620 if (min_refresh_in_uhz > max_refresh_in_uhz) 621 min_refresh_in_uhz = max_refresh_in_uhz; 622 623 // Full range may be larger than current video timing, so cap at nominal 624 if (max_refresh_in_uhz > nominal_field_rate_in_uhz) 625 max_refresh_in_uhz = nominal_field_rate_in_uhz; 626 627 // Full range may be larger than current video timing, so cap at nominal 628 if (min_refresh_in_uhz > nominal_field_rate_in_uhz) 629 min_refresh_in_uhz = nominal_field_rate_in_uhz; 630 631 if (!vrr_settings_require_update(core_freesync, 632 in_config, min_refresh_in_uhz, max_refresh_in_uhz, 633 in_out_vrr)) 634 return; 635 636 in_out_vrr->state = in_config->state; 637 in_out_vrr->send_vsif = in_config->vsif_supported; 638 639 if (in_config->state == VRR_STATE_UNSUPPORTED) { 640 in_out_vrr->state = VRR_STATE_UNSUPPORTED; 641 in_out_vrr->supported = false; 642 in_out_vrr->adjust.v_total_min = stream->timing.v_total; 643 in_out_vrr->adjust.v_total_max = stream->timing.v_total; 644 645 return; 646 647 } else { 648 in_out_vrr->min_refresh_in_uhz = min_refresh_in_uhz; 649 in_out_vrr->max_duration_in_us = 650 calc_duration_in_us_from_refresh_in_uhz( 651 min_refresh_in_uhz); 652 653 in_out_vrr->max_refresh_in_uhz = max_refresh_in_uhz; 654 in_out_vrr->min_duration_in_us = 655 calc_duration_in_us_from_refresh_in_uhz( 656 max_refresh_in_uhz); 657 658 refresh_range = in_out_vrr->max_refresh_in_uhz - 659 in_out_vrr->min_refresh_in_uhz; 660 661 in_out_vrr->supported = true; 662 } 663 664 in_out_vrr->fixed.ramping_active = in_config->ramping; 665 666 in_out_vrr->btr.btr_enabled = in_config->btr; 667 if (in_out_vrr->max_refresh_in_uhz < 668 2 * in_out_vrr->min_refresh_in_uhz) 669 in_out_vrr->btr.btr_enabled = false; 670 in_out_vrr->btr.btr_active = false; 671 in_out_vrr->btr.inserted_duration_in_us = 0; 672 in_out_vrr->btr.frames_to_insert = 0; 673 in_out_vrr->btr.frame_counter = 0; 674 in_out_vrr->btr.mid_point_in_us = 675 in_out_vrr->min_duration_in_us + 676 (in_out_vrr->max_duration_in_us - 677 in_out_vrr->min_duration_in_us) / 2; 678 679 if (in_out_vrr->state == VRR_STATE_UNSUPPORTED) { 680 in_out_vrr->adjust.v_total_min = stream->timing.v_total; 681 in_out_vrr->adjust.v_total_max = stream->timing.v_total; 682 } else if (in_out_vrr->state == VRR_STATE_DISABLED) { 683 in_out_vrr->adjust.v_total_min = stream->timing.v_total; 684 in_out_vrr->adjust.v_total_max = stream->timing.v_total; 685 } else if (in_out_vrr->state == VRR_STATE_INACTIVE) { 686 in_out_vrr->adjust.v_total_min = stream->timing.v_total; 687 in_out_vrr->adjust.v_total_max = stream->timing.v_total; 688 } else if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE && 689 refresh_range >= MIN_REFRESH_RANGE_IN_US) { 690 in_out_vrr->adjust.v_total_min = 691 calc_v_total_from_refresh(stream, 692 in_out_vrr->max_refresh_in_uhz); 693 in_out_vrr->adjust.v_total_max = 694 calc_v_total_from_refresh(stream, 695 in_out_vrr->min_refresh_in_uhz); 696 } else if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED) { 697 in_out_vrr->fixed.target_refresh_in_uhz = 698 in_out_vrr->min_refresh_in_uhz; 699 if (in_out_vrr->fixed.ramping_active && 700 in_out_vrr->fixed.fixed_active) { 701 /* Do not update vtotals if ramping is already active 702 * in order to continue ramp from current refresh. 703 */ 704 in_out_vrr->fixed.fixed_active = true; 705 } else { 706 in_out_vrr->fixed.fixed_active = true; 707 in_out_vrr->adjust.v_total_min = 708 calc_v_total_from_refresh(stream, 709 in_out_vrr->fixed.target_refresh_in_uhz); 710 in_out_vrr->adjust.v_total_max = 711 in_out_vrr->adjust.v_total_min; 712 } 713 } else { 714 in_out_vrr->state = VRR_STATE_INACTIVE; 715 in_out_vrr->adjust.v_total_min = stream->timing.v_total; 716 in_out_vrr->adjust.v_total_max = stream->timing.v_total; 717 } 718 } 719 720 void mod_freesync_handle_preflip(struct mod_freesync *mod_freesync, 721 const struct dc_plane_state *plane, 722 const struct dc_stream_state *stream, 723 unsigned int curr_time_stamp_in_us, 724 struct mod_vrr_params *in_out_vrr) 725 { 726 struct core_freesync *core_freesync = NULL; 727 unsigned int last_render_time_in_us = 0; 728 unsigned int average_render_time_in_us = 0; 729 730 if (mod_freesync == NULL) 731 return; 732 733 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 734 735 if (in_out_vrr->supported && 736 in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE) { 737 unsigned int i = 0; 738 unsigned int oldest_index = plane->time.index + 1; 739 740 if (oldest_index >= DC_PLANE_UPDATE_TIMES_MAX) 741 oldest_index = 0; 742 743 last_render_time_in_us = curr_time_stamp_in_us - 744 plane->time.prev_update_time_in_us; 745 746 // Sum off all entries except oldest one 747 for (i = 0; i < DC_PLANE_UPDATE_TIMES_MAX; i++) { 748 average_render_time_in_us += 749 plane->time.time_elapsed_in_us[i]; 750 } 751 average_render_time_in_us -= 752 plane->time.time_elapsed_in_us[oldest_index]; 753 754 // Add render time for current flip 755 average_render_time_in_us += last_render_time_in_us; 756 average_render_time_in_us /= DC_PLANE_UPDATE_TIMES_MAX; 757 758 if (in_out_vrr->btr.btr_enabled) { 759 apply_below_the_range(core_freesync, 760 stream, 761 last_render_time_in_us, 762 in_out_vrr); 763 } else { 764 apply_fixed_refresh(core_freesync, 765 stream, 766 last_render_time_in_us, 767 in_out_vrr); 768 } 769 770 } 771 } 772 773 void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync, 774 const struct dc_stream_state *stream, 775 struct mod_vrr_params *in_out_vrr) 776 { 777 struct core_freesync *core_freesync = NULL; 778 779 if ((mod_freesync == NULL) || (stream == NULL) || (in_out_vrr == NULL)) 780 return; 781 782 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 783 784 if (in_out_vrr->supported == false) 785 return; 786 787 /* Below the Range Logic */ 788 789 /* Only execute if in fullscreen mode */ 790 if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE && 791 in_out_vrr->btr.btr_active) { 792 /* TODO: pass in flag for Pre-DCE12 ASIC 793 * in order for frame variable duration to take affect, 794 * it needs to be done one VSYNC early, which is at 795 * frameCounter == 1. 796 * For DCE12 and newer updates to V_TOTAL_MIN/MAX 797 * will take affect on current frame 798 */ 799 if (in_out_vrr->btr.frames_to_insert == 800 in_out_vrr->btr.frame_counter) { 801 in_out_vrr->adjust.v_total_min = 802 calc_v_total_from_duration(stream, 803 in_out_vrr, 804 in_out_vrr->btr.inserted_duration_in_us); 805 in_out_vrr->adjust.v_total_max = 806 in_out_vrr->adjust.v_total_min; 807 } 808 809 if (in_out_vrr->btr.frame_counter > 0) 810 in_out_vrr->btr.frame_counter--; 811 812 /* Restore FreeSync */ 813 if (in_out_vrr->btr.frame_counter == 0) { 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 } 821 } 822 823 /* If in fullscreen freesync mode or in video, do not program 824 * static screen ramp values 825 */ 826 if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE) 827 in_out_vrr->fixed.ramping_active = false; 828 829 /* Gradual Static Screen Ramping Logic */ 830 /* Execute if ramp is active and user enabled freesync static screen*/ 831 if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED && 832 in_out_vrr->fixed.ramping_active) { 833 update_v_total_for_static_ramp( 834 core_freesync, stream, in_out_vrr); 835 } 836 } 837 838 void mod_freesync_get_settings(struct mod_freesync *mod_freesync, 839 const struct mod_vrr_params *vrr, 840 unsigned int *v_total_min, unsigned int *v_total_max, 841 unsigned int *event_triggers, 842 unsigned int *window_min, unsigned int *window_max, 843 unsigned int *lfc_mid_point_in_us, 844 unsigned int *inserted_frames, 845 unsigned int *inserted_duration_in_us) 846 { 847 struct core_freesync *core_freesync = NULL; 848 849 if (mod_freesync == NULL) 850 return; 851 852 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 853 854 if (vrr->supported) { 855 *v_total_min = vrr->adjust.v_total_min; 856 *v_total_max = vrr->adjust.v_total_max; 857 *event_triggers = 0; 858 *lfc_mid_point_in_us = vrr->btr.mid_point_in_us; 859 *inserted_frames = vrr->btr.frames_to_insert; 860 *inserted_duration_in_us = vrr->btr.inserted_duration_in_us; 861 } 862 } 863 864 unsigned long long mod_freesync_calc_nominal_field_rate( 865 const struct dc_stream_state *stream) 866 { 867 unsigned long long nominal_field_rate_in_uhz = 0; 868 869 /* Calculate nominal field rate for stream */ 870 nominal_field_rate_in_uhz = stream->timing.pix_clk_khz; 871 nominal_field_rate_in_uhz *= 1000ULL * 1000ULL * 1000ULL; 872 nominal_field_rate_in_uhz = div_u64(nominal_field_rate_in_uhz, 873 stream->timing.h_total); 874 nominal_field_rate_in_uhz = div_u64(nominal_field_rate_in_uhz, 875 stream->timing.v_total); 876 877 return nominal_field_rate_in_uhz; 878 } 879 880 bool mod_freesync_is_valid_range(struct mod_freesync *mod_freesync, 881 const struct dc_stream_state *stream, 882 uint32_t min_refresh_cap_in_uhz, 883 uint32_t max_refresh_cap_in_uhz, 884 uint32_t min_refresh_request_in_uhz, 885 uint32_t max_refresh_request_in_uhz) 886 { 887 /* Calculate nominal field rate for stream */ 888 unsigned long long nominal_field_rate_in_uhz = 889 mod_freesync_calc_nominal_field_rate(stream); 890 891 /* Typically nominal refresh calculated can have some fractional part. 892 * Allow for some rounding error of actual video timing by taking floor 893 * of caps and request. Round the nominal refresh rate. 894 * 895 * Dividing will convert everything to units in Hz although input 896 * variable name is in uHz! 897 * 898 * Also note, this takes care of rounding error on the nominal refresh 899 * so by rounding error we only expect it to be off by a small amount, 900 * such as < 0.1 Hz. i.e. 143.9xxx or 144.1xxx. 901 * 902 * Example 1. Caps Min = 40 Hz, Max = 144 Hz 903 * Request Min = 40 Hz, Max = 144 Hz 904 * Nominal = 143.5x Hz rounded to 144 Hz 905 * This function should allow this as valid request 906 * 907 * Example 2. Caps Min = 40 Hz, Max = 144 Hz 908 * Request Min = 40 Hz, Max = 144 Hz 909 * Nominal = 144.4x Hz rounded to 144 Hz 910 * This function should allow this as valid request 911 * 912 * Example 3. Caps Min = 40 Hz, Max = 144 Hz 913 * Request Min = 40 Hz, Max = 144 Hz 914 * Nominal = 120.xx Hz rounded to 120 Hz 915 * This function should return NOT valid since the requested 916 * max is greater than current timing's nominal 917 * 918 * Example 4. Caps Min = 40 Hz, Max = 120 Hz 919 * Request Min = 40 Hz, Max = 120 Hz 920 * Nominal = 144.xx Hz rounded to 144 Hz 921 * This function should return NOT valid since the nominal 922 * is greater than the capability's max refresh 923 */ 924 nominal_field_rate_in_uhz = 925 div_u64(nominal_field_rate_in_uhz + 500000, 1000000); 926 min_refresh_cap_in_uhz /= 1000000; 927 max_refresh_cap_in_uhz /= 1000000; 928 min_refresh_request_in_uhz /= 1000000; 929 max_refresh_request_in_uhz /= 1000000; 930 931 // Check nominal is within range 932 if (nominal_field_rate_in_uhz > max_refresh_cap_in_uhz || 933 nominal_field_rate_in_uhz < min_refresh_cap_in_uhz) 934 return false; 935 936 // If nominal is less than max, limit the max allowed refresh rate 937 if (nominal_field_rate_in_uhz < max_refresh_cap_in_uhz) 938 max_refresh_cap_in_uhz = nominal_field_rate_in_uhz; 939 940 // Don't allow min > max 941 if (min_refresh_request_in_uhz > max_refresh_request_in_uhz) 942 return false; 943 944 // Check min is within range 945 if (min_refresh_request_in_uhz > max_refresh_cap_in_uhz || 946 min_refresh_request_in_uhz < min_refresh_cap_in_uhz) 947 return false; 948 949 // Check max is within range 950 if (max_refresh_request_in_uhz > max_refresh_cap_in_uhz || 951 max_refresh_request_in_uhz < min_refresh_cap_in_uhz) 952 return false; 953 954 // For variable range, check for at least 10 Hz range 955 if ((max_refresh_request_in_uhz != min_refresh_request_in_uhz) && 956 (max_refresh_request_in_uhz - min_refresh_request_in_uhz < 10)) 957 return false; 958 959 return true; 960 } 961 962