From: Ethan Bitnun <etbitnun@xxxxxxx> [WHAT & HOW] - Populate dml 2 callback with get_max_flickerless_instant_vtotal_increase - Use long long when necessary to prevent overflow - Add asic specific default values, currently disabled by default for every asic - Use the pre-existing debug option to protect the call to get_max_flickerless_instant_vtotal_increase Reviewed-by: Alvin Lee <alvin.lee2@xxxxxxx> Acked-by: Alex Hung <alex.hung@xxxxxxx> Signed-off-by: Ethan Bitnun <etbitnun@xxxxxxx> --- .../gpu/drm/amd/display/dc/core/dc_resource.c | 3 + .../gpu/drm/amd/display/dc/core/dc_stream.c | 64 +++++++++++++++++-- .../gpu/drm/amd/display/dc/dc_stream_priv.h | 14 ++++ .../display/dc/dcn32/dcn32_resource_helpers.c | 2 +- .../drm/amd/display/dc/dml2/dml2_wrapper.h | 3 + 5 files changed, 79 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 8a5cc8b80217..70c39eef99e5 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -43,6 +43,8 @@ #include "link.h" #include "clk_mgr.h" #include "dc_state_priv.h" +#include "dc_stream_priv.h" + #include "virtual/virtual_link_hwss.h" #include "link/hwss/link_hwss_dio.h" #include "link/hwss/link_hwss_dpia.h" @@ -5195,6 +5197,7 @@ void resource_init_common_dml2_callbacks(struct dc *dc, struct dml2_configuratio dml2_options->callbacks.get_dpp_pipes_for_plane = &resource_get_dpp_pipes_for_plane; dml2_options->callbacks.get_stream_status = &dc_state_get_stream_status; dml2_options->callbacks.get_stream_from_id = &dc_state_get_stream_from_id; + dml2_options->callbacks.get_max_flickerless_instant_vtotal_increase = &dc_stream_get_max_flickerless_instant_vtotal_increase; dml2_options->svp_pstate.callbacks.dc = dc; dml2_options->svp_pstate.callbacks.add_phantom_plane = &dc_state_add_phantom_plane; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index b5a89b587d86..de48084eac25 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -833,7 +833,7 @@ static int dc_stream_get_brightness_millinits_linear_interpolation (struct dc_st int index2, int refresh_hz) { - int slope = 0; + long long slope = 0; if (stream->lumin_data.refresh_rate_hz[index2] != stream->lumin_data.refresh_rate_hz[index1]) { slope = (stream->lumin_data.luminance_millinits[index2] - stream->lumin_data.luminance_millinits[index1]) / (stream->lumin_data.refresh_rate_hz[index2] - stream->lumin_data.refresh_rate_hz[index1]); @@ -852,7 +852,7 @@ static int dc_stream_get_refresh_hz_linear_interpolation (struct dc_stream_state int index2, int brightness_millinits) { - int slope = 1; + long long slope = 1; if (stream->lumin_data.refresh_rate_hz[index2] != stream->lumin_data.refresh_rate_hz[index1]) { slope = (stream->lumin_data.luminance_millinits[index2] - stream->lumin_data.luminance_millinits[index1]) / (stream->lumin_data.refresh_rate_hz[index2] - stream->lumin_data.refresh_rate_hz[index1]); @@ -860,7 +860,7 @@ static int dc_stream_get_refresh_hz_linear_interpolation (struct dc_stream_state int y_intercept = stream->lumin_data.luminance_millinits[index2] - slope * stream->lumin_data.refresh_rate_hz[index2]; - return ((brightness_millinits - y_intercept) / slope); + return ((int)div64_s64((brightness_millinits - y_intercept), slope)); } /* @@ -884,8 +884,9 @@ static int dc_stream_get_brightness_millinits_from_refresh (struct dc_stream_sta } /* - * Finds the lowest refresh rate that can be achieved - * from starting_refresh_hz while staying within flicker criteria + * Finds the lowest/highest refresh rate (depending on search_for_max_increase) + * that can be achieved from starting_refresh_hz while staying + * within flicker criteria */ static int dc_stream_calculate_flickerless_refresh_rate(struct dc_stream_state *stream, int current_brightness, @@ -942,7 +943,7 @@ static int dc_stream_calculate_flickerless_refresh_rate(struct dc_stream_state * } if (search_for_max_increase) - return stream->lumin_data.refresh_rate_hz[LUMINANCE_DATA_TABLE_SIZE - 1]; + return (int)div64_s64((long long)stream->timing.pix_clk_100hz*100, stream->timing.v_total*stream->timing.h_total); else return stream->lumin_data.refresh_rate_hz[0]; } @@ -982,6 +983,31 @@ static int dc_stream_get_max_delta_lumin_millinits(struct dc_stream_state *strea return (max - min); } +/* + * Determines the max flickerless instant vtotal delta for a stream. + * Determines vtotal increase/decrease based on the bool "increase" + */ +static unsigned int dc_stream_get_max_flickerless_instant_vtotal_delta(struct dc_stream_state *stream, bool is_gaming, bool increase) +{ + if (stream->timing.v_total * stream->timing.h_total == 0) + return 0; + + int current_refresh_hz = (int)div64_s64((long long)stream->timing.pix_clk_100hz*100, stream->timing.v_total*stream->timing.h_total); + + int safe_refresh_hz = dc_stream_calculate_flickerless_refresh_rate(stream, + dc_stream_get_brightness_millinits_from_refresh(stream, current_refresh_hz), + current_refresh_hz, + is_gaming, + increase); + + int safe_refresh_v_total = (int)div64_s64((long long)stream->timing.pix_clk_100hz*100, safe_refresh_hz*stream->timing.h_total); + + if (increase) + return ((stream->timing.v_total - safe_refresh_v_total) >= 0) ? (stream->timing.v_total - safe_refresh_v_total) : 0; + + return ((safe_refresh_v_total - stream->timing.v_total) >= 0) ? (safe_refresh_v_total - stream->timing.v_total) : 0; +} + /* * Finds the highest refresh rate that can be achieved * from starting_refresh_hz while staying within flicker criteria @@ -1038,3 +1064,29 @@ bool dc_stream_is_refresh_rate_range_flickerless(struct dc_stream_state *stream, return (dl <= flicker_criteria_millinits); } + +/* + * Determines the max instant vtotal delta increase that can be applied without + * flickering for a given stream + */ +unsigned int dc_stream_get_max_flickerless_instant_vtotal_decrease(struct dc_stream_state *stream, + bool is_gaming) +{ + if (!stream->lumin_data.is_valid) + return 0; + + return dc_stream_get_max_flickerless_instant_vtotal_delta(stream, is_gaming, true); +} + +/* + * Determines the max instant vtotal delta decrease that can be applied without + * flickering for a given stream + */ +unsigned int dc_stream_get_max_flickerless_instant_vtotal_increase(struct dc_stream_state *stream, + bool is_gaming) +{ + if (!stream->lumin_data.is_valid) + return 0; + + return dc_stream_get_max_flickerless_instant_vtotal_delta(stream, is_gaming, false); +} diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream_priv.h b/drivers/gpu/drm/amd/display/dc/dc_stream_priv.h index ea13804f7b14..ca37eac20986 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream_priv.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream_priv.h @@ -58,4 +58,18 @@ bool dc_stream_is_refresh_rate_range_flickerless(struct dc_stream_state *stream, int hz2, bool is_gaming); +/* + * Determines the max instant vtotal delta increase that can be applied without + * flickering for a given stream + */ +unsigned int dc_stream_get_max_flickerless_instant_vtotal_decrease(struct dc_stream_state *stream, + bool is_gaming); + +/* + * Determines the max instant vtotal delta decrease that can be applied without + * flickering for a given stream + */ +unsigned int dc_stream_get_max_flickerless_instant_vtotal_increase(struct dc_stream_state *stream, + bool is_gaming); + #endif // _DC_STREAM_PRIV_H_ diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c index eba7bfc7e4af..d184105ce2b3 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c @@ -474,7 +474,7 @@ static bool is_refresh_rate_support_mclk_switch_using_fw_based_vblank_stretch( if (refresh_rate_max_stretch_100hz < min_refresh_100hz) return false; - if (fpo_candidate_stream->ctx->dc->config.enable_fpo_flicker_detection > 0 && + if (fpo_candidate_stream->ctx->dc->config.enable_fpo_flicker_detection == 1 && !dc_stream_is_refresh_rate_range_flickerless(fpo_candidate_stream, (refresh_rate_max_stretch_100hz / 100), current_refresh_rate, false)) return false; diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h b/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h index 4e4ed1678d91..dcb4e6f4d916 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h @@ -104,6 +104,9 @@ struct dml2_dc_callbacks { struct dc_state *state, const struct dc_stream_state *stream); struct dc_stream_state *(*get_stream_from_id)(const struct dc_state *state, unsigned int id); + unsigned int (*get_max_flickerless_instant_vtotal_increase)( + struct dc_stream_state *stream, + bool is_gaming); }; struct dml2_dc_svp_callbacks { -- 2.34.1