drm/amd/display: Ensure dtbclk is enabled

[why]
ensure dtbclk is enabled before hdmistreamclk_en

pmfw could stop dtbclk on idle.
driver needs to ensure dtbclk enabled is enabled before hdmistreamclk_en
also disable debounce timer on dcn42.

Reviewed-by: Chris Park <chris.park@amd.com>
Reviewed-by: Leo Chen <leo.chen@amd.com>
Signed-off-by: Charlene Liu <Charlene.Liu@amd.com>
Signed-off-by: Roman Li <roman.li@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Charlene Liu 2026-06-30 15:56:06 -04:00 committed by Alex Deucher
parent 7cc88c0d56
commit 807d6345bc
5 changed files with 46 additions and 6 deletions

View File

@ -220,6 +220,7 @@ void dcn42_update_clocks(struct clk_mgr *clk_mgr_base,
bool update_dispclk = false;
bool dpp_clock_lowered = false;
bool has_active_display;
int actual_dtbclk = 0;
if (dc->work_arounds.skip_clock_update)
return;
@ -260,8 +261,9 @@ void dcn42_update_clocks(struct clk_mgr *clk_mgr_base,
* For dcn42b (no dtbclk hardware), init_clk_states sets dtbclk_en=false and
* new_clocks->dtbclk_en should always be false, so this block never executes.
*/
if (!clk_mgr_base->clks.dtbclk_en && new_clocks->dtbclk_en) {
int actual_dtbclk = 0;
actual_dtbclk = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dtbclk);
if (new_clocks->dtbclk_en && actual_dtbclk < 590000) {
dcn42_update_clocks_update_dtb_dto(clk_mgr, context, new_clocks->ref_dtbclk_khz);
dcn42_smu_set_dtbclk(clk_mgr, true);
@ -343,7 +345,6 @@ void dcn42_update_clocks(struct clk_mgr *clk_mgr_base,
dcn42_update_clocks_update_dtb_dto(clk_mgr, context, new_clocks->ref_dtbclk_khz);
clk_mgr_base->clks.ref_dtbclk_khz = new_clocks->ref_dtbclk_khz;
}
if (dpp_clock_lowered) {
// increase per DPP DTO before lowering global dppclk
dcn42_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
@ -1051,7 +1052,27 @@ void dcn42_get_smu_clocks(struct clk_mgr_internal *clk_mgr_int)
dm_helpers_free_gpu_mem(clk_mgr_base->ctx, DC_MEM_ALLOC_TYPE_GART,
smu_dpm_clks.dpm_clks);
}
void dcn42_request_dtbclk(struct clk_mgr *clk_mgr_base, bool enable)
{
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
/*pmfw might turn off dtblck based on allow_dtbstop*/
clk_mgr_base->clks.dtbclk_en = false;
if (enable) {
int actual_dtbclk = 0;
dcn42_smu_set_dtbclk(clk_mgr, true);
actual_dtbclk = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dtbclk);
if (actual_dtbclk > 590000) {
clk_mgr_base->clks.ref_dtbclk_khz = actual_dtbclk;
clk_mgr_base->clks.dtbclk_en = true;
}
} else {
clk_mgr_base->clks.dtbclk_en = false;
dcn42_smu_set_dtbclk(clk_mgr, false);
}
}
static struct clk_mgr_funcs dcn42_funcs = {
.get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
.get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
@ -1065,6 +1086,7 @@ static struct clk_mgr_funcs dcn42_funcs = {
.get_max_clock_khz = dcn42_get_max_clock_khz,
.get_dispclk_from_dentist = dcn42_get_dispclk_from_dentist,
.is_smu_present = dcn42_is_smu_present,
.request_dtbclk = dcn42_request_dtbclk,
.notify_cstate_disable = dcn42_notify_cstate_disable,
};

View File

@ -84,4 +84,5 @@ void dcn42_get_dpm_table_from_smu(struct clk_mgr_internal *clk_mgr, struct dcn42
void dcn42_get_smu_clocks(struct clk_mgr_internal *clk_mgr_int);
void dcn42_update_clocks_fpga(struct clk_mgr *clk_mgr, struct dc_state *context, bool safe_to_lower);
int dcn42_get_dispclk_from_dentist(struct clk_mgr *clk_mgr_base);
void dcn42_request_dtbclk(struct clk_mgr *clk_mgr_base, bool enable);
#endif //__DCN42_CLK_MGR_H__

View File

@ -1117,6 +1117,10 @@ static bool dcn401_program_pix_clk(
if (clock_source->ctx->dc->caps.is_apu &&
pix_clk_params->requested_pix_clk_100hz &&
dc_is_hdmi_frl_signal(pix_clk_params->signal_type)) {
//make sure dtbclk is enabled
if (clock_source->ctx->dc->clk_mgr->funcs->request_dtbclk)
clock_source->ctx->dc->clk_mgr->funcs->request_dtbclk(
clock_source->ctx->dc->clk_mgr, true);
/*need hdmistreamclk before vpg block register access*/
clock_source->ctx->dc->res_pool->dccg->funcs->set_hdmistreamclk(
clock_source->ctx->dc->res_pool->dccg,

View File

@ -427,6 +427,7 @@ struct clk_mgr_funcs {
struct block_sequence_state *seq_state);
void (*execute_clk_mgr_block_sequence)(struct clk_mgr *clk_mgr);
void (*request_dtbclk)(struct clk_mgr *clk_mgr_base, bool enable);
};
struct clk_mgr {

View File

@ -415,6 +415,18 @@ void hdmi_frl_LTS_clear_Link_Setting(struct ddc_service *ddc_service)
}
static uint8_t hdmi_frl_get_max_ffe_level(struct dc_link *link,
struct dc_hdmi_frl_link_settings *link_settings)
{
uint8_t max_ffe_level =
(link_settings->frl_link_rate > HDMI_FRL_LINK_RATE_12GBPS) ? 7 : 3;
if ((uint8_t)link->dc->debug.limit_ffe < max_ffe_level)
max_ffe_level = (uint8_t)link->dc->debug.limit_ffe;
return max_ffe_level;
}
static enum link_result hdmi_frl_perform_link_training(struct ddc_service *ddc_service,
struct dc_hdmi_frl_link_settings *link_settings)
{
@ -436,7 +448,7 @@ static enum link_result hdmi_frl_perform_link_training(struct ddc_service *ddc_s
struct hpo_frl_link_encoder *hpo_frl_link_enc = ddc_service->link->hpo_frl_link_enc;
struct link_encoder *dio_link_enc = ddc_service->link->link_enc;
uint8_t sink_version = 0;
uint8_t FFE_Levels = (uint8_t)ddc_service->link->dc->debug.limit_ffe;
uint8_t FFE_Levels = hdmi_frl_get_max_ffe_level(ddc_service->link, link_settings);
uint8_t current_FFE = 0;
bool override_FFE = false;
bool flt_no_timeout = false;
@ -616,7 +628,7 @@ static enum link_result hdmi_frl_perform_link_training(struct ddc_service *ddc_s
}
current_FFE++;
override_FFE = true;
if (current_FFE > 3)
if (current_FFE > FFE_Levels)
current_FFE = 0;
if (flt_no_timeout)
current_FFE = 0;
@ -642,7 +654,7 @@ static enum link_result hdmi_frl_perform_link_training(struct ddc_service *ddc_s
}
current_FFE++;
override_FFE = true;
if (current_FFE > 3)
if (current_FFE > FFE_Levels)
current_FFE = 0;
if (flt_no_timeout)
current_FFE = 0;