From: Ethan Bitnun <etbit...@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.l...@amd.com>
Acked-by: Alex Hung <alex.h...@amd.com>
Signed-off-by: Ethan Bitnun <etbit...@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

Reply via email to