Commit 405bb9ee authored by Alvin Lee's avatar Alvin Lee Committed by Alex Deucher

drm/amd/display: Implement DTBCLK ref switching on dcn32

[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: default avatarAlvin Lee <Alvin.Lee2@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent b6a93844
......@@ -29,9 +29,11 @@
#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) {
......
......@@ -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;
}
......@@ -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_ */
......@@ -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;
};
......
......@@ -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,
......
......@@ -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);
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment