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