drm/amd/display: block odd h_total timings from halving pixel rate
authorMartin Leung <Martin.Leung@amd.com>
Fri, 23 Sep 2022 21:55:14 +0000 (17:55 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Thu, 6 Oct 2022 16:01:23 +0000 (12:01 -0400)
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.Lei@amd.com>
Acked-by: Hamza Mahfooz <hamza.mahfooz@amd.com>
Signed-off-by: Martin Leung <Martin.Leung@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c

index 0e9dce4..3195be9 100644 (file)
@@ -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;
                }
index a750343..8012a48 100644 (file)
@@ -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;