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