hc
2024-01-03 2f7c68cb55ecb7331f2381deb497c27155f32faf
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,414 @@
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 (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;
716477 }
717478
718479 return false;
719480 }
720481
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
-
1165482 bool mod_freesync_get_vmin_vmax(struct mod_freesync *mod_freesync,
1166
- struct dc_stream_state *stream,
483
+ const struct dc_stream_state *stream,
1167484 unsigned int *vmin,
1168485 unsigned int *vmax)
1169486 {
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;
1183489
1184490 return true;
1185491 }
....@@ -1189,7 +495,6 @@
1189495 unsigned int *nom_v_pos,
1190496 unsigned int *v_pos)
1191497 {
1192
- unsigned int index = 0;
1193498 struct core_freesync *core_freesync = NULL;
1194499 struct crtc_position position;
1195500
....@@ -1197,7 +502,6 @@
1197502 return false;
1198503
1199504 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1200
- index = map_index_from_stream(core_freesync, stream);
1201505
1202506 if (dc_stream_get_crtc_position(core_freesync->dc, &stream, 1,
1203507 &position.vertical_count,
....@@ -1212,310 +516,629 @@
1212516 return false;
1213517 }
1214518
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)
1217521 {
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
+{
1220884 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;
1223890
1224891 if (mod_freesync == NULL)
1225892 return;
1226893
1227894 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
1228895
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);
1232899
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;
1234902
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;
1244906
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;
1246910
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);
1249917
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))
1355921 return;
1356922
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;
1358925
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;
1362931
1363
- /* Program BTR */
932
+ return;
1364933
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--;
13671113
13681114 /* 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);
13901122 }
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
-
14361123 }
1437
-}
14381124
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;
14441130
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);
15141137 }
15151138 }
15161139
15171140 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,
15191142 unsigned int *v_total_min, unsigned int *v_total_max,
15201143 unsigned int *event_triggers,
15211144 unsigned int *window_min, unsigned int *window_max,
....@@ -1523,33 +1146,94 @@
15231146 unsigned int *inserted_frames,
15241147 unsigned int *inserted_duration_in_us)
15251148 {
1526
- unsigned int stream_index, map_index;
1527
- struct core_freesync *core_freesync = NULL;
1528
-
15291149 if (mod_freesync == NULL)
15301150 return;
15311151
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;
15531159 }
15541160 }
15551161
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
+