OSDN Git Service

drm/amd/display: Implement DTBCLK ref switching on dcn32
authorAlvin Lee <Alvin.Lee2@amd.com>
Sat, 30 Apr 2022 00:41:10 +0000 (20:41 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 3 Jun 2022 20:45:01 +0000 (16:45 -0400)
[WHY & HOW]
Implements DTB ref clock switching with reg key default to OFF.
Refactors dccg DTBCLK logic to not store redundant state information
dccg. Also removes duplicated functions that should be inherited from
other dcn versions.

Signed-off-by: Alvin Lee <Alvin.Lee2@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr_smu_msg.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr_smu_msg.h
drivers/gpu/drm/amd/display/dc/dc.h
drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h

index 6a1d7c8..1db6102 100644 (file)
 #include "dcn32/dcn32_clk_mgr_smu_msg.h"
 #include "dcn20/dcn20_clk_mgr.h"
 #include "dce100/dce_clk_mgr.h"
+#include "dcn31/dcn31_clk_mgr.h"
 #include "reg_helper.h"
 #include "core_types.h"
 #include "dm_helpers.h"
+#include "dc_link_dp.h"
 
 #include "atomfirmware.h"
 #include "smu13_driver_if.h"
@@ -253,9 +255,10 @@ void dcn32_init_clocks(struct clk_mgr *clk_mgr_base)
                                        &clk_mgr_base->bw_params->clk_table.entries[0].socclk_mhz,
                                        &num_levels);
        /* DTBCLK */
-       dcn32_init_single_clock(clk_mgr, PPCLK_DTBCLK,
-                       &clk_mgr_base->bw_params->clk_table.entries[0].dtbclk_mhz,
-                       &num_levels);
+       if (!clk_mgr->base.ctx->dc->debug.disable_dtb_ref_clk_switch)
+               dcn32_init_single_clock(clk_mgr, PPCLK_DTBCLK,
+                               &clk_mgr_base->bw_params->clk_table.entries[0].dtbclk_mhz,
+                               &num_levels);
 
        /* DISPCLK */
        dcn32_init_single_clock(clk_mgr, PPCLK_DISPCLK,
@@ -270,6 +273,39 @@ void dcn32_init_clocks(struct clk_mgr *clk_mgr_base)
        dcn32_build_wm_range_table(clk_mgr);
 }
 
+static void dcn32_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr,
+                       struct dc_state *context,
+                       int ref_dtbclk_khz)
+{
+       struct dccg *dccg = clk_mgr->dccg;
+       uint32_t tg_mask = 0;
+       int i;
+
+       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 dtbclk_dto_params dto_params = {0};
+
+               /* use mask to program DTO once per tg */
+               if (pipe_ctx->stream_res.tg &&
+                               !(tg_mask & (1 << pipe_ctx->stream_res.tg->inst))) {
+                       tg_mask |= (1 << pipe_ctx->stream_res.tg->inst);
+
+                       dto_params.otg_inst = pipe_ctx->stream_res.tg->inst;
+                       dto_params.ref_dtbclk_khz = ref_dtbclk_khz;
+
+                       if (is_dp_128b_132b_signal(pipe_ctx)) {
+                               dto_params.pixclk_khz = pipe_ctx->stream->phy_pix_clk;
+
+                               if (pipe_ctx->stream_res.audio != NULL)
+                                       dto_params.req_audio_dtbclk_khz = 24000;
+                       }
+
+                       dccg->funcs->set_dtbclk_dto(clk_mgr->dccg, &dto_params);
+                       //dccg->funcs->set_audio_dtbclk_dto(clk_mgr->dccg, &dto_params);
+               }
+       }
+}
+
 static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base,
                        struct dc_state *context,
                        bool safe_to_lower)
@@ -320,7 +356,7 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base,
 
                if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) {
                        clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz;
-                       dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DCFCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dcfclk_khz));
+                       dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DCFCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dcfclk_khz));
                }
 
                if (should_set_clock(safe_to_lower, new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) {
@@ -350,7 +386,7 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base,
 
                        /* to disable P-State switching, set UCLK min = max */
                        if (!clk_mgr_base->clks.p_state_change_support)
-                               dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK,
+                               dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK,
                                                clk_mgr_base->bw_params->clk_table.entries[clk_mgr_base->bw_params->clk_table.num_entries - 1].memclk_mhz);
                }
 
@@ -379,7 +415,7 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base,
                /* set UCLK to requested value if P-State switching is supported, or to re-enable P-State switching */
                if (clk_mgr_base->clks.p_state_change_support &&
                                (update_uclk || !clk_mgr_base->clks.prev_p_state_change_support))
-                       dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dramclk_khz));
+                       dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dramclk_khz));
 
                if (clk_mgr_base->ctx->dce_version != DCN_VERSION_3_21 && clk_mgr_base->clks.fclk_p_state_change_support && update_fclk) {
                        /* Handle the code for sending a message to PMFW that FCLK P-state change is supported */
@@ -400,7 +436,7 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base,
                clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz;
 
                if (clk_mgr->smu_present)
-                       dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DPPCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dppclk_khz));
+                       dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DPPCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dppclk_khz));
 
                update_dppclk = true;
        }
@@ -409,11 +445,25 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base,
                clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
 
                if (clk_mgr->smu_present)
-                       dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DISPCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dispclk_khz));
+                       dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DISPCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dispclk_khz));
 
                update_dispclk = true;
        }
 
+       if (!new_clocks->dtbclk_en) {
+               new_clocks->ref_dtbclk_khz = 0;
+       }
+
+       /* clock limits are received with MHz precision, divide by 1000 to prevent setting clocks at every call */
+       if (!dc->debug.disable_dtb_ref_clk_switch &&
+                       should_set_clock(safe_to_lower, new_clocks->ref_dtbclk_khz / 1000, clk_mgr_base->clks.ref_dtbclk_khz / 1000)) {
+               /* DCCG requires KHz precision for DTBCLK */
+               clk_mgr_base->clks.ref_dtbclk_khz =
+                               dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DTBCLK, khz_to_mhz_ceil(new_clocks->ref_dtbclk_khz));
+
+               dcn32_update_clocks_update_dtb_dto(clk_mgr, context, clk_mgr_base->clks.ref_dtbclk_khz);
+       }
+
        if (dc->config.forced_clocks == false || (force_reset && safe_to_lower)) {
                if (dpp_clock_lowered) {
                        /* if clock is being lowered, increase DTO before lowering refclk */
@@ -502,13 +552,13 @@ static void dcn32_set_hard_min_memclk(struct clk_mgr *clk_mgr_base, bool current
 
        if (current_mode) {
                if (clk_mgr_base->clks.p_state_change_support)
-                       dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK,
+                       dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK,
                                        khz_to_mhz_ceil(clk_mgr_base->clks.dramclk_khz));
                else
-                       dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK,
+                       dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK,
                                        clk_mgr_base->bw_params->clk_table.entries[clk_mgr_base->bw_params->clk_table.num_entries - 1].memclk_mhz);
        } else {
-               dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK,
+               dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK,
                                clk_mgr_base->bw_params->clk_table.entries[0].memclk_mhz);
        }
 }
@@ -584,7 +634,7 @@ static bool dcn32_is_smu_present(struct clk_mgr *clk_mgr_base)
 
 
 static struct clk_mgr_funcs dcn32_funcs = {
-               .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+               .get_dp_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
                .update_clocks = dcn32_update_clocks,
                .init_clocks = dcn32_init_clocks,
                .notify_wm_ranges = dcn32_notify_wm_ranges,
@@ -627,7 +677,13 @@ void dcn32_clk_mgr_construct(
         * dprefclk DID divider
         */
        clk_mgr->base.dprefclk_khz = 716666;
-       clk_mgr->dccg->ref_dtbclk_khz = 268750;
+       if (ctx->dc->debug.disable_dtb_ref_clk_switch) {
+               //initialize DTB ref clock value if DPM disabled
+               if (ctx->dce_version == DCN_VERSION_3_21)
+                       clk_mgr->base.clks.ref_dtbclk_khz = 477800;
+               else
+                       clk_mgr->base.clks.ref_dtbclk_khz = 268750;
+       }
 
        /* integer part is now VCO frequency in kHz */
        clk_mgr->base.dentist_vco_freq_khz = 4300000;//dcn32_get_vco_frequency_from_reg(clk_mgr);
@@ -635,8 +691,9 @@ void dcn32_clk_mgr_construct(
        if (clk_mgr->base.dentist_vco_freq_khz == 0)
                clk_mgr->base.dentist_vco_freq_khz = 4300000; /* Updated as per HW docs */
 
-       if (clk_mgr->dccg->ref_dtbclk_khz != clk_mgr->base.boot_snapshot.dtbclk) {
-               clk_mgr->dccg->ref_dtbclk_khz = clk_mgr->base.boot_snapshot.dtbclk;
+       if (ctx->dc->debug.disable_dtb_ref_clk_switch &&
+                       clk_mgr->base.clks.ref_dtbclk_khz != clk_mgr->base.boot_snapshot.dtbclk) {
+               clk_mgr->base.clks.ref_dtbclk_khz = clk_mgr->base.boot_snapshot.dtbclk;
        }
 
        if (clk_mgr->base.boot_snapshot.dprefclk != 0) {
index 95ab268..d7c99e9 100644 (file)
@@ -114,3 +114,21 @@ void dcn32_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr)
        dcn32_smu_send_msg_with_param(clk_mgr,
                        DALSMC_MSG_TransferTableDram2Smu, TABLE_WATERMARKS, NULL);
 }
+
+/* Returns the actual frequency that was set in MHz, 0 on failure */
+unsigned int dcn32_smu_set_hard_min_by_freq(struct clk_mgr_internal *clk_mgr, uint32_t clk, uint16_t freq_mhz)
+{
+       uint32_t response = 0;
+
+       /* bits 23:16 for clock type, lower 16 bits for frequency in MHz */
+       uint32_t param = (clk << 16) | freq_mhz;
+
+       smu_print("SMU Set hard min by freq: clk = %d, freq_mhz = %d MHz\n", clk, freq_mhz);
+
+       dcn32_smu_send_msg_with_param(clk_mgr,
+                       DALSMC_MSG_SetHardMinByFreq, param, &response);
+
+       smu_print("SMU Frequency set = %d KHz\n", response);
+
+       return response;
+}
index 5f69cdc..352435e 100644 (file)
@@ -41,5 +41,6 @@ dcn32_smu_send_fclk_pstate_message(struct clk_mgr_internal *clk_mgr, bool enable
 void dcn32_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr);
 void dcn32_smu_send_cab_for_uclk_message(struct clk_mgr_internal *clk_mgr, unsigned int num_ways);
 void dcn32_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr);
+unsigned int dcn32_smu_set_hard_min_by_freq(struct clk_mgr_internal *clk_mgr, uint32_t clk, uint16_t freq_mhz);
 
 #endif /* __DCN32_CLK_MGR_SMU_MSG_H_ */
index 6916546..7bb67ab 100644 (file)
@@ -432,7 +432,6 @@ struct dc_clocks {
        enum dcn_zstate_support_state zstate_support;
        bool dtbclk_en;
        int ref_dtbclk_khz;
-       int dtbclk_khz;
        bool fclk_p_state_change_support;
        enum dcn_pwr_state pwr_state;
        /*
@@ -740,11 +739,11 @@ struct dc_debug_options {
        bool force_disable_subvp;
        bool force_subvp_mclk_switch;
        bool force_usr_allow;
+       /* uses value at boot and disables switch */
+       bool disable_dtb_ref_clk_switch;
        bool apply_vendor_specific_lttpr_wa;
        bool extended_blank_optimization;
        union aux_wake_wa_options aux_wake_wa;
-       /* uses value at boot and disables switch */
-       bool disable_dtb_ref_clk_switch;
        uint8_t psr_power_use_phy_fsm;
        enum dml_hostvm_override_opts dml_hostvm_override;
 };
index a76523c..631a8a2 100644 (file)
@@ -2191,18 +2191,15 @@ static void dce110_setup_audio_dto(
                        build_audio_output(context, pipe_ctx, &audio_output);
 
                        if (dc->res_pool->dccg && dc->res_pool->dccg->funcs->set_audio_dtbclk_dto) {
-                               struct dtbclk_dto_params dto_params = {0};
+                               /* disable audio DTBCLK DTO */
+                               dc->res_pool->dccg->funcs->set_audio_dtbclk_dto(
+                                       dc->res_pool->dccg, 0);
 
                                pipe_ctx->stream_res.audio->funcs->wall_dto_setup(
                                                pipe_ctx->stream_res.audio,
                                                pipe_ctx->stream->signal,
                                                &audio_output.crtc_info,
                                                &audio_output.pll_info);
-
-                               dc->res_pool->dccg->funcs->set_audio_dtbclk_dto(
-                                       dc->res_pool->dccg,
-                                       &dto_params);
-
                        } else
                                pipe_ctx->stream_res.audio->funcs->wall_dto_setup(
                                        pipe_ctx->stream_res.audio,
index 13dbf99..8eeb3b6 100644 (file)
@@ -590,6 +590,7 @@ void dccg31_set_audio_dtbclk_dto(
                phase = div_u64((((unsigned long long)modulo * params->req_audio_dtbclk_khz) + params->ref_dtbclk_khz - 1),
                        params->ref_dtbclk_khz);
 
+
                REG_WRITE(DCCG_AUDIO_DTBCLK_DTO_MODULO, modulo);
                REG_WRITE(DCCG_AUDIO_DTBCLK_DTO_PHASE, phase);
 
index 070be7e..08232d0 100644 (file)
@@ -179,11 +179,13 @@ void dccg32_set_dtbclk_dto(
 
 void dccg32_set_valid_pixel_rate(
                struct dccg *dccg,
+               int ref_dtbclk_khz,
                int otg_inst,
                int pixclk_khz)
 {
        struct dtbclk_dto_params dto_params = {0};
 
+       dto_params.ref_dtbclk_khz = ref_dtbclk_khz;
        dto_params.otg_inst = otg_inst;
        dto_params.pixclk_khz = pixclk_khz;
 
index b492eb4..1ea6d25 100644 (file)
@@ -3306,6 +3306,7 @@ void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context, display
        // context->bw_ctx.bw.dcn.clk.p_state_change_support |= context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching;
        context->bw_ctx.bw.dcn.clk.dppclk_khz = 0;
        context->bw_ctx.bw.dcn.clk.dtbclk_en = is_dtbclk_required(dc, context);
+       context->bw_ctx.bw.dcn.clk.ref_dtbclk_khz = context->bw_ctx.dml.vba.DTBCLKPerState[vlevel] * 1000;
        if (context->bw_ctx.dml.vba.FCLKChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] == dm_fclock_change_unsupported)
                context->bw_ctx.bw.dcn.clk.fclk_p_state_change_support = false;
        else
@@ -3560,10 +3561,15 @@ static void dcn32_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw
                        dcn3_2_soc.clock_limits[i].dscclk_mhz  = max_dispclk_mhz / 3;
 
                        /* Populate from bw_params for DTBCLK, SOCCLK */
-                       if (!bw_params->clk_table.entries[i].dtbclk_mhz && i > 0)
-                               dcn3_2_soc.clock_limits[i].dtbclk_mhz  = dcn3_2_soc.clock_limits[i-1].dtbclk_mhz;
-                       else
+                       if (i > 0) {
+                               if (!bw_params->clk_table.entries[i].dtbclk_mhz) {
+                                       dcn3_2_soc.clock_limits[i].dtbclk_mhz  = dcn3_2_soc.clock_limits[i-1].dtbclk_mhz;
+                               } else {
+                                       dcn3_2_soc.clock_limits[i].dtbclk_mhz  = bw_params->clk_table.entries[i].dtbclk_mhz;
+                               }
+                       } else if (bw_params->clk_table.entries[i].dtbclk_mhz) {
                                dcn3_2_soc.clock_limits[i].dtbclk_mhz  = bw_params->clk_table.entries[i].dtbclk_mhz;
+                       }
 
                        if (!bw_params->clk_table.entries[i].socclk_mhz && i > 0)
                                dcn3_2_soc.clock_limits[i].socclk_mhz = dcn3_2_soc.clock_limits[i-1].socclk_mhz;
index 780409e..48af91a 100644 (file)
@@ -1910,10 +1910,15 @@ static void dcn321_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *b
                        dcn3_21_soc.clock_limits[i].dscclk_mhz  = max_dispclk_mhz / 3;
 
                        /* Populate from bw_params for DTBCLK, SOCCLK */
-                       if (!bw_params->clk_table.entries[i].dtbclk_mhz && i > 0)
-                               dcn3_21_soc.clock_limits[i].dtbclk_mhz  = dcn3_21_soc.clock_limits[i-1].dtbclk_mhz;
-                       else
+                       if (i > 0) {
+                               if (!bw_params->clk_table.entries[i].dtbclk_mhz) {
+                                       dcn3_21_soc.clock_limits[i].dtbclk_mhz = dcn3_21_soc.clock_limits[i-1].dtbclk_mhz;
+                               } else {
+                                       dcn3_21_soc.clock_limits[i].dtbclk_mhz = bw_params->clk_table.entries[i].dtbclk_mhz;
+                               }
+                       } else if (bw_params->clk_table.entries[i].dtbclk_mhz) {
                                dcn3_21_soc.clock_limits[i].dtbclk_mhz  = bw_params->clk_table.entries[i].dtbclk_mhz;
+                       }
 
                        if (!bw_params->clk_table.entries[i].socclk_mhz && i > 0)
                                dcn3_21_soc.clock_limits[i].socclk_mhz = dcn3_21_soc.clock_limits[i-1].socclk_mhz;
index e0dd046..0251694 100644 (file)
@@ -70,7 +70,7 @@ struct dccg {
        int ref_dppclk;
        //int dtbclk_khz[MAX_PIPES];/* TODO needs to be removed */
        //int audio_dtbclk_khz;/* TODO needs to be removed */
-       int ref_dtbclk_khz;/* TODO needs to be removed */
+       //int ref_dtbclk_khz;/* TODO needs to be removed */
 };
 
 struct dtbclk_dto_params {
@@ -154,6 +154,7 @@ void (*set_pixel_rate_div)(
 
 void (*set_valid_pixel_rate)(
         struct dccg *dccg,
+       int ref_dtbclk_khz,
         int otg_inst,
         int pixclk_khz);