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