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 (frames_to_insert > 0) 439 inserted_frame_duration_in_us = last_render_time_in_us / 440 frames_to_insert; 441 442 if (inserted_frame_duration_in_us < in_out_vrr->min_duration_in_us) 443 inserted_frame_duration_in_us = in_out_vrr->min_duration_in_us; 444 445 /* Cache the calculated variables */ 446 in_out_vrr->btr.inserted_duration_in_us = 447 inserted_frame_duration_in_us; 448 in_out_vrr->btr.frames_to_insert = frames_to_insert; 449 in_out_vrr->btr.frame_counter = frames_to_insert; 450 } 451 } 452 453 static void apply_fixed_refresh(struct core_freesync *core_freesync, 454 const struct dc_stream_state *stream, 455 unsigned int last_render_time_in_us, 456 struct mod_vrr_params *in_out_vrr) 457 { 458 bool update = false; 459 unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us; 460 461 //Compute the exit refresh rate and exit frame duration 462 unsigned int exit_refresh_rate_in_milli_hz = ((1000000000/max_render_time_in_us) 463 + (1000*FIXED_REFRESH_EXIT_MARGIN_IN_HZ)); 464 unsigned int exit_frame_duration_in_us = 1000000000/exit_refresh_rate_in_milli_hz; 465 466 if (last_render_time_in_us < exit_frame_duration_in_us) { 467 /* Exit Fixed Refresh mode */ 468 if (in_out_vrr->fixed.fixed_active) { 469 in_out_vrr->fixed.frame_counter++; 470 471 if (in_out_vrr->fixed.frame_counter > 472 FIXED_REFRESH_EXIT_FRAME_COUNT) { 473 in_out_vrr->fixed.frame_counter = 0; 474 in_out_vrr->fixed.fixed_active = false; 475 in_out_vrr->fixed.target_refresh_in_uhz = 0; 476 update = true; 477 } 478 } 479 } else if (last_render_time_in_us > max_render_time_in_us) { 480 /* Enter Fixed Refresh mode */ 481 if (!in_out_vrr->fixed.fixed_active) { 482 in_out_vrr->fixed.frame_counter++; 483 484 if (in_out_vrr->fixed.frame_counter > 485 FIXED_REFRESH_ENTER_FRAME_COUNT) { 486 in_out_vrr->fixed.frame_counter = 0; 487 in_out_vrr->fixed.fixed_active = true; 488 in_out_vrr->fixed.target_refresh_in_uhz = 489 in_out_vrr->max_refresh_in_uhz; 490 update = true; 491 } 492 } 493 } 494 495 if (update) { 496 if (in_out_vrr->fixed.fixed_active) { 497 in_out_vrr->adjust.v_total_min = 498 calc_v_total_from_refresh( 499 stream, in_out_vrr->max_refresh_in_uhz); 500 in_out_vrr->adjust.v_total_max = 501 in_out_vrr->adjust.v_total_min; 502 } else { 503 in_out_vrr->adjust.v_total_min = 504 calc_v_total_from_refresh(stream, 505 in_out_vrr->max_refresh_in_uhz); 506 in_out_vrr->adjust.v_total_max = 507 calc_v_total_from_refresh(stream, 508 in_out_vrr->min_refresh_in_uhz); 509 } 510 } 511 } 512 513 static bool vrr_settings_require_update(struct core_freesync *core_freesync, 514 struct mod_freesync_config *in_config, 515 unsigned int min_refresh_in_uhz, 516 unsigned int max_refresh_in_uhz, 517 struct mod_vrr_params *in_vrr) 518 { 519 if (in_vrr->state != in_config->state) { 520 return true; 521 } else if (in_vrr->state == VRR_STATE_ACTIVE_FIXED && 522 in_vrr->fixed.target_refresh_in_uhz != 523 in_config->min_refresh_in_uhz) { 524 return true; 525 } else if (in_vrr->min_refresh_in_uhz != min_refresh_in_uhz) { 526 return true; 527 } else if (in_vrr->max_refresh_in_uhz != max_refresh_in_uhz) { 528 return true; 529 } 530 531 return false; 532 } 533 534 bool mod_freesync_get_vmin_vmax(struct mod_freesync *mod_freesync, 535 const struct dc_stream_state *stream, 536 unsigned int *vmin, 537 unsigned int *vmax) 538 { 539 *vmin = stream->adjust.v_total_min; 540 *vmax = stream->adjust.v_total_max; 541 542 return true; 543 } 544 545 bool mod_freesync_get_v_position(struct mod_freesync *mod_freesync, 546 struct dc_stream_state *stream, 547 unsigned int *nom_v_pos, 548 unsigned int *v_pos) 549 { 550 struct core_freesync *core_freesync = NULL; 551 struct crtc_position position; 552 553 if (mod_freesync == NULL) 554 return false; 555 556 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 557 558 if (dc_stream_get_crtc_position(core_freesync->dc, &stream, 1, 559 &position.vertical_count, 560 &position.nominal_vcount)) { 561 562 *nom_v_pos = position.nominal_vcount; 563 *v_pos = position.vertical_count; 564 565 return true; 566 } 567 568 return false; 569 } 570 571 static void build_vrr_infopacket_header_vtem(enum signal_type signal, 572 struct dc_info_packet *infopacket) 573 { 574 // HEADER 575 576 // HB0, HB1, HB2 indicates PacketType VTEMPacket 577 infopacket->hb0 = 0x7F; 578 infopacket->hb1 = 0xC0; 579 infopacket->hb2 = 0x00; //sequence_index 580 581 setFieldWithMask(&infopacket->sb[VRR_VTEM_PB0], MASK__VRR_VTEM_PB0__VFR, 1); 582 setFieldWithMask(&infopacket->sb[VRR_VTEM_PB2], MASK__VRR_VTEM_PB2__ORGANIZATION_ID, 1); 583 setFieldWithMask(&infopacket->sb[VRR_VTEM_PB3], MASK__VRR_VTEM_PB3__DATA_SET_TAG_MSB, 0); 584 setFieldWithMask(&infopacket->sb[VRR_VTEM_PB4], MASK__VRR_VTEM_PB4__DATA_SET_TAG_LSB, 1); 585 setFieldWithMask(&infopacket->sb[VRR_VTEM_PB5], MASK__VRR_VTEM_PB5__DATA_SET_LENGTH_MSB, 0); 586 setFieldWithMask(&infopacket->sb[VRR_VTEM_PB6], MASK__VRR_VTEM_PB6__DATA_SET_LENGTH_LSB, 4); 587 } 588 589 static void build_vrr_infopacket_header_v1(enum signal_type signal, 590 struct dc_info_packet *infopacket, 591 unsigned int *payload_size) 592 { 593 if (dc_is_hdmi_signal(signal)) { 594 595 /* HEADER */ 596 597 /* HB0 = Packet Type = 0x83 (Source Product 598 * Descriptor InfoFrame) 599 */ 600 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD; 601 602 /* HB1 = Version = 0x01 */ 603 infopacket->hb1 = 0x01; 604 605 /* HB2 = [Bits 7:5 = 0] [Bits 4:0 = Length = 0x08] */ 606 infopacket->hb2 = 0x08; 607 608 *payload_size = 0x08; 609 610 } else if (dc_is_dp_signal(signal)) { 611 612 /* HEADER */ 613 614 /* HB0 = Secondary-data Packet ID = 0 - Only non-zero 615 * when used to associate audio related info packets 616 */ 617 infopacket->hb0 = 0x00; 618 619 /* HB1 = Packet Type = 0x83 (Source Product 620 * Descriptor InfoFrame) 621 */ 622 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD; 623 624 /* HB2 = [Bits 7:0 = Least significant eight bits - 625 * For INFOFRAME, the value must be 1Bh] 626 */ 627 infopacket->hb2 = 0x1B; 628 629 /* HB3 = [Bits 7:2 = INFOFRAME SDP Version Number = 0x1] 630 * [Bits 1:0 = Most significant two bits = 0x00] 631 */ 632 infopacket->hb3 = 0x04; 633 634 *payload_size = 0x1B; 635 } 636 } 637 638 static void build_vrr_infopacket_header_v2(enum signal_type signal, 639 struct dc_info_packet *infopacket, 640 unsigned int *payload_size) 641 { 642 if (dc_is_hdmi_signal(signal)) { 643 644 /* HEADER */ 645 646 /* HB0 = Packet Type = 0x83 (Source Product 647 * Descriptor InfoFrame) 648 */ 649 infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD; 650 651 /* HB1 = Version = 0x02 */ 652 infopacket->hb1 = 0x02; 653 654 /* HB2 = [Bits 7:5 = 0] [Bits 4:0 = Length = 0x09] */ 655 infopacket->hb2 = 0x09; 656 657 *payload_size = 0x0A; 658 659 } else if (dc_is_dp_signal(signal)) { 660 661 /* HEADER */ 662 663 /* HB0 = Secondary-data Packet ID = 0 - Only non-zero 664 * when used to associate audio related info packets 665 */ 666 infopacket->hb0 = 0x00; 667 668 /* HB1 = Packet Type = 0x83 (Source Product 669 * Descriptor InfoFrame) 670 */ 671 infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD; 672 673 /* HB2 = [Bits 7:0 = Least significant eight bits - 674 * For INFOFRAME, the value must be 1Bh] 675 */ 676 infopacket->hb2 = 0x1B; 677 678 /* HB3 = [Bits 7:2 = INFOFRAME SDP Version Number = 0x2] 679 * [Bits 1:0 = Most significant two bits = 0x00] 680 */ 681 infopacket->hb3 = 0x08; 682 683 *payload_size = 0x1B; 684 } 685 } 686 687 static void build_vrr_vtem_infopacket_data(const struct dc_stream_state *stream, 688 const struct mod_vrr_params *vrr, 689 struct dc_info_packet *infopacket) 690 { 691 unsigned int fieldRateInHz; 692 693 if (vrr->state == VRR_STATE_ACTIVE_VARIABLE || 694 vrr->state == VRR_STATE_ACTIVE_FIXED) { 695 setFieldWithMask(&infopacket->sb[VRR_VTEM_MD0], MASK__VRR_VTEM_MD0__VRR_EN, 1); 696 } else { 697 setFieldWithMask(&infopacket->sb[VRR_VTEM_MD0], MASK__VRR_VTEM_MD0__VRR_EN, 0); 698 } 699 700 if (!stream->timing.vic) { 701 setFieldWithMask(&infopacket->sb[VRR_VTEM_MD1], MASK__VRR_VTEM_MD1__BASE_VFRONT, 702 stream->timing.v_front_porch); 703 704 705 /* TODO: In dal2, we check mode flags for a reduced blanking timing. 706 * Need a way to relay that information to this function. 707 * if("ReducedBlanking") 708 * { 709 * setFieldWithMask(&infopacket->sb[VRR_VTEM_MD2], MASK__VRR_VTEM_MD2__RB, 1; 710 * } 711 */ 712 713 //TODO: DAL2 does FixPoint and rounding. Here we might need to account for that 714 fieldRateInHz = (stream->timing.pix_clk_100hz * 100)/ 715 (stream->timing.h_total * stream->timing.v_total); 716 717 setFieldWithMask(&infopacket->sb[VRR_VTEM_MD2], MASK__VRR_VTEM_MD2__BASE_REFRESH_RATE_98, 718 fieldRateInHz >> 8); 719 setFieldWithMask(&infopacket->sb[VRR_VTEM_MD3], MASK__VRR_VTEM_MD3__BASE_REFRESH_RATE_07, 720 fieldRateInHz); 721 722 } 723 infopacket->valid = true; 724 } 725 726 static void build_vrr_infopacket_data(const struct mod_vrr_params *vrr, 727 struct dc_info_packet *infopacket) 728 { 729 /* PB1 = 0x1A (24bit AMD IEEE OUI (0x00001A) - Byte 0) */ 730 infopacket->sb[1] = 0x1A; 731 732 /* PB2 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 1) */ 733 infopacket->sb[2] = 0x00; 734 735 /* PB3 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 2) */ 736 infopacket->sb[3] = 0x00; 737 738 /* PB4 = Reserved */ 739 740 /* PB5 = Reserved */ 741 742 /* PB6 = [Bits 7:3 = Reserved] */ 743 744 /* PB6 = [Bit 0 = FreeSync Supported] */ 745 if (vrr->state != VRR_STATE_UNSUPPORTED) 746 infopacket->sb[6] |= 0x01; 747 748 /* PB6 = [Bit 1 = FreeSync Enabled] */ 749 if (vrr->state != VRR_STATE_DISABLED && 750 vrr->state != VRR_STATE_UNSUPPORTED) 751 infopacket->sb[6] |= 0x02; 752 753 /* PB6 = [Bit 2 = FreeSync Active] */ 754 if (vrr->state == VRR_STATE_ACTIVE_VARIABLE || 755 vrr->state == VRR_STATE_ACTIVE_FIXED) 756 infopacket->sb[6] |= 0x04; 757 758 /* PB7 = FreeSync Minimum refresh rate (Hz) */ 759 infopacket->sb[7] = (unsigned char)(vrr->min_refresh_in_uhz / 1000000); 760 761 /* PB8 = FreeSync Maximum refresh rate (Hz) 762 * Note: We should never go above the field rate of the mode timing set. 763 */ 764 infopacket->sb[8] = (unsigned char)(vrr->max_refresh_in_uhz / 1000000); 765 766 767 //FreeSync HDR 768 infopacket->sb[9] = 0; 769 infopacket->sb[10] = 0; 770 } 771 772 static void build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf, 773 struct dc_info_packet *infopacket) 774 { 775 if (app_tf != TRANSFER_FUNC_UNKNOWN) { 776 infopacket->valid = true; 777 778 infopacket->sb[6] |= 0x08; // PB6 = [Bit 3 = Native Color Active] 779 780 if (app_tf == TRANSFER_FUNC_GAMMA_22) { 781 infopacket->sb[9] |= 0x04; // PB6 = [Bit 2 = Gamma 2.2 EOTF Active] 782 } 783 } 784 } 785 786 static void build_vrr_infopacket_checksum(unsigned int *payload_size, 787 struct dc_info_packet *infopacket) 788 { 789 /* Calculate checksum */ 790 unsigned int idx = 0; 791 unsigned char checksum = 0; 792 793 checksum += infopacket->hb0; 794 checksum += infopacket->hb1; 795 checksum += infopacket->hb2; 796 checksum += infopacket->hb3; 797 798 for (idx = 1; idx <= *payload_size; idx++) 799 checksum += infopacket->sb[idx]; 800 801 /* PB0 = Checksum (one byte complement) */ 802 infopacket->sb[0] = (unsigned char)(0x100 - checksum); 803 804 infopacket->valid = true; 805 } 806 807 static void build_vrr_infopacket_v1(enum signal_type signal, 808 const struct mod_vrr_params *vrr, 809 struct dc_info_packet *infopacket) 810 { 811 /* SPD info packet for FreeSync */ 812 unsigned int payload_size = 0; 813 814 build_vrr_infopacket_header_v1(signal, infopacket, &payload_size); 815 build_vrr_infopacket_data(vrr, infopacket); 816 build_vrr_infopacket_checksum(&payload_size, infopacket); 817 818 infopacket->valid = true; 819 } 820 821 static void build_vrr_infopacket_v2(enum signal_type signal, 822 const struct mod_vrr_params *vrr, 823 enum color_transfer_func app_tf, 824 struct dc_info_packet *infopacket) 825 { 826 unsigned int payload_size = 0; 827 828 build_vrr_infopacket_header_v2(signal, infopacket, &payload_size); 829 build_vrr_infopacket_data(vrr, infopacket); 830 831 build_vrr_infopacket_fs2_data(app_tf, infopacket); 832 833 build_vrr_infopacket_checksum(&payload_size, infopacket); 834 835 infopacket->valid = true; 836 } 837 838 static void build_vrr_infopacket_vtem(const struct dc_stream_state *stream, 839 const struct mod_vrr_params *vrr, 840 struct dc_info_packet *infopacket) 841 { 842 //VTEM info packet for HdmiVrr 843 844 memset(infopacket, 0, sizeof(struct dc_info_packet)); 845 846 //VTEM Packet is structured differently 847 build_vrr_infopacket_header_vtem(stream->signal, infopacket); 848 build_vrr_vtem_infopacket_data(stream, vrr, infopacket); 849 850 infopacket->valid = true; 851 } 852 853 void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync, 854 const struct dc_stream_state *stream, 855 const struct mod_vrr_params *vrr, 856 enum vrr_packet_type packet_type, 857 enum color_transfer_func app_tf, 858 struct dc_info_packet *infopacket) 859 { 860 /* SPD info packet for FreeSync 861 * VTEM info packet for HdmiVRR 862 * Check if Freesync is supported. Return if false. If true, 863 * set the corresponding bit in the info packet 864 */ 865 if (!vrr->supported || (!vrr->send_info_frame && packet_type != PACKET_TYPE_VTEM)) 866 return; 867 868 switch (packet_type) { 869 case PACKET_TYPE_FS2: 870 build_vrr_infopacket_v2(stream->signal, vrr, app_tf, infopacket); 871 break; 872 case PACKET_TYPE_VTEM: 873 build_vrr_infopacket_vtem(stream, vrr, infopacket); 874 break; 875 case PACKET_TYPE_VRR: 876 case PACKET_TYPE_FS1: 877 default: 878 build_vrr_infopacket_v1(stream->signal, vrr, infopacket); 879 } 880 } 881 882 void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync, 883 const struct dc_stream_state *stream, 884 struct mod_freesync_config *in_config, 885 struct mod_vrr_params *in_out_vrr) 886 { 887 struct core_freesync *core_freesync = NULL; 888 unsigned long long nominal_field_rate_in_uhz = 0; 889 unsigned int refresh_range = 0; 890 unsigned int min_refresh_in_uhz = 0; 891 unsigned int max_refresh_in_uhz = 0; 892 893 if (mod_freesync == NULL) 894 return; 895 896 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 897 898 /* Calculate nominal field rate for stream */ 899 nominal_field_rate_in_uhz = 900 mod_freesync_calc_nominal_field_rate(stream); 901 902 min_refresh_in_uhz = in_config->min_refresh_in_uhz; 903 max_refresh_in_uhz = in_config->max_refresh_in_uhz; 904 905 // Don't allow min > max 906 if (min_refresh_in_uhz > max_refresh_in_uhz) 907 min_refresh_in_uhz = max_refresh_in_uhz; 908 909 // Full range may be larger than current video timing, so cap at nominal 910 if (max_refresh_in_uhz > nominal_field_rate_in_uhz) 911 max_refresh_in_uhz = nominal_field_rate_in_uhz; 912 913 // Full range may be larger than current video timing, so cap at nominal 914 if (min_refresh_in_uhz > nominal_field_rate_in_uhz) 915 min_refresh_in_uhz = nominal_field_rate_in_uhz; 916 917 if (!vrr_settings_require_update(core_freesync, 918 in_config, min_refresh_in_uhz, max_refresh_in_uhz, 919 in_out_vrr)) 920 return; 921 922 in_out_vrr->state = in_config->state; 923 in_out_vrr->send_info_frame = in_config->vsif_supported; 924 925 if (in_config->state == VRR_STATE_UNSUPPORTED) { 926 in_out_vrr->state = VRR_STATE_UNSUPPORTED; 927 in_out_vrr->supported = false; 928 in_out_vrr->adjust.v_total_min = stream->timing.v_total; 929 in_out_vrr->adjust.v_total_max = stream->timing.v_total; 930 931 return; 932 933 } else { 934 in_out_vrr->min_refresh_in_uhz = min_refresh_in_uhz; 935 in_out_vrr->max_duration_in_us = 936 calc_duration_in_us_from_refresh_in_uhz( 937 min_refresh_in_uhz); 938 939 in_out_vrr->max_refresh_in_uhz = max_refresh_in_uhz; 940 in_out_vrr->min_duration_in_us = 941 calc_duration_in_us_from_refresh_in_uhz( 942 max_refresh_in_uhz); 943 944 refresh_range = in_out_vrr->max_refresh_in_uhz - 945 in_out_vrr->min_refresh_in_uhz; 946 947 in_out_vrr->supported = true; 948 } 949 950 in_out_vrr->fixed.ramping_active = in_config->ramping; 951 952 in_out_vrr->btr.btr_enabled = in_config->btr; 953 if (in_out_vrr->max_refresh_in_uhz < 954 2 * in_out_vrr->min_refresh_in_uhz) 955 in_out_vrr->btr.btr_enabled = false; 956 in_out_vrr->btr.btr_active = false; 957 in_out_vrr->btr.inserted_duration_in_us = 0; 958 in_out_vrr->btr.frames_to_insert = 0; 959 in_out_vrr->btr.frame_counter = 0; 960 in_out_vrr->btr.mid_point_in_us = 961 in_out_vrr->min_duration_in_us + 962 (in_out_vrr->max_duration_in_us - 963 in_out_vrr->min_duration_in_us) / 2; 964 965 if (in_out_vrr->state == VRR_STATE_UNSUPPORTED) { 966 in_out_vrr->adjust.v_total_min = stream->timing.v_total; 967 in_out_vrr->adjust.v_total_max = stream->timing.v_total; 968 } else if (in_out_vrr->state == VRR_STATE_DISABLED) { 969 in_out_vrr->adjust.v_total_min = stream->timing.v_total; 970 in_out_vrr->adjust.v_total_max = stream->timing.v_total; 971 } else if (in_out_vrr->state == VRR_STATE_INACTIVE) { 972 in_out_vrr->adjust.v_total_min = stream->timing.v_total; 973 in_out_vrr->adjust.v_total_max = stream->timing.v_total; 974 } else if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE && 975 refresh_range >= MIN_REFRESH_RANGE_IN_US) { 976 in_out_vrr->adjust.v_total_min = 977 calc_v_total_from_refresh(stream, 978 in_out_vrr->max_refresh_in_uhz); 979 in_out_vrr->adjust.v_total_max = 980 calc_v_total_from_refresh(stream, 981 in_out_vrr->min_refresh_in_uhz); 982 } else if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED) { 983 in_out_vrr->fixed.target_refresh_in_uhz = 984 in_out_vrr->min_refresh_in_uhz; 985 if (in_out_vrr->fixed.ramping_active && 986 in_out_vrr->fixed.fixed_active) { 987 /* Do not update vtotals if ramping is already active 988 * in order to continue ramp from current refresh. 989 */ 990 in_out_vrr->fixed.fixed_active = true; 991 } else { 992 in_out_vrr->fixed.fixed_active = true; 993 in_out_vrr->adjust.v_total_min = 994 calc_v_total_from_refresh(stream, 995 in_out_vrr->fixed.target_refresh_in_uhz); 996 in_out_vrr->adjust.v_total_max = 997 in_out_vrr->adjust.v_total_min; 998 } 999 } else { 1000 in_out_vrr->state = VRR_STATE_INACTIVE; 1001 in_out_vrr->adjust.v_total_min = stream->timing.v_total; 1002 in_out_vrr->adjust.v_total_max = stream->timing.v_total; 1003 } 1004 } 1005 1006 void mod_freesync_handle_preflip(struct mod_freesync *mod_freesync, 1007 const struct dc_plane_state *plane, 1008 const struct dc_stream_state *stream, 1009 unsigned int curr_time_stamp_in_us, 1010 struct mod_vrr_params *in_out_vrr) 1011 { 1012 struct core_freesync *core_freesync = NULL; 1013 unsigned int last_render_time_in_us = 0; 1014 unsigned int average_render_time_in_us = 0; 1015 1016 if (mod_freesync == NULL) 1017 return; 1018 1019 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1020 1021 if (in_out_vrr->supported && 1022 in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE) { 1023 unsigned int i = 0; 1024 unsigned int oldest_index = plane->time.index + 1; 1025 1026 if (oldest_index >= DC_PLANE_UPDATE_TIMES_MAX) 1027 oldest_index = 0; 1028 1029 last_render_time_in_us = curr_time_stamp_in_us - 1030 plane->time.prev_update_time_in_us; 1031 1032 // Sum off all entries except oldest one 1033 for (i = 0; i < DC_PLANE_UPDATE_TIMES_MAX; i++) { 1034 average_render_time_in_us += 1035 plane->time.time_elapsed_in_us[i]; 1036 } 1037 average_render_time_in_us -= 1038 plane->time.time_elapsed_in_us[oldest_index]; 1039 1040 // Add render time for current flip 1041 average_render_time_in_us += last_render_time_in_us; 1042 average_render_time_in_us /= DC_PLANE_UPDATE_TIMES_MAX; 1043 1044 if (in_out_vrr->btr.btr_enabled) { 1045 apply_below_the_range(core_freesync, 1046 stream, 1047 last_render_time_in_us, 1048 in_out_vrr); 1049 } else { 1050 apply_fixed_refresh(core_freesync, 1051 stream, 1052 last_render_time_in_us, 1053 in_out_vrr); 1054 } 1055 1056 } 1057 } 1058 1059 void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync, 1060 const struct dc_stream_state *stream, 1061 struct mod_vrr_params *in_out_vrr) 1062 { 1063 struct core_freesync *core_freesync = NULL; 1064 1065 if ((mod_freesync == NULL) || (stream == NULL) || (in_out_vrr == NULL)) 1066 return; 1067 1068 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1069 1070 if (in_out_vrr->supported == false) 1071 return; 1072 1073 /* Below the Range Logic */ 1074 1075 /* Only execute if in fullscreen mode */ 1076 if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE && 1077 in_out_vrr->btr.btr_active) { 1078 /* TODO: pass in flag for Pre-DCE12 ASIC 1079 * in order for frame variable duration to take affect, 1080 * it needs to be done one VSYNC early, which is at 1081 * frameCounter == 1. 1082 * For DCE12 and newer updates to V_TOTAL_MIN/MAX 1083 * will take affect on current frame 1084 */ 1085 if (in_out_vrr->btr.frames_to_insert == 1086 in_out_vrr->btr.frame_counter) { 1087 in_out_vrr->adjust.v_total_min = 1088 calc_v_total_from_duration(stream, 1089 in_out_vrr, 1090 in_out_vrr->btr.inserted_duration_in_us); 1091 in_out_vrr->adjust.v_total_max = 1092 in_out_vrr->adjust.v_total_min; 1093 } 1094 1095 if (in_out_vrr->btr.frame_counter > 0) 1096 in_out_vrr->btr.frame_counter--; 1097 1098 /* Restore FreeSync */ 1099 if (in_out_vrr->btr.frame_counter == 0) { 1100 in_out_vrr->adjust.v_total_min = 1101 calc_v_total_from_refresh(stream, 1102 in_out_vrr->max_refresh_in_uhz); 1103 in_out_vrr->adjust.v_total_max = 1104 calc_v_total_from_refresh(stream, 1105 in_out_vrr->min_refresh_in_uhz); 1106 } 1107 } 1108 1109 /* If in fullscreen freesync mode or in video, do not program 1110 * static screen ramp values 1111 */ 1112 if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE) 1113 in_out_vrr->fixed.ramping_active = false; 1114 1115 /* Gradual Static Screen Ramping Logic */ 1116 /* Execute if ramp is active and user enabled freesync static screen*/ 1117 if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED && 1118 in_out_vrr->fixed.ramping_active) { 1119 update_v_total_for_static_ramp( 1120 core_freesync, stream, in_out_vrr); 1121 } 1122 } 1123 1124 void mod_freesync_get_settings(struct mod_freesync *mod_freesync, 1125 const struct mod_vrr_params *vrr, 1126 unsigned int *v_total_min, unsigned int *v_total_max, 1127 unsigned int *event_triggers, 1128 unsigned int *window_min, unsigned int *window_max, 1129 unsigned int *lfc_mid_point_in_us, 1130 unsigned int *inserted_frames, 1131 unsigned int *inserted_duration_in_us) 1132 { 1133 struct core_freesync *core_freesync = NULL; 1134 1135 if (mod_freesync == NULL) 1136 return; 1137 1138 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1139 1140 if (vrr->supported) { 1141 *v_total_min = vrr->adjust.v_total_min; 1142 *v_total_max = vrr->adjust.v_total_max; 1143 *event_triggers = 0; 1144 *lfc_mid_point_in_us = vrr->btr.mid_point_in_us; 1145 *inserted_frames = vrr->btr.frames_to_insert; 1146 *inserted_duration_in_us = vrr->btr.inserted_duration_in_us; 1147 } 1148 } 1149 1150 unsigned long long mod_freesync_calc_nominal_field_rate( 1151 const struct dc_stream_state *stream) 1152 { 1153 unsigned long long nominal_field_rate_in_uhz = 0; 1154 1155 /* Calculate nominal field rate for stream */ 1156 nominal_field_rate_in_uhz = stream->timing.pix_clk_100hz / 10; 1157 nominal_field_rate_in_uhz *= 1000ULL * 1000ULL * 1000ULL; 1158 nominal_field_rate_in_uhz = div_u64(nominal_field_rate_in_uhz, 1159 stream->timing.h_total); 1160 nominal_field_rate_in_uhz = div_u64(nominal_field_rate_in_uhz, 1161 stream->timing.v_total); 1162 1163 return nominal_field_rate_in_uhz; 1164 } 1165 1166 bool mod_freesync_is_valid_range(struct mod_freesync *mod_freesync, 1167 const struct dc_stream_state *stream, 1168 uint32_t min_refresh_cap_in_uhz, 1169 uint32_t max_refresh_cap_in_uhz, 1170 uint32_t min_refresh_request_in_uhz, 1171 uint32_t max_refresh_request_in_uhz) 1172 { 1173 /* Calculate nominal field rate for stream */ 1174 unsigned long long nominal_field_rate_in_uhz = 1175 mod_freesync_calc_nominal_field_rate(stream); 1176 1177 /* Typically nominal refresh calculated can have some fractional part. 1178 * Allow for some rounding error of actual video timing by taking floor 1179 * of caps and request. Round the nominal refresh rate. 1180 * 1181 * Dividing will convert everything to units in Hz although input 1182 * variable name is in uHz! 1183 * 1184 * Also note, this takes care of rounding error on the nominal refresh 1185 * so by rounding error we only expect it to be off by a small amount, 1186 * such as < 0.1 Hz. i.e. 143.9xxx or 144.1xxx. 1187 * 1188 * Example 1. Caps Min = 40 Hz, Max = 144 Hz 1189 * Request Min = 40 Hz, Max = 144 Hz 1190 * Nominal = 143.5x Hz rounded to 144 Hz 1191 * This function should allow this as valid request 1192 * 1193 * Example 2. Caps Min = 40 Hz, Max = 144 Hz 1194 * Request Min = 40 Hz, Max = 144 Hz 1195 * Nominal = 144.4x Hz rounded to 144 Hz 1196 * This function should allow this as valid request 1197 * 1198 * Example 3. Caps Min = 40 Hz, Max = 144 Hz 1199 * Request Min = 40 Hz, Max = 144 Hz 1200 * Nominal = 120.xx Hz rounded to 120 Hz 1201 * This function should return NOT valid since the requested 1202 * max is greater than current timing's nominal 1203 * 1204 * Example 4. Caps Min = 40 Hz, Max = 120 Hz 1205 * Request Min = 40 Hz, Max = 120 Hz 1206 * Nominal = 144.xx Hz rounded to 144 Hz 1207 * This function should return NOT valid since the nominal 1208 * is greater than the capability's max refresh 1209 */ 1210 nominal_field_rate_in_uhz = 1211 div_u64(nominal_field_rate_in_uhz + 500000, 1000000); 1212 min_refresh_cap_in_uhz /= 1000000; 1213 max_refresh_cap_in_uhz /= 1000000; 1214 min_refresh_request_in_uhz /= 1000000; 1215 max_refresh_request_in_uhz /= 1000000; 1216 1217 // Check nominal is within range 1218 if (nominal_field_rate_in_uhz > max_refresh_cap_in_uhz || 1219 nominal_field_rate_in_uhz < min_refresh_cap_in_uhz) 1220 return false; 1221 1222 // If nominal is less than max, limit the max allowed refresh rate 1223 if (nominal_field_rate_in_uhz < max_refresh_cap_in_uhz) 1224 max_refresh_cap_in_uhz = nominal_field_rate_in_uhz; 1225 1226 // Don't allow min > max 1227 if (min_refresh_request_in_uhz > max_refresh_request_in_uhz) 1228 return false; 1229 1230 // Check min is within range 1231 if (min_refresh_request_in_uhz > max_refresh_cap_in_uhz || 1232 min_refresh_request_in_uhz < min_refresh_cap_in_uhz) 1233 return false; 1234 1235 // Check max is within range 1236 if (max_refresh_request_in_uhz > max_refresh_cap_in_uhz || 1237 max_refresh_request_in_uhz < min_refresh_cap_in_uhz) 1238 return false; 1239 1240 // For variable range, check for at least 10 Hz range 1241 if ((max_refresh_request_in_uhz != min_refresh_request_in_uhz) && 1242 (max_refresh_request_in_uhz - min_refresh_request_in_uhz < 10)) 1243 return false; 1244 1245 return true; 1246 } 1247 1248