drm/amd/display: Disable AC/DC codepath when unnecessary
authorJoshua Aberback <joshua.aberback@amd.com>
Thu, 28 Mar 2024 17:43:36 +0000 (13:43 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 13 May 2024 19:45:55 +0000 (15:45 -0400)
[WHY]
If there are no DC clock limits present, or if the DC limits are the same
as the AC limits, we can disable the AC/DC codepath as there won't be any
validation differences between the two modes.

[HOW]
When all DC power mode clock limits are the same as the max clock
values, there won't be any difference between AC mode and DC mode. Zero
out DC limits that equal max and provide a new cap to indicate the
presence of any non-zero DC mode limit. In summary:
 - zero out DC limits that are the same as max clock value
 - new dc cap to indicate the presence of DC mode limits
 - set limits present if any clock has distinct AC and DC values from SMU

Acked-by: Alex Hung <alex.hung@amd.com>
Reviewed-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Joshua Aberback <joshua.aberback@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c
drivers/gpu/drm/amd/display/dc/dc.h
drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c

index 1cf750c..bd74ff4 100644 (file)
@@ -180,7 +180,6 @@ static void dcn401_build_wm_range_table(struct clk_mgr *clk_mgr)
 void dcn401_init_clocks(struct clk_mgr *clk_mgr_base)
 {
        struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
-       unsigned int num_levels;
        struct clk_limit_num_entries *num_entries_per_clk = &clk_mgr_base->bw_params->clk_table.num_entries_per_clk;
        unsigned int i;
 
@@ -208,34 +207,43 @@ void dcn401_init_clocks(struct clk_mgr *clk_mgr_base)
                        &clk_mgr_base->bw_params->clk_table.entries[0].dcfclk_mhz,
                        &num_entries_per_clk->num_dcfclk_levels);
        clk_mgr_base->bw_params->dc_mode_limit.dcfclk_mhz = dcn30_smu_get_dc_mode_max_dpm_freq(clk_mgr, PPCLK_DCFCLK);
+       if (num_entries_per_clk->num_dcfclk_levels && clk_mgr_base->bw_params->dc_mode_limit.dcfclk_mhz ==
+                       clk_mgr_base->bw_params->clk_table.entries[num_entries_per_clk->num_dcfclk_levels - 1].dcfclk_mhz)
+               clk_mgr_base->bw_params->dc_mode_limit.dcfclk_mhz = 0;
 
        /* SOCCLK */
        dcn401_init_single_clock(clk_mgr, PPCLK_SOCCLK,
                                        &clk_mgr_base->bw_params->clk_table.entries[0].socclk_mhz,
                                        &num_entries_per_clk->num_socclk_levels);
        clk_mgr_base->bw_params->dc_mode_limit.socclk_mhz = dcn30_smu_get_dc_mode_max_dpm_freq(clk_mgr, PPCLK_SOCCLK);
+       if (num_entries_per_clk->num_socclk_levels && clk_mgr_base->bw_params->dc_mode_limit.socclk_mhz ==
+                       clk_mgr_base->bw_params->clk_table.entries[num_entries_per_clk->num_socclk_levels - 1].socclk_mhz)
+               clk_mgr_base->bw_params->dc_mode_limit.socclk_mhz = 0;
 
        /* DTBCLK */
        if (!clk_mgr->base.ctx->dc->debug.disable_dtb_ref_clk_switch) {
                dcn401_init_single_clock(clk_mgr, PPCLK_DTBCLK,
                                &clk_mgr_base->bw_params->clk_table.entries[0].dtbclk_mhz,
                                &num_entries_per_clk->num_dtbclk_levels);
-               clk_mgr_base->bw_params->dc_mode_limit.dtbclk_mhz =
-                       dcn30_smu_get_dc_mode_max_dpm_freq(clk_mgr, PPCLK_DTBCLK);
+               clk_mgr_base->bw_params->dc_mode_limit.dtbclk_mhz = dcn30_smu_get_dc_mode_max_dpm_freq(clk_mgr, PPCLK_DTBCLK);
+               if (num_entries_per_clk->num_dtbclk_levels && clk_mgr_base->bw_params->dc_mode_limit.dtbclk_mhz ==
+                               clk_mgr_base->bw_params->clk_table.entries[num_entries_per_clk->num_dtbclk_levels - 1].dtbclk_mhz)
+                       clk_mgr_base->bw_params->dc_mode_limit.dtbclk_mhz = 0;
        }
 
        /* DISPCLK */
        dcn401_init_single_clock(clk_mgr, PPCLK_DISPCLK,
                        &clk_mgr_base->bw_params->clk_table.entries[0].dispclk_mhz,
                        &num_entries_per_clk->num_dispclk_levels);
-       num_levels = num_entries_per_clk->num_dispclk_levels;
        clk_mgr_base->bw_params->dc_mode_limit.dispclk_mhz = dcn30_smu_get_dc_mode_max_dpm_freq(clk_mgr, PPCLK_DISPCLK);
+       if (num_entries_per_clk->num_dispclk_levels && clk_mgr_base->bw_params->dc_mode_limit.dispclk_mhz ==
+                       clk_mgr_base->bw_params->clk_table.entries[num_entries_per_clk->num_dispclk_levels - 1].dispclk_mhz)
+               clk_mgr_base->bw_params->dc_mode_limit.dispclk_mhz = 0;
 
        /* DPPCLK */
        dcn401_init_single_clock(clk_mgr, PPCLK_DPPCLK,
                        &clk_mgr_base->bw_params->clk_table.entries[0].dppclk_mhz,
                        &num_entries_per_clk->num_dppclk_levels);
-       num_levels = num_entries_per_clk->num_dppclk_levels;
 
        if (num_entries_per_clk->num_dcfclk_levels &&
                        num_entries_per_clk->num_dtbclk_levels &&
@@ -243,7 +251,7 @@ void dcn401_init_clocks(struct clk_mgr *clk_mgr_base)
                clk_mgr->dpm_present = true;
 
        if (clk_mgr_base->ctx->dc->debug.min_disp_clk_khz) {
-               for (i = 0; i < num_levels; i++)
+               for (i = 0; i < num_entries_per_clk->num_dispclk_levels; i++)
                        if (clk_mgr_base->bw_params->clk_table.entries[i].dispclk_mhz
                                        < khz_to_mhz_ceil(clk_mgr_base->ctx->dc->debug.min_disp_clk_khz))
                                clk_mgr_base->bw_params->clk_table.entries[i].dispclk_mhz
@@ -251,7 +259,7 @@ void dcn401_init_clocks(struct clk_mgr *clk_mgr_base)
        }
 
        if (clk_mgr_base->ctx->dc->debug.min_dpp_clk_khz) {
-               for (i = 0; i < num_levels; i++)
+               for (i = 0; i < num_entries_per_clk->num_dppclk_levels; i++)
                        if (clk_mgr_base->bw_params->clk_table.entries[i].dppclk_mhz
                                        < khz_to_mhz_ceil(clk_mgr_base->ctx->dc->debug.min_dpp_clk_khz))
                                clk_mgr_base->bw_params->clk_table.entries[i].dppclk_mhz
@@ -842,12 +850,18 @@ static void dcn401_get_memclk_states_from_smu(struct clk_mgr *clk_mgr_base)
        }
 
        clk_mgr_base->bw_params->dc_mode_limit.memclk_mhz = dcn30_smu_get_dc_mode_max_dpm_freq(clk_mgr, PPCLK_UCLK);
+       if (num_entries_per_clk->num_memclk_levels && clk_mgr_base->bw_params->dc_mode_limit.memclk_mhz ==
+                       clk_mgr_base->bw_params->clk_table.entries[num_entries_per_clk->num_memclk_levels - 1].memclk_mhz)
+               clk_mgr_base->bw_params->dc_mode_limit.memclk_mhz = 0;
        clk_mgr_base->bw_params->dc_mode_softmax_memclk = clk_mgr_base->bw_params->dc_mode_limit.memclk_mhz;
 
        dcn401_init_single_clock(clk_mgr, PPCLK_FCLK,
                        &clk_mgr_base->bw_params->clk_table.entries[0].fclk_mhz,
                        &num_entries_per_clk->num_fclk_levels);
        clk_mgr_base->bw_params->dc_mode_limit.fclk_mhz = dcn30_smu_get_dc_mode_max_dpm_freq(clk_mgr, PPCLK_FCLK);
+       if (num_entries_per_clk->num_fclk_levels && clk_mgr_base->bw_params->dc_mode_limit.fclk_mhz ==
+                       clk_mgr_base->bw_params->clk_table.entries[num_entries_per_clk->num_fclk_levels - 1].fclk_mhz)
+               clk_mgr_base->bw_params->dc_mode_limit.fclk_mhz = 0;
 
        if (num_entries_per_clk->num_memclk_levels >= num_entries_per_clk->num_fclk_levels) {
                num_levels = num_entries_per_clk->num_memclk_levels;
index 8698db8..2fce8c0 100644 (file)
@@ -290,6 +290,7 @@ struct dc_caps {
        uint32_t max_disp_clock_khz_at_vmin;
        uint8_t subvp_drr_vblank_start_margin_us;
        bool cursor_not_scaled;
+       bool dcmode_power_limits_present;
 };
 
 struct dc_bug_wa {
index d9a3d6c..3b74c4a 100644 (file)
@@ -212,9 +212,19 @@ void dcn401_init_hw(struct dc *dc)
        uint32_t backlight = MAX_BACKLIGHT_LEVEL;
        uint32_t user_level = MAX_BACKLIGHT_LEVEL;
 
-       if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
+       if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) {
                dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
 
+               // mark dcmode limits present if any clock has distinct AC and DC values from SMU
+               dc->caps.dcmode_power_limits_present =
+                               (dc->clk_mgr->bw_params->clk_table.num_entries_per_clk.num_dcfclk_levels && dc->clk_mgr->bw_params->dc_mode_limit.dcfclk_mhz) ||
+                               (dc->clk_mgr->bw_params->clk_table.num_entries_per_clk.num_dispclk_levels && dc->clk_mgr->bw_params->dc_mode_limit.dispclk_mhz) ||
+                               (dc->clk_mgr->bw_params->clk_table.num_entries_per_clk.num_dtbclk_levels && dc->clk_mgr->bw_params->dc_mode_limit.dtbclk_mhz) ||
+                               (dc->clk_mgr->bw_params->clk_table.num_entries_per_clk.num_fclk_levels && dc->clk_mgr->bw_params->dc_mode_limit.fclk_mhz) ||
+                               (dc->clk_mgr->bw_params->clk_table.num_entries_per_clk.num_memclk_levels && dc->clk_mgr->bw_params->dc_mode_limit.memclk_mhz) ||
+                               (dc->clk_mgr->bw_params->clk_table.num_entries_per_clk.num_socclk_levels && dc->clk_mgr->bw_params->dc_mode_limit.socclk_mhz);
+       }
+
        // Initialize the dccg
        if (res_pool->dccg->funcs->dccg_init)
                res_pool->dccg->funcs->dccg_init(res_pool->dccg);