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); size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", level_index + i, dpm_table->dpm_levels[i].value, - freq_match ? "*" : ""); + (!is_deep_sleep && + i == nearest_level) ? "*" : ""); } } else { count = 2; -- 2.55.0
