aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/linux-yocto-4.19.8/1454-drm-amd-powerplay-implement-power_dpm_force_performa.patch
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.19.8/1454-drm-amd-powerplay-implement-power_dpm_force_performa.patch')
-rw-r--r--common/recipes-kernel/linux/linux-yocto-4.19.8/1454-drm-amd-powerplay-implement-power_dpm_force_performa.patch245
1 files changed, 245 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.19.8/1454-drm-amd-powerplay-implement-power_dpm_force_performa.patch b/common/recipes-kernel/linux/linux-yocto-4.19.8/1454-drm-amd-powerplay-implement-power_dpm_force_performa.patch
new file mode 100644
index 00000000..77d6df6d
--- /dev/null
+++ b/common/recipes-kernel/linux/linux-yocto-4.19.8/1454-drm-amd-powerplay-implement-power_dpm_force_performa.patch
@@ -0,0 +1,245 @@
+From 79fde0d3bda6a05ca31b1d319c537c26a5381e84 Mon Sep 17 00:00:00 2001
+From: Chengming Gui <Jack.Gui@amd.com>
+Date: Fri, 18 Jan 2019 11:27:25 +0800
+Subject: [PATCH 1454/2940] drm/amd/powerplay: implement
+ power_dpm_force_performance_level for SMU11
+
+add get_performance_level and force_performance_level
+to implement the sys interface for SMU11.
+
+Signed-off-by: Chengming Gui <Jack.Gui@amd.com>
+Reviewed-by: Huang Rui <ray.huang@amd.com>
+Acked-by: Alex Deucher <alexander.deucher@amd.com>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 23 ++++-
+ drivers/gpu/drm/amd/powerplay/amdgpu_smu.c | 2 +
+ .../gpu/drm/amd/powerplay/inc/amdgpu_smu.h | 6 ++
+ drivers/gpu/drm/amd/powerplay/smu_v11_0.c | 2 -
+ drivers/gpu/drm/amd/powerplay/vega20_ppt.c | 99 +++++++++++++++++++
+ 5 files changed, 127 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
+index 694d85b0f0a0..77d946f8fca5 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
+@@ -264,7 +264,9 @@ static ssize_t amdgpu_get_dpm_forced_performance_level(struct device *dev,
+ (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
+ return snprintf(buf, PAGE_SIZE, "off\n");
+
+- if (adev->powerplay.pp_funcs->get_performance_level)
++ if (is_support_sw_smu(adev))
++ level = smu_get_performance_level(&adev->smu);
++ else if (adev->powerplay.pp_funcs->get_performance_level)
+ level = amdgpu_dpm_get_performance_level(adev);
+ else
+ level = adev->pm.dpm.forced_level;
+@@ -297,7 +299,9 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
+ (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
+ return -EINVAL;
+
+- if (adev->powerplay.pp_funcs->get_performance_level)
++ if (is_support_sw_smu(adev))
++ current_level = smu_get_performance_level(&adev->smu);
++ else if (adev->powerplay.pp_funcs->get_performance_level)
+ current_level = amdgpu_dpm_get_performance_level(adev);
+
+ if (strncmp("low", buf, strlen("low")) == 0) {
+@@ -326,7 +330,20 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
+ if (current_level == level)
+ return count;
+
+- if (adev->powerplay.pp_funcs->force_performance_level) {
++ if (is_support_sw_smu(adev)) {
++ mutex_lock(&adev->pm.mutex);
++ if (adev->pm.dpm.thermal_active) {
++ count = -EINVAL;
++ mutex_unlock(&adev->pm.mutex);
++ goto fail;
++ }
++ ret = smu_force_performance_level(&adev->smu, level);
++ if (ret)
++ count = -EINVAL;
++ else
++ adev->pm.dpm.forced_level = level;
++ mutex_unlock(&adev->pm.mutex);
++ } else if (adev->powerplay.pp_funcs->force_performance_level) {
+ mutex_lock(&adev->pm.mutex);
+ if (adev->pm.dpm.thermal_active) {
+ count = -EINVAL;
+diff --git a/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c b/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c
+index 83fadcac18e6..2917411a10eb 100644
+--- a/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c
++++ b/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c
+@@ -351,6 +351,8 @@ static int smu_sw_init(void *handle)
+ smu->workload_setting[6] = PP_SMC_POWER_PROFILE_CUSTOM;
+ smu->display_config = &adev->pm.pm_display_cfg;
+
++ smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
++ smu->smu_dpm.requested_dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
+ ret = smu_init_microcode(smu);
+ if (ret) {
+ pr_err("Failed to load smu firmware!\n");
+diff --git a/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h
+index 63cd1ba60dc2..111424d0581d 100644
+--- a/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h
++++ b/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h
+@@ -423,6 +423,8 @@ struct pptable_funcs {
+ *clocks);
+ int (*get_power_profile_mode)(struct smu_context *smu, char *buf);
+ int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size);
++ enum amd_dpm_forced_level (*get_performance_level)(struct smu_context *smu);
++ int (*force_performance_level)(struct smu_context *smu, enum amd_dpm_forced_level level);
+ };
+
+ struct smu_funcs
+@@ -594,6 +596,10 @@ struct smu_funcs
+ ((smu)->funcs->get_power_profile_mode ? (smu)->funcs->get_power_profile_mode((smu), buf) : 0)
+ #define smu_set_power_profile_mode(smu, param, param_size) \
+ ((smu)->funcs->set_power_profile_mode ? (smu)->funcs->set_power_profile_mode((smu), (param), (param_size)) : 0)
++#define smu_get_performance_level(smu) \
++ ((smu)->ppt_funcs->get_performance_level ? (smu)->ppt_funcs->get_performance_level((smu)) : 0)
++#define smu_force_performance_level(smu, level) \
++ ((smu)->ppt_funcs->force_performance_level ? (smu)->ppt_funcs->force_performance_level((smu), (level)) : 0)
+
+ #define smu_msg_get_index(smu, msg) \
+ ((smu)->ppt_funcs? ((smu)->ppt_funcs->get_smu_msg_index? (smu)->ppt_funcs->get_smu_msg_index((smu), (msg)) : -EINVAL) : -EINVAL)
+diff --git a/drivers/gpu/drm/amd/powerplay/smu_v11_0.c b/drivers/gpu/drm/amd/powerplay/smu_v11_0.c
+index 93552d8c39fb..74ad160e1335 100644
+--- a/drivers/gpu/drm/amd/powerplay/smu_v11_0.c
++++ b/drivers/gpu/drm/amd/powerplay/smu_v11_0.c
+@@ -1100,7 +1100,6 @@ smu_v11_0_display_clock_voltage_request(struct smu_context *smu,
+ PPCLK_e clk_select = 0;
+ uint32_t clk_freq = clock_req->clock_freq_in_khz / 1000;
+
+- mutex_lock(&smu->mutex);
+ if (smu_feature_is_enabled(smu, FEATURE_DPM_DCEFCLK_BIT)) {
+ switch (clk_type) {
+ case amd_pp_dcef_clock:
+@@ -1129,7 +1128,6 @@ smu_v11_0_display_clock_voltage_request(struct smu_context *smu,
+ }
+
+ failed:
+- mutex_unlock(&smu->mutex);
+ return ret;
+ }
+
+diff --git a/drivers/gpu/drm/amd/powerplay/vega20_ppt.c b/drivers/gpu/drm/amd/powerplay/vega20_ppt.c
+index 5de0eabbeb29..911296d1f7cc 100644
+--- a/drivers/gpu/drm/amd/powerplay/vega20_ppt.c
++++ b/drivers/gpu/drm/amd/powerplay/vega20_ppt.c
+@@ -1744,6 +1744,103 @@ static int vega20_unforce_dpm_levels(struct smu_context *smu)
+ return ret;
+ }
+
++static enum amd_dpm_forced_level vega20_get_performance_level(struct smu_context *smu)
++{
++ struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
++ if (!smu_dpm_ctx->dpm_context)
++ return -EINVAL;
++
++ if (smu_dpm_ctx->dpm_level != smu_dpm_ctx->saved_dpm_level) {
++ mutex_lock(&(smu->mutex));
++ smu_dpm_ctx->saved_dpm_level = smu_dpm_ctx->dpm_level;
++ mutex_unlock(&(smu->mutex));
++ }
++ return smu_dpm_ctx->dpm_level;
++}
++
++static int
++vega20_force_performance_level(struct smu_context *smu, enum amd_dpm_forced_level level)
++{
++ int ret = 0;
++ int index = 0;
++ int i = 0;
++ uint32_t sclk_mask, mclk_mask, soc_mask;
++ long workload;
++ struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
++ if (!smu_dpm_ctx->dpm_context)
++ return -EINVAL;
++
++ for (i = 0; i < smu->adev->num_ip_blocks; i++) {
++ if (smu->adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC)
++ break;
++ }
++ mutex_lock(&smu->mutex);
++ smu->adev->ip_blocks[i].version->funcs->enable_umd_pstate(smu, &level);
++ ret = vega20_display_config_changed(smu);
++ if (ret) {
++ pr_err("Failed to change display config!");
++ goto failed;
++ }
++ ret = vega20_apply_clocks_adjust_rules(smu);
++ if (ret) {
++ pr_err("Failed to apply clocks adjust rules!");
++ goto failed;
++ }
++ ret = vega20_notify_smc_dispaly_config(smu);
++ if (ret) {
++ pr_err("Failed to notify smc display config!");
++ goto failed;
++ }
++ switch (level) {
++ case AMD_DPM_FORCED_LEVEL_HIGH:
++ ret = vega20_force_dpm_highest(smu);
++ break;
++
++ case AMD_DPM_FORCED_LEVEL_LOW:
++ ret = vega20_force_dpm_lowest(smu);
++ break;
++
++ case AMD_DPM_FORCED_LEVEL_AUTO:
++ ret = vega20_unforce_dpm_levels(smu);
++ break;
++
++ case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
++ case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
++ case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
++ case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
++ ret = vega20_get_profiling_clk_mask(smu, level,
++ &sclk_mask,
++ &mclk_mask,
++ &soc_mask);
++ if (ret)
++ goto failed;
++ vega20_force_clk_levels(smu, PP_SCLK, 1 << sclk_mask);
++ vega20_force_clk_levels(smu, PP_MCLK, 1 << mclk_mask);
++ break;
++
++ case AMD_DPM_FORCED_LEVEL_MANUAL:
++ case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
++ default:
++ break;
++ }
++
++ if (!ret)
++ smu_dpm_ctx->dpm_level = level;
++
++ if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) {
++ index = fls(smu->workload_mask);
++ index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
++ workload = smu->workload_setting[index];
++
++ if (smu->power_profile_mode != workload)
++ smu->funcs->set_power_profile_mode(smu, &workload, 0);
++ }
++
++failed:
++ mutex_unlock(&smu->mutex);
++ return ret;
++}
++
+ static const struct pptable_funcs vega20_ppt_funcs = {
+ .alloc_dpm_context = vega20_allocate_dpm_context,
+ .store_powerplay_table = vega20_store_powerplay_table,
+@@ -1761,6 +1858,8 @@ static const struct pptable_funcs vega20_ppt_funcs = {
+ .get_clock_by_type_with_latency = vega20_get_clock_by_type_with_latency,
+ .set_default_od8_settings = vega20_set_default_od8_setttings,
+ .get_od_percentage = vega20_get_od_percentage,
++ .get_performance_level = vega20_get_performance_level,
++ .force_performance_level = vega20_force_performance_level,
+ };
+
+ void vega20_set_ppt_funcs(struct smu_context *smu)
+--
+2.17.1
+