From: Martin Leung <martin.le...@amd.com>

why:
when dynamic odm was turned on, there is also logic to halve the pixelclk
this still turned on when we avoided odm in the case of odd h_total timings

how:
block the pixel clk mechanism also in the case of odd h_total timings

Reviewed-by: Jun Lei <jun....@amd.com>
Acked-by: Hamza Mahfooz <hamza.mahf...@amd.com>
Signed-off-by: Martin Leung <martin.le...@amd.com>
---
 .../dc/dcn32/dcn32_dio_stream_encoder.c       | 35 ++++++++++++++++++-
 .../drm/amd/display/dc/dcn32/dcn32_hwseq.c    |  9 ++---
 2 files changed, 39 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.c 
b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.c
index 0e9dce414641..3195be9d38f5 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.c
@@ -243,6 +243,39 @@ static bool is_two_pixels_per_containter(const struct 
dc_crtc_timing *timing)
        return two_pix;
 }
 
+static bool is_h_timing_divisible_by_2(const struct dc_crtc_timing *timing)
+{
+       /* math borrowed from function of same name in inc/resource
+        * checks if h_timing is divisible by 2
+        */
+
+       bool divisible = false;
+       uint16_t h_blank_start = 0;
+       uint16_t h_blank_end = 0;
+
+       if (timing) {
+               h_blank_start = timing->h_total - timing->h_front_porch;
+               h_blank_end = h_blank_start - timing->h_addressable;
+
+               /* HTOTAL, Hblank start/end, and Hsync start/end all must be
+                * divisible by 2 in order for the horizontal timing params
+                * to be considered divisible by 2. Hsync start is always 0.
+                */
+               divisible = (timing->h_total % 2 == 0) &&
+                               (h_blank_start % 2 == 0) &&
+                               (h_blank_end % 2 == 0) &&
+                               (timing->h_sync_width % 2 == 0);
+       }
+       return divisible;
+}
+
+static bool is_dp_dig_pixel_rate_div_policy(struct dc *dc, const struct 
dc_crtc_timing *timing)
+{
+       /* should be functionally the same as 
dcn32_is_dp_dig_pixel_rate_div_policy for DP encoders*/
+       return is_h_timing_divisible_by_2(timing) &&
+               dc->debug.enable_dp_dig_pixel_rate_div_policy;
+}
+
 static void enc32_stream_encoder_dp_unblank(
         struct dc_link *link,
                struct stream_encoder *enc,
@@ -259,7 +292,7 @@ static void enc32_stream_encoder_dp_unblank(
 
                /* YCbCr 4:2:0 : Computed VID_M will be 2X the input rate */
                if (is_two_pixels_per_containter(&param->timing) || 
param->opp_cnt > 1
-                       || dc->debug.enable_dp_dig_pixel_rate_div_policy) {
+                       || is_dp_dig_pixel_rate_div_policy(dc, &param->timing)) 
{
                        /*this logic should be the same in 
get_pixel_clock_parameters() */
                        n_multiply = 1;
                }
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c 
b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c
index a750343ca521..8012a48859b5 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c
@@ -1161,7 +1161,6 @@ unsigned int dcn32_calculate_dccg_k1_k2_values(struct 
pipe_ctx *pipe_ctx, unsign
 {
        struct dc_stream_state *stream = pipe_ctx->stream;
        unsigned int odm_combine_factor = 0;
-       struct dc *dc = pipe_ctx->stream->ctx->dc;
        bool two_pix_per_container = false;
 
        // For phantom pipes, use the same programming as the main pipes
@@ -1189,7 +1188,7 @@ unsigned int dcn32_calculate_dccg_k1_k2_values(struct 
pipe_ctx *pipe_ctx, unsign
                } else {
                        *k1_div = PIXEL_RATE_DIV_BY_1;
                        *k2_div = PIXEL_RATE_DIV_BY_4;
-                       if ((odm_combine_factor == 2) || 
dc->debug.enable_dp_dig_pixel_rate_div_policy)
+                       if ((odm_combine_factor == 2) || 
dcn32_is_dp_dig_pixel_rate_div_policy(pipe_ctx))
                                *k2_div = PIXEL_RATE_DIV_BY_2;
                }
        }
@@ -1226,7 +1225,6 @@ void dcn32_unblank_stream(struct pipe_ctx *pipe_ctx,
        struct dc_link *link = stream->link;
        struct dce_hwseq *hws = link->dc->hwseq;
        struct pipe_ctx *odm_pipe;
-       struct dc *dc = pipe_ctx->stream->ctx->dc;
        uint32_t pix_per_cycle = 1;
 
        params.opp_cnt = 1;
@@ -1245,7 +1243,7 @@ void dcn32_unblank_stream(struct pipe_ctx *pipe_ctx,
                                pipe_ctx->stream_res.tg->inst);
        } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
                if (optc2_is_two_pixels_per_containter(&stream->timing) || 
params.opp_cnt > 1
-                       || dc->debug.enable_dp_dig_pixel_rate_div_policy) {
+                       || dcn32_is_dp_dig_pixel_rate_div_policy(pipe_ctx)) {
                        params.timing.pix_clk_100hz /= 2;
                        pix_per_cycle = 2;
                }
@@ -1262,6 +1260,9 @@ bool dcn32_is_dp_dig_pixel_rate_div_policy(struct 
pipe_ctx *pipe_ctx)
 {
        struct dc *dc = pipe_ctx->stream->ctx->dc;
 
+       if (!is_h_timing_divisible_by_2(pipe_ctx->stream))
+               return false;
+
        if (dc_is_dp_signal(pipe_ctx->stream->signal) && 
!is_dp_128b_132b_signal(pipe_ctx) &&
                dc->debug.enable_dp_dig_pixel_rate_div_policy)
                return true;
-- 
2.37.2

Reply via email to