root/drivers/gpu/drm/amd/display/modules/freesync/freesync.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mod_freesync_create
  2. mod_freesync_destroy
  3. calc_refresh_in_uhz_from_duration
  4. calc_duration_in_us_from_refresh_in_uhz
  5. calc_duration_in_us_from_v_total
  6. calc_v_total_from_refresh
  7. calc_v_total_from_duration
  8. update_v_total_for_static_ramp
  9. apply_below_the_range
  10. apply_fixed_refresh
  11. vrr_settings_require_update
  12. mod_freesync_get_vmin_vmax
  13. mod_freesync_get_v_position
  14. build_vrr_infopacket_data
  15. build_vrr_infopacket_fs2_data
  16. build_vrr_infopacket_header_v1
  17. build_vrr_infopacket_header_v2
  18. build_vrr_infopacket_checksum
  19. build_vrr_infopacket_v1
  20. build_vrr_infopacket_v2
  21. mod_freesync_build_vrr_infopacket
  22. mod_freesync_build_vrr_params
  23. mod_freesync_handle_preflip
  24. mod_freesync_handle_v_update
  25. mod_freesync_get_settings
  26. mod_freesync_calc_nominal_field_rate
  27. mod_freesync_is_valid_range

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

/* [<][>][^][v][top][bottom][index][help] */