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