|
@@ -76,6 +76,16 @@ struct fixed_refresh {
|
|
|
bool program_fixed_refresh;
|
|
|
};
|
|
|
|
|
|
+struct freesync_range {
|
|
|
+ unsigned int min_refresh;
|
|
|
+ unsigned int max_frame_duration;
|
|
|
+ unsigned int vmax;
|
|
|
+
|
|
|
+ unsigned int max_refresh;
|
|
|
+ unsigned int min_frame_duration;
|
|
|
+ unsigned int vmin;
|
|
|
+};
|
|
|
+
|
|
|
struct freesync_state {
|
|
|
bool fullscreen;
|
|
|
bool static_screen;
|
|
@@ -89,6 +99,7 @@ struct freesync_state {
|
|
|
struct gradual_static_ramp static_ramp;
|
|
|
struct below_the_range btr;
|
|
|
struct fixed_refresh fixed_refresh;
|
|
|
+ struct freesync_range freesync_range;
|
|
|
};
|
|
|
|
|
|
struct freesync_entity {
|
|
@@ -342,8 +353,11 @@ static void update_stream(struct core_freesync *core_freesync,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void calc_vmin_vmax(struct core_freesync *core_freesync,
|
|
|
- const struct dc_stream *stream, int *vmin, int *vmax)
|
|
|
+static void calc_freesync_range(struct core_freesync *core_freesync,
|
|
|
+ const struct dc_stream *stream,
|
|
|
+ struct freesync_state *state,
|
|
|
+ unsigned int min_refresh_in_uhz,
|
|
|
+ unsigned int max_refresh_in_uhz)
|
|
|
{
|
|
|
unsigned int min_frame_duration_in_ns = 0, max_frame_duration_in_ns = 0;
|
|
|
unsigned int index = map_index_from_stream(core_freesync, stream);
|
|
@@ -351,29 +365,50 @@ static void calc_vmin_vmax(struct core_freesync *core_freesync,
|
|
|
|
|
|
min_frame_duration_in_ns = ((unsigned int) (div64_u64(
|
|
|
(1000000000ULL * 1000000),
|
|
|
- core_freesync->map[index].state.
|
|
|
- nominal_refresh_rate_in_micro_hz)));
|
|
|
+ max_refresh_in_uhz)));
|
|
|
max_frame_duration_in_ns = ((unsigned int) (div64_u64(
|
|
|
- (1000000000ULL * 1000000),
|
|
|
- core_freesync->map[index].caps->min_refresh_in_micro_hz)));
|
|
|
+ (1000000000ULL * 1000000),
|
|
|
+ min_refresh_in_uhz)));
|
|
|
+
|
|
|
+ state->freesync_range.min_refresh = min_refresh_in_uhz;
|
|
|
+ state->freesync_range.max_refresh = max_refresh_in_uhz;
|
|
|
|
|
|
- *vmax = div64_u64(div64_u64(((unsigned long long)(
|
|
|
- max_frame_duration_in_ns) * stream->timing.pix_clk_khz),
|
|
|
- stream->timing.h_total), 1000000);
|
|
|
- *vmin = div64_u64(div64_u64(((unsigned long long)(
|
|
|
- min_frame_duration_in_ns) * stream->timing.pix_clk_khz),
|
|
|
- stream->timing.h_total), 1000000);
|
|
|
+ state->freesync_range.max_frame_duration = max_frame_duration_in_ns;
|
|
|
+ state->freesync_range.min_frame_duration = min_frame_duration_in_ns;
|
|
|
+
|
|
|
+ state->freesync_range.vmax = div64_u64(div64_u64(((unsigned long long)(
|
|
|
+ max_frame_duration_in_ns) * stream->timing.pix_clk_khz),
|
|
|
+ stream->timing.h_total), 1000000);
|
|
|
+ state->freesync_range.vmin = div64_u64(div64_u64(((unsigned long long)(
|
|
|
+ min_frame_duration_in_ns) * stream->timing.pix_clk_khz),
|
|
|
+ stream->timing.h_total), 1000000);
|
|
|
|
|
|
/* In case of 4k free sync monitor, vmin or vmax cannot be less than vtotal */
|
|
|
- if (*vmin < vtotal) {
|
|
|
+ if (state->freesync_range.vmin < vtotal) {
|
|
|
ASSERT(false);
|
|
|
- *vmin = vtotal;
|
|
|
+ state->freesync_range.vmin = vtotal;
|
|
|
}
|
|
|
|
|
|
- if (*vmax < vtotal) {
|
|
|
+ if (state->freesync_range.vmax < vtotal) {
|
|
|
ASSERT(false);
|
|
|
- *vmax = vtotal;
|
|
|
+ state->freesync_range.vmax = vtotal;
|
|
|
}
|
|
|
+
|
|
|
+ /* Determine whether BTR can be supported */
|
|
|
+ if (max_frame_duration_in_ns >=
|
|
|
+ 2 * min_frame_duration_in_ns)
|
|
|
+ core_freesync->map[index].caps->btr_supported = true;
|
|
|
+ else
|
|
|
+ core_freesync->map[index].caps->btr_supported = false;
|
|
|
+
|
|
|
+ /* Cache the time variables */
|
|
|
+ state->time.max_render_time_in_us =
|
|
|
+ max_frame_duration_in_ns / 1000;
|
|
|
+ state->time.min_render_time_in_us =
|
|
|
+ min_frame_duration_in_ns / 1000;
|
|
|
+ state->btr.mid_point_in_us =
|
|
|
+ (max_frame_duration_in_ns +
|
|
|
+ min_frame_duration_in_ns) / 2000;
|
|
|
}
|
|
|
|
|
|
static void calc_v_total_from_duration(const struct dc_stream *stream,
|
|
@@ -518,9 +553,8 @@ static bool set_freesync_on_streams(struct core_freesync *core_freesync,
|
|
|
state->fixed_refresh.fixed_refresh_active == false) {
|
|
|
/* Enable freesync */
|
|
|
|
|
|
- calc_vmin_vmax(core_freesync,
|
|
|
- streams[stream_idx],
|
|
|
- &v_total_min, &v_total_max);
|
|
|
+ v_total_min = state->freesync_range.vmin;
|
|
|
+ v_total_max = state->freesync_range.vmax;
|
|
|
|
|
|
/* Update the freesync context for the stream */
|
|
|
update_stream_freesync_context(core_freesync,
|
|
@@ -696,7 +730,7 @@ void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync,
|
|
|
(1000000000ULL * 1000000),
|
|
|
state->nominal_refresh_rate_in_micro_hz)));
|
|
|
|
|
|
- calc_vmin_vmax(core_freesync, *streams, &vmin, &vmax);
|
|
|
+ vmin = state->freesync_range.vmin;
|
|
|
|
|
|
inserted_frame_v_total = vmin;
|
|
|
|
|
@@ -941,11 +975,120 @@ bool mod_freesync_get_user_enable(struct mod_freesync *mod_freesync,
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+bool mod_freesync_override_min_max(struct mod_freesync *mod_freesync,
|
|
|
+ const struct dc_stream *streams,
|
|
|
+ unsigned int min_refresh,
|
|
|
+ unsigned int max_refresh)
|
|
|
+{
|
|
|
+ unsigned int index = 0;
|
|
|
+ struct core_freesync *core_freesync;
|
|
|
+ struct freesync_state *state;
|
|
|
+
|
|
|
+ if (mod_freesync == NULL)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
|
|
|
+ index = map_index_from_stream(core_freesync, streams);
|
|
|
+ state = &core_freesync->map[index].state;
|
|
|
+
|
|
|
+ if (min_refresh == 0 || max_refresh == 0) {
|
|
|
+ /* Restore defaults */
|
|
|
+ calc_freesync_range(core_freesync, streams, state,
|
|
|
+ core_freesync->map[index].caps->
|
|
|
+ min_refresh_in_micro_hz,
|
|
|
+ state->nominal_refresh_rate_in_micro_hz);
|
|
|
+ } else {
|
|
|
+ calc_freesync_range(core_freesync, streams,
|
|
|
+ state,
|
|
|
+ min_refresh,
|
|
|
+ max_refresh);
|
|
|
+
|
|
|
+ /* Program vtotal min/max */
|
|
|
+ core_freesync->dc->stream_funcs.adjust_vmin_vmax(
|
|
|
+ core_freesync->dc, &streams, 1,
|
|
|
+ state->freesync_range.vmin,
|
|
|
+ state->freesync_range.vmax);
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+bool mod_freesync_get_min_max(struct mod_freesync *mod_freesync,
|
|
|
+ const struct dc_stream *stream,
|
|
|
+ unsigned int *min_refresh,
|
|
|
+ unsigned int *max_refresh)
|
|
|
+{
|
|
|
+ unsigned int index = 0;
|
|
|
+ struct core_freesync *core_freesync = NULL;
|
|
|
+
|
|
|
+ if (mod_freesync == NULL)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
|
|
|
+ index = map_index_from_stream(core_freesync, stream);
|
|
|
+
|
|
|
+ *min_refresh =
|
|
|
+ core_freesync->map[index].state.freesync_range.min_refresh;
|
|
|
+ *max_refresh =
|
|
|
+ core_freesync->map[index].state.freesync_range.max_refresh;
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+bool mod_freesync_get_vmin_vmax(struct mod_freesync *mod_freesync,
|
|
|
+ const struct dc_stream *stream,
|
|
|
+ unsigned int *vmin,
|
|
|
+ unsigned int *vmax)
|
|
|
+{
|
|
|
+ unsigned int index = 0;
|
|
|
+ struct core_freesync *core_freesync = NULL;
|
|
|
+
|
|
|
+ if (mod_freesync == NULL)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
|
|
|
+ index = map_index_from_stream(core_freesync, stream);
|
|
|
+
|
|
|
+ *vmin =
|
|
|
+ core_freesync->map[index].state.freesync_range.vmin;
|
|
|
+ *vmax =
|
|
|
+ core_freesync->map[index].state.freesync_range.vmax;
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+bool mod_freesync_get_v_position(struct mod_freesync *mod_freesync,
|
|
|
+ const struct dc_stream *stream,
|
|
|
+ unsigned int *nom_v_pos,
|
|
|
+ unsigned int *v_pos)
|
|
|
+{
|
|
|
+ unsigned int index = 0;
|
|
|
+ struct core_freesync *core_freesync = NULL;
|
|
|
+ struct crtc_position position;
|
|
|
+
|
|
|
+ if (mod_freesync == NULL)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync);
|
|
|
+ index = map_index_from_stream(core_freesync, stream);
|
|
|
+
|
|
|
+ if (core_freesync->dc->stream_funcs.get_crtc_position(
|
|
|
+ core_freesync->dc, &stream, 1,
|
|
|
+ &position.vertical_count, &position.nominal_vcount)) {
|
|
|
+
|
|
|
+ *nom_v_pos = position.vertical_count;
|
|
|
+ *v_pos = position.nominal_vcount;
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
void mod_freesync_notify_mode_change(struct mod_freesync *mod_freesync,
|
|
|
const struct dc_stream **streams, int num_streams)
|
|
|
{
|
|
|
unsigned int stream_index, map_index;
|
|
|
- unsigned min_frame_duration_in_ns, max_frame_duration_in_ns;
|
|
|
struct freesync_state *state;
|
|
|
struct core_freesync *core_freesync = NULL;
|
|
|
|
|
@@ -965,37 +1108,23 @@ void mod_freesync_notify_mode_change(struct mod_freesync *mod_freesync,
|
|
|
unsigned long long temp;
|
|
|
temp = streams[stream_index]->timing.pix_clk_khz;
|
|
|
temp *= 1000ULL * 1000ULL * 1000ULL;
|
|
|
- temp = div_u64(temp, streams[stream_index]->timing.h_total);
|
|
|
- temp = div_u64(temp, streams[stream_index]->timing.v_total);
|
|
|
- state->nominal_refresh_rate_in_micro_hz = (unsigned int) temp;
|
|
|
+ temp = div_u64(temp,
|
|
|
+ streams[stream_index]->timing.h_total);
|
|
|
+ temp = div_u64(temp,
|
|
|
+ streams[stream_index]->timing.v_total);
|
|
|
+ state->nominal_refresh_rate_in_micro_hz =
|
|
|
+ (unsigned int) temp;
|
|
|
|
|
|
/* Update the stream */
|
|
|
update_stream(core_freesync, streams[stream_index]);
|
|
|
|
|
|
- /* Determine whether BTR can be supported */
|
|
|
- min_frame_duration_in_ns = ((unsigned int) (div64_u64(
|
|
|
- (1000000000ULL * 1000000),
|
|
|
- state->nominal_refresh_rate_in_micro_hz)));
|
|
|
-
|
|
|
- max_frame_duration_in_ns = ((unsigned int) (div64_u64(
|
|
|
- (1000000000ULL * 1000000),
|
|
|
- core_freesync->map[map_index].caps->min_refresh_in_micro_hz)));
|
|
|
-
|
|
|
- if (max_frame_duration_in_ns >=
|
|
|
- 2 * min_frame_duration_in_ns)
|
|
|
- core_freesync->map[map_index].caps->btr_supported = true;
|
|
|
- else
|
|
|
- core_freesync->map[map_index].caps->btr_supported = false;
|
|
|
-
|
|
|
- /* Cache the time variables */
|
|
|
- state->time.max_render_time_in_us =
|
|
|
- max_frame_duration_in_ns / 1000;
|
|
|
- state->time.min_render_time_in_us =
|
|
|
- min_frame_duration_in_ns / 1000;
|
|
|
- state->btr.mid_point_in_us =
|
|
|
- (max_frame_duration_in_ns +
|
|
|
- min_frame_duration_in_ns) / 2000;
|
|
|
-
|
|
|
+ /* Calculate vmin/vmax and refresh rate for
|
|
|
+ * current mode
|
|
|
+ */
|
|
|
+ calc_freesync_range(core_freesync, *streams, state,
|
|
|
+ core_freesync->map[stream_index].caps->
|
|
|
+ min_refresh_in_micro_hz,
|
|
|
+ state->nominal_refresh_rate_in_micro_hz);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1178,7 +1307,7 @@ static void apply_fixed_refresh(struct core_freesync *core_freesync,
|
|
|
/* Fixed Refresh set to "active" so engage (fix to max) */
|
|
|
} else {
|
|
|
|
|
|
- calc_vmin_vmax(core_freesync, stream, &vmin, &vmax);
|
|
|
+ vmin = state->freesync_range.vmin;
|
|
|
|
|
|
vmax = vmin;
|
|
|
|