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 <linux/slab.h> 27 28 #include "dm_services.h" 29 #include "dc.h" 30 #include "mod_freesync.h" 31 #include "core_types.h" 32 33 #define MOD_FREESYNC_MAX_CONCURRENT_STREAMS 32 34 35 #define MIN_REFRESH_RANGE_IN_US 10000000 36 /* Refresh rate ramp at a fixed rate of 65 Hz/second */ 37 #define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65) 38 /* Number of elements in the render times cache array */ 39 #define RENDER_TIMES_MAX_COUNT 10 40 /* Threshold to exit BTR (to avoid frequent enter-exits at the lower limit) */ 41 #define BTR_EXIT_MARGIN 2000 42 /* Threshold to change BTR multiplier (to avoid frequent changes) */ 43 #define BTR_DRIFT_MARGIN 2000 44 /*Threshold to exit fixed refresh rate*/ 45 #define FIXED_REFRESH_EXIT_MARGIN_IN_HZ 4 46 /* Number of consecutive frames to check before entering/exiting fixed refresh*/ 47 #define FIXED_REFRESH_ENTER_FRAME_COUNT 5 48 #define FIXED_REFRESH_EXIT_FRAME_COUNT 5 49 50 struct core_freesync { 51 struct mod_freesync public; 52 struct dc *dc; 53 }; 54 55 void setFieldWithMask(unsigned char *dest, unsigned int mask, unsigned int value) 56 { 57 unsigned int shift = 0; 58 59 if (!mask || !dest) 60 return; 61 62 while (!((mask >> shift) & 1)) 63 shift++; 64 65 //reset 66 *dest = *dest & ~mask; 67 //set 68 //dont let value span past mask 69 value = value & (mask >> shift); 70 //insert value 71 *dest = *dest | (value << shift); 72 } 73 74 // VTEM Byte Offset 75 #define VRR_VTEM_PB0 0 76 #define VRR_VTEM_PB1 1 77 #define VRR_VTEM_PB2 2 78 #define VRR_VTEM_PB3 3 79 #define VRR_VTEM_PB4 4 80 #define VRR_VTEM_PB5 5 81 #define VRR_VTEM_PB6 6 82 83 #define VRR_VTEM_MD0 7 84 #define VRR_VTEM_MD1 8 85 #define VRR_VTEM_MD2 9 86 #define VRR_VTEM_MD3 10 87 88 89 // VTEM Byte Masks 90 //PB0 91 #define MASK__VRR_VTEM_PB0__RESERVED0 0x01 92 #define MASK__VRR_VTEM_PB0__SYNC 0x02 93 #define MASK__VRR_VTEM_PB0__VFR 0x04 94 #define MASK__VRR_VTEM_PB0__AFR 0x08 95 #define MASK__VRR_VTEM_PB0__DS_TYPE 0x30 96 //0: Periodic pseudo-static EM Data Set 97 //1: Periodic dynamic EM Data Set 98 //2: Unique EM Data Set 99 //3: Reserved 100 #define MASK__VRR_VTEM_PB0__END 0x40 101 #define MASK__VRR_VTEM_PB0__NEW 0x80 102 103 //PB1 104 #define MASK__VRR_VTEM_PB1__RESERVED1 0xFF 105 106 //PB2 107 #define MASK__VRR_VTEM_PB2__ORGANIZATION_ID 0xFF 108 //0: This is a Vendor Specific EM Data Set 109 //1: This EM Data Set is defined by This Specification (HDMI 2.1 r102.clean) 110 //2: This EM Data Set is defined by CTA-861-G 111 //3: This EM Data Set is defined by VESA 112 //PB3 113 #define MASK__VRR_VTEM_PB3__DATA_SET_TAG_MSB 0xFF 114 //PB4 115 #define MASK__VRR_VTEM_PB4__DATA_SET_TAG_LSB 0xFF 116 //PB5 117 #define MASK__VRR_VTEM_PB5__DATA_SET_LENGTH_MSB 0xFF 118 //PB6 119 #define MASK__VRR_VTEM_PB6__DATA_SET_LENGTH_LSB 0xFF 120 121 122 123 //PB7-27 (20 bytes): 124 //PB7 = MD0 125 #define MASK__VRR_VTEM_MD0__VRR_EN 0x01 126 #define MASK__VRR_VTEM_MD0__M_CONST 0x02 127 #define MASK__VRR_VTEM_MD0__RESERVED2 0x0C 128 #define MASK__VRR_VTEM_MD0__FVA_FACTOR_M1 0xF0 129 130 //MD1 131 #define MASK__VRR_VTEM_MD1__BASE_VFRONT 0xFF 132 133 //MD2 134 #define MASK__VRR_VTEM_MD2__BASE_REFRESH_RATE_98 0x03 135 #define MASK__VRR_VTEM_MD2__RB 0x04 136 #define MASK__VRR_VTEM_MD2__RESERVED3 0xF8 137 138 //MD3 139 #define MASK__VRR_VTEM_MD3__BASE_REFRESH_RATE_07 0xFF 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 if (core_freesync == NULL) 151 goto fail_alloc_context; 152 153 if (dc == NULL) 154 goto fail_construct; 155 156 core_freesync->dc = dc; 157 return &core_freesync->public; 158 159 fail_construct: 160 kfree(core_freesync); 161 162 fail_alloc_context: 163 return NULL; 164 } 165 166 void mod_freesync_destroy(struct mod_freesync *mod_freesync) 167 { 168 struct core_freesync *core_freesync = NULL; 169 if (mod_freesync == NULL) 170 return; 171 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 172 kfree(core_freesync); 173 } 174 175 #if 0 /* unused currently */ 176 static unsigned int calc_refresh_in_uhz_from_duration( 177 unsigned int duration_in_ns) 178 { 179 unsigned int refresh_in_uhz = 180 ((unsigned int)(div64_u64((1000000000ULL * 1000000), 181 duration_in_ns))); 182 return refresh_in_uhz; 183 } 184 #endif 185 186 static unsigned int calc_duration_in_us_from_refresh_in_uhz( 187 unsigned int refresh_in_uhz) 188 { 189 unsigned int duration_in_us = 190 ((unsigned int)(div64_u64((1000000000ULL * 1000), 191 refresh_in_uhz))); 192 return duration_in_us; 193 } 194 195 static unsigned int calc_duration_in_us_from_v_total( 196 const struct dc_stream_state *stream, 197 const struct mod_vrr_params *in_vrr, 198 unsigned int v_total) 199 { 200 unsigned int duration_in_us = 201 (unsigned int)(div64_u64(((unsigned long long)(v_total) 202 * 10000) * stream->timing.h_total, 203 stream->timing.pix_clk_100hz)); 204 205 return duration_in_us; 206 } 207 208 static unsigned int calc_v_total_from_refresh( 209 const struct dc_stream_state *stream, 210 unsigned int refresh_in_uhz) 211 { 212 unsigned int v_total = stream->timing.v_total; 213 unsigned int frame_duration_in_ns; 214 215 frame_duration_in_ns = 216 ((unsigned int)(div64_u64((1000000000ULL * 1000000), 217 refresh_in_uhz))); 218 219 v_total = div64_u64(div64_u64(((unsigned long long)( 220 frame_duration_in_ns) * (stream->timing.pix_clk_100hz / 10)), 221 stream->timing.h_total), 1000000); 222 223 /* v_total cannot be less than nominal */ 224 if (v_total < stream->timing.v_total) { 225 ASSERT(v_total < stream->timing.v_total); 226 v_total = stream->timing.v_total; 227 } 228 229 return v_total; 230 } 231 232 static unsigned int calc_v_total_from_duration( 233 const struct dc_stream_state *stream, 234 const struct mod_vrr_params *vrr, 235 unsigned int duration_in_us) 236 { 237 unsigned int v_total = 0; 238 239 if (duration_in_us < vrr->min_duration_in_us) 240 duration_in_us = vrr->min_duration_in_us; 241 242 if (duration_in_us > vrr->max_duration_in_us) 243 duration_in_us = vrr->max_duration_in_us; 244 245 v_total = div64_u64(div64_u64(((unsigned long long)( 246 duration_in_us) * (stream->timing.pix_clk_100hz / 10)), 247 stream->timing.h_total), 1000); 248 249 /* v_total cannot be less than nominal */ 250 if (v_total < stream->timing.v_total) { 251 ASSERT(v_total < stream->timing.v_total); 252 v_total = stream->timing.v_total; 253 } 254 255 return v_total; 256 } 257 258 static void update_v_total_for_static_ramp( 259 struct core_freesync *core_freesync, 260 const struct dc_stream_state *stream, 261 struct mod_vrr_params *in_out_vrr) 262 { 263 unsigned int v_total = 0; 264 unsigned int current_duration_in_us = 265 calc_duration_in_us_from_v_total( 266 stream, in_out_vrr, 267 in_out_vrr->adjust.v_total_max); 268 unsigned int target_duration_in_us = 269 calc_duration_in_us_from_refresh_in_uhz( 270 in_out_vrr->fixed.target_refresh_in_uhz); 271 bool ramp_direction_is_up = (current_duration_in_us > 272 target_duration_in_us) ? true : false; 273 274 /* Calc ratio between new and current frame duration with 3 digit */ 275 unsigned int frame_duration_ratio = div64_u64(1000000, 276 (1000 + div64_u64(((unsigned long long)( 277 STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME) * 278 current_duration_in_us), 279 1000000))); 280 281 /* Calculate delta between new and current frame duration in us */ 282 unsigned int frame_duration_delta = div64_u64(((unsigned long long)( 283 current_duration_in_us) * 284 (1000 - frame_duration_ratio)), 1000); 285 286 /* Adjust frame duration delta based on ratio between current and 287 * standard frame duration (frame duration at 60 Hz refresh rate). 288 */ 289 unsigned int ramp_rate_interpolated = div64_u64(((unsigned long long)( 290 frame_duration_delta) * current_duration_in_us), 16666); 291 292 /* Going to a higher refresh rate (lower frame duration) */ 293 if (ramp_direction_is_up) { 294 /* reduce frame duration */ 295 current_duration_in_us -= ramp_rate_interpolated; 296 297 /* adjust for frame duration below min */ 298 if (current_duration_in_us <= target_duration_in_us) { 299 in_out_vrr->fixed.ramping_active = false; 300 in_out_vrr->fixed.ramping_done = true; 301 current_duration_in_us = 302 calc_duration_in_us_from_refresh_in_uhz( 303 in_out_vrr->fixed.target_refresh_in_uhz); 304 } 305 /* Going to a lower refresh rate (larger frame duration) */ 306 } else { 307 /* increase frame duration */ 308 current_duration_in_us += ramp_rate_interpolated; 309 310 /* adjust for frame duration above max */ 311 if (current_duration_in_us >= target_duration_in_us) { 312 in_out_vrr->fixed.ramping_active = false; 313 in_out_vrr->fixed.ramping_done = true; 314 current_duration_in_us = 315 calc_duration_in_us_from_refresh_in_uhz( 316 in_out_vrr->fixed.target_refresh_in_uhz); 317 } 318 } 319 320 v_total = div64_u64(div64_u64(((unsigned long long)( 321 current_duration_in_us) * (stream->timing.pix_clk_100hz / 10)), 322 stream->timing.h_total), 1000); 323 324 in_out_vrr->adjust.v_total_min = v_total; 325 in_out_vrr->adjust.v_total_max = v_total; 326 } 327 328 static void apply_below_the_range(struct core_freesync *core_freesync, 329 const struct dc_stream_state *stream, 330 unsigned int last_render_time_in_us, 331 struct mod_vrr_params *in_out_vrr) 332 { 333 unsigned int inserted_frame_duration_in_us = 0; 334 unsigned int mid_point_frames_ceil = 0; 335 unsigned int mid_point_frames_floor = 0; 336 unsigned int frame_time_in_us = 0; 337 unsigned int delta_from_mid_point_in_us_1 = 0xFFFFFFFF; 338 unsigned int delta_from_mid_point_in_us_2 = 0xFFFFFFFF; 339 unsigned int frames_to_insert = 0; 340 unsigned int min_frame_duration_in_ns = 0; 341 unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us; 342 unsigned int delta_from_mid_point_delta_in_us; 343 344 min_frame_duration_in_ns = ((unsigned int) (div64_u64( 345 (1000000000ULL * 1000000), 346 in_out_vrr->max_refresh_in_uhz))); 347 348 /* Program BTR */ 349 if (last_render_time_in_us + BTR_EXIT_MARGIN < max_render_time_in_us) { 350 /* Exit Below the Range */ 351 if (in_out_vrr->btr.btr_active) { 352 in_out_vrr->btr.frame_counter = 0; 353 in_out_vrr->btr.btr_active = false; 354 } 355 } else if (last_render_time_in_us > max_render_time_in_us) { 356 /* Enter Below the Range */ 357 in_out_vrr->btr.btr_active = true; 358 } 359 360 /* BTR set to "not active" so disengage */ 361 if (!in_out_vrr->btr.btr_active) { 362 in_out_vrr->btr.inserted_duration_in_us = 0; 363 in_out_vrr->btr.frames_to_insert = 0; 364 in_out_vrr->btr.frame_counter = 0; 365 366 /* Restore FreeSync */ 367 in_out_vrr->adjust.v_total_min = 368 calc_v_total_from_refresh(stream, 369 in_out_vrr->max_refresh_in_uhz); 370 in_out_vrr->adjust.v_total_max = 371 calc_v_total_from_refresh(stream, 372 in_out_vrr->min_refresh_in_uhz); 373 /* BTR set to "active" so engage */ 374 } else { 375 376 /* Calculate number of midPoint frames that could fit within 377 * the render time interval- take ceil of this value 378 */ 379 mid_point_frames_ceil = (last_render_time_in_us + 380 in_out_vrr->btr.mid_point_in_us - 1) / 381 in_out_vrr->btr.mid_point_in_us; 382 383 if (mid_point_frames_ceil > 0) { 384 frame_time_in_us = last_render_time_in_us / 385 mid_point_frames_ceil; 386 delta_from_mid_point_in_us_1 = 387 (in_out_vrr->btr.mid_point_in_us > 388 frame_time_in_us) ? 389 (in_out_vrr->btr.mid_point_in_us - frame_time_in_us) : 390 (frame_time_in_us - in_out_vrr->btr.mid_point_in_us); 391 } 392 393 /* Calculate number of midPoint frames that could fit within 394 * the render time interval- take floor of this value 395 */ 396 mid_point_frames_floor = last_render_time_in_us / 397 in_out_vrr->btr.mid_point_in_us; 398 399 if (mid_point_frames_floor > 0) { 400 401 frame_time_in_us = last_render_time_in_us / 402 mid_point_frames_floor; 403 delta_from_mid_point_in_us_2 = 404 (in_out_vrr->btr.mid_point_in_us > 405 frame_time_in_us) ? 406 (in_out_vrr->btr.mid_point_in_us - frame_time_in_us) : 407 (frame_time_in_us - in_out_vrr->btr.mid_point_in_us); 408 } 409 410 /* Choose number of frames to insert based on how close it 411 * can get to the mid point of the variable range. 412 */ 413 if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) { 414 frames_to_insert = mid_point_frames_ceil; 415 delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_2 - 416 delta_from_mid_point_in_us_1; 417 } else { 418 frames_to_insert = mid_point_frames_floor; 419 delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_1 - 420 delta_from_mid_point_in_us_2; 421 } 422 423 /* Prefer current frame multiplier when BTR is enabled unless it drifts 424 * too far from the midpoint 425 */ 426 if (in_out_vrr->btr.frames_to_insert != 0 && 427 delta_from_mid_point_delta_in_us < BTR_DRIFT_MARGIN) { 428 if (((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) < 429 in_out_vrr->max_duration_in_us) && 430 ((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) > 431 in_out_vrr->min_duration_in_us)) 432 frames_to_insert = in_out_vrr->btr.frames_to_insert; 433 } 434 435 /* Either we've calculated the number of frames to insert, 436 * or we need to insert min duration frames 437 */ 438 if (last_render_time_in_us / frames_to_insert < 439 in_out_vrr->min_duration_in_us){ 440 frames_to_insert -= (frames_to_insert > 1) ? 441 1 : 0; 442 } 443 444 if (frames_to_insert > 0) 445 inserted_frame_duration_in_us = last_render_time_in_us / 446 frames_to_insert; 447 448 if (inserted_frame_duration_in_us < in_out_vrr->min_duration_in_us) 449 inserted_frame_duration_in_us = in_out_vrr->min_duration_in_us; 450 451 /* Cache the calculated variables */ 452 in_out_vrr->btr.inserted_duration_in_us = 453 inserted_frame_duration_in_us; 454 in_out_vrr->btr.frames_to_insert = frames_to_insert; 455 in_out_vrr->btr.frame_counter = frames_to_insert; 456 } 457 } 458 459 static void apply_fixed_refresh(struct core_freesync *core_freesync, 460 const struct dc_stream_state *stream, 461 unsigned int last_render_time_in_us, 462 struct mod_vrr_params *in_out_vrr) 463 { 464 bool update = false; 465 unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us; 466 467 //Compute the exit refresh rate and exit frame duration 468 unsigned int exit_refresh_rate_in_milli_hz = ((1000000000/max_render_time_in_us) 469 + (1000*FIXED_REFRESH_EXIT_MARGIN_IN_HZ)); 470 unsigned int exit_frame_duration_in_us = 1000000000/exit_refresh_rate_in_milli_hz; 471 472 if (last_render_time_in_us < exit_frame_duration_in_us) { 473 /* Exit Fixed Refresh mode */ 474 if (in_out_vrr->fixed.fixed_active) { 475 in_out_vrr->fixed.frame_counter++; 476 477 if (in_out_vrr->fixed.frame_counter > 478 FIXED_REFRESH_EXIT_FRAME_COUNT) { 479 in_out_vrr->fixed.frame_counter = 0; 480 in_out_vrr->fixed.fixed_active = false; 481 in_out_vrr->fixed.target_refresh_in_uhz = 0; 482 update = true; 483 } 484 } 485 } else if (last_render_time_in_us > max_render_time_in_us) { 486 /* Enter Fixed Refresh mode */ 487 if (!in_out_vrr->fixed.fixed_active) { 488 in_out_vrr->fixed.frame_counter++; 489 490 if (in_out_vrr->fixed.frame_counter > 491 FIXED_REFRESH_ENTER_FRAME_COUNT) { 492 in_out_vrr->fixed.frame_counter = 0; 493 in_out_vrr->fixed.fixed_active = true; 494 in_out_vrr->fixed.target_refresh_in_uhz = 495 in_out_vrr->max_refresh_in_uhz; 496 update = true; 497 } 498 } 499 } 500 501 if (update) { 502 if (in_out_vrr->fixed.fixed_active) { 503 in_out_vrr->adjust.v_total_min = 504 calc_v_total_from_refresh( 505 stream, in_out_vrr->max_refresh_in_uhz); 506 in_out_vrr->adjust.v_total_max = 507 in_out_vrr->adjust.v_total_min; 508 } else { 509 in_out_vrr->adjust.v_total_min = 510 calc_v_total_from_refresh(stream, 511 in_out_vrr->max_refresh_in_uhz); 512 in_out_vrr->adjust.v_total_max = 513 calc_v_total_from_refresh(stream, 514 in_out_vrr->min_refresh_in_uhz); 515 } 516 } 517 } 518 519 static bool vrr_settings_require_update(struct core_freesync *core_freesync, 520 struct mod_freesync_config *in_config, 521 unsigned int min_refresh_in_uhz, 522 unsigned int max_refresh_in_uhz, 523 struct mod_vrr_params *in_vrr) 524 { 525 if (in_vrr->state != in_config->state) { 526 return true; 527 } else if (in_vrr->state == VRR_STATE_ACTIVE_FIXED && 528 in_vrr->fixed.target_refresh_in_uhz != 529 in_config->min_refresh_in_uhz) { 530 return true; 531 } else if (in_vrr->min_refresh_in_uhz != min_refresh_in_uhz) { 532 return true; 533 } else if (in_vrr->max_refresh_in_uhz != max_refresh_in_uhz) { 534 return true; 535 } 536 537 return false; 538 } 539 540 bool mod_freesync_get_vmin_vmax(struct mod_freesync *mod_freesync, 541 const struct dc_stream_state *stream, 542 unsigned int *vmin, 543 unsigned int *vmax) 544 { 545 *vmin = stream->adjust.v_total_min; 546 *vmax = stream->adjust.v_total_max; 547 548 return true; 549 } 550 551 bool mod_freesync_get_v_position(struct mod_freesync *mod_freesync, 552 struct dc_stream_state *stream, 553 unsigned int *nom_v_pos, 554 unsigned int *v_pos) 555 { 556 struct core_freesync *core_freesync = NULL; 557 struct crtc_position position; 558 559 if (mod_freesync == NULL) 560 return false; 561 562 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 563 564 if (dc_stream_get_crtc_position(core_freesync->dc, &stream, 1, 565 &position.vertical_count, 566 &position.nominal_vcount)) { 567 568 *nom_v_pos = position.nominal_vcount; 569 *v_pos = position.vertical_count; 570 571 return true; 572 } 573 574 return false; 575 } 576 577 static void build_vrr_infopacket_header_vtem(enum signal_type signal, 578 struct dc_info_packet *infopacket) 579 { 580 // HEADER 581 582 // HB0, HB1, HB2 indicates PacketType VTEMPacket 583 infopacket->hb0 = 0x7F; 584 infopacket->hb1 = 0xC0; 585 infopacket->hb2 = 0x00; //sequence_index 586 587 setFieldWithMask(&infopacket->sb[VRR_VTEM_PB0], MASK__VRR_VTEM_PB0__VFR, 1); 588 setFieldWithMask(&infopacket->sb[VRR_VTEM_PB2], MASK__VRR_VTEM_PB2__ORGANIZATION_ID, 1); 589 setFieldWithMask(&infopacket->sb[VRR_VTEM_PB3], MASK__VRR_VTEM_PB3__DATA_SET_TAG_MSB, 0); 590 setFieldWithMask(&infopacket->sb[VRR_VTEM_PB4], MASK__VRR_VTEM_PB4__DATA_SET_TAG_LSB, 1); 591 setFieldWithMask(&infopacket->sb[VRR_VTEM_PB5], MASK__VRR_VTEM_PB5__DATA_SET_LENGTH_MSB, 0); 592 setFieldWithMask(&infopacket->sb[VRR_VTEM_PB6], MASK__VRR_VTEM_PB6__DATA_SET_LENGTH_LSB, 4); 593 } 594 595 static void build_vrr_infopacket_header_v1(enum signal_type signal, 596 struct dc_info_packet *infopacket, 597 unsigned int *payload_size) 598 { 599 if (dc_is_hdmi_signal(signal)) { 600 601 /* HEADER */ 602 603 /* HB0 = Packet Type = 0x83 (Source Product 604 * Descriptor InfoFrame) 605 */ 606 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD; 607 608 /* HB1 = Version = 0x01 */ 609 infopacket->hb1 = 0x01; 610 611 /* HB2 = [Bits 7:5 = 0] [Bits 4:0 = Length = 0x08] */ 612 infopacket->hb2 = 0x08; 613 614 *payload_size = 0x08; 615 616 } else if (dc_is_dp_signal(signal)) { 617 618 /* HEADER */ 619 620 /* HB0 = Secondary-data Packet ID = 0 - Only non-zero 621 * when used to associate audio related info packets 622 */ 623 infopacket->hb0 = 0x00; 624 625 /* HB1 = Packet Type = 0x83 (Source Product 626 * Descriptor InfoFrame) 627 */ 628 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD; 629 630 /* HB2 = [Bits 7:0 = Least significant eight bits - 631 * For INFOFRAME, the value must be 1Bh] 632 */ 633 infopacket->hb2 = 0x1B; 634 635 /* HB3 = [Bits 7:2 = INFOFRAME SDP Version Number = 0x1] 636 * [Bits 1:0 = Most significant two bits = 0x00] 637 */ 638 infopacket->hb3 = 0x04; 639 640 *payload_size = 0x1B; 641 } 642 } 643 644 static void build_vrr_infopacket_header_v2(enum signal_type signal, 645 struct dc_info_packet *infopacket, 646 unsigned int *payload_size) 647 { 648 if (dc_is_hdmi_signal(signal)) { 649 650 /* HEADER */ 651 652 /* HB0 = Packet Type = 0x83 (Source Product 653 * Descriptor InfoFrame) 654 */ 655 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD; 656 657 /* HB1 = Version = 0x02 */ 658 infopacket->hb1 = 0x02; 659 660 /* HB2 = [Bits 7:5 = 0] [Bits 4:0 = Length = 0x09] */ 661 infopacket->hb2 = 0x09; 662 663 *payload_size = 0x0A; 664 665 } else if (dc_is_dp_signal(signal)) { 666 667 /* HEADER */ 668 669 /* HB0 = Secondary-data Packet ID = 0 - Only non-zero 670 * when used to associate audio related info packets 671 */ 672 infopacket->hb0 = 0x00; 673 674 /* HB1 = Packet Type = 0x83 (Source Product 675 * Descriptor InfoFrame) 676 */ 677 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD; 678 679 /* HB2 = [Bits 7:0 = Least significant eight bits - 680 * For INFOFRAME, the value must be 1Bh] 681 */ 682 infopacket->hb2 = 0x1B; 683 684 /* HB3 = [Bits 7:2 = INFOFRAME SDP Version Number = 0x2] 685 * [Bits 1:0 = Most significant two bits = 0x00] 686 */ 687 infopacket->hb3 = 0x08; 688 689 *payload_size = 0x1B; 690 } 691 } 692 693 static void build_vrr_vtem_infopacket_data(const struct dc_stream_state *stream, 694 const struct mod_vrr_params *vrr, 695 struct dc_info_packet *infopacket) 696 { 697 unsigned int fieldRateInHz; 698 699 if (vrr->state == VRR_STATE_ACTIVE_VARIABLE || 700 vrr->state == VRR_STATE_ACTIVE_FIXED) { 701 setFieldWithMask(&infopacket->sb[VRR_VTEM_MD0], MASK__VRR_VTEM_MD0__VRR_EN, 1); 702 } else { 703 setFieldWithMask(&infopacket->sb[VRR_VTEM_MD0], MASK__VRR_VTEM_MD0__VRR_EN, 0); 704 } 705 706 if (!stream->timing.vic) { 707 setFieldWithMask(&infopacket->sb[VRR_VTEM_MD1], MASK__VRR_VTEM_MD1__BASE_VFRONT, 708 stream->timing.v_front_porch); 709 710 711 /* TODO: In dal2, we check mode flags for a reduced blanking timing. 712 * Need a way to relay that information to this function. 713 * if("ReducedBlanking") 714 * { 715 * setFieldWithMask(&infopacket->sb[VRR_VTEM_MD2], MASK__VRR_VTEM_MD2__RB, 1; 716 * } 717 */ 718 719 //TODO: DAL2 does FixPoint and rounding. Here we might need to account for that 720 fieldRateInHz = (stream->timing.pix_clk_100hz * 100)/ 721 (stream->timing.h_total * stream->timing.v_total); 722 723 setFieldWithMask(&infopacket->sb[VRR_VTEM_MD2], MASK__VRR_VTEM_MD2__BASE_REFRESH_RATE_98, 724 fieldRateInHz >> 8); 725 setFieldWithMask(&infopacket->sb[VRR_VTEM_MD3], MASK__VRR_VTEM_MD3__BASE_REFRESH_RATE_07, 726 fieldRateInHz); 727 728 } 729 infopacket->valid = true; 730 } 731 732 static void build_vrr_infopacket_data(const struct mod_vrr_params *vrr, 733 struct dc_info_packet *infopacket) 734 { 735 /* PB1 = 0x1A (24bit AMD IEEE OUI (0x00001A) - Byte 0) */ 736 infopacket->sb[1] = 0x1A; 737 738 /* PB2 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 1) */ 739 infopacket->sb[2] = 0x00; 740 741 /* PB3 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 2) */ 742 infopacket->sb[3] = 0x00; 743 744 /* PB4 = Reserved */ 745 746 /* PB5 = Reserved */ 747 748 /* PB6 = [Bits 7:3 = Reserved] */ 749 750 /* PB6 = [Bit 0 = FreeSync Supported] */ 751 if (vrr->state != VRR_STATE_UNSUPPORTED) 752 infopacket->sb[6] |= 0x01; 753 754 /* PB6 = [Bit 1 = FreeSync Enabled] */ 755 if (vrr->state != VRR_STATE_DISABLED && 756 vrr->state != VRR_STATE_UNSUPPORTED) 757 infopacket->sb[6] |= 0x02; 758 759 /* PB6 = [Bit 2 = FreeSync Active] */ 760 if (vrr->state == VRR_STATE_ACTIVE_VARIABLE || 761 vrr->state == VRR_STATE_ACTIVE_FIXED) 762 infopacket->sb[6] |= 0x04; 763 764 /* PB7 = FreeSync Minimum refresh rate (Hz) */ 765 infopacket->sb[7] = (unsigned char)(vrr->min_refresh_in_uhz / 1000000); 766 767 /* PB8 = FreeSync Maximum refresh rate (Hz) 768 * Note: We should never go above the field rate of the mode timing set. 769 */ 770 infopacket->sb[8] = (unsigned char)(vrr->max_refresh_in_uhz / 1000000); 771 772 773 //FreeSync HDR 774 infopacket->sb[9] = 0; 775 infopacket->sb[10] = 0; 776 } 777 778 static void build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf, 779 struct dc_info_packet *infopacket) 780 { 781 if (app_tf != TRANSFER_FUNC_UNKNOWN) { 782 infopacket->valid = true; 783 784 infopacket->sb[6] |= 0x08; // PB6 = [Bit 3 = Native Color Active] 785 786 if (app_tf == TRANSFER_FUNC_GAMMA_22) { 787 infopacket->sb[9] |= 0x04; // PB6 = [Bit 2 = Gamma 2.2 EOTF Active] 788 } 789 } 790 } 791 792 static void build_vrr_infopacket_checksum(unsigned int *payload_size, 793 struct dc_info_packet *infopacket) 794 { 795 /* Calculate checksum */ 796 unsigned int idx = 0; 797 unsigned char checksum = 0; 798 799 checksum += infopacket->hb0; 800 checksum += infopacket->hb1; 801 checksum += infopacket->hb2; 802 checksum += infopacket->hb3; 803 804 for (idx = 1; idx <= *payload_size; idx++) 805 checksum += infopacket->sb[idx]; 806 807 /* PB0 = Checksum (one byte complement) */ 808 infopacket->sb[0] = (unsigned char)(0x100 - checksum); 809 810 infopacket->valid = true; 811 } 812 813 static void build_vrr_infopacket_v1(enum signal_type signal, 814 const struct mod_vrr_params *vrr, 815 struct dc_info_packet *infopacket) 816 { 817 /* SPD info packet for FreeSync */ 818 unsigned int payload_size = 0; 819 820 build_vrr_infopacket_header_v1(signal, infopacket, &payload_size); 821 build_vrr_infopacket_data(vrr, infopacket); 822 build_vrr_infopacket_checksum(&payload_size, infopacket); 823 824 infopacket->valid = true; 825 } 826 827 static void build_vrr_infopacket_v2(enum signal_type signal, 828 const struct mod_vrr_params *vrr, 829 enum color_transfer_func app_tf, 830 struct dc_info_packet *infopacket) 831 { 832 unsigned int payload_size = 0; 833 834 build_vrr_infopacket_header_v2(signal, infopacket, &payload_size); 835 build_vrr_infopacket_data(vrr, infopacket); 836 837 build_vrr_infopacket_fs2_data(app_tf, infopacket); 838 839 build_vrr_infopacket_checksum(&payload_size, infopacket); 840 841 infopacket->valid = true; 842 } 843 844 static void build_vrr_infopacket_vtem(const struct dc_stream_state *stream, 845 const struct mod_vrr_params *vrr, 846 struct dc_info_packet *infopacket) 847 { 848 //VTEM info packet for HdmiVrr 849 850 memset(infopacket, 0, sizeof(struct dc_info_packet)); 851 852 //VTEM Packet is structured differently 853 build_vrr_infopacket_header_vtem(stream->signal, infopacket); 854 build_vrr_vtem_infopacket_data(stream, vrr, infopacket); 855 856 infopacket->valid = true; 857 } 858 859 void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync, 860 const struct dc_stream_state *stream, 861 const struct mod_vrr_params *vrr, 862 enum vrr_packet_type packet_type, 863 enum color_transfer_func app_tf, 864 struct dc_info_packet *infopacket) 865 { 866 /* SPD info packet for FreeSync 867 * VTEM info packet for HdmiVRR 868 * Check if Freesync is supported. Return if false. If true, 869 * set the corresponding bit in the info packet 870 */ 871 if (!vrr->supported || (!vrr->send_info_frame && packet_type != PACKET_TYPE_VTEM)) 872 return; 873 874 switch (packet_type) { 875 case PACKET_TYPE_FS2: 876 build_vrr_infopacket_v2(stream->signal, vrr, app_tf, infopacket); 877 break; 878 case PACKET_TYPE_VTEM: 879 build_vrr_infopacket_vtem(stream, vrr, infopacket); 880 break; 881 case PACKET_TYPE_VRR: 882 case PACKET_TYPE_FS1: 883 default: 884 build_vrr_infopacket_v1(stream->signal, vrr, infopacket); 885 } 886 } 887 888 void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync, 889 const struct dc_stream_state *stream, 890 struct mod_freesync_config *in_config, 891 struct mod_vrr_params *in_out_vrr) 892 { 893 struct core_freesync *core_freesync = NULL; 894 unsigned long long nominal_field_rate_in_uhz = 0; 895 unsigned int refresh_range = 0; 896 unsigned long long min_refresh_in_uhz = 0; 897 unsigned long long max_refresh_in_uhz = 0; 898 899 if (mod_freesync == NULL) 900 return; 901 902 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 903 904 /* Calculate nominal field rate for stream */ 905 nominal_field_rate_in_uhz = 906 mod_freesync_calc_nominal_field_rate(stream); 907 908 min_refresh_in_uhz = in_config->min_refresh_in_uhz; 909 max_refresh_in_uhz = in_config->max_refresh_in_uhz; 910 911 // Don't allow min > max 912 if (min_refresh_in_uhz > max_refresh_in_uhz) 913 min_refresh_in_uhz = max_refresh_in_uhz; 914 915 // Full range may be larger than current video timing, so cap at nominal 916 if (max_refresh_in_uhz > nominal_field_rate_in_uhz) 917 max_refresh_in_uhz = nominal_field_rate_in_uhz; 918 919 // Full range may be larger than current video timing, so cap at nominal 920 if (min_refresh_in_uhz > nominal_field_rate_in_uhz) 921 min_refresh_in_uhz = nominal_field_rate_in_uhz; 922 923 if (!vrr_settings_require_update(core_freesync, 924 in_config, (unsigned int)min_refresh_in_uhz, (unsigned int)max_refresh_in_uhz, 925 in_out_vrr)) 926 return; 927 928 in_out_vrr->state = in_config->state; 929 in_out_vrr->send_info_frame = in_config->vsif_supported; 930 931 if (in_config->state == VRR_STATE_UNSUPPORTED) { 932 in_out_vrr->state = VRR_STATE_UNSUPPORTED; 933 in_out_vrr->supported = false; 934 in_out_vrr->adjust.v_total_min = stream->timing.v_total; 935 in_out_vrr->adjust.v_total_max = stream->timing.v_total; 936 937 return; 938 939 } else { 940 in_out_vrr->min_refresh_in_uhz = (unsigned int)min_refresh_in_uhz; 941 in_out_vrr->max_duration_in_us = 942 calc_duration_in_us_from_refresh_in_uhz( 943 (unsigned int)min_refresh_in_uhz); 944 945 in_out_vrr->max_refresh_in_uhz = (unsigned int)max_refresh_in_uhz; 946 in_out_vrr->min_duration_in_us = 947 calc_duration_in_us_from_refresh_in_uhz( 948 (unsigned int)max_refresh_in_uhz); 949 950 refresh_range = in_out_vrr->max_refresh_in_uhz - 951 in_out_vrr->min_refresh_in_uhz; 952 953 in_out_vrr->supported = true; 954 } 955 956 in_out_vrr->fixed.ramping_active = in_config->ramping; 957 958 in_out_vrr->btr.btr_enabled = in_config->btr; 959 960 if (in_out_vrr->max_refresh_in_uhz < 961 2 * in_out_vrr->min_refresh_in_uhz) 962 in_out_vrr->btr.btr_enabled = false; 963 964 in_out_vrr->btr.btr_active = false; 965 in_out_vrr->btr.inserted_duration_in_us = 0; 966 in_out_vrr->btr.frames_to_insert = 0; 967 in_out_vrr->btr.frame_counter = 0; 968 in_out_vrr->btr.mid_point_in_us = 969 (in_out_vrr->min_duration_in_us + 970 in_out_vrr->max_duration_in_us) / 2; 971 972 if (in_out_vrr->state == VRR_STATE_UNSUPPORTED) { 973 in_out_vrr->adjust.v_total_min = stream->timing.v_total; 974 in_out_vrr->adjust.v_total_max = stream->timing.v_total; 975 } else if (in_out_vrr->state == VRR_STATE_DISABLED) { 976 in_out_vrr->adjust.v_total_min = stream->timing.v_total; 977 in_out_vrr->adjust.v_total_max = stream->timing.v_total; 978 } else if (in_out_vrr->state == VRR_STATE_INACTIVE) { 979 in_out_vrr->adjust.v_total_min = stream->timing.v_total; 980 in_out_vrr->adjust.v_total_max = stream->timing.v_total; 981 } else if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE && 982 refresh_range >= MIN_REFRESH_RANGE_IN_US) { 983 in_out_vrr->adjust.v_total_min = 984 calc_v_total_from_refresh(stream, 985 in_out_vrr->max_refresh_in_uhz); 986 in_out_vrr->adjust.v_total_max = 987 calc_v_total_from_refresh(stream, 988 in_out_vrr->min_refresh_in_uhz); 989 } else if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED) { 990 in_out_vrr->fixed.target_refresh_in_uhz = 991 in_out_vrr->min_refresh_in_uhz; 992 if (in_out_vrr->fixed.ramping_active && 993 in_out_vrr->fixed.fixed_active) { 994 /* Do not update vtotals if ramping is already active 995 * in order to continue ramp from current refresh. 996 */ 997 in_out_vrr->fixed.fixed_active = true; 998 } else { 999 in_out_vrr->fixed.fixed_active = true; 1000 in_out_vrr->adjust.v_total_min = 1001 calc_v_total_from_refresh(stream, 1002 in_out_vrr->fixed.target_refresh_in_uhz); 1003 in_out_vrr->adjust.v_total_max = 1004 in_out_vrr->adjust.v_total_min; 1005 } 1006 } else { 1007 in_out_vrr->state = VRR_STATE_INACTIVE; 1008 in_out_vrr->adjust.v_total_min = stream->timing.v_total; 1009 in_out_vrr->adjust.v_total_max = stream->timing.v_total; 1010 } 1011 } 1012 1013 void mod_freesync_handle_preflip(struct mod_freesync *mod_freesync, 1014 const struct dc_plane_state *plane, 1015 const struct dc_stream_state *stream, 1016 unsigned int curr_time_stamp_in_us, 1017 struct mod_vrr_params *in_out_vrr) 1018 { 1019 struct core_freesync *core_freesync = NULL; 1020 unsigned int last_render_time_in_us = 0; 1021 unsigned int average_render_time_in_us = 0; 1022 1023 if (mod_freesync == NULL) 1024 return; 1025 1026 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1027 1028 if (in_out_vrr->supported && 1029 in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE) { 1030 unsigned int i = 0; 1031 unsigned int oldest_index = plane->time.index + 1; 1032 1033 if (oldest_index >= DC_PLANE_UPDATE_TIMES_MAX) 1034 oldest_index = 0; 1035 1036 last_render_time_in_us = curr_time_stamp_in_us - 1037 plane->time.prev_update_time_in_us; 1038 1039 // Sum off all entries except oldest one 1040 for (i = 0; i < DC_PLANE_UPDATE_TIMES_MAX; i++) { 1041 average_render_time_in_us += 1042 plane->time.time_elapsed_in_us[i]; 1043 } 1044 average_render_time_in_us -= 1045 plane->time.time_elapsed_in_us[oldest_index]; 1046 1047 // Add render time for current flip 1048 average_render_time_in_us += last_render_time_in_us; 1049 average_render_time_in_us /= DC_PLANE_UPDATE_TIMES_MAX; 1050 1051 if (in_out_vrr->btr.btr_enabled) { 1052 apply_below_the_range(core_freesync, 1053 stream, 1054 last_render_time_in_us, 1055 in_out_vrr); 1056 } else { 1057 apply_fixed_refresh(core_freesync, 1058 stream, 1059 last_render_time_in_us, 1060 in_out_vrr); 1061 } 1062 1063 } 1064 } 1065 1066 void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync, 1067 const struct dc_stream_state *stream, 1068 struct mod_vrr_params *in_out_vrr) 1069 { 1070 struct core_freesync *core_freesync = NULL; 1071 1072 if ((mod_freesync == NULL) || (stream == NULL) || (in_out_vrr == NULL)) 1073 return; 1074 1075 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1076 1077 if (in_out_vrr->supported == false) 1078 return; 1079 1080 /* Below the Range Logic */ 1081 1082 /* Only execute if in fullscreen mode */ 1083 if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE && 1084 in_out_vrr->btr.btr_active) { 1085 /* TODO: pass in flag for Pre-DCE12 ASIC 1086 * in order for frame variable duration to take affect, 1087 * it needs to be done one VSYNC early, which is at 1088 * frameCounter == 1. 1089 * For DCE12 and newer updates to V_TOTAL_MIN/MAX 1090 * will take affect on current frame 1091 */ 1092 if (in_out_vrr->btr.frames_to_insert == 1093 in_out_vrr->btr.frame_counter) { 1094 in_out_vrr->adjust.v_total_min = 1095 calc_v_total_from_duration(stream, 1096 in_out_vrr, 1097 in_out_vrr->btr.inserted_duration_in_us); 1098 in_out_vrr->adjust.v_total_max = 1099 in_out_vrr->adjust.v_total_min; 1100 } 1101 1102 if (in_out_vrr->btr.frame_counter > 0) 1103 in_out_vrr->btr.frame_counter--; 1104 1105 /* Restore FreeSync */ 1106 if (in_out_vrr->btr.frame_counter == 0) { 1107 in_out_vrr->adjust.v_total_min = 1108 calc_v_total_from_refresh(stream, 1109 in_out_vrr->max_refresh_in_uhz); 1110 in_out_vrr->adjust.v_total_max = 1111 calc_v_total_from_refresh(stream, 1112 in_out_vrr->min_refresh_in_uhz); 1113 } 1114 } 1115 1116 /* If in fullscreen freesync mode or in video, do not program 1117 * static screen ramp values 1118 */ 1119 if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE) 1120 in_out_vrr->fixed.ramping_active = false; 1121 1122 /* Gradual Static Screen Ramping Logic */ 1123 /* Execute if ramp is active and user enabled freesync static screen*/ 1124 if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED && 1125 in_out_vrr->fixed.ramping_active) { 1126 update_v_total_for_static_ramp( 1127 core_freesync, stream, in_out_vrr); 1128 } 1129 } 1130 1131 void mod_freesync_get_settings(struct mod_freesync *mod_freesync, 1132 const struct mod_vrr_params *vrr, 1133 unsigned int *v_total_min, unsigned int *v_total_max, 1134 unsigned int *event_triggers, 1135 unsigned int *window_min, unsigned int *window_max, 1136 unsigned int *lfc_mid_point_in_us, 1137 unsigned int *inserted_frames, 1138 unsigned int *inserted_duration_in_us) 1139 { 1140 struct core_freesync *core_freesync = NULL; 1141 1142 if (mod_freesync == NULL) 1143 return; 1144 1145 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1146 1147 if (vrr->supported) { 1148 *v_total_min = vrr->adjust.v_total_min; 1149 *v_total_max = vrr->adjust.v_total_max; 1150 *event_triggers = 0; 1151 *lfc_mid_point_in_us = vrr->btr.mid_point_in_us; 1152 *inserted_frames = vrr->btr.frames_to_insert; 1153 *inserted_duration_in_us = vrr->btr.inserted_duration_in_us; 1154 } 1155 } 1156 1157 unsigned long long mod_freesync_calc_nominal_field_rate( 1158 const struct dc_stream_state *stream) 1159 { 1160 unsigned long long nominal_field_rate_in_uhz = 0; 1161 1162 /* Calculate nominal field rate for stream */ 1163 nominal_field_rate_in_uhz = stream->timing.pix_clk_100hz / 10; 1164 nominal_field_rate_in_uhz *= 1000ULL * 1000ULL * 1000ULL; 1165 nominal_field_rate_in_uhz = div_u64(nominal_field_rate_in_uhz, 1166 stream->timing.h_total); 1167 nominal_field_rate_in_uhz = div_u64(nominal_field_rate_in_uhz, 1168 stream->timing.v_total); 1169 1170 return nominal_field_rate_in_uhz; 1171 } 1172 1173 bool mod_freesync_is_valid_range(struct mod_freesync *mod_freesync, 1174 const struct dc_stream_state *stream, 1175 uint32_t min_refresh_cap_in_uhz, 1176 uint32_t max_refresh_cap_in_uhz, 1177 uint32_t min_refresh_request_in_uhz, 1178 uint32_t max_refresh_request_in_uhz) 1179 { 1180 /* Calculate nominal field rate for stream */ 1181 unsigned long long nominal_field_rate_in_uhz = 1182 mod_freesync_calc_nominal_field_rate(stream); 1183 1184 /* Typically nominal refresh calculated can have some fractional part. 1185 * Allow for some rounding error of actual video timing by taking floor 1186 * of caps and request. Round the nominal refresh rate. 1187 * 1188 * Dividing will convert everything to units in Hz although input 1189 * variable name is in uHz! 1190 * 1191 * Also note, this takes care of rounding error on the nominal refresh 1192 * so by rounding error we only expect it to be off by a small amount, 1193 * such as < 0.1 Hz. i.e. 143.9xxx or 144.1xxx. 1194 * 1195 * Example 1. Caps Min = 40 Hz, Max = 144 Hz 1196 * Request Min = 40 Hz, Max = 144 Hz 1197 * Nominal = 143.5x Hz rounded to 144 Hz 1198 * This function should allow this as valid request 1199 * 1200 * Example 2. Caps Min = 40 Hz, Max = 144 Hz 1201 * Request Min = 40 Hz, Max = 144 Hz 1202 * Nominal = 144.4x Hz rounded to 144 Hz 1203 * This function should allow this as valid request 1204 * 1205 * Example 3. Caps Min = 40 Hz, Max = 144 Hz 1206 * Request Min = 40 Hz, Max = 144 Hz 1207 * Nominal = 120.xx Hz rounded to 120 Hz 1208 * This function should return NOT valid since the requested 1209 * max is greater than current timing's nominal 1210 * 1211 * Example 4. Caps Min = 40 Hz, Max = 120 Hz 1212 * Request Min = 40 Hz, Max = 120 Hz 1213 * Nominal = 144.xx Hz rounded to 144 Hz 1214 * This function should return NOT valid since the nominal 1215 * is greater than the capability's max refresh 1216 */ 1217 nominal_field_rate_in_uhz = 1218 div_u64(nominal_field_rate_in_uhz + 500000, 1000000); 1219 min_refresh_cap_in_uhz /= 1000000; 1220 max_refresh_cap_in_uhz /= 1000000; 1221 min_refresh_request_in_uhz /= 1000000; 1222 max_refresh_request_in_uhz /= 1000000; 1223 1224 // Check nominal is within range 1225 if (nominal_field_rate_in_uhz > max_refresh_cap_in_uhz || 1226 nominal_field_rate_in_uhz < min_refresh_cap_in_uhz) 1227 return false; 1228 1229 // If nominal is less than max, limit the max allowed refresh rate 1230 if (nominal_field_rate_in_uhz < max_refresh_cap_in_uhz) 1231 max_refresh_cap_in_uhz = nominal_field_rate_in_uhz; 1232 1233 // Don't allow min > max 1234 if (min_refresh_request_in_uhz > max_refresh_request_in_uhz) 1235 return false; 1236 1237 // Check min is within range 1238 if (min_refresh_request_in_uhz > max_refresh_cap_in_uhz || 1239 min_refresh_request_in_uhz < min_refresh_cap_in_uhz) 1240 return false; 1241 1242 // Check max is within range 1243 if (max_refresh_request_in_uhz > max_refresh_cap_in_uhz || 1244 max_refresh_request_in_uhz < min_refresh_cap_in_uhz) 1245 return false; 1246 1247 // For variable range, check for at least 10 Hz range 1248 if ((max_refresh_request_in_uhz != min_refresh_request_in_uhz) && 1249 (max_refresh_request_in_uhz - min_refresh_request_in_uhz < 10)) 1250 return false; 1251 1252 return true; 1253 } 1254 1255