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