drm/amd/display: Remove DISPCLK dentist programming for dcn32
authorDillon Varone <Dillon.Varone@amd.com>
Tue, 20 Dec 2022 20:45:48 +0000 (15:45 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 17 Jan 2023 20:40:10 +0000 (15:40 -0500)
[WHY?]
For dcn32, SMU handles DISPCLK dentist programming.

[HOW?]
Only use calls to SMU to set DISPCLK.

Tested-by: Daniel Wheeler <Daniel.Wheeler@amd.com>
Reviewed-by: Aric Cyr <Aric.Cyr@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Dillon Varone <Dillon.Varone@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c

index 791a788c52f2b89147a2ce47f7b6e618c5d03da6..352c977d1495a39f821725683521f53e103e51de 100644 (file)
@@ -256,6 +256,94 @@ static void dcn32_update_dppclk_dispclk_freq(struct clk_mgr_internal *clk_mgr, s
        }
 }
 
+static void dcn32_update_clocks_update_dentist(
+               struct clk_mgr_internal *clk_mgr,
+               struct dc_state *context,
+               uint32_t old_dispclk_khz)
+{
+       uint32_t new_disp_divider = 0;
+       uint32_t old_disp_divider = 0;
+       uint32_t new_dispclk_wdivider = 0;
+       uint32_t old_dispclk_wdivider = 0;
+       uint32_t i;
+
+       if (old_dispclk_khz == 0 || clk_mgr->base.clks.dispclk_khz == 0)
+               return;
+
+       new_disp_divider = DENTIST_DIVIDER_RANGE_SCALE_FACTOR
+                       * clk_mgr->base.dentist_vco_freq_khz / clk_mgr->base.clks.dispclk_khz;
+       old_disp_divider = DENTIST_DIVIDER_RANGE_SCALE_FACTOR
+                       * clk_mgr->base.dentist_vco_freq_khz / old_dispclk_khz;
+
+       new_dispclk_wdivider = dentist_get_did_from_divider(new_disp_divider);
+       old_dispclk_wdivider = dentist_get_did_from_divider(old_disp_divider);
+
+       /* When changing divider to or from 127, some extra programming is required to prevent corruption */
+       if (old_dispclk_wdivider == 127 && new_dispclk_wdivider != 127) {
+               for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) {
+                       struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+                       uint32_t fifo_level;
+                       struct dccg *dccg = clk_mgr->base.ctx->dc->res_pool->dccg;
+                       struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
+                       int32_t N;
+                       int32_t j;
+
+                       if (!pipe_ctx->stream)
+                               continue;
+                       /* Virtual encoders don't have this function */
+                       if (!stream_enc->funcs->get_fifo_cal_average_level)
+                               continue;
+                       fifo_level = stream_enc->funcs->get_fifo_cal_average_level(
+                                       stream_enc);
+                       N = fifo_level / 4;
+                       dccg->funcs->set_fifo_errdet_ovr_en(
+                                       dccg,
+                                       true);
+                       for (j = 0; j < N - 4; j++)
+                               dccg->funcs->otg_drop_pixel(
+                                               dccg,
+                                               pipe_ctx->stream_res.tg->inst);
+                       dccg->funcs->set_fifo_errdet_ovr_en(
+                                       dccg,
+                                       false);
+               }
+       } else if (new_dispclk_wdivider == 127 && old_dispclk_wdivider != 127) {
+               /* request clock with 126 divider first */
+               uint32_t temp_disp_divider = dentist_get_divider_from_did(126);
+               uint32_t temp_dispclk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR * clk_mgr->base.dentist_vco_freq_khz) / temp_disp_divider;
+
+               if (clk_mgr->smu_present)
+                       dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DISPCLK, khz_to_mhz_ceil(temp_dispclk_khz));
+
+               for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) {
+                       struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+                       struct dccg *dccg = clk_mgr->base.ctx->dc->res_pool->dccg;
+                       struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
+                       uint32_t fifo_level;
+                       int32_t N;
+                       int32_t j;
+
+                       if (!pipe_ctx->stream)
+                               continue;
+                       /* Virtual encoders don't have this function */
+                       if (!stream_enc->funcs->get_fifo_cal_average_level)
+                               continue;
+                       fifo_level = stream_enc->funcs->get_fifo_cal_average_level(
+                                       stream_enc);
+                       N = fifo_level / 4;
+                       dccg->funcs->set_fifo_errdet_ovr_en(dccg, true);
+                       for (j = 0; j < 12 - N; j++)
+                               dccg->funcs->otg_add_pixel(dccg,
+                                               pipe_ctx->stream_res.tg->inst);
+                       dccg->funcs->set_fifo_errdet_ovr_en(dccg, false);
+               }
+       }
+
+       /* do requested DISPCLK updates*/
+       if (clk_mgr->smu_present)
+               dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DISPCLK, khz_to_mhz_ceil(clk_mgr->base.clks.dispclk_khz));
+}
+
 static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base,
                        struct dc_state *context,
                        bool safe_to_lower)
@@ -274,6 +362,7 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base,
        bool p_state_change_support;
        bool fclk_p_state_change_support;
        int total_plane_count;
+       int old_dispclk_khz = clk_mgr_base->clks.dispclk_khz;
 
        if (dc->work_arounds.skip_clock_update)
                return;
@@ -397,9 +486,6 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base,
        if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) {
                clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
 
-               if (clk_mgr->smu_present)
-                       dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DISPCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dispclk_khz));
-
                update_dispclk = true;
        }
 
@@ -419,13 +505,13 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base,
                if (dpp_clock_lowered) {
                        /* if clock is being lowered, increase DTO before lowering refclk */
                        dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
-                       dcn20_update_clocks_update_dentist(clk_mgr, context);
+                       dcn32_update_clocks_update_dentist(clk_mgr, context, old_dispclk_khz);
                        if (clk_mgr->smu_present)
                                dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DPPCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dppclk_khz));
                } else {
                        /* if clock is being raised, increase refclk before lowering DTO */
                        if (update_dppclk || update_dispclk)
-                               dcn20_update_clocks_update_dentist(clk_mgr, context);
+                               dcn32_update_clocks_update_dentist(clk_mgr, context, old_dispclk_khz);
                        /* There is a check inside dcn20_update_clocks_update_dpp_dto which ensures
                         * that we do not lower dto when it is not safe to lower. We do not need to
                         * compare the current and new dppclk before calling this function.