summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 17:35:05 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 17:39:31 +0000
commit85c675d0d09a45a135bddd15d7b385f8758c32fb (patch)
tree76267dbc9b9a130337be3640948fe397b04ac629 /drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
parentAdding upstream version 6.6.15. (diff)
downloadlinux-85c675d0d09a45a135bddd15d7b385f8758c32fb.tar.xz
linux-85c675d0d09a45a135bddd15d7b385f8758c32fb.zip
Adding upstream version 6.7.7.upstream/6.7.7
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c')
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c222
1 files changed, 181 insertions, 41 deletions
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index 56e4c312c..60dce148b 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -44,6 +44,7 @@
#include "smu_v13_0_5_ppt.h"
#include "smu_v13_0_6_ppt.h"
#include "smu_v13_0_7_ppt.h"
+#include "smu_v14_0_0_ppt.h"
#include "amd_pcie.h"
/*
@@ -216,6 +217,20 @@ static int smu_set_gfx_imu_enable(struct smu_context *smu)
return smu_set_gfx_power_up_by_imu(smu);
}
+static bool is_vcn_enabled(struct amdgpu_device *adev)
+{
+ int i;
+
+ for (i = 0; i < adev->num_ip_blocks; i++) {
+ if ((adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_VCN ||
+ adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_JPEG) &&
+ !adev->ip_blocks[i].status.valid)
+ return false;
+ }
+
+ return true;
+}
+
static int smu_dpm_set_vcn_enable(struct smu_context *smu,
bool enable)
{
@@ -223,6 +238,12 @@ static int smu_dpm_set_vcn_enable(struct smu_context *smu,
struct smu_power_gate *power_gate = &smu_power->power_gate;
int ret = 0;
+ /*
+ * don't poweron vcn/jpeg when they are skipped.
+ */
+ if (!is_vcn_enabled(smu->adev))
+ return 0;
+
if (!smu->ppt_funcs->dpm_set_vcn_enable)
return 0;
@@ -243,6 +264,9 @@ static int smu_dpm_set_jpeg_enable(struct smu_context *smu,
struct smu_power_gate *power_gate = &smu_power->power_gate;
int ret = 0;
+ if (!is_vcn_enabled(smu->adev))
+ return 0;
+
if (!smu->ppt_funcs->dpm_set_jpeg_enable)
return 0;
@@ -256,6 +280,49 @@ static int smu_dpm_set_jpeg_enable(struct smu_context *smu,
return ret;
}
+static int smu_dpm_set_vpe_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 (!smu->ppt_funcs->dpm_set_vpe_enable)
+ return 0;
+
+ if (atomic_read(&power_gate->vpe_gated) ^ enable)
+ return 0;
+
+ ret = smu->ppt_funcs->dpm_set_vpe_enable(smu, enable);
+ if (!ret)
+ atomic_set(&power_gate->vpe_gated, !enable);
+
+ return ret;
+}
+
+static int smu_dpm_set_umsch_mm_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 (!smu->adev->enable_umsch_mm)
+ return 0;
+
+ if (!smu->ppt_funcs->dpm_set_umsch_mm_enable)
+ return 0;
+
+ if (atomic_read(&power_gate->umsch_mm_gated) ^ enable)
+ return 0;
+
+ ret = smu->ppt_funcs->dpm_set_umsch_mm_enable(smu, enable);
+ if (!ret)
+ atomic_set(&power_gate->umsch_mm_gated, !enable);
+
+ return ret;
+}
+
/**
* smu_dpm_set_power_gate - power gate/ungate the specific IP block
*
@@ -314,6 +381,12 @@ static int smu_dpm_set_power_gate(void *handle,
dev_err(smu->adev->dev, "Failed to power %s JPEG!\n",
gate ? "gate" : "ungate");
break;
+ case AMD_IP_BLOCK_TYPE_VPE:
+ ret = smu_dpm_set_vpe_enable(smu, !gate);
+ if (ret)
+ dev_err(smu->adev->dev, "Failed to power %s VPE!\n",
+ gate ? "gate" : "ungate");
+ break;
default:
dev_err(smu->adev->dev, "Unsupported block type!\n");
return -EINVAL;
@@ -463,7 +536,7 @@ bool is_support_sw_smu(struct amdgpu_device *adev)
if (adev->asic_type == CHIP_VEGA20)
return false;
- if (adev->ip_versions[MP1_HWIP][0] >= IP_VERSION(11, 0, 0))
+ if (amdgpu_ip_version(adev, MP1_HWIP, 0) >= IP_VERSION(11, 0, 0))
return true;
return false;
@@ -581,7 +654,7 @@ static int smu_set_funcs(struct amdgpu_device *adev)
if (adev->pm.pp_feature & PP_OVERDRIVE_MASK)
smu->od_enabled = true;
- switch (adev->ip_versions[MP1_HWIP][0]) {
+ switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
case IP_VERSION(11, 0, 0):
case IP_VERSION(11, 0, 5):
case IP_VERSION(11, 0, 9):
@@ -638,6 +711,9 @@ static int smu_set_funcs(struct amdgpu_device *adev)
case IP_VERSION(13, 0, 7):
smu_v13_0_7_set_ppt_funcs(smu);
break;
+ case IP_VERSION(14, 0, 0):
+ smu_v14_0_0_set_ppt_funcs(smu);
+ break;
default:
return -EINVAL;
}
@@ -745,8 +821,8 @@ static int smu_late_init(void *handle)
adev->pm.ac_power = power_supply_is_system_supplied() > 0;
smu_set_ac_dc(smu);
- if ((adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 1)) ||
- (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 3)))
+ if ((amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 1)) ||
+ (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 3)))
return 0;
if (!amdgpu_sriov_vf(adev) || smu->od_enabled) {
@@ -766,7 +842,8 @@ static int smu_late_init(void *handle)
ret = smu_get_asic_power_limits(smu,
&smu->current_power_limit,
&smu->default_power_limit,
- &smu->max_power_limit);
+ &smu->max_power_limit,
+ &smu->min_power_limit);
if (ret) {
dev_err(adev->dev, "Failed to get asic power limits!\n");
return ret;
@@ -1100,6 +1177,21 @@ static void smu_swctf_delayed_work_handler(struct work_struct *work)
orderly_poweroff(true);
}
+static void smu_init_xgmi_plpd_mode(struct smu_context *smu)
+{
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 2)) {
+ smu->plpd_mode = XGMI_PLPD_DEFAULT;
+ return;
+ }
+
+ /* PMFW put PLPD into default policy after enabling the feature */
+ if (smu_feature_is_enabled(smu,
+ SMU_FEATURE_XGMI_PER_LINK_PWR_DWN_BIT))
+ smu->plpd_mode = XGMI_PLPD_DEFAULT;
+ else
+ smu->plpd_mode = XGMI_PLPD_NONE;
+}
+
static int smu_sw_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -1120,6 +1212,8 @@ static int smu_sw_init(void *handle)
atomic_set(&smu->smu_power.power_gate.vcn_gated, 1);
atomic_set(&smu->smu_power.power_gate.jpeg_gated, 1);
+ atomic_set(&smu->smu_power.power_gate.vpe_gated, 1);
+ atomic_set(&smu->smu_power.power_gate.umsch_mm_gated, 1);
smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT];
smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT] = 0;
@@ -1229,7 +1323,7 @@ static int smu_smc_hw_setup(struct smu_context *smu)
uint64_t features_supported;
int ret = 0;
- switch (adev->ip_versions[MP1_HWIP][0]) {
+ switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
case IP_VERSION(11, 0, 7):
case IP_VERSION(11, 0, 11):
case IP_VERSION(11, 5, 0):
@@ -1331,6 +1425,8 @@ static int smu_smc_hw_setup(struct smu_context *smu)
return ret;
}
+ smu_init_xgmi_plpd_mode(smu);
+
ret = smu_feature_get_enabled_mask(smu, &features_supported);
if (ret) {
dev_err(adev->dev, "Failed to retrieve supported dpm features!\n");
@@ -1419,7 +1515,7 @@ static int smu_start_smc_engine(struct smu_context *smu)
int ret = 0;
if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) {
- if (adev->ip_versions[MP1_HWIP][0] < IP_VERSION(11, 0, 0)) {
+ if (amdgpu_ip_version(adev, MP1_HWIP, 0) < IP_VERSION(11, 0, 0)) {
if (smu->ppt_funcs->load_microcode) {
ret = smu->ppt_funcs->load_microcode(smu);
if (ret)
@@ -1470,6 +1566,8 @@ static int smu_hw_init(void *handle)
return ret;
smu_dpm_set_vcn_enable(smu, true);
smu_dpm_set_jpeg_enable(smu, true);
+ smu_dpm_set_vpe_enable(smu, true);
+ smu_dpm_set_umsch_mm_enable(smu, true);
smu_set_gfx_cgpg(smu, true);
}
@@ -1519,7 +1617,7 @@ static int smu_disable_dpms(struct smu_context *smu)
* For SMU 13.0.0 and 13.0.7, PMFW will handle the DPM features(disablement or others)
* properly on suspend/reset/unload. Driver involvement may cause some unexpected issues.
*/
- switch (adev->ip_versions[MP1_HWIP][0]) {
+ switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
case IP_VERSION(13, 0, 0):
case IP_VERSION(13, 0, 7):
case IP_VERSION(13, 0, 10):
@@ -1540,7 +1638,7 @@ static int smu_disable_dpms(struct smu_context *smu)
* properly.
*/
if (smu->uploading_custom_pp_table) {
- switch (adev->ip_versions[MP1_HWIP][0]) {
+ switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
case IP_VERSION(11, 0, 0):
case IP_VERSION(11, 0, 5):
case IP_VERSION(11, 0, 9):
@@ -1560,7 +1658,7 @@ static int smu_disable_dpms(struct smu_context *smu)
* on BACO in. Driver involvement is unnecessary.
*/
if (use_baco) {
- switch (adev->ip_versions[MP1_HWIP][0]) {
+ switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
case IP_VERSION(11, 0, 7):
case IP_VERSION(11, 0, 0):
case IP_VERSION(11, 0, 5):
@@ -1573,13 +1671,14 @@ static int smu_disable_dpms(struct smu_context *smu)
}
/*
- * For SMU 13.0.4/11, PMFW will handle the features disablement properly
+ * For SMU 13.0.4/11 and 14.0.0, PMFW will handle the features disablement properly
* for gpu reset and S0i3 cases. Driver involvement is unnecessary.
*/
if (amdgpu_in_reset(adev) || adev->in_s0ix) {
- switch (adev->ip_versions[MP1_HWIP][0]) {
+ switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
case IP_VERSION(13, 0, 4):
case IP_VERSION(13, 0, 11):
+ case IP_VERSION(14, 0, 0):
return 0;
default:
break;
@@ -1604,7 +1703,18 @@ static int smu_disable_dpms(struct smu_context *smu)
}
}
- if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(9, 4, 2) &&
+ /* Notify SMU RLC is going to be off, stop RLC and SMU interaction.
+ * otherwise SMU will hang while interacting with RLC if RLC is halted
+ * this is a WA for Vangogh asic which fix the SMU hang issue.
+ */
+ ret = smu_notify_rlc_state(smu, false);
+ if (ret) {
+ dev_err(adev->dev, "Fail to notify rlc status!\n");
+ return ret;
+ }
+
+ if (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(9, 4, 2) &&
+ !((adev->flags & AMD_IS_APU) && adev->gfx.imu.funcs) &&
!amdgpu_sriov_vf(adev) && adev->gfx.rlc.funcs->stop)
adev->gfx.rlc.funcs->stop(adev);
@@ -1646,6 +1756,8 @@ static int smu_hw_fini(void *handle)
smu_dpm_set_vcn_enable(smu, false);
smu_dpm_set_jpeg_enable(smu, false);
+ smu_dpm_set_vpe_enable(smu, false);
+ smu_dpm_set_umsch_mm_enable(smu, false);
adev->vcn.cur_state = AMD_PG_STATE_GATE;
adev->jpeg.cur_state = AMD_PG_STATE_GATE;
@@ -2131,23 +2243,6 @@ static int smu_set_df_cstate(void *handle,
return ret;
}
-int smu_allow_xgmi_power_down(struct smu_context *smu, bool en)
-{
- int ret = 0;
-
- if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
- return -EOPNOTSUPP;
-
- if (!smu->ppt_funcs || !smu->ppt_funcs->allow_xgmi_power_down)
- return 0;
-
- ret = smu->ppt_funcs->allow_xgmi_power_down(smu, en);
- if (ret)
- dev_err(smu->adev->dev, "[AllowXgmiPowerDown] failed!\n");
-
- return ret;
-}
-
int smu_write_watermarks_table(struct smu_context *smu)
{
if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
@@ -2234,6 +2329,14 @@ const struct amdgpu_ip_block_version smu_v13_0_ip_block = {
.funcs = &smu_ip_funcs,
};
+const struct amdgpu_ip_block_version smu_v14_0_ip_block = {
+ .type = AMD_IP_BLOCK_TYPE_SMC,
+ .major = 14,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &smu_ip_funcs,
+};
+
static int smu_load_microcode(void *handle)
{
struct smu_context *smu = handle;
@@ -2336,7 +2439,6 @@ int smu_get_power_limit(void *handle,
break;
default:
return -EOPNOTSUPP;
- break;
}
switch (pp_limit_level) {
@@ -2350,9 +2452,10 @@ int smu_get_power_limit(void *handle,
limit_level = SMU_PPT_LIMIT_MAX;
break;
case PP_PWR_LIMIT_MIN:
+ limit_level = SMU_PPT_LIMIT_MIN;
+ break;
default:
return -EOPNOTSUPP;
- break;
}
if (limit_type != SMU_DEFAULT_PPT_LIMIT) {
@@ -2361,16 +2464,16 @@ int smu_get_power_limit(void *handle,
} else {
switch (limit_level) {
case SMU_PPT_LIMIT_CURRENT:
- switch (adev->ip_versions[MP1_HWIP][0]) {
+ switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
case IP_VERSION(13, 0, 2):
+ case IP_VERSION(13, 0, 6):
case IP_VERSION(11, 0, 7):
case IP_VERSION(11, 0, 11):
case IP_VERSION(11, 0, 12):
case IP_VERSION(11, 0, 13):
ret = smu_get_asic_power_limits(smu,
&smu->current_power_limit,
- NULL,
- NULL);
+ NULL, NULL, NULL);
break;
default:
break;
@@ -2383,8 +2486,11 @@ int smu_get_power_limit(void *handle,
case SMU_PPT_LIMIT_MAX:
*limit = smu->max_power_limit;
break;
- default:
+ case SMU_PPT_LIMIT_MIN:
+ *limit = smu->min_power_limit;
break;
+ default:
+ return -EINVAL;
}
}
@@ -2405,10 +2511,10 @@ static int smu_set_power_limit(void *handle, uint32_t limit)
if (smu->ppt_funcs->set_power_limit)
return smu->ppt_funcs->set_power_limit(smu, limit_type, limit);
- if (limit > smu->max_power_limit) {
+ if ((limit > smu->max_power_limit) || (limit < smu->min_power_limit)) {
dev_err(smu->adev->dev,
- "New power limit (%d) is over the max allowed %d\n",
- limit, smu->max_power_limit);
+ "New power limit (%d) is out of range [%d,%d]\n",
+ limit, smu->min_power_limit, smu->max_power_limit);
return -EINVAL;
}
@@ -2474,6 +2580,16 @@ static enum smu_clk_type smu_convert_to_smuclk(enum pp_clock_type type)
clk_type = SMU_OD_VDDGFX_OFFSET; break;
case OD_CCLK:
clk_type = SMU_OD_CCLK; break;
+ case OD_FAN_CURVE:
+ clk_type = SMU_OD_FAN_CURVE; break;
+ case OD_ACOUSTIC_LIMIT:
+ clk_type = SMU_OD_ACOUSTIC_LIMIT; break;
+ case OD_ACOUSTIC_TARGET:
+ clk_type = SMU_OD_ACOUSTIC_TARGET; break;
+ case OD_FAN_TARGET_TEMPERATURE:
+ clk_type = SMU_OD_FAN_TARGET_TEMPERATURE; break;
+ case OD_FAN_MINIMUM_PWM:
+ clk_type = SMU_OD_FAN_MINIMUM_PWM; break;
default:
clk_type = SMU_CLK_COUNT; break;
}
@@ -2607,7 +2723,7 @@ unlock:
static int smu_get_apu_thermal_limit(void *handle, uint32_t *limit)
{
- int ret = -EINVAL;
+ int ret = -EOPNOTSUPP;
struct smu_context *smu = handle;
if (smu->ppt_funcs && smu->ppt_funcs->get_apu_thermal_limit)
@@ -2618,7 +2734,7 @@ static int smu_get_apu_thermal_limit(void *handle, uint32_t *limit)
static int smu_set_apu_thermal_limit(void *handle, uint32_t limit)
{
- int ret = -EINVAL;
+ int ret = -EOPNOTSUPP;
struct smu_context *smu = handle;
if (smu->ppt_funcs && smu->ppt_funcs->set_apu_thermal_limit)
@@ -3117,6 +3233,30 @@ static int smu_get_prv_buffer_details(void *handle, void **addr, size_t *size)
return 0;
}
+int smu_set_xgmi_plpd_mode(struct smu_context *smu,
+ enum pp_xgmi_plpd_mode mode)
+{
+ int ret = -EOPNOTSUPP;
+
+ if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
+ return ret;
+
+ /* PLPD policy is not supported if it's NONE */
+ if (smu->plpd_mode == XGMI_PLPD_NONE)
+ return ret;
+
+ if (smu->plpd_mode == mode)
+ return 0;
+
+ if (smu->ppt_funcs && smu->ppt_funcs->select_xgmi_plpd_policy)
+ ret = smu->ppt_funcs->select_xgmi_plpd_policy(smu, mode);
+
+ if (!ret)
+ smu->plpd_mode = mode;
+
+ return ret;
+}
+
static const struct amd_pm_funcs swsmu_pm_funcs = {
/* export for sysfs */
.set_fan_control_mode = smu_set_fan_control_mode,