From: Matthew Stewart <Matthew.Stewart2@amd.com>
To: <amd-gfx@lists.freedesktop.org>
Cc: Harry Wentland <harry.wentland@amd.com>,
Leo Li <sunpeng.li@amd.com>,
Aurabindo Pillai <aurabindo.pillai@amd.com>,
Roman Li <roman.li@amd.com>, Wayne Lin <wayne.lin@amd.com>,
Tom Chung <chiahsuan.chung@amd.com>,
"Fangzhi Zuo" <jerry.zuo@amd.com>, Ray Wu <Ray.Wu@amd.com>,
Dan Wheeler <daniel.wheeler@amd.com>,
Ivan Lipski <ivan.lipski@amd.com>,
Chuanyu Tseng <Chuanyu.Tseng@amd.com>,
Gabe Teeger <gabe.teeger@amd.com>,
Charlene Liu <charlene.liu@amd.com>,
Matthew Stewart <matthew.stewart2@amd.com>
Subject: [PATCH 2/2] drm/amd/display: add dcn42b specific SMU clock table read
Date: Thu, 16 Jul 2026 15:07:36 -0400 [thread overview]
Message-ID: <20260716190844.368565-3-Matthew.Stewart2@amd.com> (raw)
In-Reply-To: <20260716190844.368565-1-Matthew.Stewart2@amd.com>
From: Gabe Teeger <gabe.teeger@amd.com>
[Why]
On DCN42B the SMU reports its DpmClocks table in a different
layout than DCN42, with extra clock domains. The clk_mgr was
parsing it with the DCN42 layout.
[How]
Add a DCN42B DpmClocks struct and a dcn42b_get_smu_clocks() that
allocates and parses the DCN42B layout, reusing the shared dcn42
helpers so DCN42 is untouched. Populate DCF, SOC, DISP, DPP and
FCLK levels and the memory pstate table.
Reviewed-by: Charlene Liu <charlene.liu@amd.com>
Signed-off-by: Gabe Teeger <gabe.teeger@amd.com>
Signed-off-by: Matthew Stewart <matthew.stewart2@amd.com>
---
.../dc/clk_mgr/dcn42b/dcn42b_clk_mgr.c | 183 ++++++++++++++++--
1 file changed, 172 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42b/dcn42b_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42b/dcn42b_clk_mgr.c
index 4be5abdc60ea..2c2ba09221e4 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42b/dcn42b_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42b/dcn42b_clk_mgr.c
@@ -221,10 +221,6 @@ static void init_clk_states(struct clk_mgr *clk_mgr)
clk_mgr->clks.zstate_support = DCN_ZSTATE_SUPPORT_UNKNOWN;
}
-/* dcn42b_get_dpm_table_from_smu removed: reuse dcn42_get_dpm_table_from_smu.
- * Function is identical - only uses SMU calls, no hardware register differences.
- */
-
void dcn42b_init_clocks(struct clk_mgr *clk_mgr_base)
{
struct clk_mgr_internal *clk_mgr_int = TO_CLK_MGR_INTERNAL(clk_mgr_base);
@@ -412,6 +408,176 @@ static struct clk_mgr_funcs dcn42b_funcs = {
.is_smu_present = dcn42_is_smu_present,
};
+typedef struct {
+ uint32_t DcfClocks[NUM_DCFCLK_DPM_LEVELS];
+ uint32_t DispClocks[NUM_DISPCLK_DPM_LEVELS];
+ uint32_t DppClocks[NUM_DPPCLK_DPM_LEVELS];
+ uint32_t SocClocks[NUM_SOCCLK_DPM_LEVELS];
+ uint32_t VPEClocks[NUM_VPE_DPM_LEVELS];
+ uint32_t FclkClocks_Freq[NUM_FCLK_DPM_LEVELS];
+ uint32_t FclkClocks_Voltage[NUM_FCLK_DPM_LEVELS];
+ uint32_t SocVoltage[NUM_SOC_VOLTAGE_LEVELS];
+ MemPstateTable_t MemPstateTable[NUM_MEM_PSTATE_LEVELS];
+
+ uint8_t NumDcfClkLevelsEnabled;
+ uint8_t NumDispClkLevelsEnabled; //Applies to both Dispclk and Dppclk
+ uint8_t NumSocClkLevelsEnabled;
+ uint8_t VpeClkLevelsEnabled;
+
+ uint8_t NumMemPstatesEnabled;
+ uint8_t NumFclkLevelsEnabled;
+ uint8_t Spare1;
+ uint8_t Spare2;
+
+ uint8_t Spare3;
+ uint8_t Spare4;
+ uint8_t Spare5[2];
+
+ uint32_t MinGfxClk;
+ uint32_t MaxGfxClk;
+
+ uint32_t Spare6[8];
+ uint32_t Spare7[8];
+ uint32_t Spare8[8];
+ uint32_t Spare9[8];
+} DpmClocks_t_dcn42b;
+struct dcn42b_smu_dpm_clks {
+ DpmClocks_t_dcn42b *dpm_clks;
+ union large_integer mc_address;
+};
+
+static void dcn42b_get_dpm_table_from_smu(struct clk_mgr_internal *clk_mgr,
+ struct dcn42b_smu_dpm_clks *smu_dpm_clks)
+{
+ DpmClocks_t_dcn42b *table = smu_dpm_clks->dpm_clks;
+
+ if (!clk_mgr->smu_ver)
+ return;
+
+ if (!table || smu_dpm_clks->mc_address.quad_part == 0)
+ return;
+
+ memset(table, 0, sizeof(*table));
+
+ dcn42_smu_set_dram_addr_high(clk_mgr,
+ smu_dpm_clks->mc_address.high_part);
+ dcn42_smu_set_dram_addr_low(clk_mgr,
+ smu_dpm_clks->mc_address.low_part);
+ dcn42_smu_transfer_dpm_table_smu_2_dram(clk_mgr);
+}
+
+static void dcn42b_get_smu_clocks(struct clk_mgr_internal *clk_mgr_int)
+{
+ struct clk_mgr *clk_mgr_base = &clk_mgr_int->base;
+ struct dcn42b_smu_dpm_clks smu_dpm_clks = { 0 };
+
+ DC_LOGGER_INIT(clk_mgr_base->ctx->logger);
+ (void)dc_logger;
+
+ smu_dpm_clks.dpm_clks = (DpmClocks_t_dcn42b *)dm_helpers_allocate_gpu_mem(
+ clk_mgr_base->ctx,
+ DC_MEM_ALLOC_TYPE_GART,
+ sizeof(DpmClocks_t_dcn42b),
+ &smu_dpm_clks.mc_address.quad_part);
+
+ ASSERT(smu_dpm_clks.dpm_clks);
+ if (clk_mgr_base->ctx->dc->debug.pstate_enabled && smu_dpm_clks.mc_address.quad_part != 0) {
+ int i;
+ DpmClocks_t_dcn42b *dpm_clks = smu_dpm_clks.dpm_clks;
+
+ dcn42b_get_dpm_table_from_smu(clk_mgr_int, &smu_dpm_clks);
+ DC_LOG_SMU("NumDcfClkLevelsEnabled: %d\n"
+ "NumDispClkLevelsEnabled: %d\n"
+ "NumSocClkLevelsEnabled: %d\n"
+ "VpeClkLevelsEnabled: %d\n"
+ "FClkLevelsEnabled: %d\n"
+ "NumMemPstatesEnabled: %d\n"
+ "MinGfxClk: %d\n"
+ "MaxGfxClk: %d\n",
+ dpm_clks->NumDcfClkLevelsEnabled,
+ dpm_clks->NumDispClkLevelsEnabled,
+ dpm_clks->NumSocClkLevelsEnabled,
+ dpm_clks->VpeClkLevelsEnabled,
+ dpm_clks->NumFclkLevelsEnabled,
+ dpm_clks->NumMemPstatesEnabled,
+ dpm_clks->MinGfxClk,
+ dpm_clks->MaxGfxClk);
+
+ for (i = 0; i < NUM_DCFCLK_DPM_LEVELS; i++)
+ DC_LOG_SMU("dpm_clks->DcfClocks[%d] = %d\n", i, dpm_clks->DcfClocks[i]);
+ for (i = 0; i < NUM_DISPCLK_DPM_LEVELS; i++)
+ DC_LOG_SMU("dpm_clks->DispClocks[%d] = %d\n", i, dpm_clks->DispClocks[i]);
+ for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++)
+ DC_LOG_SMU("dpm_clks->SocClocks[%d] = %d\n", i, dpm_clks->SocClocks[i]);
+ for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) {
+ DC_LOG_SMU("dpm_clks->FclkClocks_Freq[%d] = %d\n", i, dpm_clks->FclkClocks_Freq[i]);
+ DC_LOG_SMU("dpm_clks->FclkClocks_Voltage[%d] = %d\n", i, dpm_clks->FclkClocks_Voltage[i]);
+ }
+ for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++)
+ DC_LOG_SMU("dpm_clks->SocVoltage[%d] = %d\n", i, dpm_clks->SocVoltage[i]);
+
+ for (i = 0; i < NUM_MEM_PSTATE_LEVELS; i++)
+ DC_LOG_SMU("dpm_clks.MemPstateTable[%d].UClk = %d MemClk = %d Voltage = %d\n",
+ i, dpm_clks->MemPstateTable[i].UClk, dpm_clks->MemPstateTable[i].MemClk, dpm_clks->MemPstateTable[i].Voltage);
+
+ if (clk_mgr_base->ctx->dc_bios->integrated_info && clk_mgr_base->ctx->dc->config.use_default_clock_table == false) {
+ /* DCFCLK */
+ dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].dcfclk_mhz,
+ dpm_clks->DcfClocks,
+ dpm_clks->NumDcfClkLevelsEnabled);
+ clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dcfclk_levels = dpm_clks->NumDcfClkLevelsEnabled;
+
+ /* SOCCLK */
+ dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].socclk_mhz,
+ dpm_clks->SocClocks,
+ dpm_clks->NumSocClkLevelsEnabled);
+ clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_socclk_levels = dpm_clks->NumSocClkLevelsEnabled;
+
+ /* DISPCLK */
+ dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].dispclk_mhz,
+ dpm_clks->DispClocks,
+ dpm_clks->NumDispClkLevelsEnabled);
+ clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dispclk_levels = dpm_clks->NumDispClkLevelsEnabled;
+
+ /* DPPCLK */
+ dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].dppclk_mhz,
+ dpm_clks->DppClocks,
+ dpm_clks->NumDispClkLevelsEnabled);
+ clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dppclk_levels = dpm_clks->NumDispClkLevelsEnabled;
+
+ /* FCLK */
+ dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].fclk_mhz,
+ dpm_clks->FclkClocks_Freq,
+ NUM_FCLK_DPM_LEVELS);
+ clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_fclk_levels = dpm_clks->NumFclkLevelsEnabled;
+ clk_mgr_base->bw_params->clk_table.num_entries = dpm_clks->NumFclkLevelsEnabled;
+
+ /* Memory Pstate table is in reverse order for dcn42. Proper way to map this is for pmfw to provide an fclk indexed uclk key since we consume fclk matched pairs.*/
+ ASSERT(dpm_clks->NumMemPstatesEnabled <= NUM_MEM_PSTATE_LEVELS);
+ if (dpm_clks->NumMemPstatesEnabled > NUM_MEM_PSTATE_LEVELS)
+ dpm_clks->NumMemPstatesEnabled = NUM_MEM_PSTATE_LEVELS;
+ for (i = 0; i < dpm_clks->NumDcfClkLevelsEnabled; i++) {
+ if (i < dpm_clks->NumMemPstatesEnabled) {
+ clk_mgr_base->bw_params->clk_table.entries[dpm_clks->NumMemPstatesEnabled - 1 - i].memclk_mhz = dpm_clks->MemPstateTable[i].MemClk;
+ clk_mgr_base->bw_params->clk_table.entries[dpm_clks->NumMemPstatesEnabled - 1 - i].wck_ratio = dcn42_convert_wck_ratio(dpm_clks->MemPstateTable[i].WckRatio);
+ } else {
+ clk_mgr_base->bw_params->clk_table.entries[i].memclk_mhz = dpm_clks->MemPstateTable[0].MemClk;
+ clk_mgr_base->bw_params->clk_table.entries[i].wck_ratio = dcn42_convert_wck_ratio(dpm_clks->MemPstateTable[0].WckRatio);
+ }
+ }
+
+ clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_memclk_levels = dpm_clks->NumDcfClkLevelsEnabled;
+
+ /* DTBCLK tied off in DCN42B */
+ clk_mgr_base->bw_params->clk_table.entries[0].dtbclk_mhz = 0;
+ clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dtbclk_levels = 0;
+ }
+ }
+ if (smu_dpm_clks.dpm_clks && smu_dpm_clks.mc_address.quad_part != 0)
+ dm_helpers_free_gpu_mem(clk_mgr_base->ctx, DC_MEM_ALLOC_TYPE_GART,
+ smu_dpm_clks.dpm_clks);
+}
+
void dcn42b_clk_mgr_construct(
struct dc_context *ctx,
struct clk_mgr_dcn42 *clk_mgr,
@@ -473,11 +639,6 @@ void dcn42b_clk_mgr_construct(
dcn42b_read_ss_info_from_lut(&clk_mgr->base);
clk_mgr->base.base.bw_params = &dcn42b_bw_params;
- if (clk_mgr->base.smu_present) {
- dcn42_get_smu_clocks(&clk_mgr->base);
- //overwrite values from dcn42_get_smu_clocks since dtbclk is tied off in DCN42B
- clk_mgr->base.base.bw_params->clk_table.entries[0].dtbclk_mhz = 0;
- clk_mgr->base.base.bw_params->clk_table.num_entries_per_clk.num_dtbclk_levels = 0;
- clk_mgr->base.base.clks.ref_dtbclk_khz = 0;
- }
+ if (clk_mgr->base.smu_present)
+ dcn42b_get_smu_clocks(&clk_mgr->base);
}
--
2.55.0
prev parent reply other threads:[~2026-07-16 19:07 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-16 19:07 [PATCH 0/2] DCN42B driver load fixes Matthew Stewart
2026-07-16 19:07 ` [PATCH 1/2] drm/amdgpu: Switch order of GC and Display IP blocks Matthew Stewart
2026-07-16 19:42 ` Aurabindo Pillai
2026-07-16 19:07 ` Matthew Stewart [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260716190844.368565-3-Matthew.Stewart2@amd.com \
--to=matthew.stewart2@amd.com \
--cc=Chuanyu.Tseng@amd.com \
--cc=Ray.Wu@amd.com \
--cc=amd-gfx@lists.freedesktop.org \
--cc=aurabindo.pillai@amd.com \
--cc=charlene.liu@amd.com \
--cc=chiahsuan.chung@amd.com \
--cc=daniel.wheeler@amd.com \
--cc=gabe.teeger@amd.com \
--cc=harry.wentland@amd.com \
--cc=ivan.lipski@amd.com \
--cc=jerry.zuo@amd.com \
--cc=roman.li@amd.com \
--cc=sunpeng.li@amd.com \
--cc=wayne.lin@amd.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.