xref: /dflybsd-src/sys/dev/drm/amd/display/modules/freesync/freesync.c (revision b843c749addef9340ee7d4e250b09fdd492602a1)
1*b843c749SSergey Zigachev /*
2*b843c749SSergey Zigachev  * Copyright 2016 Advanced Micro Devices, Inc.
3*b843c749SSergey Zigachev  *
4*b843c749SSergey Zigachev  * Permission is hereby granted, free of charge, to any person obtaining a
5*b843c749SSergey Zigachev  * copy of this software and associated documentation files (the "Software"),
6*b843c749SSergey Zigachev  * to deal in the Software without restriction, including without limitation
7*b843c749SSergey Zigachev  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*b843c749SSergey Zigachev  * and/or sell copies of the Software, and to permit persons to whom the
9*b843c749SSergey Zigachev  * Software is furnished to do so, subject to the following conditions:
10*b843c749SSergey Zigachev  *
11*b843c749SSergey Zigachev  * The above copyright notice and this permission notice shall be included in
12*b843c749SSergey Zigachev  * all copies or substantial portions of the Software.
13*b843c749SSergey Zigachev  *
14*b843c749SSergey Zigachev  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*b843c749SSergey Zigachev  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*b843c749SSergey Zigachev  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17*b843c749SSergey Zigachev  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18*b843c749SSergey Zigachev  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19*b843c749SSergey Zigachev  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20*b843c749SSergey Zigachev  * OTHER DEALINGS IN THE SOFTWARE.
21*b843c749SSergey Zigachev  *
22*b843c749SSergey Zigachev  * Authors: AMD
23*b843c749SSergey Zigachev  *
24*b843c749SSergey Zigachev  */
25*b843c749SSergey Zigachev 
26*b843c749SSergey Zigachev #include "dm_services.h"
27*b843c749SSergey Zigachev #include "dc.h"
28*b843c749SSergey Zigachev #include "mod_freesync.h"
29*b843c749SSergey Zigachev #include "core_types.h"
30*b843c749SSergey Zigachev 
31*b843c749SSergey Zigachev #define MOD_FREESYNC_MAX_CONCURRENT_STREAMS  32
32*b843c749SSergey Zigachev 
33*b843c749SSergey Zigachev /* Refresh rate ramp at a fixed rate of 65 Hz/second */
34*b843c749SSergey Zigachev #define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65)
35*b843c749SSergey Zigachev /* Number of elements in the render times cache array */
36*b843c749SSergey Zigachev #define RENDER_TIMES_MAX_COUNT 10
37*b843c749SSergey Zigachev /* Threshold to exit BTR (to avoid frequent enter-exits at the lower limit) */
38*b843c749SSergey Zigachev #define BTR_EXIT_MARGIN 2000
39*b843c749SSergey Zigachev /* Number of consecutive frames to check before entering/exiting fixed refresh*/
40*b843c749SSergey Zigachev #define FIXED_REFRESH_ENTER_FRAME_COUNT 5
41*b843c749SSergey Zigachev #define FIXED_REFRESH_EXIT_FRAME_COUNT 5
42*b843c749SSergey Zigachev 
43*b843c749SSergey Zigachev #define FREESYNC_REGISTRY_NAME "freesync_v1"
44*b843c749SSergey Zigachev 
45*b843c749SSergey Zigachev #define FREESYNC_NO_STATIC_FOR_EXTERNAL_DP_REGKEY "DalFreeSyncNoStaticForExternalDp"
46*b843c749SSergey Zigachev 
47*b843c749SSergey Zigachev #define FREESYNC_NO_STATIC_FOR_INTERNAL_REGKEY "DalFreeSyncNoStaticForInternal"
48*b843c749SSergey Zigachev 
49*b843c749SSergey Zigachev #define FREESYNC_DEFAULT_REGKEY "LCDFreeSyncDefault"
50*b843c749SSergey Zigachev 
51*b843c749SSergey Zigachev struct gradual_static_ramp {
52*b843c749SSergey Zigachev 	bool ramp_is_active;
53*b843c749SSergey Zigachev 	bool ramp_direction_is_up;
54*b843c749SSergey Zigachev 	unsigned int ramp_current_frame_duration_in_ns;
55*b843c749SSergey Zigachev };
56*b843c749SSergey Zigachev 
57*b843c749SSergey Zigachev struct freesync_time {
58*b843c749SSergey Zigachev 	/* video (48Hz feature) related */
59*b843c749SSergey Zigachev 	unsigned int update_duration_in_ns;
60*b843c749SSergey Zigachev 
61*b843c749SSergey Zigachev 	/* BTR/fixed refresh related */
62*b843c749SSergey Zigachev 	unsigned int prev_time_stamp_in_us;
63*b843c749SSergey Zigachev 
64*b843c749SSergey Zigachev 	unsigned int min_render_time_in_us;
65*b843c749SSergey Zigachev 	unsigned int max_render_time_in_us;
66*b843c749SSergey Zigachev 
67*b843c749SSergey Zigachev 	unsigned int render_times_index;
68*b843c749SSergey Zigachev 	unsigned int render_times[RENDER_TIMES_MAX_COUNT];
69*b843c749SSergey Zigachev 
70*b843c749SSergey Zigachev 	unsigned int min_window;
71*b843c749SSergey Zigachev 	unsigned int max_window;
72*b843c749SSergey Zigachev };
73*b843c749SSergey Zigachev 
74*b843c749SSergey Zigachev struct below_the_range {
75*b843c749SSergey Zigachev 	bool btr_active;
76*b843c749SSergey Zigachev 	bool program_btr;
77*b843c749SSergey Zigachev 
78*b843c749SSergey Zigachev 	unsigned int mid_point_in_us;
79*b843c749SSergey Zigachev 
80*b843c749SSergey Zigachev 	unsigned int inserted_frame_duration_in_us;
81*b843c749SSergey Zigachev 	unsigned int frames_to_insert;
82*b843c749SSergey Zigachev 	unsigned int frame_counter;
83*b843c749SSergey Zigachev };
84*b843c749SSergey Zigachev 
85*b843c749SSergey Zigachev struct fixed_refresh {
86*b843c749SSergey Zigachev 	bool fixed_active;
87*b843c749SSergey Zigachev 	bool program_fixed;
88*b843c749SSergey Zigachev 	unsigned int frame_counter;
89*b843c749SSergey Zigachev };
90*b843c749SSergey Zigachev 
91*b843c749SSergey Zigachev struct freesync_range {
92*b843c749SSergey Zigachev 	unsigned int min_refresh;
93*b843c749SSergey Zigachev 	unsigned int max_frame_duration;
94*b843c749SSergey Zigachev 	unsigned int vmax;
95*b843c749SSergey Zigachev 
96*b843c749SSergey Zigachev 	unsigned int max_refresh;
97*b843c749SSergey Zigachev 	unsigned int min_frame_duration;
98*b843c749SSergey Zigachev 	unsigned int vmin;
99*b843c749SSergey Zigachev };
100*b843c749SSergey Zigachev 
101*b843c749SSergey Zigachev struct freesync_state {
102*b843c749SSergey Zigachev 	bool fullscreen;
103*b843c749SSergey Zigachev 	bool static_screen;
104*b843c749SSergey Zigachev 	bool video;
105*b843c749SSergey Zigachev 
106*b843c749SSergey Zigachev 	unsigned int vmin;
107*b843c749SSergey Zigachev 	unsigned int vmax;
108*b843c749SSergey Zigachev 
109*b843c749SSergey Zigachev 	struct freesync_time time;
110*b843c749SSergey Zigachev 
111*b843c749SSergey Zigachev 	unsigned int nominal_refresh_rate_in_micro_hz;
112*b843c749SSergey Zigachev 	bool windowed_fullscreen;
113*b843c749SSergey Zigachev 
114*b843c749SSergey Zigachev 	struct gradual_static_ramp static_ramp;
115*b843c749SSergey Zigachev 	struct below_the_range btr;
116*b843c749SSergey Zigachev 	struct fixed_refresh fixed_refresh;
117*b843c749SSergey Zigachev 	struct freesync_range freesync_range;
118*b843c749SSergey Zigachev };
119*b843c749SSergey Zigachev 
120*b843c749SSergey Zigachev struct freesync_entity {
121*b843c749SSergey Zigachev 	struct dc_stream_state *stream;
122*b843c749SSergey Zigachev 	struct mod_freesync_caps *caps;
123*b843c749SSergey Zigachev 	struct freesync_state state;
124*b843c749SSergey Zigachev 	struct mod_freesync_user_enable user_enable;
125*b843c749SSergey Zigachev };
126*b843c749SSergey Zigachev 
127*b843c749SSergey Zigachev struct freesync_registry_options {
128*b843c749SSergey Zigachev 	bool drr_external_supported;
129*b843c749SSergey Zigachev 	bool drr_internal_supported;
130*b843c749SSergey Zigachev 	bool lcd_freesync_default_set;
131*b843c749SSergey Zigachev 	int lcd_freesync_default_value;
132*b843c749SSergey Zigachev };
133*b843c749SSergey Zigachev 
134*b843c749SSergey Zigachev struct core_freesync {
135*b843c749SSergey Zigachev 	struct mod_freesync public;
136*b843c749SSergey Zigachev 	struct dc *dc;
137*b843c749SSergey Zigachev 	struct freesync_registry_options opts;
138*b843c749SSergey Zigachev 	struct freesync_entity *map;
139*b843c749SSergey Zigachev 	int num_entities;
140*b843c749SSergey Zigachev };
141*b843c749SSergey Zigachev 
142*b843c749SSergey Zigachev #define MOD_FREESYNC_TO_CORE(mod_freesync)\
143*b843c749SSergey Zigachev 		container_of(mod_freesync, struct core_freesync, public)
144*b843c749SSergey Zigachev 
mod_freesync_create(struct dc * dc)145*b843c749SSergey Zigachev struct mod_freesync *mod_freesync_create(struct dc *dc)
146*b843c749SSergey Zigachev {
147*b843c749SSergey Zigachev 	struct core_freesync *core_freesync =
148*b843c749SSergey Zigachev 			kzalloc(sizeof(struct core_freesync), GFP_KERNEL);
149*b843c749SSergey Zigachev 
150*b843c749SSergey Zigachev 
151*b843c749SSergey Zigachev 	struct persistent_data_flag flag;
152*b843c749SSergey Zigachev 
153*b843c749SSergey Zigachev 	int i, data = 0;
154*b843c749SSergey Zigachev 
155*b843c749SSergey Zigachev 	if (core_freesync == NULL)
156*b843c749SSergey Zigachev 		goto fail_alloc_context;
157*b843c749SSergey Zigachev 
158*b843c749SSergey Zigachev 	core_freesync->map = kcalloc(MOD_FREESYNC_MAX_CONCURRENT_STREAMS,
159*b843c749SSergey Zigachev 					sizeof(struct freesync_entity),
160*b843c749SSergey Zigachev 					GFP_KERNEL);
161*b843c749SSergey Zigachev 
162*b843c749SSergey Zigachev 	if (core_freesync->map == NULL)
163*b843c749SSergey Zigachev 		goto fail_alloc_map;
164*b843c749SSergey Zigachev 
165*b843c749SSergey Zigachev 	for (i = 0; i < MOD_FREESYNC_MAX_CONCURRENT_STREAMS; i++)
166*b843c749SSergey Zigachev 		core_freesync->map[i].stream = NULL;
167*b843c749SSergey Zigachev 
168*b843c749SSergey Zigachev 	core_freesync->num_entities = 0;
169*b843c749SSergey Zigachev 
170*b843c749SSergey Zigachev 	if (dc == NULL)
171*b843c749SSergey Zigachev 		goto fail_construct;
172*b843c749SSergey Zigachev 
173*b843c749SSergey Zigachev 	core_freesync->dc = dc;
174*b843c749SSergey Zigachev 
175*b843c749SSergey Zigachev 	/* Create initial module folder in registry for freesync enable data */
176*b843c749SSergey Zigachev 	flag.save_per_edid = true;
177*b843c749SSergey Zigachev 	flag.save_per_link = false;
178*b843c749SSergey Zigachev 	dm_write_persistent_data(dc->ctx, NULL, FREESYNC_REGISTRY_NAME,
179*b843c749SSergey Zigachev 			NULL, NULL, 0, &flag);
180*b843c749SSergey Zigachev 	flag.save_per_edid = false;
181*b843c749SSergey Zigachev 	flag.save_per_link = false;
182*b843c749SSergey Zigachev 
183*b843c749SSergey Zigachev 	if (dm_read_persistent_data(dc->ctx, NULL, NULL,
184*b843c749SSergey Zigachev 			FREESYNC_NO_STATIC_FOR_INTERNAL_REGKEY,
185*b843c749SSergey Zigachev 			&data, sizeof(data), &flag)) {
186*b843c749SSergey Zigachev 		core_freesync->opts.drr_internal_supported =
187*b843c749SSergey Zigachev 			(data & 1) ? false : true;
188*b843c749SSergey Zigachev 	}
189*b843c749SSergey Zigachev 
190*b843c749SSergey Zigachev 	if (dm_read_persistent_data(dc->ctx, NULL, NULL,
191*b843c749SSergey Zigachev 			FREESYNC_NO_STATIC_FOR_EXTERNAL_DP_REGKEY,
192*b843c749SSergey Zigachev 			&data, sizeof(data), &flag)) {
193*b843c749SSergey Zigachev 		core_freesync->opts.drr_external_supported =
194*b843c749SSergey Zigachev 				(data & 1) ? false : true;
195*b843c749SSergey Zigachev 	}
196*b843c749SSergey Zigachev 
197*b843c749SSergey Zigachev 	if (dm_read_persistent_data(dc->ctx, NULL, NULL,
198*b843c749SSergey Zigachev 			FREESYNC_DEFAULT_REGKEY,
199*b843c749SSergey Zigachev 			&data, sizeof(data), &flag)) {
200*b843c749SSergey Zigachev 		core_freesync->opts.lcd_freesync_default_set = true;
201*b843c749SSergey Zigachev 		core_freesync->opts.lcd_freesync_default_value = data;
202*b843c749SSergey Zigachev 	} else {
203*b843c749SSergey Zigachev 		core_freesync->opts.lcd_freesync_default_set = false;
204*b843c749SSergey Zigachev 		core_freesync->opts.lcd_freesync_default_value = 0;
205*b843c749SSergey Zigachev 	}
206*b843c749SSergey Zigachev 
207*b843c749SSergey Zigachev 	return &core_freesync->public;
208*b843c749SSergey Zigachev 
209*b843c749SSergey Zigachev fail_construct:
210*b843c749SSergey Zigachev 	kfree(core_freesync->map);
211*b843c749SSergey Zigachev 
212*b843c749SSergey Zigachev fail_alloc_map:
213*b843c749SSergey Zigachev 	kfree(core_freesync);
214*b843c749SSergey Zigachev 
215*b843c749SSergey Zigachev fail_alloc_context:
216*b843c749SSergey Zigachev 	return NULL;
217*b843c749SSergey Zigachev }
218*b843c749SSergey Zigachev 
mod_freesync_destroy(struct mod_freesync * mod_freesync)219*b843c749SSergey Zigachev void mod_freesync_destroy(struct mod_freesync *mod_freesync)
220*b843c749SSergey Zigachev {
221*b843c749SSergey Zigachev 	if (mod_freesync != NULL) {
222*b843c749SSergey Zigachev 		int i;
223*b843c749SSergey Zigachev 		struct core_freesync *core_freesync =
224*b843c749SSergey Zigachev 				MOD_FREESYNC_TO_CORE(mod_freesync);
225*b843c749SSergey Zigachev 
226*b843c749SSergey Zigachev 		for (i = 0; i < core_freesync->num_entities; i++)
227*b843c749SSergey Zigachev 			if (core_freesync->map[i].stream)
228*b843c749SSergey Zigachev 				dc_stream_release(core_freesync->map[i].stream);
229*b843c749SSergey Zigachev 
230*b843c749SSergey Zigachev 		kfree(core_freesync->map);
231*b843c749SSergey Zigachev 
232*b843c749SSergey Zigachev 		kfree(core_freesync);
233*b843c749SSergey Zigachev 	}
234*b843c749SSergey Zigachev }
235*b843c749SSergey Zigachev 
236*b843c749SSergey Zigachev /* Given a specific dc_stream* this function finds its equivalent
237*b843c749SSergey Zigachev  * on the core_freesync->map and returns the corresponding index
238*b843c749SSergey Zigachev  */
map_index_from_stream(struct core_freesync * core_freesync,struct dc_stream_state * stream)239*b843c749SSergey Zigachev static unsigned int map_index_from_stream(struct core_freesync *core_freesync,
240*b843c749SSergey Zigachev 		struct dc_stream_state *stream)
241*b843c749SSergey Zigachev {
242*b843c749SSergey Zigachev 	unsigned int index = 0;
243*b843c749SSergey Zigachev 
244*b843c749SSergey Zigachev 	for (index = 0; index < core_freesync->num_entities; index++) {
245*b843c749SSergey Zigachev 		if (core_freesync->map[index].stream == stream) {
246*b843c749SSergey Zigachev 			return index;
247*b843c749SSergey Zigachev 		}
248*b843c749SSergey Zigachev 	}
249*b843c749SSergey Zigachev 	/* Could not find stream requested */
250*b843c749SSergey Zigachev 	ASSERT(false);
251*b843c749SSergey Zigachev 	return index;
252*b843c749SSergey Zigachev }
253*b843c749SSergey Zigachev 
mod_freesync_add_stream(struct mod_freesync * mod_freesync,struct dc_stream_state * stream,struct mod_freesync_caps * caps)254*b843c749SSergey Zigachev bool mod_freesync_add_stream(struct mod_freesync *mod_freesync,
255*b843c749SSergey Zigachev 		struct dc_stream_state *stream, struct mod_freesync_caps *caps)
256*b843c749SSergey Zigachev {
257*b843c749SSergey Zigachev 	struct dc  *dc = NULL;
258*b843c749SSergey Zigachev 	struct core_freesync *core_freesync = NULL;
259*b843c749SSergey Zigachev 	int persistent_freesync_enable = 0;
260*b843c749SSergey Zigachev 	struct persistent_data_flag flag;
261*b843c749SSergey Zigachev 	unsigned int nom_refresh_rate_uhz;
262*b843c749SSergey Zigachev 	unsigned long long temp;
263*b843c749SSergey Zigachev 
264*b843c749SSergey Zigachev 	if (mod_freesync == NULL)
265*b843c749SSergey Zigachev 		return false;
266*b843c749SSergey Zigachev 
267*b843c749SSergey Zigachev 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
268*b843c749SSergey Zigachev 	dc = core_freesync->dc;
269*b843c749SSergey Zigachev 
270*b843c749SSergey Zigachev 	flag.save_per_edid = true;
271*b843c749SSergey Zigachev 	flag.save_per_link = false;
272*b843c749SSergey Zigachev 
273*b843c749SSergey Zigachev 	if (core_freesync->num_entities < MOD_FREESYNC_MAX_CONCURRENT_STREAMS) {
274*b843c749SSergey Zigachev 
275*b843c749SSergey Zigachev 		dc_stream_retain(stream);
276*b843c749SSergey Zigachev 
277*b843c749SSergey Zigachev 		temp = stream->timing.pix_clk_khz;
278*b843c749SSergey Zigachev 		temp *= 1000ULL * 1000ULL * 1000ULL;
279*b843c749SSergey Zigachev 		temp = div_u64(temp, stream->timing.h_total);
280*b843c749SSergey Zigachev 		temp = div_u64(temp, stream->timing.v_total);
281*b843c749SSergey Zigachev 
282*b843c749SSergey Zigachev 		nom_refresh_rate_uhz = (unsigned int) temp;
283*b843c749SSergey Zigachev 
284*b843c749SSergey Zigachev 		core_freesync->map[core_freesync->num_entities].stream = stream;
285*b843c749SSergey Zigachev 		core_freesync->map[core_freesync->num_entities].caps = caps;
286*b843c749SSergey Zigachev 
287*b843c749SSergey Zigachev 		core_freesync->map[core_freesync->num_entities].state.
288*b843c749SSergey Zigachev 			fullscreen = false;
289*b843c749SSergey Zigachev 		core_freesync->map[core_freesync->num_entities].state.
290*b843c749SSergey Zigachev 			static_screen = false;
291*b843c749SSergey Zigachev 		core_freesync->map[core_freesync->num_entities].state.
292*b843c749SSergey Zigachev 			video = false;
293*b843c749SSergey Zigachev 		core_freesync->map[core_freesync->num_entities].state.time.
294*b843c749SSergey Zigachev 			update_duration_in_ns = 0;
295*b843c749SSergey Zigachev 		core_freesync->map[core_freesync->num_entities].state.
296*b843c749SSergey Zigachev 			static_ramp.ramp_is_active = false;
297*b843c749SSergey Zigachev 
298*b843c749SSergey Zigachev 		/* get persistent data from registry */
299*b843c749SSergey Zigachev 		if (dm_read_persistent_data(dc->ctx, stream->sink,
300*b843c749SSergey Zigachev 					FREESYNC_REGISTRY_NAME,
301*b843c749SSergey Zigachev 					"userenable", &persistent_freesync_enable,
302*b843c749SSergey Zigachev 					sizeof(int), &flag)) {
303*b843c749SSergey Zigachev 			core_freesync->map[core_freesync->num_entities].user_enable.
304*b843c749SSergey Zigachev 				enable_for_gaming =
305*b843c749SSergey Zigachev 				(persistent_freesync_enable & 1) ? true : false;
306*b843c749SSergey Zigachev 			core_freesync->map[core_freesync->num_entities].user_enable.
307*b843c749SSergey Zigachev 				enable_for_static =
308*b843c749SSergey Zigachev 				(persistent_freesync_enable & 2) ? true : false;
309*b843c749SSergey Zigachev 			core_freesync->map[core_freesync->num_entities].user_enable.
310*b843c749SSergey Zigachev 				enable_for_video =
311*b843c749SSergey Zigachev 				(persistent_freesync_enable & 4) ? true : false;
312*b843c749SSergey Zigachev 		/* If FreeSync display and LCDFreeSyncDefault is set, use as default values write back to userenable */
313*b843c749SSergey Zigachev 		} else if (caps->supported && (core_freesync->opts.lcd_freesync_default_set)) {
314*b843c749SSergey Zigachev 			core_freesync->map[core_freesync->num_entities].user_enable.enable_for_gaming =
315*b843c749SSergey Zigachev 				(core_freesync->opts.lcd_freesync_default_value & 1) ? true : false;
316*b843c749SSergey Zigachev 			core_freesync->map[core_freesync->num_entities].user_enable.enable_for_static =
317*b843c749SSergey Zigachev 				(core_freesync->opts.lcd_freesync_default_value & 2) ? true : false;
318*b843c749SSergey Zigachev 			core_freesync->map[core_freesync->num_entities].user_enable.enable_for_video =
319*b843c749SSergey Zigachev 				(core_freesync->opts.lcd_freesync_default_value & 4) ? true : false;
320*b843c749SSergey Zigachev 			dm_write_persistent_data(dc->ctx, stream->sink,
321*b843c749SSergey Zigachev 						FREESYNC_REGISTRY_NAME,
322*b843c749SSergey Zigachev 						"userenable", &core_freesync->opts.lcd_freesync_default_value,
323*b843c749SSergey Zigachev 						sizeof(int), &flag);
324*b843c749SSergey Zigachev 		} else {
325*b843c749SSergey Zigachev 			core_freesync->map[core_freesync->num_entities].user_enable.
326*b843c749SSergey Zigachev 					enable_for_gaming = false;
327*b843c749SSergey Zigachev 			core_freesync->map[core_freesync->num_entities].user_enable.
328*b843c749SSergey Zigachev 					enable_for_static = false;
329*b843c749SSergey Zigachev 			core_freesync->map[core_freesync->num_entities].user_enable.
330*b843c749SSergey Zigachev 					enable_for_video = false;
331*b843c749SSergey Zigachev 		}
332*b843c749SSergey Zigachev 
333*b843c749SSergey Zigachev 		if (caps->supported &&
334*b843c749SSergey Zigachev 			nom_refresh_rate_uhz >= caps->min_refresh_in_micro_hz &&
335*b843c749SSergey Zigachev 			nom_refresh_rate_uhz <= caps->max_refresh_in_micro_hz)
336*b843c749SSergey Zigachev 			stream->ignore_msa_timing_param = 1;
337*b843c749SSergey Zigachev 
338*b843c749SSergey Zigachev 		core_freesync->num_entities++;
339*b843c749SSergey Zigachev 		return true;
340*b843c749SSergey Zigachev 	}
341*b843c749SSergey Zigachev 	return false;
342*b843c749SSergey Zigachev }
343*b843c749SSergey Zigachev 
mod_freesync_remove_stream(struct mod_freesync * mod_freesync,struct dc_stream_state * stream)344*b843c749SSergey Zigachev bool mod_freesync_remove_stream(struct mod_freesync *mod_freesync,
345*b843c749SSergey Zigachev 		struct dc_stream_state *stream)
346*b843c749SSergey Zigachev {
347*b843c749SSergey Zigachev 	int i = 0;
348*b843c749SSergey Zigachev 	struct core_freesync *core_freesync = NULL;
349*b843c749SSergey Zigachev 	unsigned int index = 0;
350*b843c749SSergey Zigachev 
351*b843c749SSergey Zigachev 	if (mod_freesync == NULL)
352*b843c749SSergey Zigachev 		return false;
353*b843c749SSergey Zigachev 
354*b843c749SSergey Zigachev 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
355*b843c749SSergey Zigachev 	index = map_index_from_stream(core_freesync, stream);
356*b843c749SSergey Zigachev 
357*b843c749SSergey Zigachev 	dc_stream_release(core_freesync->map[index].stream);
358*b843c749SSergey Zigachev 	core_freesync->map[index].stream = NULL;
359*b843c749SSergey Zigachev 	/* To remove this entity, shift everything after down */
360*b843c749SSergey Zigachev 	for (i = index; i < core_freesync->num_entities - 1; i++)
361*b843c749SSergey Zigachev 		core_freesync->map[i] = core_freesync->map[i + 1];
362*b843c749SSergey Zigachev 	core_freesync->num_entities--;
363*b843c749SSergey Zigachev 	return true;
364*b843c749SSergey Zigachev }
365*b843c749SSergey Zigachev 
adjust_vmin_vmax(struct core_freesync * core_freesync,struct dc_stream_state ** streams,int num_streams,int map_index,unsigned int v_total_min,unsigned int v_total_max)366*b843c749SSergey Zigachev static void adjust_vmin_vmax(struct core_freesync *core_freesync,
367*b843c749SSergey Zigachev 				struct dc_stream_state **streams,
368*b843c749SSergey Zigachev 				int num_streams,
369*b843c749SSergey Zigachev 				int map_index,
370*b843c749SSergey Zigachev 				unsigned int v_total_min,
371*b843c749SSergey Zigachev 				unsigned int v_total_max)
372*b843c749SSergey Zigachev {
373*b843c749SSergey Zigachev 	if (num_streams == 0 || streams == NULL || num_streams > 1)
374*b843c749SSergey Zigachev 		return;
375*b843c749SSergey Zigachev 
376*b843c749SSergey Zigachev 	core_freesync->map[map_index].state.vmin = v_total_min;
377*b843c749SSergey Zigachev 	core_freesync->map[map_index].state.vmax = v_total_max;
378*b843c749SSergey Zigachev 
379*b843c749SSergey Zigachev 	dc_stream_adjust_vmin_vmax(core_freesync->dc, streams,
380*b843c749SSergey Zigachev 				num_streams, v_total_min,
381*b843c749SSergey Zigachev 				v_total_max);
382*b843c749SSergey Zigachev }
383*b843c749SSergey Zigachev 
384*b843c749SSergey Zigachev 
update_stream_freesync_context(struct core_freesync * core_freesync,struct dc_stream_state * stream)385*b843c749SSergey Zigachev static void update_stream_freesync_context(struct core_freesync *core_freesync,
386*b843c749SSergey Zigachev 		struct dc_stream_state *stream)
387*b843c749SSergey Zigachev {
388*b843c749SSergey Zigachev 	unsigned int index;
389*b843c749SSergey Zigachev 	struct freesync_context *ctx;
390*b843c749SSergey Zigachev 
391*b843c749SSergey Zigachev 	ctx = &stream->freesync_ctx;
392*b843c749SSergey Zigachev 
393*b843c749SSergey Zigachev 	index = map_index_from_stream(core_freesync, stream);
394*b843c749SSergey Zigachev 
395*b843c749SSergey Zigachev 	ctx->supported = core_freesync->map[index].caps->supported;
396*b843c749SSergey Zigachev 	ctx->enabled = (core_freesync->map[index].user_enable.enable_for_gaming ||
397*b843c749SSergey Zigachev 		core_freesync->map[index].user_enable.enable_for_video ||
398*b843c749SSergey Zigachev 		core_freesync->map[index].user_enable.enable_for_static);
399*b843c749SSergey Zigachev 	ctx->active = (core_freesync->map[index].state.fullscreen ||
400*b843c749SSergey Zigachev 		core_freesync->map[index].state.video ||
401*b843c749SSergey Zigachev 		core_freesync->map[index].state.static_ramp.ramp_is_active);
402*b843c749SSergey Zigachev 	ctx->min_refresh_in_micro_hz =
403*b843c749SSergey Zigachev 			core_freesync->map[index].caps->min_refresh_in_micro_hz;
404*b843c749SSergey Zigachev 	ctx->nominal_refresh_in_micro_hz = core_freesync->
405*b843c749SSergey Zigachev 		map[index].state.nominal_refresh_rate_in_micro_hz;
406*b843c749SSergey Zigachev 
407*b843c749SSergey Zigachev }
408*b843c749SSergey Zigachev 
update_stream(struct core_freesync * core_freesync,struct dc_stream_state * stream)409*b843c749SSergey Zigachev static void update_stream(struct core_freesync *core_freesync,
410*b843c749SSergey Zigachev 		struct dc_stream_state *stream)
411*b843c749SSergey Zigachev {
412*b843c749SSergey Zigachev 	unsigned int index = map_index_from_stream(core_freesync, stream);
413*b843c749SSergey Zigachev 	if (core_freesync->map[index].caps->supported) {
414*b843c749SSergey Zigachev 		stream->ignore_msa_timing_param = 1;
415*b843c749SSergey Zigachev 		update_stream_freesync_context(core_freesync, stream);
416*b843c749SSergey Zigachev 	}
417*b843c749SSergey Zigachev }
418*b843c749SSergey Zigachev 
calc_freesync_range(struct core_freesync * core_freesync,struct dc_stream_state * stream,struct freesync_state * state,unsigned int min_refresh_in_uhz,unsigned int max_refresh_in_uhz)419*b843c749SSergey Zigachev static void calc_freesync_range(struct core_freesync *core_freesync,
420*b843c749SSergey Zigachev 		struct dc_stream_state *stream,
421*b843c749SSergey Zigachev 		struct freesync_state *state,
422*b843c749SSergey Zigachev 		unsigned int min_refresh_in_uhz,
423*b843c749SSergey Zigachev 		unsigned int max_refresh_in_uhz)
424*b843c749SSergey Zigachev {
425*b843c749SSergey Zigachev 	unsigned int min_frame_duration_in_ns = 0, max_frame_duration_in_ns = 0;
426*b843c749SSergey Zigachev 	unsigned int index = map_index_from_stream(core_freesync, stream);
427*b843c749SSergey Zigachev 	uint32_t vtotal = stream->timing.v_total;
428*b843c749SSergey Zigachev 
429*b843c749SSergey Zigachev 	if ((min_refresh_in_uhz == 0) || (max_refresh_in_uhz == 0)) {
430*b843c749SSergey Zigachev 		state->freesync_range.min_refresh =
431*b843c749SSergey Zigachev 				state->nominal_refresh_rate_in_micro_hz;
432*b843c749SSergey Zigachev 		state->freesync_range.max_refresh =
433*b843c749SSergey Zigachev 				state->nominal_refresh_rate_in_micro_hz;
434*b843c749SSergey Zigachev 
435*b843c749SSergey Zigachev 		state->freesync_range.max_frame_duration = 0;
436*b843c749SSergey Zigachev 		state->freesync_range.min_frame_duration = 0;
437*b843c749SSergey Zigachev 
438*b843c749SSergey Zigachev 		state->freesync_range.vmax = vtotal;
439*b843c749SSergey Zigachev 		state->freesync_range.vmin = vtotal;
440*b843c749SSergey Zigachev 
441*b843c749SSergey Zigachev 		return;
442*b843c749SSergey Zigachev 	}
443*b843c749SSergey Zigachev 
444*b843c749SSergey Zigachev 	min_frame_duration_in_ns = ((unsigned int) (div64_u64(
445*b843c749SSergey Zigachev 					(1000000000ULL * 1000000),
446*b843c749SSergey Zigachev 					max_refresh_in_uhz)));
447*b843c749SSergey Zigachev 	max_frame_duration_in_ns = ((unsigned int) (div64_u64(
448*b843c749SSergey Zigachev 		(1000000000ULL * 1000000),
449*b843c749SSergey Zigachev 		min_refresh_in_uhz)));
450*b843c749SSergey Zigachev 
451*b843c749SSergey Zigachev 	state->freesync_range.min_refresh = min_refresh_in_uhz;
452*b843c749SSergey Zigachev 	state->freesync_range.max_refresh = max_refresh_in_uhz;
453*b843c749SSergey Zigachev 
454*b843c749SSergey Zigachev 	state->freesync_range.max_frame_duration = max_frame_duration_in_ns;
455*b843c749SSergey Zigachev 	state->freesync_range.min_frame_duration = min_frame_duration_in_ns;
456*b843c749SSergey Zigachev 
457*b843c749SSergey Zigachev 	state->freesync_range.vmax = div64_u64(div64_u64(((unsigned long long)(
458*b843c749SSergey Zigachev 		max_frame_duration_in_ns) * stream->timing.pix_clk_khz),
459*b843c749SSergey Zigachev 		stream->timing.h_total), 1000000);
460*b843c749SSergey Zigachev 	state->freesync_range.vmin = div64_u64(div64_u64(((unsigned long long)(
461*b843c749SSergey Zigachev 		min_frame_duration_in_ns) * stream->timing.pix_clk_khz),
462*b843c749SSergey Zigachev 		stream->timing.h_total), 1000000);
463*b843c749SSergey Zigachev 
464*b843c749SSergey Zigachev 	/* vmin/vmax cannot be less than vtotal */
465*b843c749SSergey Zigachev 	if (state->freesync_range.vmin < vtotal) {
466*b843c749SSergey Zigachev 		/* Error of 1 is permissible */
467*b843c749SSergey Zigachev 		ASSERT((state->freesync_range.vmin + 1) >= vtotal);
468*b843c749SSergey Zigachev 		state->freesync_range.vmin = vtotal;
469*b843c749SSergey Zigachev 	}
470*b843c749SSergey Zigachev 
471*b843c749SSergey Zigachev 	if (state->freesync_range.vmax < vtotal) {
472*b843c749SSergey Zigachev 		/* Error of 1 is permissible */
473*b843c749SSergey Zigachev 		ASSERT((state->freesync_range.vmax + 1) >= vtotal);
474*b843c749SSergey Zigachev 		state->freesync_range.vmax = vtotal;
475*b843c749SSergey Zigachev 	}
476*b843c749SSergey Zigachev 
477*b843c749SSergey Zigachev 	/* Determine whether BTR can be supported */
478*b843c749SSergey Zigachev 	if (max_frame_duration_in_ns >=
479*b843c749SSergey Zigachev 			2 * min_frame_duration_in_ns)
480*b843c749SSergey Zigachev 		core_freesync->map[index].caps->btr_supported = true;
481*b843c749SSergey Zigachev 	else
482*b843c749SSergey Zigachev 		core_freesync->map[index].caps->btr_supported = false;
483*b843c749SSergey Zigachev 
484*b843c749SSergey Zigachev 	/* Cache the time variables */
485*b843c749SSergey Zigachev 	state->time.max_render_time_in_us =
486*b843c749SSergey Zigachev 		max_frame_duration_in_ns / 1000;
487*b843c749SSergey Zigachev 	state->time.min_render_time_in_us =
488*b843c749SSergey Zigachev 		min_frame_duration_in_ns / 1000;
489*b843c749SSergey Zigachev 	state->btr.mid_point_in_us =
490*b843c749SSergey Zigachev 		(max_frame_duration_in_ns +
491*b843c749SSergey Zigachev 		min_frame_duration_in_ns) / 2000;
492*b843c749SSergey Zigachev }
493*b843c749SSergey Zigachev 
calc_v_total_from_duration(struct dc_stream_state * stream,unsigned int duration_in_ns,int * v_total_nominal)494*b843c749SSergey Zigachev static void calc_v_total_from_duration(struct dc_stream_state *stream,
495*b843c749SSergey Zigachev 		unsigned int duration_in_ns, int *v_total_nominal)
496*b843c749SSergey Zigachev {
497*b843c749SSergey Zigachev 	*v_total_nominal = div64_u64(div64_u64(((unsigned long long)(
498*b843c749SSergey Zigachev 				duration_in_ns) * stream->timing.pix_clk_khz),
499*b843c749SSergey Zigachev 				stream->timing.h_total), 1000000);
500*b843c749SSergey Zigachev }
501*b843c749SSergey Zigachev 
calc_v_total_for_static_ramp(struct core_freesync * core_freesync,struct dc_stream_state * stream,unsigned int index,int * v_total)502*b843c749SSergey Zigachev static void calc_v_total_for_static_ramp(struct core_freesync *core_freesync,
503*b843c749SSergey Zigachev 		struct dc_stream_state *stream,
504*b843c749SSergey Zigachev 		unsigned int index, int *v_total)
505*b843c749SSergey Zigachev {
506*b843c749SSergey Zigachev 	unsigned int frame_duration = 0;
507*b843c749SSergey Zigachev 
508*b843c749SSergey Zigachev 	struct gradual_static_ramp *static_ramp_variables =
509*b843c749SSergey Zigachev 				&core_freesync->map[index].state.static_ramp;
510*b843c749SSergey Zigachev 
511*b843c749SSergey Zigachev 	/* Calc ratio between new and current frame duration with 3 digit */
512*b843c749SSergey Zigachev 	unsigned int frame_duration_ratio = div64_u64(1000000,
513*b843c749SSergey Zigachev 		(1000 +  div64_u64(((unsigned long long)(
514*b843c749SSergey Zigachev 		STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME) *
515*b843c749SSergey Zigachev 		static_ramp_variables->ramp_current_frame_duration_in_ns),
516*b843c749SSergey Zigachev 		1000000000)));
517*b843c749SSergey Zigachev 
518*b843c749SSergey Zigachev 	/* Calculate delta between new and current frame duration in ns */
519*b843c749SSergey Zigachev 	unsigned int frame_duration_delta = div64_u64(((unsigned long long)(
520*b843c749SSergey Zigachev 		static_ramp_variables->ramp_current_frame_duration_in_ns) *
521*b843c749SSergey Zigachev 		(1000 - frame_duration_ratio)), 1000);
522*b843c749SSergey Zigachev 
523*b843c749SSergey Zigachev 	/* Adjust frame duration delta based on ratio between current and
524*b843c749SSergey Zigachev 	 * standard frame duration (frame duration at 60 Hz refresh rate).
525*b843c749SSergey Zigachev 	 */
526*b843c749SSergey Zigachev 	unsigned int ramp_rate_interpolated = div64_u64(((unsigned long long)(
527*b843c749SSergey Zigachev 		frame_duration_delta) * static_ramp_variables->
528*b843c749SSergey Zigachev 		ramp_current_frame_duration_in_ns), 16666666);
529*b843c749SSergey Zigachev 
530*b843c749SSergey Zigachev 	/* Going to a higher refresh rate (lower frame duration) */
531*b843c749SSergey Zigachev 	if (static_ramp_variables->ramp_direction_is_up) {
532*b843c749SSergey Zigachev 		/* reduce frame duration */
533*b843c749SSergey Zigachev 		static_ramp_variables->ramp_current_frame_duration_in_ns -=
534*b843c749SSergey Zigachev 			ramp_rate_interpolated;
535*b843c749SSergey Zigachev 
536*b843c749SSergey Zigachev 		/* min frame duration */
537*b843c749SSergey Zigachev 		frame_duration = ((unsigned int) (div64_u64(
538*b843c749SSergey Zigachev 			(1000000000ULL * 1000000),
539*b843c749SSergey Zigachev 			core_freesync->map[index].state.
540*b843c749SSergey Zigachev 			nominal_refresh_rate_in_micro_hz)));
541*b843c749SSergey Zigachev 
542*b843c749SSergey Zigachev 		/* adjust for frame duration below min */
543*b843c749SSergey Zigachev 		if (static_ramp_variables->ramp_current_frame_duration_in_ns <=
544*b843c749SSergey Zigachev 			frame_duration) {
545*b843c749SSergey Zigachev 
546*b843c749SSergey Zigachev 			static_ramp_variables->ramp_is_active = false;
547*b843c749SSergey Zigachev 			static_ramp_variables->
548*b843c749SSergey Zigachev 				ramp_current_frame_duration_in_ns =
549*b843c749SSergey Zigachev 				frame_duration;
550*b843c749SSergey Zigachev 		}
551*b843c749SSergey Zigachev 	/* Going to a lower refresh rate (larger frame duration) */
552*b843c749SSergey Zigachev 	} else {
553*b843c749SSergey Zigachev 		/* increase frame duration */
554*b843c749SSergey Zigachev 		static_ramp_variables->ramp_current_frame_duration_in_ns +=
555*b843c749SSergey Zigachev 			ramp_rate_interpolated;
556*b843c749SSergey Zigachev 
557*b843c749SSergey Zigachev 		/* max frame duration */
558*b843c749SSergey Zigachev 		frame_duration = ((unsigned int) (div64_u64(
559*b843c749SSergey Zigachev 			(1000000000ULL * 1000000),
560*b843c749SSergey Zigachev 			core_freesync->map[index].caps->min_refresh_in_micro_hz)));
561*b843c749SSergey Zigachev 
562*b843c749SSergey Zigachev 		/* adjust for frame duration above max */
563*b843c749SSergey Zigachev 		if (static_ramp_variables->ramp_current_frame_duration_in_ns >=
564*b843c749SSergey Zigachev 			frame_duration) {
565*b843c749SSergey Zigachev 
566*b843c749SSergey Zigachev 			static_ramp_variables->ramp_is_active = false;
567*b843c749SSergey Zigachev 			static_ramp_variables->
568*b843c749SSergey Zigachev 				ramp_current_frame_duration_in_ns =
569*b843c749SSergey Zigachev 				frame_duration;
570*b843c749SSergey Zigachev 		}
571*b843c749SSergey Zigachev 	}
572*b843c749SSergey Zigachev 
573*b843c749SSergey Zigachev 	calc_v_total_from_duration(stream, static_ramp_variables->
574*b843c749SSergey Zigachev 		ramp_current_frame_duration_in_ns, v_total);
575*b843c749SSergey Zigachev }
576*b843c749SSergey Zigachev 
reset_freesync_state_variables(struct freesync_state * state)577*b843c749SSergey Zigachev static void reset_freesync_state_variables(struct freesync_state* state)
578*b843c749SSergey Zigachev {
579*b843c749SSergey Zigachev 	state->static_ramp.ramp_is_active = false;
580*b843c749SSergey Zigachev 	if (state->nominal_refresh_rate_in_micro_hz)
581*b843c749SSergey Zigachev 		state->static_ramp.ramp_current_frame_duration_in_ns =
582*b843c749SSergey Zigachev 			((unsigned int) (div64_u64(
583*b843c749SSergey Zigachev 			(1000000000ULL * 1000000),
584*b843c749SSergey Zigachev 			state->nominal_refresh_rate_in_micro_hz)));
585*b843c749SSergey Zigachev 
586*b843c749SSergey Zigachev 	state->btr.btr_active = false;
587*b843c749SSergey Zigachev 	state->btr.frame_counter = 0;
588*b843c749SSergey Zigachev 	state->btr.frames_to_insert = 0;
589*b843c749SSergey Zigachev 	state->btr.inserted_frame_duration_in_us = 0;
590*b843c749SSergey Zigachev 	state->btr.program_btr = false;
591*b843c749SSergey Zigachev 
592*b843c749SSergey Zigachev 	state->fixed_refresh.fixed_active = false;
593*b843c749SSergey Zigachev 	state->fixed_refresh.program_fixed = false;
594*b843c749SSergey Zigachev }
595*b843c749SSergey Zigachev /*
596*b843c749SSergey Zigachev  * Sets freesync mode on a stream depending on current freesync state.
597*b843c749SSergey Zigachev  */
set_freesync_on_streams(struct core_freesync * core_freesync,struct dc_stream_state ** streams,int num_streams)598*b843c749SSergey Zigachev static bool set_freesync_on_streams(struct core_freesync *core_freesync,
599*b843c749SSergey Zigachev 		struct dc_stream_state **streams, int num_streams)
600*b843c749SSergey Zigachev {
601*b843c749SSergey Zigachev 	int v_total_nominal = 0, v_total_min = 0, v_total_max = 0;
602*b843c749SSergey Zigachev 	unsigned int stream_idx, map_index = 0;
603*b843c749SSergey Zigachev 	struct freesync_state *state;
604*b843c749SSergey Zigachev 
605*b843c749SSergey Zigachev 	if (num_streams == 0 || streams == NULL || num_streams > 1)
606*b843c749SSergey Zigachev 		return false;
607*b843c749SSergey Zigachev 
608*b843c749SSergey Zigachev 	for (stream_idx = 0; stream_idx < num_streams; stream_idx++) {
609*b843c749SSergey Zigachev 
610*b843c749SSergey Zigachev 		map_index = map_index_from_stream(core_freesync,
611*b843c749SSergey Zigachev 				streams[stream_idx]);
612*b843c749SSergey Zigachev 
613*b843c749SSergey Zigachev 		state = &core_freesync->map[map_index].state;
614*b843c749SSergey Zigachev 
615*b843c749SSergey Zigachev 		if (core_freesync->map[map_index].caps->supported) {
616*b843c749SSergey Zigachev 
617*b843c749SSergey Zigachev 			/* Fullscreen has the topmost priority. If the
618*b843c749SSergey Zigachev 			 * fullscreen bit is set, we are in a fullscreen
619*b843c749SSergey Zigachev 			 * application where it should not matter if it is
620*b843c749SSergey Zigachev 			 * static screen. We should not check the static_screen
621*b843c749SSergey Zigachev 			 * or video bit.
622*b843c749SSergey Zigachev 			 *
623*b843c749SSergey Zigachev 			 * Special cases of fullscreen include btr and fixed
624*b843c749SSergey Zigachev 			 * refresh. We program btr on every flip and involves
625*b843c749SSergey Zigachev 			 * programming full range right before the last inserted frame.
626*b843c749SSergey Zigachev 			 * However, we do not want to program the full freesync range
627*b843c749SSergey Zigachev 			 * when fixed refresh is active, because we only program
628*b843c749SSergey Zigachev 			 * that logic once and this will override it.
629*b843c749SSergey Zigachev 			 */
630*b843c749SSergey Zigachev 			if (core_freesync->map[map_index].user_enable.
631*b843c749SSergey Zigachev 				enable_for_gaming == true &&
632*b843c749SSergey Zigachev 				state->fullscreen == true &&
633*b843c749SSergey Zigachev 				state->fixed_refresh.fixed_active == false) {
634*b843c749SSergey Zigachev 				/* Enable freesync */
635*b843c749SSergey Zigachev 
636*b843c749SSergey Zigachev 				v_total_min = state->freesync_range.vmin;
637*b843c749SSergey Zigachev 				v_total_max = state->freesync_range.vmax;
638*b843c749SSergey Zigachev 
639*b843c749SSergey Zigachev 				/* Update the freesync context for the stream */
640*b843c749SSergey Zigachev 				update_stream_freesync_context(core_freesync,
641*b843c749SSergey Zigachev 						streams[stream_idx]);
642*b843c749SSergey Zigachev 
643*b843c749SSergey Zigachev 				adjust_vmin_vmax(core_freesync, streams,
644*b843c749SSergey Zigachev 						num_streams, map_index,
645*b843c749SSergey Zigachev 						v_total_min,
646*b843c749SSergey Zigachev 						v_total_max);
647*b843c749SSergey Zigachev 
648*b843c749SSergey Zigachev 				return true;
649*b843c749SSergey Zigachev 
650*b843c749SSergey Zigachev 			} else if (core_freesync->map[map_index].user_enable.
651*b843c749SSergey Zigachev 				enable_for_video && state->video == true) {
652*b843c749SSergey Zigachev 				/* Enable 48Hz feature */
653*b843c749SSergey Zigachev 
654*b843c749SSergey Zigachev 				calc_v_total_from_duration(streams[stream_idx],
655*b843c749SSergey Zigachev 					state->time.update_duration_in_ns,
656*b843c749SSergey Zigachev 					&v_total_nominal);
657*b843c749SSergey Zigachev 
658*b843c749SSergey Zigachev 				/* Program only if v_total_nominal is in range*/
659*b843c749SSergey Zigachev 				if (v_total_nominal >=
660*b843c749SSergey Zigachev 					streams[stream_idx]->timing.v_total) {
661*b843c749SSergey Zigachev 
662*b843c749SSergey Zigachev 					/* Update the freesync context for
663*b843c749SSergey Zigachev 					 * the stream
664*b843c749SSergey Zigachev 					 */
665*b843c749SSergey Zigachev 					update_stream_freesync_context(
666*b843c749SSergey Zigachev 						core_freesync,
667*b843c749SSergey Zigachev 						streams[stream_idx]);
668*b843c749SSergey Zigachev 
669*b843c749SSergey Zigachev 					adjust_vmin_vmax(
670*b843c749SSergey Zigachev 						core_freesync, streams,
671*b843c749SSergey Zigachev 						num_streams, map_index,
672*b843c749SSergey Zigachev 						v_total_nominal,
673*b843c749SSergey Zigachev 						v_total_nominal);
674*b843c749SSergey Zigachev 				}
675*b843c749SSergey Zigachev 				return true;
676*b843c749SSergey Zigachev 
677*b843c749SSergey Zigachev 			} else {
678*b843c749SSergey Zigachev 				/* Disable freesync */
679*b843c749SSergey Zigachev 				v_total_nominal = streams[stream_idx]->
680*b843c749SSergey Zigachev 					timing.v_total;
681*b843c749SSergey Zigachev 
682*b843c749SSergey Zigachev 				/* Update the freesync context for
683*b843c749SSergey Zigachev 				 * the stream
684*b843c749SSergey Zigachev 				 */
685*b843c749SSergey Zigachev 				update_stream_freesync_context(
686*b843c749SSergey Zigachev 					core_freesync,
687*b843c749SSergey Zigachev 					streams[stream_idx]);
688*b843c749SSergey Zigachev 
689*b843c749SSergey Zigachev 				adjust_vmin_vmax(core_freesync, streams,
690*b843c749SSergey Zigachev 						num_streams, map_index,
691*b843c749SSergey Zigachev 						v_total_nominal,
692*b843c749SSergey Zigachev 						v_total_nominal);
693*b843c749SSergey Zigachev 
694*b843c749SSergey Zigachev 				/* Reset the cached variables */
695*b843c749SSergey Zigachev 				reset_freesync_state_variables(state);
696*b843c749SSergey Zigachev 
697*b843c749SSergey Zigachev 				return true;
698*b843c749SSergey Zigachev 			}
699*b843c749SSergey Zigachev 		} else {
700*b843c749SSergey Zigachev 			/* Disable freesync */
701*b843c749SSergey Zigachev 			v_total_nominal = streams[stream_idx]->
702*b843c749SSergey Zigachev 				timing.v_total;
703*b843c749SSergey Zigachev 			/*
704*b843c749SSergey Zigachev 			 * we have to reset drr always even sink does
705*b843c749SSergey Zigachev 			 * not support freesync because a former stream has
706*b843c749SSergey Zigachev 			 * be programmed
707*b843c749SSergey Zigachev 			 */
708*b843c749SSergey Zigachev 			adjust_vmin_vmax(core_freesync, streams,
709*b843c749SSergey Zigachev 						num_streams, map_index,
710*b843c749SSergey Zigachev 						v_total_nominal,
711*b843c749SSergey Zigachev 						v_total_nominal);
712*b843c749SSergey Zigachev 			/* Reset the cached variables */
713*b843c749SSergey Zigachev 			reset_freesync_state_variables(state);
714*b843c749SSergey Zigachev 		}
715*b843c749SSergey Zigachev 
716*b843c749SSergey Zigachev 	}
717*b843c749SSergey Zigachev 
718*b843c749SSergey Zigachev 	return false;
719*b843c749SSergey Zigachev }
720*b843c749SSergey Zigachev 
set_static_ramp_variables(struct core_freesync * core_freesync,unsigned int index,bool enable_static_screen)721*b843c749SSergey Zigachev static void set_static_ramp_variables(struct core_freesync *core_freesync,
722*b843c749SSergey Zigachev 		unsigned int index, bool enable_static_screen)
723*b843c749SSergey Zigachev {
724*b843c749SSergey Zigachev 	unsigned int frame_duration = 0;
725*b843c749SSergey Zigachev 	unsigned int nominal_refresh_rate = core_freesync->map[index].state.
726*b843c749SSergey Zigachev 			nominal_refresh_rate_in_micro_hz;
727*b843c749SSergey Zigachev 	unsigned int min_refresh_rate= core_freesync->map[index].caps->
728*b843c749SSergey Zigachev 			min_refresh_in_micro_hz;
729*b843c749SSergey Zigachev 	struct gradual_static_ramp *static_ramp_variables =
730*b843c749SSergey Zigachev 			&core_freesync->map[index].state.static_ramp;
731*b843c749SSergey Zigachev 
732*b843c749SSergey Zigachev 	/* If we are ENABLING static screen, refresh rate should go DOWN.
733*b843c749SSergey Zigachev 	 * If we are DISABLING static screen, refresh rate should go UP.
734*b843c749SSergey Zigachev 	 */
735*b843c749SSergey Zigachev 	if (enable_static_screen)
736*b843c749SSergey Zigachev 		static_ramp_variables->ramp_direction_is_up = false;
737*b843c749SSergey Zigachev 	else
738*b843c749SSergey Zigachev 		static_ramp_variables->ramp_direction_is_up = true;
739*b843c749SSergey Zigachev 
740*b843c749SSergey Zigachev 	/* If ramp is not active, set initial frame duration depending on
741*b843c749SSergey Zigachev 	 * whether we are enabling/disabling static screen mode. If the ramp is
742*b843c749SSergey Zigachev 	 * already active, ramp should continue in the opposite direction
743*b843c749SSergey Zigachev 	 * starting with the current frame duration
744*b843c749SSergey Zigachev 	 */
745*b843c749SSergey Zigachev 	if (!static_ramp_variables->ramp_is_active) {
746*b843c749SSergey Zigachev 		if (enable_static_screen == true) {
747*b843c749SSergey Zigachev 			/* Going to lower refresh rate, so start from max
748*b843c749SSergey Zigachev 			 * refresh rate (min frame duration)
749*b843c749SSergey Zigachev 			 */
750*b843c749SSergey Zigachev 			frame_duration = ((unsigned int) (div64_u64(
751*b843c749SSergey Zigachev 				(1000000000ULL * 1000000),
752*b843c749SSergey Zigachev 				nominal_refresh_rate)));
753*b843c749SSergey Zigachev 		} else {
754*b843c749SSergey Zigachev 			/* Going to higher refresh rate, so start from min
755*b843c749SSergey Zigachev 			 * refresh rate (max frame duration)
756*b843c749SSergey Zigachev 			 */
757*b843c749SSergey Zigachev 			frame_duration = ((unsigned int) (div64_u64(
758*b843c749SSergey Zigachev 				(1000000000ULL * 1000000),
759*b843c749SSergey Zigachev 				min_refresh_rate)));
760*b843c749SSergey Zigachev 		}
761*b843c749SSergey Zigachev 		static_ramp_variables->
762*b843c749SSergey Zigachev 			ramp_current_frame_duration_in_ns = frame_duration;
763*b843c749SSergey Zigachev 
764*b843c749SSergey Zigachev 		static_ramp_variables->ramp_is_active = true;
765*b843c749SSergey Zigachev 	}
766*b843c749SSergey Zigachev }
767*b843c749SSergey Zigachev 
mod_freesync_handle_v_update(struct mod_freesync * mod_freesync,struct dc_stream_state ** streams,int num_streams)768*b843c749SSergey Zigachev void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync,
769*b843c749SSergey Zigachev 		struct dc_stream_state **streams, int num_streams)
770*b843c749SSergey Zigachev {
771*b843c749SSergey Zigachev 	unsigned int index, v_total, inserted_frame_v_total = 0;
772*b843c749SSergey Zigachev 	unsigned int min_frame_duration_in_ns, vmax, vmin = 0;
773*b843c749SSergey Zigachev 	struct freesync_state *state;
774*b843c749SSergey Zigachev 	struct core_freesync *core_freesync = NULL;
775*b843c749SSergey Zigachev 	struct dc_static_screen_events triggers = {0};
776*b843c749SSergey Zigachev 
777*b843c749SSergey Zigachev 	if (mod_freesync == NULL)
778*b843c749SSergey Zigachev 		return;
779*b843c749SSergey Zigachev 
780*b843c749SSergey Zigachev 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
781*b843c749SSergey Zigachev 
782*b843c749SSergey Zigachev 	if (core_freesync->num_entities == 0)
783*b843c749SSergey Zigachev 		return;
784*b843c749SSergey Zigachev 
785*b843c749SSergey Zigachev 	index = map_index_from_stream(core_freesync,
786*b843c749SSergey Zigachev 		streams[0]);
787*b843c749SSergey Zigachev 
788*b843c749SSergey Zigachev 	if (core_freesync->map[index].caps->supported == false)
789*b843c749SSergey Zigachev 		return;
790*b843c749SSergey Zigachev 
791*b843c749SSergey Zigachev 	state = &core_freesync->map[index].state;
792*b843c749SSergey Zigachev 
793*b843c749SSergey Zigachev 	/* Below the Range Logic */
794*b843c749SSergey Zigachev 
795*b843c749SSergey Zigachev 	/* Only execute if in fullscreen mode */
796*b843c749SSergey Zigachev 	if (state->fullscreen == true &&
797*b843c749SSergey Zigachev 		core_freesync->map[index].user_enable.enable_for_gaming &&
798*b843c749SSergey Zigachev 		core_freesync->map[index].caps->btr_supported &&
799*b843c749SSergey Zigachev 		state->btr.btr_active) {
800*b843c749SSergey Zigachev 
801*b843c749SSergey Zigachev 		/* TODO: pass in flag for Pre-DCE12 ASIC
802*b843c749SSergey Zigachev 		 * in order for frame variable duration to take affect,
803*b843c749SSergey Zigachev 		 * it needs to be done one VSYNC early, which is at
804*b843c749SSergey Zigachev 		 * frameCounter == 1.
805*b843c749SSergey Zigachev 		 * For DCE12 and newer updates to V_TOTAL_MIN/MAX
806*b843c749SSergey Zigachev 		 * will take affect on current frame
807*b843c749SSergey Zigachev 		 */
808*b843c749SSergey Zigachev 		if (state->btr.frames_to_insert == state->btr.frame_counter) {
809*b843c749SSergey Zigachev 
810*b843c749SSergey Zigachev 			min_frame_duration_in_ns = ((unsigned int) (div64_u64(
811*b843c749SSergey Zigachev 					(1000000000ULL * 1000000),
812*b843c749SSergey Zigachev 					state->nominal_refresh_rate_in_micro_hz)));
813*b843c749SSergey Zigachev 
814*b843c749SSergey Zigachev 			vmin = state->freesync_range.vmin;
815*b843c749SSergey Zigachev 
816*b843c749SSergey Zigachev 			inserted_frame_v_total = vmin;
817*b843c749SSergey Zigachev 
818*b843c749SSergey Zigachev 			if (min_frame_duration_in_ns / 1000)
819*b843c749SSergey Zigachev 				inserted_frame_v_total =
820*b843c749SSergey Zigachev 					state->btr.inserted_frame_duration_in_us *
821*b843c749SSergey Zigachev 					vmin / (min_frame_duration_in_ns / 1000);
822*b843c749SSergey Zigachev 
823*b843c749SSergey Zigachev 			/* Set length of inserted frames as v_total_max*/
824*b843c749SSergey Zigachev 			vmax = inserted_frame_v_total;
825*b843c749SSergey Zigachev 			vmin = inserted_frame_v_total;
826*b843c749SSergey Zigachev 
827*b843c749SSergey Zigachev 			/* Program V_TOTAL */
828*b843c749SSergey Zigachev 			adjust_vmin_vmax(core_freesync, streams,
829*b843c749SSergey Zigachev 						num_streams, index,
830*b843c749SSergey Zigachev 						vmin, vmax);
831*b843c749SSergey Zigachev 		}
832*b843c749SSergey Zigachev 
833*b843c749SSergey Zigachev 		if (state->btr.frame_counter > 0)
834*b843c749SSergey Zigachev 			state->btr.frame_counter--;
835*b843c749SSergey Zigachev 
836*b843c749SSergey Zigachev 		/* Restore FreeSync */
837*b843c749SSergey Zigachev 		if (state->btr.frame_counter == 0)
838*b843c749SSergey Zigachev 			set_freesync_on_streams(core_freesync, streams, num_streams);
839*b843c749SSergey Zigachev 	}
840*b843c749SSergey Zigachev 
841*b843c749SSergey Zigachev 	/* If in fullscreen freesync mode or in video, do not program
842*b843c749SSergey Zigachev 	 * static screen ramp values
843*b843c749SSergey Zigachev 	 */
844*b843c749SSergey Zigachev 	if (state->fullscreen == true || state->video == true) {
845*b843c749SSergey Zigachev 
846*b843c749SSergey Zigachev 		state->static_ramp.ramp_is_active = false;
847*b843c749SSergey Zigachev 
848*b843c749SSergey Zigachev 		return;
849*b843c749SSergey Zigachev 	}
850*b843c749SSergey Zigachev 
851*b843c749SSergey Zigachev 	/* Gradual Static Screen Ramping Logic */
852*b843c749SSergey Zigachev 
853*b843c749SSergey Zigachev 	/* Execute if ramp is active and user enabled freesync static screen*/
854*b843c749SSergey Zigachev 	if (state->static_ramp.ramp_is_active &&
855*b843c749SSergey Zigachev 		core_freesync->map[index].user_enable.enable_for_static) {
856*b843c749SSergey Zigachev 
857*b843c749SSergey Zigachev 		calc_v_total_for_static_ramp(core_freesync, streams[0],
858*b843c749SSergey Zigachev 				index, &v_total);
859*b843c749SSergey Zigachev 
860*b843c749SSergey Zigachev 		/* Update the freesync context for the stream */
861*b843c749SSergey Zigachev 		update_stream_freesync_context(core_freesync, streams[0]);
862*b843c749SSergey Zigachev 
863*b843c749SSergey Zigachev 		/* Program static screen ramp values */
864*b843c749SSergey Zigachev 		adjust_vmin_vmax(core_freesync, streams,
865*b843c749SSergey Zigachev 					num_streams, index,
866*b843c749SSergey Zigachev 					v_total,
867*b843c749SSergey Zigachev 					v_total);
868*b843c749SSergey Zigachev 
869*b843c749SSergey Zigachev 		triggers.overlay_update = true;
870*b843c749SSergey Zigachev 		triggers.surface_update = true;
871*b843c749SSergey Zigachev 
872*b843c749SSergey Zigachev 		dc_stream_set_static_screen_events(core_freesync->dc, streams,
873*b843c749SSergey Zigachev 						   num_streams, &triggers);
874*b843c749SSergey Zigachev 	}
875*b843c749SSergey Zigachev }
876*b843c749SSergey Zigachev 
mod_freesync_update_state(struct mod_freesync * mod_freesync,struct dc_stream_state ** streams,int num_streams,struct mod_freesync_params * freesync_params)877*b843c749SSergey Zigachev void mod_freesync_update_state(struct mod_freesync *mod_freesync,
878*b843c749SSergey Zigachev 		struct dc_stream_state **streams, int num_streams,
879*b843c749SSergey Zigachev 		struct mod_freesync_params *freesync_params)
880*b843c749SSergey Zigachev {
881*b843c749SSergey Zigachev 	bool freesync_program_required = false;
882*b843c749SSergey Zigachev 	unsigned int stream_index;
883*b843c749SSergey Zigachev 	struct freesync_state *state;
884*b843c749SSergey Zigachev 	struct core_freesync *core_freesync = NULL;
885*b843c749SSergey Zigachev 	struct dc_static_screen_events triggers = {0};
886*b843c749SSergey Zigachev 
887*b843c749SSergey Zigachev 	if (mod_freesync == NULL)
888*b843c749SSergey Zigachev 		return;
889*b843c749SSergey Zigachev 
890*b843c749SSergey Zigachev 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
891*b843c749SSergey Zigachev 
892*b843c749SSergey Zigachev 	if (core_freesync->num_entities == 0)
893*b843c749SSergey Zigachev 		return;
894*b843c749SSergey Zigachev 
895*b843c749SSergey Zigachev 	for(stream_index = 0; stream_index < num_streams; stream_index++) {
896*b843c749SSergey Zigachev 
897*b843c749SSergey Zigachev 		unsigned int map_index = map_index_from_stream(core_freesync,
898*b843c749SSergey Zigachev 				streams[stream_index]);
899*b843c749SSergey Zigachev 
900*b843c749SSergey Zigachev 		bool is_embedded = dc_is_embedded_signal(
901*b843c749SSergey Zigachev 				streams[stream_index]->sink->sink_signal);
902*b843c749SSergey Zigachev 
903*b843c749SSergey Zigachev 		struct freesync_registry_options *opts = &core_freesync->opts;
904*b843c749SSergey Zigachev 
905*b843c749SSergey Zigachev 		state = &core_freesync->map[map_index].state;
906*b843c749SSergey Zigachev 
907*b843c749SSergey Zigachev 		switch (freesync_params->state){
908*b843c749SSergey Zigachev 		case FREESYNC_STATE_FULLSCREEN:
909*b843c749SSergey Zigachev 			state->fullscreen = freesync_params->enable;
910*b843c749SSergey Zigachev 			freesync_program_required = true;
911*b843c749SSergey Zigachev 			state->windowed_fullscreen =
912*b843c749SSergey Zigachev 					freesync_params->windowed_fullscreen;
913*b843c749SSergey Zigachev 			break;
914*b843c749SSergey Zigachev 		case FREESYNC_STATE_STATIC_SCREEN:
915*b843c749SSergey Zigachev 			/* Static screen ramp is disabled by default, but can
916*b843c749SSergey Zigachev 			 * be enabled through regkey.
917*b843c749SSergey Zigachev 			 */
918*b843c749SSergey Zigachev 			if ((is_embedded && opts->drr_internal_supported) ||
919*b843c749SSergey Zigachev 				(!is_embedded && opts->drr_external_supported))
920*b843c749SSergey Zigachev 
921*b843c749SSergey Zigachev 				if (state->static_screen !=
922*b843c749SSergey Zigachev 						freesync_params->enable) {
923*b843c749SSergey Zigachev 
924*b843c749SSergey Zigachev 					/* Change the state flag */
925*b843c749SSergey Zigachev 					state->static_screen =
926*b843c749SSergey Zigachev 							freesync_params->enable;
927*b843c749SSergey Zigachev 
928*b843c749SSergey Zigachev 					/* Update static screen ramp */
929*b843c749SSergey Zigachev 					set_static_ramp_variables(core_freesync,
930*b843c749SSergey Zigachev 						map_index,
931*b843c749SSergey Zigachev 						freesync_params->enable);
932*b843c749SSergey Zigachev 				}
933*b843c749SSergey Zigachev 			/* We program the ramp starting next VUpdate */
934*b843c749SSergey Zigachev 			break;
935*b843c749SSergey Zigachev 		case FREESYNC_STATE_VIDEO:
936*b843c749SSergey Zigachev 			/* Change core variables only if there is a change*/
937*b843c749SSergey Zigachev 			if(freesync_params->update_duration_in_ns !=
938*b843c749SSergey Zigachev 				state->time.update_duration_in_ns) {
939*b843c749SSergey Zigachev 
940*b843c749SSergey Zigachev 				state->video = freesync_params->enable;
941*b843c749SSergey Zigachev 				state->time.update_duration_in_ns =
942*b843c749SSergey Zigachev 					freesync_params->update_duration_in_ns;
943*b843c749SSergey Zigachev 
944*b843c749SSergey Zigachev 				freesync_program_required = true;
945*b843c749SSergey Zigachev 			}
946*b843c749SSergey Zigachev 			break;
947*b843c749SSergey Zigachev 		case FREESYNC_STATE_NONE:
948*b843c749SSergey Zigachev 			/* handle here to avoid warning */
949*b843c749SSergey Zigachev 			break;
950*b843c749SSergey Zigachev 		}
951*b843c749SSergey Zigachev 	}
952*b843c749SSergey Zigachev 
953*b843c749SSergey Zigachev 	/* Update mask */
954*b843c749SSergey Zigachev 	triggers.overlay_update = true;
955*b843c749SSergey Zigachev 	triggers.surface_update = true;
956*b843c749SSergey Zigachev 
957*b843c749SSergey Zigachev 	dc_stream_set_static_screen_events(core_freesync->dc, streams,
958*b843c749SSergey Zigachev 					   num_streams, &triggers);
959*b843c749SSergey Zigachev 
960*b843c749SSergey Zigachev 	if (freesync_program_required)
961*b843c749SSergey Zigachev 		/* Program freesync according to current state*/
962*b843c749SSergey Zigachev 		set_freesync_on_streams(core_freesync, streams, num_streams);
963*b843c749SSergey Zigachev }
964*b843c749SSergey Zigachev 
965*b843c749SSergey Zigachev 
mod_freesync_get_state(struct mod_freesync * mod_freesync,struct dc_stream_state * stream,struct mod_freesync_params * freesync_params)966*b843c749SSergey Zigachev bool mod_freesync_get_state(struct mod_freesync *mod_freesync,
967*b843c749SSergey Zigachev 		struct dc_stream_state *stream,
968*b843c749SSergey Zigachev 		struct mod_freesync_params *freesync_params)
969*b843c749SSergey Zigachev {
970*b843c749SSergey Zigachev 	unsigned int index = 0;
971*b843c749SSergey Zigachev 	struct core_freesync *core_freesync = NULL;
972*b843c749SSergey Zigachev 
973*b843c749SSergey Zigachev 	if (mod_freesync == NULL)
974*b843c749SSergey Zigachev 		return false;
975*b843c749SSergey Zigachev 
976*b843c749SSergey Zigachev 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
977*b843c749SSergey Zigachev 	index = map_index_from_stream(core_freesync, stream);
978*b843c749SSergey Zigachev 
979*b843c749SSergey Zigachev 	if (core_freesync->map[index].state.fullscreen) {
980*b843c749SSergey Zigachev 		freesync_params->state = FREESYNC_STATE_FULLSCREEN;
981*b843c749SSergey Zigachev 		freesync_params->enable = true;
982*b843c749SSergey Zigachev 	} else if (core_freesync->map[index].state.static_screen) {
983*b843c749SSergey Zigachev 		freesync_params->state = FREESYNC_STATE_STATIC_SCREEN;
984*b843c749SSergey Zigachev 		freesync_params->enable = true;
985*b843c749SSergey Zigachev 	} else if (core_freesync->map[index].state.video) {
986*b843c749SSergey Zigachev 		freesync_params->state = FREESYNC_STATE_VIDEO;
987*b843c749SSergey Zigachev 		freesync_params->enable = true;
988*b843c749SSergey Zigachev 	} else {
989*b843c749SSergey Zigachev 		freesync_params->state = FREESYNC_STATE_NONE;
990*b843c749SSergey Zigachev 		freesync_params->enable = false;
991*b843c749SSergey Zigachev 	}
992*b843c749SSergey Zigachev 
993*b843c749SSergey Zigachev 	freesync_params->update_duration_in_ns =
994*b843c749SSergey Zigachev 		core_freesync->map[index].state.time.update_duration_in_ns;
995*b843c749SSergey Zigachev 
996*b843c749SSergey Zigachev 	freesync_params->windowed_fullscreen =
997*b843c749SSergey Zigachev 			core_freesync->map[index].state.windowed_fullscreen;
998*b843c749SSergey Zigachev 
999*b843c749SSergey Zigachev 	return true;
1000*b843c749SSergey Zigachev }
1001*b843c749SSergey Zigachev 
mod_freesync_set_user_enable(struct mod_freesync * mod_freesync,struct dc_stream_state ** streams,int num_streams,struct mod_freesync_user_enable * user_enable)1002*b843c749SSergey Zigachev bool mod_freesync_set_user_enable(struct mod_freesync *mod_freesync,
1003*b843c749SSergey Zigachev 		struct dc_stream_state **streams, int num_streams,
1004*b843c749SSergey Zigachev 		struct mod_freesync_user_enable *user_enable)
1005*b843c749SSergey Zigachev {
1006*b843c749SSergey Zigachev 	unsigned int stream_index, map_index;
1007*b843c749SSergey Zigachev 	int persistent_data = 0;
1008*b843c749SSergey Zigachev 	struct persistent_data_flag flag;
1009*b843c749SSergey Zigachev 	struct dc  *dc = NULL;
1010*b843c749SSergey Zigachev 	struct core_freesync *core_freesync = NULL;
1011*b843c749SSergey Zigachev 
1012*b843c749SSergey Zigachev 	if (mod_freesync == NULL)
1013*b843c749SSergey Zigachev 		return false;
1014*b843c749SSergey Zigachev 
1015*b843c749SSergey Zigachev 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1016*b843c749SSergey Zigachev 	dc = core_freesync->dc;
1017*b843c749SSergey Zigachev 
1018*b843c749SSergey Zigachev 	flag.save_per_edid = true;
1019*b843c749SSergey Zigachev 	flag.save_per_link = false;
1020*b843c749SSergey Zigachev 
1021*b843c749SSergey Zigachev 	for(stream_index = 0; stream_index < num_streams;
1022*b843c749SSergey Zigachev 			stream_index++){
1023*b843c749SSergey Zigachev 
1024*b843c749SSergey Zigachev 		map_index = map_index_from_stream(core_freesync,
1025*b843c749SSergey Zigachev 				streams[stream_index]);
1026*b843c749SSergey Zigachev 
1027*b843c749SSergey Zigachev 		core_freesync->map[map_index].user_enable = *user_enable;
1028*b843c749SSergey Zigachev 
1029*b843c749SSergey Zigachev 		/* Write persistent data in registry*/
1030*b843c749SSergey Zigachev 		if (core_freesync->map[map_index].user_enable.
1031*b843c749SSergey Zigachev 				enable_for_gaming)
1032*b843c749SSergey Zigachev 			persistent_data = persistent_data | 1;
1033*b843c749SSergey Zigachev 		if (core_freesync->map[map_index].user_enable.
1034*b843c749SSergey Zigachev 				enable_for_static)
1035*b843c749SSergey Zigachev 			persistent_data = persistent_data | 2;
1036*b843c749SSergey Zigachev 		if (core_freesync->map[map_index].user_enable.
1037*b843c749SSergey Zigachev 				enable_for_video)
1038*b843c749SSergey Zigachev 			persistent_data = persistent_data | 4;
1039*b843c749SSergey Zigachev 
1040*b843c749SSergey Zigachev 		dm_write_persistent_data(dc->ctx,
1041*b843c749SSergey Zigachev 					streams[stream_index]->sink,
1042*b843c749SSergey Zigachev 					FREESYNC_REGISTRY_NAME,
1043*b843c749SSergey Zigachev 					"userenable",
1044*b843c749SSergey Zigachev 					&persistent_data,
1045*b843c749SSergey Zigachev 					sizeof(int),
1046*b843c749SSergey Zigachev 					&flag);
1047*b843c749SSergey Zigachev 	}
1048*b843c749SSergey Zigachev 
1049*b843c749SSergey Zigachev 	set_freesync_on_streams(core_freesync, streams, num_streams);
1050*b843c749SSergey Zigachev 
1051*b843c749SSergey Zigachev 	return true;
1052*b843c749SSergey Zigachev }
1053*b843c749SSergey Zigachev 
mod_freesync_get_user_enable(struct mod_freesync * mod_freesync,struct dc_stream_state * stream,struct mod_freesync_user_enable * user_enable)1054*b843c749SSergey Zigachev bool mod_freesync_get_user_enable(struct mod_freesync *mod_freesync,
1055*b843c749SSergey Zigachev 		struct dc_stream_state *stream,
1056*b843c749SSergey Zigachev 		struct mod_freesync_user_enable *user_enable)
1057*b843c749SSergey Zigachev {
1058*b843c749SSergey Zigachev 	unsigned int index = 0;
1059*b843c749SSergey Zigachev 	struct core_freesync *core_freesync = NULL;
1060*b843c749SSergey Zigachev 
1061*b843c749SSergey Zigachev 	if (mod_freesync == NULL)
1062*b843c749SSergey Zigachev 		return false;
1063*b843c749SSergey Zigachev 
1064*b843c749SSergey Zigachev 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1065*b843c749SSergey Zigachev 	index = map_index_from_stream(core_freesync, stream);
1066*b843c749SSergey Zigachev 
1067*b843c749SSergey Zigachev 	*user_enable = core_freesync->map[index].user_enable;
1068*b843c749SSergey Zigachev 
1069*b843c749SSergey Zigachev 	return true;
1070*b843c749SSergey Zigachev }
1071*b843c749SSergey Zigachev 
mod_freesync_get_static_ramp_active(struct mod_freesync * mod_freesync,struct dc_stream_state * stream,bool * is_ramp_active)1072*b843c749SSergey Zigachev bool mod_freesync_get_static_ramp_active(struct mod_freesync *mod_freesync,
1073*b843c749SSergey Zigachev 		struct dc_stream_state *stream,
1074*b843c749SSergey Zigachev 		bool *is_ramp_active)
1075*b843c749SSergey Zigachev {
1076*b843c749SSergey Zigachev 	unsigned int index = 0;
1077*b843c749SSergey Zigachev 	struct core_freesync *core_freesync = NULL;
1078*b843c749SSergey Zigachev 
1079*b843c749SSergey Zigachev 	if (mod_freesync == NULL)
1080*b843c749SSergey Zigachev 		return false;
1081*b843c749SSergey Zigachev 
1082*b843c749SSergey Zigachev 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1083*b843c749SSergey Zigachev 	index = map_index_from_stream(core_freesync, stream);
1084*b843c749SSergey Zigachev 
1085*b843c749SSergey Zigachev 	*is_ramp_active =
1086*b843c749SSergey Zigachev 		core_freesync->map[index].state.static_ramp.ramp_is_active;
1087*b843c749SSergey Zigachev 
1088*b843c749SSergey Zigachev 	return true;
1089*b843c749SSergey Zigachev }
1090*b843c749SSergey Zigachev 
mod_freesync_override_min_max(struct mod_freesync * mod_freesync,struct dc_stream_state * streams,unsigned int min_refresh,unsigned int max_refresh,struct mod_freesync_caps * caps)1091*b843c749SSergey Zigachev bool mod_freesync_override_min_max(struct mod_freesync *mod_freesync,
1092*b843c749SSergey Zigachev 		struct dc_stream_state *streams,
1093*b843c749SSergey Zigachev 		unsigned int min_refresh,
1094*b843c749SSergey Zigachev 		unsigned int max_refresh,
1095*b843c749SSergey Zigachev 		struct mod_freesync_caps *caps)
1096*b843c749SSergey Zigachev {
1097*b843c749SSergey Zigachev 	unsigned int index = 0;
1098*b843c749SSergey Zigachev 	struct core_freesync *core_freesync;
1099*b843c749SSergey Zigachev 	struct freesync_state *state;
1100*b843c749SSergey Zigachev 
1101*b843c749SSergey Zigachev 	if (mod_freesync == NULL)
1102*b843c749SSergey Zigachev 		return false;
1103*b843c749SSergey Zigachev 
1104*b843c749SSergey Zigachev 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1105*b843c749SSergey Zigachev 	index = map_index_from_stream(core_freesync, streams);
1106*b843c749SSergey Zigachev 	state = &core_freesync->map[index].state;
1107*b843c749SSergey Zigachev 
1108*b843c749SSergey Zigachev 	if (max_refresh == 0)
1109*b843c749SSergey Zigachev 		max_refresh = state->nominal_refresh_rate_in_micro_hz;
1110*b843c749SSergey Zigachev 
1111*b843c749SSergey Zigachev 	if (min_refresh == 0) {
1112*b843c749SSergey Zigachev 		/* Restore defaults */
1113*b843c749SSergey Zigachev 		calc_freesync_range(core_freesync, streams, state,
1114*b843c749SSergey Zigachev 			core_freesync->map[index].caps->
1115*b843c749SSergey Zigachev 			min_refresh_in_micro_hz,
1116*b843c749SSergey Zigachev 			state->nominal_refresh_rate_in_micro_hz);
1117*b843c749SSergey Zigachev 	} else {
1118*b843c749SSergey Zigachev 		calc_freesync_range(core_freesync, streams,
1119*b843c749SSergey Zigachev 				state,
1120*b843c749SSergey Zigachev 				min_refresh,
1121*b843c749SSergey Zigachev 				max_refresh);
1122*b843c749SSergey Zigachev 
1123*b843c749SSergey Zigachev 		/* Program vtotal min/max */
1124*b843c749SSergey Zigachev 		adjust_vmin_vmax(core_freesync, &streams, 1, index,
1125*b843c749SSergey Zigachev 				state->freesync_range.vmin,
1126*b843c749SSergey Zigachev 				state->freesync_range.vmax);
1127*b843c749SSergey Zigachev 	}
1128*b843c749SSergey Zigachev 
1129*b843c749SSergey Zigachev 	if (min_refresh != 0 &&
1130*b843c749SSergey Zigachev 			dc_is_embedded_signal(streams->sink->sink_signal) &&
1131*b843c749SSergey Zigachev 			(max_refresh - min_refresh >= 10000000)) {
1132*b843c749SSergey Zigachev 		caps->supported = true;
1133*b843c749SSergey Zigachev 		caps->min_refresh_in_micro_hz = min_refresh;
1134*b843c749SSergey Zigachev 		caps->max_refresh_in_micro_hz = max_refresh;
1135*b843c749SSergey Zigachev 	}
1136*b843c749SSergey Zigachev 
1137*b843c749SSergey Zigachev 	/* Update the stream */
1138*b843c749SSergey Zigachev 	update_stream(core_freesync, streams);
1139*b843c749SSergey Zigachev 
1140*b843c749SSergey Zigachev 	return true;
1141*b843c749SSergey Zigachev }
1142*b843c749SSergey Zigachev 
mod_freesync_get_min_max(struct mod_freesync * mod_freesync,struct dc_stream_state * stream,unsigned int * min_refresh,unsigned int * max_refresh)1143*b843c749SSergey Zigachev bool mod_freesync_get_min_max(struct mod_freesync *mod_freesync,
1144*b843c749SSergey Zigachev 		struct dc_stream_state *stream,
1145*b843c749SSergey Zigachev 		unsigned int *min_refresh,
1146*b843c749SSergey Zigachev 		unsigned int *max_refresh)
1147*b843c749SSergey Zigachev {
1148*b843c749SSergey Zigachev 	unsigned int index = 0;
1149*b843c749SSergey Zigachev 	struct core_freesync *core_freesync = NULL;
1150*b843c749SSergey Zigachev 
1151*b843c749SSergey Zigachev 	if (mod_freesync == NULL)
1152*b843c749SSergey Zigachev 		return false;
1153*b843c749SSergey Zigachev 
1154*b843c749SSergey Zigachev 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1155*b843c749SSergey Zigachev 	index = map_index_from_stream(core_freesync, stream);
1156*b843c749SSergey Zigachev 
1157*b843c749SSergey Zigachev 	*min_refresh =
1158*b843c749SSergey Zigachev 		core_freesync->map[index].state.freesync_range.min_refresh;
1159*b843c749SSergey Zigachev 	*max_refresh =
1160*b843c749SSergey Zigachev 		core_freesync->map[index].state.freesync_range.max_refresh;
1161*b843c749SSergey Zigachev 
1162*b843c749SSergey Zigachev 	return true;
1163*b843c749SSergey Zigachev }
1164*b843c749SSergey Zigachev 
mod_freesync_get_vmin_vmax(struct mod_freesync * mod_freesync,struct dc_stream_state * stream,unsigned int * vmin,unsigned int * vmax)1165*b843c749SSergey Zigachev bool mod_freesync_get_vmin_vmax(struct mod_freesync *mod_freesync,
1166*b843c749SSergey Zigachev 		struct dc_stream_state *stream,
1167*b843c749SSergey Zigachev 		unsigned int *vmin,
1168*b843c749SSergey Zigachev 		unsigned int *vmax)
1169*b843c749SSergey Zigachev {
1170*b843c749SSergey Zigachev 	unsigned int index = 0;
1171*b843c749SSergey Zigachev 	struct core_freesync *core_freesync = NULL;
1172*b843c749SSergey Zigachev 
1173*b843c749SSergey Zigachev 	if (mod_freesync == NULL)
1174*b843c749SSergey Zigachev 		return false;
1175*b843c749SSergey Zigachev 
1176*b843c749SSergey Zigachev 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1177*b843c749SSergey Zigachev 	index = map_index_from_stream(core_freesync, stream);
1178*b843c749SSergey Zigachev 
1179*b843c749SSergey Zigachev 	*vmin =
1180*b843c749SSergey Zigachev 		core_freesync->map[index].state.freesync_range.vmin;
1181*b843c749SSergey Zigachev 	*vmax =
1182*b843c749SSergey Zigachev 		core_freesync->map[index].state.freesync_range.vmax;
1183*b843c749SSergey Zigachev 
1184*b843c749SSergey Zigachev 	return true;
1185*b843c749SSergey Zigachev }
1186*b843c749SSergey Zigachev 
mod_freesync_get_v_position(struct mod_freesync * mod_freesync,struct dc_stream_state * stream,unsigned int * nom_v_pos,unsigned int * v_pos)1187*b843c749SSergey Zigachev bool mod_freesync_get_v_position(struct mod_freesync *mod_freesync,
1188*b843c749SSergey Zigachev 		struct dc_stream_state *stream,
1189*b843c749SSergey Zigachev 		unsigned int *nom_v_pos,
1190*b843c749SSergey Zigachev 		unsigned int *v_pos)
1191*b843c749SSergey Zigachev {
1192*b843c749SSergey Zigachev 	unsigned int index = 0;
1193*b843c749SSergey Zigachev 	struct core_freesync *core_freesync = NULL;
1194*b843c749SSergey Zigachev 	struct crtc_position position;
1195*b843c749SSergey Zigachev 
1196*b843c749SSergey Zigachev 	if (mod_freesync == NULL)
1197*b843c749SSergey Zigachev 		return false;
1198*b843c749SSergey Zigachev 
1199*b843c749SSergey Zigachev 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1200*b843c749SSergey Zigachev 	index = map_index_from_stream(core_freesync, stream);
1201*b843c749SSergey Zigachev 
1202*b843c749SSergey Zigachev 	if (dc_stream_get_crtc_position(core_freesync->dc, &stream, 1,
1203*b843c749SSergey Zigachev 					&position.vertical_count,
1204*b843c749SSergey Zigachev 					&position.nominal_vcount)) {
1205*b843c749SSergey Zigachev 
1206*b843c749SSergey Zigachev 		*nom_v_pos = position.nominal_vcount;
1207*b843c749SSergey Zigachev 		*v_pos = position.vertical_count;
1208*b843c749SSergey Zigachev 
1209*b843c749SSergey Zigachev 		return true;
1210*b843c749SSergey Zigachev 	}
1211*b843c749SSergey Zigachev 
1212*b843c749SSergey Zigachev 	return false;
1213*b843c749SSergey Zigachev }
1214*b843c749SSergey Zigachev 
mod_freesync_notify_mode_change(struct mod_freesync * mod_freesync,struct dc_stream_state ** streams,int num_streams)1215*b843c749SSergey Zigachev void mod_freesync_notify_mode_change(struct mod_freesync *mod_freesync,
1216*b843c749SSergey Zigachev 		struct dc_stream_state **streams, int num_streams)
1217*b843c749SSergey Zigachev {
1218*b843c749SSergey Zigachev 	unsigned int stream_index, map_index;
1219*b843c749SSergey Zigachev 	struct freesync_state *state;
1220*b843c749SSergey Zigachev 	struct core_freesync *core_freesync = NULL;
1221*b843c749SSergey Zigachev 	struct dc_static_screen_events triggers = {0};
1222*b843c749SSergey Zigachev 	unsigned long long temp = 0;
1223*b843c749SSergey Zigachev 
1224*b843c749SSergey Zigachev 	if (mod_freesync == NULL)
1225*b843c749SSergey Zigachev 		return;
1226*b843c749SSergey Zigachev 
1227*b843c749SSergey Zigachev 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1228*b843c749SSergey Zigachev 
1229*b843c749SSergey Zigachev 	for (stream_index = 0; stream_index < num_streams; stream_index++) {
1230*b843c749SSergey Zigachev 		map_index = map_index_from_stream(core_freesync,
1231*b843c749SSergey Zigachev 				streams[stream_index]);
1232*b843c749SSergey Zigachev 
1233*b843c749SSergey Zigachev 		state = &core_freesync->map[map_index].state;
1234*b843c749SSergey Zigachev 
1235*b843c749SSergey Zigachev 		/* Update the field rate for new timing */
1236*b843c749SSergey Zigachev 		temp = streams[stream_index]->timing.pix_clk_khz;
1237*b843c749SSergey Zigachev 		temp *= 1000ULL * 1000ULL * 1000ULL;
1238*b843c749SSergey Zigachev 		temp = div_u64(temp,
1239*b843c749SSergey Zigachev 				streams[stream_index]->timing.h_total);
1240*b843c749SSergey Zigachev 		temp = div_u64(temp,
1241*b843c749SSergey Zigachev 				streams[stream_index]->timing.v_total);
1242*b843c749SSergey Zigachev 		state->nominal_refresh_rate_in_micro_hz =
1243*b843c749SSergey Zigachev 				(unsigned int) temp;
1244*b843c749SSergey Zigachev 
1245*b843c749SSergey Zigachev 		if (core_freesync->map[map_index].caps->supported) {
1246*b843c749SSergey Zigachev 
1247*b843c749SSergey Zigachev 			/* Update the stream */
1248*b843c749SSergey Zigachev 			update_stream(core_freesync, streams[stream_index]);
1249*b843c749SSergey Zigachev 
1250*b843c749SSergey Zigachev 			/* Calculate vmin/vmax and refresh rate for
1251*b843c749SSergey Zigachev 			 * current mode
1252*b843c749SSergey Zigachev 			 */
1253*b843c749SSergey Zigachev 			calc_freesync_range(core_freesync, *streams, state,
1254*b843c749SSergey Zigachev 				core_freesync->map[map_index].caps->
1255*b843c749SSergey Zigachev 				min_refresh_in_micro_hz,
1256*b843c749SSergey Zigachev 				state->nominal_refresh_rate_in_micro_hz);
1257*b843c749SSergey Zigachev 
1258*b843c749SSergey Zigachev 			/* Update mask */
1259*b843c749SSergey Zigachev 			triggers.overlay_update = true;
1260*b843c749SSergey Zigachev 			triggers.surface_update = true;
1261*b843c749SSergey Zigachev 
1262*b843c749SSergey Zigachev 			dc_stream_set_static_screen_events(core_freesync->dc,
1263*b843c749SSergey Zigachev 							   streams, num_streams,
1264*b843c749SSergey Zigachev 							   &triggers);
1265*b843c749SSergey Zigachev 		}
1266*b843c749SSergey Zigachev 	}
1267*b843c749SSergey Zigachev 
1268*b843c749SSergey Zigachev 	/* Program freesync according to current state*/
1269*b843c749SSergey Zigachev 	set_freesync_on_streams(core_freesync, streams, num_streams);
1270*b843c749SSergey Zigachev }
1271*b843c749SSergey Zigachev 
1272*b843c749SSergey Zigachev /* Add the timestamps to the cache and determine whether BTR programming
1273*b843c749SSergey Zigachev  * is required, depending on the times calculated
1274*b843c749SSergey Zigachev  */
update_timestamps(struct core_freesync * core_freesync,const struct dc_stream_state * stream,unsigned int map_index,unsigned int last_render_time_in_us)1275*b843c749SSergey Zigachev static void update_timestamps(struct core_freesync *core_freesync,
1276*b843c749SSergey Zigachev 		const struct dc_stream_state *stream, unsigned int map_index,
1277*b843c749SSergey Zigachev 		unsigned int last_render_time_in_us)
1278*b843c749SSergey Zigachev {
1279*b843c749SSergey Zigachev 	struct freesync_state *state = &core_freesync->map[map_index].state;
1280*b843c749SSergey Zigachev 
1281*b843c749SSergey Zigachev 	state->time.render_times[state->time.render_times_index] =
1282*b843c749SSergey Zigachev 			last_render_time_in_us;
1283*b843c749SSergey Zigachev 	state->time.render_times_index++;
1284*b843c749SSergey Zigachev 
1285*b843c749SSergey Zigachev 	if (state->time.render_times_index >= RENDER_TIMES_MAX_COUNT)
1286*b843c749SSergey Zigachev 		state->time.render_times_index = 0;
1287*b843c749SSergey Zigachev 
1288*b843c749SSergey Zigachev 	if (last_render_time_in_us + BTR_EXIT_MARGIN <
1289*b843c749SSergey Zigachev 		state->time.max_render_time_in_us) {
1290*b843c749SSergey Zigachev 
1291*b843c749SSergey Zigachev 		/* Exit Below the Range */
1292*b843c749SSergey Zigachev 		if (state->btr.btr_active) {
1293*b843c749SSergey Zigachev 
1294*b843c749SSergey Zigachev 			state->btr.program_btr = true;
1295*b843c749SSergey Zigachev 			state->btr.btr_active = false;
1296*b843c749SSergey Zigachev 			state->btr.frame_counter = 0;
1297*b843c749SSergey Zigachev 
1298*b843c749SSergey Zigachev 		/* Exit Fixed Refresh mode */
1299*b843c749SSergey Zigachev 		} else if (state->fixed_refresh.fixed_active) {
1300*b843c749SSergey Zigachev 
1301*b843c749SSergey Zigachev 			state->fixed_refresh.frame_counter++;
1302*b843c749SSergey Zigachev 
1303*b843c749SSergey Zigachev 			if (state->fixed_refresh.frame_counter >
1304*b843c749SSergey Zigachev 					FIXED_REFRESH_EXIT_FRAME_COUNT) {
1305*b843c749SSergey Zigachev 				state->fixed_refresh.frame_counter = 0;
1306*b843c749SSergey Zigachev 				state->fixed_refresh.program_fixed = true;
1307*b843c749SSergey Zigachev 				state->fixed_refresh.fixed_active = false;
1308*b843c749SSergey Zigachev 			}
1309*b843c749SSergey Zigachev 		}
1310*b843c749SSergey Zigachev 
1311*b843c749SSergey Zigachev 	} else if (last_render_time_in_us > state->time.max_render_time_in_us) {
1312*b843c749SSergey Zigachev 
1313*b843c749SSergey Zigachev 		/* Enter Below the Range */
1314*b843c749SSergey Zigachev 		if (!state->btr.btr_active &&
1315*b843c749SSergey Zigachev 			core_freesync->map[map_index].caps->btr_supported) {
1316*b843c749SSergey Zigachev 
1317*b843c749SSergey Zigachev 			state->btr.program_btr = true;
1318*b843c749SSergey Zigachev 			state->btr.btr_active = true;
1319*b843c749SSergey Zigachev 
1320*b843c749SSergey Zigachev 		/* Enter Fixed Refresh mode */
1321*b843c749SSergey Zigachev 		} else if (!state->fixed_refresh.fixed_active &&
1322*b843c749SSergey Zigachev 			!core_freesync->map[map_index].caps->btr_supported) {
1323*b843c749SSergey Zigachev 
1324*b843c749SSergey Zigachev 			state->fixed_refresh.frame_counter++;
1325*b843c749SSergey Zigachev 
1326*b843c749SSergey Zigachev 			if (state->fixed_refresh.frame_counter >
1327*b843c749SSergey Zigachev 					FIXED_REFRESH_ENTER_FRAME_COUNT) {
1328*b843c749SSergey Zigachev 				state->fixed_refresh.frame_counter = 0;
1329*b843c749SSergey Zigachev 				state->fixed_refresh.program_fixed = true;
1330*b843c749SSergey Zigachev 				state->fixed_refresh.fixed_active = true;
1331*b843c749SSergey Zigachev 			}
1332*b843c749SSergey Zigachev 		}
1333*b843c749SSergey Zigachev 	}
1334*b843c749SSergey Zigachev 
1335*b843c749SSergey Zigachev 	/* When Below the Range is active, must react on every frame */
1336*b843c749SSergey Zigachev 	if (state->btr.btr_active)
1337*b843c749SSergey Zigachev 		state->btr.program_btr = true;
1338*b843c749SSergey Zigachev }
1339*b843c749SSergey Zigachev 
apply_below_the_range(struct core_freesync * core_freesync,struct dc_stream_state * stream,unsigned int map_index,unsigned int last_render_time_in_us)1340*b843c749SSergey Zigachev static void apply_below_the_range(struct core_freesync *core_freesync,
1341*b843c749SSergey Zigachev 		struct dc_stream_state *stream, unsigned int map_index,
1342*b843c749SSergey Zigachev 		unsigned int last_render_time_in_us)
1343*b843c749SSergey Zigachev {
1344*b843c749SSergey Zigachev 	unsigned int inserted_frame_duration_in_us = 0;
1345*b843c749SSergey Zigachev 	unsigned int mid_point_frames_ceil = 0;
1346*b843c749SSergey Zigachev 	unsigned int mid_point_frames_floor = 0;
1347*b843c749SSergey Zigachev 	unsigned int frame_time_in_us = 0;
1348*b843c749SSergey Zigachev 	unsigned int delta_from_mid_point_in_us_1 = 0xFFFFFFFF;
1349*b843c749SSergey Zigachev 	unsigned int delta_from_mid_point_in_us_2 = 0xFFFFFFFF;
1350*b843c749SSergey Zigachev 	unsigned int frames_to_insert = 0;
1351*b843c749SSergey Zigachev 	unsigned int min_frame_duration_in_ns = 0;
1352*b843c749SSergey Zigachev 	struct freesync_state *state = &core_freesync->map[map_index].state;
1353*b843c749SSergey Zigachev 
1354*b843c749SSergey Zigachev 	if (!state->btr.program_btr)
1355*b843c749SSergey Zigachev 		return;
1356*b843c749SSergey Zigachev 
1357*b843c749SSergey Zigachev 	state->btr.program_btr = false;
1358*b843c749SSergey Zigachev 
1359*b843c749SSergey Zigachev 	min_frame_duration_in_ns = ((unsigned int) (div64_u64(
1360*b843c749SSergey Zigachev 		(1000000000ULL * 1000000),
1361*b843c749SSergey Zigachev 		state->nominal_refresh_rate_in_micro_hz)));
1362*b843c749SSergey Zigachev 
1363*b843c749SSergey Zigachev 	/* Program BTR */
1364*b843c749SSergey Zigachev 
1365*b843c749SSergey Zigachev 	/* BTR set to "not active" so disengage */
1366*b843c749SSergey Zigachev 	if (!state->btr.btr_active)
1367*b843c749SSergey Zigachev 
1368*b843c749SSergey Zigachev 		/* Restore FreeSync */
1369*b843c749SSergey Zigachev 		set_freesync_on_streams(core_freesync, &stream, 1);
1370*b843c749SSergey Zigachev 
1371*b843c749SSergey Zigachev 	/* BTR set to "active" so engage */
1372*b843c749SSergey Zigachev 	else {
1373*b843c749SSergey Zigachev 
1374*b843c749SSergey Zigachev 		/* Calculate number of midPoint frames that could fit within
1375*b843c749SSergey Zigachev 		 * the render time interval- take ceil of this value
1376*b843c749SSergey Zigachev 		 */
1377*b843c749SSergey Zigachev 		mid_point_frames_ceil = (last_render_time_in_us +
1378*b843c749SSergey Zigachev 			state->btr.mid_point_in_us- 1) /
1379*b843c749SSergey Zigachev 			state->btr.mid_point_in_us;
1380*b843c749SSergey Zigachev 
1381*b843c749SSergey Zigachev 		if (mid_point_frames_ceil > 0) {
1382*b843c749SSergey Zigachev 
1383*b843c749SSergey Zigachev 			frame_time_in_us = last_render_time_in_us /
1384*b843c749SSergey Zigachev 				mid_point_frames_ceil;
1385*b843c749SSergey Zigachev 			delta_from_mid_point_in_us_1 =
1386*b843c749SSergey Zigachev 				(state->btr.mid_point_in_us >
1387*b843c749SSergey Zigachev 				frame_time_in_us) ?
1388*b843c749SSergey Zigachev 				(state->btr.mid_point_in_us - frame_time_in_us):
1389*b843c749SSergey Zigachev 				(frame_time_in_us - state->btr.mid_point_in_us);
1390*b843c749SSergey Zigachev 		}
1391*b843c749SSergey Zigachev 
1392*b843c749SSergey Zigachev 		/* Calculate number of midPoint frames that could fit within
1393*b843c749SSergey Zigachev 		 * the render time interval- take floor of this value
1394*b843c749SSergey Zigachev 		 */
1395*b843c749SSergey Zigachev 		mid_point_frames_floor = last_render_time_in_us /
1396*b843c749SSergey Zigachev 			state->btr.mid_point_in_us;
1397*b843c749SSergey Zigachev 
1398*b843c749SSergey Zigachev 		if (mid_point_frames_floor > 0) {
1399*b843c749SSergey Zigachev 
1400*b843c749SSergey Zigachev 			frame_time_in_us = last_render_time_in_us /
1401*b843c749SSergey Zigachev 				mid_point_frames_floor;
1402*b843c749SSergey Zigachev 			delta_from_mid_point_in_us_2 =
1403*b843c749SSergey Zigachev 				(state->btr.mid_point_in_us >
1404*b843c749SSergey Zigachev 				frame_time_in_us) ?
1405*b843c749SSergey Zigachev 				(state->btr.mid_point_in_us - frame_time_in_us):
1406*b843c749SSergey Zigachev 				(frame_time_in_us - state->btr.mid_point_in_us);
1407*b843c749SSergey Zigachev 		}
1408*b843c749SSergey Zigachev 
1409*b843c749SSergey Zigachev 		/* Choose number of frames to insert based on how close it
1410*b843c749SSergey Zigachev 		 * can get to the mid point of the variable range.
1411*b843c749SSergey Zigachev 		 */
1412*b843c749SSergey Zigachev 		if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2)
1413*b843c749SSergey Zigachev 			frames_to_insert = mid_point_frames_ceil;
1414*b843c749SSergey Zigachev 		else
1415*b843c749SSergey Zigachev 			frames_to_insert = mid_point_frames_floor;
1416*b843c749SSergey Zigachev 
1417*b843c749SSergey Zigachev 		/* Either we've calculated the number of frames to insert,
1418*b843c749SSergey Zigachev 		 * or we need to insert min duration frames
1419*b843c749SSergey Zigachev 		 */
1420*b843c749SSergey Zigachev 		if (frames_to_insert > 0)
1421*b843c749SSergey Zigachev 			inserted_frame_duration_in_us = last_render_time_in_us /
1422*b843c749SSergey Zigachev 							frames_to_insert;
1423*b843c749SSergey Zigachev 
1424*b843c749SSergey Zigachev 		if (inserted_frame_duration_in_us <
1425*b843c749SSergey Zigachev 			state->time.min_render_time_in_us)
1426*b843c749SSergey Zigachev 
1427*b843c749SSergey Zigachev 			inserted_frame_duration_in_us =
1428*b843c749SSergey Zigachev 				state->time.min_render_time_in_us;
1429*b843c749SSergey Zigachev 
1430*b843c749SSergey Zigachev 		/* Cache the calculated variables */
1431*b843c749SSergey Zigachev 		state->btr.inserted_frame_duration_in_us =
1432*b843c749SSergey Zigachev 			inserted_frame_duration_in_us;
1433*b843c749SSergey Zigachev 		state->btr.frames_to_insert = frames_to_insert;
1434*b843c749SSergey Zigachev 		state->btr.frame_counter = frames_to_insert;
1435*b843c749SSergey Zigachev 
1436*b843c749SSergey Zigachev 	}
1437*b843c749SSergey Zigachev }
1438*b843c749SSergey Zigachev 
apply_fixed_refresh(struct core_freesync * core_freesync,struct dc_stream_state * stream,unsigned int map_index)1439*b843c749SSergey Zigachev static void apply_fixed_refresh(struct core_freesync *core_freesync,
1440*b843c749SSergey Zigachev 		struct dc_stream_state *stream, unsigned int map_index)
1441*b843c749SSergey Zigachev {
1442*b843c749SSergey Zigachev 	unsigned int vmin = 0, vmax = 0;
1443*b843c749SSergey Zigachev 	struct freesync_state *state = &core_freesync->map[map_index].state;
1444*b843c749SSergey Zigachev 
1445*b843c749SSergey Zigachev 	if (!state->fixed_refresh.program_fixed)
1446*b843c749SSergey Zigachev 		return;
1447*b843c749SSergey Zigachev 
1448*b843c749SSergey Zigachev 	state->fixed_refresh.program_fixed = false;
1449*b843c749SSergey Zigachev 
1450*b843c749SSergey Zigachev 	/* Program Fixed Refresh */
1451*b843c749SSergey Zigachev 
1452*b843c749SSergey Zigachev 	/* Fixed Refresh set to "not active" so disengage */
1453*b843c749SSergey Zigachev 	if (!state->fixed_refresh.fixed_active) {
1454*b843c749SSergey Zigachev 		set_freesync_on_streams(core_freesync, &stream, 1);
1455*b843c749SSergey Zigachev 
1456*b843c749SSergey Zigachev 	/* Fixed Refresh set to "active" so engage (fix to max) */
1457*b843c749SSergey Zigachev 	} else {
1458*b843c749SSergey Zigachev 
1459*b843c749SSergey Zigachev 		vmin = state->freesync_range.vmin;
1460*b843c749SSergey Zigachev 		vmax = vmin;
1461*b843c749SSergey Zigachev 		adjust_vmin_vmax(core_freesync, &stream, map_index,
1462*b843c749SSergey Zigachev 					1, vmin, vmax);
1463*b843c749SSergey Zigachev 	}
1464*b843c749SSergey Zigachev }
1465*b843c749SSergey Zigachev 
mod_freesync_pre_update_plane_addresses(struct mod_freesync * mod_freesync,struct dc_stream_state ** streams,int num_streams,unsigned int curr_time_stamp_in_us)1466*b843c749SSergey Zigachev void mod_freesync_pre_update_plane_addresses(struct mod_freesync *mod_freesync,
1467*b843c749SSergey Zigachev 		struct dc_stream_state **streams, int num_streams,
1468*b843c749SSergey Zigachev 		unsigned int curr_time_stamp_in_us)
1469*b843c749SSergey Zigachev {
1470*b843c749SSergey Zigachev 	unsigned int stream_index, map_index, last_render_time_in_us = 0;
1471*b843c749SSergey Zigachev 	struct core_freesync *core_freesync = NULL;
1472*b843c749SSergey Zigachev 
1473*b843c749SSergey Zigachev 	if (mod_freesync == NULL)
1474*b843c749SSergey Zigachev 		return;
1475*b843c749SSergey Zigachev 
1476*b843c749SSergey Zigachev 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1477*b843c749SSergey Zigachev 
1478*b843c749SSergey Zigachev 	for (stream_index = 0; stream_index < num_streams; stream_index++) {
1479*b843c749SSergey Zigachev 
1480*b843c749SSergey Zigachev 		map_index = map_index_from_stream(core_freesync,
1481*b843c749SSergey Zigachev 						streams[stream_index]);
1482*b843c749SSergey Zigachev 
1483*b843c749SSergey Zigachev 		if (core_freesync->map[map_index].caps->supported) {
1484*b843c749SSergey Zigachev 
1485*b843c749SSergey Zigachev 			last_render_time_in_us = curr_time_stamp_in_us -
1486*b843c749SSergey Zigachev 					core_freesync->map[map_index].state.time.
1487*b843c749SSergey Zigachev 					prev_time_stamp_in_us;
1488*b843c749SSergey Zigachev 
1489*b843c749SSergey Zigachev 			/* Add the timestamps to the cache and determine
1490*b843c749SSergey Zigachev 			 * whether BTR program is required
1491*b843c749SSergey Zigachev 			 */
1492*b843c749SSergey Zigachev 			update_timestamps(core_freesync, streams[stream_index],
1493*b843c749SSergey Zigachev 					map_index, last_render_time_in_us);
1494*b843c749SSergey Zigachev 
1495*b843c749SSergey Zigachev 			if (core_freesync->map[map_index].state.fullscreen &&
1496*b843c749SSergey Zigachev 				core_freesync->map[map_index].user_enable.
1497*b843c749SSergey Zigachev 				enable_for_gaming) {
1498*b843c749SSergey Zigachev 
1499*b843c749SSergey Zigachev 				if (core_freesync->map[map_index].caps->btr_supported) {
1500*b843c749SSergey Zigachev 
1501*b843c749SSergey Zigachev 					apply_below_the_range(core_freesync,
1502*b843c749SSergey Zigachev 						streams[stream_index], map_index,
1503*b843c749SSergey Zigachev 						last_render_time_in_us);
1504*b843c749SSergey Zigachev 				} else {
1505*b843c749SSergey Zigachev 					apply_fixed_refresh(core_freesync,
1506*b843c749SSergey Zigachev 						streams[stream_index], map_index);
1507*b843c749SSergey Zigachev 				}
1508*b843c749SSergey Zigachev 			}
1509*b843c749SSergey Zigachev 
1510*b843c749SSergey Zigachev 			core_freesync->map[map_index].state.time.
1511*b843c749SSergey Zigachev 				prev_time_stamp_in_us = curr_time_stamp_in_us;
1512*b843c749SSergey Zigachev 		}
1513*b843c749SSergey Zigachev 
1514*b843c749SSergey Zigachev 	}
1515*b843c749SSergey Zigachev }
1516*b843c749SSergey Zigachev 
mod_freesync_get_settings(struct mod_freesync * mod_freesync,struct dc_stream_state ** streams,int num_streams,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)1517*b843c749SSergey Zigachev void mod_freesync_get_settings(struct mod_freesync *mod_freesync,
1518*b843c749SSergey Zigachev 		struct dc_stream_state **streams, int num_streams,
1519*b843c749SSergey Zigachev 		unsigned int *v_total_min, unsigned int *v_total_max,
1520*b843c749SSergey Zigachev 		unsigned int *event_triggers,
1521*b843c749SSergey Zigachev 		unsigned int *window_min, unsigned int *window_max,
1522*b843c749SSergey Zigachev 		unsigned int *lfc_mid_point_in_us,
1523*b843c749SSergey Zigachev 		unsigned int *inserted_frames,
1524*b843c749SSergey Zigachev 		unsigned int *inserted_duration_in_us)
1525*b843c749SSergey Zigachev {
1526*b843c749SSergey Zigachev 	unsigned int stream_index, map_index;
1527*b843c749SSergey Zigachev 	struct core_freesync *core_freesync = NULL;
1528*b843c749SSergey Zigachev 
1529*b843c749SSergey Zigachev 	if (mod_freesync == NULL)
1530*b843c749SSergey Zigachev 		return;
1531*b843c749SSergey Zigachev 
1532*b843c749SSergey Zigachev 	core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1533*b843c749SSergey Zigachev 
1534*b843c749SSergey Zigachev 	for (stream_index = 0; stream_index < num_streams; stream_index++) {
1535*b843c749SSergey Zigachev 
1536*b843c749SSergey Zigachev 		map_index = map_index_from_stream(core_freesync,
1537*b843c749SSergey Zigachev 						streams[stream_index]);
1538*b843c749SSergey Zigachev 
1539*b843c749SSergey Zigachev 		if (core_freesync->map[map_index].caps->supported) {
1540*b843c749SSergey Zigachev 			struct freesync_state state =
1541*b843c749SSergey Zigachev 					core_freesync->map[map_index].state;
1542*b843c749SSergey Zigachev 			*v_total_min = state.vmin;
1543*b843c749SSergey Zigachev 			*v_total_max = state.vmax;
1544*b843c749SSergey Zigachev 			*event_triggers = 0;
1545*b843c749SSergey Zigachev 			*window_min = state.time.min_window;
1546*b843c749SSergey Zigachev 			*window_max = state.time.max_window;
1547*b843c749SSergey Zigachev 			*lfc_mid_point_in_us = state.btr.mid_point_in_us;
1548*b843c749SSergey Zigachev 			*inserted_frames = state.btr.frames_to_insert;
1549*b843c749SSergey Zigachev 			*inserted_duration_in_us =
1550*b843c749SSergey Zigachev 					state.btr.inserted_frame_duration_in_us;
1551*b843c749SSergey Zigachev 		}
1552*b843c749SSergey Zigachev 
1553*b843c749SSergey Zigachev 	}
1554*b843c749SSergey Zigachev }
1555*b843c749SSergey Zigachev 
1556