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