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 /* Refresh rate ramp at a fixed rate of 65 Hz/second */ 34 #define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65) 35 /* Number of elements in the render times cache array */ 36 #define RENDER_TIMES_MAX_COUNT 20 37 /* Threshold to exit BTR (to avoid frequent enter-exits at the lower limit) */ 38 #define BTR_EXIT_MARGIN 2000 39 /* Number of consecutive frames to check before entering/exiting fixed refresh*/ 40 #define FIXED_REFRESH_ENTER_FRAME_COUNT 5 41 #define FIXED_REFRESH_EXIT_FRAME_COUNT 5 42 43 #define FREESYNC_REGISTRY_NAME "freesync_v1" 44 45 #define FREESYNC_NO_STATIC_FOR_EXTERNAL_DP_REGKEY "DalFreeSyncNoStaticForExternalDp" 46 47 #define FREESYNC_NO_STATIC_FOR_INTERNAL_REGKEY "DalFreeSyncNoStaticForInternal" 48 49 struct gradual_static_ramp { 50 bool ramp_is_active; 51 bool ramp_direction_is_up; 52 unsigned int ramp_current_frame_duration_in_ns; 53 }; 54 55 struct time_cache { 56 /* video (48Hz feature) related */ 57 unsigned int update_duration_in_ns; 58 59 /* BTR/fixed refresh related */ 60 unsigned int prev_time_stamp_in_us; 61 62 unsigned int min_render_time_in_us; 63 unsigned int max_render_time_in_us; 64 65 unsigned int render_times_index; 66 unsigned int render_times[RENDER_TIMES_MAX_COUNT]; 67 }; 68 69 struct below_the_range { 70 bool btr_active; 71 bool program_btr; 72 73 unsigned int mid_point_in_us; 74 75 unsigned int inserted_frame_duration_in_us; 76 unsigned int frames_to_insert; 77 unsigned int frame_counter; 78 }; 79 80 struct fixed_refresh { 81 bool fixed_active; 82 bool program_fixed; 83 unsigned int frame_counter; 84 }; 85 86 struct freesync_range { 87 unsigned int min_refresh; 88 unsigned int max_frame_duration; 89 unsigned int vmax; 90 91 unsigned int max_refresh; 92 unsigned int min_frame_duration; 93 unsigned int vmin; 94 }; 95 96 struct freesync_state { 97 bool fullscreen; 98 bool static_screen; 99 bool video; 100 101 unsigned int nominal_refresh_rate_in_micro_hz; 102 bool windowed_fullscreen; 103 104 struct time_cache time; 105 106 struct gradual_static_ramp static_ramp; 107 struct below_the_range btr; 108 struct fixed_refresh fixed_refresh; 109 struct freesync_range freesync_range; 110 }; 111 112 struct freesync_entity { 113 struct dc_stream_state *stream; 114 struct mod_freesync_caps *caps; 115 struct freesync_state state; 116 struct mod_freesync_user_enable user_enable; 117 }; 118 119 struct freesync_registry_options { 120 bool drr_external_supported; 121 bool drr_internal_supported; 122 }; 123 124 struct core_freesync { 125 struct mod_freesync public; 126 struct dc *dc; 127 struct freesync_entity *map; 128 int num_entities; 129 struct freesync_registry_options opts; 130 }; 131 132 #define MOD_FREESYNC_TO_CORE(mod_freesync)\ 133 container_of(mod_freesync, struct core_freesync, public) 134 135 static bool check_dc_support(const struct dc *dc) 136 { 137 if (dc->stream_funcs.adjust_vmin_vmax == NULL) 138 return false; 139 140 return true; 141 } 142 143 struct mod_freesync *mod_freesync_create(struct dc *dc) 144 { 145 struct core_freesync *core_freesync = 146 kzalloc(sizeof(struct core_freesync), GFP_KERNEL); 147 148 149 struct persistent_data_flag flag; 150 151 int i, data = 0; 152 153 if (core_freesync == NULL) 154 goto fail_alloc_context; 155 156 core_freesync->map = kzalloc(sizeof(struct freesync_entity) * MOD_FREESYNC_MAX_CONCURRENT_STREAMS, 157 GFP_KERNEL); 158 159 if (core_freesync->map == NULL) 160 goto fail_alloc_map; 161 162 for (i = 0; i < MOD_FREESYNC_MAX_CONCURRENT_STREAMS; i++) 163 core_freesync->map[i].stream = NULL; 164 165 core_freesync->num_entities = 0; 166 167 if (dc == NULL) 168 goto fail_construct; 169 170 core_freesync->dc = dc; 171 172 if (!check_dc_support(dc)) 173 goto fail_construct; 174 175 /* Create initial module folder in registry for freesync enable data */ 176 flag.save_per_edid = true; 177 flag.save_per_link = false; 178 dm_write_persistent_data(dc->ctx, NULL, FREESYNC_REGISTRY_NAME, 179 NULL, NULL, 0, &flag); 180 flag.save_per_edid = false; 181 flag.save_per_link = false; 182 183 if (dm_read_persistent_data(dc->ctx, NULL, NULL, 184 FREESYNC_NO_STATIC_FOR_INTERNAL_REGKEY, 185 &data, sizeof(data), &flag)) { 186 core_freesync->opts.drr_internal_supported = 187 (data & 1) ? false : true; 188 } 189 190 if (dm_read_persistent_data(dc->ctx, NULL, NULL, 191 FREESYNC_NO_STATIC_FOR_EXTERNAL_DP_REGKEY, 192 &data, sizeof(data), &flag)) { 193 core_freesync->opts.drr_external_supported = 194 (data & 1) ? false : true; 195 } 196 197 return &core_freesync->public; 198 199 fail_construct: 200 kfree(core_freesync->map); 201 202 fail_alloc_map: 203 kfree(core_freesync); 204 205 fail_alloc_context: 206 return NULL; 207 } 208 209 void mod_freesync_destroy(struct mod_freesync *mod_freesync) 210 { 211 if (mod_freesync != NULL) { 212 int i; 213 struct core_freesync *core_freesync = 214 MOD_FREESYNC_TO_CORE(mod_freesync); 215 216 for (i = 0; i < core_freesync->num_entities; i++) 217 if (core_freesync->map[i].stream) 218 dc_stream_release(core_freesync->map[i].stream); 219 220 kfree(core_freesync->map); 221 222 kfree(core_freesync); 223 } 224 } 225 226 /* Given a specific dc_stream* this function finds its equivalent 227 * on the core_freesync->map and returns the corresponding index 228 */ 229 static unsigned int map_index_from_stream(struct core_freesync *core_freesync, 230 struct dc_stream_state *stream) 231 { 232 unsigned int index = 0; 233 234 for (index = 0; index < core_freesync->num_entities; index++) { 235 if (core_freesync->map[index].stream == stream) { 236 return index; 237 } 238 } 239 /* Could not find stream requested */ 240 ASSERT(false); 241 return index; 242 } 243 244 bool mod_freesync_add_stream(struct mod_freesync *mod_freesync, 245 struct dc_stream_state *stream, struct mod_freesync_caps *caps) 246 { 247 struct dc *dc = NULL; 248 struct core_freesync *core_freesync = NULL; 249 int persistent_freesync_enable = 0; 250 struct persistent_data_flag flag; 251 unsigned int nom_refresh_rate_uhz; 252 unsigned long long temp; 253 254 if (mod_freesync == NULL) 255 return false; 256 257 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 258 dc = core_freesync->dc; 259 260 flag.save_per_edid = true; 261 flag.save_per_link = false; 262 263 if (core_freesync->num_entities < MOD_FREESYNC_MAX_CONCURRENT_STREAMS) { 264 265 dc_stream_retain(stream); 266 267 temp = stream->timing.pix_clk_khz; 268 temp *= 1000ULL * 1000ULL * 1000ULL; 269 temp = div_u64(temp, stream->timing.h_total); 270 temp = div_u64(temp, stream->timing.v_total); 271 272 nom_refresh_rate_uhz = (unsigned int) temp; 273 274 core_freesync->map[core_freesync->num_entities].stream = stream; 275 core_freesync->map[core_freesync->num_entities].caps = caps; 276 277 core_freesync->map[core_freesync->num_entities].state. 278 fullscreen = false; 279 core_freesync->map[core_freesync->num_entities].state. 280 static_screen = false; 281 core_freesync->map[core_freesync->num_entities].state. 282 video = false; 283 core_freesync->map[core_freesync->num_entities].state.time. 284 update_duration_in_ns = 0; 285 core_freesync->map[core_freesync->num_entities].state. 286 static_ramp.ramp_is_active = false; 287 288 /* get persistent data from registry */ 289 if (dm_read_persistent_data(dc->ctx, stream->sink, 290 FREESYNC_REGISTRY_NAME, 291 "userenable", &persistent_freesync_enable, 292 sizeof(int), &flag)) { 293 core_freesync->map[core_freesync->num_entities].user_enable. 294 enable_for_gaming = 295 (persistent_freesync_enable & 1) ? true : false; 296 core_freesync->map[core_freesync->num_entities].user_enable. 297 enable_for_static = 298 (persistent_freesync_enable & 2) ? true : false; 299 core_freesync->map[core_freesync->num_entities].user_enable. 300 enable_for_video = 301 (persistent_freesync_enable & 4) ? true : false; 302 } else { 303 core_freesync->map[core_freesync->num_entities].user_enable. 304 enable_for_gaming = false; 305 core_freesync->map[core_freesync->num_entities].user_enable. 306 enable_for_static = false; 307 core_freesync->map[core_freesync->num_entities].user_enable. 308 enable_for_video = false; 309 } 310 311 if (caps->supported && 312 nom_refresh_rate_uhz >= caps->min_refresh_in_micro_hz && 313 nom_refresh_rate_uhz <= caps->max_refresh_in_micro_hz) 314 stream->ignore_msa_timing_param = 1; 315 316 core_freesync->num_entities++; 317 return true; 318 } 319 return false; 320 } 321 322 bool mod_freesync_remove_stream(struct mod_freesync *mod_freesync, 323 struct dc_stream_state *stream) 324 { 325 int i = 0; 326 struct core_freesync *core_freesync = NULL; 327 unsigned int index = 0; 328 329 if (mod_freesync == NULL) 330 return false; 331 332 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 333 index = map_index_from_stream(core_freesync, stream); 334 335 dc_stream_release(core_freesync->map[index].stream); 336 core_freesync->map[index].stream = NULL; 337 /* To remove this entity, shift everything after down */ 338 for (i = index; i < core_freesync->num_entities - 1; i++) 339 core_freesync->map[i] = core_freesync->map[i + 1]; 340 core_freesync->num_entities--; 341 return true; 342 } 343 344 static void update_stream_freesync_context(struct core_freesync *core_freesync, 345 struct dc_stream_state *stream) 346 { 347 unsigned int index; 348 struct freesync_context *ctx; 349 350 ctx = &stream->freesync_ctx; 351 352 index = map_index_from_stream(core_freesync, stream); 353 354 ctx->supported = core_freesync->map[index].caps->supported; 355 ctx->enabled = (core_freesync->map[index].user_enable.enable_for_gaming || 356 core_freesync->map[index].user_enable.enable_for_video || 357 core_freesync->map[index].user_enable.enable_for_static); 358 ctx->active = (core_freesync->map[index].state.fullscreen || 359 core_freesync->map[index].state.video || 360 core_freesync->map[index].state.static_ramp.ramp_is_active); 361 ctx->min_refresh_in_micro_hz = 362 core_freesync->map[index].caps->min_refresh_in_micro_hz; 363 ctx->nominal_refresh_in_micro_hz = core_freesync-> 364 map[index].state.nominal_refresh_rate_in_micro_hz; 365 366 } 367 368 static void update_stream(struct core_freesync *core_freesync, 369 struct dc_stream_state *stream) 370 { 371 unsigned int index = map_index_from_stream(core_freesync, stream); 372 if (core_freesync->map[index].caps->supported) { 373 stream->ignore_msa_timing_param = 1; 374 update_stream_freesync_context(core_freesync, stream); 375 } 376 } 377 378 static void calc_freesync_range(struct core_freesync *core_freesync, 379 struct dc_stream_state *stream, 380 struct freesync_state *state, 381 unsigned int min_refresh_in_uhz, 382 unsigned int max_refresh_in_uhz) 383 { 384 unsigned int min_frame_duration_in_ns = 0, max_frame_duration_in_ns = 0; 385 unsigned int index = map_index_from_stream(core_freesync, stream); 386 uint32_t vtotal = stream->timing.v_total; 387 388 if ((min_refresh_in_uhz == 0) || (max_refresh_in_uhz == 0)) { 389 state->freesync_range.min_refresh = 390 state->nominal_refresh_rate_in_micro_hz; 391 state->freesync_range.max_refresh = 392 state->nominal_refresh_rate_in_micro_hz; 393 394 state->freesync_range.max_frame_duration = 0; 395 state->freesync_range.min_frame_duration = 0; 396 397 state->freesync_range.vmax = vtotal; 398 state->freesync_range.vmin = vtotal; 399 400 return; 401 } 402 403 min_frame_duration_in_ns = ((unsigned int) (div64_u64( 404 (1000000000ULL * 1000000), 405 max_refresh_in_uhz))); 406 max_frame_duration_in_ns = ((unsigned int) (div64_u64( 407 (1000000000ULL * 1000000), 408 min_refresh_in_uhz))); 409 410 state->freesync_range.min_refresh = min_refresh_in_uhz; 411 state->freesync_range.max_refresh = max_refresh_in_uhz; 412 413 state->freesync_range.max_frame_duration = max_frame_duration_in_ns; 414 state->freesync_range.min_frame_duration = min_frame_duration_in_ns; 415 416 state->freesync_range.vmax = div64_u64(div64_u64(((unsigned long long)( 417 max_frame_duration_in_ns) * stream->timing.pix_clk_khz), 418 stream->timing.h_total), 1000000); 419 state->freesync_range.vmin = div64_u64(div64_u64(((unsigned long long)( 420 min_frame_duration_in_ns) * stream->timing.pix_clk_khz), 421 stream->timing.h_total), 1000000); 422 423 /* vmin/vmax cannot be less than vtotal */ 424 if (state->freesync_range.vmin < vtotal) { 425 /* Error of 1 is permissible */ 426 ASSERT((state->freesync_range.vmin + 1) >= vtotal); 427 state->freesync_range.vmin = vtotal; 428 } 429 430 if (state->freesync_range.vmax < vtotal) { 431 /* Error of 1 is permissible */ 432 ASSERT((state->freesync_range.vmax + 1) >= vtotal); 433 state->freesync_range.vmax = vtotal; 434 } 435 436 /* Determine whether BTR can be supported */ 437 if (max_frame_duration_in_ns >= 438 2 * min_frame_duration_in_ns) 439 core_freesync->map[index].caps->btr_supported = true; 440 else 441 core_freesync->map[index].caps->btr_supported = false; 442 443 /* Cache the time variables */ 444 state->time.max_render_time_in_us = 445 max_frame_duration_in_ns / 1000; 446 state->time.min_render_time_in_us = 447 min_frame_duration_in_ns / 1000; 448 state->btr.mid_point_in_us = 449 (max_frame_duration_in_ns + 450 min_frame_duration_in_ns) / 2000; 451 } 452 453 static void calc_v_total_from_duration(struct dc_stream_state *stream, 454 unsigned int duration_in_ns, int *v_total_nominal) 455 { 456 *v_total_nominal = div64_u64(div64_u64(((unsigned long long)( 457 duration_in_ns) * stream->timing.pix_clk_khz), 458 stream->timing.h_total), 1000000); 459 } 460 461 static void calc_v_total_for_static_ramp(struct core_freesync *core_freesync, 462 struct dc_stream_state *stream, 463 unsigned int index, int *v_total) 464 { 465 unsigned int frame_duration = 0; 466 467 struct gradual_static_ramp *static_ramp_variables = 468 &core_freesync->map[index].state.static_ramp; 469 470 /* Calc ratio between new and current frame duration with 3 digit */ 471 unsigned int frame_duration_ratio = div64_u64(1000000, 472 (1000 + div64_u64(((unsigned long long)( 473 STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME) * 474 static_ramp_variables->ramp_current_frame_duration_in_ns), 475 1000000000))); 476 477 /* Calculate delta between new and current frame duration in ns */ 478 unsigned int frame_duration_delta = div64_u64(((unsigned long long)( 479 static_ramp_variables->ramp_current_frame_duration_in_ns) * 480 (1000 - frame_duration_ratio)), 1000); 481 482 /* Adjust frame duration delta based on ratio between current and 483 * standard frame duration (frame duration at 60 Hz refresh rate). 484 */ 485 unsigned int ramp_rate_interpolated = div64_u64(((unsigned long long)( 486 frame_duration_delta) * static_ramp_variables-> 487 ramp_current_frame_duration_in_ns), 16666666); 488 489 /* Going to a higher refresh rate (lower frame duration) */ 490 if (static_ramp_variables->ramp_direction_is_up) { 491 /* reduce frame duration */ 492 static_ramp_variables->ramp_current_frame_duration_in_ns -= 493 ramp_rate_interpolated; 494 495 /* min frame duration */ 496 frame_duration = ((unsigned int) (div64_u64( 497 (1000000000ULL * 1000000), 498 core_freesync->map[index].state. 499 nominal_refresh_rate_in_micro_hz))); 500 501 /* adjust for frame duration below min */ 502 if (static_ramp_variables->ramp_current_frame_duration_in_ns <= 503 frame_duration) { 504 505 static_ramp_variables->ramp_is_active = false; 506 static_ramp_variables-> 507 ramp_current_frame_duration_in_ns = 508 frame_duration; 509 } 510 /* Going to a lower refresh rate (larger frame duration) */ 511 } else { 512 /* increase frame duration */ 513 static_ramp_variables->ramp_current_frame_duration_in_ns += 514 ramp_rate_interpolated; 515 516 /* max frame duration */ 517 frame_duration = ((unsigned int) (div64_u64( 518 (1000000000ULL * 1000000), 519 core_freesync->map[index].caps->min_refresh_in_micro_hz))); 520 521 /* adjust for frame duration above max */ 522 if (static_ramp_variables->ramp_current_frame_duration_in_ns >= 523 frame_duration) { 524 525 static_ramp_variables->ramp_is_active = false; 526 static_ramp_variables-> 527 ramp_current_frame_duration_in_ns = 528 frame_duration; 529 } 530 } 531 532 calc_v_total_from_duration(stream, static_ramp_variables-> 533 ramp_current_frame_duration_in_ns, v_total); 534 } 535 536 static void reset_freesync_state_variables(struct freesync_state* state) 537 { 538 state->static_ramp.ramp_is_active = false; 539 if (state->nominal_refresh_rate_in_micro_hz) 540 state->static_ramp.ramp_current_frame_duration_in_ns = 541 ((unsigned int) (div64_u64( 542 (1000000000ULL * 1000000), 543 state->nominal_refresh_rate_in_micro_hz))); 544 545 state->btr.btr_active = false; 546 state->btr.frame_counter = 0; 547 state->btr.frames_to_insert = 0; 548 state->btr.inserted_frame_duration_in_us = 0; 549 state->btr.program_btr = false; 550 551 state->fixed_refresh.fixed_active = false; 552 state->fixed_refresh.program_fixed = false; 553 } 554 /* 555 * Sets freesync mode on a stream depending on current freesync state. 556 */ 557 static bool set_freesync_on_streams(struct core_freesync *core_freesync, 558 struct dc_stream_state **streams, int num_streams) 559 { 560 int v_total_nominal = 0, v_total_min = 0, v_total_max = 0; 561 unsigned int stream_idx, map_index = 0; 562 struct freesync_state *state; 563 564 if (num_streams == 0 || streams == NULL || num_streams > 1) 565 return false; 566 567 for (stream_idx = 0; stream_idx < num_streams; stream_idx++) { 568 569 map_index = map_index_from_stream(core_freesync, 570 streams[stream_idx]); 571 572 state = &core_freesync->map[map_index].state; 573 574 if (core_freesync->map[map_index].caps->supported) { 575 576 /* Fullscreen has the topmost priority. If the 577 * fullscreen bit is set, we are in a fullscreen 578 * application where it should not matter if it is 579 * static screen. We should not check the static_screen 580 * or video bit. 581 * 582 * Special cases of fullscreen include btr and fixed 583 * refresh. We program btr on every flip and involves 584 * programming full range right before the last inserted frame. 585 * However, we do not want to program the full freesync range 586 * when fixed refresh is active, because we only program 587 * that logic once and this will override it. 588 */ 589 if (core_freesync->map[map_index].user_enable. 590 enable_for_gaming == true && 591 state->fullscreen == true && 592 state->fixed_refresh.fixed_active == false) { 593 /* Enable freesync */ 594 595 v_total_min = state->freesync_range.vmin; 596 v_total_max = state->freesync_range.vmax; 597 598 /* Update the freesync context for the stream */ 599 update_stream_freesync_context(core_freesync, 600 streams[stream_idx]); 601 602 core_freesync->dc->stream_funcs. 603 adjust_vmin_vmax(core_freesync->dc, streams, 604 num_streams, v_total_min, 605 v_total_max); 606 607 return true; 608 609 } else if (core_freesync->map[map_index].user_enable. 610 enable_for_video && state->video == true) { 611 /* Enable 48Hz feature */ 612 613 calc_v_total_from_duration(streams[stream_idx], 614 state->time.update_duration_in_ns, 615 &v_total_nominal); 616 617 /* Program only if v_total_nominal is in range*/ 618 if (v_total_nominal >= 619 streams[stream_idx]->timing.v_total) { 620 621 /* Update the freesync context for 622 * the stream 623 */ 624 update_stream_freesync_context( 625 core_freesync, 626 streams[stream_idx]); 627 628 core_freesync->dc->stream_funcs. 629 adjust_vmin_vmax( 630 core_freesync->dc, streams, 631 num_streams, v_total_nominal, 632 v_total_nominal); 633 } 634 return true; 635 636 } else { 637 /* Disable freesync */ 638 v_total_nominal = streams[stream_idx]-> 639 timing.v_total; 640 641 /* Update the freesync context for 642 * the stream 643 */ 644 update_stream_freesync_context( 645 core_freesync, 646 streams[stream_idx]); 647 648 core_freesync->dc->stream_funcs. 649 adjust_vmin_vmax( 650 core_freesync->dc, streams, 651 num_streams, v_total_nominal, 652 v_total_nominal); 653 654 /* Reset the cached variables */ 655 reset_freesync_state_variables(state); 656 657 return true; 658 } 659 } else { 660 /* Disable freesync */ 661 v_total_nominal = streams[stream_idx]-> 662 timing.v_total; 663 /* 664 * we have to reset drr always even sink does 665 * not support freesync because a former stream has 666 * be programmed 667 */ 668 core_freesync->dc->stream_funcs. 669 adjust_vmin_vmax( 670 core_freesync->dc, streams, 671 num_streams, v_total_nominal, 672 v_total_nominal); 673 /* Reset the cached variables */ 674 reset_freesync_state_variables(state); 675 } 676 677 } 678 679 return false; 680 } 681 682 static void set_static_ramp_variables(struct core_freesync *core_freesync, 683 unsigned int index, bool enable_static_screen) 684 { 685 unsigned int frame_duration = 0; 686 unsigned int nominal_refresh_rate = core_freesync->map[index].state. 687 nominal_refresh_rate_in_micro_hz; 688 unsigned int min_refresh_rate= core_freesync->map[index].caps-> 689 min_refresh_in_micro_hz; 690 struct gradual_static_ramp *static_ramp_variables = 691 &core_freesync->map[index].state.static_ramp; 692 693 /* If we are ENABLING static screen, refresh rate should go DOWN. 694 * If we are DISABLING static screen, refresh rate should go UP. 695 */ 696 if (enable_static_screen) 697 static_ramp_variables->ramp_direction_is_up = false; 698 else 699 static_ramp_variables->ramp_direction_is_up = true; 700 701 /* If ramp is not active, set initial frame duration depending on 702 * whether we are enabling/disabling static screen mode. If the ramp is 703 * already active, ramp should continue in the opposite direction 704 * starting with the current frame duration 705 */ 706 if (!static_ramp_variables->ramp_is_active) { 707 if (enable_static_screen == true) { 708 /* Going to lower refresh rate, so start from max 709 * refresh rate (min frame duration) 710 */ 711 frame_duration = ((unsigned int) (div64_u64( 712 (1000000000ULL * 1000000), 713 nominal_refresh_rate))); 714 } else { 715 /* Going to higher refresh rate, so start from min 716 * refresh rate (max frame duration) 717 */ 718 frame_duration = ((unsigned int) (div64_u64( 719 (1000000000ULL * 1000000), 720 min_refresh_rate))); 721 } 722 static_ramp_variables-> 723 ramp_current_frame_duration_in_ns = frame_duration; 724 725 static_ramp_variables->ramp_is_active = true; 726 } 727 } 728 729 void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync, 730 struct dc_stream_state **streams, int num_streams) 731 { 732 unsigned int index, v_total, inserted_frame_v_total = 0; 733 unsigned int min_frame_duration_in_ns, vmax, vmin = 0; 734 struct freesync_state *state; 735 struct core_freesync *core_freesync = NULL; 736 struct dc_static_screen_events triggers = {0}; 737 738 if (mod_freesync == NULL) 739 return; 740 741 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 742 743 if (core_freesync->num_entities == 0) 744 return; 745 746 index = map_index_from_stream(core_freesync, 747 streams[0]); 748 749 if (core_freesync->map[index].caps->supported == false) 750 return; 751 752 state = &core_freesync->map[index].state; 753 754 /* Below the Range Logic */ 755 756 /* Only execute if in fullscreen mode */ 757 if (state->fullscreen == true && 758 core_freesync->map[index].user_enable.enable_for_gaming && 759 core_freesync->map[index].caps->btr_supported && 760 state->btr.btr_active) { 761 762 /* TODO: pass in flag for Pre-DCE12 ASIC 763 * in order for frame variable duration to take affect, 764 * it needs to be done one VSYNC early, which is at 765 * frameCounter == 1. 766 * For DCE12 and newer updates to V_TOTAL_MIN/MAX 767 * will take affect on current frame 768 */ 769 if (state->btr.frames_to_insert == state->btr.frame_counter) { 770 771 min_frame_duration_in_ns = ((unsigned int) (div64_u64( 772 (1000000000ULL * 1000000), 773 state->nominal_refresh_rate_in_micro_hz))); 774 775 vmin = state->freesync_range.vmin; 776 777 inserted_frame_v_total = vmin; 778 779 if (min_frame_duration_in_ns / 1000) 780 inserted_frame_v_total = 781 state->btr.inserted_frame_duration_in_us * 782 vmin / (min_frame_duration_in_ns / 1000); 783 784 /* Set length of inserted frames as v_total_max*/ 785 vmax = inserted_frame_v_total; 786 vmin = inserted_frame_v_total; 787 788 /* Program V_TOTAL */ 789 core_freesync->dc->stream_funcs.adjust_vmin_vmax( 790 core_freesync->dc, streams, 791 num_streams, vmin, vmax); 792 } 793 794 if (state->btr.frame_counter > 0) 795 state->btr.frame_counter--; 796 797 /* Restore FreeSync */ 798 if (state->btr.frame_counter == 0) 799 set_freesync_on_streams(core_freesync, streams, num_streams); 800 } 801 802 /* If in fullscreen freesync mode or in video, do not program 803 * static screen ramp values 804 */ 805 if (state->fullscreen == true || state->video == true) { 806 807 state->static_ramp.ramp_is_active = false; 808 809 return; 810 } 811 812 /* Gradual Static Screen Ramping Logic */ 813 814 /* Execute if ramp is active and user enabled freesync static screen*/ 815 if (state->static_ramp.ramp_is_active && 816 core_freesync->map[index].user_enable.enable_for_static) { 817 818 calc_v_total_for_static_ramp(core_freesync, streams[0], 819 index, &v_total); 820 821 /* Update the freesync context for the stream */ 822 update_stream_freesync_context(core_freesync, streams[0]); 823 824 /* Program static screen ramp values */ 825 core_freesync->dc->stream_funcs.adjust_vmin_vmax( 826 core_freesync->dc, streams, 827 num_streams, v_total, 828 v_total); 829 830 triggers.overlay_update = true; 831 triggers.surface_update = true; 832 833 core_freesync->dc->stream_funcs.set_static_screen_events( 834 core_freesync->dc, streams, num_streams, 835 &triggers); 836 } 837 } 838 839 void mod_freesync_update_state(struct mod_freesync *mod_freesync, 840 struct dc_stream_state **streams, int num_streams, 841 struct mod_freesync_params *freesync_params) 842 { 843 bool freesync_program_required = false; 844 unsigned int stream_index; 845 struct freesync_state *state; 846 struct core_freesync *core_freesync = NULL; 847 struct dc_static_screen_events triggers = {0}; 848 849 if (mod_freesync == NULL) 850 return; 851 852 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 853 854 if (core_freesync->num_entities == 0) 855 return; 856 857 for(stream_index = 0; stream_index < num_streams; stream_index++) { 858 859 unsigned int map_index = map_index_from_stream(core_freesync, 860 streams[stream_index]); 861 862 bool is_embedded = dc_is_embedded_signal( 863 streams[stream_index]->sink->sink_signal); 864 865 struct freesync_registry_options *opts = &core_freesync->opts; 866 867 state = &core_freesync->map[map_index].state; 868 869 switch (freesync_params->state){ 870 case FREESYNC_STATE_FULLSCREEN: 871 state->fullscreen = freesync_params->enable; 872 freesync_program_required = true; 873 state->windowed_fullscreen = 874 freesync_params->windowed_fullscreen; 875 break; 876 case FREESYNC_STATE_STATIC_SCREEN: 877 /* Static screen ramp is disabled by default, but can 878 * be enabled through regkey. 879 */ 880 if ((is_embedded && opts->drr_internal_supported) || 881 (!is_embedded && opts->drr_external_supported)) 882 883 if (state->static_screen != 884 freesync_params->enable) { 885 886 /* Change the state flag */ 887 state->static_screen = 888 freesync_params->enable; 889 890 /* Update static screen ramp */ 891 set_static_ramp_variables(core_freesync, 892 map_index, 893 freesync_params->enable); 894 } 895 /* We program the ramp starting next VUpdate */ 896 break; 897 case FREESYNC_STATE_VIDEO: 898 /* Change core variables only if there is a change*/ 899 if(freesync_params->update_duration_in_ns != 900 state->time.update_duration_in_ns) { 901 902 state->video = freesync_params->enable; 903 state->time.update_duration_in_ns = 904 freesync_params->update_duration_in_ns; 905 906 freesync_program_required = true; 907 } 908 break; 909 case FREESYNC_STATE_NONE: 910 /* handle here to avoid warning */ 911 break; 912 } 913 } 914 915 /* Update mask */ 916 triggers.overlay_update = true; 917 triggers.surface_update = true; 918 919 core_freesync->dc->stream_funcs.set_static_screen_events( 920 core_freesync->dc, streams, num_streams, 921 &triggers); 922 923 if (freesync_program_required) 924 /* Program freesync according to current state*/ 925 set_freesync_on_streams(core_freesync, streams, num_streams); 926 } 927 928 929 bool mod_freesync_get_state(struct mod_freesync *mod_freesync, 930 struct dc_stream_state *stream, 931 struct mod_freesync_params *freesync_params) 932 { 933 unsigned int index = 0; 934 struct core_freesync *core_freesync = NULL; 935 936 if (mod_freesync == NULL) 937 return false; 938 939 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 940 index = map_index_from_stream(core_freesync, stream); 941 942 if (core_freesync->map[index].state.fullscreen) { 943 freesync_params->state = FREESYNC_STATE_FULLSCREEN; 944 freesync_params->enable = true; 945 } else if (core_freesync->map[index].state.static_screen) { 946 freesync_params->state = FREESYNC_STATE_STATIC_SCREEN; 947 freesync_params->enable = true; 948 } else if (core_freesync->map[index].state.video) { 949 freesync_params->state = FREESYNC_STATE_VIDEO; 950 freesync_params->enable = true; 951 } else { 952 freesync_params->state = FREESYNC_STATE_NONE; 953 freesync_params->enable = false; 954 } 955 956 freesync_params->update_duration_in_ns = 957 core_freesync->map[index].state.time.update_duration_in_ns; 958 959 freesync_params->windowed_fullscreen = 960 core_freesync->map[index].state.windowed_fullscreen; 961 962 return true; 963 } 964 965 bool mod_freesync_set_user_enable(struct mod_freesync *mod_freesync, 966 struct dc_stream_state **streams, int num_streams, 967 struct mod_freesync_user_enable *user_enable) 968 { 969 unsigned int stream_index, map_index; 970 int persistent_data = 0; 971 struct persistent_data_flag flag; 972 struct dc *dc = NULL; 973 struct core_freesync *core_freesync = NULL; 974 975 if (mod_freesync == NULL) 976 return false; 977 978 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 979 dc = core_freesync->dc; 980 981 flag.save_per_edid = true; 982 flag.save_per_link = false; 983 984 for(stream_index = 0; stream_index < num_streams; 985 stream_index++){ 986 987 map_index = map_index_from_stream(core_freesync, 988 streams[stream_index]); 989 990 core_freesync->map[map_index].user_enable = *user_enable; 991 992 /* Write persistent data in registry*/ 993 if (core_freesync->map[map_index].user_enable. 994 enable_for_gaming) 995 persistent_data = persistent_data | 1; 996 if (core_freesync->map[map_index].user_enable. 997 enable_for_static) 998 persistent_data = persistent_data | 2; 999 if (core_freesync->map[map_index].user_enable. 1000 enable_for_video) 1001 persistent_data = persistent_data | 4; 1002 1003 dm_write_persistent_data(dc->ctx, 1004 streams[stream_index]->sink, 1005 FREESYNC_REGISTRY_NAME, 1006 "userenable", 1007 &persistent_data, 1008 sizeof(int), 1009 &flag); 1010 } 1011 1012 set_freesync_on_streams(core_freesync, streams, num_streams); 1013 1014 return true; 1015 } 1016 1017 bool mod_freesync_get_user_enable(struct mod_freesync *mod_freesync, 1018 struct dc_stream_state *stream, 1019 struct mod_freesync_user_enable *user_enable) 1020 { 1021 unsigned int index = 0; 1022 struct core_freesync *core_freesync = NULL; 1023 1024 if (mod_freesync == NULL) 1025 return false; 1026 1027 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1028 index = map_index_from_stream(core_freesync, stream); 1029 1030 *user_enable = core_freesync->map[index].user_enable; 1031 1032 return true; 1033 } 1034 1035 bool mod_freesync_get_static_ramp_active(struct mod_freesync *mod_freesync, 1036 struct dc_stream_state *stream, 1037 bool *is_ramp_active) 1038 { 1039 unsigned int index = 0; 1040 struct core_freesync *core_freesync = NULL; 1041 1042 if (mod_freesync == NULL) 1043 return false; 1044 1045 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1046 index = map_index_from_stream(core_freesync, stream); 1047 1048 *is_ramp_active = 1049 core_freesync->map[index].state.static_ramp.ramp_is_active; 1050 1051 return true; 1052 } 1053 1054 bool mod_freesync_override_min_max(struct mod_freesync *mod_freesync, 1055 struct dc_stream_state *streams, 1056 unsigned int min_refresh, 1057 unsigned int max_refresh, 1058 struct mod_freesync_caps *caps) 1059 { 1060 unsigned int index = 0; 1061 struct core_freesync *core_freesync; 1062 struct freesync_state *state; 1063 1064 if (mod_freesync == NULL) 1065 return false; 1066 1067 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1068 index = map_index_from_stream(core_freesync, streams); 1069 state = &core_freesync->map[index].state; 1070 1071 if (max_refresh == 0) 1072 max_refresh = state->nominal_refresh_rate_in_micro_hz; 1073 1074 if (min_refresh == 0) { 1075 /* Restore defaults */ 1076 calc_freesync_range(core_freesync, streams, state, 1077 core_freesync->map[index].caps-> 1078 min_refresh_in_micro_hz, 1079 state->nominal_refresh_rate_in_micro_hz); 1080 } else { 1081 calc_freesync_range(core_freesync, streams, 1082 state, 1083 min_refresh, 1084 max_refresh); 1085 1086 /* Program vtotal min/max */ 1087 core_freesync->dc->stream_funcs.adjust_vmin_vmax( 1088 core_freesync->dc, &streams, 1, 1089 state->freesync_range.vmin, 1090 state->freesync_range.vmax); 1091 } 1092 1093 if (min_refresh != 0 && 1094 dc_is_embedded_signal(streams->sink->sink_signal) && 1095 (max_refresh - min_refresh >= 10000000)) { 1096 caps->supported = true; 1097 caps->min_refresh_in_micro_hz = min_refresh; 1098 caps->max_refresh_in_micro_hz = max_refresh; 1099 } 1100 1101 /* Update the stream */ 1102 update_stream(core_freesync, streams); 1103 1104 return true; 1105 } 1106 1107 bool mod_freesync_get_min_max(struct mod_freesync *mod_freesync, 1108 struct dc_stream_state *stream, 1109 unsigned int *min_refresh, 1110 unsigned int *max_refresh) 1111 { 1112 unsigned int index = 0; 1113 struct core_freesync *core_freesync = NULL; 1114 1115 if (mod_freesync == NULL) 1116 return false; 1117 1118 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1119 index = map_index_from_stream(core_freesync, stream); 1120 1121 *min_refresh = 1122 core_freesync->map[index].state.freesync_range.min_refresh; 1123 *max_refresh = 1124 core_freesync->map[index].state.freesync_range.max_refresh; 1125 1126 return true; 1127 } 1128 1129 bool mod_freesync_get_vmin_vmax(struct mod_freesync *mod_freesync, 1130 struct dc_stream_state *stream, 1131 unsigned int *vmin, 1132 unsigned int *vmax) 1133 { 1134 unsigned int index = 0; 1135 struct core_freesync *core_freesync = NULL; 1136 1137 if (mod_freesync == NULL) 1138 return false; 1139 1140 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1141 index = map_index_from_stream(core_freesync, stream); 1142 1143 *vmin = 1144 core_freesync->map[index].state.freesync_range.vmin; 1145 *vmax = 1146 core_freesync->map[index].state.freesync_range.vmax; 1147 1148 return true; 1149 } 1150 1151 bool mod_freesync_get_v_position(struct mod_freesync *mod_freesync, 1152 struct dc_stream_state *stream, 1153 unsigned int *nom_v_pos, 1154 unsigned int *v_pos) 1155 { 1156 unsigned int index = 0; 1157 struct core_freesync *core_freesync = NULL; 1158 struct crtc_position position; 1159 1160 if (mod_freesync == NULL) 1161 return false; 1162 1163 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1164 index = map_index_from_stream(core_freesync, stream); 1165 1166 if (core_freesync->dc->stream_funcs.get_crtc_position( 1167 core_freesync->dc, &stream, 1, 1168 &position.vertical_count, &position.nominal_vcount)) { 1169 1170 *nom_v_pos = position.nominal_vcount; 1171 *v_pos = position.vertical_count; 1172 1173 return true; 1174 } 1175 1176 return false; 1177 } 1178 1179 void mod_freesync_notify_mode_change(struct mod_freesync *mod_freesync, 1180 struct dc_stream_state **streams, int num_streams) 1181 { 1182 unsigned int stream_index, map_index; 1183 struct freesync_state *state; 1184 struct core_freesync *core_freesync = NULL; 1185 struct dc_static_screen_events triggers = {0}; 1186 unsigned long long temp = 0; 1187 1188 if (mod_freesync == NULL) 1189 return; 1190 1191 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1192 1193 for (stream_index = 0; stream_index < num_streams; stream_index++) { 1194 map_index = map_index_from_stream(core_freesync, 1195 streams[stream_index]); 1196 1197 state = &core_freesync->map[map_index].state; 1198 1199 /* Update the field rate for new timing */ 1200 temp = streams[stream_index]->timing.pix_clk_khz; 1201 temp *= 1000ULL * 1000ULL * 1000ULL; 1202 temp = div_u64(temp, 1203 streams[stream_index]->timing.h_total); 1204 temp = div_u64(temp, 1205 streams[stream_index]->timing.v_total); 1206 state->nominal_refresh_rate_in_micro_hz = 1207 (unsigned int) temp; 1208 1209 if (core_freesync->map[map_index].caps->supported) { 1210 1211 /* Update the stream */ 1212 update_stream(core_freesync, streams[stream_index]); 1213 1214 /* Calculate vmin/vmax and refresh rate for 1215 * current mode 1216 */ 1217 calc_freesync_range(core_freesync, *streams, state, 1218 core_freesync->map[map_index].caps-> 1219 min_refresh_in_micro_hz, 1220 state->nominal_refresh_rate_in_micro_hz); 1221 1222 /* Update mask */ 1223 triggers.overlay_update = true; 1224 triggers.surface_update = true; 1225 1226 core_freesync->dc->stream_funcs.set_static_screen_events( 1227 core_freesync->dc, streams, num_streams, 1228 &triggers); 1229 } 1230 } 1231 1232 /* Program freesync according to current state*/ 1233 set_freesync_on_streams(core_freesync, streams, num_streams); 1234 } 1235 1236 /* Add the timestamps to the cache and determine whether BTR programming 1237 * is required, depending on the times calculated 1238 */ 1239 static void update_timestamps(struct core_freesync *core_freesync, 1240 const struct dc_stream_state *stream, unsigned int map_index, 1241 unsigned int last_render_time_in_us) 1242 { 1243 struct freesync_state *state = &core_freesync->map[map_index].state; 1244 1245 state->time.render_times[state->time.render_times_index] = 1246 last_render_time_in_us; 1247 state->time.render_times_index++; 1248 1249 if (state->time.render_times_index >= RENDER_TIMES_MAX_COUNT) 1250 state->time.render_times_index = 0; 1251 1252 if (last_render_time_in_us + BTR_EXIT_MARGIN < 1253 state->time.max_render_time_in_us) { 1254 1255 /* Exit Below the Range */ 1256 if (state->btr.btr_active) { 1257 1258 state->btr.program_btr = true; 1259 state->btr.btr_active = false; 1260 state->btr.frame_counter = 0; 1261 1262 /* Exit Fixed Refresh mode */ 1263 } else if (state->fixed_refresh.fixed_active) { 1264 1265 state->fixed_refresh.frame_counter++; 1266 1267 if (state->fixed_refresh.frame_counter > 1268 FIXED_REFRESH_EXIT_FRAME_COUNT) { 1269 state->fixed_refresh.frame_counter = 0; 1270 state->fixed_refresh.program_fixed = true; 1271 state->fixed_refresh.fixed_active = false; 1272 } 1273 } 1274 1275 } else if (last_render_time_in_us > state->time.max_render_time_in_us) { 1276 1277 /* Enter Below the Range */ 1278 if (!state->btr.btr_active && 1279 core_freesync->map[map_index].caps->btr_supported) { 1280 1281 state->btr.program_btr = true; 1282 state->btr.btr_active = true; 1283 1284 /* Enter Fixed Refresh mode */ 1285 } else if (!state->fixed_refresh.fixed_active && 1286 !core_freesync->map[map_index].caps->btr_supported) { 1287 1288 state->fixed_refresh.frame_counter++; 1289 1290 if (state->fixed_refresh.frame_counter > 1291 FIXED_REFRESH_ENTER_FRAME_COUNT) { 1292 state->fixed_refresh.frame_counter = 0; 1293 state->fixed_refresh.program_fixed = true; 1294 state->fixed_refresh.fixed_active = true; 1295 } 1296 } 1297 } 1298 1299 /* When Below the Range is active, must react on every frame */ 1300 if (state->btr.btr_active) 1301 state->btr.program_btr = true; 1302 } 1303 1304 static void apply_below_the_range(struct core_freesync *core_freesync, 1305 struct dc_stream_state *stream, unsigned int map_index, 1306 unsigned int last_render_time_in_us) 1307 { 1308 unsigned int inserted_frame_duration_in_us = 0; 1309 unsigned int mid_point_frames_ceil = 0; 1310 unsigned int mid_point_frames_floor = 0; 1311 unsigned int frame_time_in_us = 0; 1312 unsigned int delta_from_mid_point_in_us_1 = 0xFFFFFFFF; 1313 unsigned int delta_from_mid_point_in_us_2 = 0xFFFFFFFF; 1314 unsigned int frames_to_insert = 0; 1315 unsigned int min_frame_duration_in_ns = 0; 1316 struct freesync_state *state = &core_freesync->map[map_index].state; 1317 1318 if (!state->btr.program_btr) 1319 return; 1320 1321 state->btr.program_btr = false; 1322 1323 min_frame_duration_in_ns = ((unsigned int) (div64_u64( 1324 (1000000000ULL * 1000000), 1325 state->nominal_refresh_rate_in_micro_hz))); 1326 1327 /* Program BTR */ 1328 1329 /* BTR set to "not active" so disengage */ 1330 if (!state->btr.btr_active) 1331 1332 /* Restore FreeSync */ 1333 set_freesync_on_streams(core_freesync, &stream, 1); 1334 1335 /* BTR set to "active" so engage */ 1336 else { 1337 1338 /* Calculate number of midPoint frames that could fit within 1339 * the render time interval- take ceil of this value 1340 */ 1341 mid_point_frames_ceil = (last_render_time_in_us + 1342 state->btr.mid_point_in_us- 1) / 1343 state->btr.mid_point_in_us; 1344 1345 if (mid_point_frames_ceil > 0) { 1346 1347 frame_time_in_us = last_render_time_in_us / 1348 mid_point_frames_ceil; 1349 delta_from_mid_point_in_us_1 = 1350 (state->btr.mid_point_in_us > 1351 frame_time_in_us) ? 1352 (state->btr.mid_point_in_us - frame_time_in_us): 1353 (frame_time_in_us - state->btr.mid_point_in_us); 1354 } 1355 1356 /* Calculate number of midPoint frames that could fit within 1357 * the render time interval- take floor of this value 1358 */ 1359 mid_point_frames_floor = last_render_time_in_us / 1360 state->btr.mid_point_in_us; 1361 1362 if (mid_point_frames_floor > 0) { 1363 1364 frame_time_in_us = last_render_time_in_us / 1365 mid_point_frames_floor; 1366 delta_from_mid_point_in_us_2 = 1367 (state->btr.mid_point_in_us > 1368 frame_time_in_us) ? 1369 (state->btr.mid_point_in_us - frame_time_in_us): 1370 (frame_time_in_us - state->btr.mid_point_in_us); 1371 } 1372 1373 /* Choose number of frames to insert based on how close it 1374 * can get to the mid point of the variable range. 1375 */ 1376 if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) 1377 frames_to_insert = mid_point_frames_ceil; 1378 else 1379 frames_to_insert = mid_point_frames_floor; 1380 1381 /* Either we've calculated the number of frames to insert, 1382 * or we need to insert min duration frames 1383 */ 1384 if (frames_to_insert > 0) 1385 inserted_frame_duration_in_us = last_render_time_in_us / 1386 frames_to_insert; 1387 1388 if (inserted_frame_duration_in_us < 1389 state->time.min_render_time_in_us) 1390 1391 inserted_frame_duration_in_us = 1392 state->time.min_render_time_in_us; 1393 1394 /* Cache the calculated variables */ 1395 state->btr.inserted_frame_duration_in_us = 1396 inserted_frame_duration_in_us; 1397 state->btr.frames_to_insert = frames_to_insert; 1398 state->btr.frame_counter = frames_to_insert; 1399 1400 } 1401 } 1402 1403 static void apply_fixed_refresh(struct core_freesync *core_freesync, 1404 struct dc_stream_state *stream, unsigned int map_index) 1405 { 1406 unsigned int vmin = 0, vmax = 0; 1407 struct freesync_state *state = &core_freesync->map[map_index].state; 1408 1409 if (!state->fixed_refresh.program_fixed) 1410 return; 1411 1412 state->fixed_refresh.program_fixed = false; 1413 1414 /* Program Fixed Refresh */ 1415 1416 /* Fixed Refresh set to "not active" so disengage */ 1417 if (!state->fixed_refresh.fixed_active) { 1418 set_freesync_on_streams(core_freesync, &stream, 1); 1419 1420 /* Fixed Refresh set to "active" so engage (fix to max) */ 1421 } else { 1422 1423 vmin = state->freesync_range.vmin; 1424 1425 vmax = vmin; 1426 1427 core_freesync->dc->stream_funcs.adjust_vmin_vmax( 1428 core_freesync->dc, &stream, 1429 1, vmin, 1430 vmax); 1431 } 1432 } 1433 1434 void mod_freesync_pre_update_plane_addresses(struct mod_freesync *mod_freesync, 1435 struct dc_stream_state **streams, int num_streams, 1436 unsigned int curr_time_stamp_in_us) 1437 { 1438 unsigned int stream_index, map_index, last_render_time_in_us = 0; 1439 struct core_freesync *core_freesync = NULL; 1440 1441 if (mod_freesync == NULL) 1442 return; 1443 1444 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1445 1446 for (stream_index = 0; stream_index < num_streams; stream_index++) { 1447 1448 map_index = map_index_from_stream(core_freesync, 1449 streams[stream_index]); 1450 1451 if (core_freesync->map[map_index].caps->supported) { 1452 1453 last_render_time_in_us = curr_time_stamp_in_us - 1454 core_freesync->map[map_index].state.time. 1455 prev_time_stamp_in_us; 1456 1457 /* Add the timestamps to the cache and determine 1458 * whether BTR program is required 1459 */ 1460 update_timestamps(core_freesync, streams[stream_index], 1461 map_index, last_render_time_in_us); 1462 1463 if (core_freesync->map[map_index].state.fullscreen && 1464 core_freesync->map[map_index].user_enable. 1465 enable_for_gaming) { 1466 1467 if (core_freesync->map[map_index].caps->btr_supported) { 1468 1469 apply_below_the_range(core_freesync, 1470 streams[stream_index], map_index, 1471 last_render_time_in_us); 1472 } else { 1473 apply_fixed_refresh(core_freesync, 1474 streams[stream_index], map_index); 1475 } 1476 } 1477 1478 core_freesync->map[map_index].state.time. 1479 prev_time_stamp_in_us = curr_time_stamp_in_us; 1480 } 1481 1482 } 1483 } 1484