diff options
Diffstat (limited to 'drivers/gpu/drm/amd/powerplay/navi10_ppt.c')
-rw-r--r-- | drivers/gpu/drm/amd/powerplay/navi10_ppt.c | 176 |
1 files changed, 133 insertions, 43 deletions
diff --git a/drivers/gpu/drm/amd/powerplay/navi10_ppt.c b/drivers/gpu/drm/amd/powerplay/navi10_ppt.c index 880fe0930d9e..4aaad255a288 100644 --- a/drivers/gpu/drm/amd/powerplay/navi10_ppt.c +++ b/drivers/gpu/drm/amd/powerplay/navi10_ppt.c @@ -331,7 +331,10 @@ navi10_get_allowed_feature_mask(struct smu_context *smu, | FEATURE_MASK(FEATURE_DS_DCEFCLK_BIT) | FEATURE_MASK(FEATURE_FW_DSTATE_BIT) | FEATURE_MASK(FEATURE_BACO_BIT) - | FEATURE_MASK(FEATURE_ACDC_BIT); + | FEATURE_MASK(FEATURE_ACDC_BIT) + | FEATURE_MASK(FEATURE_GFX_SS_BIT) + | FEATURE_MASK(FEATURE_APCC_DFLL_BIT) + | FEATURE_MASK(FEATURE_FW_CTF_BIT); if (adev->pm.pp_feature & PP_MCLK_DPM_MASK) *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_UCLK_BIT) @@ -339,8 +342,7 @@ navi10_get_allowed_feature_mask(struct smu_context *smu, | FEATURE_MASK(FEATURE_MEM_MVDD_SCALING_BIT); if (adev->pm.pp_feature & PP_GFXOFF_MASK) { - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_SS_BIT) - | FEATURE_MASK(FEATURE_GFXOFF_BIT); + *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFXOFF_BIT); /* TODO: remove it once fw fix the bug */ *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_FW_DSTATE_BIT); } @@ -465,9 +467,6 @@ static int navi10_append_powerplay_table(struct smu_context *smu) smc_pptable->MvddRatio = smc_dpm_table->MvddRatio; if (adev->pm.pp_feature & PP_GFXOFF_MASK) { - *(uint64_t *)smc_pptable->FeaturesToRun |= FEATURE_MASK(FEATURE_GFX_SS_BIT) - | FEATURE_MASK(FEATURE_GFXOFF_BIT); - /* TODO: remove it once SMU fw fix it */ smc_pptable->DebugOverrides |= DPM_OVERRIDE_DISABLE_DFLL_PLL_SHUTDOWN; } @@ -614,7 +613,7 @@ static int navi10_get_current_clk_freq_by_table(struct smu_context *smu, memset(&metrics, 0, sizeof(metrics)); - ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, (void *)&metrics, false); + ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0, (void *)&metrics, false); if (ret) return ret; @@ -627,11 +626,26 @@ static int navi10_get_current_clk_freq_by_table(struct smu_context *smu, return ret; } +static bool navi10_is_support_fine_grained_dpm(struct smu_context *smu, enum smu_clk_type clk_type) +{ + PPTable_t *pptable = smu->smu_table.driver_pptable; + DpmDescriptor_t *dpm_desc = NULL; + uint32_t clk_index = 0; + + clk_index = smu_clk_get_index(smu, clk_type); + dpm_desc = &pptable->DpmDescriptor[clk_index]; + + /* 0 - Fine grained DPM, 1 - Discrete DPM */ + return dpm_desc->SnapToDiscrete == 0 ? true : false; +} + static int navi10_print_clk_levels(struct smu_context *smu, enum smu_clk_type clk_type, char *buf) { int i, size = 0, ret = 0; uint32_t cur_value = 0, value = 0, count = 0; + uint32_t freq_values[3] = {0}; + uint32_t mark_index = 0; switch (clk_type) { case SMU_GFXCLK: @@ -644,22 +658,42 @@ static int navi10_print_clk_levels(struct smu_context *smu, ret = smu_get_current_clk_freq(smu, clk_type, &cur_value); if (ret) return size; + /* 10KHz -> MHz */ cur_value = cur_value / 100; - size += sprintf(buf, "current clk: %uMhz\n", cur_value); - ret = smu_get_dpm_level_count(smu, clk_type, &count); if (ret) return size; - for (i = 0; i < count; i++) { - ret = smu_get_dpm_freq_by_index(smu, clk_type, i, &value); + if (!navi10_is_support_fine_grained_dpm(smu, clk_type)) { + for (i = 0; i < count; i++) { + ret = smu_get_dpm_freq_by_index(smu, clk_type, i, &value); + if (ret) + return size; + + size += sprintf(buf + size, "%d: %uMhz %s\n", i, value, + cur_value == value ? "*" : ""); + } + } else { + ret = smu_get_dpm_freq_by_index(smu, clk_type, 0, &freq_values[0]); if (ret) return size; + ret = smu_get_dpm_freq_by_index(smu, clk_type, count - 1, &freq_values[2]); + if (ret) + return size; + + freq_values[1] = cur_value; + mark_index = cur_value == freq_values[0] ? 0 : + cur_value == freq_values[2] ? 2 : 1; + if (mark_index != 1) + freq_values[1] = (freq_values[0] + freq_values[2]) / 2; + + for (i = 0; i < 3; i++) { + size += sprintf(buf + size, "%d: %uMhz %s\n", i, freq_values[i], + i == mark_index ? "*" : ""); + } - size += sprintf(buf + size, "%d: %uMhz %s\n", i, value, - cur_value == value ? "*" : ""); } break; default: @@ -709,7 +743,7 @@ static int navi10_force_clk_levels(struct smu_context *smu, static int navi10_populate_umd_state_clk(struct smu_context *smu) { int ret = 0; - uint32_t min_sclk_freq = 0; + uint32_t min_sclk_freq = 0, min_mclk_freq = 0; ret = smu_get_dpm_freq_range(smu, SMU_SCLK, &min_sclk_freq, NULL); if (ret) @@ -717,6 +751,12 @@ static int navi10_populate_umd_state_clk(struct smu_context *smu) smu->pstate_sclk = min_sclk_freq * 100; + ret = smu_get_dpm_freq_range(smu, SMU_MCLK, &min_mclk_freq, NULL); + if (ret) + return ret; + + smu->pstate_mclk = min_mclk_freq * 100; + return ret; } @@ -827,27 +867,20 @@ static int navi10_force_dpm_limit_value(struct smu_context *smu, bool highest) return ret; } -static int navi10_unforce_dpm_levels(struct smu_context *smu) { - +static int navi10_unforce_dpm_levels(struct smu_context *smu) +{ int ret = 0, i = 0; uint32_t min_freq, max_freq; enum smu_clk_type clk_type; - struct clk_feature_map { - enum smu_clk_type clk_type; - uint32_t feature; - } clk_feature_map[] = { - {SMU_GFXCLK, SMU_FEATURE_DPM_GFXCLK_BIT}, - {SMU_MCLK, SMU_FEATURE_DPM_UCLK_BIT}, - {SMU_SOCCLK, SMU_FEATURE_DPM_SOCCLK_BIT}, + enum smu_clk_type clks[] = { + SMU_GFXCLK, + SMU_MCLK, + SMU_SOCCLK, }; - for (i = 0; i < ARRAY_SIZE(clk_feature_map); i++) { - if (!smu_feature_is_enabled(smu, clk_feature_map[i].feature)) - continue; - - clk_type = clk_feature_map[i].clk_type; - + for (i = 0; i < ARRAY_SIZE(clks); i++) { + clk_type = clks[i]; ret = smu_get_dpm_freq_range(smu, clk_type, &min_freq, &max_freq); if (ret) return ret; @@ -868,7 +901,7 @@ static int navi10_get_gpu_power(struct smu_context *smu, uint32_t *value) if (!value) return -EINVAL; - ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, (void *)&metrics, + ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0, (void *)&metrics, false); if (ret) return ret; @@ -890,7 +923,7 @@ static int navi10_get_current_activity_percent(struct smu_context *smu, msleep(1); - ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, + ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0, (void *)&metrics, false); if (ret) return ret; @@ -921,22 +954,23 @@ static bool navi10_is_dpm_running(struct smu_context *smu) return !!(feature_enabled & SMC_DPM_FEATURE); } -static int navi10_get_fan_speed(struct smu_context *smu, uint16_t *value) +static int navi10_get_fan_speed_rpm(struct smu_context *smu, + uint32_t *speed) { SmuMetrics_t metrics; int ret = 0; - if (!value) + if (!speed) return -EINVAL; memset(&metrics, 0, sizeof(metrics)); - ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, + ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0, (void *)&metrics, false); if (ret) return ret; - *value = metrics.CurrFanSpeed; + *speed = metrics.CurrFanSpeed; return ret; } @@ -946,10 +980,10 @@ static int navi10_get_fan_speed_percent(struct smu_context *smu, { int ret = 0; uint32_t percent = 0; - uint16_t current_rpm; + uint32_t current_rpm; PPTable_t *pptable = smu->smu_table.driver_pptable; - ret = navi10_get_fan_speed(smu, ¤t_rpm); + ret = navi10_get_fan_speed_rpm(smu, ¤t_rpm); if (ret) return ret; @@ -997,7 +1031,7 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf) /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ workload_type = smu_workload_get_type(smu, i); result = smu_update_table(smu, - SMU_TABLE_ACTIVITY_MONITOR_COEFF | workload_type << 16, + SMU_TABLE_ACTIVITY_MONITOR_COEFF, workload_type, (void *)(&activity_monitor), false); if (result) { pr_err("[%s] Failed to get activity monitor!", __func__); @@ -1070,7 +1104,7 @@ static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, u return -EINVAL; ret = smu_update_table(smu, - SMU_TABLE_ACTIVITY_MONITOR_COEFF | WORKLOAD_PPLIB_CUSTOM_BIT << 16, + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, (void *)(&activity_monitor), false); if (ret) { pr_err("[%s] Failed to get activity monitor!", __func__); @@ -1114,7 +1148,7 @@ static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, u } ret = smu_update_table(smu, - SMU_TABLE_ACTIVITY_MONITOR_COEFF | WORKLOAD_PPLIB_CUSTOM_BIT << 16, + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, (void *)(&activity_monitor), true); if (ret) { pr_err("[%s] Failed to set activity monitor!", __func__); @@ -1157,14 +1191,14 @@ static int navi10_get_profiling_clk_mask(struct smu_context *smu, ret = smu_get_dpm_level_count(smu, SMU_MCLK, &level_count); if (ret) return ret; - *sclk_mask = level_count - 1; + *mclk_mask = level_count - 1; } if(soc_mask) { ret = smu_get_dpm_level_count(smu, SMU_SOCCLK, &level_count); if (ret) return ret; - *sclk_mask = level_count - 1; + *soc_mask = level_count - 1; } } @@ -1280,7 +1314,7 @@ static int navi10_thermal_get_temperature(struct smu_context *smu, if (!value) return -EINVAL; - ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, (void *)&metrics, false); + ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0, (void *)&metrics, false); if (ret) return ret; @@ -1532,6 +1566,60 @@ static int navi10_set_ppfeature_status(struct smu_context *smu, return 0; } +static int navi10_set_peak_clock_by_device(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + int ret = 0; + uint32_t sclk_freq = 0, uclk_freq = 0; + uint32_t uclk_level = 0; + + switch (adev->rev_id) { + case 0xf0: /* XTX */ + case 0xc0: + sclk_freq = NAVI10_PEAK_SCLK_XTX; + break; + case 0xf1: /* XT */ + case 0xc1: + sclk_freq = NAVI10_PEAK_SCLK_XT; + break; + default: /* XL */ + sclk_freq = NAVI10_PEAK_SCLK_XL; + break; + } + + ret = smu_get_dpm_level_count(smu, SMU_UCLK, &uclk_level); + if (ret) + return ret; + ret = smu_get_dpm_freq_by_index(smu, SMU_UCLK, uclk_level - 1, &uclk_freq); + if (ret) + return ret; + + ret = smu_set_soft_freq_range(smu, SMU_SCLK, sclk_freq, sclk_freq); + if (ret) + return ret; + ret = smu_set_soft_freq_range(smu, SMU_UCLK, uclk_freq, uclk_freq); + if (ret) + return ret; + + return ret; +} + +static int navi10_set_performance_level(struct smu_context *smu, enum amd_dpm_forced_level level) +{ + int ret = 0; + + switch (level) { + case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: + ret = navi10_set_peak_clock_by_device(smu); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + static const struct pptable_funcs navi10_ppt_funcs = { .tables_init = navi10_tables_init, .alloc_dpm_context = navi10_allocate_dpm_context, @@ -1559,6 +1647,7 @@ static const struct pptable_funcs navi10_ppt_funcs = { .unforce_dpm_levels = navi10_unforce_dpm_levels, .is_dpm_running = navi10_is_dpm_running, .get_fan_speed_percent = navi10_get_fan_speed_percent, + .get_fan_speed_rpm = navi10_get_fan_speed_rpm, .get_power_profile_mode = navi10_get_power_profile_mode, .set_power_profile_mode = navi10_set_power_profile_mode, .get_profiling_clk_mask = navi10_get_profiling_clk_mask, @@ -1567,6 +1656,7 @@ static const struct pptable_funcs navi10_ppt_funcs = { .get_uclk_dpm_states = navi10_get_uclk_dpm_states, .get_ppfeature_status = navi10_get_ppfeature_status, .set_ppfeature_status = navi10_set_ppfeature_status, + .set_performance_level = navi10_set_performance_level, }; void navi10_set_ppt_funcs(struct smu_context *smu) |