-----Original Message-----
From: Lazar, Lijo <[email protected]>
Sent: Monday, October 12, 2026 12:12
To: Wang, Kevin <[email protected]>; [email protected]
Cc: Deucher, Alexander <[email protected]>; Zhang, Hawking
<[email protected]>; Feng, Kenneth <[email protected]>
Subject: Re: [PATCH] drm/amd/pm: mark the current DPM clock level active
On 12-Oct-26 6:57 AM, Kevin Wang wrote:
PMFW can report clocks outside or between advertised DPM levels.
Report a clock below DPM0 as a special active S level.
Mark the nearest level active for a discrete DPM table.
Clamp a clock above the table range to the maximum DPM level.
Keep reporting the actual clock for a fine-grained DPM table.
Signed-off-by: Kevin Wang <[email protected]>
---
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 35 ++++++++++++++++++++------
1 file changed, 27 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
index 361657c19ea3..8cf616517ddd 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
@@ -1391,11 +1391,12 @@ int smu_cmn_print_dpm_clk_levels(struct
smu_context *smu,
uint32_t cur_clk, char *buf, int *offset)
{
uint32_t min_clk, max_clk, level_index, count;
+ uint32_t nearest_level = 0, nearest_diff = U32_MAX;
uint32_t freq_values[3];
+ uint32_t clk_diff, level_clk;
int size, lvl, i;
bool is_fine_grained;
bool is_deep_sleep;
- bool freq_match;
if (!dpm_table || !buf)
return -EINVAL;
@@ -1407,23 +1408,41 @@ int smu_cmn_print_dpm_clk_levels(struct
smu_context *smu,
min_clk = SMU_DPM_TABLE_MIN(dpm_table);
max_clk = SMU_DPM_TABLE_MAX(dpm_table);
- /* Deep sleep - current clock < min_clock/2, TBD: cur_clk = 0 as GFXOFF */
- is_deep_sleep = cur_clk < min_clk / 2;
+ /* A clock below DPM0 is reported as a special deep-sleep level. */
+ is_deep_sleep = cur_clk < min_clk;
if (is_deep_sleep) {
size += sysfs_emit_at(buf, size, "S: %uMhz *\n", cur_clk);
level_index = 1;
}
+ /*
+ * Discrete tables mark the level nearest to the current clock. Clamp
+ * clocks above the advertised range to the last level. Fine-grained
+ * tables keep reporting the actual current clock between min and max.
+ */
if (!is_fine_grained || count == 1) {
+ if (!is_deep_sleep) {
+ if (cur_clk >= max_clk) {
+ nearest_level = count - 1;
+ } else {
+ for (i = 0; i < count; i++) {
+ level_clk = dpm_table->dpm_levels[i].value;
+ clk_diff = cur_clk > level_clk ?
+ cur_clk - level_clk : level_clk -
cur_clk;
+ if (clk_diff < nearest_diff) {
+ nearest_diff = clk_diff;
+ nearest_level = i;
+ }
+ }
+ }
+ }
+
for (i = 0; i < count; i++) {
- freq_match = !is_deep_sleep &&
- smu_cmn_freqs_match(
- cur_clk,
- dpm_table->dpm_levels[i].value);
By this change, if this function is no longer used, it can be removed as well.