From: Alvin Lee <alvin.l...@amd.com>

[Why & How]
- If for any reason PMFW fails to set the expected (or valid)
  DISPCLK WDIVIDER, then DAL will program DENTIST DISPCLK
  WDIVIDER to correct for this issue

Reviewed-by: Samson Tam <samson....@amd.com>
Acked-by: Qingqing Zhuo <qingqing.z...@amd.com>
Signed-off-by: Alvin Lee <alvin.l...@amd.com>
---
 .../display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c  | 41 ++++++++++++++-----
 drivers/gpu/drm/amd/display/dc/dc.h           |  1 +
 .../drm/amd/display/dc/dcn32/dcn32_resource.c |  1 +
 .../amd/display/dc/dcn321/dcn321_resource.c   |  1 +
 4 files changed, 34 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c 
b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
index 61768bf726f8..e686d6610fd4 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
@@ -257,25 +257,24 @@ 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)
+               struct dc_state *context)
 {
        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;
+       uint32_t dentist_dispclk_wdivider_readback = 0;
+       struct dc *dc = clk_mgr->base.ctx->dc;
 
-       if (old_dispclk_khz == 0 || clk_mgr->base.clks.dispclk_khz == 0)
+       if (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);
+       REG_GET(DENTIST_DISPCLK_CNTL,
+                       DENTIST_DISPCLK_WDIVIDER, &old_dispclk_wdivider);
 
        /* When changing divider to or from 127, some extra programming is 
required to prevent corruption */
        if (old_dispclk_wdivider == 127 && new_dispclk_wdivider != 127) {
@@ -314,6 +313,17 @@ static void dcn32_update_clocks_update_dentist(
                if (clk_mgr->smu_present)
                        dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DISPCLK, 
khz_to_mhz_ceil(temp_dispclk_khz));
 
+               if (dc->debug.override_dispclk_programming) {
+                       REG_GET(DENTIST_DISPCLK_CNTL,
+                                       DENTIST_DISPCLK_WDIVIDER, 
&dentist_dispclk_wdivider_readback);
+
+                       if (dentist_dispclk_wdivider_readback != 126) {
+                               REG_UPDATE(DENTIST_DISPCLK_CNTL,
+                                               DENTIST_DISPCLK_WDIVIDER, 126);
+                               REG_WAIT(DENTIST_DISPCLK_CNTL, 
DENTIST_DISPCLK_CHG_DONE, 1, 50, 2000);
+                       }
+               }
+
                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;
@@ -341,6 +351,18 @@ static void dcn32_update_clocks_update_dentist(
        /* 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));
+
+       if (dc->debug.override_dispclk_programming) {
+               REG_GET(DENTIST_DISPCLK_CNTL,
+                               DENTIST_DISPCLK_WDIVIDER, 
&dentist_dispclk_wdivider_readback);
+
+               if (dentist_dispclk_wdivider_readback > new_dispclk_wdivider) {
+                       REG_UPDATE(DENTIST_DISPCLK_CNTL,
+                                       DENTIST_DISPCLK_WDIVIDER, 
new_dispclk_wdivider);
+                       REG_WAIT(DENTIST_DISPCLK_CNTL, 
DENTIST_DISPCLK_CHG_DONE, 1, 50, 2000);
+               }
+       }
+
 }
 
 static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base,
@@ -361,7 +383,6 @@ 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;
@@ -504,13 +525,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);
-                       dcn32_update_clocks_update_dentist(clk_mgr, context, 
old_dispclk_khz);
+                       dcn32_update_clocks_update_dentist(clk_mgr, context);
                        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)
-                               dcn32_update_clocks_update_dentist(clk_mgr, 
context, old_dispclk_khz);
+                               dcn32_update_clocks_update_dentist(clk_mgr, 
context);
                        /* 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.
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h 
b/drivers/gpu/drm/amd/display/dc/dc.h
index 1fde43378689..8a62f3e93e35 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -874,6 +874,7 @@ struct dc_debug_options {
        bool disable_unbounded_requesting;
        bool dig_fifo_off_in_blank;
        bool temp_mst_deallocation_sequence;
+       bool override_dispclk_programming;
 };
 
 struct gpu_info_soc_bounding_box_v1_0;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c 
b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
index 74e50c09bb62..16efb86232d8 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
@@ -726,6 +726,7 @@ static const struct dc_debug_options debug_defaults_drv = {
        .alloc_extra_way_for_cursor = true,
        .min_prefetch_in_strobe_ns = 60000, // 60us
        .disable_unbounded_requesting = false,
+       .override_dispclk_programming = true,
 };
 
 static const struct dc_debug_options debug_defaults_diags = {
diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c 
b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
index 55f918b44077..deaa4769be10 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
@@ -724,6 +724,7 @@ static const struct dc_debug_options debug_defaults_drv = {
        .alloc_extra_way_for_cursor = true,
        .min_prefetch_in_strobe_ns = 60000, // 60us
        .disable_unbounded_requesting = false,
+       .override_dispclk_programming = true,
 };
 
 static const struct dc_debug_options debug_defaults_diags = {
-- 
2.34.1

Reply via email to