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