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 
mod_freesync_create(struct dc * dc)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 
mod_freesync_destroy(struct mod_freesync * mod_freesync)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 
calc_duration_in_us_from_refresh_in_uhz(unsigned int refresh_in_uhz)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 
calc_duration_in_us_from_v_total(const struct dc_stream_state * stream,const struct mod_vrr_params * in_vrr,unsigned int v_total)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 
calc_v_total_from_refresh(const struct dc_stream_state * stream,unsigned int refresh_in_uhz)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 
calc_v_total_from_duration(const struct dc_stream_state * stream,const struct mod_vrr_params * vrr,unsigned int duration_in_us)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 
update_v_total_for_static_ramp(struct core_freesync * core_freesync,const struct dc_stream_state * stream,struct mod_vrr_params * in_out_vrr)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 
apply_below_the_range(struct core_freesync * core_freesync,const struct dc_stream_state * stream,unsigned int last_render_time_in_us,struct mod_vrr_params * in_out_vrr)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 
apply_fixed_refresh(struct core_freesync * core_freesync,const struct dc_stream_state * stream,unsigned int last_render_time_in_us,struct mod_vrr_params * in_out_vrr)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 
vrr_settings_require_update(struct core_freesync * core_freesync,struct mod_freesync_config * in_config,unsigned int min_refresh_in_uhz,unsigned int max_refresh_in_uhz,struct mod_vrr_params * in_vrr)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 
mod_freesync_get_vmin_vmax(struct mod_freesync * mod_freesync,const struct dc_stream_state * stream,unsigned int * vmin,unsigned int * vmax)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 
mod_freesync_get_v_position(struct mod_freesync * mod_freesync,struct dc_stream_state * stream,unsigned int * nom_v_pos,unsigned int * v_pos)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 
build_vrr_infopacket_data(const struct mod_vrr_params * vrr,struct dc_info_packet * infopacket)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 
build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf,struct dc_info_packet * infopacket)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 
build_vrr_infopacket_header_v1(enum signal_type signal,struct dc_info_packet * infopacket,unsigned int * payload_size)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 
build_vrr_infopacket_header_v2(enum signal_type signal,struct dc_info_packet * infopacket,unsigned int * payload_size)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 
build_vrr_infopacket_checksum(unsigned int * payload_size,struct dc_info_packet * infopacket)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 
build_vrr_infopacket_v1(enum signal_type signal,const struct mod_vrr_params * vrr,struct dc_info_packet * infopacket)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 
build_vrr_infopacket_v2(enum signal_type signal,const struct mod_vrr_params * vrr,enum color_transfer_func app_tf,struct dc_info_packet * infopacket)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 
mod_freesync_build_vrr_infopacket(struct mod_freesync * mod_freesync,const struct dc_stream_state * stream,const struct mod_vrr_params * vrr,enum vrr_packet_type packet_type,enum color_transfer_func app_tf,struct dc_info_packet * infopacket)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 
mod_freesync_build_vrr_params(struct mod_freesync * mod_freesync,const struct dc_stream_state * stream,struct mod_freesync_config * in_config,struct mod_vrr_params * in_out_vrr)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 
mod_freesync_handle_preflip(struct mod_freesync * mod_freesync,const struct dc_plane_state * plane,const struct dc_stream_state * stream,unsigned int curr_time_stamp_in_us,struct mod_vrr_params * in_out_vrr)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 
mod_freesync_handle_v_update(struct mod_freesync * mod_freesync,const struct dc_stream_state * stream,struct mod_vrr_params * in_out_vrr)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 
mod_freesync_get_settings(struct mod_freesync * mod_freesync,const struct mod_vrr_params * vrr,unsigned int * v_total_min,unsigned int * v_total_max,unsigned int * event_triggers,unsigned int * window_min,unsigned int * window_max,unsigned int * lfc_mid_point_in_us,unsigned int * inserted_frames,unsigned int * inserted_duration_in_us)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 
mod_freesync_calc_nominal_field_rate(const struct dc_stream_state * stream)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 
mod_freesync_is_valid_range(struct mod_freesync * mod_freesync,const struct dc_stream_state * stream,uint32_t min_refresh_cap_in_uhz,uint32_t max_refresh_cap_in_uhz,uint32_t min_refresh_request_in_uhz,uint32_t max_refresh_request_in_uhz)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