[PATCH 18/20] drm/amd/display: Find max flickerless instant vtotal delta

Alex Hung alex.hung at amd.com
Wed May 8 17:13:18 UTC 2024


From: Ethan Bitnun <etbitnun at amd.com>

[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 at amd.com>
Acked-by: Alex Hung <alex.hung at amd.com>
Signed-off-by: Ethan Bitnun <etbitnun at amd.com>
---
 .../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



More information about the amd-gfx mailing list