diff options
Diffstat (limited to 'drivers/gpu/drm/amd/powerplay/renoir_ppt.c')
-rw-r--r-- | drivers/gpu/drm/amd/powerplay/renoir_ppt.c | 228 |
1 files changed, 221 insertions, 7 deletions
diff --git a/drivers/gpu/drm/amd/powerplay/renoir_ppt.c b/drivers/gpu/drm/amd/powerplay/renoir_ppt.c index 977bdd962e98..861e6410363b 100644 --- a/drivers/gpu/drm/amd/powerplay/renoir_ppt.c +++ b/drivers/gpu/drm/amd/powerplay/renoir_ppt.c @@ -31,6 +31,9 @@ #include "renoir_ppt.h" +#define CLK_MAP(clk, index) \ + [SMU_##clk] = {1, (index)} + #define MSG_MAP(msg, index) \ [SMU_MSG_##msg] = {1, (index)} @@ -104,6 +107,14 @@ static struct smu_12_0_cmn2aisc_mapping renoir_message_map[SMU_MSG_MAX_COUNT] = MSG_MAP(SetHardMinFclkByFreq, PPSMC_MSG_SetHardMinFclkByFreq), }; +static struct smu_12_0_cmn2aisc_mapping renoir_clk_map[SMU_CLK_COUNT] = { + CLK_MAP(GFXCLK, CLOCK_GFXCLK), + CLK_MAP(SCLK, CLOCK_GFXCLK), + CLK_MAP(SOCCLK, CLOCK_SOCCLK), + CLK_MAP(UCLK, CLOCK_UMCCLK), + CLK_MAP(MCLK, CLOCK_UMCCLK), +}; + static struct smu_12_0_cmn2aisc_mapping renoir_table_map[SMU_TABLE_COUNT] = { TAB_MAP_VALID(WATERMARKS), TAB_MAP_INVALID(CUSTOM_DPM), @@ -125,6 +136,21 @@ static int renoir_get_smu_msg_index(struct smu_context *smc, uint32_t index) return mapping.map_to; } +static int renoir_get_smu_clk_index(struct smu_context *smc, uint32_t index) +{ + struct smu_12_0_cmn2aisc_mapping mapping; + + if (index >= SMU_CLK_COUNT) + return -EINVAL; + + mapping = renoir_clk_map[index]; + if (!(mapping.valid_mapping)) { + return -EINVAL; + } + + return mapping.map_to; +} + static int renoir_get_smu_table_index(struct smu_context *smc, uint32_t index) { struct smu_12_0_cmn2aisc_mapping mapping; @@ -139,6 +165,30 @@ static int renoir_get_smu_table_index(struct smu_context *smc, uint32_t index) return mapping.map_to; } +static int renoir_get_metrics_table(struct smu_context *smu, + SmuMetrics_t *metrics_table) +{ + struct smu_table_context *smu_table= &smu->smu_table; + int ret = 0; + + mutex_lock(&smu->metrics_lock); + if (!smu_table->metrics_time || time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(100))) { + ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0, + (void *)smu_table->metrics_table, false); + if (ret) { + pr_info("Failed to export SMU metrics table!\n"); + mutex_unlock(&smu->metrics_lock); + return ret; + } + smu_table->metrics_time = jiffies; + } + + memcpy(metrics_table, smu_table->metrics_table, sizeof(SmuMetrics_t)); + mutex_unlock(&smu->metrics_lock); + + return ret; +} + static int renoir_tables_init(struct smu_context *smu, struct smu_table *tables) { struct smu_table_context *smu_table = &smu->smu_table; @@ -154,6 +204,15 @@ static int renoir_tables_init(struct smu_context *smu, struct smu_table *tables) if (!smu_table->clocks_table) return -ENOMEM; + smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL); + if (!smu_table->metrics_table) + return -ENOMEM; + smu_table->metrics_time = 0; + + smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); + if (!smu_table->watermarks_table) + return -ENOMEM; + return 0; } @@ -187,8 +246,7 @@ static int renoir_print_clk_levels(struct smu_context *smu, memset(&metrics, 0, sizeof(metrics)); - ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0, - (void *)&metrics, false); + ret = renoir_get_metrics_table(smu, &metrics); if (ret) return ret; @@ -301,6 +359,51 @@ static int renoir_dpm_set_uvd_enable(struct smu_context *smu, bool enable) return ret; } +static int renoir_dpm_set_jpeg_enable(struct smu_context *smu, bool enable) +{ + struct smu_power_context *smu_power = &smu->smu_power; + struct smu_power_gate *power_gate = &smu_power->power_gate; + int ret = 0; + + if (enable) { + if (smu_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) { + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_PowerUpJpeg, 0); + if (ret) + return ret; + } + power_gate->jpeg_gated = false; + } else { + if (smu_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) { + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_PowerDownJpeg, 0); + if (ret) + return ret; + } + power_gate->jpeg_gated = true; + } + + return ret; +} + +static int renoir_get_current_clk_freq_by_table(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *value) +{ + int ret = 0, clk_id = 0; + SmuMetrics_t metrics; + + ret = renoir_get_metrics_table(smu, &metrics); + if (ret) + return ret; + + clk_id = smu_clk_get_index(smu, clk_type); + if (clk_id < 0) + return clk_id; + + *value = metrics.ClockFrequency[clk_id]; + + return ret; +} + static int renoir_force_dpm_limit_value(struct smu_context *smu, bool highest) { int ret = 0, i = 0; @@ -361,6 +464,50 @@ static int renoir_unforce_dpm_levels(struct smu_context *smu) { return ret; } +static int renoir_get_gpu_temperature(struct smu_context *smu, uint32_t *value) +{ + int ret = 0; + SmuMetrics_t metrics; + + if (!value) + return -EINVAL; + + ret = renoir_get_metrics_table(smu, &metrics); + if (ret) + return ret; + + *value = (metrics.GfxTemperature / 100) * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + + return 0; +} + +static int renoir_get_current_activity_percent(struct smu_context *smu, + enum amd_pp_sensors sensor, + uint32_t *value) +{ + int ret = 0; + SmuMetrics_t metrics; + + if (!value) + return -EINVAL; + + ret = renoir_get_metrics_table(smu, &metrics); + if (ret) + return ret; + + switch (sensor) { + case AMDGPU_PP_SENSOR_GPU_LOAD: + *value = metrics.AverageGfxActivity / 100; + break; + default: + pr_err("Invalid sensor for retrieving clock activity\n"); + return -EINVAL; + } + + return 0; +} + static int renoir_get_workload_type(struct smu_context *smu, uint32_t profile) { @@ -565,19 +712,43 @@ static int renoir_set_peak_clock_by_device(struct smu_context *smu) return ret; } -static int renoir_set_performance_level(struct smu_context *smu, enum amd_dpm_forced_level level) +static int renoir_set_performance_level(struct smu_context *smu, + enum amd_dpm_forced_level level) { int ret = 0; + uint32_t sclk_mask, mclk_mask, soc_mask; switch (level) { + case AMD_DPM_FORCED_LEVEL_HIGH: + ret = smu_force_dpm_limit_value(smu, true); + break; + case AMD_DPM_FORCED_LEVEL_LOW: + ret = smu_force_dpm_limit_value(smu, false); + break; + case AMD_DPM_FORCED_LEVEL_AUTO: + case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: + ret = smu_unforce_dpm_levels(smu); + break; + case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: + case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: + ret = smu_get_profiling_clk_mask(smu, level, + &sclk_mask, + &mclk_mask, + &soc_mask); + if (ret) + return ret; + smu_force_clk_levels(smu, SMU_SCLK, 1 << sclk_mask, false); + smu_force_clk_levels(smu, SMU_MCLK, 1 << mclk_mask, false); + smu_force_clk_levels(smu, SMU_SOCCLK, 1 << soc_mask, false); + break; case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: ret = renoir_set_peak_clock_by_device(smu); break; + case AMD_DPM_FORCED_LEVEL_MANUAL: + case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: default: - ret = -EINVAL; break; } - return ret; } @@ -636,9 +807,17 @@ static int renoir_set_watermarks_table( } /* pass data to smu controller */ - ret = smu_write_watermarks_table(smu); + if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && + !(smu->watermarks_bitmap & WATERMARKS_LOADED)) { + ret = smu_write_watermarks_table(smu); + if (ret) { + pr_err("Failed to update WMTABLE!"); + return ret; + } + smu->watermarks_bitmap |= WATERMARKS_LOADED; + } - return ret; + return 0; } static int renoir_get_power_profile_mode(struct smu_context *smu, @@ -674,8 +853,36 @@ static int renoir_get_power_profile_mode(struct smu_context *smu, return size; } +static int renoir_read_sensor(struct smu_context *smu, + enum amd_pp_sensors sensor, + void *data, uint32_t *size) +{ + int ret = 0; + + if (!data || !size) + return -EINVAL; + + mutex_lock(&smu->sensor_lock); + switch (sensor) { + case AMDGPU_PP_SENSOR_GPU_LOAD: + ret = renoir_get_current_activity_percent(smu, sensor, (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_GPU_TEMP: + ret = renoir_get_gpu_temperature(smu, (uint32_t *)data); + *size = 4; + break; + default: + ret = smu_v12_0_read_sensor(smu, sensor, data, size); + } + mutex_unlock(&smu->sensor_lock); + + return ret; +} + static const struct pptable_funcs renoir_ppt_funcs = { .get_smu_msg_index = renoir_get_smu_msg_index, + .get_smu_clk_index = renoir_get_smu_clk_index, .get_smu_table_index = renoir_get_smu_table_index, .tables_init = renoir_tables_init, .set_power_state = NULL, @@ -683,6 +890,8 @@ static const struct pptable_funcs renoir_ppt_funcs = { .print_clk_levels = renoir_print_clk_levels, .get_current_power_state = renoir_get_current_power_state, .dpm_set_uvd_enable = renoir_dpm_set_uvd_enable, + .dpm_set_jpeg_enable = renoir_dpm_set_jpeg_enable, + .get_current_clk_freq_by_table = renoir_get_current_clk_freq_by_table, .force_dpm_limit_value = renoir_force_dpm_limit_value, .unforce_dpm_levels = renoir_unforce_dpm_levels, .get_workload_type = renoir_get_workload_type, @@ -693,10 +902,12 @@ static const struct pptable_funcs renoir_ppt_funcs = { .get_dpm_clock_table = renoir_get_dpm_clock_table, .set_watermarks_table = renoir_set_watermarks_table, .get_power_profile_mode = renoir_get_power_profile_mode, + .read_sensor = renoir_read_sensor, .check_fw_status = smu_v12_0_check_fw_status, .check_fw_version = smu_v12_0_check_fw_version, .powergate_sdma = smu_v12_0_powergate_sdma, .powergate_vcn = smu_v12_0_powergate_vcn, + .powergate_jpeg = smu_v12_0_powergate_jpeg, .send_smc_msg_with_param = smu_v12_0_send_msg_with_param, .read_smc_arg = smu_v12_0_read_arg, .set_gfx_cgpg = smu_v12_0_set_gfx_cgpg, @@ -704,9 +915,12 @@ static const struct pptable_funcs renoir_ppt_funcs = { .init_smc_tables = smu_v12_0_init_smc_tables, .fini_smc_tables = smu_v12_0_fini_smc_tables, .populate_smc_tables = smu_v12_0_populate_smc_tables, + .get_enabled_mask = smu_v12_0_get_enabled_mask, + .get_current_clk_freq = smu_v12_0_get_current_clk_freq, .get_dpm_ultimate_freq = smu_v12_0_get_dpm_ultimate_freq, .mode2_reset = smu_v12_0_mode2_reset, .set_soft_freq_limited_range = smu_v12_0_set_soft_freq_limited_range, + .set_driver_table_location = smu_v12_0_set_driver_table_location, }; void renoir_set_ppt_funcs(struct smu_context *smu) |