diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/modules/freesync/freesync.c')
-rw-r--r-- | drivers/gpu/drm/amd/display/modules/freesync/freesync.c | 155 |
1 files changed, 125 insertions, 30 deletions
diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c index b4723af368a5..27d4003aa2c7 100644 --- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c | |||
@@ -33,7 +33,7 @@ | |||
33 | /* Refresh rate ramp at a fixed rate of 65 Hz/second */ | 33 | /* Refresh rate ramp at a fixed rate of 65 Hz/second */ |
34 | #define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65) | 34 | #define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65) |
35 | /* Number of elements in the render times cache array */ | 35 | /* Number of elements in the render times cache array */ |
36 | #define RENDER_TIMES_MAX_COUNT 20 | 36 | #define RENDER_TIMES_MAX_COUNT 10 |
37 | /* Threshold to exit BTR (to avoid frequent enter-exits at the lower limit) */ | 37 | /* Threshold to exit BTR (to avoid frequent enter-exits at the lower limit) */ |
38 | #define BTR_EXIT_MARGIN 2000 | 38 | #define BTR_EXIT_MARGIN 2000 |
39 | /* Number of consecutive frames to check before entering/exiting fixed refresh*/ | 39 | /* Number of consecutive frames to check before entering/exiting fixed refresh*/ |
@@ -46,13 +46,15 @@ | |||
46 | 46 | ||
47 | #define FREESYNC_NO_STATIC_FOR_INTERNAL_REGKEY "DalFreeSyncNoStaticForInternal" | 47 | #define FREESYNC_NO_STATIC_FOR_INTERNAL_REGKEY "DalFreeSyncNoStaticForInternal" |
48 | 48 | ||
49 | #define FREESYNC_DEFAULT_REGKEY "LCDFreeSyncDefault" | ||
50 | |||
49 | struct gradual_static_ramp { | 51 | struct gradual_static_ramp { |
50 | bool ramp_is_active; | 52 | bool ramp_is_active; |
51 | bool ramp_direction_is_up; | 53 | bool ramp_direction_is_up; |
52 | unsigned int ramp_current_frame_duration_in_ns; | 54 | unsigned int ramp_current_frame_duration_in_ns; |
53 | }; | 55 | }; |
54 | 56 | ||
55 | struct time_cache { | 57 | struct freesync_time { |
56 | /* video (48Hz feature) related */ | 58 | /* video (48Hz feature) related */ |
57 | unsigned int update_duration_in_ns; | 59 | unsigned int update_duration_in_ns; |
58 | 60 | ||
@@ -64,6 +66,9 @@ struct time_cache { | |||
64 | 66 | ||
65 | unsigned int render_times_index; | 67 | unsigned int render_times_index; |
66 | unsigned int render_times[RENDER_TIMES_MAX_COUNT]; | 68 | unsigned int render_times[RENDER_TIMES_MAX_COUNT]; |
69 | |||
70 | unsigned int min_window; | ||
71 | unsigned int max_window; | ||
67 | }; | 72 | }; |
68 | 73 | ||
69 | struct below_the_range { | 74 | struct below_the_range { |
@@ -98,11 +103,14 @@ struct freesync_state { | |||
98 | bool static_screen; | 103 | bool static_screen; |
99 | bool video; | 104 | bool video; |
100 | 105 | ||
106 | unsigned int vmin; | ||
107 | unsigned int vmax; | ||
108 | |||
109 | struct freesync_time time; | ||
110 | |||
101 | unsigned int nominal_refresh_rate_in_micro_hz; | 111 | unsigned int nominal_refresh_rate_in_micro_hz; |
102 | bool windowed_fullscreen; | 112 | bool windowed_fullscreen; |
103 | 113 | ||
104 | struct time_cache time; | ||
105 | |||
106 | struct gradual_static_ramp static_ramp; | 114 | struct gradual_static_ramp static_ramp; |
107 | struct below_the_range btr; | 115 | struct below_the_range btr; |
108 | struct fixed_refresh fixed_refresh; | 116 | struct fixed_refresh fixed_refresh; |
@@ -119,14 +127,16 @@ struct freesync_entity { | |||
119 | struct freesync_registry_options { | 127 | struct freesync_registry_options { |
120 | bool drr_external_supported; | 128 | bool drr_external_supported; |
121 | bool drr_internal_supported; | 129 | bool drr_internal_supported; |
130 | bool lcd_freesync_default_set; | ||
131 | int lcd_freesync_default_value; | ||
122 | }; | 132 | }; |
123 | 133 | ||
124 | struct core_freesync { | 134 | struct core_freesync { |
125 | struct mod_freesync public; | 135 | struct mod_freesync public; |
126 | struct dc *dc; | 136 | struct dc *dc; |
137 | struct freesync_registry_options opts; | ||
127 | struct freesync_entity *map; | 138 | struct freesync_entity *map; |
128 | int num_entities; | 139 | int num_entities; |
129 | struct freesync_registry_options opts; | ||
130 | }; | 140 | }; |
131 | 141 | ||
132 | #define MOD_FREESYNC_TO_CORE(mod_freesync)\ | 142 | #define MOD_FREESYNC_TO_CORE(mod_freesync)\ |
@@ -146,7 +156,7 @@ struct mod_freesync *mod_freesync_create(struct dc *dc) | |||
146 | goto fail_alloc_context; | 156 | goto fail_alloc_context; |
147 | 157 | ||
148 | core_freesync->map = kzalloc(sizeof(struct freesync_entity) * MOD_FREESYNC_MAX_CONCURRENT_STREAMS, | 158 | core_freesync->map = kzalloc(sizeof(struct freesync_entity) * MOD_FREESYNC_MAX_CONCURRENT_STREAMS, |
149 | GFP_KERNEL); | 159 | GFP_KERNEL); |
150 | 160 | ||
151 | if (core_freesync->map == NULL) | 161 | if (core_freesync->map == NULL) |
152 | goto fail_alloc_map; | 162 | goto fail_alloc_map; |
@@ -183,6 +193,16 @@ struct mod_freesync *mod_freesync_create(struct dc *dc) | |||
183 | (data & 1) ? false : true; | 193 | (data & 1) ? false : true; |
184 | } | 194 | } |
185 | 195 | ||
196 | if (dm_read_persistent_data(dc->ctx, NULL, NULL, | ||
197 | FREESYNC_DEFAULT_REGKEY, | ||
198 | &data, sizeof(data), &flag)) { | ||
199 | core_freesync->opts.lcd_freesync_default_set = true; | ||
200 | core_freesync->opts.lcd_freesync_default_value = data; | ||
201 | } else { | ||
202 | core_freesync->opts.lcd_freesync_default_set = false; | ||
203 | core_freesync->opts.lcd_freesync_default_value = 0; | ||
204 | } | ||
205 | |||
186 | return &core_freesync->public; | 206 | return &core_freesync->public; |
187 | 207 | ||
188 | fail_construct: | 208 | fail_construct: |
@@ -288,6 +308,18 @@ bool mod_freesync_add_stream(struct mod_freesync *mod_freesync, | |||
288 | core_freesync->map[core_freesync->num_entities].user_enable. | 308 | core_freesync->map[core_freesync->num_entities].user_enable. |
289 | enable_for_video = | 309 | enable_for_video = |
290 | (persistent_freesync_enable & 4) ? true : false; | 310 | (persistent_freesync_enable & 4) ? true : false; |
311 | /* If FreeSync display and LCDFreeSyncDefault is set, use as default values write back to userenable */ | ||
312 | } else if (caps->supported && (core_freesync->opts.lcd_freesync_default_set)) { | ||
313 | core_freesync->map[core_freesync->num_entities].user_enable.enable_for_gaming = | ||
314 | (core_freesync->opts.lcd_freesync_default_value & 1) ? true : false; | ||
315 | core_freesync->map[core_freesync->num_entities].user_enable.enable_for_static = | ||
316 | (core_freesync->opts.lcd_freesync_default_value & 2) ? true : false; | ||
317 | core_freesync->map[core_freesync->num_entities].user_enable.enable_for_video = | ||
318 | (core_freesync->opts.lcd_freesync_default_value & 4) ? true : false; | ||
319 | dm_write_persistent_data(dc->ctx, stream->sink, | ||
320 | FREESYNC_REGISTRY_NAME, | ||
321 | "userenable", &core_freesync->opts.lcd_freesync_default_value, | ||
322 | sizeof(int), &flag); | ||
291 | } else { | 323 | } else { |
292 | core_freesync->map[core_freesync->num_entities].user_enable. | 324 | core_freesync->map[core_freesync->num_entities].user_enable. |
293 | enable_for_gaming = false; | 325 | enable_for_gaming = false; |
@@ -330,6 +362,25 @@ bool mod_freesync_remove_stream(struct mod_freesync *mod_freesync, | |||
330 | return true; | 362 | return true; |
331 | } | 363 | } |
332 | 364 | ||
365 | static void adjust_vmin_vmax(struct core_freesync *core_freesync, | ||
366 | struct dc_stream_state **streams, | ||
367 | int num_streams, | ||
368 | int map_index, | ||
369 | unsigned int v_total_min, | ||
370 | unsigned int v_total_max) | ||
371 | { | ||
372 | if (num_streams == 0 || streams == NULL || num_streams > 1) | ||
373 | return; | ||
374 | |||
375 | core_freesync->map[map_index].state.vmin = v_total_min; | ||
376 | core_freesync->map[map_index].state.vmax = v_total_max; | ||
377 | |||
378 | dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, | ||
379 | num_streams, v_total_min, | ||
380 | v_total_max); | ||
381 | } | ||
382 | |||
383 | |||
333 | static void update_stream_freesync_context(struct core_freesync *core_freesync, | 384 | static void update_stream_freesync_context(struct core_freesync *core_freesync, |
334 | struct dc_stream_state *stream) | 385 | struct dc_stream_state *stream) |
335 | { | 386 | { |
@@ -588,9 +639,10 @@ static bool set_freesync_on_streams(struct core_freesync *core_freesync, | |||
588 | update_stream_freesync_context(core_freesync, | 639 | update_stream_freesync_context(core_freesync, |
589 | streams[stream_idx]); | 640 | streams[stream_idx]); |
590 | 641 | ||
591 | dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, | 642 | adjust_vmin_vmax(core_freesync, streams, |
592 | num_streams, v_total_min, | 643 | num_streams, map_index, |
593 | v_total_max); | 644 | v_total_min, |
645 | v_total_max); | ||
594 | 646 | ||
595 | return true; | 647 | return true; |
596 | 648 | ||
@@ -613,9 +665,10 @@ static bool set_freesync_on_streams(struct core_freesync *core_freesync, | |||
613 | core_freesync, | 665 | core_freesync, |
614 | streams[stream_idx]); | 666 | streams[stream_idx]); |
615 | 667 | ||
616 | dc_stream_adjust_vmin_vmax( | 668 | adjust_vmin_vmax( |
617 | core_freesync->dc, streams, | 669 | core_freesync, streams, |
618 | num_streams, v_total_nominal, | 670 | num_streams, map_index, |
671 | v_total_nominal, | ||
619 | v_total_nominal); | 672 | v_total_nominal); |
620 | } | 673 | } |
621 | return true; | 674 | return true; |
@@ -632,9 +685,10 @@ static bool set_freesync_on_streams(struct core_freesync *core_freesync, | |||
632 | core_freesync, | 685 | core_freesync, |
633 | streams[stream_idx]); | 686 | streams[stream_idx]); |
634 | 687 | ||
635 | dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, | 688 | adjust_vmin_vmax(core_freesync, streams, |
636 | num_streams, v_total_nominal, | 689 | num_streams, map_index, |
637 | v_total_nominal); | 690 | v_total_nominal, |
691 | v_total_nominal); | ||
638 | 692 | ||
639 | /* Reset the cached variables */ | 693 | /* Reset the cached variables */ |
640 | reset_freesync_state_variables(state); | 694 | reset_freesync_state_variables(state); |
@@ -650,9 +704,10 @@ static bool set_freesync_on_streams(struct core_freesync *core_freesync, | |||
650 | * not support freesync because a former stream has | 704 | * not support freesync because a former stream has |
651 | * be programmed | 705 | * be programmed |
652 | */ | 706 | */ |
653 | dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, | 707 | adjust_vmin_vmax(core_freesync, streams, |
654 | num_streams, v_total_nominal, | 708 | num_streams, map_index, |
655 | v_total_nominal); | 709 | v_total_nominal, |
710 | v_total_nominal); | ||
656 | /* Reset the cached variables */ | 711 | /* Reset the cached variables */ |
657 | reset_freesync_state_variables(state); | 712 | reset_freesync_state_variables(state); |
658 | } | 713 | } |
@@ -769,8 +824,9 @@ void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync, | |||
769 | vmin = inserted_frame_v_total; | 824 | vmin = inserted_frame_v_total; |
770 | 825 | ||
771 | /* Program V_TOTAL */ | 826 | /* Program V_TOTAL */ |
772 | dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, | 827 | adjust_vmin_vmax(core_freesync, streams, |
773 | num_streams, vmin, vmax); | 828 | num_streams, index, |
829 | vmin, vmax); | ||
774 | } | 830 | } |
775 | 831 | ||
776 | if (state->btr.frame_counter > 0) | 832 | if (state->btr.frame_counter > 0) |
@@ -804,9 +860,10 @@ void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync, | |||
804 | update_stream_freesync_context(core_freesync, streams[0]); | 860 | update_stream_freesync_context(core_freesync, streams[0]); |
805 | 861 | ||
806 | /* Program static screen ramp values */ | 862 | /* Program static screen ramp values */ |
807 | dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, | 863 | adjust_vmin_vmax(core_freesync, streams, |
808 | num_streams, v_total, | 864 | num_streams, index, |
809 | v_total); | 865 | v_total, |
866 | v_total); | ||
810 | 867 | ||
811 | triggers.overlay_update = true; | 868 | triggers.overlay_update = true; |
812 | triggers.surface_update = true; | 869 | triggers.surface_update = true; |
@@ -1063,9 +1120,9 @@ bool mod_freesync_override_min_max(struct mod_freesync *mod_freesync, | |||
1063 | max_refresh); | 1120 | max_refresh); |
1064 | 1121 | ||
1065 | /* Program vtotal min/max */ | 1122 | /* Program vtotal min/max */ |
1066 | dc_stream_adjust_vmin_vmax(core_freesync->dc, &streams, 1, | 1123 | adjust_vmin_vmax(core_freesync, &streams, 1, index, |
1067 | state->freesync_range.vmin, | 1124 | state->freesync_range.vmin, |
1068 | state->freesync_range.vmax); | 1125 | state->freesync_range.vmax); |
1069 | } | 1126 | } |
1070 | 1127 | ||
1071 | if (min_refresh != 0 && | 1128 | if (min_refresh != 0 && |
@@ -1399,11 +1456,9 @@ static void apply_fixed_refresh(struct core_freesync *core_freesync, | |||
1399 | } else { | 1456 | } else { |
1400 | 1457 | ||
1401 | vmin = state->freesync_range.vmin; | 1458 | vmin = state->freesync_range.vmin; |
1402 | |||
1403 | vmax = vmin; | 1459 | vmax = vmin; |
1404 | 1460 | adjust_vmin_vmax(core_freesync, &stream, map_index, | |
1405 | dc_stream_adjust_vmin_vmax(core_freesync->dc, &stream, | 1461 | 1, vmin, vmax); |
1406 | 1, vmin, vmax); | ||
1407 | } | 1462 | } |
1408 | } | 1463 | } |
1409 | 1464 | ||
@@ -1457,3 +1512,43 @@ void mod_freesync_pre_update_plane_addresses(struct mod_freesync *mod_freesync, | |||
1457 | 1512 | ||
1458 | } | 1513 | } |
1459 | } | 1514 | } |
1515 | |||
1516 | void mod_freesync_get_settings(struct mod_freesync *mod_freesync, | ||
1517 | struct dc_stream_state **streams, int num_streams, | ||
1518 | unsigned int *v_total_min, unsigned int *v_total_max, | ||
1519 | unsigned int *event_triggers, | ||
1520 | unsigned int *window_min, unsigned int *window_max, | ||
1521 | unsigned int *lfc_mid_point_in_us, | ||
1522 | unsigned int *inserted_frames, | ||
1523 | unsigned int *inserted_duration_in_us) | ||
1524 | { | ||
1525 | unsigned int stream_index, map_index; | ||
1526 | struct core_freesync *core_freesync = NULL; | ||
1527 | |||
1528 | if (mod_freesync == NULL) | ||
1529 | return; | ||
1530 | |||
1531 | core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); | ||
1532 | |||
1533 | for (stream_index = 0; stream_index < num_streams; stream_index++) { | ||
1534 | |||
1535 | map_index = map_index_from_stream(core_freesync, | ||
1536 | streams[stream_index]); | ||
1537 | |||
1538 | if (core_freesync->map[map_index].caps->supported) { | ||
1539 | struct freesync_state state = | ||
1540 | core_freesync->map[map_index].state; | ||
1541 | *v_total_min = state.vmin; | ||
1542 | *v_total_max = state.vmax; | ||
1543 | *event_triggers = 0; | ||
1544 | *window_min = state.time.min_window; | ||
1545 | *window_max = state.time.max_window; | ||
1546 | *lfc_mid_point_in_us = state.btr.mid_point_in_us; | ||
1547 | *inserted_frames = state.btr.frames_to_insert; | ||
1548 | *inserted_duration_in_us = | ||
1549 | state.btr.inserted_frame_duration_in_us; | ||
1550 | } | ||
1551 | |||
1552 | } | ||
1553 | } | ||
1554 | |||