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