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