hc
2023-12-06 08f87f769b595151be1afeff53e144f543faa614
kernel/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
....@@ -23,6 +23,8 @@
2323 *
2424 */
2525
26
+#include <linux/slab.h>
27
+
2628 #include "dm_services.h"
2729 #include "dc.h"
2830 #include "mod_freesync.h"
....@@ -30,113 +32,24 @@
3032
3133 #define MOD_FREESYNC_MAX_CONCURRENT_STREAMS 32
3234
35
+#define MIN_REFRESH_RANGE 10
3336 /* Refresh rate ramp at a fixed rate of 65 Hz/second */
3437 #define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65)
3538 /* Number of elements in the render times cache array */
3639 #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
3946 /* Number of consecutive frames to check before entering/exiting fixed refresh*/
4047 #define FIXED_REFRESH_ENTER_FRAME_COUNT 5
4148 #define FIXED_REFRESH_EXIT_FRAME_COUNT 5
4249
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
-
13450 struct core_freesync {
13551 struct mod_freesync public;
13652 struct dc *dc;
137
- struct freesync_registry_options opts;
138
- struct freesync_entity *map;
139
- int num_entities;
14053 };
14154
14255 #define MOD_FREESYNC_TO_CORE(mod_freesync)\
....@@ -147,69 +60,16 @@
14760 struct core_freesync *core_freesync =
14861 kzalloc(sizeof(struct core_freesync), GFP_KERNEL);
14962
150
-
151
- struct persistent_data_flag flag;
152
-
153
- int i, data = 0;
154
-
15563 if (core_freesync == NULL)
15664 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;
16965
17066 if (dc == NULL)
17167 goto fail_construct;
17268
17369 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
-
20770 return &core_freesync->public;
20871
20972 fail_construct:
210
- kfree(core_freesync->map);
211
-
212
-fail_alloc_map:
21373 kfree(core_freesync);
21474
21575 fail_alloc_context:
....@@ -218,968 +78,411 @@
21878
21979 void mod_freesync_destroy(struct mod_freesync *mod_freesync)
22080 {
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;
25881 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
-
26482 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)
37483 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);
38286 }
38387
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)
38791 {
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
39098
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;
407106 }
408107
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)
411112 {
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;
417119 }
418120
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)
424124 {
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;
428127
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)));
434131
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);
437135
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;
442140 }
443141
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;
492143 }
493144
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)
496149 {
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;
500169 }
501170
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)
505175 {
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;
510186
511187 /* Calc ratio between new and current frame duration with 3 digit */
512188 unsigned int frame_duration_ratio = div64_u64(1000000,
513189 (1000 + div64_u64(((unsigned long long)(
514190 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)));
517193
518
- /* Calculate delta between new and current frame duration in ns */
194
+ /* Calculate delta between new and current frame duration in us */
519195 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) *
521197 (1000 - frame_duration_ratio)), 1000);
522198
523199 /* Adjust frame duration delta based on ratio between current and
524200 * standard frame duration (frame duration at 60 Hz refresh rate).
525201 */
526202 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);
529204
530205 /* Going to a higher refresh rate (lower frame duration) */
531
- if (static_ramp_variables->ramp_direction_is_up) {
206
+ if (ramp_direction_is_up) {
532207 /* 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;
541209
542210 /* 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);
550217 }
551218 /* Going to a lower refresh rate (larger frame duration) */
552219 } else {
553220 /* 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;
561222
562223 /* 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);
570230 }
571231 }
572232
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;
575243 }
576244
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)
578249 {
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;
585260
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
+ }
591274
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;
604280
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 {
607290
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;
609297
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);
714306 }
715307
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 ((last_render_time_in_us / mid_point_frames_ceil) < in_out_vrr->min_duration_in_us) {
331
+ /* Check for out of range.
332
+ * If using CEIL produces a value that is out of range,
333
+ * then we are forced to use FLOOR.
334
+ */
335
+ frames_to_insert = mid_point_frames_floor;
336
+ } else if (mid_point_frames_floor < 2) {
337
+ /* Check if FLOOR would result in non-LFC. In this case
338
+ * choose to use CEIL
339
+ */
340
+ frames_to_insert = mid_point_frames_ceil;
341
+ } else if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) {
342
+ /* If choosing CEIL results in a frame duration that is
343
+ * closer to the mid point of the range.
344
+ * Choose CEIL
345
+ */
346
+ frames_to_insert = mid_point_frames_ceil;
347
+ } else {
348
+ /* If choosing FLOOR results in a frame duration that is
349
+ * closer to the mid point of the range.
350
+ * Choose FLOOR
351
+ */
352
+ frames_to_insert = mid_point_frames_floor;
353
+ }
354
+
355
+ /* Prefer current frame multiplier when BTR is enabled unless it drifts
356
+ * too far from the midpoint
357
+ */
358
+ if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) {
359
+ delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_2 -
360
+ delta_from_mid_point_in_us_1;
361
+ } else {
362
+ delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_1 -
363
+ delta_from_mid_point_in_us_2;
364
+ }
365
+ if (in_out_vrr->btr.frames_to_insert != 0 &&
366
+ delta_from_mid_point_delta_in_us < BTR_DRIFT_MARGIN) {
367
+ if (((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) <
368
+ max_render_time_in_us) &&
369
+ ((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) >
370
+ in_out_vrr->min_duration_in_us))
371
+ frames_to_insert = in_out_vrr->btr.frames_to_insert;
372
+ }
373
+
374
+ /* Either we've calculated the number of frames to insert,
375
+ * or we need to insert min duration frames
376
+ */
377
+ if (last_render_time_in_us / frames_to_insert <
378
+ in_out_vrr->min_duration_in_us){
379
+ frames_to_insert -= (frames_to_insert > 1) ?
380
+ 1 : 0;
381
+ }
382
+
383
+ if (frames_to_insert > 0)
384
+ inserted_frame_duration_in_us = last_render_time_in_us /
385
+ frames_to_insert;
386
+
387
+ if (inserted_frame_duration_in_us < in_out_vrr->min_duration_in_us)
388
+ inserted_frame_duration_in_us = in_out_vrr->min_duration_in_us;
389
+
390
+ /* Cache the calculated variables */
391
+ in_out_vrr->btr.inserted_duration_in_us =
392
+ inserted_frame_duration_in_us;
393
+ in_out_vrr->btr.frames_to_insert = frames_to_insert;
394
+ in_out_vrr->btr.frame_counter = frames_to_insert;
395
+ }
396
+}
397
+
398
+static void apply_fixed_refresh(struct core_freesync *core_freesync,
399
+ const struct dc_stream_state *stream,
400
+ unsigned int last_render_time_in_us,
401
+ struct mod_vrr_params *in_out_vrr)
402
+{
403
+ bool update = false;
404
+ unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us;
405
+
406
+ /* Compute the exit refresh rate and exit frame duration */
407
+ unsigned int exit_refresh_rate_in_milli_hz = ((1000000000/max_render_time_in_us)
408
+ + (1000*FIXED_REFRESH_EXIT_MARGIN_IN_HZ));
409
+ unsigned int exit_frame_duration_in_us = 1000000000/exit_refresh_rate_in_milli_hz;
410
+
411
+ if (last_render_time_in_us < exit_frame_duration_in_us) {
412
+ /* Exit Fixed Refresh mode */
413
+ if (in_out_vrr->fixed.fixed_active) {
414
+ in_out_vrr->fixed.frame_counter++;
415
+
416
+ if (in_out_vrr->fixed.frame_counter >
417
+ FIXED_REFRESH_EXIT_FRAME_COUNT) {
418
+ in_out_vrr->fixed.frame_counter = 0;
419
+ in_out_vrr->fixed.fixed_active = false;
420
+ in_out_vrr->fixed.target_refresh_in_uhz = 0;
421
+ update = true;
422
+ }
423
+ }
424
+ } else if (last_render_time_in_us > max_render_time_in_us) {
425
+ /* Enter Fixed Refresh mode */
426
+ if (!in_out_vrr->fixed.fixed_active) {
427
+ in_out_vrr->fixed.frame_counter++;
428
+
429
+ if (in_out_vrr->fixed.frame_counter >
430
+ FIXED_REFRESH_ENTER_FRAME_COUNT) {
431
+ in_out_vrr->fixed.frame_counter = 0;
432
+ in_out_vrr->fixed.fixed_active = true;
433
+ in_out_vrr->fixed.target_refresh_in_uhz =
434
+ in_out_vrr->max_refresh_in_uhz;
435
+ update = true;
436
+ }
437
+ }
438
+ }
439
+
440
+ if (update) {
441
+ if (in_out_vrr->fixed.fixed_active) {
442
+ in_out_vrr->adjust.v_total_min =
443
+ calc_v_total_from_refresh(
444
+ stream, in_out_vrr->max_refresh_in_uhz);
445
+ in_out_vrr->adjust.v_total_max =
446
+ in_out_vrr->adjust.v_total_min;
447
+ } else {
448
+ in_out_vrr->adjust.v_total_min =
449
+ calc_v_total_from_refresh(stream,
450
+ in_out_vrr->max_refresh_in_uhz);
451
+ in_out_vrr->adjust.v_total_max =
452
+ calc_v_total_from_refresh(stream,
453
+ in_out_vrr->min_refresh_in_uhz);
454
+ }
455
+ }
456
+}
457
+
458
+static bool vrr_settings_require_update(struct core_freesync *core_freesync,
459
+ struct mod_freesync_config *in_config,
460
+ unsigned int min_refresh_in_uhz,
461
+ unsigned int max_refresh_in_uhz,
462
+ struct mod_vrr_params *in_vrr)
463
+{
464
+ if (in_vrr->state != in_config->state) {
465
+ return true;
466
+ } else if (in_vrr->state == VRR_STATE_ACTIVE_FIXED &&
467
+ in_vrr->fixed.target_refresh_in_uhz !=
468
+ in_config->fixed_refresh_in_uhz) {
469
+ return true;
470
+ } else if (in_vrr->min_refresh_in_uhz != min_refresh_in_uhz) {
471
+ return true;
472
+ } else if (in_vrr->max_refresh_in_uhz != max_refresh_in_uhz) {
473
+ return true;
716474 }
717475
718476 return false;
719477 }
720478
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
-
1165479 bool mod_freesync_get_vmin_vmax(struct mod_freesync *mod_freesync,
1166
- struct dc_stream_state *stream,
480
+ const struct dc_stream_state *stream,
1167481 unsigned int *vmin,
1168482 unsigned int *vmax)
1169483 {
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;
484
+ *vmin = stream->adjust.v_total_min;
485
+ *vmax = stream->adjust.v_total_max;
1183486
1184487 return true;
1185488 }
....@@ -1189,7 +492,6 @@
1189492 unsigned int *nom_v_pos,
1190493 unsigned int *v_pos)
1191494 {
1192
- unsigned int index = 0;
1193495 struct core_freesync *core_freesync = NULL;
1194496 struct crtc_position position;
1195497
....@@ -1197,7 +499,6 @@
1197499 return false;
1198500
1199501 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1200
- index = map_index_from_stream(core_freesync, stream);
1201502
1202503 if (dc_stream_get_crtc_position(core_freesync->dc, &stream, 1,
1203504 &position.vertical_count,
....@@ -1212,310 +513,629 @@
1212513 return false;
1213514 }
1214515
1215
-void mod_freesync_notify_mode_change(struct mod_freesync *mod_freesync,
1216
- struct dc_stream_state **streams, int num_streams)
516
+static void build_vrr_infopacket_data_v1(const struct mod_vrr_params *vrr,
517
+ struct dc_info_packet *infopacket)
1217518 {
1218
- unsigned int stream_index, map_index;
1219
- struct freesync_state *state;
519
+ /* PB1 = 0x1A (24bit AMD IEEE OUI (0x00001A) - Byte 0) */
520
+ infopacket->sb[1] = 0x1A;
521
+
522
+ /* PB2 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 1) */
523
+ infopacket->sb[2] = 0x00;
524
+
525
+ /* PB3 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 2) */
526
+ infopacket->sb[3] = 0x00;
527
+
528
+ /* PB4 = Reserved */
529
+
530
+ /* PB5 = Reserved */
531
+
532
+ /* PB6 = [Bits 7:3 = Reserved] */
533
+
534
+ /* PB6 = [Bit 0 = FreeSync Supported] */
535
+ if (vrr->state != VRR_STATE_UNSUPPORTED)
536
+ infopacket->sb[6] |= 0x01;
537
+
538
+ /* PB6 = [Bit 1 = FreeSync Enabled] */
539
+ if (vrr->state != VRR_STATE_DISABLED &&
540
+ vrr->state != VRR_STATE_UNSUPPORTED)
541
+ infopacket->sb[6] |= 0x02;
542
+
543
+ /* PB6 = [Bit 2 = FreeSync Active] */
544
+ if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
545
+ vrr->state == VRR_STATE_ACTIVE_FIXED)
546
+ infopacket->sb[6] |= 0x04;
547
+
548
+ // For v1 & 2 infoframes program nominal if non-fs mode, otherwise full range
549
+ /* PB7 = FreeSync Minimum refresh rate (Hz) */
550
+ if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
551
+ vrr->state == VRR_STATE_ACTIVE_FIXED) {
552
+ infopacket->sb[7] = (unsigned char)((vrr->min_refresh_in_uhz + 500000) / 1000000);
553
+ } else {
554
+ infopacket->sb[7] = (unsigned char)((vrr->max_refresh_in_uhz + 500000) / 1000000);
555
+ }
556
+
557
+ /* PB8 = FreeSync Maximum refresh rate (Hz)
558
+ * Note: We should never go above the field rate of the mode timing set.
559
+ */
560
+ infopacket->sb[8] = (unsigned char)((vrr->max_refresh_in_uhz + 500000) / 1000000);
561
+
562
+ //FreeSync HDR
563
+ infopacket->sb[9] = 0;
564
+ infopacket->sb[10] = 0;
565
+}
566
+
567
+static void build_vrr_infopacket_data_v3(const struct mod_vrr_params *vrr,
568
+ struct dc_info_packet *infopacket)
569
+{
570
+ /* PB1 = 0x1A (24bit AMD IEEE OUI (0x00001A) - Byte 0) */
571
+ infopacket->sb[1] = 0x1A;
572
+
573
+ /* PB2 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 1) */
574
+ infopacket->sb[2] = 0x00;
575
+
576
+ /* PB3 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 2) */
577
+ infopacket->sb[3] = 0x00;
578
+
579
+ /* PB4 = Reserved */
580
+
581
+ /* PB5 = Reserved */
582
+
583
+ /* PB6 = [Bits 7:3 = Reserved] */
584
+
585
+ /* PB6 = [Bit 0 = FreeSync Supported] */
586
+ if (vrr->state != VRR_STATE_UNSUPPORTED)
587
+ infopacket->sb[6] |= 0x01;
588
+
589
+ /* PB6 = [Bit 1 = FreeSync Enabled] */
590
+ if (vrr->state != VRR_STATE_DISABLED &&
591
+ vrr->state != VRR_STATE_UNSUPPORTED)
592
+ infopacket->sb[6] |= 0x02;
593
+
594
+ /* PB6 = [Bit 2 = FreeSync Active] */
595
+ if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
596
+ vrr->state == VRR_STATE_ACTIVE_FIXED)
597
+ infopacket->sb[6] |= 0x04;
598
+
599
+ if (vrr->state == VRR_STATE_ACTIVE_FIXED) {
600
+ /* PB7 = FreeSync Minimum refresh rate (Hz) */
601
+ infopacket->sb[7] = (unsigned char)((vrr->fixed_refresh_in_uhz + 500000) / 1000000);
602
+ /* PB8 = FreeSync Maximum refresh rate (Hz) */
603
+ infopacket->sb[8] = (unsigned char)((vrr->fixed_refresh_in_uhz + 500000) / 1000000);
604
+ } else if (vrr->state == VRR_STATE_ACTIVE_VARIABLE) {
605
+ /* PB7 = FreeSync Minimum refresh rate (Hz) */
606
+ infopacket->sb[7] = (unsigned char)((vrr->min_refresh_in_uhz + 500000) / 1000000);
607
+ /* PB8 = FreeSync Maximum refresh rate (Hz) */
608
+ infopacket->sb[8] = (unsigned char)((vrr->max_refresh_in_uhz + 500000) / 1000000);
609
+ } else {
610
+ // Non-fs case, program nominal range
611
+ /* PB7 = FreeSync Minimum refresh rate (Hz) */
612
+ infopacket->sb[7] = (unsigned char)((vrr->max_refresh_in_uhz + 500000) / 1000000);
613
+ /* PB8 = FreeSync Maximum refresh rate (Hz) */
614
+ infopacket->sb[8] = (unsigned char)((vrr->max_refresh_in_uhz + 500000) / 1000000);
615
+ }
616
+
617
+ //FreeSync HDR
618
+ infopacket->sb[9] = 0;
619
+ infopacket->sb[10] = 0;
620
+}
621
+
622
+static void build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf,
623
+ struct dc_info_packet *infopacket)
624
+{
625
+ if (app_tf != TRANSFER_FUNC_UNKNOWN) {
626
+ infopacket->valid = true;
627
+
628
+ infopacket->sb[6] |= 0x08; // PB6 = [Bit 3 = Native Color Active]
629
+
630
+ if (app_tf == TRANSFER_FUNC_GAMMA_22) {
631
+ infopacket->sb[9] |= 0x04; // PB6 = [Bit 2 = Gamma 2.2 EOTF Active]
632
+ }
633
+ }
634
+}
635
+
636
+static void build_vrr_infopacket_header_v1(enum signal_type signal,
637
+ struct dc_info_packet *infopacket,
638
+ unsigned int *payload_size)
639
+{
640
+ if (dc_is_hdmi_signal(signal)) {
641
+
642
+ /* HEADER */
643
+
644
+ /* HB0 = Packet Type = 0x83 (Source Product
645
+ * Descriptor InfoFrame)
646
+ */
647
+ infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
648
+
649
+ /* HB1 = Version = 0x01 */
650
+ infopacket->hb1 = 0x01;
651
+
652
+ /* HB2 = [Bits 7:5 = 0] [Bits 4:0 = Length = 0x08] */
653
+ infopacket->hb2 = 0x08;
654
+
655
+ *payload_size = 0x08;
656
+
657
+ } else if (dc_is_dp_signal(signal)) {
658
+
659
+ /* HEADER */
660
+
661
+ /* HB0 = Secondary-data Packet ID = 0 - Only non-zero
662
+ * when used to associate audio related info packets
663
+ */
664
+ infopacket->hb0 = 0x00;
665
+
666
+ /* HB1 = Packet Type = 0x83 (Source Product
667
+ * Descriptor InfoFrame)
668
+ */
669
+ infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
670
+
671
+ /* HB2 = [Bits 7:0 = Least significant eight bits -
672
+ * For INFOFRAME, the value must be 1Bh]
673
+ */
674
+ infopacket->hb2 = 0x1B;
675
+
676
+ /* HB3 = [Bits 7:2 = INFOFRAME SDP Version Number = 0x1]
677
+ * [Bits 1:0 = Most significant two bits = 0x00]
678
+ */
679
+ infopacket->hb3 = 0x04;
680
+
681
+ *payload_size = 0x1B;
682
+ }
683
+}
684
+
685
+static void build_vrr_infopacket_header_v2(enum signal_type signal,
686
+ struct dc_info_packet *infopacket,
687
+ unsigned int *payload_size)
688
+{
689
+ if (dc_is_hdmi_signal(signal)) {
690
+
691
+ /* HEADER */
692
+
693
+ /* HB0 = Packet Type = 0x83 (Source Product
694
+ * Descriptor InfoFrame)
695
+ */
696
+ infopacket->hb0 = DC_HDMI_INFOFRAME_TYPE_SPD;
697
+
698
+ /* HB1 = Version = 0x02 */
699
+ infopacket->hb1 = 0x02;
700
+
701
+ /* HB2 = [Bits 7:5 = 0] [Bits 4:0 = Length = 0x09] */
702
+ infopacket->hb2 = 0x09;
703
+
704
+ *payload_size = 0x0A;
705
+
706
+ } else if (dc_is_dp_signal(signal)) {
707
+
708
+ /* HEADER */
709
+
710
+ /* HB0 = Secondary-data Packet ID = 0 - Only non-zero
711
+ * when used to associate audio related info packets
712
+ */
713
+ infopacket->hb0 = 0x00;
714
+
715
+ /* HB1 = Packet Type = 0x83 (Source Product
716
+ * Descriptor InfoFrame)
717
+ */
718
+ infopacket->hb1 = DC_HDMI_INFOFRAME_TYPE_SPD;
719
+
720
+ /* HB2 = [Bits 7:0 = Least significant eight bits -
721
+ * For INFOFRAME, the value must be 1Bh]
722
+ */
723
+ infopacket->hb2 = 0x1B;
724
+
725
+ /* HB3 = [Bits 7:2 = INFOFRAME SDP Version Number = 0x2]
726
+ * [Bits 1:0 = Most significant two bits = 0x00]
727
+ */
728
+ infopacket->hb3 = 0x08;
729
+
730
+ *payload_size = 0x1B;
731
+ }
732
+}
733
+
734
+static void build_vrr_infopacket_checksum(unsigned int *payload_size,
735
+ struct dc_info_packet *infopacket)
736
+{
737
+ /* Calculate checksum */
738
+ unsigned int idx = 0;
739
+ unsigned char checksum = 0;
740
+
741
+ checksum += infopacket->hb0;
742
+ checksum += infopacket->hb1;
743
+ checksum += infopacket->hb2;
744
+ checksum += infopacket->hb3;
745
+
746
+ for (idx = 1; idx <= *payload_size; idx++)
747
+ checksum += infopacket->sb[idx];
748
+
749
+ /* PB0 = Checksum (one byte complement) */
750
+ infopacket->sb[0] = (unsigned char)(0x100 - checksum);
751
+
752
+ infopacket->valid = true;
753
+}
754
+
755
+static void build_vrr_infopacket_v1(enum signal_type signal,
756
+ const struct mod_vrr_params *vrr,
757
+ struct dc_info_packet *infopacket)
758
+{
759
+ /* SPD info packet for FreeSync */
760
+ unsigned int payload_size = 0;
761
+
762
+ build_vrr_infopacket_header_v1(signal, infopacket, &payload_size);
763
+ build_vrr_infopacket_data_v1(vrr, infopacket);
764
+ build_vrr_infopacket_checksum(&payload_size, infopacket);
765
+
766
+ infopacket->valid = true;
767
+}
768
+
769
+static void build_vrr_infopacket_v2(enum signal_type signal,
770
+ const struct mod_vrr_params *vrr,
771
+ enum color_transfer_func app_tf,
772
+ struct dc_info_packet *infopacket)
773
+{
774
+ unsigned int payload_size = 0;
775
+
776
+ build_vrr_infopacket_header_v2(signal, infopacket, &payload_size);
777
+ build_vrr_infopacket_data_v1(vrr, infopacket);
778
+
779
+ build_vrr_infopacket_fs2_data(app_tf, infopacket);
780
+
781
+ build_vrr_infopacket_checksum(&payload_size, infopacket);
782
+
783
+ infopacket->valid = true;
784
+}
785
+#ifndef TRIM_FSFT
786
+static void build_vrr_infopacket_fast_transport_data(
787
+ bool ftActive,
788
+ unsigned int ftOutputRate,
789
+ struct dc_info_packet *infopacket)
790
+{
791
+ /* PB9 : bit7 - fast transport Active*/
792
+ unsigned char activeBit = (ftActive) ? 1 << 7 : 0;
793
+
794
+ infopacket->sb[1] &= ~activeBit; //clear bit
795
+ infopacket->sb[1] |= activeBit; //set bit
796
+
797
+ /* PB13 : Target Output Pixel Rate [kHz] - bits 7:0 */
798
+ infopacket->sb[13] = ftOutputRate & 0xFF;
799
+
800
+ /* PB14 : Target Output Pixel Rate [kHz] - bits 15:8 */
801
+ infopacket->sb[14] = (ftOutputRate >> 8) & 0xFF;
802
+
803
+ /* PB15 : Target Output Pixel Rate [kHz] - bits 23:16 */
804
+ infopacket->sb[15] = (ftOutputRate >> 16) & 0xFF;
805
+
806
+}
807
+#endif
808
+
809
+static void build_vrr_infopacket_v3(enum signal_type signal,
810
+ const struct mod_vrr_params *vrr,
811
+#ifndef TRIM_FSFT
812
+ bool ftActive, unsigned int ftOutputRate,
813
+#endif
814
+ enum color_transfer_func app_tf,
815
+ struct dc_info_packet *infopacket)
816
+{
817
+ unsigned int payload_size = 0;
818
+
819
+ build_vrr_infopacket_header_v2(signal, infopacket, &payload_size);
820
+ build_vrr_infopacket_data_v3(vrr, infopacket);
821
+
822
+ build_vrr_infopacket_fs2_data(app_tf, infopacket);
823
+
824
+#ifndef TRIM_FSFT
825
+ build_vrr_infopacket_fast_transport_data(
826
+ ftActive,
827
+ ftOutputRate,
828
+ infopacket);
829
+#endif
830
+
831
+ build_vrr_infopacket_checksum(&payload_size, infopacket);
832
+
833
+ infopacket->valid = true;
834
+}
835
+
836
+void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync,
837
+ const struct dc_stream_state *stream,
838
+ const struct mod_vrr_params *vrr,
839
+ enum vrr_packet_type packet_type,
840
+ enum color_transfer_func app_tf,
841
+ struct dc_info_packet *infopacket)
842
+{
843
+ /* SPD info packet for FreeSync
844
+ * VTEM info packet for HdmiVRR
845
+ * Check if Freesync is supported. Return if false. If true,
846
+ * set the corresponding bit in the info packet
847
+ */
848
+ if (!vrr->send_info_frame)
849
+ return;
850
+
851
+ switch (packet_type) {
852
+ case PACKET_TYPE_FS_V3:
853
+#ifndef TRIM_FSFT
854
+ // always populate with pixel rate.
855
+ build_vrr_infopacket_v3(
856
+ stream->signal, vrr,
857
+ stream->timing.flags.FAST_TRANSPORT,
858
+ (stream->timing.flags.FAST_TRANSPORT) ?
859
+ stream->timing.fast_transport_output_rate_100hz :
860
+ stream->timing.pix_clk_100hz,
861
+ app_tf, infopacket);
862
+#else
863
+ build_vrr_infopacket_v3(stream->signal, vrr, app_tf, infopacket);
864
+#endif
865
+ break;
866
+ case PACKET_TYPE_FS_V2:
867
+ build_vrr_infopacket_v2(stream->signal, vrr, app_tf, infopacket);
868
+ break;
869
+ case PACKET_TYPE_VRR:
870
+ case PACKET_TYPE_FS_V1:
871
+ default:
872
+ build_vrr_infopacket_v1(stream->signal, vrr, infopacket);
873
+ }
874
+}
875
+
876
+void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync,
877
+ const struct dc_stream_state *stream,
878
+ struct mod_freesync_config *in_config,
879
+ struct mod_vrr_params *in_out_vrr)
880
+{
1220881 struct core_freesync *core_freesync = NULL;
1221
- struct dc_static_screen_events triggers = {0};
1222
- unsigned long long temp = 0;
882
+ unsigned long long nominal_field_rate_in_uhz = 0;
883
+ unsigned long long rounded_nominal_in_uhz = 0;
884
+ unsigned int refresh_range = 0;
885
+ unsigned long long min_refresh_in_uhz = 0;
886
+ unsigned long long max_refresh_in_uhz = 0;
1223887
1224888 if (mod_freesync == NULL)
1225889 return;
1226890
1227891 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1228892
1229
- for (stream_index = 0; stream_index < num_streams; stream_index++) {
1230
- map_index = map_index_from_stream(core_freesync,
1231
- streams[stream_index]);
893
+ /* Calculate nominal field rate for stream */
894
+ nominal_field_rate_in_uhz =
895
+ mod_freesync_calc_nominal_field_rate(stream);
1232896
1233
- state = &core_freesync->map[map_index].state;
897
+ min_refresh_in_uhz = in_config->min_refresh_in_uhz;
898
+ max_refresh_in_uhz = in_config->max_refresh_in_uhz;
1234899
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;
900
+ // Full range may be larger than current video timing, so cap at nominal
901
+ if (max_refresh_in_uhz > nominal_field_rate_in_uhz)
902
+ max_refresh_in_uhz = nominal_field_rate_in_uhz;
1244903
1245
- if (core_freesync->map[map_index].caps->supported) {
904
+ // Full range may be larger than current video timing, so cap at nominal
905
+ if (min_refresh_in_uhz > max_refresh_in_uhz)
906
+ min_refresh_in_uhz = max_refresh_in_uhz;
1246907
1247
- /* Update the stream */
1248
- update_stream(core_freesync, streams[stream_index]);
908
+ // If a monitor reports exactly max refresh of 2x of min, enforce it on nominal
909
+ rounded_nominal_in_uhz =
910
+ div_u64(nominal_field_rate_in_uhz + 50000, 100000) * 100000;
911
+ if (in_config->max_refresh_in_uhz == (2 * in_config->min_refresh_in_uhz) &&
912
+ in_config->max_refresh_in_uhz == rounded_nominal_in_uhz)
913
+ min_refresh_in_uhz = div_u64(nominal_field_rate_in_uhz, 2);
1249914
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)
915
+ if (!vrr_settings_require_update(core_freesync,
916
+ in_config, (unsigned int)min_refresh_in_uhz, (unsigned int)max_refresh_in_uhz,
917
+ in_out_vrr))
1355918 return;
1356919
1357
- state->btr.program_btr = false;
920
+ in_out_vrr->state = in_config->state;
921
+ in_out_vrr->send_info_frame = in_config->vsif_supported;
1358922
1359
- min_frame_duration_in_ns = ((unsigned int) (div64_u64(
1360
- (1000000000ULL * 1000000),
1361
- state->nominal_refresh_rate_in_micro_hz)));
923
+ if (in_config->state == VRR_STATE_UNSUPPORTED) {
924
+ in_out_vrr->state = VRR_STATE_UNSUPPORTED;
925
+ in_out_vrr->supported = false;
926
+ in_out_vrr->adjust.v_total_min = stream->timing.v_total;
927
+ in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1362928
1363
- /* Program BTR */
929
+ return;
1364930
1365
- /* BTR set to "not active" so disengage */
1366
- if (!state->btr.btr_active)
931
+ } else {
932
+ in_out_vrr->min_refresh_in_uhz = (unsigned int)min_refresh_in_uhz;
933
+ in_out_vrr->max_duration_in_us =
934
+ calc_duration_in_us_from_refresh_in_uhz(
935
+ (unsigned int)min_refresh_in_uhz);
936
+
937
+ in_out_vrr->max_refresh_in_uhz = (unsigned int)max_refresh_in_uhz;
938
+ in_out_vrr->min_duration_in_us =
939
+ calc_duration_in_us_from_refresh_in_uhz(
940
+ (unsigned int)max_refresh_in_uhz);
941
+
942
+ if (in_config->state == VRR_STATE_ACTIVE_FIXED)
943
+ in_out_vrr->fixed_refresh_in_uhz = in_config->fixed_refresh_in_uhz;
944
+ else
945
+ in_out_vrr->fixed_refresh_in_uhz = 0;
946
+
947
+ refresh_range = div_u64(in_out_vrr->max_refresh_in_uhz + 500000, 1000000) -
948
++ div_u64(in_out_vrr->min_refresh_in_uhz + 500000, 1000000);
949
+
950
+ in_out_vrr->supported = true;
951
+ }
952
+
953
+ in_out_vrr->fixed.ramping_active = in_config->ramping;
954
+
955
+ in_out_vrr->btr.btr_enabled = in_config->btr;
956
+
957
+ if (in_out_vrr->max_refresh_in_uhz < (2 * in_out_vrr->min_refresh_in_uhz))
958
+ in_out_vrr->btr.btr_enabled = false;
959
+ else {
960
+ in_out_vrr->btr.margin_in_us = in_out_vrr->max_duration_in_us -
961
+ 2 * in_out_vrr->min_duration_in_us;
962
+ if (in_out_vrr->btr.margin_in_us > BTR_MAX_MARGIN)
963
+ in_out_vrr->btr.margin_in_us = BTR_MAX_MARGIN;
964
+ }
965
+
966
+ in_out_vrr->btr.btr_active = false;
967
+ in_out_vrr->btr.inserted_duration_in_us = 0;
968
+ in_out_vrr->btr.frames_to_insert = 0;
969
+ in_out_vrr->btr.frame_counter = 0;
970
+ in_out_vrr->fixed.fixed_active = false;
971
+ in_out_vrr->fixed.target_refresh_in_uhz = 0;
972
+
973
+ in_out_vrr->btr.mid_point_in_us =
974
+ (in_out_vrr->min_duration_in_us +
975
+ in_out_vrr->max_duration_in_us) / 2;
976
+
977
+ if (in_out_vrr->state == VRR_STATE_UNSUPPORTED) {
978
+ in_out_vrr->adjust.v_total_min = stream->timing.v_total;
979
+ in_out_vrr->adjust.v_total_max = stream->timing.v_total;
980
+ } else if (in_out_vrr->state == VRR_STATE_DISABLED) {
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_INACTIVE) {
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_ACTIVE_VARIABLE &&
987
+ refresh_range >= MIN_REFRESH_RANGE) {
988
+
989
+ in_out_vrr->adjust.v_total_min =
990
+ calc_v_total_from_refresh(stream,
991
+ in_out_vrr->max_refresh_in_uhz);
992
+ in_out_vrr->adjust.v_total_max =
993
+ calc_v_total_from_refresh(stream,
994
+ in_out_vrr->min_refresh_in_uhz);
995
+ } else if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED) {
996
+ in_out_vrr->fixed.target_refresh_in_uhz =
997
+ in_out_vrr->fixed_refresh_in_uhz;
998
+ if (in_out_vrr->fixed.ramping_active &&
999
+ in_out_vrr->fixed.fixed_active) {
1000
+ /* Do not update vtotals if ramping is already active
1001
+ * in order to continue ramp from current refresh.
1002
+ */
1003
+ in_out_vrr->fixed.fixed_active = true;
1004
+ } else {
1005
+ in_out_vrr->fixed.fixed_active = true;
1006
+ in_out_vrr->adjust.v_total_min =
1007
+ calc_v_total_from_refresh(stream,
1008
+ in_out_vrr->fixed.target_refresh_in_uhz);
1009
+ in_out_vrr->adjust.v_total_max =
1010
+ in_out_vrr->adjust.v_total_min;
1011
+ }
1012
+ } else {
1013
+ in_out_vrr->state = VRR_STATE_INACTIVE;
1014
+ in_out_vrr->adjust.v_total_min = stream->timing.v_total;
1015
+ in_out_vrr->adjust.v_total_max = stream->timing.v_total;
1016
+ }
1017
+}
1018
+
1019
+void mod_freesync_handle_preflip(struct mod_freesync *mod_freesync,
1020
+ const struct dc_plane_state *plane,
1021
+ const struct dc_stream_state *stream,
1022
+ unsigned int curr_time_stamp_in_us,
1023
+ struct mod_vrr_params *in_out_vrr)
1024
+{
1025
+ struct core_freesync *core_freesync = NULL;
1026
+ unsigned int last_render_time_in_us = 0;
1027
+ unsigned int average_render_time_in_us = 0;
1028
+
1029
+ if (mod_freesync == NULL)
1030
+ return;
1031
+
1032
+ core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1033
+
1034
+ if (in_out_vrr->supported &&
1035
+ in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE) {
1036
+ unsigned int i = 0;
1037
+ unsigned int oldest_index = plane->time.index + 1;
1038
+
1039
+ if (oldest_index >= DC_PLANE_UPDATE_TIMES_MAX)
1040
+ oldest_index = 0;
1041
+
1042
+ last_render_time_in_us = curr_time_stamp_in_us -
1043
+ plane->time.prev_update_time_in_us;
1044
+
1045
+ // Sum off all entries except oldest one
1046
+ for (i = 0; i < DC_PLANE_UPDATE_TIMES_MAX; i++) {
1047
+ average_render_time_in_us +=
1048
+ plane->time.time_elapsed_in_us[i];
1049
+ }
1050
+ average_render_time_in_us -=
1051
+ plane->time.time_elapsed_in_us[oldest_index];
1052
+
1053
+ // Add render time for current flip
1054
+ average_render_time_in_us += last_render_time_in_us;
1055
+ average_render_time_in_us /= DC_PLANE_UPDATE_TIMES_MAX;
1056
+
1057
+ if (in_out_vrr->btr.btr_enabled) {
1058
+ apply_below_the_range(core_freesync,
1059
+ stream,
1060
+ last_render_time_in_us,
1061
+ in_out_vrr);
1062
+ } else {
1063
+ apply_fixed_refresh(core_freesync,
1064
+ stream,
1065
+ last_render_time_in_us,
1066
+ in_out_vrr);
1067
+ }
1068
+
1069
+ }
1070
+}
1071
+
1072
+void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync,
1073
+ const struct dc_stream_state *stream,
1074
+ struct mod_vrr_params *in_out_vrr)
1075
+{
1076
+ struct core_freesync *core_freesync = NULL;
1077
+
1078
+ if ((mod_freesync == NULL) || (stream == NULL) || (in_out_vrr == NULL))
1079
+ return;
1080
+
1081
+ core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1082
+
1083
+ if (in_out_vrr->supported == false)
1084
+ return;
1085
+
1086
+ /* Below the Range Logic */
1087
+
1088
+ /* Only execute if in fullscreen mode */
1089
+ if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE &&
1090
+ in_out_vrr->btr.btr_active) {
1091
+ /* TODO: pass in flag for Pre-DCE12 ASIC
1092
+ * in order for frame variable duration to take affect,
1093
+ * it needs to be done one VSYNC early, which is at
1094
+ * frameCounter == 1.
1095
+ * For DCE12 and newer updates to V_TOTAL_MIN/MAX
1096
+ * will take affect on current frame
1097
+ */
1098
+ if (in_out_vrr->btr.frames_to_insert ==
1099
+ in_out_vrr->btr.frame_counter) {
1100
+ in_out_vrr->adjust.v_total_min =
1101
+ calc_v_total_from_duration(stream,
1102
+ in_out_vrr,
1103
+ in_out_vrr->btr.inserted_duration_in_us);
1104
+ in_out_vrr->adjust.v_total_max =
1105
+ in_out_vrr->adjust.v_total_min;
1106
+ }
1107
+
1108
+ if (in_out_vrr->btr.frame_counter > 0)
1109
+ in_out_vrr->btr.frame_counter--;
13671110
13681111 /* 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);
1112
+ if (in_out_vrr->btr.frame_counter == 0) {
1113
+ in_out_vrr->adjust.v_total_min =
1114
+ calc_v_total_from_refresh(stream,
1115
+ in_out_vrr->max_refresh_in_uhz);
1116
+ in_out_vrr->adjust.v_total_max =
1117
+ calc_v_total_from_refresh(stream,
1118
+ in_out_vrr->min_refresh_in_uhz);
13901119 }
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
-
14361120 }
1437
-}
14381121
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;
1122
+ /* If in fullscreen freesync mode or in video, do not program
1123
+ * static screen ramp values
1124
+ */
1125
+ if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE)
1126
+ in_out_vrr->fixed.ramping_active = false;
14441127
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
-
1128
+ /* Gradual Static Screen Ramping Logic */
1129
+ /* Execute if ramp is active and user enabled freesync static screen*/
1130
+ if (in_out_vrr->state == VRR_STATE_ACTIVE_FIXED &&
1131
+ in_out_vrr->fixed.ramping_active) {
1132
+ update_v_total_for_static_ramp(
1133
+ core_freesync, stream, in_out_vrr);
15141134 }
15151135 }
15161136
15171137 void mod_freesync_get_settings(struct mod_freesync *mod_freesync,
1518
- struct dc_stream_state **streams, int num_streams,
1138
+ const struct mod_vrr_params *vrr,
15191139 unsigned int *v_total_min, unsigned int *v_total_max,
15201140 unsigned int *event_triggers,
15211141 unsigned int *window_min, unsigned int *window_max,
....@@ -1523,33 +1143,94 @@
15231143 unsigned int *inserted_frames,
15241144 unsigned int *inserted_duration_in_us)
15251145 {
1526
- unsigned int stream_index, map_index;
1527
- struct core_freesync *core_freesync = NULL;
1528
-
15291146 if (mod_freesync == NULL)
15301147 return;
15311148
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
-
1149
+ if (vrr->supported) {
1150
+ *v_total_min = vrr->adjust.v_total_min;
1151
+ *v_total_max = vrr->adjust.v_total_max;
1152
+ *event_triggers = 0;
1153
+ *lfc_mid_point_in_us = vrr->btr.mid_point_in_us;
1154
+ *inserted_frames = vrr->btr.frames_to_insert;
1155
+ *inserted_duration_in_us = vrr->btr.inserted_duration_in_us;
15531156 }
15541157 }
15551158
1159
+unsigned long long mod_freesync_calc_nominal_field_rate(
1160
+ const struct dc_stream_state *stream)
1161
+{
1162
+ unsigned long long nominal_field_rate_in_uhz = 0;
1163
+ unsigned int total = stream->timing.h_total * stream->timing.v_total;
1164
+
1165
+ /* Calculate nominal field rate for stream, rounded up to nearest integer */
1166
+ nominal_field_rate_in_uhz = stream->timing.pix_clk_100hz;
1167
+ nominal_field_rate_in_uhz *= 100000000ULL;
1168
+
1169
+ nominal_field_rate_in_uhz = div_u64(nominal_field_rate_in_uhz, total);
1170
+
1171
+ return nominal_field_rate_in_uhz;
1172
+}
1173
+
1174
+bool mod_freesync_is_valid_range(uint32_t min_refresh_cap_in_uhz,
1175
+ uint32_t max_refresh_cap_in_uhz,
1176
+ uint32_t nominal_field_rate_in_uhz)
1177
+{
1178
+
1179
+ /* Typically nominal refresh calculated can have some fractional part.
1180
+ * Allow for some rounding error of actual video timing by taking floor
1181
+ * of caps and request. Round the nominal refresh rate.
1182
+ *
1183
+ * Dividing will convert everything to units in Hz although input
1184
+ * variable name is in uHz!
1185
+ *
1186
+ * Also note, this takes care of rounding error on the nominal refresh
1187
+ * so by rounding error we only expect it to be off by a small amount,
1188
+ * such as < 0.1 Hz. i.e. 143.9xxx or 144.1xxx.
1189
+ *
1190
+ * Example 1. Caps Min = 40 Hz, Max = 144 Hz
1191
+ * Request Min = 40 Hz, Max = 144 Hz
1192
+ * Nominal = 143.5x Hz rounded to 144 Hz
1193
+ * This function should allow this as valid request
1194
+ *
1195
+ * Example 2. Caps Min = 40 Hz, Max = 144 Hz
1196
+ * Request Min = 40 Hz, Max = 144 Hz
1197
+ * Nominal = 144.4x Hz rounded to 144 Hz
1198
+ * This function should allow this as valid request
1199
+ *
1200
+ * Example 3. Caps Min = 40 Hz, Max = 144 Hz
1201
+ * Request Min = 40 Hz, Max = 144 Hz
1202
+ * Nominal = 120.xx Hz rounded to 120 Hz
1203
+ * This function should return NOT valid since the requested
1204
+ * max is greater than current timing's nominal
1205
+ *
1206
+ * Example 4. Caps Min = 40 Hz, Max = 120 Hz
1207
+ * Request Min = 40 Hz, Max = 120 Hz
1208
+ * Nominal = 144.xx Hz rounded to 144 Hz
1209
+ * This function should return NOT valid since the nominal
1210
+ * is greater than the capability's max refresh
1211
+ */
1212
+ nominal_field_rate_in_uhz =
1213
+ div_u64(nominal_field_rate_in_uhz + 500000, 1000000);
1214
+ min_refresh_cap_in_uhz /= 1000000;
1215
+ max_refresh_cap_in_uhz /= 1000000;
1216
+
1217
+ // Check nominal is within range
1218
+ if (nominal_field_rate_in_uhz > max_refresh_cap_in_uhz ||
1219
+ nominal_field_rate_in_uhz < min_refresh_cap_in_uhz)
1220
+ return false;
1221
+
1222
+ // If nominal is less than max, limit the max allowed refresh rate
1223
+ if (nominal_field_rate_in_uhz < max_refresh_cap_in_uhz)
1224
+ max_refresh_cap_in_uhz = nominal_field_rate_in_uhz;
1225
+
1226
+ // Check min is within range
1227
+ if (min_refresh_cap_in_uhz > max_refresh_cap_in_uhz)
1228
+ return false;
1229
+
1230
+ // For variable range, check for at least 10 Hz range
1231
+ if (nominal_field_rate_in_uhz - min_refresh_cap_in_uhz < 10)
1232
+ return false;
1233
+
1234
+ return true;
1235
+}
1236
+