summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/pm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/pm')
-rw-r--r--drivers/gpu/drm/amd/pm/Makefile1
-rw-r--r--drivers/gpu/drm/amd/pm/amdgpu_dpm.c325
-rw-r--r--drivers/gpu/drm/amd/pm/amdgpu_dpm_internal.c86
-rw-r--r--drivers/gpu/drm/amd/pm/amdgpu_pm.c1365
-rw-r--r--drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h26
-rw-r--r--drivers/gpu/drm/amd/pm/inc/amdgpu_dpm_internal.h6
-rw-r--r--drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c95
-rw-r--r--drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c136
-rw-r--r--drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.h7
-rw-r--r--drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c637
-rw-r--r--drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.h557
-rw-r--r--drivers/gpu/drm/amd/pm/legacy-dpm/si_smc.c82
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c90
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/hardwaremanager.c20
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c15
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c12
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c78
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.h3
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c35
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c28
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c120
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_clockpowergating.c2
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_clockpowergating.h1
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c236
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h1
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_thermal.c4
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c98
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.c101
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.h2
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c164
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c34
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c4
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c70
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c2
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c230
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c2
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_thermal.c2
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/inc/hardwaremanager.h4
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h8
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c32
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/smumgr/fiji_smumgr.c9
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.c11
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/smumgr/polaris10_smumgr.c7
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/smumgr/smu10_smumgr.c6
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.c40
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.h2
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/smumgr/smu8_smumgr.c2
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/smumgr/tonga_smumgr.c9
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/smumgr/vega10_smumgr.c6
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/smumgr/vega12_smumgr.c6
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/smumgr/vega20_smumgr.c10
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/smumgr/vegam_smumgr.c2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/Makefile2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c568
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h655
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu14_driver_if_v14_0_0.h1
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_0.h231
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_8.h295
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_pmfw.h386
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_ppsmc.h146
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h131
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_ppsmc.h6
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_pmfw.h160
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_ppsmc.h133
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_8_pmfw.h427
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_8_ppsmc.h100
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h45
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h71
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h5
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h73
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0_0_pptable.h (renamed from drivers/gpu/drm/amd/pm/inc/smu_v13_0_0_pptable.h)0
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h61
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h228
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c282
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c65
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c625
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c451
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c202
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c195
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c140
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c57
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/Makefile2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c438
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c357
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c590
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c1155
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c106
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c103
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c1570
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h252
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c584
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c85
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c237
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c218
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c702
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu15/Makefile30
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c1757
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c1472
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.h28
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c2421
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.h347
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c1130
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h203
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu_internal.h5
104 files changed, 17479 insertions, 6885 deletions
diff --git a/drivers/gpu/drm/amd/pm/Makefile b/drivers/gpu/drm/amd/pm/Makefile
index ebbf188f625c..a4dde44f7a44 100644
--- a/drivers/gpu/drm/amd/pm/Makefile
+++ b/drivers/gpu/drm/amd/pm/Makefile
@@ -31,6 +31,7 @@ subdir-ccflags-y += \
-I$(FULL_AMD_PATH)/pm/swsmu/smu12 \
-I$(FULL_AMD_PATH)/pm/swsmu/smu13 \
-I$(FULL_AMD_PATH)/pm/swsmu/smu14 \
+ -I$(FULL_AMD_PATH)/pm/swsmu/smu15 \
-I$(FULL_AMD_PATH)/pm/powerplay/inc \
-I$(FULL_AMD_PATH)/pm/powerplay/smumgr\
-I$(FULL_AMD_PATH)/pm/powerplay/hwmgr \
diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
index 7a22aef6e59c..f76ba6753551 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
@@ -33,8 +33,8 @@
#include <linux/power_supply.h>
#include "amdgpu_smu.h"
-#define amdgpu_dpm_enable_bapm(adev, e) \
- ((adev)->powerplay.pp_funcs->enable_bapm((adev)->powerplay.pp_handle, (e)))
+#define amdgpu_dpm_notify_ac_dc(adev) \
+ ((adev)->powerplay.pp_funcs->notify_ac_dc((adev)->powerplay.pp_handle))
#define amdgpu_dpm_is_legacy_dpm(adev) ((adev)->powerplay.pp_handle == (adev))
@@ -80,15 +80,15 @@ int amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev,
enum ip_power_state pwr_state = gate ? POWER_STATE_OFF : POWER_STATE_ON;
bool is_vcn = block_type == AMD_IP_BLOCK_TYPE_VCN;
+ mutex_lock(&adev->pm.mutex);
+
if (atomic_read(&adev->pm.pwr_state[block_type]) == pwr_state &&
(!is_vcn || adev->vcn.num_vcn_inst == 1)) {
dev_dbg(adev->dev, "IP block%d already in the target %s state!",
block_type, gate ? "gate" : "ungate");
- return 0;
+ goto out_unlock;
}
- mutex_lock(&adev->pm.mutex);
-
switch (block_type) {
case AMD_IP_BLOCK_TYPE_UVD:
case AMD_IP_BLOCK_TYPE_VCE:
@@ -98,6 +98,7 @@ int amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev,
case AMD_IP_BLOCK_TYPE_GMC:
case AMD_IP_BLOCK_TYPE_ACP:
case AMD_IP_BLOCK_TYPE_VPE:
+ case AMD_IP_BLOCK_TYPE_ISP:
if (pp_funcs && pp_funcs->set_powergating_by_smu)
ret = (pp_funcs->set_powergating_by_smu(
(adev)->powerplay.pp_handle, block_type, gate, 0));
@@ -114,6 +115,7 @@ int amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev,
if (!ret)
atomic_set(&adev->pm.pwr_state[block_type], pwr_state);
+out_unlock:
mutex_unlock(&adev->pm.mutex);
return ret;
@@ -194,24 +196,6 @@ int amdgpu_dpm_set_mp1_state(struct amdgpu_device *adev,
return ret;
}
-int amdgpu_dpm_notify_rlc_state(struct amdgpu_device *adev, bool en)
-{
- int ret = 0;
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
-
- if (pp_funcs && pp_funcs->notify_rlc_state) {
- mutex_lock(&adev->pm.mutex);
-
- ret = pp_funcs->notify_rlc_state(
- adev->powerplay.pp_handle,
- en);
-
- mutex_unlock(&adev->pm.mutex);
- }
-
- return ret;
-}
-
int amdgpu_dpm_is_baco_supported(struct amdgpu_device *adev)
{
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
@@ -329,6 +313,34 @@ int amdgpu_dpm_mode1_reset(struct amdgpu_device *adev)
return ret;
}
+bool amdgpu_dpm_is_link_reset_supported(struct amdgpu_device *adev)
+{
+ struct smu_context *smu = adev->powerplay.pp_handle;
+ bool support_link_reset = false;
+
+ if (is_support_sw_smu(adev)) {
+ mutex_lock(&adev->pm.mutex);
+ support_link_reset = smu_link_reset_is_support(smu);
+ mutex_unlock(&adev->pm.mutex);
+ }
+
+ return support_link_reset;
+}
+
+int amdgpu_dpm_link_reset(struct amdgpu_device *adev)
+{
+ struct smu_context *smu = adev->powerplay.pp_handle;
+ int ret = -EOPNOTSUPP;
+
+ if (is_support_sw_smu(adev)) {
+ mutex_lock(&adev->pm.mutex);
+ ret = smu_link_reset(smu);
+ mutex_unlock(&adev->pm.mutex);
+ }
+
+ return ret;
+}
+
int amdgpu_dpm_switch_power_profile(struct amdgpu_device *adev,
enum PP_SMC_POWER_PROFILE type,
bool en)
@@ -349,6 +361,25 @@ int amdgpu_dpm_switch_power_profile(struct amdgpu_device *adev,
return ret;
}
+int amdgpu_dpm_pause_power_profile(struct amdgpu_device *adev,
+ bool pause)
+{
+ const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
+ int ret = 0;
+
+ if (amdgpu_sriov_vf(adev))
+ return 0;
+
+ if (pp_funcs && pp_funcs->pause_power_profile) {
+ mutex_lock(&adev->pm.mutex);
+ ret = pp_funcs->pause_power_profile(
+ adev->powerplay.pp_handle, pause);
+ mutex_unlock(&adev->pm.mutex);
+ }
+
+ return ret;
+}
+
int amdgpu_dpm_set_xgmi_pstate(struct amdgpu_device *adev,
uint32_t pstate)
{
@@ -473,8 +504,8 @@ void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev)
adev->pm.ac_power = false;
if (adev->powerplay.pp_funcs &&
- adev->powerplay.pp_funcs->enable_bapm)
- amdgpu_dpm_enable_bapm(adev, adev->pm.ac_power);
+ adev->powerplay.pp_funcs->notify_ac_dc)
+ amdgpu_dpm_notify_ac_dc(adev);
if (is_support_sw_smu(adev))
smu_set_ac_dc(adev->powerplay.pp_handle);
@@ -577,8 +608,8 @@ void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable)
ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_UVD, !enable, 0);
if (ret)
- DRM_ERROR("Dpm %s uvd failed, ret = %d. \n",
- enable ? "enable" : "disable", ret);
+ drm_err(adev_to_drm(adev), "DPM %s uvd failed, ret = %d.\n",
+ enable ? "enable" : "disable", ret);
}
void amdgpu_dpm_enable_vcn(struct amdgpu_device *adev, bool enable, int inst)
@@ -587,8 +618,8 @@ void amdgpu_dpm_enable_vcn(struct amdgpu_device *adev, bool enable, int inst)
ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_VCN, !enable, inst);
if (ret)
- DRM_ERROR("Dpm %s uvd failed, ret = %d. \n",
- enable ? "enable" : "disable", ret);
+ drm_err(adev_to_drm(adev), "DPM %s vcn failed, ret = %d.\n",
+ enable ? "enable" : "disable", ret);
}
void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable)
@@ -612,8 +643,8 @@ void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable)
ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_VCE, !enable, 0);
if (ret)
- DRM_ERROR("Dpm %s vce failed, ret = %d. \n",
- enable ? "enable" : "disable", ret);
+ drm_err(adev_to_drm(adev), "DPM %s vce failed, ret = %d.\n",
+ enable ? "enable" : "disable", ret);
}
void amdgpu_dpm_enable_jpeg(struct amdgpu_device *adev, bool enable)
@@ -622,8 +653,8 @@ void amdgpu_dpm_enable_jpeg(struct amdgpu_device *adev, bool enable)
ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_JPEG, !enable, 0);
if (ret)
- DRM_ERROR("Dpm %s jpeg failed, ret = %d. \n",
- enable ? "enable" : "disable", ret);
+ drm_err(adev_to_drm(adev), "Dpm %s jpeg failed, ret = %d.\n",
+ enable ? "enable" : "disable", ret);
}
void amdgpu_dpm_enable_vpe(struct amdgpu_device *adev, bool enable)
@@ -632,8 +663,8 @@ void amdgpu_dpm_enable_vpe(struct amdgpu_device *adev, bool enable)
ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_VPE, !enable, 0);
if (ret)
- DRM_ERROR("Dpm %s vpe failed, ret = %d.\n",
- enable ? "enable" : "disable", ret);
+ drm_err(adev_to_drm(adev), "DPM %s vpe failed, ret = %d.\n",
+ enable ? "enable" : "disable", ret);
}
int amdgpu_pm_load_smu_firmware(struct amdgpu_device *adev, uint32_t *smu_version)
@@ -719,6 +750,29 @@ int amdgpu_dpm_send_rma_reason(struct amdgpu_device *adev)
return ret;
}
+/**
+ * amdgpu_dpm_reset_sdma_is_supported - Check if SDMA reset is supported
+ * @adev: amdgpu_device pointer
+ *
+ * This function checks if the SMU supports resetting the SDMA engine.
+ * It returns false if the hardware does not support software SMU or
+ * if the feature is not supported.
+ */
+bool amdgpu_dpm_reset_sdma_is_supported(struct amdgpu_device *adev)
+{
+ struct smu_context *smu = adev->powerplay.pp_handle;
+ bool ret;
+
+ if (!is_support_sw_smu(adev))
+ return false;
+
+ mutex_lock(&adev->pm.mutex);
+ ret = smu_reset_sdma_is_supported(smu);
+ mutex_unlock(&adev->pm.mutex);
+
+ return ret;
+}
+
int amdgpu_dpm_reset_sdma(struct amdgpu_device *adev, uint32_t inst_mask)
{
struct smu_context *smu = adev->powerplay.pp_handle;
@@ -734,6 +788,36 @@ int amdgpu_dpm_reset_sdma(struct amdgpu_device *adev, uint32_t inst_mask)
return ret;
}
+int amdgpu_dpm_reset_vcn(struct amdgpu_device *adev, uint32_t inst_mask)
+{
+ struct smu_context *smu = adev->powerplay.pp_handle;
+ int ret;
+
+ if (!is_support_sw_smu(adev))
+ return -EOPNOTSUPP;
+
+ mutex_lock(&adev->pm.mutex);
+ ret = smu_reset_vcn(smu, inst_mask);
+ mutex_unlock(&adev->pm.mutex);
+
+ return ret;
+}
+
+bool amdgpu_dpm_reset_vcn_is_supported(struct amdgpu_device *adev)
+{
+ struct smu_context *smu = adev->powerplay.pp_handle;
+ bool ret;
+
+ if (!is_support_sw_smu(adev))
+ return false;
+
+ mutex_lock(&adev->pm.mutex);
+ ret = smu_reset_vcn_is_supported(smu);
+ mutex_unlock(&adev->pm.mutex);
+
+ return ret;
+}
+
int amdgpu_dpm_get_dpm_freq_range(struct amdgpu_device *adev,
enum pp_clock_type type,
uint32_t *min,
@@ -763,22 +847,16 @@ int amdgpu_dpm_set_soft_freq_range(struct amdgpu_device *adev,
uint32_t max)
{
struct smu_context *smu = adev->powerplay.pp_handle;
- int ret = 0;
-
- if (type != PP_SCLK)
- return -EINVAL;
if (!is_support_sw_smu(adev))
return -EOPNOTSUPP;
- mutex_lock(&adev->pm.mutex);
- ret = smu_set_soft_freq_range(smu,
- SMU_SCLK,
+ guard(mutex)(&adev->pm.mutex);
+
+ return smu_set_soft_freq_range(smu,
+ type,
min,
max);
- mutex_unlock(&adev->pm.mutex);
-
- return ret;
}
int amdgpu_dpm_write_watermarks_table(struct amdgpu_device *adev)
@@ -1110,8 +1188,11 @@ int amdgpu_dpm_get_pp_table(struct amdgpu_device *adev, char **table)
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
int ret = 0;
- if (!pp_funcs->get_pp_table)
- return 0;
+ if (!table)
+ return -EINVAL;
+
+ if (amdgpu_sriov_vf(adev) || !pp_funcs->get_pp_table || adev->scpm_enabled)
+ return -EOPNOTSUPP;
mutex_lock(&adev->pm.mutex);
ret = pp_funcs->get_pp_table(adev->powerplay.pp_handle,
@@ -1163,25 +1244,6 @@ int amdgpu_dpm_odn_edit_dpm_table(struct amdgpu_device *adev,
return ret;
}
-int amdgpu_dpm_print_clock_levels(struct amdgpu_device *adev,
- enum pp_clock_type type,
- char *buf)
-{
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
- int ret = 0;
-
- if (!pp_funcs->print_clock_levels)
- return 0;
-
- mutex_lock(&adev->pm.mutex);
- ret = pp_funcs->print_clock_levels(adev->powerplay.pp_handle,
- type,
- buf);
- mutex_unlock(&adev->pm.mutex);
-
- return ret;
-}
-
int amdgpu_dpm_emit_clock_levels(struct amdgpu_device *adev,
enum pp_clock_type type,
char *buf,
@@ -1508,7 +1570,7 @@ int amdgpu_dpm_get_power_limit(struct amdgpu_device *adev,
int ret = 0;
if (!pp_funcs->get_power_limit)
- return -ENODATA;
+ return -EOPNOTSUPP;
mutex_lock(&adev->pm.mutex);
ret = pp_funcs->get_power_limit(adev->powerplay.pp_handle,
@@ -1521,6 +1583,7 @@ int amdgpu_dpm_get_power_limit(struct amdgpu_device *adev,
}
int amdgpu_dpm_set_power_limit(struct amdgpu_device *adev,
+ uint32_t limit_type,
uint32_t limit)
{
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
@@ -1531,7 +1594,7 @@ int amdgpu_dpm_set_power_limit(struct amdgpu_device *adev,
mutex_lock(&adev->pm.mutex);
ret = pp_funcs->set_power_limit(adev->powerplay.pp_handle,
- limit);
+ limit_type, limit);
mutex_unlock(&adev->pm.mutex);
return ret;
@@ -1608,6 +1671,28 @@ int amdgpu_dpm_is_overdrive_supported(struct amdgpu_device *adev)
}
}
+int amdgpu_dpm_is_overdrive_enabled(struct amdgpu_device *adev)
+{
+ if (is_support_sw_smu(adev)) {
+ struct smu_context *smu = adev->powerplay.pp_handle;
+
+ return smu->od_enabled;
+ } else {
+ struct pp_hwmgr *hwmgr;
+
+ /*
+ * dpm on some legacy asics don't carry od_enabled member
+ * as its pp_handle is casted directly from adev.
+ */
+ if (amdgpu_dpm_is_legacy_dpm(adev))
+ return false;
+
+ hwmgr = (struct pp_hwmgr *)adev->powerplay.pp_handle;
+
+ return hwmgr->od_enabled;
+ }
+}
+
int amdgpu_dpm_set_pp_table(struct amdgpu_device *adev,
const char *buf,
size_t size)
@@ -1615,7 +1700,10 @@ int amdgpu_dpm_set_pp_table(struct amdgpu_device *adev,
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
int ret = 0;
- if (!pp_funcs->set_pp_table)
+ if (!buf || !size)
+ return -EINVAL;
+
+ if (amdgpu_sriov_vf(adev) || !pp_funcs->set_pp_table || adev->scpm_enabled)
return -EOPNOTSUPP;
mutex_lock(&adev->pm.mutex);
@@ -1930,3 +2018,102 @@ int amdgpu_dpm_get_dpm_clock_table(struct amdgpu_device *adev,
return ret;
}
+
+/**
+ * amdgpu_dpm_get_temp_metrics - Retrieve metrics for a specific compute
+ * partition
+ * @adev: Pointer to the device.
+ * @type: Identifier for the temperature type metrics to be fetched.
+ * @table: Pointer to a buffer where the metrics will be stored. If NULL, the
+ * function returns the size of the metrics structure.
+ *
+ * This function retrieves metrics for a specific temperature type, If the
+ * table parameter is NULL, the function returns the size of the metrics
+ * structure without populating it.
+ *
+ * Return: Size of the metrics structure on success, or a negative error code on failure.
+ */
+ssize_t amdgpu_dpm_get_temp_metrics(struct amdgpu_device *adev,
+ enum smu_temp_metric_type type, void *table)
+{
+ const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
+ int ret;
+
+ if (!pp_funcs->get_temp_metrics ||
+ !amdgpu_dpm_is_temp_metrics_supported(adev, type))
+ return -EOPNOTSUPP;
+
+ mutex_lock(&adev->pm.mutex);
+ ret = pp_funcs->get_temp_metrics(adev->powerplay.pp_handle, type, table);
+ mutex_unlock(&adev->pm.mutex);
+
+ return ret;
+}
+
+/**
+ * amdgpu_dpm_is_temp_metrics_supported - Return if specific temperature metrics support
+ * is available
+ * @adev: Pointer to the device.
+ * @type: Identifier for the temperature type metrics to be fetched.
+ *
+ * This function returns metrics if specific temperature metrics type is supported or not.
+ *
+ * Return: True in case of metrics type supported else false.
+ */
+bool amdgpu_dpm_is_temp_metrics_supported(struct amdgpu_device *adev,
+ enum smu_temp_metric_type type)
+{
+ const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
+ bool support_temp_metrics = false;
+
+ if (!pp_funcs->temp_metrics_is_supported)
+ return support_temp_metrics;
+
+ if (is_support_sw_smu(adev)) {
+ mutex_lock(&adev->pm.mutex);
+ support_temp_metrics =
+ pp_funcs->temp_metrics_is_supported(adev->powerplay.pp_handle, type);
+ mutex_unlock(&adev->pm.mutex);
+ }
+
+ return support_temp_metrics;
+}
+
+/**
+ * amdgpu_dpm_get_xcp_metrics - Retrieve metrics for a specific compute
+ * partition
+ * @adev: Pointer to the device.
+ * @xcp_id: Identifier of the XCP for which metrics are to be retrieved.
+ * @table: Pointer to a buffer where the metrics will be stored. If NULL, the
+ * function returns the size of the metrics structure.
+ *
+ * This function retrieves metrics for a specific XCP, including details such as
+ * VCN/JPEG activity, clock frequencies, and other performance metrics. If the
+ * table parameter is NULL, the function returns the size of the metrics
+ * structure without populating it.
+ *
+ * Return: Size of the metrics structure on success, or a negative error code on failure.
+ */
+ssize_t amdgpu_dpm_get_xcp_metrics(struct amdgpu_device *adev, int xcp_id,
+ void *table)
+{
+ const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
+ int ret = 0;
+
+ if (!pp_funcs->get_xcp_metrics)
+ return 0;
+
+ mutex_lock(&adev->pm.mutex);
+ ret = pp_funcs->get_xcp_metrics(adev->powerplay.pp_handle, xcp_id,
+ table);
+ mutex_unlock(&adev->pm.mutex);
+
+ return ret;
+}
+
+const struct ras_smu_drv *amdgpu_dpm_get_ras_smu_driver(struct amdgpu_device *adev)
+{
+ void *pp_handle = adev->powerplay.pp_handle;
+
+ return smu_get_ras_smu_driver(pp_handle);
+}
diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm_internal.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm_internal.c
index 42efe838fa85..b5e9c3ecf703 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_dpm_internal.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm_internal.c
@@ -27,69 +27,69 @@
#include "amdgpu_smu.h"
#include "amdgpu_dpm_internal.h"
-void amdgpu_dpm_get_active_displays(struct amdgpu_device *adev)
+void amdgpu_dpm_get_display_cfg(struct amdgpu_device *adev)
{
struct drm_device *ddev = adev_to_drm(adev);
+ struct amd_pp_display_configuration *cfg = &adev->pm.pm_display_cfg;
+ struct single_display_configuration *display_cfg;
struct drm_crtc *crtc;
struct amdgpu_crtc *amdgpu_crtc;
+ struct amdgpu_connector *conn;
+ int num_crtcs = 0;
+ int vrefresh;
+ u32 vblank_in_pixels, vblank_time_us;
+
+ cfg->min_vblank_time = 0xffffffff; /* if the displays are off, vblank time is max */
- adev->pm.dpm.new_active_crtcs = 0;
- adev->pm.dpm.new_active_crtc_count = 0;
if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) {
- list_for_each_entry(crtc,
- &ddev->mode_config.crtc_list, head) {
+ list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) {
amdgpu_crtc = to_amdgpu_crtc(crtc);
- if (amdgpu_crtc->enabled) {
- adev->pm.dpm.new_active_crtcs |= (1 << amdgpu_crtc->crtc_id);
- adev->pm.dpm.new_active_crtc_count++;
- }
- }
- }
-}
-u32 amdgpu_dpm_get_vblank_time(struct amdgpu_device *adev)
-{
- struct drm_device *dev = adev_to_drm(adev);
- struct drm_crtc *crtc;
- struct amdgpu_crtc *amdgpu_crtc;
- u32 vblank_in_pixels;
- u32 vblank_time_us = 0xffffffff; /* if the displays are off, vblank time is max */
+ /* The array should only contain active displays. */
+ if (!amdgpu_crtc->enabled)
+ continue;
+
+ conn = to_amdgpu_connector(amdgpu_crtc->connector);
+ display_cfg = &adev->pm.pm_display_cfg.displays[num_crtcs++];
+
+ if (amdgpu_crtc->hw_mode.clock) {
+ vrefresh = drm_mode_vrefresh(&amdgpu_crtc->hw_mode);
- if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) {
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- amdgpu_crtc = to_amdgpu_crtc(crtc);
- if (crtc->enabled && amdgpu_crtc->enabled && amdgpu_crtc->hw_mode.clock) {
vblank_in_pixels =
amdgpu_crtc->hw_mode.crtc_htotal *
(amdgpu_crtc->hw_mode.crtc_vblank_end -
amdgpu_crtc->hw_mode.crtc_vdisplay +
(amdgpu_crtc->v_border * 2));
- vblank_time_us = vblank_in_pixels * 1000 / amdgpu_crtc->hw_mode.clock;
- break;
- }
- }
- }
+ vblank_time_us =
+ vblank_in_pixels * 1000 / amdgpu_crtc->hw_mode.clock;
- return vblank_time_us;
-}
+ /* The legacy (non-DC) code has issues with mclk switching
+ * with refresh rates over 120 Hz. Disable mclk switching.
+ */
+ if (vrefresh > 120)
+ vblank_time_us = 0;
-u32 amdgpu_dpm_get_vrefresh(struct amdgpu_device *adev)
-{
- struct drm_device *dev = adev_to_drm(adev);
- struct drm_crtc *crtc;
- struct amdgpu_crtc *amdgpu_crtc;
- u32 vrefresh = 0;
+ /* Find minimum vblank time. */
+ if (vblank_time_us < cfg->min_vblank_time)
+ cfg->min_vblank_time = vblank_time_us;
- if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) {
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- amdgpu_crtc = to_amdgpu_crtc(crtc);
- if (crtc->enabled && amdgpu_crtc->enabled && amdgpu_crtc->hw_mode.clock) {
- vrefresh = drm_mode_vrefresh(&amdgpu_crtc->hw_mode);
- break;
+ /* Find vertical refresh rate of first active display. */
+ if (!cfg->vrefresh)
+ cfg->vrefresh = vrefresh;
}
+
+ if (amdgpu_crtc->crtc_id < cfg->crtc_index) {
+ /* Find first active CRTC and its line time. */
+ cfg->crtc_index = amdgpu_crtc->crtc_id;
+ cfg->line_time_in_us = amdgpu_crtc->line_time;
+ }
+
+ display_cfg->controller_id = amdgpu_crtc->crtc_id;
+ display_cfg->pixel_clock = conn->pixelclock_for_modeset;
}
}
- return vrefresh;
+ cfg->display_clk = adev->clock.default_dispclk;
+ cfg->num_display = num_crtcs;
}
diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
index 77b1f061bbf0..97da01aff76c 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
@@ -33,6 +33,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/nospec.h>
#include <linux/pm_runtime.h>
+#include <linux/string_choices.h>
#include <asm/processor.h>
#define MAX_NUM_OF_FEATURES_PER_SUBSET 8
@@ -40,6 +41,8 @@
#define DEVICE_ATTR_IS(_name) (attr_id == device_attr_id__##_name)
+#define power_2_mwatt(power) (((power) >> 8) * 1000 + ((power) & 0xff))
+
struct od_attribute {
struct kobj_attribute attribute;
struct list_head entry;
@@ -98,6 +101,86 @@ const char * const amdgpu_pp_profile_name[] = {
};
/**
+ * amdgpu_pm_dev_state_check - Check if device can be accessed.
+ * @adev: Target device.
+ * @runpm: Check runpm status for suspend state checks.
+ *
+ * Checks the state of the @adev for access. Return 0 if the device is
+ * accessible or a negative error code otherwise.
+ */
+static int amdgpu_pm_dev_state_check(struct amdgpu_device *adev, bool runpm)
+{
+ bool runpm_check = runpm ? adev->in_runpm : false;
+ bool full_init = (adev->init_lvl->level == AMDGPU_INIT_LEVEL_DEFAULT);
+
+ if (amdgpu_in_reset(adev) || !full_init)
+ return -EBUSY;
+
+ if (adev->in_suspend && !runpm_check)
+ return -EBUSY;
+
+ return 0;
+}
+
+/**
+ * amdgpu_pm_get_access - Check if device can be accessed, resume if needed.
+ * @adev: Target device.
+ *
+ * Checks the state of the @adev for access. Use runtime pm API to resume if
+ * needed. Return 0 if the device is accessible or a negative error code
+ * otherwise.
+ */
+static int amdgpu_pm_get_access(struct amdgpu_device *adev)
+{
+ int ret;
+
+ ret = amdgpu_pm_dev_state_check(adev, true);
+ if (ret)
+ return ret;
+
+ return pm_runtime_resume_and_get(adev->dev);
+}
+
+/**
+ * amdgpu_pm_get_access_if_active - Check if device is active for access.
+ * @adev: Target device.
+ *
+ * Checks the state of the @adev for access. Use runtime pm API to determine
+ * if device is active. Allow access only if device is active.Return 0 if the
+ * device is accessible or a negative error code otherwise.
+ */
+static int amdgpu_pm_get_access_if_active(struct amdgpu_device *adev)
+{
+ int ret;
+
+ /* Ignore runpm status. If device is in suspended state, deny access */
+ ret = amdgpu_pm_dev_state_check(adev, false);
+ if (ret)
+ return ret;
+
+ /*
+ * Allow only if device is active. If runpm is disabled also, as in
+ * kernels without CONFIG_PM, allow access.
+ */
+ ret = pm_runtime_get_if_active(adev->dev);
+ if (!ret)
+ return -EPERM;
+
+ return 0;
+}
+
+/**
+ * amdgpu_pm_put_access - Put to auto suspend mode after a device access.
+ * @adev: Target device.
+ *
+ * Should be paired with amdgpu_pm_get_access* calls
+ */
+static inline void amdgpu_pm_put_access(struct amdgpu_device *adev)
+{
+ pm_runtime_put_autosuspend(adev->dev);
+}
+
+/**
* DOC: power_dpm_state
*
* The power_dpm_state file is a legacy interface and is only provided for
@@ -140,18 +223,13 @@ static ssize_t amdgpu_get_power_dpm_state(struct device *dev,
enum amd_pm_state_type pm;
int ret;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- ret = pm_runtime_get_if_active(ddev->dev);
- if (ret <= 0)
- return ret ?: -EPERM;
+ ret = amdgpu_pm_get_access_if_active(adev);
+ if (ret)
+ return ret;
amdgpu_dpm_get_current_power_state(adev, &pm);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
return sysfs_emit(buf, "%s\n",
(pm == POWER_STATE_TYPE_BATTERY) ? "battery" :
@@ -168,28 +246,26 @@ static ssize_t amdgpu_set_power_dpm_state(struct device *dev,
enum amd_pm_state_type state;
int ret;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
+ /* Reject empty/whitespace strings - fuzzing found this is not validated */
+ if (count == 0 || sysfs_streq(buf, ""))
+ return -EINVAL;
- if (strncmp("battery", buf, strlen("battery")) == 0)
+ if (sysfs_streq(buf, "battery"))
state = POWER_STATE_TYPE_BATTERY;
- else if (strncmp("balanced", buf, strlen("balanced")) == 0)
+ else if (sysfs_streq(buf, "balanced"))
state = POWER_STATE_TYPE_BALANCED;
- else if (strncmp("performance", buf, strlen("performance")) == 0)
+ else if (sysfs_streq(buf, "performance"))
state = POWER_STATE_TYPE_PERFORMANCE;
else
return -EINVAL;
- ret = pm_runtime_resume_and_get(ddev->dev);
+ ret = amdgpu_pm_get_access(adev);
if (ret < 0)
return ret;
amdgpu_dpm_set_power_state(adev, state);
- pm_runtime_mark_last_busy(ddev->dev);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
return count;
}
@@ -263,18 +339,13 @@ static ssize_t amdgpu_get_power_dpm_force_performance_level(struct device *dev,
enum amd_dpm_forced_level level = 0xff;
int ret;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- ret = pm_runtime_get_if_active(ddev->dev);
- if (ret <= 0)
- return ret ?: -EPERM;
+ ret = amdgpu_pm_get_access_if_active(adev);
+ if (ret)
+ return ret;
level = amdgpu_dpm_get_performance_level(adev);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
return sysfs_emit(buf, "%s\n",
(level == AMD_DPM_FORCED_LEVEL_AUTO) ? "auto" :
@@ -299,43 +370,40 @@ static ssize_t amdgpu_set_power_dpm_force_performance_level(struct device *dev,
enum amd_dpm_forced_level level;
int ret = 0;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
+ /* Reject empty/whitespace strings - fuzzing found this is not validated */
+ if (count == 0 || sysfs_streq(buf, ""))
+ return -EINVAL;
- if (strncmp("low", buf, strlen("low")) == 0) {
+ if (sysfs_streq(buf, "low"))
level = AMD_DPM_FORCED_LEVEL_LOW;
- } else if (strncmp("high", buf, strlen("high")) == 0) {
+ else if (sysfs_streq(buf, "high"))
level = AMD_DPM_FORCED_LEVEL_HIGH;
- } else if (strncmp("auto", buf, strlen("auto")) == 0) {
+ else if (sysfs_streq(buf, "auto"))
level = AMD_DPM_FORCED_LEVEL_AUTO;
- } else if (strncmp("manual", buf, strlen("manual")) == 0) {
+ else if (sysfs_streq(buf, "manual"))
level = AMD_DPM_FORCED_LEVEL_MANUAL;
- } else if (strncmp("profile_exit", buf, strlen("profile_exit")) == 0) {
+ else if (sysfs_streq(buf, "profile_exit"))
level = AMD_DPM_FORCED_LEVEL_PROFILE_EXIT;
- } else if (strncmp("profile_standard", buf, strlen("profile_standard")) == 0) {
+ else if (sysfs_streq(buf, "profile_standard"))
level = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD;
- } else if (strncmp("profile_min_sclk", buf, strlen("profile_min_sclk")) == 0) {
+ else if (sysfs_streq(buf, "profile_min_sclk"))
level = AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK;
- } else if (strncmp("profile_min_mclk", buf, strlen("profile_min_mclk")) == 0) {
+ else if (sysfs_streq(buf, "profile_min_mclk"))
level = AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK;
- } else if (strncmp("profile_peak", buf, strlen("profile_peak")) == 0) {
+ else if (sysfs_streq(buf, "profile_peak"))
level = AMD_DPM_FORCED_LEVEL_PROFILE_PEAK;
- } else if (strncmp("perf_determinism", buf, strlen("perf_determinism")) == 0) {
+ else if (sysfs_streq(buf, "perf_determinism"))
level = AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM;
- } else {
+ else
return -EINVAL;
- }
- ret = pm_runtime_resume_and_get(ddev->dev);
+ ret = amdgpu_pm_get_access(adev);
if (ret < 0)
return ret;
mutex_lock(&adev->pm.stable_pstate_ctx_lock);
if (amdgpu_dpm_force_performance_level(adev, level)) {
- pm_runtime_mark_last_busy(ddev->dev);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
mutex_unlock(&adev->pm.stable_pstate_ctx_lock);
return -EINVAL;
}
@@ -343,8 +411,7 @@ static ssize_t amdgpu_set_power_dpm_force_performance_level(struct device *dev,
adev->pm.stable_pstate_ctx = NULL;
mutex_unlock(&adev->pm.stable_pstate_ctx_lock);
- pm_runtime_mark_last_busy(ddev->dev);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
return count;
}
@@ -359,19 +426,14 @@ static ssize_t amdgpu_get_pp_num_states(struct device *dev,
uint32_t i;
int buf_len, ret;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- ret = pm_runtime_get_if_active(ddev->dev);
- if (ret <= 0)
- return ret ?: -EPERM;
+ ret = amdgpu_pm_get_access_if_active(adev);
+ if (ret)
+ return ret;
if (amdgpu_dpm_get_pp_num_states(adev, &data))
memset(&data, 0, sizeof(data));
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
buf_len = sysfs_emit(buf, "states: %d\n", data.nums);
for (i = 0; i < data.nums; i++)
@@ -394,20 +456,15 @@ static ssize_t amdgpu_get_pp_cur_state(struct device *dev,
enum amd_pm_state_type pm = 0;
int i = 0, ret = 0;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- ret = pm_runtime_get_if_active(ddev->dev);
- if (ret <= 0)
- return ret ?: -EPERM;
+ ret = amdgpu_pm_get_access_if_active(adev);
+ if (ret)
+ return ret;
amdgpu_dpm_get_current_power_state(adev, &pm);
ret = amdgpu_dpm_get_pp_num_states(adev, &data);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
if (ret)
return ret;
@@ -430,11 +487,6 @@ static ssize_t amdgpu_get_pp_force_state(struct device *dev,
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = drm_to_adev(ddev);
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
if (adev->pm.pp_force_state_enabled)
return amdgpu_get_pp_cur_state(dev, attr, buf);
else
@@ -453,11 +505,6 @@ static ssize_t amdgpu_set_pp_force_state(struct device *dev,
unsigned long idx;
int ret;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
adev->pm.pp_force_state_enabled = false;
if (strlen(buf) == 1)
@@ -469,7 +516,7 @@ static ssize_t amdgpu_set_pp_force_state(struct device *dev,
idx = array_index_nospec(idx, ARRAY_SIZE(data.states));
- ret = pm_runtime_resume_and_get(ddev->dev);
+ ret = amdgpu_pm_get_access(adev);
if (ret < 0)
return ret;
@@ -490,14 +537,13 @@ static ssize_t amdgpu_set_pp_force_state(struct device *dev,
adev->pm.pp_force_state_enabled = true;
}
- pm_runtime_mark_last_busy(ddev->dev);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
return count;
err_out:
- pm_runtime_mark_last_busy(ddev->dev);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
+
return ret;
}
@@ -521,18 +567,13 @@ static ssize_t amdgpu_get_pp_table(struct device *dev,
char *table = NULL;
int size, ret;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- ret = pm_runtime_get_if_active(ddev->dev);
- if (ret <= 0)
- return ret ?: -EPERM;
+ ret = amdgpu_pm_get_access_if_active(adev);
+ if (ret)
+ return ret;
size = amdgpu_dpm_get_pp_table(adev, &table);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
if (size <= 0)
return size;
@@ -554,19 +595,13 @@ static ssize_t amdgpu_set_pp_table(struct device *dev,
struct amdgpu_device *adev = drm_to_adev(ddev);
int ret = 0;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- ret = pm_runtime_resume_and_get(ddev->dev);
+ ret = amdgpu_pm_get_access(adev);
if (ret < 0)
return ret;
ret = amdgpu_dpm_set_pp_table(adev, buf, count);
- pm_runtime_mark_last_busy(ddev->dev);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
if (ret)
return ret;
@@ -656,6 +691,8 @@ static ssize_t amdgpu_set_pp_table(struct device *dev,
* - minimum(not available for Vega20 and Navi1x) and maximum memory
* clock labeled OD_MCLK
*
+ * - minimum and maximum fabric clock labeled OD_FCLK (SMU13)
+ *
* - three <frequency, voltage> points labeled OD_VDDC_CURVE.
* They can be used to calibrate the sclk voltage curve. This is
* available for Vega20 and NV1X.
@@ -691,10 +728,11 @@ static ssize_t amdgpu_set_pp_table(struct device *dev,
* - First select manual using power_dpm_force_performance_level
*
* - For clock frequency setting, enter a new value by writing a
- * string that contains "s/m index clock" to the file. The index
+ * string that contains "s/m/f index clock" to the file. The index
* should be 0 if to set minimum clock. And 1 if to set maximum
* clock. E.g., "s 0 500" will update minimum sclk to be 500 MHz.
- * "m 1 800" will update maximum mclk to be 800Mhz. For core
+ * "m 1 800" will update maximum mclk to be 800Mhz. "f 1 1600" will
+ * update maximum fabric clock to be 1600Mhz. For core
* clocks on VanGogh, the string contains "p core index clock".
* E.g., "p 2 0 800" would set the minimum core clock on core
* 2 to 800Mhz.
@@ -735,11 +773,6 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev,
const char delimiter[3] = {' ', '\n', '\0'};
uint32_t type;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
if (count > 127 || count == 0)
return -EINVAL;
@@ -749,6 +782,8 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev,
type = PP_OD_EDIT_CCLK_VDDC_TABLE;
else if (*buf == 'm')
type = PP_OD_EDIT_MCLK_VDDC_TABLE;
+ else if (*buf == 'f')
+ type = PP_OD_EDIT_FCLK_TABLE;
else if (*buf == 'r')
type = PP_OD_RESTORE_DEFAULT_TABLE;
else if (*buf == 'c')
@@ -773,6 +808,8 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev,
while ((sub_str = strsep(&tmp_str, delimiter)) != NULL) {
if (strlen(sub_str) == 0)
continue;
+ if (parameter_size >= ARRAY_SIZE(parameter))
+ return -EINVAL;
ret = kstrtol(sub_str, 0, &parameter[parameter_size]);
if (ret)
return -EINVAL;
@@ -785,7 +822,7 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev,
tmp_str++;
}
- ret = pm_runtime_resume_and_get(ddev->dev);
+ ret = amdgpu_pm_get_access(adev);
if (ret < 0)
return ret;
@@ -806,14 +843,13 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev,
goto err_out;
}
- pm_runtime_mark_last_busy(ddev->dev);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
return count;
err_out:
- pm_runtime_mark_last_busy(ddev->dev);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
+
return -EINVAL;
}
@@ -825,9 +861,10 @@ static ssize_t amdgpu_get_pp_od_clk_voltage(struct device *dev,
struct amdgpu_device *adev = drm_to_adev(ddev);
int size = 0;
int ret;
- enum pp_clock_type od_clocks[6] = {
+ enum pp_clock_type od_clocks[] = {
OD_SCLK,
OD_MCLK,
+ OD_FCLK,
OD_VDDC_CURVE,
OD_RANGE,
OD_VDDGFX_OFFSET,
@@ -835,33 +872,20 @@ static ssize_t amdgpu_get_pp_od_clk_voltage(struct device *dev,
};
uint clk_index;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- ret = pm_runtime_get_if_active(ddev->dev);
- if (ret <= 0)
- return ret ?: -EPERM;
+ ret = amdgpu_pm_get_access_if_active(adev);
+ if (ret)
+ return ret;
- for (clk_index = 0 ; clk_index < 6 ; clk_index++) {
- ret = amdgpu_dpm_emit_clock_levels(adev, od_clocks[clk_index], buf, &size);
- if (ret)
+ for (clk_index = 0 ; clk_index < ARRAY_SIZE(od_clocks) ; clk_index++) {
+ amdgpu_dpm_emit_clock_levels(adev, od_clocks[clk_index], buf, &size);
+ if (unlikely(size >= (PAGE_SIZE - 1)))
break;
}
- if (ret == -ENOENT) {
- size = amdgpu_dpm_print_clock_levels(adev, OD_SCLK, buf);
- size += amdgpu_dpm_print_clock_levels(adev, OD_MCLK, buf + size);
- size += amdgpu_dpm_print_clock_levels(adev, OD_VDDC_CURVE, buf + size);
- size += amdgpu_dpm_print_clock_levels(adev, OD_VDDGFX_OFFSET, buf + size);
- size += amdgpu_dpm_print_clock_levels(adev, OD_RANGE, buf + size);
- size += amdgpu_dpm_print_clock_levels(adev, OD_CCLK, buf + size);
- }
if (size == 0)
size = sysfs_emit(buf, "\n");
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
return size;
}
@@ -892,23 +916,21 @@ static ssize_t amdgpu_set_pp_features(struct device *dev,
uint64_t featuremask;
int ret;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
+ /* Reject empty/whitespace strings - fuzzing found kstrtou64 accepts "" as 0 */
+ if (count == 0 || sysfs_streq(buf, ""))
+ return -EINVAL;
ret = kstrtou64(buf, 0, &featuremask);
if (ret)
return -EINVAL;
- ret = pm_runtime_resume_and_get(ddev->dev);
+ ret = amdgpu_pm_get_access(adev);
if (ret < 0)
return ret;
ret = amdgpu_dpm_set_ppfeature_status(adev, featuremask);
- pm_runtime_mark_last_busy(ddev->dev);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
if (ret)
return -EINVAL;
@@ -925,20 +947,15 @@ static ssize_t amdgpu_get_pp_features(struct device *dev,
ssize_t size;
int ret;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- ret = pm_runtime_get_if_active(ddev->dev);
- if (ret <= 0)
- return ret ?: -EPERM;
+ ret = amdgpu_pm_get_access_if_active(adev);
+ if (ret)
+ return ret;
size = amdgpu_dpm_get_ppfeature_status(adev, buf);
if (size <= 0)
size = sysfs_emit(buf, "\n");
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
return size;
}
@@ -991,23 +1008,21 @@ static ssize_t amdgpu_get_pp_dpm_clock(struct device *dev,
int size = 0;
int ret = 0;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- ret = pm_runtime_get_if_active(ddev->dev);
- if (ret <= 0)
- return ret ?: -EPERM;
+ ret = amdgpu_pm_get_access_if_active(adev);
+ if (ret)
+ return ret;
ret = amdgpu_dpm_emit_clock_levels(adev, type, buf, &size);
- if (ret == -ENOENT)
- size = amdgpu_dpm_print_clock_levels(adev, type, buf);
+ if (ret) {
+ size = ret;
+ goto out_pm_put;
+ }
if (size == 0)
size = sysfs_emit(buf, "\n");
- pm_runtime_put_autosuspend(ddev->dev);
+out_pm_put:
+ amdgpu_pm_put_access(adev);
return size;
}
@@ -1030,6 +1045,10 @@ static ssize_t amdgpu_read_mask(const char *buf, size_t count, uint32_t *mask)
*mask = 0;
+ /* Reject empty/whitespace strings - fuzzing found this is not validated */
+ if (count == 0 || sysfs_streq(buf, ""))
+ return -EINVAL;
+
bytes = min(count, sizeof(buf_cpy) - 1);
memcpy(buf_cpy, buf, bytes);
buf_cpy[bytes] = '\0';
@@ -1057,23 +1076,17 @@ static ssize_t amdgpu_set_pp_dpm_clock(struct device *dev,
int ret;
uint32_t mask = 0;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
ret = amdgpu_read_mask(buf, count, &mask);
if (ret)
return ret;
- ret = pm_runtime_resume_and_get(ddev->dev);
+ ret = amdgpu_pm_get_access(adev);
if (ret < 0)
return ret;
ret = amdgpu_dpm_force_clock_level(adev, type, mask);
- pm_runtime_mark_last_busy(ddev->dev);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
if (ret)
return -EINVAL;
@@ -1240,18 +1253,13 @@ static ssize_t amdgpu_get_pp_sclk_od(struct device *dev,
uint32_t value = 0;
int ret;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- ret = pm_runtime_get_if_active(ddev->dev);
- if (ret <= 0)
- return ret ?: -EPERM;
+ ret = amdgpu_pm_get_access_if_active(adev);
+ if (ret)
+ return ret;
value = amdgpu_dpm_get_sclk_od(adev);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
return sysfs_emit(buf, "%d\n", value);
}
@@ -1266,24 +1274,18 @@ static ssize_t amdgpu_set_pp_sclk_od(struct device *dev,
int ret;
long int value;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
ret = kstrtol(buf, 0, &value);
if (ret)
return -EINVAL;
- ret = pm_runtime_resume_and_get(ddev->dev);
+ ret = amdgpu_pm_get_access(adev);
if (ret < 0)
return ret;
amdgpu_dpm_set_sclk_od(adev, (uint32_t)value);
- pm_runtime_mark_last_busy(ddev->dev);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
return count;
}
@@ -1297,18 +1299,13 @@ static ssize_t amdgpu_get_pp_mclk_od(struct device *dev,
uint32_t value = 0;
int ret;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- ret = pm_runtime_get_if_active(ddev->dev);
- if (ret <= 0)
- return ret ?: -EPERM;
+ ret = amdgpu_pm_get_access_if_active(adev);
+ if (ret)
+ return ret;
value = amdgpu_dpm_get_mclk_od(adev);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
return sysfs_emit(buf, "%d\n", value);
}
@@ -1323,24 +1320,18 @@ static ssize_t amdgpu_set_pp_mclk_od(struct device *dev,
int ret;
long int value;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
ret = kstrtol(buf, 0, &value);
if (ret)
return -EINVAL;
- ret = pm_runtime_resume_and_get(ddev->dev);
+ ret = amdgpu_pm_get_access(adev);
if (ret < 0)
return ret;
amdgpu_dpm_set_mclk_od(adev, (uint32_t)value);
- pm_runtime_mark_last_busy(ddev->dev);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
return count;
}
@@ -1378,20 +1369,15 @@ static ssize_t amdgpu_get_pp_power_profile_mode(struct device *dev,
ssize_t size;
int ret;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- ret = pm_runtime_get_if_active(ddev->dev);
- if (ret <= 0)
- return ret ?: -EPERM;
+ ret = amdgpu_pm_get_access_if_active(adev);
+ if (ret)
+ return ret;
size = amdgpu_dpm_get_power_profile_mode(adev, buf);
if (size <= 0)
size = sysfs_emit(buf, "\n");
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
return size;
}
@@ -1409,28 +1395,26 @@ static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev,
long parameter[64];
char *sub_str, buf_cpy[128];
char *tmp_str;
- uint32_t i = 0;
char tmp[2];
long int profile_mode = 0;
const char delimiter[3] = {' ', '\n', '\0'};
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
+ /* Reject empty/whitespace strings - fuzzing found this is not validated */
+ if (count == 0 || sysfs_streq(buf, ""))
+ return -EINVAL;
- tmp[0] = *(buf);
+ tmp[0] = *(buf++);
tmp[1] = '\0';
ret = kstrtol(tmp, 0, &profile_mode);
if (ret)
return -EINVAL;
if (profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
- if (count < 2 || count > 127)
+ if (count < 2 || count > sizeof(buf_cpy))
return -EINVAL;
- while (isspace(*++buf))
- i++;
- memcpy(buf_cpy, buf, count-i);
+ while (isspace(*buf))
+ buf++;
+ strscpy(buf_cpy, buf, sizeof(buf_cpy));
tmp_str = buf_cpy;
while ((sub_str = strsep(&tmp_str, delimiter)) != NULL) {
if (strlen(sub_str) == 0)
@@ -1439,20 +1423,21 @@ static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev,
if (ret)
return -EINVAL;
parameter_size++;
+ if (!tmp_str)
+ break;
while (isspace(*tmp_str))
tmp_str++;
}
}
parameter[parameter_size] = profile_mode;
- ret = pm_runtime_resume_and_get(ddev->dev);
+ ret = amdgpu_pm_get_access(adev);
if (ret < 0)
return ret;
ret = amdgpu_dpm_set_power_profile_mode(adev, parameter, parameter_size);
- pm_runtime_mark_last_busy(ddev->dev);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
if (!ret)
return count;
@@ -1460,25 +1445,20 @@ static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev,
return -EINVAL;
}
-static int amdgpu_hwmon_get_sensor_generic(struct amdgpu_device *adev,
- enum amd_pp_sensors sensor,
- void *query)
+static int amdgpu_pm_get_sensor_generic(struct amdgpu_device *adev,
+ enum amd_pp_sensors sensor,
+ void *query)
{
int r, size = sizeof(uint32_t);
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- r = pm_runtime_get_if_active(adev->dev);
- if (r <= 0)
- return r ?: -EPERM;
+ r = amdgpu_pm_get_access_if_active(adev);
+ if (r)
+ return r;
/* get the sensor value */
r = amdgpu_dpm_read_sensor(adev, sensor, query, &size);
- pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+ amdgpu_pm_put_access(adev);
return r;
}
@@ -1500,7 +1480,7 @@ static ssize_t amdgpu_get_gpu_busy_percent(struct device *dev,
unsigned int value;
int r;
- r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GPU_LOAD, &value);
+ r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GPU_LOAD, &value);
if (r)
return r;
@@ -1524,7 +1504,7 @@ static ssize_t amdgpu_get_mem_busy_percent(struct device *dev,
unsigned int value;
int r;
- r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MEM_LOAD, &value);
+ r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MEM_LOAD, &value);
if (r)
return r;
@@ -1548,7 +1528,7 @@ static ssize_t amdgpu_get_vcn_busy_percent(struct device *dev,
unsigned int value;
int r;
- r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_VCN_LOAD, &value);
+ r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_VCN_LOAD, &value);
if (r)
return r;
@@ -1576,24 +1556,19 @@ static ssize_t amdgpu_get_pcie_bw(struct device *dev,
uint64_t count0 = 0, count1 = 0;
int ret;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
if (adev->flags & AMD_IS_APU)
return -ENODATA;
if (!adev->asic_funcs->get_pcie_usage)
return -ENODATA;
- ret = pm_runtime_get_if_active(ddev->dev);
- if (ret <= 0)
- return ret ?: -EPERM;
+ ret = amdgpu_pm_get_access_if_active(adev);
+ if (ret)
+ return ret;
amdgpu_asic_get_pcie_usage(adev, &count0, &count1);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
return sysfs_emit(buf, "%llu %llu %i\n",
count0, count1, pcie_get_mps(adev->pdev));
@@ -1616,11 +1591,6 @@ static ssize_t amdgpu_get_unique_id(struct device *dev,
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = drm_to_adev(ddev);
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
if (adev->unique_id)
return sysfs_emit(buf, "%016llx\n", adev->unique_id);
@@ -1651,7 +1621,7 @@ static ssize_t amdgpu_get_thermal_throttling_logging(struct device *dev,
return sysfs_emit(buf, "%s: thermal throttling logging %s, with interval %d seconds\n",
adev_to_drm(adev)->unique,
- atomic_read(&adev->throttling_logging_enabled) ? "enabled" : "disabled",
+ str_enabled_disabled(atomic_read(&adev->throttling_logging_enabled)),
adev->throttling_logging_rs.interval / HZ + 1);
}
@@ -1663,29 +1633,26 @@ static ssize_t amdgpu_set_thermal_throttling_logging(struct device *dev,
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = drm_to_adev(ddev);
long throttling_logging_interval;
- unsigned long flags;
int ret = 0;
ret = kstrtol(buf, 0, &throttling_logging_interval);
if (ret)
return ret;
+ /* Reject negative values - only 0 (disable) or 1-3600 (seconds) are valid */
+ if (throttling_logging_interval < 0)
+ return -EINVAL;
+
if (throttling_logging_interval > 3600)
return -EINVAL;
if (throttling_logging_interval > 0) {
- raw_spin_lock_irqsave(&adev->throttling_logging_rs.lock, flags);
/*
* Reset the ratelimit timer internals.
* This can effectively restart the timer.
*/
- adev->throttling_logging_rs.interval =
- (throttling_logging_interval - 1) * HZ;
- adev->throttling_logging_rs.begin = 0;
- adev->throttling_logging_rs.printed = 0;
- adev->throttling_logging_rs.missed = 0;
- raw_spin_unlock_irqrestore(&adev->throttling_logging_rs.lock, flags);
-
+ ratelimit_state_reset_interval(&adev->throttling_logging_rs,
+ (throttling_logging_interval - 1) * HZ);
atomic_set(&adev->throttling_logging_enabled, 1);
} else {
atomic_set(&adev->throttling_logging_enabled, 0);
@@ -1715,9 +1682,9 @@ static ssize_t amdgpu_get_apu_thermal_cap(struct device *dev,
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = drm_to_adev(ddev);
- ret = pm_runtime_get_if_active(ddev->dev);
- if (ret <= 0)
- return ret ?: -EPERM;
+ ret = amdgpu_pm_get_access_if_active(adev);
+ if (ret)
+ return ret;
ret = amdgpu_dpm_get_apu_thermal_limit(adev, &limit);
if (!ret)
@@ -1725,7 +1692,7 @@ static ssize_t amdgpu_get_apu_thermal_cap(struct device *dev,
else
size = sysfs_emit(buf, "failed to get thermal limit\n");
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
return size;
}
@@ -1749,20 +1716,18 @@ static ssize_t amdgpu_set_apu_thermal_cap(struct device *dev,
return -EINVAL;
}
- ret = pm_runtime_resume_and_get(ddev->dev);
+ ret = amdgpu_pm_get_access(adev);
if (ret < 0)
return ret;
ret = amdgpu_dpm_set_apu_thermal_limit(adev, value);
if (ret) {
- pm_runtime_mark_last_busy(ddev->dev);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
dev_err(dev, "failed to update thermal limit\n");
return ret;
}
- pm_runtime_mark_last_busy(ddev->dev);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
return count;
}
@@ -1786,18 +1751,13 @@ static ssize_t amdgpu_get_pm_metrics(struct device *dev,
ssize_t size = 0;
int ret;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- ret = pm_runtime_get_if_active(ddev->dev);
- if (ret <= 0)
- return ret ?: -EPERM;
+ ret = amdgpu_pm_get_access_if_active(adev);
+ if (ret)
+ return ret;
size = amdgpu_dpm_get_pm_metrics(adev, buf, PAGE_SIZE);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
return size;
}
@@ -1824,14 +1784,9 @@ static ssize_t amdgpu_get_gpu_metrics(struct device *dev,
ssize_t size = 0;
int ret;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- ret = pm_runtime_get_if_active(ddev->dev);
- if (ret <= 0)
- return ret ?: -EPERM;
+ ret = amdgpu_pm_get_access_if_active(adev);
+ if (ret)
+ return ret;
size = amdgpu_dpm_get_gpu_metrics(adev, &gpu_metrics);
if (size <= 0)
@@ -1843,7 +1798,7 @@ static ssize_t amdgpu_get_gpu_metrics(struct device *dev,
memcpy(buf, gpu_metrics, size);
out:
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
return size;
}
@@ -1856,7 +1811,7 @@ static int amdgpu_show_powershift_percent(struct device *dev,
uint32_t ss_power;
int r = 0, i;
- r = amdgpu_hwmon_get_sensor_generic(adev, sensor, (void *)&ss_power);
+ r = amdgpu_pm_get_sensor_generic(adev, sensor, (void *)&ss_power);
if (r == -EOPNOTSUPP) {
/* sensor not available on dGPU, try to read from APU */
adev = NULL;
@@ -1869,7 +1824,7 @@ static int amdgpu_show_powershift_percent(struct device *dev,
}
mutex_unlock(&mgpu_info.mutex);
if (adev)
- r = amdgpu_hwmon_get_sensor_generic(adev, sensor, (void *)&ss_power);
+ r = amdgpu_pm_get_sensor_generic(adev, sensor, (void *)&ss_power);
}
if (r)
@@ -1936,42 +1891,35 @@ static ssize_t amdgpu_set_smartshift_bias(struct device *dev,
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = drm_to_adev(ddev);
- int r = 0;
+ int r;
int bias = 0;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
+ r = kstrtoint(buf, 10, &bias);
+ if (r)
+ return r;
- r = pm_runtime_resume_and_get(ddev->dev);
+ r = amdgpu_pm_get_access(adev);
if (r < 0)
return r;
- r = kstrtoint(buf, 10, &bias);
- if (r)
- goto out;
-
if (bias > AMDGPU_SMARTSHIFT_MAX_BIAS)
bias = AMDGPU_SMARTSHIFT_MAX_BIAS;
else if (bias < AMDGPU_SMARTSHIFT_MIN_BIAS)
bias = AMDGPU_SMARTSHIFT_MIN_BIAS;
amdgpu_smartshift_bias = bias;
- r = count;
/* TODO: update bias level with SMU message */
-out:
- pm_runtime_mark_last_busy(ddev->dev);
- pm_runtime_put_autosuspend(ddev->dev);
- return r;
+ amdgpu_pm_put_access(adev);
+
+ return count;
}
static int ss_power_attr_update(struct amdgpu_device *adev, struct amdgpu_device_attr *attr,
uint32_t mask, enum amdgpu_device_attr_states *states)
{
- if (!amdgpu_device_supports_smart_shift(adev_to_drm(adev)))
+ if (!amdgpu_device_supports_smart_shift(adev))
*states = ATTR_STATE_UNSUPPORTED;
return 0;
@@ -1982,13 +1930,13 @@ static int ss_bias_attr_update(struct amdgpu_device *adev, struct amdgpu_device_
{
uint32_t ss_power;
- if (!amdgpu_device_supports_smart_shift(adev_to_drm(adev)))
+ if (!amdgpu_device_supports_smart_shift(adev))
*states = ATTR_STATE_UNSUPPORTED;
- else if (amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_SS_APU_SHARE,
- (void *)&ss_power))
+ else if (amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_SS_APU_SHARE,
+ (void *)&ss_power))
*states = ATTR_STATE_UNSUPPORTED;
- else if (amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_SS_DGPU_SHARE,
- (void *)&ss_power))
+ else if (amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_SS_DGPU_SHARE,
+ (void *)&ss_power))
*states = ATTR_STATE_UNSUPPORTED;
return 0;
@@ -1997,8 +1945,6 @@ static int ss_bias_attr_update(struct amdgpu_device *adev, struct amdgpu_device_
static int pp_od_clk_voltage_attr_update(struct amdgpu_device *adev, struct amdgpu_device_attr *attr,
uint32_t mask, enum amdgpu_device_attr_states *states)
{
- uint32_t gc_ver = amdgpu_ip_version(adev, GC_HWIP, 0);
-
*states = ATTR_STATE_SUPPORTED;
if (!amdgpu_dpm_is_overdrive_supported(adev)) {
@@ -2006,10 +1952,9 @@ static int pp_od_clk_voltage_attr_update(struct amdgpu_device *adev, struct amdg
return 0;
}
- /* Enable pp_od_clk_voltage node for gc 9.4.3 SRIOV/BM support */
- if (gc_ver == IP_VERSION(9, 4, 3) ||
- gc_ver == IP_VERSION(9, 4, 4)) {
- if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev))
+ /* Enable pp_od_clk_voltage node for gc 9.4.3, 9.4.4, 9.5.0, 12.1.0 SRIOV/BM support */
+ if (amdgpu_is_multi_aid(adev)) {
+ if (amdgpu_sriov_multi_vf_mode(adev))
*states = ATTR_STATE_UNSUPPORTED;
return 0;
}
@@ -2044,7 +1989,7 @@ static int pp_dpm_dcefclk_attr_update(struct amdgpu_device *adev, struct amdgpu_
* setting should not be allowed from VF if not in one VF mode.
*/
if (gc_ver >= IP_VERSION(10, 0, 0) ||
- (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev))) {
+ (amdgpu_sriov_multi_vf_mode(adev))) {
dev_attr->attr.mode &= ~S_IWUGO;
dev_attr->store = NULL;
}
@@ -2086,8 +2031,7 @@ static int pp_dpm_clk_default_attr_update(struct amdgpu_device *adev, struct amd
gc_ver == IP_VERSION(11, 5, 0) ||
gc_ver == IP_VERSION(11, 0, 2) ||
gc_ver == IP_VERSION(11, 0, 3) ||
- gc_ver == IP_VERSION(9, 4, 3) ||
- gc_ver == IP_VERSION(9, 4, 4)))
+ amdgpu_is_multi_aid(adev)))
*states = ATTR_STATE_UNSUPPORTED;
} else if (DEVICE_ATTR_IS(pp_dpm_vclk1)) {
if (!((gc_ver == IP_VERSION(10, 3, 1) ||
@@ -2108,8 +2052,7 @@ static int pp_dpm_clk_default_attr_update(struct amdgpu_device *adev, struct amd
gc_ver == IP_VERSION(11, 5, 0) ||
gc_ver == IP_VERSION(11, 0, 2) ||
gc_ver == IP_VERSION(11, 0, 3) ||
- gc_ver == IP_VERSION(9, 4, 3) ||
- gc_ver == IP_VERSION(9, 4, 4)))
+ amdgpu_is_multi_aid(adev)))
*states = ATTR_STATE_UNSUPPORTED;
} else if (DEVICE_ATTR_IS(pp_dpm_dclk1)) {
if (!((gc_ver == IP_VERSION(10, 3, 1) ||
@@ -2118,16 +2061,13 @@ static int pp_dpm_clk_default_attr_update(struct amdgpu_device *adev, struct amd
gc_ver == IP_VERSION(11, 0, 3)) && adev->vcn.num_vcn_inst >= 2))
*states = ATTR_STATE_UNSUPPORTED;
} else if (DEVICE_ATTR_IS(pp_dpm_pcie)) {
- if (gc_ver == IP_VERSION(9, 4, 2) ||
- gc_ver == IP_VERSION(9, 4, 3) ||
- gc_ver == IP_VERSION(9, 4, 4))
+ if (amdgpu_is_multi_aid(adev))
*states = ATTR_STATE_UNSUPPORTED;
}
switch (gc_ver) {
case IP_VERSION(9, 4, 1):
- case IP_VERSION(9, 4, 2):
- /* the Mi series card does not support standalone mclk/socclk/fclk level setting */
+ /* Arcturus does not support standalone mclk/socclk/fclk level setting */
if (DEVICE_ATTR_IS(pp_dpm_mclk) ||
DEVICE_ATTR_IS(pp_dpm_socclk) ||
DEVICE_ATTR_IS(pp_dpm_fclk)) {
@@ -2135,6 +2075,19 @@ static int pp_dpm_clk_default_attr_update(struct amdgpu_device *adev, struct amd
dev_attr->store = NULL;
}
break;
+ case IP_VERSION(9, 4, 2):
+ if (DEVICE_ATTR_IS(pp_dpm_mclk) ||
+ DEVICE_ATTR_IS(pp_dpm_socclk)) {
+ /* Aldebaran mclk/socclk DPM only supports voltage control,
+ * not allow to set dpm level directly */
+ dev_attr->attr.mode &= ~S_IWUGO;
+ dev_attr->store = NULL;
+ } else if (DEVICE_ATTR_IS(pp_dpm_fclk) ||
+ DEVICE_ATTR_IS(pp_dpm_pcie)) {
+ /* Aldebaran does not support fclk/pcie dpm */
+ *states = ATTR_STATE_UNSUPPORTED;
+ }
+ break;
default:
break;
}
@@ -2148,6 +2101,318 @@ static int pp_dpm_clk_default_attr_update(struct amdgpu_device *adev, struct amd
return 0;
}
+/**
+ * DOC: board
+ *
+ * Certain SOCs can support various board attributes reporting. This is useful
+ * for user application to monitor various board reated attributes.
+ *
+ * The amdgpu driver provides a sysfs API for reporting board attributes. Presently,
+ * nine types of attributes are reported. Baseboard temperature and
+ * gpu board temperature are reported as binary files. Npm status, current node power limit,
+ * max node power limit, node power, global ppt residency, baseboard_power, baseboard_power_limit
+ * is reported as ASCII text file.
+ *
+ * * .. code-block:: console
+ *
+ * hexdump /sys/bus/pci/devices/.../board/baseboard_temp
+ *
+ * hexdump /sys/bus/pci/devices/.../board/gpuboard_temp
+ *
+ * hexdump /sys/bus/pci/devices/.../board/npm_status
+ *
+ * hexdump /sys/bus/pci/devices/.../board/cur_node_power_limit
+ *
+ * hexdump /sys/bus/pci/devices/.../board/max_node_power_limit
+ *
+ * hexdump /sys/bus/pci/devices/.../board/node_power
+ *
+ * hexdump /sys/bus/pci/devices/.../board/global_ppt_resid
+ *
+ * hexdump /sys/bus/pci/devices/.../board/baseboard_power
+ *
+ * hexdump /sys/bus/pci/devices/.../board/baseboard_power_limit
+ */
+
+/**
+ * DOC: baseboard_temp
+ *
+ * The amdgpu driver provides a sysfs API for retrieving current baseboard
+ * temperature metrics data. The file baseboard_temp is used for this.
+ * Reading the file will dump all the current baseboard temperature metrics data.
+ */
+static ssize_t amdgpu_get_baseboard_temp_metrics(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct drm_device *ddev = dev_get_drvdata(dev);
+ struct amdgpu_device *adev = drm_to_adev(ddev);
+ ssize_t size;
+ int ret;
+
+ ret = amdgpu_pm_get_access_if_active(adev);
+ if (ret)
+ return ret;
+
+ size = amdgpu_dpm_get_temp_metrics(adev, SMU_TEMP_METRIC_BASEBOARD, NULL);
+ if (size <= 0)
+ goto out;
+ if (size >= PAGE_SIZE) {
+ ret = -ENOSPC;
+ goto out;
+ }
+
+ amdgpu_dpm_get_temp_metrics(adev, SMU_TEMP_METRIC_BASEBOARD, buf);
+
+out:
+ amdgpu_pm_put_access(adev);
+
+ if (ret)
+ return ret;
+
+ return size;
+}
+
+/**
+ * DOC: gpuboard_temp
+ *
+ * The amdgpu driver provides a sysfs API for retrieving current gpuboard
+ * temperature metrics data. The file gpuboard_temp is used for this.
+ * Reading the file will dump all the current gpuboard temperature metrics data.
+ */
+static ssize_t amdgpu_get_gpuboard_temp_metrics(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct drm_device *ddev = dev_get_drvdata(dev);
+ struct amdgpu_device *adev = drm_to_adev(ddev);
+ ssize_t size;
+ int ret;
+
+ ret = amdgpu_pm_get_access_if_active(adev);
+ if (ret)
+ return ret;
+
+ size = amdgpu_dpm_get_temp_metrics(adev, SMU_TEMP_METRIC_GPUBOARD, NULL);
+ if (size <= 0)
+ goto out;
+ if (size >= PAGE_SIZE) {
+ ret = -ENOSPC;
+ goto out;
+ }
+
+ amdgpu_dpm_get_temp_metrics(adev, SMU_TEMP_METRIC_GPUBOARD, buf);
+
+out:
+ amdgpu_pm_put_access(adev);
+
+ if (ret)
+ return ret;
+
+ return size;
+}
+
+/**
+ * DOC: cur_node_power_limit
+ *
+ * The amdgpu driver provides a sysfs API for retrieving current node power limit.
+ * The file cur_node_power_limit is used for this.
+ */
+static ssize_t amdgpu_show_cur_node_power_limit(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct drm_device *ddev = dev_get_drvdata(dev);
+ struct amdgpu_device *adev = drm_to_adev(ddev);
+ u32 nplimit;
+ int r;
+
+ /* get the current node power limit */
+ r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_NODEPOWERLIMIT,
+ (void *)&nplimit);
+ if (r)
+ return r;
+
+ return sysfs_emit(buf, "%u\n", nplimit);
+}
+
+/**
+ * DOC: node_power
+ *
+ * The amdgpu driver provides a sysfs API for retrieving current node power.
+ * The file node_power is used for this.
+ */
+static ssize_t amdgpu_show_node_power(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct drm_device *ddev = dev_get_drvdata(dev);
+ struct amdgpu_device *adev = drm_to_adev(ddev);
+ u32 npower;
+ int r;
+
+ /* get the node power */
+ r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_NODEPOWER,
+ (void *)&npower);
+ if (r)
+ return r;
+
+ return sysfs_emit(buf, "%u\n", npower);
+}
+
+/**
+ * DOC: npm_status
+ *
+ * The amdgpu driver provides a sysfs API for retrieving current node power management status.
+ * The file npm_status is used for this. It shows the status as enabled or disabled based on
+ * current node power value. If node power is zero, status is disabled else enabled.
+ */
+static ssize_t amdgpu_show_npm_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct drm_device *ddev = dev_get_drvdata(dev);
+ struct amdgpu_device *adev = drm_to_adev(ddev);
+ u32 npower;
+ int r;
+
+ /* get the node power */
+ r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_NODEPOWER,
+ (void *)&npower);
+ if (r)
+ return r;
+
+ return sysfs_emit(buf, "%s\n", str_enabled_disabled(npower));
+}
+
+/**
+ * DOC: global_ppt_resid
+ *
+ * The amdgpu driver provides a sysfs API for retrieving global ppt residency.
+ * The file global_ppt_resid is used for this.
+ */
+static ssize_t amdgpu_show_global_ppt_resid(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct drm_device *ddev = dev_get_drvdata(dev);
+ struct amdgpu_device *adev = drm_to_adev(ddev);
+ u32 gpptresid;
+ int r;
+
+ /* get the global ppt residency */
+ r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GPPTRESIDENCY,
+ (void *)&gpptresid);
+ if (r)
+ return r;
+
+ return sysfs_emit(buf, "%u\n", gpptresid);
+}
+
+/**
+ * DOC: max_node_power_limit
+ *
+ * The amdgpu driver provides a sysfs API for retrieving maximum node power limit.
+ * The file max_node_power_limit is used for this.
+ */
+static ssize_t amdgpu_show_max_node_power_limit(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct drm_device *ddev = dev_get_drvdata(dev);
+ struct amdgpu_device *adev = drm_to_adev(ddev);
+ u32 max_nplimit;
+ int r;
+
+ /* get the max node power limit */
+ r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MAXNODEPOWERLIMIT,
+ (void *)&max_nplimit);
+ if (r)
+ return r;
+
+ return sysfs_emit(buf, "%u\n", max_nplimit);
+}
+
+/**
+ * DOC: baseboard_power
+ *
+ * The amdgpu driver provides a sysfs API for retrieving current ubb power in watts.
+ * The file baseboard_power is used for this.
+ */
+static ssize_t amdgpu_show_baseboard_power(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct drm_device *ddev = dev_get_drvdata(dev);
+ struct amdgpu_device *adev = drm_to_adev(ddev);
+ u32 ubbpower;
+ int r;
+
+ /* get the ubb power */
+ r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_UBB_POWER,
+ (void *)&ubbpower);
+ if (r)
+ return r;
+
+ return sysfs_emit(buf, "%u\n", ubbpower);
+}
+
+/**
+ * DOC: baseboard_power_limit
+ *
+ * The amdgpu driver provides a sysfs API for retrieving threshold ubb power in watts.
+ * The file baseboard_power_limit is used for this.
+ */
+static ssize_t amdgpu_show_baseboard_power_limit(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct drm_device *ddev = dev_get_drvdata(dev);
+ struct amdgpu_device *adev = drm_to_adev(ddev);
+ u32 ubbpowerlimit;
+ int r;
+
+ /* get the ubb power limit */
+ r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_UBB_POWER_LIMIT,
+ (void *)&ubbpowerlimit);
+ if (r)
+ return r;
+
+ return sysfs_emit(buf, "%u\n", ubbpowerlimit);
+}
+
+static DEVICE_ATTR(baseboard_temp, 0444, amdgpu_get_baseboard_temp_metrics, NULL);
+static DEVICE_ATTR(gpuboard_temp, 0444, amdgpu_get_gpuboard_temp_metrics, NULL);
+static DEVICE_ATTR(cur_node_power_limit, 0444, amdgpu_show_cur_node_power_limit, NULL);
+static DEVICE_ATTR(node_power, 0444, amdgpu_show_node_power, NULL);
+static DEVICE_ATTR(global_ppt_resid, 0444, amdgpu_show_global_ppt_resid, NULL);
+static DEVICE_ATTR(max_node_power_limit, 0444, amdgpu_show_max_node_power_limit, NULL);
+static DEVICE_ATTR(npm_status, 0444, amdgpu_show_npm_status, NULL);
+static DEVICE_ATTR(baseboard_power, 0444, amdgpu_show_baseboard_power, NULL);
+static DEVICE_ATTR(baseboard_power_limit, 0444, amdgpu_show_baseboard_power_limit, NULL);
+
+static struct attribute *board_attrs[] = {
+ &dev_attr_baseboard_temp.attr,
+ &dev_attr_gpuboard_temp.attr,
+ NULL
+};
+
+static umode_t amdgpu_board_attr_visible(struct kobject *kobj, struct attribute *attr, int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct drm_device *ddev = dev_get_drvdata(dev);
+ struct amdgpu_device *adev = drm_to_adev(ddev);
+
+ if (attr == &dev_attr_baseboard_temp.attr) {
+ if (!amdgpu_dpm_is_temp_metrics_supported(adev, SMU_TEMP_METRIC_BASEBOARD))
+ return 0;
+ }
+
+ if (attr == &dev_attr_gpuboard_temp.attr) {
+ if (!amdgpu_dpm_is_temp_metrics_supported(adev, SMU_TEMP_METRIC_GPUBOARD))
+ return 0;
+ }
+
+ return attr->mode;
+}
+
+const struct attribute_group amdgpu_board_attr_group = {
+ .name = "board",
+ .attrs = board_attrs,
+ .is_visible = amdgpu_board_attr_visible,
+};
+
/* pm policy attributes */
struct amdgpu_pm_policy_attr {
struct device_attribute dev_attr;
@@ -2218,11 +2483,6 @@ static ssize_t amdgpu_get_pm_policy_attr(struct device *dev,
policy_attr =
container_of(attr, struct amdgpu_pm_policy_attr, dev_attr);
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
return amdgpu_dpm_get_pm_policy_info(adev, policy_attr->id, buf);
}
@@ -2239,11 +2499,6 @@ static ssize_t amdgpu_set_pm_policy_attr(struct device *dev,
char *tmp, *param;
long val;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
count = min(count, sizeof(tmp_buf));
memcpy(tmp_buf, buf, count);
tmp_buf[count - 1] = '\0';
@@ -2269,14 +2524,13 @@ static ssize_t amdgpu_set_pm_policy_attr(struct device *dev,
policy_attr =
container_of(attr, struct amdgpu_pm_policy_attr, dev_attr);
- ret = pm_runtime_resume_and_get(ddev->dev);
+ ret = amdgpu_pm_get_access(adev);
if (ret < 0)
return ret;
ret = amdgpu_dpm_set_pm_policy(adev, policy_attr->id, val);
- pm_runtime_mark_last_busy(ddev->dev);
- pm_runtime_put_autosuspend(ddev->dev);
+ amdgpu_pm_put_access(adev);
if (ret)
return ret;
@@ -2289,12 +2543,12 @@ static ssize_t amdgpu_set_pm_policy_attr(struct device *dev,
.dev_attr = __ATTR(_name, 0644, amdgpu_get_pm_policy_attr, \
amdgpu_set_pm_policy_attr), \
.id = PP_PM_POLICY_##_id, \
- };
+ }
#define AMDGPU_PM_POLICY_ATTR_VAR(_name) pm_policy_attr_##_name.dev_attr.attr
-AMDGPU_PM_POLICY_ATTR(soc_pstate, SOC_PSTATE)
-AMDGPU_PM_POLICY_ATTR(xgmi_plpd, XGMI_PLPD)
+AMDGPU_PM_POLICY_ATTR(soc_pstate, SOC_PSTATE);
+AMDGPU_PM_POLICY_ATTR(xgmi_plpd, XGMI_PLPD);
static struct attribute *pm_policy_attrs[] = {
&AMDGPU_PM_POLICY_ATTR_VAR(soc_pstate),
@@ -2332,7 +2586,7 @@ static struct amdgpu_device_attr amdgpu_device_attrs[] = {
AMDGPU_DEVICE_ATTR_RO(pp_num_states, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF),
AMDGPU_DEVICE_ATTR_RO(pp_cur_state, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF),
AMDGPU_DEVICE_ATTR_RW(pp_force_state, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF),
- AMDGPU_DEVICE_ATTR_RW(pp_table, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF),
+ AMDGPU_DEVICE_ATTR_RW(pp_table, ATTR_FLAG_BASIC),
AMDGPU_DEVICE_ATTR_RW(pp_dpm_sclk, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF,
.attr_update = pp_dpm_clk_default_attr_update),
AMDGPU_DEVICE_ATTR_RW(pp_dpm_mclk, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF,
@@ -2395,13 +2649,22 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_
gc_ver == IP_VERSION(9, 0, 1))
*states = ATTR_STATE_UNSUPPORTED;
} else if (DEVICE_ATTR_IS(vcn_busy_percent)) {
- if (!(gc_ver == IP_VERSION(10, 3, 1) ||
- gc_ver == IP_VERSION(10, 3, 3) ||
- gc_ver == IP_VERSION(10, 3, 6) ||
- gc_ver == IP_VERSION(10, 3, 7) ||
- gc_ver == IP_VERSION(11, 0, 1) ||
- gc_ver == IP_VERSION(11, 0, 4) ||
- gc_ver == IP_VERSION(11, 5, 0)))
+ if (!(gc_ver == IP_VERSION(9, 3, 0) ||
+ gc_ver == IP_VERSION(10, 3, 1) ||
+ gc_ver == IP_VERSION(10, 3, 3) ||
+ gc_ver == IP_VERSION(10, 3, 6) ||
+ gc_ver == IP_VERSION(10, 3, 7) ||
+ gc_ver == IP_VERSION(11, 0, 0) ||
+ gc_ver == IP_VERSION(11, 0, 1) ||
+ gc_ver == IP_VERSION(11, 0, 2) ||
+ gc_ver == IP_VERSION(11, 0, 3) ||
+ gc_ver == IP_VERSION(11, 0, 4) ||
+ gc_ver == IP_VERSION(11, 5, 0) ||
+ gc_ver == IP_VERSION(11, 5, 1) ||
+ gc_ver == IP_VERSION(11, 5, 2) ||
+ gc_ver == IP_VERSION(11, 5, 3) ||
+ gc_ver == IP_VERSION(12, 0, 0) ||
+ gc_ver == IP_VERSION(12, 0, 1)))
*states = ATTR_STATE_UNSUPPORTED;
} else if (DEVICE_ATTR_IS(pcie_bw)) {
/* PCIe Perf counters won't work on APU nodes */
@@ -2416,6 +2679,7 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_
case IP_VERSION(9, 4, 2):
case IP_VERSION(9, 4, 3):
case IP_VERSION(9, 4, 4):
+ case IP_VERSION(9, 5, 0):
case IP_VERSION(10, 3, 0):
case IP_VERSION(11, 0, 0):
case IP_VERSION(11, 0, 1):
@@ -2423,6 +2687,7 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_
case IP_VERSION(11, 0, 3):
case IP_VERSION(12, 0, 0):
case IP_VERSION(12, 0, 1):
+ case IP_VERSION(12, 1, 0):
*states = ATTR_STATE_SUPPORTED;
break;
default:
@@ -2433,6 +2698,11 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_
gc_ver != IP_VERSION(9, 4, 3)) ||
gc_ver < IP_VERSION(9, 0, 0))
*states = ATTR_STATE_UNSUPPORTED;
+
+ if (adev->scpm_enabled) {
+ dev_attr->attr.mode &= ~S_IWUGO;
+ dev_attr->store = NULL;
+ }
} else if (DEVICE_ATTR_IS(gpu_metrics)) {
if (gc_ver < IP_VERSION(9, 1, 0))
*states = ATTR_STATE_UNSUPPORTED;
@@ -2454,6 +2724,15 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_
if (amdgpu_dpm_get_apu_thermal_limit(adev, &limit) ==
-EOPNOTSUPP)
*states = ATTR_STATE_UNSUPPORTED;
+ } else if (DEVICE_ATTR_IS(pp_table)) {
+ int ret;
+ char *tmp = NULL;
+
+ ret = amdgpu_dpm_get_pp_table(adev, &tmp);
+ if (ret == -EOPNOTSUPP || !tmp)
+ *states = ATTR_STATE_UNSUPPORTED;
+ else
+ *states = ATTR_STATE_SUPPORTED;
}
switch (gc_ver) {
@@ -2509,7 +2788,7 @@ static int amdgpu_device_attr_create(struct amdgpu_device *adev,
name, ret);
}
- attr_entry = kmalloc(sizeof(*attr_entry), GFP_KERNEL);
+ attr_entry = kmalloc_obj(*attr_entry);
if (!attr_entry)
return -ENOMEM;
@@ -2583,18 +2862,18 @@ static ssize_t amdgpu_hwmon_show_temp(struct device *dev,
switch (channel) {
case PP_TEMP_JUNCTION:
/* get current junction temperature */
- r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_HOTSPOT_TEMP,
- (void *)&temp);
+ r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_HOTSPOT_TEMP,
+ (void *)&temp);
break;
case PP_TEMP_EDGE:
/* get current edge temperature */
- r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_EDGE_TEMP,
- (void *)&temp);
+ r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_EDGE_TEMP,
+ (void *)&temp);
break;
case PP_TEMP_MEM:
/* get current memory temperature */
- r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MEM_TEMP,
- (void *)&temp);
+ r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MEM_TEMP,
+ (void *)&temp);
break;
default:
r = -EINVAL;
@@ -2701,18 +2980,13 @@ static ssize_t amdgpu_hwmon_get_pwm1_enable(struct device *dev,
u32 pwm_mode = 0;
int ret;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- ret = pm_runtime_get_if_active(adev->dev);
- if (ret <= 0)
- return ret ?: -EPERM;
+ ret = amdgpu_pm_get_access_if_active(adev);
+ if (ret)
+ return ret;
ret = amdgpu_dpm_get_fan_control_mode(adev, &pwm_mode);
- pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+ amdgpu_pm_put_access(adev);
if (ret)
return -EINVAL;
@@ -2730,11 +3004,6 @@ static ssize_t amdgpu_hwmon_set_pwm1_enable(struct device *dev,
u32 pwm_mode;
int value;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
err = kstrtoint(buf, 10, &value);
if (err)
return err;
@@ -2748,14 +3017,13 @@ static ssize_t amdgpu_hwmon_set_pwm1_enable(struct device *dev,
else
return -EINVAL;
- ret = pm_runtime_resume_and_get(adev->dev);
+ ret = amdgpu_pm_get_access(adev);
if (ret < 0)
return ret;
ret = amdgpu_dpm_set_fan_control_mode(adev, pwm_mode);
- pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
- pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+ amdgpu_pm_put_access(adev);
if (ret)
return -EINVAL;
@@ -2786,16 +3054,11 @@ static ssize_t amdgpu_hwmon_set_pwm1(struct device *dev,
u32 value;
u32 pwm_mode;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
err = kstrtou32(buf, 10, &value);
if (err)
return err;
- err = pm_runtime_resume_and_get(adev->dev);
+ err = amdgpu_pm_get_access(adev);
if (err < 0)
return err;
@@ -2812,8 +3075,7 @@ static ssize_t amdgpu_hwmon_set_pwm1(struct device *dev,
err = amdgpu_dpm_set_fan_speed_pwm(adev, value);
out:
- pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
- pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+ amdgpu_pm_put_access(adev);
if (err)
return err;
@@ -2829,18 +3091,13 @@ static ssize_t amdgpu_hwmon_get_pwm1(struct device *dev,
int err;
u32 speed = 0;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- err = pm_runtime_get_if_active(adev->dev);
- if (err <= 0)
- return err ?: -EPERM;
+ err = amdgpu_pm_get_access_if_active(adev);
+ if (err)
+ return err;
err = amdgpu_dpm_get_fan_speed_pwm(adev, &speed);
- pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+ amdgpu_pm_put_access(adev);
if (err)
return err;
@@ -2856,18 +3113,13 @@ static ssize_t amdgpu_hwmon_get_fan1_input(struct device *dev,
int err;
u32 speed = 0;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- err = pm_runtime_get_if_active(adev->dev);
- if (err <= 0)
- return err ?: -EPERM;
+ err = amdgpu_pm_get_access_if_active(adev);
+ if (err)
+ return err;
err = amdgpu_dpm_get_fan_speed_rpm(adev, &speed);
- pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+ amdgpu_pm_put_access(adev);
if (err)
return err;
@@ -2883,8 +3135,8 @@ static ssize_t amdgpu_hwmon_get_fan1_min(struct device *dev,
u32 min_rpm = 0;
int r;
- r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MIN_FAN_RPM,
- (void *)&min_rpm);
+ r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MIN_FAN_RPM,
+ (void *)&min_rpm);
if (r)
return r;
@@ -2900,8 +3152,8 @@ static ssize_t amdgpu_hwmon_get_fan1_max(struct device *dev,
u32 max_rpm = 0;
int r;
- r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MAX_FAN_RPM,
- (void *)&max_rpm);
+ r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MAX_FAN_RPM,
+ (void *)&max_rpm);
if (r)
return r;
@@ -2917,18 +3169,13 @@ static ssize_t amdgpu_hwmon_get_fan1_target(struct device *dev,
int err;
u32 rpm = 0;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- err = pm_runtime_get_if_active(adev->dev);
- if (err <= 0)
- return err ?: -EPERM;
+ err = amdgpu_pm_get_access_if_active(adev);
+ if (err)
+ return err;
err = amdgpu_dpm_get_fan_speed_rpm(adev, &rpm);
- pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+ amdgpu_pm_put_access(adev);
if (err)
return err;
@@ -2945,16 +3192,11 @@ static ssize_t amdgpu_hwmon_set_fan1_target(struct device *dev,
u32 value;
u32 pwm_mode;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
err = kstrtou32(buf, 10, &value);
if (err)
return err;
- err = pm_runtime_resume_and_get(adev->dev);
+ err = amdgpu_pm_get_access(adev);
if (err < 0)
return err;
@@ -2970,8 +3212,7 @@ static ssize_t amdgpu_hwmon_set_fan1_target(struct device *dev,
err = amdgpu_dpm_set_fan_speed_rpm(adev, value);
out:
- pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
- pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+ amdgpu_pm_put_access(adev);
if (err)
return err;
@@ -2987,18 +3228,13 @@ static ssize_t amdgpu_hwmon_get_fan1_enable(struct device *dev,
u32 pwm_mode = 0;
int ret;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- ret = pm_runtime_get_if_active(adev->dev);
- if (ret <= 0)
- return ret ?: -EPERM;
+ ret = amdgpu_pm_get_access_if_active(adev);
+ if (ret)
+ return ret;
ret = amdgpu_dpm_get_fan_control_mode(adev, &pwm_mode);
- pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+ amdgpu_pm_put_access(adev);
if (ret)
return -EINVAL;
@@ -3016,11 +3252,6 @@ static ssize_t amdgpu_hwmon_set_fan1_enable(struct device *dev,
int value;
u32 pwm_mode;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
err = kstrtoint(buf, 10, &value);
if (err)
return err;
@@ -3032,14 +3263,13 @@ static ssize_t amdgpu_hwmon_set_fan1_enable(struct device *dev,
else
return -EINVAL;
- err = pm_runtime_resume_and_get(adev->dev);
+ err = amdgpu_pm_get_access(adev);
if (err < 0)
return err;
err = amdgpu_dpm_set_fan_control_mode(adev, pwm_mode);
- pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
- pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+ amdgpu_pm_put_access(adev);
if (err)
return -EINVAL;
@@ -3056,14 +3286,31 @@ static ssize_t amdgpu_hwmon_show_vddgfx(struct device *dev,
int r;
/* get the voltage */
- r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_VDDGFX,
- (void *)&vddgfx);
+ r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_VDDGFX,
+ (void *)&vddgfx);
if (r)
return r;
return sysfs_emit(buf, "%d\n", vddgfx);
}
+static ssize_t amdgpu_hwmon_show_vddboard(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct amdgpu_device *adev = dev_get_drvdata(dev);
+ u32 vddboard;
+ int r;
+
+ /* get the voltage */
+ r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_VDDBOARD,
+ (void *)&vddboard);
+ if (r)
+ return r;
+
+ return sysfs_emit(buf, "%d\n", vddboard);
+}
+
static ssize_t amdgpu_hwmon_show_vddgfx_label(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -3071,6 +3318,12 @@ static ssize_t amdgpu_hwmon_show_vddgfx_label(struct device *dev,
return sysfs_emit(buf, "vddgfx\n");
}
+static ssize_t amdgpu_hwmon_show_vddboard_label(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sysfs_emit(buf, "vddboard\n");
+}
static ssize_t amdgpu_hwmon_show_vddnb(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -3084,8 +3337,8 @@ static ssize_t amdgpu_hwmon_show_vddnb(struct device *dev,
return -EINVAL;
/* get the voltage */
- r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_VDDNB,
- (void *)&vddnb);
+ r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_VDDNB,
+ (void *)&vddnb);
if (r)
return r;
@@ -3103,18 +3356,15 @@ static int amdgpu_hwmon_get_power(struct device *dev,
enum amd_pp_sensors sensor)
{
struct amdgpu_device *adev = dev_get_drvdata(dev);
- unsigned int uw;
u32 query = 0;
int r;
- r = amdgpu_hwmon_get_sensor_generic(adev, sensor, (void *)&query);
+ r = amdgpu_pm_get_sensor_generic(adev, sensor, (void *)&query);
if (r)
return r;
/* convert to microwatts */
- uw = (query >> 8) * 1000000 + (query & 0xff) * 1000;
-
- return uw;
+ return power_2_mwatt(query) * 1000;
}
static ssize_t amdgpu_hwmon_show_power_avg(struct device *dev,
@@ -3154,14 +3404,9 @@ static ssize_t amdgpu_hwmon_show_power_cap_generic(struct device *dev,
ssize_t size;
int r;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- r = pm_runtime_get_if_active(adev->dev);
- if (r <= 0)
- return r ?: -EPERM;
+ r = amdgpu_pm_get_access_if_active(adev);
+ if (r)
+ return r;
r = amdgpu_dpm_get_power_limit(adev, &limit,
pp_limit_level, power_type);
@@ -3171,7 +3416,7 @@ static ssize_t amdgpu_hwmon_show_power_cap_generic(struct device *dev,
else
size = sysfs_emit(buf, "\n");
- pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+ amdgpu_pm_put_access(adev);
return size;
}
@@ -3219,7 +3464,9 @@ static ssize_t amdgpu_hwmon_show_power_label(struct device *dev,
to_sensor_dev_attr(attr)->index == PP_PWR_TYPE_FAST ?
"fastPPT" : "slowPPT");
else
- return sysfs_emit(buf, "PPT\n");
+ return sysfs_emit(buf, "%s\n",
+ to_sensor_dev_attr(attr)->index == PP_PWR_TYPE_FAST ?
+ "PPT1" : "PPT");
}
static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev,
@@ -3232,29 +3479,19 @@ static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev,
int err;
u32 value;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- if (amdgpu_sriov_vf(adev))
- return -EINVAL;
-
err = kstrtou32(buf, 10, &value);
if (err)
return err;
value = value / 1000000; /* convert to Watt */
- value |= limit_type << 24;
- err = pm_runtime_resume_and_get(adev->dev);
+ err = amdgpu_pm_get_access(adev);
if (err < 0)
return err;
- err = amdgpu_dpm_set_power_limit(adev, value);
+ err = amdgpu_dpm_set_power_limit(adev, limit_type, value);
- pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
- pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+ amdgpu_pm_put_access(adev);
if (err)
return err;
@@ -3271,8 +3508,8 @@ static ssize_t amdgpu_hwmon_show_sclk(struct device *dev,
int r;
/* get the sclk */
- r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GFX_SCLK,
- (void *)&sclk);
+ r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GFX_SCLK,
+ (void *)&sclk);
if (r)
return r;
@@ -3295,8 +3532,8 @@ static ssize_t amdgpu_hwmon_show_mclk(struct device *dev,
int r;
/* get the sclk */
- r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GFX_MCLK,
- (void *)&mclk);
+ r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GFX_MCLK,
+ (void *)&mclk);
if (r)
return r;
@@ -3425,6 +3662,8 @@ static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, amdgpu_hwmon_show_vddgfx, NULL, 0)
static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, amdgpu_hwmon_show_vddgfx_label, NULL, 0);
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, amdgpu_hwmon_show_vddnb, NULL, 0);
static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, amdgpu_hwmon_show_vddnb_label, NULL, 0);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, amdgpu_hwmon_show_vddboard, NULL, 0);
+static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, amdgpu_hwmon_show_vddboard_label, NULL, 0);
static SENSOR_DEVICE_ATTR(power1_average, S_IRUGO, amdgpu_hwmon_show_power_avg, NULL, 0);
static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, amdgpu_hwmon_show_power_input, NULL, 0);
static SENSOR_DEVICE_ATTR(power1_cap_max, S_IRUGO, amdgpu_hwmon_show_power_cap_max, NULL, 0);
@@ -3432,7 +3671,6 @@ static SENSOR_DEVICE_ATTR(power1_cap_min, S_IRUGO, amdgpu_hwmon_show_power_cap_m
static SENSOR_DEVICE_ATTR(power1_cap, S_IRUGO | S_IWUSR, amdgpu_hwmon_show_power_cap, amdgpu_hwmon_set_power_cap, 0);
static SENSOR_DEVICE_ATTR(power1_cap_default, S_IRUGO, amdgpu_hwmon_show_power_cap_default, NULL, 0);
static SENSOR_DEVICE_ATTR(power1_label, S_IRUGO, amdgpu_hwmon_show_power_label, NULL, 0);
-static SENSOR_DEVICE_ATTR(power2_average, S_IRUGO, amdgpu_hwmon_show_power_avg, NULL, 1);
static SENSOR_DEVICE_ATTR(power2_cap_max, S_IRUGO, amdgpu_hwmon_show_power_cap_max, NULL, 1);
static SENSOR_DEVICE_ATTR(power2_cap_min, S_IRUGO, amdgpu_hwmon_show_power_cap_min, NULL, 1);
static SENSOR_DEVICE_ATTR(power2_cap, S_IRUGO | S_IWUSR, amdgpu_hwmon_show_power_cap, amdgpu_hwmon_set_power_cap, 1);
@@ -3472,6 +3710,8 @@ static struct attribute *hwmon_attributes[] = {
&sensor_dev_attr_in0_label.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_in1_label.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_label.dev_attr.attr,
&sensor_dev_attr_power1_average.dev_attr.attr,
&sensor_dev_attr_power1_input.dev_attr.attr,
&sensor_dev_attr_power1_cap_max.dev_attr.attr,
@@ -3479,7 +3719,6 @@ static struct attribute *hwmon_attributes[] = {
&sensor_dev_attr_power1_cap.dev_attr.attr,
&sensor_dev_attr_power1_cap_default.dev_attr.attr,
&sensor_dev_attr_power1_label.dev_attr.attr,
- &sensor_dev_attr_power2_average.dev_attr.attr,
&sensor_dev_attr_power2_cap_max.dev_attr.attr,
&sensor_dev_attr_power2_cap_min.dev_attr.attr,
&sensor_dev_attr_power2_cap.dev_attr.attr,
@@ -3532,7 +3771,7 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
/* Skip crit temp on APU */
if ((((adev->flags & AMD_IS_APU) && (adev->family >= AMDGPU_FAMILY_CZ)) ||
- (gc_ver == IP_VERSION(9, 4, 3) || gc_ver == IP_VERSION(9, 4, 4))) &&
+ amdgpu_is_multi_aid(adev)) &&
(attr == &sensor_dev_attr_temp1_crit.dev_attr.attr ||
attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr))
return 0;
@@ -3566,14 +3805,20 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
effective_mode &= ~S_IWUSR;
/* not implemented yet for APUs other than GC 10.3.1 (vangogh) and 9.4.3 */
- if (((adev->family == AMDGPU_FAMILY_SI) ||
- ((adev->flags & AMD_IS_APU) && (gc_ver != IP_VERSION(10, 3, 1)) &&
- (gc_ver != IP_VERSION(9, 4, 3) && gc_ver != IP_VERSION(9, 4, 4)))) &&
- (attr == &sensor_dev_attr_power1_cap_max.dev_attr.attr ||
- attr == &sensor_dev_attr_power1_cap_min.dev_attr.attr ||
- attr == &sensor_dev_attr_power1_cap.dev_attr.attr ||
- attr == &sensor_dev_attr_power1_cap_default.dev_attr.attr))
- return 0;
+ if (attr == &sensor_dev_attr_power1_cap_max.dev_attr.attr ||
+ attr == &sensor_dev_attr_power1_cap_min.dev_attr.attr ||
+ attr == &sensor_dev_attr_power1_cap.dev_attr.attr ||
+ attr == &sensor_dev_attr_power1_cap_default.dev_attr.attr) {
+ if (adev->family == AMDGPU_FAMILY_SI ||
+ ((adev->flags & AMD_IS_APU) && gc_ver != IP_VERSION(10, 3, 1) &&
+ (gc_ver != IP_VERSION(9, 4, 3) && gc_ver != IP_VERSION(9, 4, 4))) ||
+ (amdgpu_sriov_vf(adev) && gc_ver == IP_VERSION(11, 0, 3)))
+ return 0;
+ }
+
+ if (attr == &sensor_dev_attr_power1_cap.dev_attr.attr &&
+ amdgpu_virt_cap_is_rw(&adev->virt.virt_caps, AMDGPU_VIRT_CAP_POWER_LIMIT))
+ effective_mode |= S_IWUSR;
/* not implemented yet for APUs having < GC 9.3.0 (Renoir) */
if (((adev->family == AMDGPU_FAMILY_SI) ||
@@ -3583,10 +3828,12 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
/* not all products support both average and instantaneous */
if (attr == &sensor_dev_attr_power1_average.dev_attr.attr &&
- amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GPU_AVG_POWER, (void *)&tmp) == -EOPNOTSUPP)
+ amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GPU_AVG_POWER,
+ (void *)&tmp) == -EOPNOTSUPP)
return 0;
if (attr == &sensor_dev_attr_power1_input.dev_attr.attr &&
- amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GPU_INPUT_POWER, (void *)&tmp) == -EOPNOTSUPP)
+ amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GPU_INPUT_POWER,
+ (void *)&tmp) == -EOPNOTSUPP)
return 0;
/* hide max/min values if we can't both query and manage the fan */
@@ -3606,20 +3853,25 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
if ((adev->family == AMDGPU_FAMILY_SI || /* not implemented yet */
adev->family == AMDGPU_FAMILY_KV || /* not implemented yet */
- (gc_ver == IP_VERSION(9, 4, 3) ||
- gc_ver == IP_VERSION(9, 4, 4))) &&
+ amdgpu_is_multi_aid(adev)) &&
(attr == &sensor_dev_attr_in0_input.dev_attr.attr ||
attr == &sensor_dev_attr_in0_label.dev_attr.attr))
return 0;
/* only APUs other than gc 9,4,3 have vddnb */
if ((!(adev->flags & AMD_IS_APU) ||
- (gc_ver == IP_VERSION(9, 4, 3) ||
- gc_ver == IP_VERSION(9, 4, 4))) &&
+ amdgpu_is_multi_aid(adev)) &&
(attr == &sensor_dev_attr_in1_input.dev_attr.attr ||
attr == &sensor_dev_attr_in1_label.dev_attr.attr))
return 0;
+ /* only few boards support vddboard */
+ if ((attr == &sensor_dev_attr_in2_input.dev_attr.attr ||
+ attr == &sensor_dev_attr_in2_label.dev_attr.attr) &&
+ amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_VDDBOARD,
+ (void *)&tmp) == -EOPNOTSUPP)
+ return 0;
+
/* no mclk on APUs other than gc 9,4,3*/
if (((adev->flags & AMD_IS_APU) && (gc_ver != IP_VERSION(9, 4, 3))) &&
(attr == &sensor_dev_attr_freq2_input.dev_attr.attr ||
@@ -3637,8 +3889,7 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
return 0;
/* hotspot temperature for gc 9,4,3*/
- if (gc_ver == IP_VERSION(9, 4, 3) ||
- gc_ver == IP_VERSION(9, 4, 4)) {
+ if (amdgpu_is_multi_aid(adev)) {
if (attr == &sensor_dev_attr_temp1_input.dev_attr.attr ||
attr == &sensor_dev_attr_temp1_emergency.dev_attr.attr ||
attr == &sensor_dev_attr_temp1_label.dev_attr.attr)
@@ -3658,14 +3909,15 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
attr == &sensor_dev_attr_temp3_emergency.dev_attr.attr))
return 0;
- /* only Vangogh has fast PPT limit and power labels */
- if (!(gc_ver == IP_VERSION(10, 3, 1)) &&
- (attr == &sensor_dev_attr_power2_average.dev_attr.attr ||
- attr == &sensor_dev_attr_power2_cap_max.dev_attr.attr ||
+ /* only a few GPUs have fast PPT limit and power labels */
+ if ((attr == &sensor_dev_attr_power2_cap_max.dev_attr.attr ||
attr == &sensor_dev_attr_power2_cap_min.dev_attr.attr ||
attr == &sensor_dev_attr_power2_cap.dev_attr.attr ||
attr == &sensor_dev_attr_power2_cap_default.dev_attr.attr ||
- attr == &sensor_dev_attr_power2_label.dev_attr.attr))
+ attr == &sensor_dev_attr_power2_label.dev_attr.attr) &&
+ (amdgpu_dpm_get_power_limit(adev, &tmp,
+ PP_PWR_LIMIT_MAX,
+ PP_PWR_TYPE_FAST) == -EOPNOTSUPP))
return 0;
return effective_mode;
@@ -3688,20 +3940,20 @@ static int amdgpu_retrieve_od_settings(struct amdgpu_device *adev,
int size = 0;
int ret;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- ret = pm_runtime_get_if_active(adev->dev);
- if (ret <= 0)
- return ret ?: -EPERM;
+ ret = amdgpu_pm_get_access_if_active(adev);
+ if (ret)
+ return ret;
- size = amdgpu_dpm_print_clock_levels(adev, od_type, buf);
+ ret = amdgpu_dpm_emit_clock_levels(adev, od_type, buf, &size);
+ if (ret) {
+ size = ret;
+ goto out_pm_put;
+ }
if (size == 0)
size = sysfs_emit(buf, "\n");
- pm_runtime_put_autosuspend(adev->dev);
+out_pm_put:
+ amdgpu_pm_put_access(adev);
return size;
}
@@ -3710,6 +3962,7 @@ static int parse_input_od_command_lines(const char *buf,
size_t count,
u32 *type,
long *params,
+ size_t params_max,
uint32_t *num_of_params)
{
const char delimiter[3] = {' ', '\n', '\0'};
@@ -3745,11 +3998,17 @@ static int parse_input_od_command_lines(const char *buf,
if (strlen(sub_str) == 0)
continue;
+ if (parameter_size >= params_max)
+ return -EINVAL;
+
ret = kstrtol(sub_str, 0, &params[parameter_size]);
if (ret)
return -EINVAL;
parameter_size++;
+ if (!tmp_str)
+ break;
+
while (isspace(*tmp_str))
tmp_str++;
}
@@ -3769,20 +4028,16 @@ amdgpu_distribute_custom_od_settings(struct amdgpu_device *adev,
long parameter[64];
int ret;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
ret = parse_input_od_command_lines(in_buf,
count,
&cmd_type,
parameter,
+ ARRAY_SIZE(parameter),
&parameter_size);
if (ret)
return ret;
- ret = pm_runtime_resume_and_get(adev->dev);
+ ret = amdgpu_pm_get_access(adev);
if (ret < 0)
return ret;
@@ -3801,14 +4056,12 @@ amdgpu_distribute_custom_od_settings(struct amdgpu_device *adev,
goto err_out;
}
- pm_runtime_mark_last_busy(adev->dev);
- pm_runtime_put_autosuspend(adev->dev);
+ amdgpu_pm_put_access(adev);
return count;
err_out:
- pm_runtime_mark_last_busy(adev->dev);
- pm_runtime_put_autosuspend(adev->dev);
+ amdgpu_pm_put_access(adev);
return ret;
}
@@ -4379,7 +4632,7 @@ static int amdgpu_od_set_init(struct amdgpu_device *adev)
int ret;
/* Setup the top `gpu_od` directory which holds all other OD interfaces */
- top_set = kzalloc(sizeof(*top_set), GFP_KERNEL);
+ top_set = kzalloc_obj(*top_set);
if (!top_set)
return -ENOMEM;
list_add(&top_set->entry, &adev->pm.od_kobj_list);
@@ -4416,7 +4669,7 @@ static int amdgpu_od_set_init(struct amdgpu_device *adev)
* The container is presented as a plain file under top `gpu_od`
* directory.
*/
- attribute = kzalloc(sizeof(*attribute), GFP_KERNEL);
+ attribute = kzalloc_obj(*attribute);
if (!attribute) {
ret = -ENOMEM;
goto err_out;
@@ -4436,7 +4689,7 @@ static int amdgpu_od_set_init(struct amdgpu_device *adev)
goto err_out;
} else {
/* The container is presented as a sub directory. */
- sub_set = kzalloc(sizeof(*sub_set), GFP_KERNEL);
+ sub_set = kzalloc_obj(*sub_set);
if (!sub_set) {
ret = -ENOMEM;
goto err_out;
@@ -4466,7 +4719,7 @@ static int amdgpu_od_set_init(struct amdgpu_device *adev)
* With the container presented as a sub directory, the entry within
* it is presented as a plain file under the sub directory.
*/
- attribute = kzalloc(sizeof(*attribute), GFP_KERNEL);
+ attribute = kzalloc_obj(*attribute);
if (!attribute) {
ret = -ENOMEM;
goto err_out;
@@ -4507,6 +4760,7 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
{
enum amdgpu_sriov_vf_mode mode;
uint32_t mask = 0;
+ uint32_t tmp;
int ret;
if (adev->pm.sysfs_initialized)
@@ -4565,7 +4819,37 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
ret = devm_device_add_group(adev->dev,
&amdgpu_pm_policy_attr_group);
if (ret)
- goto err_out0;
+ goto err_out1;
+ }
+
+ if (amdgpu_dpm_is_temp_metrics_supported(adev, SMU_TEMP_METRIC_GPUBOARD)) {
+ ret = devm_device_add_group(adev->dev,
+ &amdgpu_board_attr_group);
+ if (ret)
+ goto err_out1;
+ if (amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MAXNODEPOWERLIMIT,
+ (void *)&tmp) != -EOPNOTSUPP) {
+ sysfs_add_file_to_group(&adev->dev->kobj,
+ &dev_attr_cur_node_power_limit.attr,
+ amdgpu_board_attr_group.name);
+ sysfs_add_file_to_group(&adev->dev->kobj, &dev_attr_node_power.attr,
+ amdgpu_board_attr_group.name);
+ sysfs_add_file_to_group(&adev->dev->kobj, &dev_attr_global_ppt_resid.attr,
+ amdgpu_board_attr_group.name);
+ sysfs_add_file_to_group(&adev->dev->kobj,
+ &dev_attr_max_node_power_limit.attr,
+ amdgpu_board_attr_group.name);
+ sysfs_add_file_to_group(&adev->dev->kobj, &dev_attr_npm_status.attr,
+ amdgpu_board_attr_group.name);
+ }
+ if (amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_UBB_POWER_LIMIT,
+ (void *)&tmp) != -EOPNOTSUPP) {
+ sysfs_add_file_to_group(&adev->dev->kobj,
+ &dev_attr_baseboard_power_limit.attr,
+ amdgpu_board_attr_group.name);
+ sysfs_add_file_to_group(&adev->dev->kobj, &dev_attr_baseboard_power.attr,
+ amdgpu_board_attr_group.name);
+ }
}
adev->pm.sysfs_initialized = true;
@@ -4623,7 +4907,7 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a
{
uint32_t mp1_ver = amdgpu_ip_version(adev, MP1_HWIP, 0);
uint32_t gc_ver = amdgpu_ip_version(adev, GC_HWIP, 0);
- uint32_t value;
+ uint32_t value, mwatt, centiwatt;
uint64_t value64 = 0;
uint32_t query = 0;
int size;
@@ -4648,17 +4932,21 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a
seq_printf(m, "\t%u mV (VDDNB)\n", value);
size = sizeof(uint32_t);
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_AVG_POWER, (void *)&query, &size)) {
+ mwatt = power_2_mwatt(query);
+ centiwatt = DIV_ROUND_CLOSEST(mwatt, 10);
if (adev->flags & AMD_IS_APU)
- seq_printf(m, "\t%u.%02u W (average SoC including CPU)\n", query >> 8, query & 0xff);
+ seq_printf(m, "\t%u.%02u W (average SoC including CPU)\n", centiwatt / 100, centiwatt % 100);
else
- seq_printf(m, "\t%u.%02u W (average SoC)\n", query >> 8, query & 0xff);
+ seq_printf(m, "\t%u.%02u W (average SoC)\n", centiwatt / 100, centiwatt % 100);
}
size = sizeof(uint32_t);
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_INPUT_POWER, (void *)&query, &size)) {
+ mwatt = power_2_mwatt(query);
+ centiwatt = DIV_ROUND_CLOSEST(mwatt, 10);
if (adev->flags & AMD_IS_APU)
- seq_printf(m, "\t%u.%02u W (current SoC including CPU)\n", query >> 8, query & 0xff);
+ seq_printf(m, "\t%u.%02u W (current SoC including CPU)\n", centiwatt / 100, centiwatt % 100);
else
- seq_printf(m, "\t%u.%02u W (current SoC)\n", query >> 8, query & 0xff);
+ seq_printf(m, "\t%u.%02u W (current SoC)\n", centiwatt / 100, centiwatt % 100);
}
size = sizeof(value);
seq_printf(m, "\n");
@@ -4778,16 +5066,10 @@ static void amdgpu_parse_cg_state(struct seq_file *m, u64 flags)
static int amdgpu_debugfs_pm_info_show(struct seq_file *m, void *unused)
{
struct amdgpu_device *adev = (struct amdgpu_device *)m->private;
- struct drm_device *dev = adev_to_drm(adev);
u64 flags = 0;
int r;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- r = pm_runtime_resume_and_get(dev->dev);
+ r = amdgpu_pm_get_access(adev);
if (r < 0)
return r;
@@ -4804,7 +5086,7 @@ static int amdgpu_debugfs_pm_info_show(struct seq_file *m, void *unused)
seq_printf(m, "\n");
out:
- pm_runtime_put_autosuspend(dev->dev);
+ amdgpu_pm_put_access(adev);
return r;
}
@@ -4824,10 +5106,9 @@ static ssize_t amdgpu_pm_prv_buffer_read(struct file *f, char __user *buf,
void *smu_prv_buf;
int ret = 0;
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
+ ret = amdgpu_pm_dev_state_check(adev, true);
+ if (ret)
+ return ret;
ret = amdgpu_dpm_get_smu_prv_buf_details(adev, &smu_prv_buf, &smu_prv_buf_size);
if (ret)
diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
index 1f5ac7e0230d..aa3f427819a0 100644
--- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
+++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
@@ -263,10 +263,6 @@ struct amdgpu_dpm {
u32 voltage_response_time;
u32 backbias_response_time;
void *priv;
- u32 new_active_crtcs;
- int new_active_crtc_count;
- u32 current_active_crtcs;
- int current_active_crtc_count;
struct amdgpu_dpm_dynamic_state dyn_state;
struct amdgpu_dpm_fan fan;
u32 tdp_limit;
@@ -295,7 +291,8 @@ enum ip_power_state {
};
/* Used to mask smu debug modes */
-#define SMU_DEBUG_HALT_ON_ERROR 0x1
+#define SMU_DEBUG_HALT_ON_ERROR BIT(0)
+#define SMU_DEBUG_POOL_USE_VRAM BIT(1)
#define MAX_SMU_I2C_BUSES 2
@@ -409,22 +406,24 @@ int amdgpu_dpm_set_xgmi_pstate(struct amdgpu_device *adev,
int amdgpu_dpm_switch_power_profile(struct amdgpu_device *adev,
enum PP_SMC_POWER_PROFILE type,
bool en);
+int amdgpu_dpm_pause_power_profile(struct amdgpu_device *adev,
+ bool pause);
int amdgpu_dpm_baco_reset(struct amdgpu_device *adev);
int amdgpu_dpm_mode2_reset(struct amdgpu_device *adev);
+int amdgpu_dpm_link_reset(struct amdgpu_device *adev);
int amdgpu_dpm_enable_gfx_features(struct amdgpu_device *adev);
int amdgpu_dpm_is_baco_supported(struct amdgpu_device *adev);
bool amdgpu_dpm_is_mode1_reset_supported(struct amdgpu_device *adev);
+bool amdgpu_dpm_is_link_reset_supported(struct amdgpu_device *adev);
int amdgpu_dpm_mode1_reset(struct amdgpu_device *adev);
int amdgpu_dpm_set_mp1_state(struct amdgpu_device *adev,
enum pp_mp1_state mp1_state);
-int amdgpu_dpm_notify_rlc_state(struct amdgpu_device *adev, bool en);
-
int amdgpu_dpm_set_gfx_power_up_by_imu(struct amdgpu_device *adev);
int amdgpu_dpm_baco_exit(struct amdgpu_device *adev);
@@ -519,6 +518,10 @@ int amdgpu_dpm_get_power_profile_mode(struct amdgpu_device *adev,
int amdgpu_dpm_set_power_profile_mode(struct amdgpu_device *adev,
long *input, uint32_t size);
int amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void **table);
+ssize_t amdgpu_dpm_get_xcp_metrics(struct amdgpu_device *adev, int xcp_id,
+ void *table);
+ssize_t amdgpu_dpm_get_temp_metrics(struct amdgpu_device *adev,
+ enum smu_temp_metric_type type, void *table);
/**
* @get_pm_metrics: Get one snapshot of power management metrics from PMFW. The
@@ -548,7 +551,7 @@ int amdgpu_dpm_get_power_limit(struct amdgpu_device *adev,
enum pp_power_limit_level pp_limit_level,
enum pp_power_type power_type);
int amdgpu_dpm_set_power_limit(struct amdgpu_device *adev,
- uint32_t limit);
+ uint32_t limit_type, uint32_t limit);
int amdgpu_dpm_is_cclk_dpm_supported(struct amdgpu_device *adev);
int amdgpu_dpm_debugfs_print_current_performance_level(struct amdgpu_device *adev,
struct seq_file *m);
@@ -556,6 +559,7 @@ int amdgpu_dpm_get_smu_prv_buf_details(struct amdgpu_device *adev,
void **addr,
size_t *size);
int amdgpu_dpm_is_overdrive_supported(struct amdgpu_device *adev);
+int amdgpu_dpm_is_overdrive_enabled(struct amdgpu_device *adev);
int amdgpu_dpm_set_pp_table(struct amdgpu_device *adev,
const char *buf,
size_t size);
@@ -603,5 +607,11 @@ int amdgpu_dpm_set_pm_policy(struct amdgpu_device *adev, int policy_type,
ssize_t amdgpu_dpm_get_pm_policy_info(struct amdgpu_device *adev,
enum pp_pm_policy p_type, char *buf);
int amdgpu_dpm_reset_sdma(struct amdgpu_device *adev, uint32_t inst_mask);
+bool amdgpu_dpm_reset_sdma_is_supported(struct amdgpu_device *adev);
+int amdgpu_dpm_reset_vcn(struct amdgpu_device *adev, uint32_t inst_mask);
+bool amdgpu_dpm_reset_vcn_is_supported(struct amdgpu_device *adev);
+bool amdgpu_dpm_is_temp_metrics_supported(struct amdgpu_device *adev,
+ enum smu_temp_metric_type type);
+const struct ras_smu_drv *amdgpu_dpm_get_ras_smu_driver(struct amdgpu_device *adev);
#endif
diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm_internal.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm_internal.h
index 5c2a89f0d5d5..cc6d7ba040e9 100644
--- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm_internal.h
+++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm_internal.h
@@ -23,10 +23,6 @@
#ifndef __AMDGPU_DPM_INTERNAL_H__
#define __AMDGPU_DPM_INTERNAL_H__
-void amdgpu_dpm_get_active_displays(struct amdgpu_device *adev);
-
-u32 amdgpu_dpm_get_vblank_time(struct amdgpu_device *adev);
-
-u32 amdgpu_dpm_get_vrefresh(struct amdgpu_device *adev);
+void amdgpu_dpm_get_display_cfg(struct amdgpu_device *adev);
#endif
diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
index e237ea1185a7..b763fdf43c60 100644
--- a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
+++ b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
@@ -1233,16 +1233,16 @@ static void kv_update_requested_ps(struct amdgpu_device *adev,
adev->pm.dpm.requested_ps = &pi->requested_rps;
}
-static void kv_dpm_enable_bapm(void *handle, bool enable)
+static void kv_dpm_enable_bapm(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
struct kv_power_info *pi = kv_get_pi(adev);
int ret;
if (pi->bapm_enable) {
- ret = amdgpu_kv_smc_bapm_enable(adev, enable);
+ ret = amdgpu_kv_smc_bapm_enable(adev, adev->pm.ac_power);
if (ret)
- DRM_ERROR("amdgpu_kv_smc_bapm_enable failed\n");
+ drm_err(adev_to_drm(adev), "amdgpu_kv_smc_bapm_enable failed\n");
}
}
@@ -1266,40 +1266,40 @@ static int kv_dpm_enable(struct amdgpu_device *adev)
ret = kv_process_firmware_header(adev);
if (ret) {
- DRM_ERROR("kv_process_firmware_header failed\n");
+ drm_err(adev_to_drm(adev), "kv_process_firmware_header failed\n");
return ret;
}
kv_init_fps_limits(adev);
kv_init_graphics_levels(adev);
ret = kv_program_bootup_state(adev);
if (ret) {
- DRM_ERROR("kv_program_bootup_state failed\n");
+ drm_err(adev_to_drm(adev), "kv_program_bootup_state failed\n");
return ret;
}
kv_calculate_dfs_bypass_settings(adev);
ret = kv_upload_dpm_settings(adev);
if (ret) {
- DRM_ERROR("kv_upload_dpm_settings failed\n");
+ drm_err(adev_to_drm(adev), "kv_upload_dpm_settings failed\n");
return ret;
}
ret = kv_populate_uvd_table(adev);
if (ret) {
- DRM_ERROR("kv_populate_uvd_table failed\n");
+ drm_err(adev_to_drm(adev), "kv_populate_uvd_table failed\n");
return ret;
}
ret = kv_populate_vce_table(adev);
if (ret) {
- DRM_ERROR("kv_populate_vce_table failed\n");
+ drm_err(adev_to_drm(adev), "kv_populate_vce_table failed\n");
return ret;
}
ret = kv_populate_samu_table(adev);
if (ret) {
- DRM_ERROR("kv_populate_samu_table failed\n");
+ drm_err(adev_to_drm(adev), "kv_populate_samu_table failed\n");
return ret;
}
ret = kv_populate_acp_table(adev);
if (ret) {
- DRM_ERROR("kv_populate_acp_table failed\n");
+ drm_err(adev_to_drm(adev), "kv_populate_acp_table failed\n");
return ret;
}
kv_program_vc(adev);
@@ -1310,39 +1310,39 @@ static int kv_dpm_enable(struct amdgpu_device *adev)
if (pi->enable_auto_thermal_throttling) {
ret = kv_enable_auto_thermal_throttling(adev);
if (ret) {
- DRM_ERROR("kv_enable_auto_thermal_throttling failed\n");
+ drm_err(adev_to_drm(adev), "kv_enable_auto_thermal_throttling failed\n");
return ret;
}
}
ret = kv_enable_dpm_voltage_scaling(adev);
if (ret) {
- DRM_ERROR("kv_enable_dpm_voltage_scaling failed\n");
+ drm_err(adev_to_drm(adev), "kv_enable_dpm_voltage_scaling failed\n");
return ret;
}
ret = kv_set_dpm_interval(adev);
if (ret) {
- DRM_ERROR("kv_set_dpm_interval failed\n");
+ drm_err(adev_to_drm(adev), "kv_set_dpm_interval failed\n");
return ret;
}
ret = kv_set_dpm_boot_state(adev);
if (ret) {
- DRM_ERROR("kv_set_dpm_boot_state failed\n");
+ drm_err(adev_to_drm(adev), "kv_set_dpm_boot_state failed\n");
return ret;
}
ret = kv_enable_ulv(adev, true);
if (ret) {
- DRM_ERROR("kv_enable_ulv failed\n");
+ drm_err(adev_to_drm(adev), "kv_enable_ulv failed\n");
return ret;
}
kv_start_dpm(adev);
ret = kv_enable_didt(adev, true);
if (ret) {
- DRM_ERROR("kv_enable_didt failed\n");
+ drm_err(adev_to_drm(adev), "kv_enable_didt failed\n");
return ret;
}
ret = kv_enable_smc_cac(adev, true);
if (ret) {
- DRM_ERROR("kv_enable_smc_cac failed\n");
+ drm_err(adev_to_drm(adev), "kv_enable_smc_cac failed\n");
return ret;
}
@@ -1350,7 +1350,7 @@ static int kv_dpm_enable(struct amdgpu_device *adev)
ret = amdgpu_kv_smc_bapm_enable(adev, false);
if (ret) {
- DRM_ERROR("amdgpu_kv_smc_bapm_enable failed\n");
+ drm_err(adev_to_drm(adev), "amdgpu_kv_smc_bapm_enable failed\n");
return ret;
}
@@ -1358,7 +1358,7 @@ static int kv_dpm_enable(struct amdgpu_device *adev)
kv_is_internal_thermal_sensor(adev->pm.int_thermal_type)) {
ret = kv_set_thermal_temperature_range(adev, KV_TEMP_RANGE_MIN, KV_TEMP_RANGE_MAX);
if (ret) {
- DRM_ERROR("kv_set_thermal_temperature_range failed\n");
+ drm_err(adev_to_drm(adev), "kv_set_thermal_temperature_range failed\n");
return ret;
}
amdgpu_irq_get(adev, &adev->pm.dpm.thermal.irq,
@@ -1382,7 +1382,7 @@ static void kv_dpm_disable(struct amdgpu_device *adev)
err = amdgpu_kv_smc_bapm_enable(adev, false);
if (err)
- DRM_ERROR("amdgpu_kv_smc_bapm_enable failed\n");
+ drm_err(adev_to_drm(adev), "amdgpu_kv_smc_bapm_enable failed\n");
if (adev->asic_type == CHIP_MULLINS)
kv_enable_nb_dpm(adev, false);
@@ -1920,7 +1920,7 @@ static int kv_dpm_set_power_state(void *handle)
if (pi->bapm_enable) {
ret = amdgpu_kv_smc_bapm_enable(adev, adev->pm.ac_power);
if (ret) {
- DRM_ERROR("amdgpu_kv_smc_bapm_enable failed\n");
+ drm_err(adev_to_drm(adev), "amdgpu_kv_smc_bapm_enable failed\n");
return ret;
}
}
@@ -1931,7 +1931,7 @@ static int kv_dpm_set_power_state(void *handle)
kv_update_dfs_bypass_settings(adev, new_ps);
ret = kv_calculate_ds_divider(adev);
if (ret) {
- DRM_ERROR("kv_calculate_ds_divider failed\n");
+ drm_err(adev_to_drm(adev), "kv_calculate_ds_divider failed\n");
return ret;
}
kv_calculate_nbps_level_settings(adev);
@@ -1947,7 +1947,7 @@ static int kv_dpm_set_power_state(void *handle)
ret = kv_update_vce_dpm(adev, new_ps, old_ps);
if (ret) {
- DRM_ERROR("kv_update_vce_dpm failed\n");
+ drm_err(adev_to_drm(adev), "kv_update_vce_dpm failed\n");
return ret;
}
kv_update_sclk_t(adev);
@@ -1960,7 +1960,7 @@ static int kv_dpm_set_power_state(void *handle)
kv_update_dfs_bypass_settings(adev, new_ps);
ret = kv_calculate_ds_divider(adev);
if (ret) {
- DRM_ERROR("kv_calculate_ds_divider failed\n");
+ drm_err(adev_to_drm(adev), "kv_calculate_ds_divider failed\n");
return ret;
}
kv_calculate_nbps_level_settings(adev);
@@ -1972,7 +1972,7 @@ static int kv_dpm_set_power_state(void *handle)
kv_set_enabled_levels(adev);
ret = kv_update_vce_dpm(adev, new_ps, old_ps);
if (ret) {
- DRM_ERROR("kv_update_vce_dpm failed\n");
+ drm_err(adev_to_drm(adev), "kv_update_vce_dpm failed\n");
return ret;
}
kv_update_acp_boot_level(adev);
@@ -2299,7 +2299,7 @@ static void kv_apply_state_adjust_rules(struct amdgpu_device *adev,
if (pi->sys_info.nb_dpm_enable) {
force_high = (mclk >= pi->sys_info.nbp_memory_clock[3]) ||
- pi->video_start || (adev->pm.dpm.new_active_crtc_count >= 3) ||
+ pi->video_start || (adev->pm.pm_display_cfg.num_display >= 3) ||
pi->disable_nb_ps3_in_battery;
ps->dpm0_pg_nb_ps_lo = force_high ? 0x2 : 0x3;
ps->dpm0_pg_nb_ps_hi = 0x2;
@@ -2358,7 +2358,7 @@ static int kv_calculate_nbps_level_settings(struct amdgpu_device *adev)
return 0;
force_high = ((mclk >= pi->sys_info.nbp_memory_clock[3]) ||
- (adev->pm.dpm.new_active_crtc_count >= 3) || pi->video_start);
+ (adev->pm.pm_display_cfg.num_display >= 3) || pi->video_start);
if (force_high) {
for (i = pi->lowest_valid; i <= pi->highest_valid; i++)
@@ -2521,7 +2521,7 @@ static int kv_set_thermal_temperature_range(struct amdgpu_device *adev,
if (high_temp > max_temp)
high_temp = max_temp;
if (high_temp < low_temp) {
- DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
+ drm_err(adev_to_drm(adev), "invalid thermal range: %d - %d\n", low_temp, high_temp);
return -EINVAL;
}
@@ -2563,7 +2563,7 @@ static int kv_parse_sys_info_table(struct amdgpu_device *adev)
data_offset);
if (crev != 8) {
- DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
+ drm_err(adev_to_drm(adev), "Unsupported IGP table: %d %d\n", frev, crev);
return -EINVAL;
}
pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_8.ulBootUpEngineClock);
@@ -2579,7 +2579,7 @@ static int kv_parse_sys_info_table(struct amdgpu_device *adev)
else
pi->sys_info.htc_hyst_lmt = igp_info->info_8.ucHtcHystLmt;
if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) {
- DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n");
+ drm_err(adev_to_drm(adev), "The htcTmpLmt should be larger than htcHystLmt.\n");
}
if (le32_to_cpu(igp_info->info_8.ulSystemConfig) & (1 << 3))
@@ -2594,7 +2594,7 @@ static int kv_parse_sys_info_table(struct amdgpu_device *adev)
le32_to_cpu(igp_info->info_8.ulNbpStateNClkFreq[i]);
}
if (le32_to_cpu(igp_info->info_8.ulGPUCapInfo) &
- SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS)
+ SYS_INFO_GPUCAPS__ENABLE_DFS_BYPASS)
pi->caps_enable_dfs_bypass = true;
sumo_construct_sclk_voltage_mapping_table(adev,
@@ -2724,9 +2724,8 @@ static int kv_parse_power_table(struct amdgpu_device *adev)
(mode_info->atom_context->bios + data_offset +
le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
- adev->pm.dpm.ps = kcalloc(state_array->ucNumEntries,
- sizeof(struct amdgpu_ps),
- GFP_KERNEL);
+ adev->pm.dpm.ps = kzalloc_objs(struct amdgpu_ps,
+ state_array->ucNumEntries);
if (!adev->pm.dpm.ps)
return -ENOMEM;
power_state_offset = (u8 *)state_array->states;
@@ -2736,7 +2735,7 @@ static int kv_parse_power_table(struct amdgpu_device *adev)
non_clock_array_index = power_state->v2.nonClockInfoIndex;
non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
&non_clock_info_array->nonClockInfo[non_clock_array_index];
- ps = kzalloc(sizeof(struct kv_ps), GFP_KERNEL);
+ ps = kzalloc_obj(struct kv_ps);
if (ps == NULL)
return -ENOMEM;
adev->pm.dpm.ps[i].ps_priv = ps;
@@ -2783,7 +2782,7 @@ static int kv_dpm_init(struct amdgpu_device *adev)
struct kv_power_info *pi;
int ret, i;
- pi = kzalloc(sizeof(struct kv_power_info), GFP_KERNEL);
+ pi = kzalloc_obj(struct kv_power_info);
if (pi == NULL)
return -ENOMEM;
adev->pm.dpm.priv = pi;
@@ -2886,16 +2885,18 @@ kv_dpm_print_power_state(void *handle, void *request_ps)
struct kv_ps *ps = kv_get_ps(rps);
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- amdgpu_dpm_print_class_info(rps->class, rps->class2);
- amdgpu_dpm_print_cap_info(rps->caps);
- printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+ amdgpu_dpm_dbg_print_class_info(adev, rps->class, rps->class2);
+ amdgpu_dpm_dbg_print_cap_info(adev, rps->caps);
+ drm_dbg(adev_to_drm(adev), "vclk: %d, dclk: %d\n",
+ rps->vclk, rps->dclk);
for (i = 0; i < ps->num_levels; i++) {
struct kv_pl *pl = &ps->levels[i];
- printk("\t\tpower level %d sclk: %u vddc: %u\n",
- i, pl->sclk,
- kv_convert_8bit_index_to_voltage(adev, pl->vddc_index));
+ drm_dbg(adev_to_drm(adev),
+ "power level %d sclk: %u vddc: %u\n",
+ i, pl->sclk,
+ kv_convert_8bit_index_to_voltage(adev, pl->vddc_index));
}
- amdgpu_dpm_print_ps_status(adev, rps);
+ amdgpu_dpm_dbg_print_ps_status(adev, rps);
}
static void kv_dpm_fini(struct amdgpu_device *adev)
@@ -3013,13 +3014,13 @@ static int kv_dpm_sw_init(struct amdgpu_ip_block *ip_block)
adev->pm.dpm.current_ps = adev->pm.dpm.requested_ps = adev->pm.dpm.boot_ps;
if (amdgpu_dpm == 1)
amdgpu_pm_print_power_states(adev);
- DRM_INFO("amdgpu: dpm initialized\n");
+ drm_info(adev_to_drm(adev), "dpm initialized\n");
return 0;
dpm_failed:
kv_dpm_fini(adev);
- DRM_ERROR("amdgpu: dpm initialization failed\n");
+ drm_err(adev_to_drm(adev), "dpm initialization failed: %d\n", ret);
return ret;
}
@@ -3107,7 +3108,7 @@ static int kv_dpm_resume(struct amdgpu_ip_block *ip_block)
return ret;
}
-static bool kv_dpm_is_idle(void *handle)
+static bool kv_dpm_is_idle(struct amdgpu_ip_block *ip_block)
{
return true;
}
@@ -3340,7 +3341,7 @@ static const struct amd_pm_funcs kv_dpm_funcs = {
.debugfs_print_current_performance_level = &kv_dpm_debugfs_print_current_performance_level,
.force_performance_level = &kv_dpm_force_performance_level,
.set_powergating_by_smu = kv_set_powergating_by_smu,
- .enable_bapm = &kv_dpm_enable_bapm,
+ .notify_ac_dc = &kv_dpm_enable_bapm,
.get_vce_clock_state = amdgpu_get_vce_clock_state,
.check_state_equal = kv_check_state_equal,
.read_sensor = &kv_dpm_read_sensor,
diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c
index c7518b13e787..6362a14b1a6e 100644
--- a/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c
+++ b/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c
@@ -47,7 +47,7 @@
#define amdgpu_dpm_check_state_equal(adev, cps, rps, equal) \
((adev)->powerplay.pp_funcs->check_state_equal((adev)->powerplay.pp_handle, (cps), (rps), (equal)))
-void amdgpu_dpm_print_class_info(u32 class, u32 class2)
+void amdgpu_dpm_dbg_print_class_info(struct amdgpu_device *adev, u32 class, u32 class2)
{
const char *s;
@@ -66,71 +66,45 @@ void amdgpu_dpm_print_class_info(u32 class, u32 class2)
s = "performance";
break;
}
- printk("\tui class: %s\n", s);
- printk("\tinternal class:");
+ drm_dbg(adev_to_drm(adev), "\tui class: %s\n", s);
if (((class & ~ATOM_PPLIB_CLASSIFICATION_UI_MASK) == 0) &&
(class2 == 0))
- pr_cont(" none");
- else {
- if (class & ATOM_PPLIB_CLASSIFICATION_BOOT)
- pr_cont(" boot");
- if (class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
- pr_cont(" thermal");
- if (class & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE)
- pr_cont(" limited_pwr");
- if (class & ATOM_PPLIB_CLASSIFICATION_REST)
- pr_cont(" rest");
- if (class & ATOM_PPLIB_CLASSIFICATION_FORCED)
- pr_cont(" forced");
- if (class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
- pr_cont(" 3d_perf");
- if (class & ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE)
- pr_cont(" ovrdrv");
- if (class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
- pr_cont(" uvd");
- if (class & ATOM_PPLIB_CLASSIFICATION_3DLOW)
- pr_cont(" 3d_low");
- if (class & ATOM_PPLIB_CLASSIFICATION_ACPI)
- pr_cont(" acpi");
- if (class & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
- pr_cont(" uvd_hd2");
- if (class & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
- pr_cont(" uvd_hd");
- if (class & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
- pr_cont(" uvd_sd");
- if (class2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2)
- pr_cont(" limited_pwr2");
- if (class2 & ATOM_PPLIB_CLASSIFICATION2_ULV)
- pr_cont(" ulv");
- if (class2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
- pr_cont(" uvd_mvc");
- }
- pr_cont("\n");
+ drm_dbg(adev_to_drm(adev), "\tinternal class: none\n");
+ else
+ drm_dbg(adev_to_drm(adev), "\tinternal class: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+ (class & ATOM_PPLIB_CLASSIFICATION_BOOT) ? " boot" : "",
+ (class & ATOM_PPLIB_CLASSIFICATION_THERMAL) ? " thermal" : "",
+ (class & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE) ? " limited_pwr" : "",
+ (class & ATOM_PPLIB_CLASSIFICATION_REST) ? " rest" : "",
+ (class & ATOM_PPLIB_CLASSIFICATION_FORCED) ? " forced" : "",
+ (class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE) ? " 3d_perf" : "",
+ (class & ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE) ? " ovrdrv" : "",
+ (class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) ? " uvd" : "",
+ (class & ATOM_PPLIB_CLASSIFICATION_3DLOW) ? " 3d_low" : "",
+ (class & ATOM_PPLIB_CLASSIFICATION_ACPI) ? " acpi" : "",
+ (class & ATOM_PPLIB_CLASSIFICATION_HD2STATE) ? " uvd_hd2" : "",
+ (class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) ? " uvd_hd" : "",
+ (class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) ? " uvd_sd" : "",
+ (class2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2) ? " limited_pwr2" : "",
+ (class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) ? " ulv" : "",
+ (class2 & ATOM_PPLIB_CLASSIFICATION2_MVC) ? " uvd_mvc" : "");
}
-void amdgpu_dpm_print_cap_info(u32 caps)
+void amdgpu_dpm_dbg_print_cap_info(struct amdgpu_device *adev, u32 caps)
{
- printk("\tcaps:");
- if (caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY)
- pr_cont(" single_disp");
- if (caps & ATOM_PPLIB_SUPPORTS_VIDEO_PLAYBACK)
- pr_cont(" video");
- if (caps & ATOM_PPLIB_DISALLOW_ON_DC)
- pr_cont(" no_dc");
- pr_cont("\n");
+ drm_dbg(adev_to_drm(adev), "\tcaps: %s%s%s\n",
+ (caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) ? " single_disp" : "",
+ (caps & ATOM_PPLIB_SUPPORTS_VIDEO_PLAYBACK) ? " video" : "",
+ (caps & ATOM_PPLIB_DISALLOW_ON_DC) ? " no_dc" : "");
}
-void amdgpu_dpm_print_ps_status(struct amdgpu_device *adev,
+void amdgpu_dpm_dbg_print_ps_status(struct amdgpu_device *adev,
struct amdgpu_ps *rps)
{
- printk("\tstatus:");
- if (rps == adev->pm.dpm.current_ps)
- pr_cont(" c");
- if (rps == adev->pm.dpm.requested_ps)
- pr_cont(" r");
- if (rps == adev->pm.dpm.boot_ps)
- pr_cont(" b");
- pr_cont("\n");
+ drm_dbg(adev_to_drm(adev), "\tstatus:%s%s%s\n",
+ rps == adev->pm.dpm.current_ps ? " c" : "",
+ rps == adev->pm.dpm.requested_ps ? " r" : "",
+ rps == adev->pm.dpm.boot_ps ? " b" : "");
}
void amdgpu_pm_print_power_states(struct amdgpu_device *adev)
@@ -328,9 +302,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev)
ATOM_PPLIB_PhaseSheddingLimits_Record *entry;
adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries =
- kcalloc(psl->ucNumEntries,
- sizeof(struct amdgpu_phase_shedding_limits_entry),
- GFP_KERNEL);
+ kzalloc_objs(struct amdgpu_phase_shedding_limits_entry,
+ psl->ucNumEntries);
if (!adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries)
return -ENOMEM;
@@ -529,7 +502,7 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev)
(mode_info->atom_context->bios + data_offset +
le16_to_cpu(ext_hdr->usPPMTableOffset));
adev->pm.dpm.dyn_state.ppm_table =
- kzalloc(sizeof(struct amdgpu_ppm_table), GFP_KERNEL);
+ kzalloc_obj(struct amdgpu_ppm_table);
if (!adev->pm.dpm.dyn_state.ppm_table)
return -ENOMEM;
adev->pm.dpm.dyn_state.ppm_table->ppm_design = ppm->ucPpmDesign;
@@ -583,7 +556,7 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev)
le16_to_cpu(ext_hdr->usPowerTuneTableOffset));
ATOM_PowerTune_Table *pt;
adev->pm.dpm.dyn_state.cac_tdp_table =
- kzalloc(sizeof(struct amdgpu_cac_tdp_table), GFP_KERNEL);
+ kzalloc_obj(struct amdgpu_cac_tdp_table);
if (!adev->pm.dpm.dyn_state.cac_tdp_table)
return -ENOMEM;
if (rev > 0) {
@@ -699,64 +672,64 @@ void amdgpu_add_thermal_controller(struct amdgpu_device *adev)
adev->pm.fan_max_rpm = controller->ucFanMaxRPM;
}
if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) {
- DRM_INFO("Internal thermal controller %s fan control\n",
+ drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n",
(controller->ucFanParameters &
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
adev->pm.int_thermal_type = THERMAL_TYPE_RV6XX;
} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) {
- DRM_INFO("Internal thermal controller %s fan control\n",
+ drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n",
(controller->ucFanParameters &
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
adev->pm.int_thermal_type = THERMAL_TYPE_RV770;
} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) {
- DRM_INFO("Internal thermal controller %s fan control\n",
+ drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n",
(controller->ucFanParameters &
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
adev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN;
} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SUMO) {
- DRM_INFO("Internal thermal controller %s fan control\n",
+ drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n",
(controller->ucFanParameters &
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
adev->pm.int_thermal_type = THERMAL_TYPE_SUMO;
} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_NISLANDS) {
- DRM_INFO("Internal thermal controller %s fan control\n",
+ drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n",
(controller->ucFanParameters &
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
adev->pm.int_thermal_type = THERMAL_TYPE_NI;
} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SISLANDS) {
- DRM_INFO("Internal thermal controller %s fan control\n",
+ drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n",
(controller->ucFanParameters &
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
adev->pm.int_thermal_type = THERMAL_TYPE_SI;
} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_CISLANDS) {
- DRM_INFO("Internal thermal controller %s fan control\n",
+ drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n",
(controller->ucFanParameters &
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
adev->pm.int_thermal_type = THERMAL_TYPE_CI;
} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_KAVERI) {
- DRM_INFO("Internal thermal controller %s fan control\n",
+ drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n",
(controller->ucFanParameters &
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
adev->pm.int_thermal_type = THERMAL_TYPE_KV;
} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) {
- DRM_INFO("External GPIO thermal controller %s fan control\n",
+ drm_info(adev_to_drm(adev), "External GPIO thermal controller %s fan control\n",
(controller->ucFanParameters &
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
adev->pm.int_thermal_type = THERMAL_TYPE_EXTERNAL_GPIO;
} else if (controller->ucType ==
ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL) {
- DRM_INFO("ADT7473 with internal thermal controller %s fan control\n",
+ drm_info(adev_to_drm(adev), "ADT7473 with internal thermal controller %s fan control\n",
(controller->ucFanParameters &
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
adev->pm.int_thermal_type = THERMAL_TYPE_ADT7473_WITH_INTERNAL;
} else if (controller->ucType ==
ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL) {
- DRM_INFO("EMC2103 with internal thermal controller %s fan control\n",
+ drm_info(adev_to_drm(adev), "EMC2103 with internal thermal controller %s fan control\n",
(controller->ucFanParameters &
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
adev->pm.int_thermal_type = THERMAL_TYPE_EMC2103_WITH_INTERNAL;
} else if (controller->ucType < ARRAY_SIZE(pp_lib_thermal_controller_names)) {
- DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n",
+ drm_info(adev_to_drm(adev), "Possible %s thermal controller at 0x%02x %s fan control\n",
pp_lib_thermal_controller_names[controller->ucType],
controller->ucI2cAddress >> 1,
(controller->ucFanParameters &
@@ -772,7 +745,7 @@ void amdgpu_add_thermal_controller(struct amdgpu_device *adev)
i2c_new_client_device(&adev->pm.i2c_bus->adapter, &info);
}
} else {
- DRM_INFO("Unknown thermal controller type %d at 0x%02x %s fan control\n",
+ drm_info(adev_to_drm(adev), "Unknown thermal controller type %d at 0x%02x %s fan control\n",
controller->ucType,
controller->ucI2cAddress >> 1,
(controller->ucFanParameters &
@@ -797,8 +770,7 @@ static struct amdgpu_ps *amdgpu_dpm_pick_power_state(struct amdgpu_device *adev,
int i;
struct amdgpu_ps *ps;
u32 ui_class;
- bool single_display = (adev->pm.dpm.new_active_crtc_count < 2) ?
- true : false;
+ bool single_display = adev->pm.pm_display_cfg.num_display < 2;
/* check if the vblank period is too short to adjust the mclk */
if (single_display && adev->powerplay.pp_funcs->vblank_too_short) {
@@ -943,9 +915,9 @@ static int amdgpu_dpm_change_power_state_locked(struct amdgpu_device *adev)
return -EINVAL;
if (amdgpu_dpm == 1 && pp_funcs->print_power_state) {
- printk("switching from power state:\n");
+ drm_dbg(adev_to_drm(adev), "switching from power state\n");
amdgpu_dpm_print_power_state(adev, adev->pm.dpm.current_ps);
- printk("switching to power state:\n");
+ drm_dbg(adev_to_drm(adev), "switching to power state\n");
amdgpu_dpm_print_power_state(adev, adev->pm.dpm.requested_ps);
}
@@ -971,9 +943,6 @@ static int amdgpu_dpm_change_power_state_locked(struct amdgpu_device *adev)
amdgpu_dpm_post_set_power_state(adev);
- adev->pm.dpm.current_active_crtcs = adev->pm.dpm.new_active_crtcs;
- adev->pm.dpm.current_active_crtc_count = adev->pm.dpm.new_active_crtc_count;
-
if (pp_funcs->force_performance_level) {
if (adev->pm.dpm.thermal_active) {
enum amd_dpm_forced_level level = adev->pm.dpm.forced_level;
@@ -994,7 +963,8 @@ void amdgpu_legacy_dpm_compute_clocks(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- amdgpu_dpm_get_active_displays(adev);
+ if (!adev->dc_enabled)
+ amdgpu_dpm_get_display_cfg(adev);
amdgpu_dpm_change_power_state_locked(adev);
}
diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.h b/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.h
index 93bd3973330c..7120eef30509 100644
--- a/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.h
+++ b/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.h
@@ -23,10 +23,9 @@
#ifndef __LEGACY_DPM_H__
#define __LEGACY_DPM_H__
-void amdgpu_dpm_print_class_info(u32 class, u32 class2);
-void amdgpu_dpm_print_cap_info(u32 caps);
-void amdgpu_dpm_print_ps_status(struct amdgpu_device *adev,
- struct amdgpu_ps *rps);
+void amdgpu_dpm_dbg_print_class_info(struct amdgpu_device *adev, u32 class, u32 class2);
+void amdgpu_dpm_dbg_print_cap_info(struct amdgpu_device *adev, u32 caps);
+void amdgpu_dpm_dbg_print_ps_status(struct amdgpu_device *adev, struct amdgpu_ps *rps);
int amdgpu_get_platform_caps(struct amdgpu_device *adev);
int amdgpu_parse_extended_power_table(struct amdgpu_device *adev);
void amdgpu_free_extended_power_table(struct amdgpu_device *adev);
diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
index d6dfe2599ebe..8079da7c5335 100644
--- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
+++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
@@ -30,16 +30,32 @@
#include "amdgpu_atombios.h"
#include "amdgpu_dpm_internal.h"
#include "amd_pcie.h"
-#include "sid.h"
+#include "atom.h"
+#include "gfx_v6_0.h"
#include "r600_dpm.h"
+#include "sid.h"
#include "si_dpm.h"
-#include "atom.h"
#include "../include/pptable.h"
#include <linux/math64.h>
#include <linux/seq_file.h>
#include <linux/firmware.h>
#include <legacy_dpm.h>
+#include "bif/bif_3_0_d.h"
+#include "bif/bif_3_0_sh_mask.h"
+
+#include "dce/dce_6_0_d.h"
+#include "dce/dce_6_0_sh_mask.h"
+
+#include "gca/gfx_6_0_d.h"
+#include "gca/gfx_6_0_sh_mask.h"
+
+#include"gmc/gmc_6_0_d.h"
+#include"gmc/gmc_6_0_sh_mask.h"
+
+#include "smu/smu_6_0_d.h"
+#include "smu/smu_6_0_sh_mask.h"
+
#define MC_CG_ARB_FREQ_F0 0x0a
#define MC_CG_ARB_FREQ_F1 0x0b
#define MC_CG_ARB_FREQ_F2 0x0c
@@ -2193,7 +2209,7 @@ static u32 si_calculate_cac_wintime(struct amdgpu_device *adev)
if (xclk == 0)
return 0;
- cac_window = RREG32(CG_CAC_CTRL) & CAC_WINDOW_MASK;
+ cac_window = RREG32(mmCG_CAC_CTRL) & CG_CAC_CTRL__CAC_WINDOW_MASK;
cac_window_size = ((cac_window & 0xFFFF0000) >> 16) * (cac_window & 0x0000FFFF);
wintime = (cac_window_size * 100) / xclk;
@@ -2257,8 +2273,6 @@ static int si_populate_smc_tdp_limits(struct amdgpu_device *adev,
if (scaling_factor == 0)
return -EINVAL;
- memset(smc_table, 0, sizeof(SISLANDS_SMC_STATETABLE));
-
ret = si_calculate_adjusted_tdp_limits(adev,
false, /* ??? */
adev->pm.dpm.tdp_adjustment,
@@ -2267,6 +2281,12 @@ static int si_populate_smc_tdp_limits(struct amdgpu_device *adev,
if (ret)
return ret;
+ if (adev->pdev->device == 0x6611 && adev->pdev->revision == 0x87) {
+ /* Workaround buggy powertune on Radeon 430 and 520. */
+ tdp_limit = 32;
+ near_tdp_limit = 28;
+ }
+
smc_table->dpm2Params.TDPLimit =
cpu_to_be32(si_scale_power_for_smc(tdp_limit, scaling_factor) * 1000);
smc_table->dpm2Params.NearTDPLimit =
@@ -2312,16 +2332,8 @@ static int si_populate_smc_tdp_limits_2(struct amdgpu_device *adev,
if (ni_pi->enable_power_containment) {
SISLANDS_SMC_STATETABLE *smc_table = &si_pi->smc_statetable;
- u32 scaling_factor = si_get_smc_power_scaling_factor(adev);
int ret;
- memset(smc_table, 0, sizeof(SISLANDS_SMC_STATETABLE));
-
- smc_table->dpm2Params.NearTDPLimit =
- cpu_to_be32(si_scale_power_for_smc(adev->pm.dpm.near_tdp_limit_adjusted, scaling_factor) * 1000);
- smc_table->dpm2Params.SafePowerLimit =
- cpu_to_be32(si_scale_power_for_smc((adev->pm.dpm.near_tdp_limit_adjusted * SISLANDS_DPM2_TDP_SAFE_LIMIT_PERCENT) / 100, scaling_factor) * 1000);
-
ret = amdgpu_si_copy_bytes_to_smc(adev,
(si_pi->state_table_start +
offsetof(SISLANDS_SMC_STATETABLE, dpm2Params) +
@@ -2489,19 +2501,19 @@ static int si_populate_sq_ramping_values(struct amdgpu_device *adev,
if (adev->pm.dpm.sq_ramping_threshold == 0)
return -EINVAL;
- if (SISLANDS_DPM2_SQ_RAMP_MAX_POWER > (MAX_POWER_MASK >> MAX_POWER_SHIFT))
+ if (SISLANDS_DPM2_SQ_RAMP_MAX_POWER > (SQ_POWER_THROTTLE__MAX_POWER_MASK >> SQ_POWER_THROTTLE__MAX_POWER__SHIFT))
enable_sq_ramping = false;
- if (SISLANDS_DPM2_SQ_RAMP_MIN_POWER > (MIN_POWER_MASK >> MIN_POWER_SHIFT))
+ if (SISLANDS_DPM2_SQ_RAMP_MIN_POWER > (SQ_POWER_THROTTLE__MIN_POWER_MASK >> SQ_POWER_THROTTLE__MIN_POWER__SHIFT))
enable_sq_ramping = false;
- if (SISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA > (MAX_POWER_DELTA_MASK >> MAX_POWER_DELTA_SHIFT))
+ if (SISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA > (SQ_POWER_THROTTLE2__MAX_POWER_DELTA_MASK >> SQ_POWER_THROTTLE2__MAX_POWER_DELTA__SHIFT))
enable_sq_ramping = false;
- if (SISLANDS_DPM2_SQ_RAMP_STI_SIZE > (STI_SIZE_MASK >> STI_SIZE_SHIFT))
+ if (SISLANDS_DPM2_SQ_RAMP_STI_SIZE > (SQ_POWER_THROTTLE2__SHORT_TERM_INTERVAL_SIZE_MASK >> SQ_POWER_THROTTLE2__SHORT_TERM_INTERVAL_SIZE__SHIFT))
enable_sq_ramping = false;
- if (SISLANDS_DPM2_SQ_RAMP_LTI_RATIO > (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))
+ if (SISLANDS_DPM2_SQ_RAMP_LTI_RATIO > (SQ_POWER_THROTTLE2__LONG_TERM_INTERVAL_RATIO_MASK >> SQ_POWER_THROTTLE2__LONG_TERM_INTERVAL_RATIO__SHIFT))
enable_sq_ramping = false;
for (i = 0; i < state->performance_level_count; i++) {
@@ -2510,14 +2522,17 @@ static int si_populate_sq_ramping_values(struct amdgpu_device *adev,
if ((state->performance_levels[i].sclk >= adev->pm.dpm.sq_ramping_threshold) &&
enable_sq_ramping) {
- sq_power_throttle |= MAX_POWER(SISLANDS_DPM2_SQ_RAMP_MAX_POWER);
- sq_power_throttle |= MIN_POWER(SISLANDS_DPM2_SQ_RAMP_MIN_POWER);
- sq_power_throttle2 |= MAX_POWER_DELTA(SISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA);
- sq_power_throttle2 |= STI_SIZE(SISLANDS_DPM2_SQ_RAMP_STI_SIZE);
- sq_power_throttle2 |= LTI_RATIO(SISLANDS_DPM2_SQ_RAMP_LTI_RATIO);
+ sq_power_throttle |= SISLANDS_DPM2_SQ_RAMP_MAX_POWER << SQ_POWER_THROTTLE__MAX_POWER__SHIFT;
+ sq_power_throttle |= SISLANDS_DPM2_SQ_RAMP_MIN_POWER << SQ_POWER_THROTTLE__MIN_POWER__SHIFT;
+ sq_power_throttle2 |= SISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA << SQ_POWER_THROTTLE2__MAX_POWER_DELTA__SHIFT;
+ sq_power_throttle2 |= SISLANDS_DPM2_SQ_RAMP_STI_SIZE << SQ_POWER_THROTTLE2__SHORT_TERM_INTERVAL_SIZE__SHIFT;
+ sq_power_throttle2 |= SISLANDS_DPM2_SQ_RAMP_LTI_RATIO << SQ_POWER_THROTTLE2__LONG_TERM_INTERVAL_RATIO__SHIFT;
} else {
- sq_power_throttle |= MAX_POWER_MASK | MIN_POWER_MASK;
- sq_power_throttle2 |= MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
+ sq_power_throttle |= SQ_POWER_THROTTLE__MAX_POWER_MASK |
+ SQ_POWER_THROTTLE__MIN_POWER_MASK;
+ sq_power_throttle2 |= SQ_POWER_THROTTLE2__MAX_POWER_DELTA_MASK |
+ SQ_POWER_THROTTLE2__SHORT_TERM_INTERVAL_SIZE_MASK |
+ SQ_POWER_THROTTLE2__LONG_TERM_INTERVAL_RATIO_MASK;
}
smc_state->levels[i].SQPowerThrottle = cpu_to_be32(sq_power_throttle);
@@ -2539,18 +2554,13 @@ static int si_enable_power_containment(struct amdgpu_device *adev,
if (enable) {
if (!si_should_disable_uvd_powertune(adev, amdgpu_new_state)) {
smc_result = amdgpu_si_send_msg_to_smc(adev, PPSMC_TDPClampingActive);
- if (smc_result != PPSMC_Result_OK) {
+ if (smc_result != PPSMC_Result_OK)
ret = -EINVAL;
- ni_pi->pc_enabled = false;
- } else {
- ni_pi->pc_enabled = true;
- }
}
} else {
smc_result = amdgpu_si_send_msg_to_smc(adev, PPSMC_TDPClampingInactive);
if (smc_result != PPSMC_Result_OK)
ret = -EINVAL;
- ni_pi->pc_enabled = false;
}
}
@@ -2576,7 +2586,7 @@ static int si_initialize_smc_dte_tables(struct amdgpu_device *adev)
if (dte_data->k <= 0)
return -EINVAL;
- dte_tables = kzalloc(sizeof(Smc_SIslands_DTE_Configuration), GFP_KERNEL);
+ dte_tables = kzalloc_obj(Smc_SIslands_DTE_Configuration);
if (dte_tables == NULL) {
si_pi->enable_dte = false;
return -ENOMEM;
@@ -2757,13 +2767,13 @@ static int si_initialize_smc_cac_tables(struct amdgpu_device *adev)
if (ni_pi->enable_cac == false)
return 0;
- cac_tables = kzalloc(sizeof(PP_SIslands_CacConfig), GFP_KERNEL);
+ cac_tables = kzalloc_obj(PP_SIslands_CacConfig);
if (!cac_tables)
return -ENOMEM;
- reg = RREG32(CG_CAC_CTRL) & ~CAC_WINDOW_MASK;
- reg |= CAC_WINDOW(si_pi->powertune_data->cac_window);
- WREG32(CG_CAC_CTRL, reg);
+ reg = RREG32(mmCG_CAC_CTRL) & ~CG_CAC_CTRL__CAC_WINDOW_MASK;
+ reg |= (si_pi->powertune_data->cac_window << CG_CAC_CTRL__CAC_WINDOW__SHIFT);
+ WREG32(mmCG_CAC_CTRL, reg);
si_pi->dyn_powertune_data.cac_leakage = adev->pm.dpm.cac_leakage;
si_pi->dyn_powertune_data.dc_pwr_value =
@@ -2954,7 +2964,7 @@ static int si_init_smc_spll_table(struct amdgpu_device *adev)
if (si_pi->spll_table_start == 0)
return -EINVAL;
- spll_table = kzalloc(sizeof(SMC_SISLANDS_SPLL_DIV_TABLE), GFP_KERNEL);
+ spll_table = kzalloc_obj(SMC_SISLANDS_SPLL_DIV_TABLE);
if (spll_table == NULL)
return -ENOMEM;
@@ -2962,10 +2972,10 @@ static int si_init_smc_spll_table(struct amdgpu_device *adev)
ret = si_calculate_sclk_params(adev, sclk, &sclk_params);
if (ret)
break;
- p_div = (sclk_params.vCG_SPLL_FUNC_CNTL & SPLL_PDIV_A_MASK) >> SPLL_PDIV_A_SHIFT;
- fb_div = (sclk_params.vCG_SPLL_FUNC_CNTL_3 & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT;
- clk_s = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM & CLK_S_MASK) >> CLK_S_SHIFT;
- clk_v = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM_2 & CLK_V_MASK) >> CLK_V_SHIFT;
+ p_div = (sclk_params.vCG_SPLL_FUNC_CNTL & CG_SPLL_FUNC_CNTL__SPLL_PDIV_A_MASK) >> CG_SPLL_FUNC_CNTL__SPLL_PDIV_A__SHIFT;
+ fb_div = (sclk_params.vCG_SPLL_FUNC_CNTL_3 & CG_SPLL_FUNC_CNTL_3__SPLL_FB_DIV_MASK) >> CG_SPLL_FUNC_CNTL_3__SPLL_FB_DIV__SHIFT;
+ clk_s = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM & CG_SPLL_SPREAD_SPECTRUM__CLK_S_MASK) >> CG_SPLL_SPREAD_SPECTRUM__CLK_S__SHIFT;
+ clk_v = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM_2 & CG_SPLL_SPREAD_SPECTRUM_2__CLK_V_MASK) >> CG_SPLL_SPREAD_SPECTRUM_2__CLK_V__SHIFT;
fb_div &= ~0x00001FFF;
fb_div >>= 1;
@@ -3062,11 +3072,21 @@ static int si_get_vce_clock_voltage(struct amdgpu_device *adev,
static bool si_dpm_vblank_too_short(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- u32 vblank_time = amdgpu_dpm_get_vblank_time(adev);
+ u32 vblank_time = adev->pm.pm_display_cfg.min_vblank_time;
/* we never hit the non-gddr5 limit so disable it */
u32 switch_limit = adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 0;
- if (vblank_time < switch_limit)
+ /* Disregard vblank time when there are no displays connected */
+ if (!adev->pm.pm_display_cfg.num_display)
+ return false;
+
+ /* Consider zero vblank time too short and disable MCLK switching.
+ * Note that the vblank time is set to maximum when no displays are attached,
+ * so we'll still enable MCLK switching in that case.
+ */
+ if (vblank_time == 0)
+ return true;
+ else if (vblank_time < switch_limit)
return true;
else
return false;
@@ -3422,6 +3442,8 @@ static void rv770_get_engine_memory_ss(struct amdgpu_device *adev)
static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
struct amdgpu_ps *rps)
{
+ const struct amd_pp_display_configuration *display_cfg =
+ &adev->pm.pm_display_cfg;
struct si_ps *ps = si_get_ps(rps);
struct amdgpu_clock_and_voltage_limits *max_limits;
bool disable_mclk_switching = false;
@@ -3430,14 +3452,17 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
u16 vddc, vddci, min_vce_voltage = 0;
u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc;
u32 max_sclk = 0, max_mclk = 0;
+ u32 high_pixelclock_count = 0;
int i;
if (adev->asic_type == CHIP_HAINAN) {
if ((adev->pdev->revision == 0x81) ||
(adev->pdev->revision == 0xC3) ||
+ (adev->pdev->device == 0x6660) ||
(adev->pdev->device == 0x6664) ||
(adev->pdev->device == 0x6665) ||
- (adev->pdev->device == 0x6667)) {
+ (adev->pdev->device == 0x6667) ||
+ (adev->pdev->device == 0x666F)) {
max_sclk = 75000;
}
if ((adev->pdev->revision == 0xC3) ||
@@ -3445,18 +3470,57 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
max_sclk = 60000;
max_mclk = 80000;
}
+ if ((adev->pdev->device == 0x666f) &&
+ (adev->pdev->revision == 0x00)) {
+ max_sclk = 80000;
+ max_mclk = 95000;
+ }
} else if (adev->asic_type == CHIP_OLAND) {
if ((adev->pdev->revision == 0xC7) ||
(adev->pdev->revision == 0x80) ||
(adev->pdev->revision == 0x81) ||
(adev->pdev->revision == 0x83) ||
- (adev->pdev->revision == 0x87) ||
+ (adev->pdev->revision == 0x87 &&
+ adev->pdev->device != 0x6611) ||
(adev->pdev->device == 0x6604) ||
(adev->pdev->device == 0x6605)) {
max_sclk = 75000;
+ } else if (adev->pdev->revision == 0x87 &&
+ adev->pdev->device == 0x6611) {
+ /* Radeon 430 and 520 */
+ max_sclk = 78000;
}
}
+ /* We define "high pixelclock" for SI as higher than necessary for 4K 30Hz.
+ * For example, 4K 60Hz and 1080p 144Hz fall into this category.
+ * Find number of such displays connected.
+ */
+ for (i = 0; i < display_cfg->num_display; i++) {
+ /* The array only contains active displays. */
+ if (display_cfg->displays[i].pixel_clock > 297000)
+ high_pixelclock_count++;
+ }
+
+ /* These are some ad-hoc fixes to some issues observed with SI GPUs.
+ * They are necessary because we don't have something like dce_calcs
+ * for these GPUs to calculate bandwidth requirements.
+ */
+ if (high_pixelclock_count) {
+ /* Work around flickering lines at the bottom edge
+ * of the screen when using a single 4K 60Hz monitor.
+ */
+ disable_mclk_switching = true;
+
+ /* On Oland, we observe some flickering when two 4K 60Hz
+ * displays are connected, possibly because voltage is too low.
+ * Raise the voltage by requiring a higher SCLK.
+ * (Voltage cannot be adjusted independently without also SCLK.)
+ */
+ if (high_pixelclock_count > 1 && adev->asic_type == CHIP_OLAND)
+ disable_sclk_switching = true;
+ }
+
if (rps->vce_active) {
rps->evclk = adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].evclk;
rps->ecclk = adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].ecclk;
@@ -3467,7 +3531,7 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
rps->ecclk = 0;
}
- if ((adev->pm.dpm.new_active_crtc_count > 1) ||
+ if ((adev->pm.pm_display_cfg.num_display > 1) ||
si_dpm_vblank_too_short(adev))
disable_mclk_switching = true;
@@ -3615,7 +3679,7 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
ps->performance_levels[i].mclk,
max_limits->vddc, &ps->performance_levels[i].vddc);
btc_apply_voltage_dependency_rules(&adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk,
- adev->clock.current_dispclk,
+ display_cfg->display_clk,
max_limits->vddc, &ps->performance_levels[i].vddc);
}
@@ -3669,10 +3733,10 @@ static bool si_is_special_1gb_platform(struct amdgpu_device *adev)
WREG32(MC_SEQ_IO_DEBUG_INDEX, 0xb);
width = ((RREG32(MC_SEQ_IO_DEBUG_DATA) >> 1) & 1) ? 16 : 32;
- tmp = RREG32(MC_ARB_RAMCFG);
- row = ((tmp & NOOFROWS_MASK) >> NOOFROWS_SHIFT) + 10;
- column = ((tmp & NOOFCOLS_MASK) >> NOOFCOLS_SHIFT) + 8;
- bank = ((tmp & NOOFBANK_MASK) >> NOOFBANK_SHIFT) + 2;
+ tmp = RREG32(mmMC_ARB_RAMCFG);
+ row = ((tmp & MC_ARB_RAMCFG__NOOFROWS_MASK) >> MC_ARB_RAMCFG__NOOFROWS__SHIFT) + 10;
+ column = ((tmp & MC_ARB_RAMCFG__NOOFCOLS_MASK) >> MC_ARB_RAMCFG__NOOFCOLS__SHIFT) + 8;
+ bank = ((tmp & MC_ARB_RAMCFG__NOOFBANK_MASK) >> MC_ARB_RAMCFG__NOOFBANK__SHIFT) + 2;
density = (1 << (row + column - 20 + bank)) * width;
@@ -3756,11 +3820,11 @@ static void si_set_dpm_event_sources(struct amdgpu_device *adev, u32 sources)
}
if (want_thermal_protection) {
- WREG32_P(CG_THERMAL_CTRL, DPM_EVENT_SRC(dpm_event_src), ~DPM_EVENT_SRC_MASK);
+ WREG32_P(mmCG_THERMAL_CTRL, dpm_event_src << CG_THERMAL_CTRL__DPM_EVENT_SRC__SHIFT, ~CG_THERMAL_CTRL__DPM_EVENT_SRC_MASK);
if (pi->thermal_protection)
- WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS);
+ WREG32_P(mmGENERAL_PWRMGT, 0, ~GENERAL_PWRMGT__THERMAL_PROTECTION_DIS_MASK);
} else {
- WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS);
+ WREG32_P(mmGENERAL_PWRMGT, GENERAL_PWRMGT__THERMAL_PROTECTION_DIS_MASK, ~GENERAL_PWRMGT__THERMAL_PROTECTION_DIS_MASK);
}
}
@@ -3785,20 +3849,20 @@ static void si_enable_auto_throttle_source(struct amdgpu_device *adev,
static void si_start_dpm(struct amdgpu_device *adev)
{
- WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN);
+ WREG32_P(mmGENERAL_PWRMGT, GENERAL_PWRMGT__GLOBAL_PWRMGT_EN_MASK, ~GENERAL_PWRMGT__GLOBAL_PWRMGT_EN_MASK);
}
static void si_stop_dpm(struct amdgpu_device *adev)
{
- WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN);
+ WREG32_P(mmGENERAL_PWRMGT, 0, ~GENERAL_PWRMGT__GLOBAL_PWRMGT_EN_MASK);
}
static void si_enable_sclk_control(struct amdgpu_device *adev, bool enable)
{
if (enable)
- WREG32_P(SCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_OFF);
+ WREG32_P(mmSCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_CNTL__SCLK_PWRMGT_OFF_MASK);
else
- WREG32_P(SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF);
+ WREG32_P(mmSCLK_PWRMGT_CNTL, SCLK_PWRMGT_CNTL__SCLK_PWRMGT_OFF_MASK, ~SCLK_PWRMGT_CNTL__SCLK_PWRMGT_OFF_MASK);
}
@@ -3824,21 +3888,23 @@ static void si_notify_hardware_vpu_recovery_event(struct amdgpu_device *adev)
}
#endif
-#if 0
-static int si_notify_hw_of_powersource(struct amdgpu_device *adev, bool ac_power)
+static void si_notify_hw_of_powersource(void *handle)
{
- if (ac_power)
- return (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_RunningOnAC) == PPSMC_Result_OK) ?
- 0 : -EINVAL;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- return 0;
+ /* Check if the platform already manages the AC/DC switch via dedicated GPIO. */
+ if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC)
+ return;
+
+ /* The SMU automatically notices DC, but needs to be notified when switching to AC. */
+ if (adev->pm.ac_power)
+ amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_RunningOnAC);
}
-#endif
static PPSMC_Result si_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
PPSMC_Msg msg, u32 parameter)
{
- WREG32(SMC_SCRATCH0, parameter);
+ WREG32(mmSMC_SCRATCH0, parameter);
return amdgpu_si_send_msg_to_smc(adev, msg);
}
@@ -4023,12 +4089,12 @@ static void si_read_clock_registers(struct amdgpu_device *adev)
{
struct si_power_info *si_pi = si_get_pi(adev);
- si_pi->clock_registers.cg_spll_func_cntl = RREG32(CG_SPLL_FUNC_CNTL);
- si_pi->clock_registers.cg_spll_func_cntl_2 = RREG32(CG_SPLL_FUNC_CNTL_2);
- si_pi->clock_registers.cg_spll_func_cntl_3 = RREG32(CG_SPLL_FUNC_CNTL_3);
- si_pi->clock_registers.cg_spll_func_cntl_4 = RREG32(CG_SPLL_FUNC_CNTL_4);
- si_pi->clock_registers.cg_spll_spread_spectrum = RREG32(CG_SPLL_SPREAD_SPECTRUM);
- si_pi->clock_registers.cg_spll_spread_spectrum_2 = RREG32(CG_SPLL_SPREAD_SPECTRUM_2);
+ si_pi->clock_registers.cg_spll_func_cntl = RREG32(mmCG_SPLL_FUNC_CNTL);
+ si_pi->clock_registers.cg_spll_func_cntl_2 = RREG32(mmCG_SPLL_FUNC_CNTL_2);
+ si_pi->clock_registers.cg_spll_func_cntl_3 = RREG32(mmCG_SPLL_FUNC_CNTL_3);
+ si_pi->clock_registers.cg_spll_func_cntl_4 = RREG32(mmCG_SPLL_FUNC_CNTL_4);
+ si_pi->clock_registers.cg_spll_spread_spectrum = RREG32(mmCG_SPLL_SPREAD_SPECTRUM);
+ si_pi->clock_registers.cg_spll_spread_spectrum_2 = RREG32(mmCG_SPLL_SPREAD_SPECTRUM_2);
si_pi->clock_registers.dll_cntl = RREG32(DLL_CNTL);
si_pi->clock_registers.mclk_pwrmgt_cntl = RREG32(MCLK_PWRMGT_CNTL);
si_pi->clock_registers.mpll_ad_func_cntl = RREG32(MPLL_AD_FUNC_CNTL);
@@ -4044,14 +4110,14 @@ static void si_enable_thermal_protection(struct amdgpu_device *adev,
bool enable)
{
if (enable)
- WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS);
+ WREG32_P(mmGENERAL_PWRMGT, 0, ~GENERAL_PWRMGT__THERMAL_PROTECTION_DIS_MASK);
else
- WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS);
+ WREG32_P(mmGENERAL_PWRMGT, GENERAL_PWRMGT__THERMAL_PROTECTION_DIS_MASK, ~GENERAL_PWRMGT__THERMAL_PROTECTION_DIS_MASK);
}
static void si_enable_acpi_power_management(struct amdgpu_device *adev)
{
- WREG32_P(GENERAL_PWRMGT, STATIC_PM_EN, ~STATIC_PM_EN);
+ WREG32_P(mmGENERAL_PWRMGT, GENERAL_PWRMGT__STATIC_PM_EN_MASK, ~GENERAL_PWRMGT__STATIC_PM_EN_MASK);
}
#if 0
@@ -4132,44 +4198,35 @@ static void si_program_ds_registers(struct amdgpu_device *adev)
tmp = 0x1;
if (eg_pi->sclk_deep_sleep) {
- WREG32_P(MISC_CLK_CNTL, DEEP_SLEEP_CLK_SEL(tmp), ~DEEP_SLEEP_CLK_SEL_MASK);
- WREG32_P(CG_SPLL_AUTOSCALE_CNTL, AUTOSCALE_ON_SS_CLEAR,
- ~AUTOSCALE_ON_SS_CLEAR);
+ WREG32_P(mmMISC_CLK_CNTL, (tmp << MISC_CLK_CNTL__DEEP_SLEEP_CLK_SEL__SHIFT), ~MISC_CLK_CNTL__DEEP_SLEEP_CLK_SEL_MASK);
+ WREG32_P(mmCG_SPLL_AUTOSCALE_CNTL, CG_SPLL_AUTOSCALE_CNTL__AUTOSCALE_ON_SS_CLEAR_MASK,
+ ~CG_SPLL_AUTOSCALE_CNTL__AUTOSCALE_ON_SS_CLEAR_MASK);
}
}
static void si_program_display_gap(struct amdgpu_device *adev)
{
+ const struct amd_pp_display_configuration *cfg = &adev->pm.pm_display_cfg;
u32 tmp, pipe;
- int i;
- tmp = RREG32(CG_DISPLAY_GAP_CNTL) & ~(DISP1_GAP_MASK | DISP2_GAP_MASK);
- if (adev->pm.dpm.new_active_crtc_count > 0)
- tmp |= DISP1_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM);
+ tmp = RREG32(mmCG_DISPLAY_GAP_CNTL) & ~(CG_DISPLAY_GAP_CNTL__DISP1_GAP_MASK | CG_DISPLAY_GAP_CNTL__DISP2_GAP_MASK);
+ if (cfg->num_display > 0)
+ tmp |= R600_PM_DISPLAY_GAP_VBLANK_OR_WM << CG_DISPLAY_GAP_CNTL__DISP1_GAP__SHIFT;
else
- tmp |= DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE);
+ tmp |= R600_PM_DISPLAY_GAP_IGNORE << CG_DISPLAY_GAP_CNTL__DISP1_GAP__SHIFT;
- if (adev->pm.dpm.new_active_crtc_count > 1)
- tmp |= DISP2_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM);
+ if (cfg->num_display > 1)
+ tmp |= R600_PM_DISPLAY_GAP_VBLANK_OR_WM << CG_DISPLAY_GAP_CNTL__DISP2_GAP__SHIFT;
else
- tmp |= DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE);
+ tmp |= R600_PM_DISPLAY_GAP_IGNORE << CG_DISPLAY_GAP_CNTL__DISP2_GAP__SHIFT;
- WREG32(CG_DISPLAY_GAP_CNTL, tmp);
+ WREG32(mmCG_DISPLAY_GAP_CNTL, tmp);
tmp = RREG32(DCCG_DISP_SLOW_SELECT_REG);
pipe = (tmp & DCCG_DISP1_SLOW_SELECT_MASK) >> DCCG_DISP1_SLOW_SELECT_SHIFT;
- if ((adev->pm.dpm.new_active_crtc_count > 0) &&
- (!(adev->pm.dpm.new_active_crtcs & (1 << pipe)))) {
- /* find the first active crtc */
- for (i = 0; i < adev->mode_info.num_crtc; i++) {
- if (adev->pm.dpm.new_active_crtcs & (1 << i))
- break;
- }
- if (i == adev->mode_info.num_crtc)
- pipe = 0;
- else
- pipe = i;
+ if (cfg->num_display > 0 && pipe != cfg->crtc_index) {
+ pipe = cfg->crtc_index;
tmp &= ~DCCG_DISP1_SLOW_SELECT_MASK;
tmp |= DCCG_DISP1_SLOW_SELECT(pipe);
@@ -4180,7 +4237,7 @@ static void si_program_display_gap(struct amdgpu_device *adev)
* This can be a problem on PowerXpress systems or if you want to use the card
* for offscreen rendering or compute if there are no crtcs enabled.
*/
- si_notify_smc_display_change(adev, adev->pm.dpm.new_active_crtc_count > 0);
+ si_notify_smc_display_change(adev, cfg->num_display > 0);
}
static void si_enable_spread_spectrum(struct amdgpu_device *adev, bool enable)
@@ -4189,10 +4246,10 @@ static void si_enable_spread_spectrum(struct amdgpu_device *adev, bool enable)
if (enable) {
if (pi->sclk_ss)
- WREG32_P(GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, ~DYN_SPREAD_SPECTRUM_EN);
+ WREG32_P(mmGENERAL_PWRMGT, GENERAL_PWRMGT__DYN_SPREAD_SPECTRUM_EN_MASK, ~GENERAL_PWRMGT__DYN_SPREAD_SPECTRUM_EN_MASK);
} else {
- WREG32_P(CG_SPLL_SPREAD_SPECTRUM, 0, ~SSEN);
- WREG32_P(GENERAL_PWRMGT, 0, ~DYN_SPREAD_SPECTRUM_EN);
+ WREG32_P(mmCG_SPLL_SPREAD_SPECTRUM, 0, ~CG_SPLL_SPREAD_SPECTRUM__SSEN_MASK);
+ WREG32_P(mmGENERAL_PWRMGT, 0, ~GENERAL_PWRMGT__DYN_SPREAD_SPECTRUM_EN_MASK);
}
}
@@ -4214,15 +4271,15 @@ static void si_setup_bsp(struct amdgpu_device *adev)
&pi->pbsu);
- pi->dsp = BSP(pi->bsp) | BSU(pi->bsu);
- pi->psp = BSP(pi->pbsp) | BSU(pi->pbsu);
+ pi->dsp = (pi->bsp << CG_BSP__BSP__SHIFT) | (pi->bsu << CG_BSP__BSU__SHIFT);
+ pi->psp = (pi->pbsp << CG_BSP__BSP__SHIFT) | (pi->pbsu << CG_BSP__BSU__SHIFT);
- WREG32(CG_BSP, pi->dsp);
+ WREG32(mmCG_BSP, pi->dsp);
}
static void si_program_git(struct amdgpu_device *adev)
{
- WREG32_P(CG_GIT, CG_GICST(R600_GICST_DFLT), ~CG_GICST_MASK);
+ WREG32_P(mmCG_GIT, R600_GICST_DFLT << CG_GIT__CG_GICST__SHIFT, ~CG_GIT__CG_GICST_MASK);
}
static void si_program_tp(struct amdgpu_device *adev)
@@ -4231,54 +4288,54 @@ static void si_program_tp(struct amdgpu_device *adev)
enum r600_td td = R600_TD_DFLT;
for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
- WREG32(CG_FFCT_0 + i, (UTC_0(r600_utc[i]) | DTC_0(r600_dtc[i])));
+ WREG32(mmCG_FFCT_0 + i, (r600_utc[i] << CG_FFCT_0__UTC_0__SHIFT | r600_dtc[i] << CG_FFCT_0__DTC_0__SHIFT));
if (td == R600_TD_AUTO)
- WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_FORCE_TREND_SEL);
+ WREG32_P(mmSCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_CNTL__FIR_FORCE_TREND_SEL_MASK);
else
- WREG32_P(SCLK_PWRMGT_CNTL, FIR_FORCE_TREND_SEL, ~FIR_FORCE_TREND_SEL);
+ WREG32_P(mmSCLK_PWRMGT_CNTL, SCLK_PWRMGT_CNTL__FIR_FORCE_TREND_SEL_MASK, ~SCLK_PWRMGT_CNTL__FIR_FORCE_TREND_SEL_MASK);
if (td == R600_TD_UP)
- WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_TREND_MODE);
+ WREG32_P(mmSCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_CNTL__FIR_TREND_MODE_MASK);
if (td == R600_TD_DOWN)
- WREG32_P(SCLK_PWRMGT_CNTL, FIR_TREND_MODE, ~FIR_TREND_MODE);
+ WREG32_P(mmSCLK_PWRMGT_CNTL, SCLK_PWRMGT_CNTL__FIR_TREND_MODE_MASK, ~SCLK_PWRMGT_CNTL__FIR_TREND_MODE_MASK);
}
static void si_program_tpp(struct amdgpu_device *adev)
{
- WREG32(CG_TPC, R600_TPC_DFLT);
+ WREG32(mmCG_TPC, R600_TPC_DFLT);
}
static void si_program_sstp(struct amdgpu_device *adev)
{
- WREG32(CG_SSP, (SSTU(R600_SSTU_DFLT) | SST(R600_SST_DFLT)));
+ WREG32(mmCG_SSP, (R600_SSTU_DFLT << CG_SSP__SSTU__SHIFT| R600_SST_DFLT << CG_SSP__SST__SHIFT));
}
static void si_enable_display_gap(struct amdgpu_device *adev)
{
- u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);
+ u32 tmp = RREG32(mmCG_DISPLAY_GAP_CNTL);
- tmp &= ~(DISP1_GAP_MASK | DISP2_GAP_MASK);
- tmp |= (DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE) |
- DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE));
+ tmp &= ~(CG_DISPLAY_GAP_CNTL__DISP1_GAP_MASK | CG_DISPLAY_GAP_CNTL__DISP2_GAP_MASK);
+ tmp |= (R600_PM_DISPLAY_GAP_IGNORE << CG_DISPLAY_GAP_CNTL__DISP1_GAP__SHIFT |
+ R600_PM_DISPLAY_GAP_IGNORE << CG_DISPLAY_GAP_CNTL__DISP2_GAP__SHIFT);
- tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
- tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK) |
- DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE));
- WREG32(CG_DISPLAY_GAP_CNTL, tmp);
+ tmp &= ~(CG_DISPLAY_GAP_CNTL__DISP1_GAP_MCHG_MASK | CG_DISPLAY_GAP_CNTL__DISP2_GAP_MCHG_MASK);
+ tmp |= (R600_PM_DISPLAY_GAP_VBLANK << CG_DISPLAY_GAP_CNTL__DISP1_GAP_MCHG__SHIFT |
+ R600_PM_DISPLAY_GAP_IGNORE << CG_DISPLAY_GAP_CNTL__DISP2_GAP_MCHG__SHIFT);
+ WREG32(mmCG_DISPLAY_GAP_CNTL, tmp);
}
static void si_program_vc(struct amdgpu_device *adev)
{
struct rv7xx_power_info *pi = rv770_get_pi(adev);
- WREG32(CG_FTV, pi->vrc);
+ WREG32(mmCG_FTV, pi->vrc);
}
static void si_clear_vc(struct amdgpu_device *adev)
{
- WREG32(CG_FTV, 0);
+ WREG32(mmCG_FTV, 0);
}
static u8 si_get_ddr3_mclk_frequency_ratio(u32 memory_clock)
@@ -4735,7 +4792,7 @@ static u32 si_calculate_memory_refresh_rate(struct amdgpu_device *adev,
u32 dram_rows;
u32 dram_refresh_rate;
u32 mc_arb_rfsh_rate;
- u32 tmp = (RREG32(MC_ARB_RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT;
+ u32 tmp = (RREG32(mmMC_ARB_RAMCFG) & MC_ARB_RAMCFG__NOOFROWS_MASK) >> MC_ARB_RAMCFG__NOOFROWS__SHIFT;
if (tmp >= 4)
dram_rows = 16384;
@@ -4909,7 +4966,7 @@ static int si_populate_smc_initial_state(struct amdgpu_device *adev,
si_populate_initial_mvdd_value(adev, &table->initialState.level.mvdd);
- reg = CG_R(0xffff) | CG_L(0);
+ reg = 0xffff << CG_AT__CG_R__SHIFT | 0 << CG_AT__CG_L__SHIFT;
table->initialState.level.aT = cpu_to_be32(reg);
table->initialState.level.bSP = cpu_to_be32(pi->dsp);
table->initialState.level.gen2PCIE = (u8)si_pi->boot_pcie_gen;
@@ -4935,10 +4992,13 @@ static int si_populate_smc_initial_state(struct amdgpu_device *adev,
table->initialState.level.dpm2.BelowSafeInc = 0;
table->initialState.level.dpm2.PwrEfficiencyRatio = 0;
- reg = MIN_POWER_MASK | MAX_POWER_MASK;
+ reg = SQ_POWER_THROTTLE__MIN_POWER_MASK |
+ SQ_POWER_THROTTLE__MAX_POWER_MASK;
table->initialState.level.SQPowerThrottle = cpu_to_be32(reg);
- reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
+ reg = SQ_POWER_THROTTLE2__MAX_POWER_DELTA_MASK |
+ SQ_POWER_THROTTLE2__SHORT_TERM_INTERVAL_SIZE_MASK |
+ SQ_POWER_THROTTLE2__LONG_TERM_INTERVAL_RATIO_MASK;
table->initialState.level.SQPowerThrottle_2 = cpu_to_be32(reg);
return 0;
@@ -5057,8 +5117,8 @@ static int si_populate_smc_acpi_state(struct amdgpu_device *adev,
dll_cntl &= ~(MRDCK0_BYPASS | MRDCK1_BYPASS);
- spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
- spll_func_cntl_2 |= SCLK_MUX_SEL(4);
+ spll_func_cntl_2 &= ~CG_SPLL_FUNC_CNTL_2__SCLK_MUX_SEL_MASK;
+ spll_func_cntl_2 |= 4 << CG_SPLL_FUNC_CNTL_2__SCLK_MUX_SEL__SHIFT;
table->ACPIState.level.mclk.vDLL_CNTL =
cpu_to_be32(dll_cntl);
@@ -5102,10 +5162,10 @@ static int si_populate_smc_acpi_state(struct amdgpu_device *adev,
table->ACPIState.level.dpm2.BelowSafeInc = 0;
table->ACPIState.level.dpm2.PwrEfficiencyRatio = 0;
- reg = MIN_POWER_MASK | MAX_POWER_MASK;
+ reg = SQ_POWER_THROTTLE__MIN_POWER_MASK | SQ_POWER_THROTTLE__MAX_POWER_MASK;
table->ACPIState.level.SQPowerThrottle = cpu_to_be32(reg);
- reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
+ reg = SQ_POWER_THROTTLE2__MAX_POWER_DELTA_MASK | SQ_POWER_THROTTLE2__SHORT_TERM_INTERVAL_SIZE_MASK | SQ_POWER_THROTTLE2__LONG_TERM_INTERVAL_RATIO_MASK;
table->ACPIState.level.SQPowerThrottle_2 = cpu_to_be32(reg);
return 0;
@@ -5250,8 +5310,8 @@ static int si_init_smc_table(struct amdgpu_device *adev)
if (ret)
return ret;
- WREG32(CG_ULV_CONTROL, ulv->cg_ulv_control);
- WREG32(CG_ULV_PARAMETER, ulv->cg_ulv_parameter);
+ WREG32(mmCG_ULV_CONTROL, ulv->cg_ulv_control);
+ WREG32(mmCG_ULV_PARAMETER, ulv->cg_ulv_parameter);
lane_width = amdgpu_get_pcie_lanes(adev);
si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_non_ulv_pcie_link_width, lane_width);
@@ -5294,16 +5354,16 @@ static int si_calculate_sclk_params(struct amdgpu_device *adev,
do_div(tmp, reference_clock);
fbdiv = (u32) tmp;
- spll_func_cntl &= ~(SPLL_PDIV_A_MASK | SPLL_REF_DIV_MASK);
- spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div);
- spll_func_cntl |= SPLL_PDIV_A(dividers.post_div);
+ spll_func_cntl &= ~(CG_SPLL_FUNC_CNTL__SPLL_PDIV_A_MASK | CG_SPLL_FUNC_CNTL__SPLL_REF_DIV_MASK);
+ spll_func_cntl |= dividers.ref_div << CG_SPLL_FUNC_CNTL__SPLL_REF_DIV__SHIFT;
+ spll_func_cntl |= dividers.post_div << CG_SPLL_FUNC_CNTL__SPLL_PDIV_A__SHIFT;
- spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
- spll_func_cntl_2 |= SCLK_MUX_SEL(2);
+ spll_func_cntl_2 &= ~CG_SPLL_FUNC_CNTL_2__SCLK_MUX_SEL_MASK;
+ spll_func_cntl_2 |= 2 << CG_SPLL_FUNC_CNTL_2__SCLK_MUX_SEL__SHIFT;
- spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK;
- spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv);
- spll_func_cntl_3 |= SPLL_DITHEN;
+ spll_func_cntl_3 &= ~CG_SPLL_FUNC_CNTL_3__SPLL_FB_DIV_MASK;
+ spll_func_cntl_3 |= fbdiv << CG_SPLL_FUNC_CNTL_3__SPLL_FB_DIV__SHIFT;
+ spll_func_cntl_3 |= CG_SPLL_FUNC_CNTL_3__SPLL_DITHEN_MASK;
if (pi->sclk_ss) {
struct amdgpu_atom_ss ss;
@@ -5314,12 +5374,12 @@ static int si_calculate_sclk_params(struct amdgpu_device *adev,
u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate);
u32 clk_v = 4 * ss.percentage * fbdiv / (clk_s * 10000);
- cg_spll_spread_spectrum &= ~CLK_S_MASK;
- cg_spll_spread_spectrum |= CLK_S(clk_s);
- cg_spll_spread_spectrum |= SSEN;
+ cg_spll_spread_spectrum &= ~CG_SPLL_SPREAD_SPECTRUM__CLK_S_MASK;
+ cg_spll_spread_spectrum |= clk_s << CG_SPLL_SPREAD_SPECTRUM__CLK_S__SHIFT;
+ cg_spll_spread_spectrum |= CG_SPLL_SPREAD_SPECTRUM__SSEN_MASK;
- cg_spll_spread_spectrum_2 &= ~CLK_V_MASK;
- cg_spll_spread_spectrum_2 |= CLK_V(clk_v);
+ cg_spll_spread_spectrum_2 &= ~CG_SPLL_SPREAD_SPECTRUM_2__CLK_V_MASK;
+ cg_spll_spread_spectrum_2 |= clk_v << CG_SPLL_SPREAD_SPECTRUM_2__CLK_V__SHIFT;
}
}
@@ -5485,8 +5545,8 @@ static int si_convert_power_level_to_smc(struct amdgpu_device *adev,
if (pi->mclk_stutter_mode_threshold &&
(pl->mclk <= pi->mclk_stutter_mode_threshold) &&
!eg_pi->uvd_enabled &&
- (RREG32(DPG_PIPE_STUTTER_CONTROL) & STUTTER_ENABLE) &&
- (adev->pm.dpm.new_active_crtc_count <= 2)) {
+ (RREG32(mmDPG_PIPE_STUTTER_CONTROL) & DPG_PIPE_STUTTER_CONTROL__STUTTER_ENABLE_MASK) &&
+ (adev->pm.pm_display_cfg.num_display <= 2)) {
level->mcFlags |= SISLANDS_SMC_MC_STUTTER_EN;
}
@@ -5579,7 +5639,7 @@ static int si_populate_smc_t(struct amdgpu_device *adev,
return -EINVAL;
if (state->performance_level_count < 2) {
- a_t = CG_R(0xffff) | CG_L(0);
+ a_t = 0xffff << CG_AT__CG_R__SHIFT | 0 << CG_AT__CG_L__SHIFT;
smc_state->levels[0].aT = cpu_to_be32(a_t);
return 0;
}
@@ -5600,13 +5660,13 @@ static int si_populate_smc_t(struct amdgpu_device *adev,
t_l = (i + 1) * 1000 + 50 * R600_AH_DFLT;
}
- a_t = be32_to_cpu(smc_state->levels[i].aT) & ~CG_R_MASK;
- a_t |= CG_R(t_l * pi->bsp / 20000);
+ a_t = be32_to_cpu(smc_state->levels[i].aT) & ~CG_AT__CG_R_MASK;
+ a_t |= (t_l * pi->bsp / 20000) << CG_AT__CG_R__SHIFT;
smc_state->levels[i].aT = cpu_to_be32(a_t);
high_bsp = (i == state->performance_level_count - 2) ?
pi->pbsp : pi->bsp;
- a_t = CG_R(0xffff) | CG_L(t_h * high_bsp / 20000);
+ a_t = (0xffff) << CG_AT__CG_R__SHIFT | (t_h * high_bsp / 20000) << CG_AT__CG_L__SHIFT;
smc_state->levels[i + 1].aT = cpu_to_be32(a_t);
}
@@ -5615,14 +5675,10 @@ static int si_populate_smc_t(struct amdgpu_device *adev,
static int si_disable_ulv(struct amdgpu_device *adev)
{
- struct si_power_info *si_pi = si_get_pi(adev);
- struct si_ulv_param *ulv = &si_pi->ulv;
-
- if (ulv->supported)
- return (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_DisableULV) == PPSMC_Result_OK) ?
- 0 : -EINVAL;
+ PPSMC_Result r;
- return 0;
+ r = amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_DisableULV);
+ return (r == PPSMC_Result_OK) ? 0 : -EINVAL;
}
static bool si_is_state_ulv_compatible(struct amdgpu_device *adev,
@@ -5639,7 +5695,7 @@ static bool si_is_state_ulv_compatible(struct amdgpu_device *adev,
/* XXX validate against display requirements! */
for (i = 0; i < adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count; i++) {
- if (adev->clock.current_dispclk <=
+ if (adev->pm.pm_display_cfg.display_clk <=
adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[i].clk) {
if (ulv->pl.vddc <
adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[i].v)
@@ -5793,39 +5849,36 @@ static int si_upload_ulv_state(struct amdgpu_device *adev)
static int si_upload_smc_data(struct amdgpu_device *adev)
{
- struct amdgpu_crtc *amdgpu_crtc = NULL;
- int i;
+ const struct amd_pp_display_configuration *cfg = &adev->pm.pm_display_cfg;
+ u32 crtc_index = 0;
+ u32 mclk_change_block_cp_min = 0;
+ u32 mclk_change_block_cp_max = 0;
- if (adev->pm.dpm.new_active_crtc_count == 0)
- return 0;
+ /* When a display is plugged in, program these so that the SMC
+ * performs MCLK switching when it doesn't cause flickering.
+ * When no display is plugged in, there is no need to restrict
+ * MCLK switching, so program them to zero.
+ */
+ if (cfg->num_display) {
+ crtc_index = cfg->crtc_index;
- for (i = 0; i < adev->mode_info.num_crtc; i++) {
- if (adev->pm.dpm.new_active_crtcs & (1 << i)) {
- amdgpu_crtc = adev->mode_info.crtcs[i];
- break;
+ if (cfg->line_time_in_us) {
+ mclk_change_block_cp_min = 200 / cfg->line_time_in_us;
+ mclk_change_block_cp_max = 100 / cfg->line_time_in_us;
}
}
- if (amdgpu_crtc == NULL)
- return 0;
-
- if (amdgpu_crtc->line_time <= 0)
- return 0;
-
- if (si_write_smc_soft_register(adev,
- SI_SMC_SOFT_REGISTER_crtc_index,
- amdgpu_crtc->crtc_id) != PPSMC_Result_OK)
- return 0;
+ si_write_smc_soft_register(adev,
+ SI_SMC_SOFT_REGISTER_crtc_index,
+ crtc_index);
- if (si_write_smc_soft_register(adev,
- SI_SMC_SOFT_REGISTER_mclk_change_block_cp_min,
- amdgpu_crtc->wm_high / amdgpu_crtc->line_time) != PPSMC_Result_OK)
- return 0;
+ si_write_smc_soft_register(adev,
+ SI_SMC_SOFT_REGISTER_mclk_change_block_cp_min,
+ mclk_change_block_cp_min);
- if (si_write_smc_soft_register(adev,
- SI_SMC_SOFT_REGISTER_mclk_change_block_cp_max,
- amdgpu_crtc->wm_low / amdgpu_crtc->line_time) != PPSMC_Result_OK)
- return 0;
+ si_write_smc_soft_register(adev,
+ SI_SMC_SOFT_REGISTER_mclk_change_block_cp_max,
+ mclk_change_block_cp_max);
return 0;
}
@@ -6009,7 +6062,7 @@ static int si_initialize_mc_reg_table(struct amdgpu_device *adev)
u8 module_index = rv770_get_memory_module_index(adev);
int ret;
- table = kzalloc(sizeof(struct atom_mc_reg_table), GFP_KERNEL);
+ table = kzalloc_obj(struct atom_mc_reg_table);
if (!table)
return -ENOMEM;
@@ -6180,9 +6233,9 @@ static int si_upload_mc_reg_table(struct amdgpu_device *adev,
static void si_enable_voltage_control(struct amdgpu_device *adev, bool enable)
{
if (enable)
- WREG32_P(GENERAL_PWRMGT, VOLT_PWRMGT_EN, ~VOLT_PWRMGT_EN);
+ WREG32_P(mmGENERAL_PWRMGT, GENERAL_PWRMGT__VOLT_PWRMGT_EN_MASK, ~GENERAL_PWRMGT__VOLT_PWRMGT_EN_MASK);
else
- WREG32_P(GENERAL_PWRMGT, 0, ~VOLT_PWRMGT_EN);
+ WREG32_P(mmGENERAL_PWRMGT, 0, ~GENERAL_PWRMGT__VOLT_PWRMGT_EN_MASK);
}
static enum si_pcie_gen si_get_maximum_link_speed(struct amdgpu_device *adev,
@@ -6204,8 +6257,8 @@ static u16 si_get_current_pcie_speed(struct amdgpu_device *adev)
{
u32 speed_cntl;
- speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL) & LC_CURRENT_DATA_RATE_MASK;
- speed_cntl >>= LC_CURRENT_DATA_RATE_SHIFT;
+ speed_cntl = RREG32_PCIE_PORT(ixPCIE_LC_SPEED_CNTL) & PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK;
+ speed_cntl >>= PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT;
return (u16)speed_cntl;
}
@@ -6412,21 +6465,21 @@ static void si_dpm_setup_asic(struct amdgpu_device *adev)
static int si_thermal_enable_alert(struct amdgpu_device *adev,
bool enable)
{
- u32 thermal_int = RREG32(CG_THERMAL_INT);
+ u32 thermal_int = RREG32(mmCG_THERMAL_INT);
if (enable) {
PPSMC_Result result;
- thermal_int &= ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
- WREG32(CG_THERMAL_INT, thermal_int);
+ thermal_int &= ~(CG_THERMAL_INT__THERM_INT_MASK_HIGH_MASK | CG_THERMAL_INT__THERM_INT_MASK_LOW_MASK);
+ WREG32(mmCG_THERMAL_INT, thermal_int);
result = amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_EnableThermalInterrupt);
if (result != PPSMC_Result_OK) {
DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
return -EINVAL;
}
} else {
- thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW;
- WREG32(CG_THERMAL_INT, thermal_int);
+ thermal_int |= CG_THERMAL_INT__THERM_INT_MASK_HIGH_MASK | CG_THERMAL_INT__THERM_INT_MASK_LOW_MASK;
+ WREG32(mmCG_THERMAL_INT, thermal_int);
}
return 0;
@@ -6447,9 +6500,9 @@ static int si_thermal_set_temperature_range(struct amdgpu_device *adev,
return -EINVAL;
}
- WREG32_P(CG_THERMAL_INT, DIG_THERM_INTH(high_temp / 1000), ~DIG_THERM_INTH_MASK);
- WREG32_P(CG_THERMAL_INT, DIG_THERM_INTL(low_temp / 1000), ~DIG_THERM_INTL_MASK);
- WREG32_P(CG_THERMAL_CTRL, DIG_THERM_DPM(high_temp / 1000), ~DIG_THERM_DPM_MASK);
+ WREG32_P(mmCG_THERMAL_INT, (high_temp / 1000) << CG_THERMAL_INT__DIG_THERM_INTH__SHIFT, ~CG_THERMAL_INT__DIG_THERM_INTH_MASK);
+ WREG32_P(mmCG_THERMAL_INT, (low_temp / 1000) << CG_THERMAL_INT__DIG_THERM_INTL__SHIFT, ~CG_THERMAL_INT__DIG_THERM_INTL_MASK);
+ WREG32_P(mmCG_THERMAL_CTRL, (high_temp / 1000) << CG_THERMAL_CTRL__DIG_THERM_DPM__SHIFT, ~CG_THERMAL_CTRL__DIG_THERM_DPM_MASK);
adev->pm.dpm.thermal.min_temp = low_temp;
adev->pm.dpm.thermal.max_temp = high_temp;
@@ -6463,20 +6516,20 @@ static void si_fan_ctrl_set_static_mode(struct amdgpu_device *adev, u32 mode)
u32 tmp;
if (si_pi->fan_ctrl_is_in_default_mode) {
- tmp = (RREG32(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK) >> FDO_PWM_MODE_SHIFT;
+ tmp = (RREG32(mmCG_FDO_CTRL2) & CG_FDO_CTRL2__FDO_PWM_MODE_MASK) >> CG_FDO_CTRL2__FDO_PWM_MODE__SHIFT;
si_pi->fan_ctrl_default_mode = tmp;
- tmp = (RREG32(CG_FDO_CTRL2) & TMIN_MASK) >> TMIN_SHIFT;
+ tmp = (RREG32(mmCG_FDO_CTRL2) & CG_FDO_CTRL2__TMIN_MASK) >> CG_FDO_CTRL2__TMIN__SHIFT;
si_pi->t_min = tmp;
si_pi->fan_ctrl_is_in_default_mode = false;
}
- tmp = RREG32(CG_FDO_CTRL2) & ~TMIN_MASK;
- tmp |= TMIN(0);
- WREG32(CG_FDO_CTRL2, tmp);
+ tmp = RREG32(mmCG_FDO_CTRL2) & ~CG_FDO_CTRL2__TMIN_MASK;
+ tmp |= 0 << CG_FDO_CTRL2__TMIN__SHIFT;
+ WREG32(mmCG_FDO_CTRL2, tmp);
- tmp = RREG32(CG_FDO_CTRL2) & ~FDO_PWM_MODE_MASK;
- tmp |= FDO_PWM_MODE(mode);
- WREG32(CG_FDO_CTRL2, tmp);
+ tmp = RREG32(mmCG_FDO_CTRL2) & ~CG_FDO_CTRL2__FDO_PWM_MODE_MASK;
+ tmp |= mode << CG_FDO_CTRL2__FDO_PWM_MODE__SHIFT;
+ WREG32(mmCG_FDO_CTRL2, tmp);
}
static int si_thermal_setup_fan_table(struct amdgpu_device *adev)
@@ -6495,7 +6548,7 @@ static int si_thermal_setup_fan_table(struct amdgpu_device *adev)
return 0;
}
- duty100 = (RREG32(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
+ duty100 = (RREG32(mmCG_FDO_CTRL1) & CG_FDO_CTRL1__FMAX_DUTY100_MASK) >> CG_FDO_CTRL1__FMAX_DUTY100__SHIFT;
if (duty100 == 0) {
adev->pm.dpm.fan.ucode_fan_control = false;
@@ -6531,7 +6584,7 @@ static int si_thermal_setup_fan_table(struct amdgpu_device *adev)
reference_clock) / 1600);
fan_table.fdo_max = cpu_to_be16((u16)duty100);
- tmp = (RREG32(CG_MULT_THERMAL_CTRL) & TEMP_SEL_MASK) >> TEMP_SEL_SHIFT;
+ tmp = (RREG32(mmCG_MULT_THERMAL_CTRL) & CG_MULT_THERMAL_CTRL__TEMP_SEL_MASK) >> CG_MULT_THERMAL_CTRL__TEMP_SEL__SHIFT;
fan_table.temp_src = (uint8_t)tmp;
ret = amdgpu_si_copy_bytes_to_smc(adev,
@@ -6590,8 +6643,8 @@ static int si_dpm_get_fan_speed_pwm(void *handle,
if (adev->pm.no_fan)
return -ENOENT;
- duty100 = (RREG32(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
- duty = (RREG32(CG_THERMAL_STATUS) & FDO_PWM_DUTY_MASK) >> FDO_PWM_DUTY_SHIFT;
+ duty100 = (RREG32(mmCG_FDO_CTRL1) & CG_FDO_CTRL1__FMAX_DUTY100_MASK) >> CG_FDO_CTRL1__FMAX_DUTY100__SHIFT;
+ duty = (RREG32(mmCG_THERMAL_STATUS) & CG_THERMAL_STATUS__FDO_PWM_DUTY_MASK) >> CG_THERMAL_STATUS__FDO_PWM_DUTY__SHIFT;
if (duty100 == 0)
return -EINVAL;
@@ -6621,7 +6674,7 @@ static int si_dpm_set_fan_speed_pwm(void *handle,
if (speed > 255)
return -EINVAL;
- duty100 = (RREG32(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
+ duty100 = (RREG32(mmCG_FDO_CTRL1) & CG_FDO_CTRL1__FMAX_DUTY100_MASK) >> CG_FDO_CTRL1__FMAX_DUTY100__SHIFT;
if (duty100 == 0)
return -EINVAL;
@@ -6630,9 +6683,9 @@ static int si_dpm_set_fan_speed_pwm(void *handle,
do_div(tmp64, 255);
duty = (u32)tmp64;
- tmp = RREG32(CG_FDO_CTRL0) & ~FDO_STATIC_DUTY_MASK;
- tmp |= FDO_STATIC_DUTY(duty);
- WREG32(CG_FDO_CTRL0, tmp);
+ tmp = RREG32(mmCG_FDO_CTRL0) & ~CG_FDO_CTRL0__FDO_STATIC_DUTY_MASK;
+ tmp |= duty << CG_FDO_CTRL0__FDO_STATIC_DUTY__SHIFT;
+ WREG32(mmCG_FDO_CTRL0, tmp);
return 0;
}
@@ -6672,8 +6725,8 @@ static int si_dpm_get_fan_control_mode(void *handle, u32 *fan_mode)
if (si_pi->fan_is_controlled_by_smc)
return 0;
- tmp = RREG32(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK;
- *fan_mode = (tmp >> FDO_PWM_MODE_SHIFT);
+ tmp = RREG32(mmCG_FDO_CTRL2) & CG_FDO_CTRL2__FDO_PWM_MODE_MASK;
+ *fan_mode = (tmp >> CG_FDO_CTRL2__FDO_PWM_MODE__SHIFT);
return 0;
}
@@ -6691,7 +6744,7 @@ static int si_fan_ctrl_get_fan_speed_rpm(struct amdgpu_device *adev,
if (adev->pm.fan_pulses_per_revolution == 0)
return -ENOENT;
- tach_period = (RREG32(CG_TACH_STATUS) & TACH_PERIOD_MASK) >> TACH_PERIOD_SHIFT;
+ tach_period = (RREG32(mmCG_TACH_STATUS) & CG_TACH_STATUS__TACH_PERIOD_MASK) >> CG_TACH_STATUS__TACH_PERIOD__SHIFT;
if (tach_period == 0)
return -ENOENT;
@@ -6720,9 +6773,9 @@ static int si_fan_ctrl_set_fan_speed_rpm(struct amdgpu_device *adev,
si_fan_ctrl_stop_smc_fan_control(adev);
tach_period = 60 * xclk * 10000 / (8 * speed);
- tmp = RREG32(CG_TACH_CTRL) & ~TARGET_PERIOD_MASK;
- tmp |= TARGET_PERIOD(tach_period);
- WREG32(CG_TACH_CTRL, tmp);
+ tmp = RREG32(mmCG_TACH_CTRL) & ~CG_TACH_CTRL__TARGET_PERIOD_MASK;
+ tmp |= tach_period << CG_TACH_CTRL__TARGET_PERIOD__SHIFT;
+ WREG32(mmCG_TACH_CTRL, tmp);
si_fan_ctrl_set_static_mode(adev, FDO_PWM_MODE_STATIC_RPM);
@@ -6736,13 +6789,13 @@ static void si_fan_ctrl_set_default_mode(struct amdgpu_device *adev)
u32 tmp;
if (!si_pi->fan_ctrl_is_in_default_mode) {
- tmp = RREG32(CG_FDO_CTRL2) & ~FDO_PWM_MODE_MASK;
- tmp |= FDO_PWM_MODE(si_pi->fan_ctrl_default_mode);
- WREG32(CG_FDO_CTRL2, tmp);
+ tmp = RREG32(mmCG_FDO_CTRL2) & ~CG_FDO_CTRL2__FDO_PWM_MODE_MASK;
+ tmp |= si_pi->fan_ctrl_default_mode << CG_FDO_CTRL2__FDO_PWM_MODE__SHIFT;
+ WREG32(mmCG_FDO_CTRL2, tmp);
- tmp = RREG32(CG_FDO_CTRL2) & ~TMIN_MASK;
- tmp |= TMIN(si_pi->t_min);
- WREG32(CG_FDO_CTRL2, tmp);
+ tmp = RREG32(mmCG_FDO_CTRL2) & ~CG_FDO_CTRL2__TMIN_MASK;
+ tmp |= si_pi->t_min << CG_FDO_CTRL2__TMIN__SHIFT;
+ WREG32(mmCG_FDO_CTRL2, tmp);
si_pi->fan_ctrl_is_in_default_mode = true;
}
}
@@ -6760,14 +6813,14 @@ static void si_thermal_initialize(struct amdgpu_device *adev)
u32 tmp;
if (adev->pm.fan_pulses_per_revolution) {
- tmp = RREG32(CG_TACH_CTRL) & ~EDGE_PER_REV_MASK;
- tmp |= EDGE_PER_REV(adev->pm.fan_pulses_per_revolution -1);
- WREG32(CG_TACH_CTRL, tmp);
+ tmp = RREG32(mmCG_TACH_CTRL) & ~CG_TACH_CTRL__EDGE_PER_REV_MASK;
+ tmp |= (adev->pm.fan_pulses_per_revolution -1) << CG_TACH_CTRL__EDGE_PER_REV__SHIFT;
+ WREG32(mmCG_TACH_CTRL, tmp);
}
- tmp = RREG32(CG_FDO_CTRL2) & ~TACH_PWM_RESP_RATE_MASK;
- tmp |= TACH_PWM_RESP_RATE(0x28);
- WREG32(CG_FDO_CTRL2, tmp);
+ tmp = RREG32(mmCG_FDO_CTRL2) & ~CG_FDO_CTRL2__TACH_PWM_RESP_RATE_MASK;
+ tmp |= 0x28 << CG_FDO_CTRL2__TACH_PWM_RESP_RATE__SHIFT;
+ WREG32(mmCG_FDO_CTRL2, tmp);
}
static int si_thermal_start_thermal_controller(struct amdgpu_device *adev)
@@ -7007,13 +7060,20 @@ static void si_set_vce_clock(struct amdgpu_device *adev,
if ((old_rps->evclk != new_rps->evclk) ||
(old_rps->ecclk != new_rps->ecclk)) {
/* Turn the clocks on when encoding, off otherwise */
+ dev_dbg(adev->dev, "set VCE clocks: %u, %u\n", new_rps->evclk, new_rps->ecclk);
+
if (new_rps->evclk || new_rps->ecclk) {
- /* Place holder for future VCE1.0 porting to amdgpu
- vce_v1_0_enable_mgcg(adev, false, false);*/
+ amdgpu_asic_set_vce_clocks(adev, new_rps->evclk, new_rps->ecclk);
+ amdgpu_device_ip_set_clockgating_state(
+ adev, AMD_IP_BLOCK_TYPE_VCE, AMD_CG_STATE_UNGATE);
+ amdgpu_device_ip_set_powergating_state(
+ adev, AMD_IP_BLOCK_TYPE_VCE, AMD_PG_STATE_UNGATE);
} else {
- /* Place holder for future VCE1.0 porting to amdgpu
- vce_v1_0_enable_mgcg(adev, true, false);
- amdgpu_asic_set_vce_clocks(adev, new_rps->evclk, new_rps->ecclk);*/
+ amdgpu_device_ip_set_powergating_state(
+ adev, AMD_IP_BLOCK_TYPE_VCE, AMD_PG_STATE_GATE);
+ amdgpu_device_ip_set_clockgating_state(
+ adev, AMD_IP_BLOCK_TYPE_VCE, AMD_CG_STATE_GATE);
+ amdgpu_asic_set_vce_clocks(adev, 0, 0);
}
}
}
@@ -7182,6 +7242,7 @@ static void si_parse_pplib_clock_info(struct amdgpu_device *adev,
struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
struct si_power_info *si_pi = si_get_pi(adev);
struct si_ps *ps = si_get_ps(rps);
+ struct amdgpu_clock_and_voltage_limits *limits;
u16 leakage_voltage;
struct rv7xx_pl *pl = &ps->performance_levels[index];
int ret;
@@ -7241,12 +7302,30 @@ static void si_parse_pplib_clock_info(struct amdgpu_device *adev,
si_pi->mvdd_bootup_value = mvdd;
}
+ /*
+ * Update maximum allowed clock limits.
+ * VBIOS can contain conflicting values between:
+ * - the maximum allowed clocks and voltages on AC or DC
+ * - the clocks and voltages in power states on AC or DC
+ */
if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) ==
- ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) {
- adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk = pl->sclk;
- adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk = pl->mclk;
- adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddc = pl->vddc;
- adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddci = pl->vddci;
+ ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE)
+ limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
+ else if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) ==
+ ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)
+ limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
+ else
+ limits = NULL;
+
+ if (limits) {
+ if (pl->sclk > limits->sclk)
+ limits->sclk = pl->sclk;
+ if (pl->mclk > limits->mclk)
+ limits->mclk = pl->mclk;
+ if (pl->vddc > limits->vddc)
+ limits->vddc = pl->vddc;
+ if (pl->vddci > limits->vddci)
+ limits->vddci = pl->vddci;
}
}
@@ -7289,9 +7368,8 @@ static int si_parse_power_table(struct amdgpu_device *adev)
(mode_info->atom_context->bios + data_offset +
le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
- adev->pm.dpm.ps = kcalloc(state_array->ucNumEntries,
- sizeof(struct amdgpu_ps),
- GFP_KERNEL);
+ adev->pm.dpm.ps = kzalloc_objs(struct amdgpu_ps,
+ state_array->ucNumEntries);
if (!adev->pm.dpm.ps)
return -ENOMEM;
power_state_offset = (u8 *)state_array->states;
@@ -7301,7 +7379,7 @@ static int si_parse_power_table(struct amdgpu_device *adev)
non_clock_array_index = power_state->v2.nonClockInfoIndex;
non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
&non_clock_info_array->nonClockInfo[non_clock_array_index];
- ps = kzalloc(sizeof(struct si_ps), GFP_KERNEL);
+ ps = kzalloc_obj(struct si_ps);
if (ps == NULL)
return -ENOMEM;
adev->pm.dpm.ps[i].ps_priv = ps;
@@ -7354,7 +7432,7 @@ static int si_dpm_init(struct amdgpu_device *adev)
struct atom_clock_dividers dividers;
int ret;
- si_pi = kzalloc(sizeof(struct si_power_info), GFP_KERNEL);
+ si_pi = kzalloc_obj(struct si_power_info);
if (si_pi == NULL)
return -ENOMEM;
adev->pm.dpm.priv = si_pi;
@@ -7391,9 +7469,7 @@ static int si_dpm_init(struct amdgpu_device *adev)
return ret;
adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries =
- kcalloc(4,
- sizeof(struct amdgpu_clock_voltage_dependency_entry),
- GFP_KERNEL);
+ kzalloc_objs(struct amdgpu_clock_voltage_dependency_entry, 4);
if (!adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries)
return -ENOMEM;
@@ -7465,8 +7541,6 @@ static int si_dpm_init(struct amdgpu_device *adev)
pi->pasi = CYPRESS_HASI_DFLT;
pi->vrc = SISLANDS_VRC_DFLT;
- pi->gfx_clock_gating = true;
-
eg_pi->sclk_deep_sleep = true;
si_pi->sclk_deep_sleep_above_low = false;
@@ -7477,7 +7551,6 @@ static int si_dpm_init(struct amdgpu_device *adev)
eg_pi->dynamic_ac_timing = true;
- eg_pi->light_sleep = true;
#if defined(CONFIG_ACPI)
eg_pi->pcie_performance_request =
amdgpu_acpi_is_pcie_performance_request_supported(adev);
@@ -7530,14 +7603,15 @@ static void si_dpm_debugfs_print_current_performance_level(void *handle,
struct si_ps *ps = si_get_ps(rps);
struct rv7xx_pl *pl;
u32 current_index =
- (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
- CURRENT_STATE_INDEX_SHIFT;
+ (RREG32(mmTARGET_AND_CURRENT_PROFILE_INDEX) & TARGET_AND_CURRENT_PROFILE_INDEX__CURRENT_STATE_INDEX_MASK) >>
+ TARGET_AND_CURRENT_PROFILE_INDEX__CURRENT_STATE_INDEX__SHIFT;
if (current_index >= ps->performance_level_count) {
seq_printf(m, "invalid dpm profile %d\n", current_index);
} else {
pl = &ps->performance_levels[current_index];
seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+ seq_printf(m, "vce evclk: %d ecclk: %d\n", rps->evclk, rps->ecclk);
seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u vddci: %u pcie gen: %u\n",
current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci, pl->pcie_gen + 1);
}
@@ -7554,14 +7628,14 @@ static int si_dpm_set_interrupt_state(struct amdgpu_device *adev,
case AMDGPU_THERMAL_IRQ_LOW_TO_HIGH:
switch (state) {
case AMDGPU_IRQ_STATE_DISABLE:
- cg_thermal_int = RREG32_SMC(CG_THERMAL_INT);
- cg_thermal_int |= THERM_INT_MASK_HIGH;
- WREG32_SMC(CG_THERMAL_INT, cg_thermal_int);
+ cg_thermal_int = RREG32_SMC(mmCG_THERMAL_INT);
+ cg_thermal_int |= CG_THERMAL_INT__THERM_INT_MASK_HIGH_MASK;
+ WREG32(mmCG_THERMAL_INT, cg_thermal_int);
break;
case AMDGPU_IRQ_STATE_ENABLE:
- cg_thermal_int = RREG32_SMC(CG_THERMAL_INT);
- cg_thermal_int &= ~THERM_INT_MASK_HIGH;
- WREG32_SMC(CG_THERMAL_INT, cg_thermal_int);
+ cg_thermal_int = RREG32_SMC(mmCG_THERMAL_INT);
+ cg_thermal_int &= ~CG_THERMAL_INT__THERM_INT_MASK_HIGH_MASK;
+ WREG32(mmCG_THERMAL_INT, cg_thermal_int);
break;
default:
break;
@@ -7571,14 +7645,14 @@ static int si_dpm_set_interrupt_state(struct amdgpu_device *adev,
case AMDGPU_THERMAL_IRQ_HIGH_TO_LOW:
switch (state) {
case AMDGPU_IRQ_STATE_DISABLE:
- cg_thermal_int = RREG32_SMC(CG_THERMAL_INT);
- cg_thermal_int |= THERM_INT_MASK_LOW;
- WREG32_SMC(CG_THERMAL_INT, cg_thermal_int);
+ cg_thermal_int = RREG32_SMC(mmCG_THERMAL_INT);
+ cg_thermal_int |= CG_THERMAL_INT__THERM_INT_MASK_LOW_MASK;
+ WREG32(mmCG_THERMAL_INT, cg_thermal_int);
break;
case AMDGPU_IRQ_STATE_ENABLE:
- cg_thermal_int = RREG32_SMC(CG_THERMAL_INT);
- cg_thermal_int &= ~THERM_INT_MASK_LOW;
- WREG32_SMC(CG_THERMAL_INT, cg_thermal_int);
+ cg_thermal_int = RREG32_SMC(mmCG_THERMAL_INT);
+ cg_thermal_int &= ~CG_THERMAL_INT__THERM_INT_MASK_LOW_MASK;
+ WREG32(mmCG_THERMAL_INT, cg_thermal_int);
break;
default:
break;
@@ -7756,13 +7830,12 @@ static int si_dpm_sw_init(struct amdgpu_ip_block *ip_block)
adev->pm.dpm.current_ps = adev->pm.dpm.requested_ps = adev->pm.dpm.boot_ps;
if (amdgpu_dpm == 1)
amdgpu_pm_print_power_states(adev);
- DRM_INFO("amdgpu: dpm initialized\n");
-
+ drm_info(adev_to_drm(adev), "si dpm initialized\n");
return 0;
dpm_failed:
si_dpm_fini(adev);
- DRM_ERROR("amdgpu: dpm initialization failed\n");
+ drm_err(adev_to_drm(adev), "dpm initialization failed\n");
return ret;
}
@@ -7852,7 +7925,7 @@ static int si_dpm_resume(struct amdgpu_ip_block *ip_block)
return ret;
}
-static bool si_dpm_is_idle(void *handle)
+static bool si_dpm_is_idle(struct amdgpu_ip_block *ip_block)
{
/* XXX */
return true;
@@ -7883,8 +7956,8 @@ static int si_dpm_get_temp(void *handle)
int actual_temp = 0;
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- temp = (RREG32(CG_MULT_THERMAL_STATUS) & CTF_TEMP_MASK) >>
- CTF_TEMP_SHIFT;
+ temp = (RREG32(mmCG_MULT_THERMAL_STATUS) & CG_MULT_THERMAL_STATUS__CTF_TEMP_MASK) >>
+ CG_MULT_THERMAL_STATUS__CTF_TEMP__SHIFT;
if (temp & 0x200)
actual_temp = 255;
@@ -7929,15 +8002,16 @@ static void si_dpm_print_power_state(void *handle,
struct rv7xx_pl *pl;
int i;
- amdgpu_dpm_print_class_info(rps->class, rps->class2);
- amdgpu_dpm_print_cap_info(rps->caps);
- DRM_INFO("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+ amdgpu_dpm_dbg_print_class_info(adev, rps->class, rps->class2);
+ amdgpu_dpm_dbg_print_cap_info(adev, rps->caps);
+ drm_dbg(adev_to_drm(adev), "\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+ drm_dbg(adev_to_drm(adev), "\tvce evclk: %d ecclk: %d\n", rps->evclk, rps->ecclk);
for (i = 0; i < ps->performance_level_count; i++) {
pl = &ps->performance_levels[i];
- DRM_INFO("\t\tpower level %d sclk: %u mclk: %u vddc: %u vddci: %u pcie gen: %u\n",
+ drm_dbg(adev_to_drm(adev), "\t\tpower level %d sclk: %u mclk: %u vddc: %u vddci: %u pcie gen: %u\n",
i, pl->sclk, pl->mclk, pl->vddc, pl->vddci, pl->pcie_gen + 1);
}
- amdgpu_dpm_print_ps_status(adev, rps);
+ amdgpu_dpm_dbg_print_ps_status(adev, rps);
}
static int si_dpm_early_init(struct amdgpu_ip_block *ip_block)
@@ -8014,8 +8088,8 @@ static int si_dpm_read_sensor(void *handle, int idx,
struct si_ps *ps = si_get_ps(rps);
uint32_t sclk, mclk;
u32 pl_index =
- (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
- CURRENT_STATE_INDEX_SHIFT;
+ (RREG32(mmTARGET_AND_CURRENT_PROFILE_INDEX) & TARGET_AND_CURRENT_PROFILE_INDEX__CURRENT_STATE_INDEX_MASK) >>
+ TARGET_AND_CURRENT_PROFILE_INDEX__CURRENT_STATE_INDEX__SHIFT;
/* size must be at least 4 bytes for all sensors */
if (*size < 4)
@@ -8091,6 +8165,7 @@ static const struct amd_pm_funcs si_dpm_funcs = {
.get_vce_clock_state = amdgpu_get_vce_clock_state,
.read_sensor = &si_dpm_read_sensor,
.pm_compute_clocks = amdgpu_legacy_dpm_compute_clocks,
+ .notify_ac_dc = si_notify_hw_of_powersource,
};
static const struct amdgpu_irq_src_funcs si_dpm_irq_funcs = {
diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.h b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.h
index 11cb7874a6bb..3aed75fbf913 100644
--- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.h
+++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.h
@@ -38,11 +38,7 @@
#define MC_ARB_DRAM_TIMING2_2 0xa00
#define MC_ARB_DRAM_TIMING2_3 0xa01
-#define MAX_NO_OF_MVDD_VALUES 2
-#define MAX_NO_VREG_STEPS 32
#define NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE 16
-#define SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE 32
-#define SMC_NISLANDS_MC_REGISTER_ARRAY_SET_COUNT 20
#define RV770_ASI_DFLT 1000
#define CYPRESS_HASI_DFLT 400000
#define PCIE_PERF_REQ_PECI_GEN1 2
@@ -51,11 +47,6 @@
#define RV770_DEFAULT_VCLK_FREQ 53300 /* 10 khz */
#define RV770_DEFAULT_DCLK_FREQ 40000 /* 10 khz */
-#define SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE 16
-
-#define RV770_SMC_TABLE_ADDRESS 0xB000
-#define RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE 3
-
#define SMC_STROBE_RATIO 0x0F
#define SMC_STROBE_ENABLE 0x10
@@ -64,27 +55,6 @@
#define SMC_MC_RTT_ENABLE 0x04
#define SMC_MC_STUTTER_EN 0x08
-#define RV770_SMC_VOLTAGEMASK_VDDC 0
-#define RV770_SMC_VOLTAGEMASK_MVDD 1
-#define RV770_SMC_VOLTAGEMASK_VDDCI 2
-#define RV770_SMC_VOLTAGEMASK_MAX 4
-
-#define NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE 16
-#define NISLANDS_SMC_STROBE_RATIO 0x0F
-#define NISLANDS_SMC_STROBE_ENABLE 0x10
-
-#define NISLANDS_SMC_MC_EDC_RD_FLAG 0x01
-#define NISLANDS_SMC_MC_EDC_WR_FLAG 0x02
-#define NISLANDS_SMC_MC_RTT_ENABLE 0x04
-#define NISLANDS_SMC_MC_STUTTER_EN 0x08
-
-#define MAX_NO_VREG_STEPS 32
-
-#define NISLANDS_SMC_VOLTAGEMASK_VDDC 0
-#define NISLANDS_SMC_VOLTAGEMASK_MVDD 1
-#define NISLANDS_SMC_VOLTAGEMASK_VDDCI 2
-#define NISLANDS_SMC_VOLTAGEMASK_MAX 4
-
#define SISLANDS_MCREGISTERTABLE_INITIAL_SLOT 0
#define SISLANDS_MCREGISTERTABLE_ACPI_SLOT 1
#define SISLANDS_MCREGISTERTABLE_ULV_SLOT 2
@@ -219,32 +189,6 @@ enum si_cac_config_reg_type
SISLANDS_CACCONFIG_MAX
};
-enum si_power_level {
- SI_POWER_LEVEL_LOW = 0,
- SI_POWER_LEVEL_MEDIUM = 1,
- SI_POWER_LEVEL_HIGH = 2,
- SI_POWER_LEVEL_CTXSW = 3,
-};
-
-enum si_td {
- SI_TD_AUTO,
- SI_TD_UP,
- SI_TD_DOWN,
-};
-
-enum si_display_watermark {
- SI_DISPLAY_WATERMARK_LOW = 0,
- SI_DISPLAY_WATERMARK_HIGH = 1,
-};
-
-enum si_display_gap
-{
- SI_PM_DISPLAY_GAP_VBLANK_OR_WM = 0,
- SI_PM_DISPLAY_GAP_VBLANK = 1,
- SI_PM_DISPLAY_GAP_WATERMARK = 2,
- SI_PM_DISPLAY_GAP_IGNORE = 3,
-};
-
extern const struct amdgpu_ip_block_version si_smu_ip_block;
struct ni_leakage_coeffients
@@ -258,56 +202,6 @@ struct ni_leakage_coeffients
u32 t_ref;
};
-struct SMC_Evergreen_MCRegisterAddress
-{
- uint16_t s0;
- uint16_t s1;
-};
-
-typedef struct SMC_Evergreen_MCRegisterAddress SMC_Evergreen_MCRegisterAddress;
-
-struct evergreen_mc_reg_entry {
- u32 mclk_max;
- u32 mc_data[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE];
-};
-
-struct evergreen_mc_reg_table {
- u8 last;
- u8 num_entries;
- u16 valid_flag;
- struct evergreen_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
- SMC_Evergreen_MCRegisterAddress mc_reg_address[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE];
-};
-
-struct SMC_Evergreen_MCRegisterSet
-{
- uint32_t value[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE];
-};
-
-typedef struct SMC_Evergreen_MCRegisterSet SMC_Evergreen_MCRegisterSet;
-
-struct SMC_Evergreen_MCRegisters
-{
- uint8_t last;
- uint8_t reserved[3];
- SMC_Evergreen_MCRegisterAddress address[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE];
- SMC_Evergreen_MCRegisterSet data[5];
-};
-
-typedef struct SMC_Evergreen_MCRegisters SMC_Evergreen_MCRegisters;
-
-struct SMC_NIslands_MCRegisterSet
-{
- uint32_t value[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE];
-};
-
-typedef struct SMC_NIslands_MCRegisterSet SMC_NIslands_MCRegisterSet;
-
-struct ni_mc_reg_entry {
- u32 mclk_max;
- u32 mc_data[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE];
-};
-
struct SMC_NIslands_MCRegisterAddress
{
uint16_t s0;
@@ -316,257 +210,20 @@ struct SMC_NIslands_MCRegisterAddress
typedef struct SMC_NIslands_MCRegisterAddress SMC_NIslands_MCRegisterAddress;
-struct SMC_NIslands_MCRegisters
-{
- uint8_t last;
- uint8_t reserved[3];
- SMC_NIslands_MCRegisterAddress address[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE];
- SMC_NIslands_MCRegisterSet data[SMC_NISLANDS_MC_REGISTER_ARRAY_SET_COUNT];
-};
-
-typedef struct SMC_NIslands_MCRegisters SMC_NIslands_MCRegisters;
-
-struct evergreen_ulv_param {
- bool supported;
- struct rv7xx_pl *pl;
-};
-
-struct evergreen_arb_registers {
- u32 mc_arb_dram_timing;
- u32 mc_arb_dram_timing2;
- u32 mc_arb_rfsh_rate;
- u32 mc_arb_burst_time;
-};
-
-struct at {
- u32 rlp;
- u32 rmp;
- u32 lhp;
- u32 lmp;
-};
-
-struct ni_clock_registers {
- u32 cg_spll_func_cntl;
- u32 cg_spll_func_cntl_2;
- u32 cg_spll_func_cntl_3;
- u32 cg_spll_func_cntl_4;
- u32 cg_spll_spread_spectrum;
- u32 cg_spll_spread_spectrum_2;
- u32 mclk_pwrmgt_cntl;
- u32 dll_cntl;
- u32 mpll_ad_func_cntl;
- u32 mpll_ad_func_cntl_2;
- u32 mpll_dq_func_cntl;
- u32 mpll_dq_func_cntl_2;
- u32 mpll_ss1;
- u32 mpll_ss2;
-};
-
-struct RV770_SMC_SCLK_VALUE
-{
- uint32_t vCG_SPLL_FUNC_CNTL;
- uint32_t vCG_SPLL_FUNC_CNTL_2;
- uint32_t vCG_SPLL_FUNC_CNTL_3;
- uint32_t vCG_SPLL_SPREAD_SPECTRUM;
- uint32_t vCG_SPLL_SPREAD_SPECTRUM_2;
- uint32_t sclk_value;
-};
-
-typedef struct RV770_SMC_SCLK_VALUE RV770_SMC_SCLK_VALUE;
-
-struct RV770_SMC_MCLK_VALUE
-{
- uint32_t vMPLL_AD_FUNC_CNTL;
- uint32_t vMPLL_AD_FUNC_CNTL_2;
- uint32_t vMPLL_DQ_FUNC_CNTL;
- uint32_t vMPLL_DQ_FUNC_CNTL_2;
- uint32_t vMCLK_PWRMGT_CNTL;
- uint32_t vDLL_CNTL;
- uint32_t vMPLL_SS;
- uint32_t vMPLL_SS2;
- uint32_t mclk_value;
-};
-
-typedef struct RV770_SMC_MCLK_VALUE RV770_SMC_MCLK_VALUE;
-
-
-struct RV730_SMC_MCLK_VALUE
-{
- uint32_t vMCLK_PWRMGT_CNTL;
- uint32_t vDLL_CNTL;
- uint32_t vMPLL_FUNC_CNTL;
- uint32_t vMPLL_FUNC_CNTL2;
- uint32_t vMPLL_FUNC_CNTL3;
- uint32_t vMPLL_SS;
- uint32_t vMPLL_SS2;
- uint32_t mclk_value;
-};
-
-typedef struct RV730_SMC_MCLK_VALUE RV730_SMC_MCLK_VALUE;
-
-struct RV770_SMC_VOLTAGE_VALUE
-{
- uint16_t value;
- uint8_t index;
- uint8_t padding;
-};
-
-typedef struct RV770_SMC_VOLTAGE_VALUE RV770_SMC_VOLTAGE_VALUE;
-
-union RV7XX_SMC_MCLK_VALUE
-{
- RV770_SMC_MCLK_VALUE mclk770;
- RV730_SMC_MCLK_VALUE mclk730;
-};
-
-typedef union RV7XX_SMC_MCLK_VALUE RV7XX_SMC_MCLK_VALUE, *LPRV7XX_SMC_MCLK_VALUE;
-
-struct RV770_SMC_HW_PERFORMANCE_LEVEL
-{
- uint8_t arbValue;
- union{
- uint8_t seqValue;
- uint8_t ACIndex;
- };
- uint8_t displayWatermark;
- uint8_t gen2PCIE;
- uint8_t gen2XSP;
- uint8_t backbias;
- uint8_t strobeMode;
- uint8_t mcFlags;
- uint32_t aT;
- uint32_t bSP;
- RV770_SMC_SCLK_VALUE sclk;
- RV7XX_SMC_MCLK_VALUE mclk;
- RV770_SMC_VOLTAGE_VALUE vddc;
- RV770_SMC_VOLTAGE_VALUE mvdd;
- RV770_SMC_VOLTAGE_VALUE vddci;
- uint8_t reserved1;
- uint8_t reserved2;
- uint8_t stateFlags;
- uint8_t padding;
-};
-
-typedef struct RV770_SMC_HW_PERFORMANCE_LEVEL RV770_SMC_HW_PERFORMANCE_LEVEL;
-
-struct RV770_SMC_SWSTATE
-{
- uint8_t flags;
- uint8_t padding1;
- uint8_t padding2;
- uint8_t padding3;
- RV770_SMC_HW_PERFORMANCE_LEVEL levels[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE];
-};
-
-typedef struct RV770_SMC_SWSTATE RV770_SMC_SWSTATE;
-
-struct RV770_SMC_VOLTAGEMASKTABLE
-{
- uint8_t highMask[RV770_SMC_VOLTAGEMASK_MAX];
- uint32_t lowMask[RV770_SMC_VOLTAGEMASK_MAX];
-};
-
-typedef struct RV770_SMC_VOLTAGEMASKTABLE RV770_SMC_VOLTAGEMASKTABLE;
-
-struct RV770_SMC_STATETABLE
-{
- uint8_t thermalProtectType;
- uint8_t systemFlags;
- uint8_t maxVDDCIndexInPPTable;
- uint8_t extraFlags;
- uint8_t highSMIO[MAX_NO_VREG_STEPS];
- uint32_t lowSMIO[MAX_NO_VREG_STEPS];
- RV770_SMC_VOLTAGEMASKTABLE voltageMaskTable;
- RV770_SMC_SWSTATE initialState;
- RV770_SMC_SWSTATE ACPIState;
- RV770_SMC_SWSTATE driverState;
- RV770_SMC_SWSTATE ULVState;
-};
-
-typedef struct RV770_SMC_STATETABLE RV770_SMC_STATETABLE;
-
-struct vddc_table_entry {
- u16 vddc;
- u8 vddc_index;
- u8 high_smio;
- u32 low_smio;
-};
-
-struct rv770_clock_registers {
- u32 cg_spll_func_cntl;
- u32 cg_spll_func_cntl_2;
- u32 cg_spll_func_cntl_3;
- u32 cg_spll_spread_spectrum;
- u32 cg_spll_spread_spectrum_2;
- u32 mpll_ad_func_cntl;
- u32 mpll_ad_func_cntl_2;
- u32 mpll_dq_func_cntl;
- u32 mpll_dq_func_cntl_2;
- u32 mclk_pwrmgt_cntl;
- u32 dll_cntl;
- u32 mpll_ss1;
- u32 mpll_ss2;
-};
-
-struct rv730_clock_registers {
- u32 cg_spll_func_cntl;
- u32 cg_spll_func_cntl_2;
- u32 cg_spll_func_cntl_3;
- u32 cg_spll_spread_spectrum;
- u32 cg_spll_spread_spectrum_2;
- u32 mclk_pwrmgt_cntl;
- u32 dll_cntl;
- u32 mpll_func_cntl;
- u32 mpll_func_cntl2;
- u32 mpll_func_cntl3;
- u32 mpll_ss;
- u32 mpll_ss2;
-};
-
-union r7xx_clock_registers {
- struct rv770_clock_registers rv770;
- struct rv730_clock_registers rv730;
-};
-
struct rv7xx_power_info {
/* flags */
- bool mem_gddr5;
- bool pcie_gen2;
- bool dynamic_pcie_gen2;
- bool acpi_pcie_gen2;
- bool boot_in_gen2;
bool voltage_control; /* vddc */
bool mvdd_control;
bool sclk_ss;
bool mclk_ss;
bool dynamic_ss;
- bool gfx_clock_gating;
- bool mg_clock_gating;
- bool mgcgtssm;
- bool power_gating;
bool thermal_protection;
- bool display_gap;
- bool dcodt;
- bool ulps;
- /* registers */
- union r7xx_clock_registers clk_regs;
- u32 s0_vid_lower_smio_cntl;
/* voltage */
- u32 vddc_mask_low;
- u32 mvdd_mask_low;
u32 mvdd_split_frequency;
- u32 mvdd_low_smio[MAX_NO_OF_MVDD_VALUES];
u16 max_vddc;
u16 max_vddc_in_table;
u16 min_vddc_in_table;
- struct vddc_table_entry vddc_table[MAX_NO_VREG_STEPS];
- u8 valid_vddc_entries;
- /* dc odt */
- u32 mclk_odt_threshold;
- u8 odt_value_0[2];
- u8 odt_value_1[2];
/* stored values */
- u32 boot_sclk;
u16 acpi_vddc;
u32 ref_div;
u32 active_auto_throttle_sources;
@@ -582,17 +239,6 @@ struct rv7xx_power_info {
u32 asi;
u32 pasi;
u32 vrc;
- u32 restricted_levels;
- u32 rlp;
- u32 rmp;
- u32 lhp;
- u32 lmp;
- /* smc offsets */
- u16 state_table_start;
- u16 soft_regs_start;
- u16 sram_end;
- /* scratch structs */
- RV770_SMC_STATETABLE smc_statetable;
};
enum si_pcie_gen {
@@ -611,44 +257,12 @@ struct rv7xx_pl {
enum si_pcie_gen pcie_gen; /* si+ only */
};
-struct rv7xx_ps {
- struct rv7xx_pl high;
- struct rv7xx_pl medium;
- struct rv7xx_pl low;
- bool dc_compatible;
-};
-
struct si_ps {
u16 performance_level_count;
bool dc_compatible;
struct rv7xx_pl performance_levels[NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE];
};
-struct ni_mc_reg_table {
- u8 last;
- u8 num_entries;
- u16 valid_flag;
- struct ni_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
- SMC_NIslands_MCRegisterAddress mc_reg_address[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE];
-};
-
-struct ni_cac_data
-{
- struct ni_leakage_coeffients leakage_coefficients;
- u32 i_leakage;
- s32 leakage_minimum_temperature;
- u32 pwr_const;
- u32 dc_cac_value;
- u32 bif_cac_value;
- u32 lkge_pwr;
- u8 mc_wr_weight;
- u8 mc_rd_weight;
- u8 allow_ovrflw;
- u8 num_win_tdp;
- u8 l2num_win_tdp;
- u8 lts_truncate_n;
-};
-
struct evergreen_power_info {
/* must be first! */
struct rv7xx_power_info rv7xx;
@@ -657,203 +271,33 @@ struct evergreen_power_info {
bool dynamic_ac_timing;
bool abm;
bool mcls;
- bool light_sleep;
- bool memory_transition;
bool pcie_performance_request;
- bool pcie_performance_request_registered;
bool sclk_deep_sleep;
- bool dll_default_on;
- bool ls_clock_gating;
bool smu_uvd_hs;
bool uvd_enabled;
/* stored values */
u16 acpi_vddci;
- u8 mvdd_high_index;
- u8 mvdd_low_index;
u32 mclk_edc_wr_enable_threshold;
- struct evergreen_mc_reg_table mc_reg_table;
struct atom_voltage_table vddc_voltage_table;
struct atom_voltage_table vddci_voltage_table;
- struct evergreen_arb_registers bootup_arb_registers;
- struct evergreen_ulv_param ulv;
- struct at ats[2];
- /* smc offsets */
- u16 mc_reg_table_start;
struct amdgpu_ps current_rps;
- struct rv7xx_ps current_ps;
struct amdgpu_ps requested_rps;
- struct rv7xx_ps requested_ps;
-};
-
-struct PP_NIslands_Dpm2PerfLevel
-{
- uint8_t MaxPS;
- uint8_t TgtAct;
- uint8_t MaxPS_StepInc;
- uint8_t MaxPS_StepDec;
- uint8_t PSST;
- uint8_t NearTDPDec;
- uint8_t AboveSafeInc;
- uint8_t BelowSafeInc;
- uint8_t PSDeltaLimit;
- uint8_t PSDeltaWin;
- uint8_t Reserved[6];
-};
-
-typedef struct PP_NIslands_Dpm2PerfLevel PP_NIslands_Dpm2PerfLevel;
-
-struct PP_NIslands_DPM2Parameters
-{
- uint32_t TDPLimit;
- uint32_t NearTDPLimit;
- uint32_t SafePowerLimit;
- uint32_t PowerBoostLimit;
-};
-typedef struct PP_NIslands_DPM2Parameters PP_NIslands_DPM2Parameters;
-
-struct NISLANDS_SMC_SCLK_VALUE
-{
- uint32_t vCG_SPLL_FUNC_CNTL;
- uint32_t vCG_SPLL_FUNC_CNTL_2;
- uint32_t vCG_SPLL_FUNC_CNTL_3;
- uint32_t vCG_SPLL_FUNC_CNTL_4;
- uint32_t vCG_SPLL_SPREAD_SPECTRUM;
- uint32_t vCG_SPLL_SPREAD_SPECTRUM_2;
- uint32_t sclk_value;
-};
-
-typedef struct NISLANDS_SMC_SCLK_VALUE NISLANDS_SMC_SCLK_VALUE;
-
-struct NISLANDS_SMC_MCLK_VALUE
-{
- uint32_t vMPLL_FUNC_CNTL;
- uint32_t vMPLL_FUNC_CNTL_1;
- uint32_t vMPLL_FUNC_CNTL_2;
- uint32_t vMPLL_AD_FUNC_CNTL;
- uint32_t vMPLL_AD_FUNC_CNTL_2;
- uint32_t vMPLL_DQ_FUNC_CNTL;
- uint32_t vMPLL_DQ_FUNC_CNTL_2;
- uint32_t vMCLK_PWRMGT_CNTL;
- uint32_t vDLL_CNTL;
- uint32_t vMPLL_SS;
- uint32_t vMPLL_SS2;
- uint32_t mclk_value;
-};
-
-typedef struct NISLANDS_SMC_MCLK_VALUE NISLANDS_SMC_MCLK_VALUE;
-
-struct NISLANDS_SMC_VOLTAGE_VALUE
-{
- uint16_t value;
- uint8_t index;
- uint8_t padding;
-};
-
-typedef struct NISLANDS_SMC_VOLTAGE_VALUE NISLANDS_SMC_VOLTAGE_VALUE;
-
-struct NISLANDS_SMC_HW_PERFORMANCE_LEVEL
-{
- uint8_t arbValue;
- uint8_t ACIndex;
- uint8_t displayWatermark;
- uint8_t gen2PCIE;
- uint8_t reserved1;
- uint8_t reserved2;
- uint8_t strobeMode;
- uint8_t mcFlags;
- uint32_t aT;
- uint32_t bSP;
- NISLANDS_SMC_SCLK_VALUE sclk;
- NISLANDS_SMC_MCLK_VALUE mclk;
- NISLANDS_SMC_VOLTAGE_VALUE vddc;
- NISLANDS_SMC_VOLTAGE_VALUE mvdd;
- NISLANDS_SMC_VOLTAGE_VALUE vddci;
- NISLANDS_SMC_VOLTAGE_VALUE std_vddc;
- uint32_t powergate_en;
- uint8_t hUp;
- uint8_t hDown;
- uint8_t stateFlags;
- uint8_t arbRefreshState;
- uint32_t SQPowerThrottle;
- uint32_t SQPowerThrottle_2;
- uint32_t reserved[2];
- PP_NIslands_Dpm2PerfLevel dpm2;
-};
-
-typedef struct NISLANDS_SMC_HW_PERFORMANCE_LEVEL NISLANDS_SMC_HW_PERFORMANCE_LEVEL;
-
-struct NISLANDS_SMC_SWSTATE
-{
- uint8_t flags;
- uint8_t levelCount;
- uint8_t padding2;
- uint8_t padding3;
- NISLANDS_SMC_HW_PERFORMANCE_LEVEL levels[];
-};
-
-typedef struct NISLANDS_SMC_SWSTATE NISLANDS_SMC_SWSTATE;
-
-struct NISLANDS_SMC_VOLTAGEMASKTABLE
-{
- uint8_t highMask[NISLANDS_SMC_VOLTAGEMASK_MAX];
- uint32_t lowMask[NISLANDS_SMC_VOLTAGEMASK_MAX];
-};
-
-typedef struct NISLANDS_SMC_VOLTAGEMASKTABLE NISLANDS_SMC_VOLTAGEMASKTABLE;
-
-#define NISLANDS_MAX_NO_VREG_STEPS 32
-
-struct NISLANDS_SMC_STATETABLE
-{
- uint8_t thermalProtectType;
- uint8_t systemFlags;
- uint8_t maxVDDCIndexInPPTable;
- uint8_t extraFlags;
- uint8_t highSMIO[NISLANDS_MAX_NO_VREG_STEPS];
- uint32_t lowSMIO[NISLANDS_MAX_NO_VREG_STEPS];
- NISLANDS_SMC_VOLTAGEMASKTABLE voltageMaskTable;
- PP_NIslands_DPM2Parameters dpm2Params;
- NISLANDS_SMC_SWSTATE initialState;
- NISLANDS_SMC_SWSTATE ACPIState;
- NISLANDS_SMC_SWSTATE ULVState;
- NISLANDS_SMC_SWSTATE driverState;
- NISLANDS_SMC_HW_PERFORMANCE_LEVEL dpmLevels[NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1];
};
-typedef struct NISLANDS_SMC_STATETABLE NISLANDS_SMC_STATETABLE;
-
struct ni_power_info {
/* must be first! */
struct evergreen_power_info eg;
- struct ni_clock_registers clock_registers;
- struct ni_mc_reg_table mc_reg_table;
u32 mclk_rtt_mode_threshold;
/* flags */
- bool use_power_boost_limit;
bool support_cac_long_term_average;
bool cac_enabled;
bool cac_configuration_required;
bool driver_calculate_cac_leakage;
- bool pc_enabled;
bool enable_power_containment;
bool enable_cac;
bool enable_sq_ramping;
- /* smc offsets */
- u16 arb_table_start;
- u16 fan_table_start;
- u16 cac_table_start;
- u16 spll_table_start;
- /* CAC stuff */
- struct ni_cac_data cac_data;
- u32 dc_cac_table[NISLANDS_DCCAC_MAX_LEVELS];
- const struct ni_cac_weights *cac_weights;
- u8 lta_window_size;
- u8 lts_truncate;
struct si_ps current_ps;
struct si_ps requested_ps;
- /* scratch structs */
- SMC_NIslands_MCRegisters smc_mc_reg_table;
- NISLANDS_SMC_STATETABLE smc_statetable;
};
struct si_cac_config_reg
@@ -952,7 +396,6 @@ struct si_leakage_voltage
struct si_leakage_voltage_entry entries[SISLANDS_MAX_LEAKAGE_COUNT];
};
-
struct si_ulv_param {
bool supported;
u32 cg_ulv_control;
diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/si_smc.c b/drivers/gpu/drm/amd/pm/legacy-dpm/si_smc.c
index 8f994ffa9cd1..e1c509bfc390 100644
--- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_smc.c
+++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_smc.c
@@ -30,6 +30,12 @@
#include "amdgpu_ucode.h"
#include "sislands_smc.h"
+#include "smu/smu_6_0_d.h"
+#include "smu/smu_6_0_sh_mask.h"
+
+#include "gca/gfx_6_0_d.h"
+#include "gca/gfx_6_0_sh_mask.h"
+
static int si_set_smc_sram_address(struct amdgpu_device *adev,
u32 smc_address, u32 limit)
{
@@ -38,8 +44,8 @@ static int si_set_smc_sram_address(struct amdgpu_device *adev,
if ((smc_address + 3) > limit)
return -EINVAL;
- WREG32(SMC_IND_INDEX_0, smc_address);
- WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
+ WREG32(mmSMC_IND_INDEX_0, smc_address);
+ WREG32_P(mmSMC_IND_ACCESS_CNTL, 0, ~SMC_IND_ACCESS_CNTL__AUTO_INCREMENT_IND_0_MASK);
return 0;
}
@@ -59,7 +65,7 @@ int amdgpu_si_copy_bytes_to_smc(struct amdgpu_device *adev,
addr = smc_start_address;
- spin_lock_irqsave(&adev->smc_idx_lock, flags);
+ spin_lock_irqsave(&adev->reg.smc.lock, flags);
while (byte_count >= 4) {
/* SMC address space is BE */
data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
@@ -68,7 +74,7 @@ int amdgpu_si_copy_bytes_to_smc(struct amdgpu_device *adev,
if (ret)
goto done;
- WREG32(SMC_IND_DATA_0, data);
+ WREG32(mmSMC_IND_DATA_0, data);
src += 4;
byte_count -= 4;
@@ -83,7 +89,7 @@ int amdgpu_si_copy_bytes_to_smc(struct amdgpu_device *adev,
if (ret)
goto done;
- original_data = RREG32(SMC_IND_DATA_0);
+ original_data = RREG32(mmSMC_IND_DATA_0);
extra_shift = 8 * (4 - byte_count);
while (byte_count > 0) {
@@ -99,11 +105,11 @@ int amdgpu_si_copy_bytes_to_smc(struct amdgpu_device *adev,
if (ret)
goto done;
- WREG32(SMC_IND_DATA_0, data);
+ WREG32(mmSMC_IND_DATA_0, data);
}
done:
- spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
+ spin_unlock_irqrestore(&adev->reg.smc.lock, flags);
return ret;
}
@@ -121,10 +127,10 @@ void amdgpu_si_reset_smc(struct amdgpu_device *adev)
{
u32 tmp;
- RREG32(CB_CGTT_SCLK_CTRL);
- RREG32(CB_CGTT_SCLK_CTRL);
- RREG32(CB_CGTT_SCLK_CTRL);
- RREG32(CB_CGTT_SCLK_CTRL);
+ RREG32(mmCB_CGTT_SCLK_CTRL);
+ RREG32(mmCB_CGTT_SCLK_CTRL);
+ RREG32(mmCB_CGTT_SCLK_CTRL);
+ RREG32(mmCB_CGTT_SCLK_CTRL);
tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL) |
RST_REG;
@@ -166,20 +172,42 @@ PPSMC_Result amdgpu_si_send_msg_to_smc(struct amdgpu_device *adev,
{
u32 tmp;
int i;
+ int usec_timeout;
+
+ /* SMC seems to process some messages exceptionally slowly. */
+ switch (msg) {
+ case PPSMC_MSG_NoForcedLevel:
+ case PPSMC_MSG_SetEnabledLevels:
+ case PPSMC_MSG_SetForcedLevels:
+ case PPSMC_MSG_DisableULV:
+ case PPSMC_MSG_SwitchToSwState:
+ usec_timeout = 1000000; /* 1 sec */
+ break;
+ default:
+ usec_timeout = 200000; /* 200 ms */
+ break;
+ }
if (!amdgpu_si_is_smc_running(adev))
return PPSMC_Result_Failed;
- WREG32(SMC_MESSAGE_0, msg);
+ WREG32(mmSMC_MESSAGE_0, msg);
- for (i = 0; i < adev->usec_timeout; i++) {
- tmp = RREG32(SMC_RESP_0);
+ for (i = 0; i < usec_timeout; i++) {
+ tmp = RREG32(mmSMC_RESP_0);
if (tmp != 0)
break;
udelay(1);
}
- return (PPSMC_Result)RREG32(SMC_RESP_0);
+ tmp = RREG32(mmSMC_RESP_0);
+ if (tmp == 0) {
+ drm_warn(adev_to_drm(adev),
+ "%s timeout on message: %x (SMC_SCRATCH0: %x)\n",
+ __func__, msg, RREG32(mmSMC_SCRATCH0));
+ }
+
+ return (PPSMC_Result)tmp;
}
PPSMC_Result amdgpu_si_wait_for_smc_inactive(struct amdgpu_device *adev)
@@ -224,20 +252,20 @@ int amdgpu_si_load_smc_ucode(struct amdgpu_device *adev, u32 limit)
if (ucode_size & 3)
return -EINVAL;
- spin_lock_irqsave(&adev->smc_idx_lock, flags);
- WREG32(SMC_IND_INDEX_0, ucode_start_address);
- WREG32_P(SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, ~AUTO_INCREMENT_IND_0);
+ spin_lock_irqsave(&adev->reg.smc.lock, flags);
+ WREG32(mmSMC_IND_INDEX_0, ucode_start_address);
+ WREG32_P(mmSMC_IND_ACCESS_CNTL, SMC_IND_ACCESS_CNTL__AUTO_INCREMENT_IND_0_MASK, ~SMC_IND_ACCESS_CNTL__AUTO_INCREMENT_IND_0_MASK);
while (ucode_size >= 4) {
/* SMC address space is BE */
data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
- WREG32(SMC_IND_DATA_0, data);
+ WREG32(mmSMC_IND_DATA_0, data);
src += 4;
ucode_size -= 4;
}
- WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
- spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
+ WREG32_P(mmSMC_IND_ACCESS_CNTL, 0, ~SMC_IND_ACCESS_CNTL__AUTO_INCREMENT_IND_0_MASK);
+ spin_unlock_irqrestore(&adev->reg.smc.lock, flags);
return 0;
}
@@ -248,11 +276,11 @@ int amdgpu_si_read_smc_sram_dword(struct amdgpu_device *adev, u32 smc_address,
unsigned long flags;
int ret;
- spin_lock_irqsave(&adev->smc_idx_lock, flags);
+ spin_lock_irqsave(&adev->reg.smc.lock, flags);
ret = si_set_smc_sram_address(adev, smc_address, limit);
if (ret == 0)
- *value = RREG32(SMC_IND_DATA_0);
- spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
+ *value = RREG32(mmSMC_IND_DATA_0);
+ spin_unlock_irqrestore(&adev->reg.smc.lock, flags);
return ret;
}
@@ -263,11 +291,11 @@ int amdgpu_si_write_smc_sram_dword(struct amdgpu_device *adev, u32 smc_address,
unsigned long flags;
int ret;
- spin_lock_irqsave(&adev->smc_idx_lock, flags);
+ spin_lock_irqsave(&adev->reg.smc.lock, flags);
ret = si_set_smc_sram_address(adev, smc_address, limit);
if (ret == 0)
- WREG32(SMC_IND_DATA_0, value);
- spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
+ WREG32(mmSMC_IND_DATA_0, value);
+ spin_unlock_irqrestore(&adev->reg.smc.lock, flags);
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
index 686345f75f26..6f5c27bdc1e9 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
@@ -20,7 +20,6 @@
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
-#include "pp_debug.h"
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/gfp.h>
@@ -28,12 +27,10 @@
#include <linux/firmware.h>
#include <linux/reboot.h>
#include "amd_shared.h"
-#include "amd_powerplay.h"
#include "power_state.h"
#include "amdgpu.h"
#include "hwmgr.h"
#include "amdgpu_dpm_internal.h"
-#include "amdgpu_display.h"
static const struct amd_pm_funcs pp_dpm_funcs;
@@ -44,13 +41,18 @@ static int amd_powerplay_create(struct amdgpu_device *adev)
if (adev == NULL)
return -EINVAL;
- hwmgr = kzalloc(sizeof(struct pp_hwmgr), GFP_KERNEL);
+ hwmgr = kzalloc_obj(struct pp_hwmgr);
if (hwmgr == NULL)
return -ENOMEM;
hwmgr->adev = adev;
hwmgr->not_vf = !amdgpu_sriov_vf(adev);
hwmgr->device = amdgpu_cgs_create_device(adev);
+ if (!hwmgr->device) {
+ kfree(hwmgr);
+ return -ENOMEM;
+ }
+
mutex_init(&hwmgr->msg_lock);
hwmgr->chip_family = adev->family;
hwmgr->chip_id = adev->asic_type;
@@ -196,7 +198,7 @@ static void pp_reserve_vram_for_smu(struct amdgpu_device *adev)
&adev->pm.smu_prv_buffer,
&gpu_addr,
&cpu_ptr)) {
- DRM_ERROR("amdgpu: failed to create smu prv buffer\n");
+ drm_err(adev_to_drm(adev), "failed to create smu prv buffer\n");
return;
}
@@ -211,7 +213,7 @@ static void pp_reserve_vram_for_smu(struct amdgpu_device *adev)
if (r) {
amdgpu_bo_free_kernel(&adev->pm.smu_prv_buffer, NULL, NULL);
adev->pm.smu_prv_buffer = NULL;
- DRM_ERROR("amdgpu: failed to notify SMU buffer address\n");
+ drm_err(adev_to_drm(adev), "failed to notify SMU buffer address\n");
}
}
@@ -239,7 +241,7 @@ static void pp_late_fini(struct amdgpu_ip_block *ip_block)
}
-static bool pp_is_idle(void *handle)
+static bool pp_is_idle(struct amdgpu_ip_block *ip_block)
{
return false;
}
@@ -629,9 +631,12 @@ static int pp_dpm_get_pp_table(void *handle, char **table)
{
struct pp_hwmgr *hwmgr = handle;
- if (!hwmgr || !hwmgr->pm_en || !hwmgr->soft_pp_table)
+ if (!hwmgr || !hwmgr->pm_en || !table)
return -EINVAL;
+ if (!hwmgr->soft_pp_table)
+ return -EOPNOTSUPP;
+
*table = (char *)hwmgr->soft_pp_table;
return hwmgr->soft_pp_table_size;
}
@@ -660,6 +665,9 @@ static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size)
if (!hwmgr || !hwmgr->pm_en)
return -EINVAL;
+ if (size > hwmgr->soft_pp_table_size)
+ return -EINVAL;
+
if (!hwmgr->hardcode_pp_table) {
hwmgr->hardcode_pp_table = kmemdup(hwmgr->soft_pp_table,
hwmgr->soft_pp_table_size,
@@ -719,21 +727,6 @@ static int pp_dpm_emit_clock_levels(void *handle,
return hwmgr->hwmgr_func->emit_clock_levels(hwmgr, type, buf, offset);
}
-static int pp_dpm_print_clock_levels(void *handle,
- enum pp_clock_type type, char *buf)
-{
- struct pp_hwmgr *hwmgr = handle;
-
- if (!hwmgr || !hwmgr->pm_en)
- return -EINVAL;
-
- if (hwmgr->hwmgr_func->print_clock_levels == NULL) {
- pr_info_ratelimited("%s was not implemented.\n", __func__);
- return 0;
- }
- return hwmgr->hwmgr_func->print_clock_levels(hwmgr, type, buf);
-}
-
static int pp_dpm_get_sclk_od(void *handle)
{
struct pp_hwmgr *hwmgr = handle;
@@ -950,7 +943,7 @@ static int pp_dpm_switch_power_profile(void *handle,
return 0;
}
-static int pp_set_power_limit(void *handle, uint32_t limit)
+static int pp_set_power_limit(void *handle, uint32_t limit_type, uint32_t limit)
{
struct pp_hwmgr *hwmgr = handle;
uint32_t max_power_limit;
@@ -1030,21 +1023,9 @@ static int pp_display_configuration_change(void *handle,
return 0;
}
-static int pp_get_display_power_level(void *handle,
- struct amd_pp_simple_clock_info *output)
-{
- struct pp_hwmgr *hwmgr = handle;
-
- if (!hwmgr || !hwmgr->pm_en || !output)
- return -EINVAL;
-
- return phm_get_dal_power_level(hwmgr, output);
-}
-
static int pp_get_current_clocks(void *handle,
struct amd_pp_clock_info *clocks)
{
- struct amd_pp_simple_clock_info simple_clocks = { 0 };
struct pp_clock_info hw_clocks;
struct pp_hwmgr *hwmgr = handle;
int ret = 0;
@@ -1052,8 +1033,6 @@ static int pp_get_current_clocks(void *handle,
if (!hwmgr || !hwmgr->pm_en)
return -EINVAL;
- phm_get_dal_power_level(hwmgr, &simple_clocks);
-
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_PowerContainment))
ret = phm_get_clock_info(hwmgr, &hwmgr->current_ps->hardware,
@@ -1063,7 +1042,8 @@ static int pp_get_current_clocks(void *handle,
&hw_clocks, PHM_PerformanceLevelDesignation_Activity);
if (ret) {
- pr_debug("Error in phm_get_clock_info \n");
+ drm_err(adev_to_drm(hwmgr->adev),
+ "Error in phm_get_clock_info\n");
return -EINVAL;
}
@@ -1077,11 +1057,6 @@ static int pp_get_current_clocks(void *handle,
clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk;
clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk;
- if (simple_clocks.level == 0)
- clocks->max_clocks_state = PP_DAL_POWERLEVEL_7;
- else
- clocks->max_clocks_state = simple_clocks.level;
-
if (0 == phm_get_current_shallow_sleep_clocks(hwmgr, &hwmgr->current_ps->hardware, &hw_clocks)) {
clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk;
clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk;
@@ -1158,8 +1133,6 @@ static int pp_get_display_mode_validation_clocks(void *handle,
if (!hwmgr || !hwmgr->pm_en || !clocks)
return -EINVAL;
- clocks->level = PP_DAL_POWERLEVEL_7;
-
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DynamicPatchPowerState))
ret = phm_get_max_high_clocks(hwmgr, clocks);
@@ -1549,16 +1522,7 @@ static void pp_pm_compute_clocks(void *handle)
struct amdgpu_device *adev = hwmgr->adev;
if (!adev->dc_enabled) {
- amdgpu_dpm_get_active_displays(adev);
- adev->pm.pm_display_cfg.num_display = adev->pm.dpm.new_active_crtc_count;
- adev->pm.pm_display_cfg.vrefresh = amdgpu_dpm_get_vrefresh(adev);
- adev->pm.pm_display_cfg.min_vblank_time = amdgpu_dpm_get_vblank_time(adev);
- /* we have issues with mclk switching with
- * refresh rates over 120 hz on the non-DC code.
- */
- if (adev->pm.pm_display_cfg.vrefresh > 120)
- adev->pm.pm_display_cfg.min_vblank_time = 0;
-
+ amdgpu_dpm_get_display_cfg(adev);
pp_display_configuration_change(handle,
&adev->pm.pm_display_cfg);
}
@@ -1568,6 +1532,17 @@ static void pp_pm_compute_clocks(void *handle)
NULL);
}
+static void pp_dpm_notify_ac_dc(void *handle)
+{
+ struct pp_hwmgr *hwmgr = handle;
+
+ if (!hwmgr || !hwmgr->pm_en)
+ return;
+
+ if (hwmgr->hwmgr_func->notify_ac_dc)
+ hwmgr->hwmgr_func->notify_ac_dc(hwmgr);
+}
+
static const struct amd_pm_funcs pp_dpm_funcs = {
.load_firmware = pp_dpm_load_fw,
.wait_for_fw_loading_complete = pp_dpm_fw_loading_complete,
@@ -1586,7 +1561,6 @@ static const struct amd_pm_funcs pp_dpm_funcs = {
.set_pp_table = pp_dpm_set_pp_table,
.force_clock_level = pp_dpm_force_clock_level,
.emit_clock_levels = pp_dpm_emit_clock_levels,
- .print_clock_levels = pp_dpm_print_clock_levels,
.get_sclk_od = pp_dpm_get_sclk_od,
.set_sclk_od = pp_dpm_set_sclk_od,
.get_mclk_od = pp_dpm_get_mclk_od,
@@ -1607,7 +1581,6 @@ static const struct amd_pm_funcs pp_dpm_funcs = {
.get_sclk = pp_dpm_get_sclk,
.get_mclk = pp_dpm_get_mclk,
.display_configuration_change = pp_display_configuration_change,
- .get_display_power_level = pp_get_display_power_level,
.get_current_clocks = pp_get_current_clocks,
.get_clock_by_type = pp_get_clock_by_type,
.get_clock_by_type_with_latency = pp_get_clock_by_type_with_latency,
@@ -1634,4 +1607,5 @@ static const struct amd_pm_funcs pp_dpm_funcs = {
.gfx_state_change_set = pp_gfx_state_change_set,
.get_smu_prv_buf_details = pp_get_prv_buffer_details,
.pm_compute_clocks = pp_pm_compute_clocks,
+ .notify_ac_dc = pp_dpm_notify_ac_dc,
};
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hardwaremanager.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hardwaremanager.c
index 90452b66e107..72c2d3b69a03 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hardwaremanager.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hardwaremanager.c
@@ -149,16 +149,6 @@ int phm_apply_clock_adjust_rules(struct pp_hwmgr *hwmgr)
return 0;
}
-int phm_powerdown_uvd(struct pp_hwmgr *hwmgr)
-{
- PHM_FUNC_CHECK(hwmgr);
-
- if (hwmgr->hwmgr_func->powerdown_uvd != NULL)
- return hwmgr->hwmgr_func->powerdown_uvd(hwmgr);
- return 0;
-}
-
-
int phm_disable_clock_power_gatings(struct pp_hwmgr *hwmgr)
{
PHM_FUNC_CHECK(hwmgr);
@@ -338,16 +328,6 @@ int phm_store_dal_configuration_data(struct pp_hwmgr *hwmgr,
return 0;
}
-int phm_get_dal_power_level(struct pp_hwmgr *hwmgr,
- struct amd_pp_simple_clock_info *info)
-{
- PHM_FUNC_CHECK(hwmgr);
-
- if (info == NULL || hwmgr->hwmgr_func->get_dal_power_level == NULL)
- return -EINVAL;
- return hwmgr->hwmgr_func->get_dal_power_level(hwmgr, info);
-}
-
int phm_set_cpu_power_state(struct pp_hwmgr *hwmgr)
{
PHM_FUNC_CHECK(hwmgr);
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c
index 2b5ac21fee39..1d6e30269d56 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c
@@ -104,6 +104,21 @@ int hwmgr_early_init(struct pp_hwmgr *hwmgr)
PP_GFXOFF_MASK);
hwmgr->pp_table_version = PP_TABLE_V0;
hwmgr->od_enabled = false;
+ switch (hwmgr->chip_id) {
+ case CHIP_BONAIRE:
+ /* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM
+ * R7 260X cards with old MC ucode: MCLK DPM is unstable
+ */
+ if (adev->pdev->subsystem_vendor == 0x106B ||
+ adev->pdev->device == 0x6658) {
+ dev_info(adev->dev, "disabling MCLK DPM on quirky ASIC");
+ adev->pm.pp_feature &= ~PP_MCLK_DPM_MASK;
+ hwmgr->feature_mask &= ~PP_MCLK_DPM_MASK;
+ }
+ break;
+ default:
+ break;
+ }
smu7_init_function_pointers(hwmgr);
break;
case AMDGPU_FAMILY_CZ:
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c
index 4bd92fd782be..ce166a7f8e42 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c
@@ -143,6 +143,10 @@ int atomctrl_initialize_mc_reg_table(
vram_info = (ATOM_VRAM_INFO_HEADER_V2_1 *)
smu_atom_get_data_table(hwmgr->adev,
GetIndexIntoMasterTable(DATA, VRAM_Info), &size, &frev, &crev);
+ if (!vram_info) {
+ pr_err("Could not retrieve the VramInfo table!");
+ return -EINVAL;
+ }
if (module_index >= vram_info->ucNumOfVRAMModule) {
pr_err("Invalid VramInfo table.");
@@ -180,6 +184,10 @@ int atomctrl_initialize_mc_reg_table_v2_2(
vram_info = (ATOM_VRAM_INFO_HEADER_V2_2 *)
smu_atom_get_data_table(hwmgr->adev,
GetIndexIntoMasterTable(DATA, VRAM_Info), &size, &frev, &crev);
+ if (!vram_info) {
+ pr_err("Could not retrieve the VramInfo table!");
+ return -EINVAL;
+ }
if (module_index >= vram_info->ucNumOfVRAMModule) {
pr_err("Invalid VramInfo table.");
@@ -555,8 +563,8 @@ bool atomctrl_is_voltage_controlled_by_gpio_v3(
PP_ASSERT_WITH_CODE((NULL != voltage_info),
"Could not find Voltage Table in BIOS.", return false;);
- ret = (NULL != atomctrl_lookup_voltage_type_v3
- (voltage_info, voltage_type, voltage_mode)) ? true : false;
+ ret = atomctrl_lookup_voltage_type_v3
+ (voltage_info, voltage_type, voltage_mode) != NULL;
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c
index 82d540334318..6120f14caab0 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c
@@ -158,84 +158,6 @@ int pp_atomfwctrl_get_voltage_table_v4(struct pp_hwmgr *hwmgr,
return result;
}
-
-static struct atom_gpio_pin_lut_v2_1 *pp_atomfwctrl_get_gpio_lookup_table(
- struct pp_hwmgr *hwmgr)
-{
- const void *table_address;
- uint16_t idx;
-
- idx = GetIndexIntoMasterDataTable(gpio_pin_lut);
- table_address = smu_atom_get_data_table(hwmgr->adev,
- idx, NULL, NULL, NULL);
- PP_ASSERT_WITH_CODE(table_address,
- "Error retrieving BIOS Table Address!",
- return NULL);
-
- return (struct atom_gpio_pin_lut_v2_1 *)table_address;
-}
-
-static bool pp_atomfwctrl_lookup_gpio_pin(
- struct atom_gpio_pin_lut_v2_1 *gpio_lookup_table,
- const uint32_t pin_id,
- struct pp_atomfwctrl_gpio_pin_assignment *gpio_pin_assignment)
-{
- unsigned int size = le16_to_cpu(
- gpio_lookup_table->table_header.structuresize);
- unsigned int offset =
- offsetof(struct atom_gpio_pin_lut_v2_1, gpio_pin[0]);
- unsigned long start = (unsigned long)gpio_lookup_table;
-
- while (offset < size) {
- const struct atom_gpio_pin_assignment *pin_assignment =
- (const struct atom_gpio_pin_assignment *)(start + offset);
-
- if (pin_id == pin_assignment->gpio_id) {
- gpio_pin_assignment->uc_gpio_pin_bit_shift =
- pin_assignment->gpio_bitshift;
- gpio_pin_assignment->us_gpio_pin_aindex =
- le16_to_cpu(pin_assignment->data_a_reg_index);
- return true;
- }
- offset += offsetof(struct atom_gpio_pin_assignment, gpio_id) + 1;
- }
- return false;
-}
-
-/*
- * Returns TRUE if the given pin id find in lookup table.
- */
-bool pp_atomfwctrl_get_pp_assign_pin(struct pp_hwmgr *hwmgr,
- const uint32_t pin_id,
- struct pp_atomfwctrl_gpio_pin_assignment *gpio_pin_assignment)
-{
- bool ret = false;
- struct atom_gpio_pin_lut_v2_1 *gpio_lookup_table =
- pp_atomfwctrl_get_gpio_lookup_table(hwmgr);
-
- /* If we cannot find the table do NOT try to control this voltage. */
- PP_ASSERT_WITH_CODE(gpio_lookup_table,
- "Could not find GPIO lookup Table in BIOS.",
- return false);
-
- ret = pp_atomfwctrl_lookup_gpio_pin(gpio_lookup_table,
- pin_id, gpio_pin_assignment);
-
- return ret;
-}
-
-/*
- * Enter to SelfRefresh mode.
- * @param hwmgr
- */
-int pp_atomfwctrl_enter_self_refresh(struct pp_hwmgr *hwmgr)
-{
- /* 0 - no action
- * 1 - leave power to video memory always on
- */
- return 0;
-}
-
/** pp_atomfwctrl_get_gpu_pll_dividers_vega10().
*
* @param hwmgr input parameter: pointer to HwMgr
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.h
index e86e05c786d9..0d62903d5676 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.h
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.h
@@ -217,9 +217,6 @@ struct pp_atomfwctrl_smc_dpm_parameters {
int pp_atomfwctrl_get_gpu_pll_dividers_vega10(struct pp_hwmgr *hwmgr,
uint32_t clock_type, uint32_t clock_value,
struct pp_atomfwctrl_clock_dividers_soc15 *dividers);
-int pp_atomfwctrl_enter_self_refresh(struct pp_hwmgr *hwmgr);
-bool pp_atomfwctrl_get_pp_assign_pin(struct pp_hwmgr *hwmgr, const uint32_t pin_id,
- struct pp_atomfwctrl_gpio_pin_assignment *gpio_pin_assignment);
int pp_atomfwctrl_get_voltage_table_v4(struct pp_hwmgr *hwmgr, uint8_t voltage_type,
uint8_t voltage_mode, struct pp_atomfwctrl_voltage_table *voltage_table);
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c
index 6cfef1b295ab..6fcca65bd7d4 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c
@@ -165,7 +165,7 @@ static int get_vddc_lookup_table(
PP_ASSERT_WITH_CODE((0 != vddc_lookup_pp_tables->ucNumEntries),
"Invalid CAC Leakage PowerPlay Table!", return 1);
- table = kzalloc(struct_size(table, entries, max_levels), GFP_KERNEL);
+ table = kzalloc_flex(*table, entries, max_levels);
if (!table)
return -ENOMEM;
@@ -200,7 +200,7 @@ static int get_platform_power_management_table(
struct pp_hwmgr *hwmgr,
ATOM_Tonga_PPM_Table *atom_ppm_table)
{
- struct phm_ppm_table *ptr = kzalloc(sizeof(*ptr), GFP_KERNEL);
+ struct phm_ppm_table *ptr = kzalloc_obj(*ptr);
struct phm_ppt_v1_information *pp_table_information =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
@@ -321,8 +321,7 @@ static int get_valid_clk(
PP_ASSERT_WITH_CODE((0 != clk_volt_pp_table->count),
"Invalid PowerPlay Table!", return -1);
- table = kzalloc(struct_size(table, values, clk_volt_pp_table->count),
- GFP_KERNEL);
+ table = kzalloc_flex(*table, values, clk_volt_pp_table->count);
if (!table)
return -ENOMEM;
@@ -371,8 +370,8 @@ static int get_mclk_voltage_dependency_table(
PP_ASSERT_WITH_CODE((0 != mclk_dep_table->ucNumEntries),
"Invalid PowerPlay Table!", return -1);
- mclk_table = kzalloc(struct_size(mclk_table, entries, mclk_dep_table->ucNumEntries),
- GFP_KERNEL);
+ mclk_table = kzalloc_flex(*mclk_table, entries,
+ mclk_dep_table->ucNumEntries);
if (!mclk_table)
return -ENOMEM;
@@ -415,8 +414,8 @@ static int get_sclk_voltage_dependency_table(
PP_ASSERT_WITH_CODE((0 != tonga_table->ucNumEntries),
"Invalid PowerPlay Table!", return -1);
- sclk_table = kzalloc(struct_size(sclk_table, entries, tonga_table->ucNumEntries),
- GFP_KERNEL);
+ sclk_table = kzalloc_flex(*sclk_table, entries,
+ tonga_table->ucNumEntries);
if (!sclk_table)
return -ENOMEM;
@@ -444,8 +443,8 @@ static int get_sclk_voltage_dependency_table(
PP_ASSERT_WITH_CODE((0 != polaris_table->ucNumEntries),
"Invalid PowerPlay Table!", return -1);
- sclk_table = kzalloc(struct_size(sclk_table, entries, polaris_table->ucNumEntries),
- GFP_KERNEL);
+ sclk_table = kzalloc_flex(*sclk_table, entries,
+ polaris_table->ucNumEntries);
if (!sclk_table)
return -ENOMEM;
@@ -491,9 +490,8 @@ static int get_pcie_table(
PP_ASSERT_WITH_CODE((atom_pcie_table->ucNumEntries != 0),
"Invalid PowerPlay Table!", return -1);
- pcie_table = kzalloc(struct_size(pcie_table, entries,
- atom_pcie_table->ucNumEntries),
- GFP_KERNEL);
+ pcie_table = kzalloc_flex(*pcie_table, entries,
+ atom_pcie_table->ucNumEntries);
if (!pcie_table)
return -ENOMEM;
@@ -528,9 +526,8 @@ static int get_pcie_table(
PP_ASSERT_WITH_CODE((atom_pcie_table->ucNumEntries != 0),
"Invalid PowerPlay Table!", return -1);
- pcie_table = kzalloc(struct_size(pcie_table, entries,
- atom_pcie_table->ucNumEntries),
- GFP_KERNEL);
+ pcie_table = kzalloc_flex(*pcie_table, entries,
+ atom_pcie_table->ucNumEntries);
if (!pcie_table)
return -ENOMEM;
@@ -724,8 +721,8 @@ static int get_mm_clock_voltage_table(
PP_ASSERT_WITH_CODE((0 != mm_dependency_table->ucNumEntries),
"Invalid PowerPlay Table!", return -1);
- mm_table = kzalloc(struct_size(mm_table, entries, mm_dependency_table->ucNumEntries),
- GFP_KERNEL);
+ mm_table = kzalloc_flex(*mm_table, entries,
+ mm_dependency_table->ucNumEntries);
if (!mm_table)
return -ENOMEM;
@@ -1141,7 +1138,7 @@ static int pp_tables_v1_0_initialize(struct pp_hwmgr *hwmgr)
int result = 0;
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table;
- hwmgr->pptable = kzalloc(sizeof(struct phm_ppt_v1_information), GFP_KERNEL);
+ hwmgr->pptable = kzalloc_obj(struct phm_ppt_v1_information);
PP_ASSERT_WITH_CODE((NULL != hwmgr->pptable),
"Failed to allocate hwmgr->pptable!", return -ENOMEM);
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c
index f06b29e33ba4..bfd8fbb0b49d 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c
@@ -382,8 +382,7 @@ static int get_clock_voltage_dependency_table(struct pp_hwmgr *hwmgr,
unsigned long i;
struct phm_clock_voltage_dependency_table *dep_table;
- dep_table = kzalloc(struct_size(dep_table, entries, table->ucNumEntries),
- GFP_KERNEL);
+ dep_table = kzalloc_flex(*dep_table, entries, table->ucNumEntries);
if (NULL == dep_table)
return -ENOMEM;
@@ -409,7 +408,7 @@ static int get_valid_clk(struct pp_hwmgr *hwmgr,
unsigned long i;
struct phm_clock_array *clock_table;
- clock_table = kzalloc(struct_size(clock_table, values, table->count), GFP_KERNEL);
+ clock_table = kzalloc_flex(*clock_table, values, table->count);
if (!clock_table)
return -ENOMEM;
@@ -1209,8 +1208,7 @@ static int get_uvd_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
unsigned long i;
struct phm_uvd_clock_voltage_dependency_table *uvd_table;
- uvd_table = kzalloc(struct_size(uvd_table, entries, table->numEntries),
- GFP_KERNEL);
+ uvd_table = kzalloc_flex(*uvd_table, entries, table->numEntries);
if (!uvd_table)
return -ENOMEM;
@@ -1239,8 +1237,7 @@ static int get_vce_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
unsigned long i;
struct phm_vce_clock_voltage_dependency_table *vce_table;
- vce_table = kzalloc(struct_size(vce_table, entries, table->numEntries),
- GFP_KERNEL);
+ vce_table = kzalloc_flex(*vce_table, entries, table->numEntries);
if (!vce_table)
return -ENOMEM;
@@ -1267,8 +1264,7 @@ static int get_samu_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
unsigned long i;
struct phm_samu_clock_voltage_dependency_table *samu_table;
- samu_table = kzalloc(struct_size(samu_table, entries, table->numEntries),
- GFP_KERNEL);
+ samu_table = kzalloc_flex(*samu_table, entries, table->numEntries);
if (!samu_table)
return -ENOMEM;
@@ -1292,8 +1288,7 @@ static int get_acp_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
unsigned long i;
struct phm_acp_clock_voltage_dependency_table *acp_table;
- acp_table = kzalloc(struct_size(acp_table, entries, table->numEntries),
- GFP_KERNEL);
+ acp_table = kzalloc_flex(*acp_table, entries, table->numEntries);
if (!acp_table)
return -ENOMEM;
@@ -1324,7 +1319,6 @@ static int init_clock_voltage_dependency(struct pp_hwmgr *hwmgr,
hwmgr->dyn_state.vddc_dependency_on_sclk = NULL;
hwmgr->dyn_state.vddci_dependency_on_mclk = NULL;
hwmgr->dyn_state.vddc_dependency_on_mclk = NULL;
- hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
hwmgr->dyn_state.mvdd_dependency_on_mclk = NULL;
hwmgr->dyn_state.vce_clock_voltage_dependency_table = NULL;
hwmgr->dyn_state.uvd_clock_voltage_dependency_table = NULL;
@@ -1487,8 +1481,8 @@ static int get_cac_leakage_table(struct pp_hwmgr *hwmgr,
if (!hwmgr || !table || !ptable)
return -EINVAL;
- cac_leakage_table = kzalloc(struct_size(cac_leakage_table, entries, table->ucNumEntries),
- GFP_KERNEL);
+ cac_leakage_table = kzalloc_flex(*cac_leakage_table, entries,
+ table->ucNumEntries);
if (!cac_leakage_table)
return -ENOMEM;
@@ -1514,7 +1508,7 @@ static int get_cac_leakage_table(struct pp_hwmgr *hwmgr,
static int get_platform_power_management_table(struct pp_hwmgr *hwmgr,
ATOM_PPLIB_PPM_Table *atom_ppm_table)
{
- struct phm_ppm_table *ptr = kzalloc(sizeof(struct phm_ppm_table), GFP_KERNEL);
+ struct phm_ppm_table *ptr = kzalloc_obj(struct phm_ppm_table);
if (NULL == ptr)
return -ENOMEM;
@@ -1625,8 +1619,8 @@ static int init_phase_shedding_table(struct pp_hwmgr *hwmgr,
unsigned long i;
- table = kzalloc(struct_size(table, entries, ptable->ucNumEntries),
- GFP_KERNEL);
+ table = kzalloc_flex(*table, entries,
+ ptable->ucNumEntries);
if (!table)
return -ENOMEM;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c
index a8c732e07006..15456c1c3614 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c
@@ -127,42 +127,6 @@ static int smu10_construct_max_power_limits_table(struct pp_hwmgr *hwmgr,
return 0;
}
-static int smu10_init_dynamic_state_adjustment_rule_settings(
- struct pp_hwmgr *hwmgr)
-{
- int count = 8;
- struct phm_clock_voltage_dependency_table *table_clk_vlt;
-
- table_clk_vlt = kzalloc(struct_size(table_clk_vlt, entries, count),
- GFP_KERNEL);
-
- if (NULL == table_clk_vlt) {
- pr_err("Can not allocate memory!\n");
- return -ENOMEM;
- }
-
- table_clk_vlt->count = count;
- table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_0;
- table_clk_vlt->entries[0].v = 0;
- table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_1;
- table_clk_vlt->entries[1].v = 1;
- table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_2;
- table_clk_vlt->entries[2].v = 2;
- table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_3;
- table_clk_vlt->entries[3].v = 3;
- table_clk_vlt->entries[4].clk = PP_DAL_POWERLEVEL_4;
- table_clk_vlt->entries[4].v = 4;
- table_clk_vlt->entries[5].clk = PP_DAL_POWERLEVEL_5;
- table_clk_vlt->entries[5].v = 5;
- table_clk_vlt->entries[6].clk = PP_DAL_POWERLEVEL_6;
- table_clk_vlt->entries[6].v = 6;
- table_clk_vlt->entries[7].clk = PP_DAL_POWERLEVEL_7;
- table_clk_vlt->entries[7].v = 7;
- hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt;
-
- return 0;
-}
-
static int smu10_get_system_info_data(struct pp_hwmgr *hwmgr)
{
struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)hwmgr->backend;
@@ -176,8 +140,6 @@ static int smu10_get_system_info_data(struct pp_hwmgr *hwmgr)
smu10_construct_max_power_limits_table (hwmgr,
&hwmgr->dyn_state.max_clock_voltage_on_ac);
- smu10_init_dynamic_state_adjustment_rule_settings(hwmgr);
-
return 0;
}
@@ -473,7 +435,7 @@ static int smu10_get_clock_voltage_dependency_table(struct pp_hwmgr *hwmgr,
uint32_t i;
struct smu10_voltage_dependency_table *ptable;
- ptable = kzalloc(struct_size(ptable, entries, num_entry), GFP_KERNEL);
+ ptable = kzalloc_flex(*ptable, entries, num_entry);
if (NULL == ptable)
return -ENOMEM;
@@ -551,7 +513,7 @@ static int smu10_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
int result = 0;
struct smu10_hwmgr *data;
- data = kzalloc(sizeof(struct smu10_hwmgr), GFP_KERNEL);
+ data = kzalloc_obj(struct smu10_hwmgr);
if (data == NULL)
return -ENOMEM;
@@ -612,9 +574,6 @@ static int smu10_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
kfree(pinfo->vdd_dep_on_phyclk);
pinfo->vdd_dep_on_phyclk = NULL;
- kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
- hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
-
kfree(hwmgr->backend);
hwmgr->backend = NULL;
@@ -963,12 +922,6 @@ static int smu10_store_cc6_data(struct pp_hwmgr *hwmgr, uint32_t separation_time
return 0;
}
-static int smu10_get_dal_power_level(struct pp_hwmgr *hwmgr,
- struct amd_pp_simple_clock_info *info)
-{
- return -EINVAL;
-}
-
static int smu10_force_clock_level(struct pp_hwmgr *hwmgr,
enum pp_clock_type type, uint32_t mask)
{
@@ -1024,15 +977,16 @@ static int smu10_force_clock_level(struct pp_hwmgr *hwmgr,
return 0;
}
-static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr,
- enum pp_clock_type type, char *buf)
+static int smu10_emit_clock_levels(struct pp_hwmgr *hwmgr,
+ enum pp_clock_type type, char *buf,
+ int *offset)
{
struct smu10_hwmgr *data = (struct smu10_hwmgr *)(hwmgr->backend);
struct smu10_voltage_dependency_table *mclk_table =
data->clock_vol_info.vdd_dep_on_fclk;
- uint32_t i, now, size = 0;
+ uint32_t i, now, size = *offset;
uint32_t min_freq, max_freq = 0;
- uint32_t ret = 0;
+ int ret = 0;
switch (type) {
case PP_SCLK:
@@ -1048,15 +1002,15 @@ static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr,
else
i = 1;
- size += sprintf(buf + size, "0: %uMhz %s\n",
- data->gfx_min_freq_limit/100,
- i == 0 ? "*" : "");
- size += sprintf(buf + size, "1: %uMhz %s\n",
- i == 1 ? now : SMU10_UMD_PSTATE_GFXCLK,
- i == 1 ? "*" : "");
- size += sprintf(buf + size, "2: %uMhz %s\n",
- data->gfx_max_freq_limit/100,
- i == 2 ? "*" : "");
+ size += sysfs_emit_at(buf, size, "0: %uMhz %s\n",
+ data->gfx_min_freq_limit / 100,
+ i == 0 ? "*" : "");
+ size += sysfs_emit_at(buf, size, "1: %uMhz %s\n",
+ i == 1 ? now : SMU10_UMD_PSTATE_GFXCLK,
+ i == 1 ? "*" : "");
+ size += sysfs_emit_at(buf, size, "2: %uMhz %s\n",
+ data->gfx_max_freq_limit / 100,
+ i == 2 ? "*" : "");
break;
case PP_MCLK:
ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetFclkFrequency, &now);
@@ -1064,11 +1018,12 @@ static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr,
return ret;
for (i = 0; i < mclk_table->count; i++)
- size += sprintf(buf + size, "%d: %uMhz %s\n",
- i,
- mclk_table->entries[i].clk / 100,
- ((mclk_table->entries[i].clk / 100)
- == now) ? "*" : "");
+ size += sysfs_emit_at(
+ buf, size, "%d: %uMhz %s\n", i,
+ mclk_table->entries[i].clk / 100,
+ ((mclk_table->entries[i].clk / 100) == now) ?
+ "*" :
+ "");
break;
case OD_SCLK:
if (hwmgr->od_enabled) {
@@ -1079,11 +1034,17 @@ static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr,
if (ret)
return ret;
- size += sprintf(buf + size, "%s:\n", "OD_SCLK");
- size += sprintf(buf + size, "0: %10uMhz\n",
- (data->gfx_actual_soft_min_freq > 0) ? data->gfx_actual_soft_min_freq : min_freq);
- size += sprintf(buf + size, "1: %10uMhz\n",
- (data->gfx_actual_soft_max_freq > 0) ? data->gfx_actual_soft_max_freq : max_freq);
+ size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK");
+ size += sysfs_emit_at(
+ buf, size, "0: %10uMhz\n",
+ (data->gfx_actual_soft_min_freq > 0) ?
+ data->gfx_actual_soft_min_freq :
+ min_freq);
+ size += sysfs_emit_at(
+ buf, size, "1: %10uMhz\n",
+ (data->gfx_actual_soft_max_freq > 0) ?
+ data->gfx_actual_soft_max_freq :
+ max_freq);
}
break;
case OD_RANGE:
@@ -1095,16 +1056,19 @@ static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr,
if (ret)
return ret;
- size += sprintf(buf + size, "%s:\n", "OD_RANGE");
- size += sprintf(buf + size, "SCLK: %7uMHz %10uMHz\n",
- min_freq, max_freq);
+ size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");
+ size += sysfs_emit_at(buf, size,
+ "SCLK: %7uMHz %10uMHz\n",
+ min_freq, max_freq);
}
break;
default:
break;
}
- return size;
+ *offset = size;
+
+ return 0;
}
static int smu10_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state,
@@ -1642,7 +1606,6 @@ static const struct pp_hwmgr_func smu10_hwmgr_funcs = {
.apply_state_adjust_rules = smu10_apply_state_adjust_rules,
.force_dpm_level = smu10_dpm_force_dpm_level,
.get_power_state_size = smu10_get_power_state_size,
- .powerdown_uvd = NULL,
.powergate_uvd = smu10_powergate_vcn,
.powergate_vce = NULL,
.get_mclk = smu10_dpm_get_mclk,
@@ -1653,8 +1616,7 @@ static const struct pp_hwmgr_func smu10_hwmgr_funcs = {
.set_cpu_power_state = smu10_set_cpu_power_state,
.store_cc6_data = smu10_store_cc6_data,
.force_clock_level = smu10_force_clock_level,
- .print_clock_levels = smu10_print_clock_levels,
- .get_dal_power_level = smu10_get_dal_power_level,
+ .emit_clock_levels = smu10_emit_clock_levels,
.get_performance_level = smu10_get_performance_level,
.get_current_shallow_sleep_clocks = smu10_get_current_shallow_sleep_clocks,
.get_clock_by_type_with_latency = smu10_get_clock_by_type_with_latency,
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_clockpowergating.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_clockpowergating.c
index f2bda3bcbbde..5e4c80f7b20a 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_clockpowergating.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_clockpowergating.c
@@ -55,7 +55,7 @@ static int smu7_update_vce_dpm(struct pp_hwmgr *hwmgr, bool bgate)
return smu7_enable_disable_vce_dpm(hwmgr, !bgate);
}
-int smu7_powerdown_uvd(struct pp_hwmgr *hwmgr)
+static int smu7_powerdown_uvd(struct pp_hwmgr *hwmgr)
{
if (phm_cf_want_uvd_power_gating(hwmgr))
return smum_send_msg_to_smc(hwmgr,
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_clockpowergating.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_clockpowergating.h
index fc8f8a6acc72..e56abbadc78b 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_clockpowergating.h
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_clockpowergating.h
@@ -28,7 +28,6 @@
void smu7_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate);
void smu7_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate);
-int smu7_powerdown_uvd(struct pp_hwmgr *hwmgr);
int smu7_powergate_acp(struct pp_hwmgr *hwmgr, bool bgate);
int smu7_disable_clock_power_gating(struct pp_hwmgr *hwmgr);
int smu7_update_clock_gatings(struct pp_hwmgr *hwmgr,
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c
index 632a25957477..95bf187f02a5 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c
@@ -787,7 +787,7 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr)
hwmgr->dyn_state.vddc_dependency_on_mclk;
struct phm_cac_leakage_table *std_voltage_table =
hwmgr->dyn_state.cac_leakage_table;
- uint32_t i;
+ uint32_t i, clk;
PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL,
"SCLK dependency table is missing. This table is mandatory", return -EINVAL);
@@ -804,10 +804,12 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr)
data->dpm_table.sclk_table.count = 0;
for (i = 0; i < allowed_vdd_sclk_table->count; i++) {
+ clk = min(allowed_vdd_sclk_table->entries[i].clk, data->sclk_cap);
+
if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count-1].value !=
- allowed_vdd_sclk_table->entries[i].clk) {
+ clk) {
data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value =
- allowed_vdd_sclk_table->entries[i].clk;
+ clk;
data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = (i == 0) ? 1 : 0;
data->dpm_table.sclk_table.count++;
}
@@ -2794,11 +2796,11 @@ static int smu7_patch_dependency_tables_with_leakage(struct pp_hwmgr *hwmgr)
if (tmp)
return -EINVAL;
- tmp = smu7_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
+ tmp = smu7_patch_vddci(hwmgr, hwmgr->dyn_state.vddci_dependency_on_mclk);
if (tmp)
return -EINVAL;
- tmp = smu7_patch_vddci(hwmgr, hwmgr->dyn_state.vddci_dependency_on_mclk);
+ tmp = smu7_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dependency_on_display_clock);
if (tmp)
return -EINVAL;
@@ -2883,8 +2885,8 @@ static int smu7_set_private_data_based_on_pptable_v0(struct pp_hwmgr *hwmgr)
static int smu7_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
{
- kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
- hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
+ kfree(hwmgr->dyn_state.vddc_dependency_on_display_clock);
+ hwmgr->dyn_state.vddc_dependency_on_display_clock = NULL;
kfree(hwmgr->backend);
hwmgr->backend = NULL;
@@ -2955,17 +2957,82 @@ static int smu7_update_edc_leakage_table(struct pp_hwmgr *hwmgr)
return ret;
}
+static int smu7_init_voltage_dependency_on_display_clock_table(struct pp_hwmgr *hwmgr)
+{
+ struct phm_clock_voltage_dependency_table *table;
+
+ if (!amdgpu_device_ip_get_ip_block(hwmgr->adev, AMD_IP_BLOCK_TYPE_DCE))
+ return 0;
+
+ table = kzalloc(struct_size(table, entries, 4), GFP_KERNEL);
+ if (!table)
+ return -ENOMEM;
+
+ if (hwmgr->chip_id >= CHIP_POLARIS10) {
+ table->entries[0].clk = 38918;
+ table->entries[1].clk = 45900;
+ table->entries[2].clk = 66700;
+ table->entries[3].clk = 113200;
+
+ table->entries[0].v = 700;
+ table->entries[1].v = 740;
+ table->entries[2].v = 800;
+ table->entries[3].v = 900;
+ } else {
+ if (hwmgr->chip_family == AMDGPU_FAMILY_CZ) {
+ table->entries[0].clk = 35200;
+ table->entries[1].clk = 35200;
+ table->entries[2].clk = 46700;
+ table->entries[3].clk = 64300;
+ } else {
+ table->entries[0].clk = 0;
+ table->entries[1].clk = 35200;
+ table->entries[2].clk = 54000;
+ table->entries[3].clk = 62500;
+ }
+
+ table->entries[0].v = 0;
+ table->entries[1].v = 720;
+ table->entries[2].v = 810;
+ table->entries[3].v = 900;
+ }
+
+ table->count = 4;
+ hwmgr->dyn_state.vddc_dependency_on_display_clock = table;
+ return 0;
+}
+
+static void smu7_set_sclk_cap(struct pp_hwmgr *hwmgr)
+{
+ struct amdgpu_device *adev = hwmgr->adev;
+ struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+ data->sclk_cap = 0xffffffff;
+
+ if (hwmgr->od_enabled)
+ return;
+
+ /* R9 390X board: last sclk dpm level is unstable, use lower sclk */
+ if (adev->pdev->device == 0x67B0 &&
+ adev->pdev->subsystem_vendor == 0x1043)
+ data->sclk_cap = 104000; /* 1040 MHz */
+
+ if (data->sclk_cap != 0xffffffff)
+ dev_info(adev->dev, "sclk cap: %u kHz on quirky ASIC\n", data->sclk_cap * 10);
+}
+
static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
{
struct amdgpu_device *adev = hwmgr->adev;
struct smu7_hwmgr *data;
int result = 0;
- data = kzalloc(sizeof(struct smu7_hwmgr), GFP_KERNEL);
+ data = kzalloc_obj(struct smu7_hwmgr);
if (data == NULL)
return -ENOMEM;
hwmgr->backend = data;
+ smu7_set_sclk_cap(hwmgr);
smu7_patch_voltage_workaround(hwmgr);
smu7_init_dpm_defaults(hwmgr);
@@ -2983,6 +3050,10 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
smu7_get_elb_voltages(hwmgr);
}
+ result = smu7_init_voltage_dependency_on_display_clock_table(hwmgr);
+ if (result)
+ goto fail;
+
if (hwmgr->pp_table_version == PP_TABLE_V1) {
smu7_complete_dependency_tables(hwmgr);
smu7_set_private_data_based_on_pptable_v1(hwmgr);
@@ -2991,12 +3062,6 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
smu7_set_private_data_based_on_pptable_v0(hwmgr);
}
- /* Initalize Dynamic State Adjustment Rule Settings */
- result = phm_initializa_dynamic_state_adjustment_rule_settings(hwmgr);
-
- if (result)
- goto fail;
-
data->is_tlu_enabled = false;
hwmgr->platform_descriptor.hardwareActivityPerformanceLevels =
@@ -3079,13 +3144,40 @@ static int smu7_force_dpm_highest(struct pp_hwmgr *hwmgr)
return 0;
}
+static uint32_t smu7_lookup_vddc_from_dispclk(struct pp_hwmgr *hwmgr)
+{
+ const struct amd_pp_display_configuration *cfg = hwmgr->display_config;
+ const struct phm_clock_voltage_dependency_table *vddc_dep_on_dispclk =
+ hwmgr->dyn_state.vddc_dependency_on_display_clock;
+ uint32_t i;
+
+ if (!vddc_dep_on_dispclk || !vddc_dep_on_dispclk->count ||
+ !cfg || !cfg->num_display || !cfg->display_clk)
+ return 0;
+
+ /* Start from 1 because ClocksStateUltraLow should not be used according to DC. */
+ for (i = 1; i < vddc_dep_on_dispclk->count; ++i)
+ if (vddc_dep_on_dispclk->entries[i].clk >= cfg->display_clk)
+ return vddc_dep_on_dispclk->entries[i].v;
+
+ return vddc_dep_on_dispclk->entries[vddc_dep_on_dispclk->count - 1].v;
+}
+
+static void smu7_apply_minimum_dce_voltage_request(struct pp_hwmgr *hwmgr)
+{
+ uint32_t req_vddc = smu7_lookup_vddc_from_dispclk(hwmgr);
+
+ smum_send_msg_to_smc_with_parameter(hwmgr,
+ PPSMC_MSG_VddC_Request,
+ req_vddc * VOLTAGE_SCALE,
+ NULL);
+}
+
static int smu7_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr)
{
struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
- if (hwmgr->pp_table_version == PP_TABLE_V1)
- phm_apply_dal_min_voltage_request(hwmgr);
-/* TO DO for v0 iceland and Ci*/
+ smu7_apply_minimum_dce_voltage_request(hwmgr);
if (!data->sclk_dpm_key_disabled) {
if (data->dpm_level_enable_mask.sclk_dpm_enable_mask)
@@ -3821,7 +3913,7 @@ static int smu7_get_pp_table_entry_callback_func_v0(struct pp_hwmgr *hwmgr,
/* Performance levels are arranged from low to high. */
performance_level->memory_clock = memory_clock;
- performance_level->engine_clock = engine_clock;
+ performance_level->engine_clock = min(engine_clock, data->sclk_cap);
pcie_gen_from_bios = visland_clk_info->ucPCIEGen;
@@ -4652,7 +4744,7 @@ static const struct amdgpu_irq_src_funcs smu7_irq_funcs = {
static int smu7_register_irq_handlers(struct pp_hwmgr *hwmgr)
{
struct amdgpu_irq_src *source =
- kzalloc(sizeof(struct amdgpu_irq_src), GFP_KERNEL);
+ kzalloc_obj(struct amdgpu_irq_src);
if (!source)
return -ENOMEM;
@@ -4961,8 +5053,9 @@ static int smu7_force_clock_level(struct pp_hwmgr *hwmgr,
return 0;
}
-static int smu7_print_clock_levels(struct pp_hwmgr *hwmgr,
- enum pp_clock_type type, char *buf)
+static int smu7_emit_clock_levels(struct pp_hwmgr *hwmgr,
+ enum pp_clock_type type, char *buf,
+ int *offset)
{
struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
struct smu7_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
@@ -4971,7 +5064,7 @@ static int smu7_print_clock_levels(struct pp_hwmgr *hwmgr,
struct smu7_odn_dpm_table *odn_table = &(data->odn_dpm_table);
struct phm_odn_clock_levels *odn_sclk_table = &(odn_table->odn_core_clock_dpm_levels);
struct phm_odn_clock_levels *odn_mclk_table = &(odn_table->odn_memory_clock_dpm_levels);
- int size = 0, ret = 0;
+ int size = *offset, ret = 0;
uint32_t i, now, clock, pcie_speed;
switch (type) {
@@ -4987,9 +5080,10 @@ static int smu7_print_clock_levels(struct pp_hwmgr *hwmgr,
now = i;
for (i = 0; i < sclk_table->count; i++)
- size += sprintf(buf + size, "%d: %uMhz %s\n",
- i, sclk_table->dpm_levels[i].value / 100,
- (i == now) ? "*" : "");
+ size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i,
+ sclk_table->dpm_levels[i].value /
+ 100,
+ (i == now) ? "*" : "");
break;
case PP_MCLK:
ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_API_GetMclkFrequency, &clock);
@@ -5003,9 +5097,10 @@ static int smu7_print_clock_levels(struct pp_hwmgr *hwmgr,
now = i;
for (i = 0; i < mclk_table->count; i++)
- size += sprintf(buf + size, "%d: %uMhz %s\n",
- i, mclk_table->dpm_levels[i].value / 100,
- (i == now) ? "*" : "");
+ size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i,
+ mclk_table->dpm_levels[i].value /
+ 100,
+ (i == now) ? "*" : "");
break;
case PP_PCIE:
pcie_speed = smu7_get_current_pcie_speed(hwmgr);
@@ -5017,48 +5112,68 @@ static int smu7_print_clock_levels(struct pp_hwmgr *hwmgr,
now = i;
for (i = 0; i < pcie_table->count; i++)
- size += sprintf(buf + size, "%d: %s %s\n", i,
- (pcie_table->dpm_levels[i].value == 0) ? "2.5GT/s, x8" :
- (pcie_table->dpm_levels[i].value == 1) ? "5.0GT/s, x16" :
- (pcie_table->dpm_levels[i].value == 2) ? "8.0GT/s, x16" : "",
- (i == now) ? "*" : "");
+ size += sysfs_emit_at(
+ buf, size, "%d: %s %s\n", i,
+ (pcie_table->dpm_levels[i].value == 0) ?
+ "2.5GT/s, x8" :
+ (pcie_table->dpm_levels[i].value == 1) ?
+ "5.0GT/s, x16" :
+ (pcie_table->dpm_levels[i].value == 2) ?
+ "8.0GT/s, x16" :
+ "",
+ (i == now) ? "*" : "");
break;
case OD_SCLK:
if (hwmgr->od_enabled) {
- size += sprintf(buf + size, "%s:\n", "OD_SCLK");
+ size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK");
for (i = 0; i < odn_sclk_table->num_of_pl; i++)
- size += sprintf(buf + size, "%d: %10uMHz %10umV\n",
- i, odn_sclk_table->entries[i].clock/100,
+ size += sysfs_emit_at(
+ buf, size, "%d: %10uMHz %10umV\n", i,
+ odn_sclk_table->entries[i].clock / 100,
odn_sclk_table->entries[i].vddc);
}
break;
case OD_MCLK:
if (hwmgr->od_enabled) {
- size += sprintf(buf + size, "%s:\n", "OD_MCLK");
+ size += sysfs_emit_at(buf, size, "%s:\n", "OD_MCLK");
for (i = 0; i < odn_mclk_table->num_of_pl; i++)
- size += sprintf(buf + size, "%d: %10uMHz %10umV\n",
- i, odn_mclk_table->entries[i].clock/100,
+ size += sysfs_emit_at(
+ buf, size, "%d: %10uMHz %10umV\n", i,
+ odn_mclk_table->entries[i].clock / 100,
odn_mclk_table->entries[i].vddc);
}
break;
case OD_RANGE:
if (hwmgr->od_enabled) {
- size += sprintf(buf + size, "%s:\n", "OD_RANGE");
- size += sprintf(buf + size, "SCLK: %7uMHz %10uMHz\n",
- data->golden_dpm_table.sclk_table.dpm_levels[0].value/100,
- hwmgr->platform_descriptor.overdriveLimit.engineClock/100);
- size += sprintf(buf + size, "MCLK: %7uMHz %10uMHz\n",
- data->golden_dpm_table.mclk_table.dpm_levels[0].value/100,
- hwmgr->platform_descriptor.overdriveLimit.memoryClock/100);
- size += sprintf(buf + size, "VDDC: %7umV %11umV\n",
- data->odn_dpm_table.min_vddc,
- data->odn_dpm_table.max_vddc);
+ size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");
+ size += sysfs_emit_at(
+ buf, size, "SCLK: %7uMHz %10uMHz\n",
+ data->golden_dpm_table.sclk_table.dpm_levels[0]
+ .value /
+ 100,
+ hwmgr->platform_descriptor.overdriveLimit
+ .engineClock /
+ 100);
+ size += sysfs_emit_at(
+ buf, size, "MCLK: %7uMHz %10uMHz\n",
+ data->golden_dpm_table.mclk_table.dpm_levels[0]
+ .value /
+ 100,
+ hwmgr->platform_descriptor.overdriveLimit
+ .memoryClock /
+ 100);
+ size += sysfs_emit_at(buf, size, "VDDC: %7umV %11umV\n",
+ data->odn_dpm_table.min_vddc,
+ data->odn_dpm_table.max_vddc);
}
break;
default:
break;
}
- return size;
+
+ *offset = size;
+
+ return 0;
}
static void smu7_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
@@ -5444,8 +5559,7 @@ static int smu7_get_thermal_temperature_range(struct pp_hwmgr *hwmgr,
thermal_data->max = table_info->cac_dtp_table->usSoftwareShutdownTemp *
PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
else if (hwmgr->pp_table_version == PP_TABLE_V0)
- thermal_data->max = data->thermal_temp_setting.temperature_shutdown *
- PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+ thermal_data->max = data->thermal_temp_setting.temperature_shutdown;
thermal_data->sw_ctf_threshold = thermal_data->max;
@@ -5740,6 +5854,20 @@ static int smu7_power_off_asic(struct pp_hwmgr *hwmgr)
return result;
}
+static void smu7_notify_ac_dc(struct pp_hwmgr *hwmgr)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
+
+ /* Check if the platform already manages the AC/DC switch via dedicated GPIO. */
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_AutomaticDCTransition))
+ return;
+
+ /* The SMU automatically notices DC, but needs to be notified when switching to AC. */
+ if (adev->pm.ac_power)
+ smum_send_msg_to_smc(hwmgr, PPSMC_MSG_RunningOnAC, NULL);
+}
+
static const struct pp_hwmgr_func smu7_hwmgr_funcs = {
.backend_init = &smu7_hwmgr_backend_init,
.backend_fini = &smu7_hwmgr_backend_fini,
@@ -5754,7 +5882,6 @@ static const struct pp_hwmgr_func smu7_hwmgr_funcs = {
.patch_boot_state = smu7_dpm_patch_boot_state,
.get_pp_table_entry = smu7_get_pp_table_entry,
.get_num_of_pp_table_entries = smu7_get_number_of_powerplay_table_entries,
- .powerdown_uvd = smu7_powerdown_uvd,
.powergate_uvd = smu7_powergate_uvd,
.powergate_vce = smu7_powergate_vce,
.disable_clock_power_gating = smu7_disable_clock_power_gating,
@@ -5777,7 +5904,7 @@ static const struct pp_hwmgr_func smu7_hwmgr_funcs = {
.set_fan_control_mode = smu7_set_fan_control_mode,
.get_fan_control_mode = smu7_get_fan_control_mode,
.force_clock_level = smu7_force_clock_level,
- .print_clock_levels = smu7_print_clock_levels,
+ .emit_clock_levels = smu7_emit_clock_levels,
.powergate_gfx = smu7_powergate_gfx,
.get_sclk_od = smu7_get_sclk_od,
.set_sclk_od = smu7_set_sclk_od,
@@ -5803,6 +5930,7 @@ static const struct pp_hwmgr_func smu7_hwmgr_funcs = {
.get_asic_baco_state = smu7_baco_get_state,
.set_asic_baco_state = smu7_baco_set_state,
.power_off_asic = smu7_power_off_asic,
+ .notify_ac_dc = smu7_notify_ac_dc,
};
uint8_t smu7_get_sleep_divider_id_from_clock(uint32_t clock,
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h
index d9e8b386bd4d..66adabeab6a3 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h
@@ -234,6 +234,7 @@ struct smu7_hwmgr {
uint32_t pcie_gen_cap;
uint32_t pcie_lane_cap;
uint32_t pcie_spc_cap;
+ uint32_t sclk_cap;
struct smu7_leakage_voltage vddc_leakage;
struct smu7_leakage_voltage vddci_leakage;
struct smu7_leakage_voltage vddcgfx_leakage;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_thermal.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_thermal.c
index a8fc0fa44db6..ba5c1237fcfe 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_thermal.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_thermal.c
@@ -267,10 +267,10 @@ int smu7_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
if (hwmgr->thermal_controller.fanInfo.bNoFan ||
(hwmgr->thermal_controller.fanInfo.
ucTachometerPulsesPerRevolution == 0) ||
- speed == 0 ||
+ (!speed || speed > UINT_MAX/8) ||
(speed < hwmgr->thermal_controller.fanInfo.ulMinRPM) ||
(speed > hwmgr->thermal_controller.fanInfo.ulMaxRPM))
- return 0;
+ return -EINVAL;
if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl))
smu7_fan_ctrl_stop_smc_fan_control(hwmgr);
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c
index 7e1197420873..8f82d7c07e8c 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c
@@ -270,42 +270,6 @@ static int smu8_construct_max_power_limits_table(struct pp_hwmgr *hwmgr,
return 0;
}
-static int smu8_init_dynamic_state_adjustment_rule_settings(
- struct pp_hwmgr *hwmgr,
- ATOM_CLK_VOLT_CAPABILITY *disp_voltage_table)
-{
- struct phm_clock_voltage_dependency_table *table_clk_vlt;
-
- table_clk_vlt = kzalloc(struct_size(table_clk_vlt, entries, 8),
- GFP_KERNEL);
-
- if (NULL == table_clk_vlt) {
- pr_err("Can not allocate memory!\n");
- return -ENOMEM;
- }
-
- table_clk_vlt->count = 8;
- table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_0;
- table_clk_vlt->entries[0].v = 0;
- table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_1;
- table_clk_vlt->entries[1].v = 1;
- table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_2;
- table_clk_vlt->entries[2].v = 2;
- table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_3;
- table_clk_vlt->entries[3].v = 3;
- table_clk_vlt->entries[4].clk = PP_DAL_POWERLEVEL_4;
- table_clk_vlt->entries[4].v = 4;
- table_clk_vlt->entries[5].clk = PP_DAL_POWERLEVEL_5;
- table_clk_vlt->entries[5].v = 5;
- table_clk_vlt->entries[6].clk = PP_DAL_POWERLEVEL_6;
- table_clk_vlt->entries[6].v = 6;
- table_clk_vlt->entries[7].clk = PP_DAL_POWERLEVEL_7;
- table_clk_vlt->entries[7].v = 7;
- hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt;
-
- return 0;
-}
-
static int smu8_get_system_info_data(struct pp_hwmgr *hwmgr)
{
struct smu8_hwmgr *data = hwmgr->backend;
@@ -394,7 +358,7 @@ static int smu8_get_system_info_data(struct pp_hwmgr *hwmgr)
}
if (le32_to_cpu(info->ulGPUCapInfo) &
- SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS) {
+ SYS_INFO_GPUCAPS__ENABLE_DFS_BYPASS) {
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_EnableDFSBypass);
}
@@ -404,9 +368,6 @@ static int smu8_get_system_info_data(struct pp_hwmgr *hwmgr)
smu8_construct_max_power_limits_table (hwmgr,
&hwmgr->dyn_state.max_clock_voltage_on_ac);
- smu8_init_dynamic_state_adjustment_rule_settings(hwmgr,
- &info->sDISPCLK_Voltage[0]);
-
return result;
}
@@ -1122,7 +1083,7 @@ static int smu8_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
int result = 0;
struct smu8_hwmgr *data;
- data = kzalloc(sizeof(struct smu8_hwmgr), GFP_KERNEL);
+ data = kzalloc_obj(struct smu8_hwmgr);
if (data == NULL)
return -ENOMEM;
@@ -1150,9 +1111,6 @@ static int smu8_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
static int smu8_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
{
if (hwmgr != NULL) {
- kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
- hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
-
kfree(hwmgr->backend);
hwmgr->backend = NULL;
}
@@ -1522,27 +1480,6 @@ static int smu8_store_cc6_data(struct pp_hwmgr *hwmgr, uint32_t separation_time,
return 0;
}
-static int smu8_get_dal_power_level(struct pp_hwmgr *hwmgr,
- struct amd_pp_simple_clock_info *info)
-{
- uint32_t i;
- const struct phm_clock_voltage_dependency_table *table =
- hwmgr->dyn_state.vddc_dep_on_dal_pwrl;
- const struct phm_clock_and_voltage_limits *limits =
- &hwmgr->dyn_state.max_clock_voltage_on_ac;
-
- info->engine_max_clock = limits->sclk;
- info->memory_max_clock = limits->mclk;
-
- for (i = table->count - 1; i > 0; i--) {
- if (limits->vddc >= table->entries[i].v) {
- info->level = table->entries[i].clk;
- return 0;
- }
- }
- return -EINVAL;
-}
-
static int smu8_force_clock_level(struct pp_hwmgr *hwmgr,
enum pp_clock_type type, uint32_t mask)
{
@@ -1564,14 +1501,15 @@ static int smu8_force_clock_level(struct pp_hwmgr *hwmgr,
return 0;
}
-static int smu8_print_clock_levels(struct pp_hwmgr *hwmgr,
- enum pp_clock_type type, char *buf)
+static int smu8_emit_clock_levels(struct pp_hwmgr *hwmgr,
+ enum pp_clock_type type, char *buf,
+ int *offset)
{
struct smu8_hwmgr *data = hwmgr->backend;
struct phm_clock_voltage_dependency_table *sclk_table =
hwmgr->dyn_state.vddc_dependency_on_sclk;
uint32_t i, now;
- int size = 0;
+ int size = *offset;
switch (type) {
case PP_SCLK:
@@ -1582,9 +1520,9 @@ static int smu8_print_clock_levels(struct pp_hwmgr *hwmgr,
CURR_SCLK_INDEX);
for (i = 0; i < sclk_table->count; i++)
- size += sprintf(buf + size, "%d: %uMhz %s\n",
- i, sclk_table->entries[i].clk / 100,
- (i == now) ? "*" : "");
+ size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i,
+ sclk_table->entries[i].clk / 100,
+ (i == now) ? "*" : "");
break;
case PP_MCLK:
now = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device,
@@ -1594,14 +1532,20 @@ static int smu8_print_clock_levels(struct pp_hwmgr *hwmgr,
CURR_MCLK_INDEX);
for (i = SMU8_NUM_NBPMEMORYCLOCK; i > 0; i--)
- size += sprintf(buf + size, "%d: %uMhz %s\n",
- SMU8_NUM_NBPMEMORYCLOCK-i, data->sys_info.nbp_memory_clock[i-1] / 100,
- (SMU8_NUM_NBPMEMORYCLOCK-i == now) ? "*" : "");
+ size += sysfs_emit_at(
+ buf, size, "%d: %uMhz %s\n",
+ SMU8_NUM_NBPMEMORYCLOCK - i,
+ data->sys_info.nbp_memory_clock[i - 1] / 100,
+ (SMU8_NUM_NBPMEMORYCLOCK - i == now) ? "*" :
+ "");
break;
default:
break;
}
- return size;
+
+ *offset = size;
+
+ return 0;
}
static int smu8_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state,
@@ -2044,7 +1988,6 @@ static const struct pp_hwmgr_func smu8_hwmgr_funcs = {
.apply_state_adjust_rules = smu8_apply_state_adjust_rules,
.force_dpm_level = smu8_dpm_force_dpm_level,
.get_power_state_size = smu8_get_power_state_size,
- .powerdown_uvd = smu8_dpm_powerdown_uvd,
.powergate_uvd = smu8_dpm_powergate_uvd,
.powergate_vce = smu8_dpm_powergate_vce,
.powergate_acp = smu8_dpm_powergate_acp,
@@ -2056,8 +1999,7 @@ static const struct pp_hwmgr_func smu8_hwmgr_funcs = {
.set_cpu_power_state = smu8_set_cpu_power_state,
.store_cc6_data = smu8_store_cc6_data,
.force_clock_level = smu8_force_clock_level,
- .print_clock_levels = smu8_print_clock_levels,
- .get_dal_power_level = smu8_get_dal_power_level,
+ .emit_clock_levels = smu8_emit_clock_levels,
.get_performance_level = smu8_get_performance_level,
.get_current_shallow_sleep_clocks = smu8_get_current_shallow_sleep_clocks,
.get_clock_by_type = smu8_get_clock_by_type,
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.c
index 79a566f3564a..085b100821b9 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.c
@@ -49,11 +49,10 @@ int phm_copy_clock_limits_array(
const uint32_t *pptable_array,
uint32_t power_saving_clock_count)
{
- uint32_t array_size, i;
+ uint32_t i;
uint32_t *table;
- array_size = sizeof(uint32_t) * power_saving_clock_count;
- table = kzalloc(array_size, GFP_KERNEL);
+ table = kcalloc(power_saving_clock_count, sizeof(uint32_t), GFP_KERNEL);
if (NULL == table)
return -ENOMEM;
@@ -71,11 +70,10 @@ int phm_copy_overdrive_settings_limits_array(
const uint32_t *pptable_array,
uint32_t od_setting_count)
{
- uint32_t array_size, i;
+ uint32_t i;
uint32_t *table;
- array_size = sizeof(uint32_t) * od_setting_count;
- table = kzalloc(array_size, GFP_KERNEL);
+ table = kcalloc(od_setting_count, sizeof(uint32_t), GFP_KERNEL);
if (NULL == table)
return -ENOMEM;
@@ -149,7 +147,7 @@ int phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr,
}
cgs_write_register(hwmgr->device, indirect_port, index);
- return phm_wait_on_register(hwmgr, indirect_port + 1, mask, value);
+ return phm_wait_on_register(hwmgr, indirect_port + 1, value, mask);
}
int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr,
@@ -211,8 +209,7 @@ int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table)
PP_ASSERT_WITH_CODE((NULL != vol_table),
"Voltage Table empty.", return -EINVAL);
- table = kzalloc(sizeof(struct pp_atomctrl_voltage_table),
- GFP_KERNEL);
+ table = kzalloc_obj(struct pp_atomctrl_voltage_table);
if (NULL == table)
return -EINVAL;
@@ -485,53 +482,6 @@ int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr,
return 0;
}
-/**
- * phm_initializa_dynamic_state_adjustment_rule_settings - Initialize Dynamic State Adjustment Rule Settings
- *
- * @hwmgr: the address of the powerplay hardware manager.
- */
-int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr)
-{
- struct phm_clock_voltage_dependency_table *table_clk_vlt;
- struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
- /* initialize vddc_dep_on_dal_pwrl table */
- table_clk_vlt = kzalloc(struct_size(table_clk_vlt, entries, 4),
- GFP_KERNEL);
-
- if (NULL == table_clk_vlt) {
- pr_err("Can not allocate space for vddc_dep_on_dal_pwrl! \n");
- return -ENOMEM;
- } else {
- table_clk_vlt->count = 4;
- table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_ULTRALOW;
- if (hwmgr->chip_id >= CHIP_POLARIS10 &&
- hwmgr->chip_id <= CHIP_VEGAM)
- table_clk_vlt->entries[0].v = 700;
- else
- table_clk_vlt->entries[0].v = 0;
- table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_LOW;
- if (hwmgr->chip_id >= CHIP_POLARIS10 &&
- hwmgr->chip_id <= CHIP_VEGAM)
- table_clk_vlt->entries[1].v = 740;
- else
- table_clk_vlt->entries[1].v = 720;
- table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_NOMINAL;
- if (hwmgr->chip_id >= CHIP_POLARIS10 &&
- hwmgr->chip_id <= CHIP_VEGAM)
- table_clk_vlt->entries[2].v = 800;
- else
- table_clk_vlt->entries[2].v = 810;
- table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_PERFORMANCE;
- table_clk_vlt->entries[3].v = 900;
- if (pptable_info != NULL)
- pptable_info->vddc_dep_on_dal_pwrl = table_clk_vlt;
- hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt;
- }
-
- return 0;
-}
-
uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask)
{
uint32_t level = 0;
@@ -542,43 +492,6 @@ uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask)
return level;
}
-void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr)
-{
- struct phm_ppt_v1_information *table_info =
- (struct phm_ppt_v1_information *)hwmgr->pptable;
- struct phm_clock_voltage_dependency_table *table =
- table_info->vddc_dep_on_dal_pwrl;
- struct phm_ppt_v1_clock_voltage_dependency_table *vddc_table;
- enum PP_DAL_POWERLEVEL dal_power_level = hwmgr->dal_power_level;
- uint32_t req_vddc = 0, req_volt, i;
-
- if (!table || table->count <= 0
- || dal_power_level < PP_DAL_POWERLEVEL_ULTRALOW
- || dal_power_level > PP_DAL_POWERLEVEL_PERFORMANCE)
- return;
-
- for (i = 0; i < table->count; i++) {
- if (dal_power_level == table->entries[i].clk) {
- req_vddc = table->entries[i].v;
- break;
- }
- }
-
- vddc_table = table_info->vdd_dep_on_sclk;
- for (i = 0; i < vddc_table->count; i++) {
- if (req_vddc <= vddc_table->entries[i].vddc) {
- req_volt = (((uint32_t)vddc_table->entries[i].vddc) * VOLTAGE_SCALE);
- smum_send_msg_to_smc_with_parameter(hwmgr,
- PPSMC_MSG_VddC_Request,
- req_volt,
- NULL);
- return;
- }
- }
- pr_err("DAL requested level can not"
- " found a available voltage in VDDC DPM Table \n");
-}
-
int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type,
uint32_t sclk, uint16_t id, uint16_t *voltage)
{
@@ -646,7 +559,7 @@ static const struct amdgpu_irq_src_funcs smu9_irq_funcs = {
int smu9_register_irq_handlers(struct pp_hwmgr *hwmgr)
{
struct amdgpu_irq_src *source =
- kzalloc(sizeof(struct amdgpu_irq_src), GFP_KERNEL);
+ kzalloc_obj(struct amdgpu_irq_src);
if (!source)
return -ENOMEM;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.h
index 83b3c9315143..d370bfd0764d 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.h
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.h
@@ -87,9 +87,7 @@ extern uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_t
extern int phm_find_boot_level(void *table, uint32_t value, uint32_t *boot_level);
extern int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr, phm_ppt_v1_voltage_lookup_table *lookup_table,
uint16_t virtual_voltage_id, int32_t *sclk);
-extern int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr);
extern uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask);
-extern void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr);
extern int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type,
uint32_t sclk, uint16_t id, uint16_t *voltage);
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c
index 9ace863792d4..4b92b52aba2b 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c
@@ -814,9 +814,6 @@ static int vega10_set_private_data_based_on_pptable(struct pp_hwmgr *hwmgr)
static int vega10_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
{
- kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
- hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
-
kfree(hwmgr->backend);
hwmgr->backend = NULL;
@@ -831,7 +828,7 @@ static int vega10_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
struct pp_atomfwctrl_voltage_table vol_table;
struct amdgpu_device *adev = hwmgr->adev;
- data = kzalloc(sizeof(struct vega10_hwmgr), GFP_KERNEL);
+ data = kzalloc_obj(struct vega10_hwmgr);
if (data == NULL)
return -ENOMEM;
@@ -1029,8 +1026,7 @@ static int vega10_trim_voltage_table(struct pp_hwmgr *hwmgr,
PP_ASSERT_WITH_CODE(vol_table,
"Voltage Table empty.", return -EINVAL);
- table = kzalloc(sizeof(struct pp_atomfwctrl_voltage_table),
- GFP_KERNEL);
+ table = kzalloc_obj(struct pp_atomfwctrl_voltage_table);
if (!table)
return -ENOMEM;
@@ -4387,20 +4383,6 @@ static uint32_t vega10_get_fan_control_mode(struct pp_hwmgr *hwmgr)
return AMD_FAN_CTRL_AUTO;
}
-static int vega10_get_dal_power_level(struct pp_hwmgr *hwmgr,
- struct amd_pp_simple_clock_info *info)
-{
- struct phm_ppt_v2_information *table_info =
- (struct phm_ppt_v2_information *)hwmgr->pptable;
- struct phm_clock_and_voltage_limits *max_limits =
- &table_info->max_clock_voltage_on_ac;
-
- info->engine_max_clock = max_limits->sclk;
- info->memory_max_clock = max_limits->mclk;
-
- return 0;
-}
-
static void vega10_get_sclks(struct pp_hwmgr *hwmgr,
struct pp_clock_levels_with_latency *clocks)
{
@@ -4825,146 +4807,6 @@ static int vega10_emit_clock_levels(struct pp_hwmgr *hwmgr,
return ret;
}
-static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr,
- enum pp_clock_type type, char *buf)
-{
- struct vega10_hwmgr *data = hwmgr->backend;
- struct vega10_single_dpm_table *sclk_table = &(data->dpm_table.gfx_table);
- struct vega10_single_dpm_table *mclk_table = &(data->dpm_table.mem_table);
- struct vega10_single_dpm_table *soc_table = &(data->dpm_table.soc_table);
- struct vega10_single_dpm_table *dcef_table = &(data->dpm_table.dcef_table);
- struct vega10_odn_clock_voltage_dependency_table *podn_vdd_dep = NULL;
- uint32_t gen_speed, lane_width, current_gen_speed, current_lane_width;
- PPTable_t *pptable = &(data->smc_state_table.pp_table);
-
- int i, ret, now, size = 0, count = 0;
-
- switch (type) {
- case PP_SCLK:
- if (data->registry_data.sclk_dpm_key_disabled)
- break;
-
- ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentGfxclkIndex, &now);
- if (ret)
- break;
-
- if (hwmgr->pp_one_vf &&
- (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK))
- count = 5;
- else
- count = sclk_table->count;
- for (i = 0; i < count; i++)
- size += sprintf(buf + size, "%d: %uMhz %s\n",
- i, sclk_table->dpm_levels[i].value / 100,
- (i == now) ? "*" : "");
- break;
- case PP_MCLK:
- if (data->registry_data.mclk_dpm_key_disabled)
- break;
-
- ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentUclkIndex, &now);
- if (ret)
- break;
-
- for (i = 0; i < mclk_table->count; i++)
- size += sprintf(buf + size, "%d: %uMhz %s\n",
- i, mclk_table->dpm_levels[i].value / 100,
- (i == now) ? "*" : "");
- break;
- case PP_SOCCLK:
- if (data->registry_data.socclk_dpm_key_disabled)
- break;
-
- ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentSocclkIndex, &now);
- if (ret)
- break;
-
- for (i = 0; i < soc_table->count; i++)
- size += sprintf(buf + size, "%d: %uMhz %s\n",
- i, soc_table->dpm_levels[i].value / 100,
- (i == now) ? "*" : "");
- break;
- case PP_DCEFCLK:
- if (data->registry_data.dcefclk_dpm_key_disabled)
- break;
-
- ret = smum_send_msg_to_smc_with_parameter(hwmgr,
- PPSMC_MSG_GetClockFreqMHz, CLK_DCEFCLK, &now);
- if (ret)
- break;
-
- for (i = 0; i < dcef_table->count; i++)
- size += sprintf(buf + size, "%d: %uMhz %s\n",
- i, dcef_table->dpm_levels[i].value / 100,
- (dcef_table->dpm_levels[i].value / 100 == now) ?
- "*" : "");
- break;
- case PP_PCIE:
- current_gen_speed =
- vega10_get_current_pcie_link_speed_level(hwmgr);
- current_lane_width =
- vega10_get_current_pcie_link_width_level(hwmgr);
- for (i = 0; i < NUM_LINK_LEVELS; i++) {
- gen_speed = pptable->PcieGenSpeed[i];
- lane_width = pptable->PcieLaneCount[i];
-
- size += sprintf(buf + size, "%d: %s %s %s\n", i,
- (gen_speed == 0) ? "2.5GT/s," :
- (gen_speed == 1) ? "5.0GT/s," :
- (gen_speed == 2) ? "8.0GT/s," :
- (gen_speed == 3) ? "16.0GT/s," : "",
- (lane_width == 1) ? "x1" :
- (lane_width == 2) ? "x2" :
- (lane_width == 3) ? "x4" :
- (lane_width == 4) ? "x8" :
- (lane_width == 5) ? "x12" :
- (lane_width == 6) ? "x16" : "",
- (current_gen_speed == gen_speed) &&
- (current_lane_width == lane_width) ?
- "*" : "");
- }
- break;
-
- case OD_SCLK:
- if (hwmgr->od_enabled) {
- size += sprintf(buf + size, "%s:\n", "OD_SCLK");
- podn_vdd_dep = &data->odn_dpm_table.vdd_dep_on_sclk;
- for (i = 0; i < podn_vdd_dep->count; i++)
- size += sprintf(buf + size, "%d: %10uMhz %10umV\n",
- i, podn_vdd_dep->entries[i].clk / 100,
- podn_vdd_dep->entries[i].vddc);
- }
- break;
- case OD_MCLK:
- if (hwmgr->od_enabled) {
- size += sprintf(buf + size, "%s:\n", "OD_MCLK");
- podn_vdd_dep = &data->odn_dpm_table.vdd_dep_on_mclk;
- for (i = 0; i < podn_vdd_dep->count; i++)
- size += sprintf(buf + size, "%d: %10uMhz %10umV\n",
- i, podn_vdd_dep->entries[i].clk/100,
- podn_vdd_dep->entries[i].vddc);
- }
- break;
- case OD_RANGE:
- if (hwmgr->od_enabled) {
- size += sprintf(buf + size, "%s:\n", "OD_RANGE");
- size += sprintf(buf + size, "SCLK: %7uMHz %10uMHz\n",
- data->golden_dpm_table.gfx_table.dpm_levels[0].value/100,
- hwmgr->platform_descriptor.overdriveLimit.engineClock/100);
- size += sprintf(buf + size, "MCLK: %7uMHz %10uMHz\n",
- data->golden_dpm_table.mem_table.dpm_levels[0].value/100,
- hwmgr->platform_descriptor.overdriveLimit.memoryClock/100);
- size += sprintf(buf + size, "VDDC: %7umV %11umV\n",
- data->odn_dpm_table.min_vddc,
- data->odn_dpm_table.max_vddc);
- }
- break;
- default:
- break;
- }
- return size;
-}
-
static int vega10_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
{
struct vega10_hwmgr *data = hwmgr->backend;
@@ -5785,14 +5627,12 @@ static const struct pp_hwmgr_func vega10_hwmgr_funcs = {
.set_fan_control_mode = vega10_set_fan_control_mode,
.get_fan_control_mode = vega10_get_fan_control_mode,
.read_sensor = vega10_read_sensor,
- .get_dal_power_level = vega10_get_dal_power_level,
.get_clock_by_type_with_latency = vega10_get_clock_by_type_with_latency,
.get_clock_by_type_with_voltage = vega10_get_clock_by_type_with_voltage,
.set_watermarks_for_clocks_ranges = vega10_set_watermarks_for_clocks_ranges,
.display_clock_voltage_request = vega10_display_clock_voltage_request,
.force_clock_level = vega10_force_clock_level,
.emit_clock_levels = vega10_emit_clock_levels,
- .print_clock_levels = vega10_print_clock_levels,
.display_config_changed = vega10_display_configuration_changed_task,
.powergate_uvd = vega10_power_gate_uvd,
.powergate_vce = vega10_power_gate_vce,
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c
index 3be616af327e..052d139584fd 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c
@@ -350,8 +350,8 @@ static int get_mm_clock_voltage_table(
PP_ASSERT_WITH_CODE((mm_dependency_table->ucNumEntries != 0),
"Invalid PowerPlay Table!", return -1);
- mm_table = kzalloc(struct_size(mm_table, entries, mm_dependency_table->ucNumEntries),
- GFP_KERNEL);
+ mm_table = kzalloc_flex(*mm_table, entries,
+ mm_dependency_table->ucNumEntries);
if (!mm_table)
return -ENOMEM;
@@ -573,8 +573,8 @@ static int get_socclk_voltage_dependency_table(
PP_ASSERT_WITH_CODE(clk_dep_table->ucNumEntries,
"Invalid PowerPlay Table!", return -1);
- clk_table = kzalloc(struct_size(clk_table, entries, clk_dep_table->ucNumEntries),
- GFP_KERNEL);
+ clk_table = kzalloc_flex(*clk_table, entries,
+ clk_dep_table->ucNumEntries);
if (!clk_table)
return -ENOMEM;
@@ -603,8 +603,8 @@ static int get_mclk_voltage_dependency_table(
PP_ASSERT_WITH_CODE(mclk_dep_table->ucNumEntries,
"Invalid PowerPlay Table!", return -1);
- mclk_table = kzalloc(struct_size(mclk_table, entries, mclk_dep_table->ucNumEntries),
- GFP_KERNEL);
+ mclk_table = kzalloc_flex(*mclk_table, entries,
+ mclk_dep_table->ucNumEntries);
if (!mclk_table)
return -ENOMEM;
@@ -640,8 +640,8 @@ static int get_gfxclk_voltage_dependency_table(
PP_ASSERT_WITH_CODE((clk_dep_table->ucNumEntries != 0),
"Invalid PowerPlay Table!", return -1);
- clk_table = kzalloc(struct_size(clk_table, entries, clk_dep_table->ucNumEntries),
- GFP_KERNEL);
+ clk_table = kzalloc_flex(*clk_table, entries,
+ clk_dep_table->ucNumEntries);
if (!clk_table)
return -ENOMEM;
@@ -702,8 +702,8 @@ static int get_pix_clk_voltage_dependency_table(
PP_ASSERT_WITH_CODE((clk_dep_table->ucNumEntries != 0),
"Invalid PowerPlay Table!", return -1);
- clk_table = kzalloc(struct_size(clk_table, entries, clk_dep_table->ucNumEntries),
- GFP_KERNEL);
+ clk_table = kzalloc_flex(*clk_table, entries,
+ clk_dep_table->ucNumEntries);
if (!clk_table)
return -ENOMEM;
@@ -755,8 +755,7 @@ static int get_dcefclk_voltage_dependency_table(
num_entries = clk_dep_table->ucNumEntries;
- clk_table = kzalloc(struct_size(clk_table, entries, num_entries),
- GFP_KERNEL);
+ clk_table = kzalloc_flex(*clk_table, entries, num_entries);
if (!clk_table)
return -ENOMEM;
@@ -794,8 +793,8 @@ static int get_pcie_table(struct pp_hwmgr *hwmgr,
"Invalid PowerPlay Table!",
return 0);
- pcie_table = kzalloc(struct_size(pcie_table, entries, atom_pcie_table->ucNumEntries),
- GFP_KERNEL);
+ pcie_table = kzalloc_flex(*pcie_table, entries,
+ atom_pcie_table->ucNumEntries);
if (!pcie_table)
return -ENOMEM;
@@ -853,8 +852,7 @@ static int get_valid_clk(
PP_ASSERT_WITH_CODE(clk_volt_pp_table->count,
"Invalid PowerPlay Table!", return -1);
- table = kzalloc(struct_size(table, values, clk_volt_pp_table->count),
- GFP_KERNEL);
+ table = kzalloc_flex(*table, values, clk_volt_pp_table->count);
if (!table)
return -ENOMEM;
@@ -1041,7 +1039,7 @@ static int get_vddc_lookup_table(
PP_ASSERT_WITH_CODE((vddc_lookup_pp_tables->ucNumEntries != 0),
"Invalid SOC_VDDD Lookup Table!", return 1);
- table = kzalloc(struct_size(table, entries, max_levels), GFP_KERNEL);
+ table = kzalloc_flex(*table, entries, max_levels);
if (!table)
return -ENOMEM;
@@ -1149,7 +1147,7 @@ static int vega10_pp_tables_initialize(struct pp_hwmgr *hwmgr)
int result = 0;
const ATOM_Vega10_POWERPLAYTABLE *powerplay_table;
- hwmgr->pptable = kzalloc(sizeof(struct phm_ppt_v2_information), GFP_KERNEL);
+ hwmgr->pptable = kzalloc_obj(struct phm_ppt_v2_information);
PP_ASSERT_WITH_CODE((hwmgr->pptable != NULL),
"Failed to allocate hwmgr->pptable!", return -ENOMEM);
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c
index 379012494da5..56423aedf3fa 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c
@@ -307,10 +307,10 @@ int vega10_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
int result = 0;
if (hwmgr->thermal_controller.fanInfo.bNoFan ||
- speed == 0 ||
+ (!speed || speed > UINT_MAX/8) ||
(speed < hwmgr->thermal_controller.fanInfo.ulMinRPM) ||
(speed > hwmgr->thermal_controller.fanInfo.ulMaxRPM))
- return -1;
+ return -EINVAL;
if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl))
result = vega10_fan_ctrl_stop_smc_fan_control(hwmgr);
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c
index 10fd4e9f016c..69a9074058ce 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c
@@ -395,7 +395,7 @@ static int vega12_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
struct vega12_hwmgr *data;
struct amdgpu_device *adev = hwmgr->adev;
- data = kzalloc(sizeof(struct vega12_hwmgr), GFP_KERNEL);
+ data = kzalloc_obj(struct vega12_hwmgr);
if (data == NULL)
return -ENOMEM;
@@ -1822,21 +1822,6 @@ static uint32_t vega12_get_fan_control_mode(struct pp_hwmgr *hwmgr)
return AMD_FAN_CTRL_AUTO;
}
-static int vega12_get_dal_power_level(struct pp_hwmgr *hwmgr,
- struct amd_pp_simple_clock_info *info)
-{
-#if 0
- struct phm_ppt_v2_information *table_info =
- (struct phm_ppt_v2_information *)hwmgr->pptable;
- struct phm_clock_and_voltage_limits *max_limits =
- &table_info->max_clock_voltage_on_ac;
-
- info->engine_max_clock = max_limits->sclk;
- info->memory_max_clock = max_limits->mclk;
-#endif
- return 0;
-}
-
static int vega12_get_clock_ranges(struct pp_hwmgr *hwmgr,
uint32_t *clock,
PPCLK_e clock_select,
@@ -2271,11 +2256,12 @@ static int vega12_get_current_pcie_link_speed(struct pp_hwmgr *hwmgr)
return link_speed[speed_level];
}
-static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr,
- enum pp_clock_type type, char *buf)
+static int vega12_emit_clock_levels(struct pp_hwmgr *hwmgr,
+ enum pp_clock_type type, char *buf,
+ int *offset)
{
- int i, now, size = 0;
struct pp_clock_levels_with_latency clocks;
+ int i, now, size = *offset;
switch (type) {
case PP_SCLK:
@@ -2289,9 +2275,13 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr,
"Attempt to get gfx clk levels Failed!",
return -1);
for (i = 0; i < clocks.num_levels; i++)
- size += sprintf(buf + size, "%d: %uMhz %s\n",
- i, clocks.data[i].clocks_in_khz / 1000,
- (clocks.data[i].clocks_in_khz / 1000 == now / 100) ? "*" : "");
+ size += sysfs_emit_at(
+ buf, size, "%d: %uMhz %s\n", i,
+ clocks.data[i].clocks_in_khz / 1000,
+ (clocks.data[i].clocks_in_khz / 1000 ==
+ now / 100) ?
+ "*" :
+ "");
break;
case PP_MCLK:
@@ -2305,9 +2295,13 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr,
"Attempt to get memory clk levels Failed!",
return -1);
for (i = 0; i < clocks.num_levels; i++)
- size += sprintf(buf + size, "%d: %uMhz %s\n",
- i, clocks.data[i].clocks_in_khz / 1000,
- (clocks.data[i].clocks_in_khz / 1000 == now / 100) ? "*" : "");
+ size += sysfs_emit_at(
+ buf, size, "%d: %uMhz %s\n", i,
+ clocks.data[i].clocks_in_khz / 1000,
+ (clocks.data[i].clocks_in_khz / 1000 ==
+ now / 100) ?
+ "*" :
+ "");
break;
case PP_SOCCLK:
@@ -2323,9 +2317,12 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr,
"Attempt to get soc clk levels Failed!",
return -1);
for (i = 0; i < clocks.num_levels; i++)
- size += sprintf(buf + size, "%d: %uMhz %s\n",
- i, clocks.data[i].clocks_in_khz / 1000,
- (clocks.data[i].clocks_in_khz / 1000 == now) ? "*" : "");
+ size += sysfs_emit_at(
+ buf, size, "%d: %uMhz %s\n", i,
+ clocks.data[i].clocks_in_khz / 1000,
+ (clocks.data[i].clocks_in_khz / 1000 == now) ?
+ "*" :
+ "");
break;
case PP_DCEFCLK:
@@ -2341,9 +2338,12 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr,
"Attempt to get dcef clk levels Failed!",
return -1);
for (i = 0; i < clocks.num_levels; i++)
- size += sprintf(buf + size, "%d: %uMhz %s\n",
- i, clocks.data[i].clocks_in_khz / 1000,
- (clocks.data[i].clocks_in_khz / 1000 == now) ? "*" : "");
+ size += sysfs_emit_at(
+ buf, size, "%d: %uMhz %s\n", i,
+ clocks.data[i].clocks_in_khz / 1000,
+ (clocks.data[i].clocks_in_khz / 1000 == now) ?
+ "*" :
+ "");
break;
case PP_PCIE:
@@ -2352,7 +2352,10 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr,
default:
break;
}
- return size;
+
+ *offset = size;
+
+ return 0;
}
static int vega12_apply_clocks_adjust_rules(struct pp_hwmgr *hwmgr)
@@ -2945,13 +2948,12 @@ static const struct pp_hwmgr_func vega12_hwmgr_funcs = {
.set_fan_control_mode = vega12_set_fan_control_mode,
.get_fan_control_mode = vega12_get_fan_control_mode,
.read_sensor = vega12_read_sensor,
- .get_dal_power_level = vega12_get_dal_power_level,
.get_clock_by_type_with_latency = vega12_get_clock_by_type_with_latency,
.get_clock_by_type_with_voltage = vega12_get_clock_by_type_with_voltage,
.set_watermarks_for_clocks_ranges = vega12_set_watermarks_for_clocks_ranges,
.display_clock_voltage_request = vega12_display_clock_voltage_request,
.force_clock_level = vega12_force_clock_level,
- .print_clock_levels = vega12_print_clock_levels,
+ .emit_clock_levels = vega12_emit_clock_levels,
.apply_clocks_adjust_rules =
vega12_apply_clocks_adjust_rules,
.pre_display_config_changed =
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c
index 89148f73b514..55e13f376039 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c
@@ -263,7 +263,7 @@ static int vega12_pp_tables_initialize(struct pp_hwmgr *hwmgr)
int result = 0;
const ATOM_Vega12_POWERPLAYTABLE *powerplay_table;
- hwmgr->pptable = kzalloc(sizeof(struct phm_ppt_v3_information), GFP_KERNEL);
+ hwmgr->pptable = kzalloc_obj(struct phm_ppt_v3_information);
PP_ASSERT_WITH_CODE((hwmgr->pptable != NULL),
"Failed to allocate hwmgr->pptable!", return -ENOMEM);
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c
index baf251fe5d82..7b8f4c1b80eb 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c
@@ -436,7 +436,7 @@ static int vega20_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
struct amdgpu_device *adev = hwmgr->adev;
int result;
- data = kzalloc(sizeof(struct vega20_hwmgr), GFP_KERNEL);
+ data = kzalloc_obj(struct vega20_hwmgr);
if (data == NULL)
return -ENOMEM;
@@ -2796,22 +2796,6 @@ static void vega20_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
}
}
-static int vega20_get_dal_power_level(struct pp_hwmgr *hwmgr,
- struct amd_pp_simple_clock_info *info)
-{
-#if 0
- struct phm_ppt_v2_information *table_info =
- (struct phm_ppt_v2_information *)hwmgr->pptable;
- struct phm_clock_and_voltage_limits *max_limits =
- &table_info->max_clock_voltage_on_ac;
-
- info->engine_max_clock = max_limits->sclk;
- info->memory_max_clock = max_limits->mclk;
-#endif
- return 0;
-}
-
-
static int vega20_get_sclks(struct pp_hwmgr *hwmgr,
struct pp_clock_levels_with_latency *clocks)
{
@@ -3362,8 +3346,9 @@ static int vega20_get_current_pcie_link_speed(struct pp_hwmgr *hwmgr)
return link_speed[speed_level];
}
-static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
- enum pp_clock_type type, char *buf)
+static int vega20_emit_clock_levels(struct pp_hwmgr *hwmgr,
+ enum pp_clock_type type, char *buf,
+ int *offset)
{
struct vega20_hwmgr *data =
(struct vega20_hwmgr *)(hwmgr->backend);
@@ -3375,7 +3360,7 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
struct pp_clock_levels_with_latency clocks;
struct vega20_single_dpm_table *fclk_dpm_table =
&(data->dpm_table.fclk_table);
- int i, now, size = 0;
+ int i, now, size = *offset;
int ret = 0;
uint32_t gen_speed, lane_width, current_gen_speed, current_lane_width;
@@ -3387,15 +3372,19 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
return ret);
if (vega20_get_sclks(hwmgr, &clocks)) {
- size += sprintf(buf + size, "0: %uMhz * (DPM disabled)\n",
- now / 100);
+ size += sysfs_emit_at(buf, size,
+ "0: %uMhz * (DPM disabled)\n",
+ now / 100);
break;
}
for (i = 0; i < clocks.num_levels; i++)
- size += sprintf(buf + size, "%d: %uMhz %s\n",
- i, clocks.data[i].clocks_in_khz / 1000,
- (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
+ size += sysfs_emit_at(
+ buf, size, "%d: %uMhz %s\n", i,
+ clocks.data[i].clocks_in_khz / 1000,
+ (clocks.data[i].clocks_in_khz == now * 10) ?
+ "*" :
+ "");
break;
case PP_MCLK:
@@ -3405,15 +3394,19 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
return ret);
if (vega20_get_memclocks(hwmgr, &clocks)) {
- size += sprintf(buf + size, "0: %uMhz * (DPM disabled)\n",
- now / 100);
+ size += sysfs_emit_at(buf, size,
+ "0: %uMhz * (DPM disabled)\n",
+ now / 100);
break;
}
for (i = 0; i < clocks.num_levels; i++)
- size += sprintf(buf + size, "%d: %uMhz %s\n",
- i, clocks.data[i].clocks_in_khz / 1000,
- (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
+ size += sysfs_emit_at(
+ buf, size, "%d: %uMhz %s\n", i,
+ clocks.data[i].clocks_in_khz / 1000,
+ (clocks.data[i].clocks_in_khz == now * 10) ?
+ "*" :
+ "");
break;
case PP_SOCCLK:
@@ -3423,15 +3416,19 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
return ret);
if (vega20_get_socclocks(hwmgr, &clocks)) {
- size += sprintf(buf + size, "0: %uMhz * (DPM disabled)\n",
- now / 100);
+ size += sysfs_emit_at(buf, size,
+ "0: %uMhz * (DPM disabled)\n",
+ now / 100);
break;
}
for (i = 0; i < clocks.num_levels; i++)
- size += sprintf(buf + size, "%d: %uMhz %s\n",
- i, clocks.data[i].clocks_in_khz / 1000,
- (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
+ size += sysfs_emit_at(
+ buf, size, "%d: %uMhz %s\n", i,
+ clocks.data[i].clocks_in_khz / 1000,
+ (clocks.data[i].clocks_in_khz == now * 10) ?
+ "*" :
+ "");
break;
case PP_FCLK:
@@ -3441,9 +3438,13 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
return ret);
for (i = 0; i < fclk_dpm_table->count; i++)
- size += sprintf(buf + size, "%d: %uMhz %s\n",
- i, fclk_dpm_table->dpm_levels[i].value,
- fclk_dpm_table->dpm_levels[i].value == (now / 100) ? "*" : "");
+ size += sysfs_emit_at(
+ buf, size, "%d: %uMhz %s\n", i,
+ fclk_dpm_table->dpm_levels[i].value,
+ fclk_dpm_table->dpm_levels[i].value ==
+ (now / 100) ?
+ "*" :
+ "");
break;
case PP_DCEFCLK:
@@ -3453,15 +3454,19 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
return ret);
if (vega20_get_dcefclocks(hwmgr, &clocks)) {
- size += sprintf(buf + size, "0: %uMhz * (DPM disabled)\n",
- now / 100);
+ size += sysfs_emit_at(buf, size,
+ "0: %uMhz * (DPM disabled)\n",
+ now / 100);
break;
}
for (i = 0; i < clocks.num_levels; i++)
- size += sprintf(buf + size, "%d: %uMhz %s\n",
- i, clocks.data[i].clocks_in_khz / 1000,
- (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
+ size += sysfs_emit_at(
+ buf, size, "%d: %uMhz %s\n", i,
+ clocks.data[i].clocks_in_khz / 1000,
+ (clocks.data[i].clocks_in_khz == now * 10) ?
+ "*" :
+ "");
break;
case PP_PCIE:
@@ -3473,40 +3478,45 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
gen_speed = pptable->PcieGenSpeed[i];
lane_width = pptable->PcieLaneCount[i];
- size += sprintf(buf + size, "%d: %s %s %dMhz %s\n", i,
- (gen_speed == 0) ? "2.5GT/s," :
- (gen_speed == 1) ? "5.0GT/s," :
- (gen_speed == 2) ? "8.0GT/s," :
- (gen_speed == 3) ? "16.0GT/s," : "",
- (lane_width == 1) ? "x1" :
- (lane_width == 2) ? "x2" :
- (lane_width == 3) ? "x4" :
- (lane_width == 4) ? "x8" :
- (lane_width == 5) ? "x12" :
- (lane_width == 6) ? "x16" : "",
- pptable->LclkFreq[i],
- (current_gen_speed == gen_speed) &&
- (current_lane_width == lane_width) ?
- "*" : "");
+ size += sysfs_emit_at(
+ buf, size, "%d: %s %s %dMhz %s\n", i,
+ (gen_speed == 0) ? "2.5GT/s," :
+ (gen_speed == 1) ? "5.0GT/s," :
+ (gen_speed == 2) ? "8.0GT/s," :
+ (gen_speed == 3) ? "16.0GT/s," :
+ "",
+ (lane_width == 1) ? "x1" :
+ (lane_width == 2) ? "x2" :
+ (lane_width == 3) ? "x4" :
+ (lane_width == 4) ? "x8" :
+ (lane_width == 5) ? "x12" :
+ (lane_width == 6) ? "x16" :
+ "",
+ pptable->LclkFreq[i],
+ (current_gen_speed == gen_speed) &&
+ (current_lane_width ==
+ lane_width) ?
+ "*" :
+ "");
}
break;
case OD_SCLK:
if (od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id &&
od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id) {
- size += sprintf(buf + size, "%s:\n", "OD_SCLK");
- size += sprintf(buf + size, "0: %10uMhz\n",
- od_table->GfxclkFmin);
- size += sprintf(buf + size, "1: %10uMhz\n",
- od_table->GfxclkFmax);
+ size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK");
+ size += sysfs_emit_at(buf, size, "0: %10uMhz\n",
+ od_table->GfxclkFmin);
+ size += sysfs_emit_at(buf, size, "1: %10uMhz\n",
+ od_table->GfxclkFmax);
}
break;
case OD_MCLK:
if (od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) {
- size += sprintf(buf + size, "%s:\n", "OD_MCLK");
- size += sprintf(buf + size, "1: %10uMhz\n",
- od_table->UclkFmax);
+ size += sysfs_emit_at(buf, size, "%s:\n", "OD_MCLK");
+ size += sysfs_emit_at(buf, size, "1: %10uMhz\n",
+ od_table->UclkFmax);
}
break;
@@ -3518,32 +3528,38 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) {
- size += sprintf(buf + size, "%s:\n", "OD_VDDC_CURVE");
- size += sprintf(buf + size, "0: %10uMhz %10dmV\n",
- od_table->GfxclkFreq1,
- od_table->GfxclkVolt1 / VOLTAGE_SCALE);
- size += sprintf(buf + size, "1: %10uMhz %10dmV\n",
- od_table->GfxclkFreq2,
- od_table->GfxclkVolt2 / VOLTAGE_SCALE);
- size += sprintf(buf + size, "2: %10uMhz %10dmV\n",
- od_table->GfxclkFreq3,
- od_table->GfxclkVolt3 / VOLTAGE_SCALE);
+ size += sysfs_emit_at(buf, size, "%s:\n",
+ "OD_VDDC_CURVE");
+ size += sysfs_emit_at(buf, size, "0: %10uMhz %10dmV\n",
+ od_table->GfxclkFreq1,
+ od_table->GfxclkVolt1 /
+ VOLTAGE_SCALE);
+ size += sysfs_emit_at(buf, size, "1: %10uMhz %10dmV\n",
+ od_table->GfxclkFreq2,
+ od_table->GfxclkVolt2 /
+ VOLTAGE_SCALE);
+ size += sysfs_emit_at(buf, size, "2: %10uMhz %10dmV\n",
+ od_table->GfxclkFreq3,
+ od_table->GfxclkVolt3 /
+ VOLTAGE_SCALE);
}
break;
case OD_RANGE:
- size += sprintf(buf + size, "%s:\n", "OD_RANGE");
+ size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");
if (od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id &&
od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id) {
- size += sprintf(buf + size, "SCLK: %7uMhz %10uMhz\n",
+ size += sysfs_emit_at(
+ buf, size, "SCLK: %7uMhz %10uMhz\n",
od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value,
od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value);
}
if (od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) {
- size += sprintf(buf + size, "MCLK: %7uMhz %10uMhz\n",
+ size += sysfs_emit_at(
+ buf, size, "MCLK: %7uMhz %10uMhz\n",
od8_settings[OD8_SETTING_UCLK_FMAX].min_value,
od8_settings[OD8_SETTING_UCLK_FMAX].max_value);
}
@@ -3554,31 +3570,52 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) {
- size += sprintf(buf + size, "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n",
+ size += sysfs_emit_at(
+ buf, size,
+ "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n",
od8_settings[OD8_SETTING_GFXCLK_FREQ1].min_value,
- od8_settings[OD8_SETTING_GFXCLK_FREQ1].max_value);
- size += sprintf(buf + size, "VDDC_CURVE_VOLT[0]: %7dmV %11dmV\n",
- od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].min_value,
- od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].max_value);
- size += sprintf(buf + size, "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n",
+ od8_settings[OD8_SETTING_GFXCLK_FREQ1]
+ .max_value);
+ size += sysfs_emit_at(
+ buf, size, "VDDC_CURVE_VOLT[0]: %7dmV %11dmV\n",
+ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1]
+ .min_value,
+ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1]
+ .max_value);
+ size += sysfs_emit_at(
+ buf, size,
+ "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n",
od8_settings[OD8_SETTING_GFXCLK_FREQ2].min_value,
- od8_settings[OD8_SETTING_GFXCLK_FREQ2].max_value);
- size += sprintf(buf + size, "VDDC_CURVE_VOLT[1]: %7dmV %11dmV\n",
- od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].min_value,
- od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].max_value);
- size += sprintf(buf + size, "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n",
+ od8_settings[OD8_SETTING_GFXCLK_FREQ2]
+ .max_value);
+ size += sysfs_emit_at(
+ buf, size, "VDDC_CURVE_VOLT[1]: %7dmV %11dmV\n",
+ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2]
+ .min_value,
+ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2]
+ .max_value);
+ size += sysfs_emit_at(
+ buf, size,
+ "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n",
od8_settings[OD8_SETTING_GFXCLK_FREQ3].min_value,
- od8_settings[OD8_SETTING_GFXCLK_FREQ3].max_value);
- size += sprintf(buf + size, "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n",
- od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].min_value,
- od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].max_value);
+ od8_settings[OD8_SETTING_GFXCLK_FREQ3]
+ .max_value);
+ size += sysfs_emit_at(
+ buf, size, "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n",
+ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3]
+ .min_value,
+ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3]
+ .max_value);
}
break;
default:
break;
}
- return size;
+
+ *offset = size;
+
+ return 0;
}
static int vega20_set_uclk_to_highest_dpm_level(struct pp_hwmgr *hwmgr,
@@ -4393,7 +4430,6 @@ static const struct pp_hwmgr_func vega20_hwmgr_funcs = {
/* export to DAL */
.get_sclk = vega20_dpm_get_sclk,
.get_mclk = vega20_dpm_get_mclk,
- .get_dal_power_level = vega20_get_dal_power_level,
.get_clock_by_type_with_latency = vega20_get_clock_by_type_with_latency,
.get_clock_by_type_with_voltage = vega20_get_clock_by_type_with_voltage,
.set_watermarks_for_clocks_ranges = vega20_set_watermarks_for_clocks_ranges,
@@ -4412,7 +4448,7 @@ static const struct pp_hwmgr_func vega20_hwmgr_funcs = {
.odn_edit_dpm_table = vega20_odn_edit_dpm_table,
/* for sysfs to retrive/set gfxclk/memclk */
.force_clock_level = vega20_force_clock_level,
- .print_clock_levels = vega20_print_clock_levels,
+ .emit_clock_levels = vega20_emit_clock_levels,
.read_sensor = vega20_read_sensor,
.get_ppfeature_status = vega20_get_ppfeature_status,
.set_ppfeature_status = vega20_set_ppfeature_status,
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c
index 2b446f8866ba..36cb7aa80d07 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c
@@ -336,7 +336,7 @@ static int vega20_pp_tables_initialize(struct pp_hwmgr *hwmgr)
int result = 0;
const ATOM_Vega20_POWERPLAYTABLE *powerplay_table;
- hwmgr->pptable = kzalloc(sizeof(struct phm_ppt_v3_information), GFP_KERNEL);
+ hwmgr->pptable = kzalloc_obj(struct phm_ppt_v3_information);
PP_ASSERT_WITH_CODE((hwmgr->pptable != NULL),
"Failed to allocate hwmgr->pptable!", return -ENOMEM);
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_thermal.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_thermal.c
index a3331ffb2daf..1b1c88590156 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_thermal.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_thermal.c
@@ -191,7 +191,7 @@ int vega20_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
uint32_t tach_period, crystal_clock_freq;
int result = 0;
- if (!speed)
+ if (!speed || speed > UINT_MAX/8)
return -EINVAL;
if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) {
diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/hardwaremanager.h b/drivers/gpu/drm/amd/pm/powerplay/inc/hardwaremanager.h
index f4f9a104d170..36dcad065fae 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/inc/hardwaremanager.h
+++ b/drivers/gpu/drm/amd/pm/powerplay/inc/hardwaremanager.h
@@ -396,7 +396,6 @@ struct phm_odn_clock_levels {
};
extern int phm_disable_clock_power_gatings(struct pp_hwmgr *hwmgr);
-extern int phm_powerdown_uvd(struct pp_hwmgr *hwmgr);
extern int phm_setup_asic(struct pp_hwmgr *hwmgr);
extern int phm_enable_dynamic_state_management(struct pp_hwmgr *hwmgr);
extern int phm_disable_dynamic_state_management(struct pp_hwmgr *hwmgr);
@@ -427,9 +426,6 @@ extern int phm_check_states_equal(struct pp_hwmgr *hwmgr,
extern int phm_store_dal_configuration_data(struct pp_hwmgr *hwmgr,
const struct amd_pp_display_configuration *display_config);
-extern int phm_get_dal_power_level(struct pp_hwmgr *hwmgr,
- struct amd_pp_simple_clock_info *info);
-
extern int phm_set_cpu_power_state(struct pp_hwmgr *hwmgr);
extern int phm_power_down_asic(struct pp_hwmgr *hwmgr);
diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h
index 227bf0e84a13..ca71efaa1656 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h
+++ b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h
@@ -257,7 +257,6 @@ struct pp_hwmgr_func {
int (*get_pp_table_entry)(struct pp_hwmgr *hwmgr,
unsigned long, struct pp_power_state *);
int (*get_num_of_pp_table_entries)(struct pp_hwmgr *hwmgr);
- int (*powerdown_uvd)(struct pp_hwmgr *hwmgr);
void (*powergate_vce)(struct pp_hwmgr *hwmgr, bool bgate);
void (*powergate_uvd)(struct pp_hwmgr *hwmgr, bool bgate);
void (*powergate_acp)(struct pp_hwmgr *hwmgr, bool bgate);
@@ -293,8 +292,6 @@ struct pp_hwmgr_func {
int (*store_cc6_data)(struct pp_hwmgr *hwmgr, uint32_t separation_time,
bool cc6_disable, bool pstate_disable,
bool pstate_switch_disable);
- int (*get_dal_power_level)(struct pp_hwmgr *hwmgr,
- struct amd_pp_simple_clock_info *info);
int (*get_performance_level)(struct pp_hwmgr *, const struct pp_hw_power_state *,
PHM_PerformanceLevelDesignation, uint32_t, PHM_PerformanceLevel *);
int (*get_current_shallow_sleep_clocks)(struct pp_hwmgr *hwmgr,
@@ -365,6 +362,7 @@ struct pp_hwmgr_func {
bool disable);
ssize_t (*get_gpu_metrics)(struct pp_hwmgr *hwmgr, void **table);
int (*gfx_state_change)(struct pp_hwmgr *hwmgr, uint32_t state);
+ void (*notify_ac_dc)(struct pp_hwmgr *hwmgr);
};
struct pp_table_func {
@@ -541,7 +539,6 @@ struct phm_ppt_v1_information {
struct phm_clock_array *valid_dcefclk_values;
struct phm_clock_and_voltage_limits max_clock_voltage_on_dc;
struct phm_clock_and_voltage_limits max_clock_voltage_on_ac;
- struct phm_clock_voltage_dependency_table *vddc_dep_on_dal_pwrl;
struct phm_ppm_table *ppm_parameter_table;
struct phm_cac_tdp_table *cac_dtp_table;
struct phm_tdp_table *tdp_table;
@@ -632,7 +629,7 @@ struct phm_dynamic_state_info {
struct phm_clock_voltage_dependency_table *vddci_dependency_on_mclk;
struct phm_clock_voltage_dependency_table *vddc_dependency_on_mclk;
struct phm_clock_voltage_dependency_table *mvdd_dependency_on_mclk;
- struct phm_clock_voltage_dependency_table *vddc_dep_on_dal_pwrl;
+ struct phm_clock_voltage_dependency_table *vddc_dependency_on_display_clock;
struct phm_clock_array *valid_sclk_values;
struct phm_clock_array *valid_mclk_values;
struct phm_clock_and_voltage_limits max_clock_voltage_on_dc;
@@ -773,7 +770,6 @@ struct pp_hwmgr {
const struct pp_smumgr_func *smumgr_funcs;
bool is_kicker;
- enum PP_DAL_POWERLEVEL dal_power_level;
struct phm_dynamic_state_info dyn_state;
const struct pp_hwmgr_func *hwmgr_func;
const struct pp_table_func *pptable_func;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c
index ad1fd3150d03..3650e7beeb67 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c
@@ -245,7 +245,7 @@ static void ci_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
smu_data->power_tune_defaults = &defaults_hawaii_pro;
break;
case 0x67B8:
- case 0x66B0:
+ case 0x67B0:
smu_data->power_tune_defaults = &defaults_hawaii_xt;
break;
case 0x6640:
@@ -543,12 +543,11 @@ static int ci_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
{
struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend);
const struct ci_pt_defaults *defaults = smu_data->power_tune_defaults;
- uint32_t temp;
if (ci_read_smc_sram_dword(hwmgr,
fuse_table_offset +
offsetof(SMU7_Discrete_PmFuses, TdcWaterfallCtl),
- (uint32_t *)&temp, SMC_RAM_END))
+ (uint32_t *)&smu_data->power_tune_table.TdcWaterfallCtl, SMC_RAM_END))
PP_ASSERT_WITH_CODE(false,
"Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!",
return -EINVAL);
@@ -1217,7 +1216,7 @@ static int ci_populate_single_memory_level(
}
memory_level->EnabledForThrottle = 1;
- memory_level->EnabledForActivity = 1;
+ memory_level->EnabledForActivity = 0;
memory_level->UpH = data->current_profile_setting.mclk_up_hyst;
memory_level->DownH = data->current_profile_setting.mclk_down_hyst;
memory_level->VoltageDownH = 0;
@@ -1322,16 +1321,25 @@ static int ci_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
return result;
}
+ if (data->mclk_dpm_key_disabled && dpm_table->mclk_table.count) {
+ /* Populate the table with the highest MCLK level when MCLK DPM is disabled */
+ for (i = 0; i < dpm_table->mclk_table.count - 1; i++) {
+ levels[i] = levels[dpm_table->mclk_table.count - 1];
+ levels[i].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH;
+ }
+ }
+
smu_data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1;
dev_id = adev->pdev->device;
- if ((dpm_table->mclk_table.count >= 2)
- && ((dev_id == 0x67B0) || (dev_id == 0x67B1))) {
- smu_data->smc_state_table.MemoryLevel[1].MinVddci =
- smu_data->smc_state_table.MemoryLevel[0].MinVddci;
- smu_data->smc_state_table.MemoryLevel[1].MinMvdd =
- smu_data->smc_state_table.MemoryLevel[0].MinMvdd;
+ if ((dpm_table->mclk_table.count >= 2) &&
+ ((dev_id == 0x67B0) || (dev_id == 0x67B1)) &&
+ (adev->pdev->revision == 0)) {
+ smu_data->smc_state_table.MemoryLevel[1].MinVddc =
+ smu_data->smc_state_table.MemoryLevel[0].MinVddc;
+ smu_data->smc_state_table.MemoryLevel[1].MinVddcPhases =
+ smu_data->smc_state_table.MemoryLevel[0].MinVddcPhases;
}
smu_data->smc_state_table.MemoryLevel[0].ActivityLevel = 0x1F;
CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.MemoryLevel[0].ActivityLevel);
@@ -2681,7 +2689,7 @@ static int ci_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
struct ci_mc_reg_table *ni_table = &smu_data->mc_reg_table;
uint8_t module_index = ci_get_memory_modile_index(hwmgr);
- table = kzalloc(sizeof(pp_atomctrl_mc_reg_table), GFP_KERNEL);
+ table = kzalloc_obj(pp_atomctrl_mc_reg_table);
if (NULL == table)
return -ENOMEM;
@@ -2735,7 +2743,7 @@ static int ci_smu_init(struct pp_hwmgr *hwmgr)
{
struct ci_smumgr *ci_priv;
- ci_priv = kzalloc(sizeof(struct ci_smumgr), GFP_KERNEL);
+ ci_priv = kzalloc_obj(struct ci_smumgr);
if (ci_priv == NULL)
return -ENOMEM;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/fiji_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/fiji_smumgr.c
index 5e43ad2b2956..7cf389e4717e 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/fiji_smumgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/fiji_smumgr.c
@@ -334,7 +334,7 @@ static int fiji_smu_init(struct pp_hwmgr *hwmgr)
{
struct fiji_smumgr *fiji_priv;
- fiji_priv = kzalloc(sizeof(struct fiji_smumgr), GFP_KERNEL);
+ fiji_priv = kzalloc_obj(struct fiji_smumgr);
if (fiji_priv == NULL)
return -ENOMEM;
@@ -2024,7 +2024,7 @@ static int fiji_init_smc_table(struct pp_hwmgr *hwmgr)
table->VoltageResponseTime = 0;
table->PhaseResponseTime = 0;
table->MemoryThermThrottleEnable = 1;
- table->PCIeBootLinkLevel = 0; /* 0:Gen1 1:Gen2 2:Gen3*/
+ table->PCIeBootLinkLevel = (uint8_t) (data->dpm_table.pcie_speed_table.count);
table->PCIeGenInterval = 1;
table->VRConfig = 0;
@@ -2540,9 +2540,8 @@ static int fiji_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
static bool fiji_is_dpm_running(struct pp_hwmgr *hwmgr)
{
- return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device,
- CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON))
- ? true : false;
+ return PHM_READ_INDIRECT_FIELD(hwmgr->device,
+ CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON) == 1;
}
static int fiji_update_dpm_settings(struct pp_hwmgr *hwmgr,
diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.c
index 17d2f5bff4a7..8f1bcbb482b5 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.c
@@ -261,7 +261,7 @@ static int iceland_smu_init(struct pp_hwmgr *hwmgr)
{
struct iceland_smumgr *iceland_priv;
- iceland_priv = kzalloc(sizeof(struct iceland_smumgr), GFP_KERNEL);
+ iceland_priv = kzalloc_obj(struct iceland_smumgr);
if (iceland_priv == NULL)
return -ENOMEM;
@@ -2028,7 +2028,7 @@ static int iceland_init_smc_table(struct pp_hwmgr *hwmgr)
table->VoltageResponseTime = 0;
table->PhaseResponseTime = 0;
table->MemoryThermThrottleEnable = 1;
- table->PCIeBootLinkLevel = 0;
+ table->PCIeBootLinkLevel = (uint8_t) (data->dpm_table.pcie_speed_table.count);
table->PCIeGenInterval = 1;
result = iceland_populate_smc_svi2_config(hwmgr, table);
@@ -2608,7 +2608,7 @@ static int iceland_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
struct iceland_mc_reg_table *ni_table = &smu_data->mc_reg_table;
uint8_t module_index = iceland_get_memory_modile_index(hwmgr);
- table = kzalloc(sizeof(pp_atomctrl_mc_reg_table), GFP_KERNEL);
+ table = kzalloc_obj(pp_atomctrl_mc_reg_table);
if (NULL == table)
return -ENOMEM;
@@ -2655,9 +2655,8 @@ static int iceland_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
static bool iceland_is_dpm_running(struct pp_hwmgr *hwmgr)
{
- return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device,
- CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON))
- ? true : false;
+ return PHM_READ_INDIRECT_FIELD(hwmgr->device,
+ CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON) == 1;
}
const struct pp_smumgr_func iceland_smu_funcs = {
diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/polaris10_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/polaris10_smumgr.c
index ff6b563ecbf5..e59b87238e76 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/polaris10_smumgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/polaris10_smumgr.c
@@ -336,7 +336,7 @@ static int polaris10_smu_init(struct pp_hwmgr *hwmgr)
{
struct polaris10_smumgr *smu_data;
- smu_data = kzalloc(sizeof(struct polaris10_smumgr), GFP_KERNEL);
+ smu_data = kzalloc_obj(struct polaris10_smumgr);
if (smu_data == NULL)
return -ENOMEM;
@@ -2578,9 +2578,8 @@ static int polaris10_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
static bool polaris10_is_dpm_running(struct pp_hwmgr *hwmgr)
{
- return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device,
- CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON))
- ? true : false;
+ return PHM_READ_INDIRECT_FIELD(hwmgr->device,
+ CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON) == 1;
}
static int polaris10_update_dpm_settings(struct pp_hwmgr *hwmgr,
diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu10_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu10_smumgr.c
index ac9ec8257f82..c9fdca88c96a 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu10_smumgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu10_smumgr.c
@@ -139,7 +139,7 @@ static int smu10_copy_table_from_smc(struct pp_hwmgr *hwmgr,
priv->smu_tables.entry[table_id].table_id,
NULL);
- amdgpu_asic_invalidate_hdp(adev, NULL);
+ amdgpu_hdp_invalidate(adev, NULL);
memcpy(table, (uint8_t *)priv->smu_tables.entry[table_id].table,
priv->smu_tables.entry[table_id].size);
@@ -164,7 +164,7 @@ static int smu10_copy_table_to_smc(struct pp_hwmgr *hwmgr,
memcpy(priv->smu_tables.entry[table_id].table, table,
priv->smu_tables.entry[table_id].size);
- amdgpu_asic_flush_hdp(adev, NULL);
+ amdgpu_hdp_flush(adev, NULL);
smum_send_msg_to_smc_with_parameter(hwmgr,
PPSMC_MSG_SetDriverDramAddrHigh,
@@ -244,7 +244,7 @@ static int smu10_smu_init(struct pp_hwmgr *hwmgr)
struct smu10_smumgr *priv;
int r;
- priv = kzalloc(sizeof(struct smu10_smumgr), GFP_KERNEL);
+ priv = kzalloc_obj(struct smu10_smumgr);
if (!priv)
return -ENOMEM;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.c
index 5a010cd38303..3e0068a6aeb2 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.c
@@ -46,42 +46,6 @@ static int smu7_set_smc_sram_address(struct pp_hwmgr *hwmgr, uint32_t smc_addr,
}
-int smu7_copy_bytes_from_smc(struct pp_hwmgr *hwmgr, uint32_t smc_start_address, uint32_t *dest, uint32_t byte_count, uint32_t limit)
-{
- uint32_t data;
- uint32_t addr;
- uint8_t *dest_byte;
- uint8_t i, data_byte[4] = {0};
- uint32_t *pdata = (uint32_t *)&data_byte;
-
- PP_ASSERT_WITH_CODE((0 == (3 & smc_start_address)), "SMC address must be 4 byte aligned.", return -EINVAL);
- PP_ASSERT_WITH_CODE((limit > (smc_start_address + byte_count)), "SMC address is beyond the SMC RAM area.", return -EINVAL);
-
- addr = smc_start_address;
-
- while (byte_count >= 4) {
- smu7_read_smc_sram_dword(hwmgr, addr, &data, limit);
-
- *dest = PP_SMC_TO_HOST_UL(data);
-
- dest += 1;
- byte_count -= 4;
- addr += 4;
- }
-
- if (byte_count) {
- smu7_read_smc_sram_dword(hwmgr, addr, &data, limit);
- *pdata = PP_SMC_TO_HOST_UL(data);
- /* Cast dest into byte type in dest_byte. This way, we don't overflow if the allocated memory is not 4-byte aligned. */
- dest_byte = (uint8_t *)dest;
- for (i = 0; i < byte_count; i++)
- dest_byte[i] = data_byte[i];
- }
-
- return 0;
-}
-
-
int smu7_copy_bytes_to_smc(struct pp_hwmgr *hwmgr, uint32_t smc_start_address,
const uint8_t *src, uint32_t byte_count, uint32_t limit)
{
@@ -369,7 +333,7 @@ int smu7_request_smu_load_fw(struct pp_hwmgr *hwmgr)
if (!smu_data->toc) {
struct SMU_DRAMData_TOC *toc;
- smu_data->toc = kzalloc(sizeof(struct SMU_DRAMData_TOC), GFP_KERNEL);
+ smu_data->toc = kzalloc_obj(struct SMU_DRAMData_TOC);
if (!smu_data->toc)
return -ENOMEM;
toc = smu_data->toc;
@@ -437,7 +401,7 @@ failed:
int smu7_check_fw_load_finish(struct pp_hwmgr *hwmgr, uint32_t fw_type)
{
struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend);
- uint32_t ret;
+ int ret;
ret = phm_wait_on_indirect_register(hwmgr, mmSMC_IND_INDEX_11,
smu_data->soft_regs_start + smum_get_offsetof(hwmgr,
diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.h b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.h
index e7303dc8c260..63e428ceaee4 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.h
+++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.h
@@ -53,8 +53,6 @@ struct smu7_smumgr {
};
-int smu7_copy_bytes_from_smc(struct pp_hwmgr *hwmgr, uint32_t smc_start_address,
- uint32_t *dest, uint32_t byte_count, uint32_t limit);
int smu7_copy_bytes_to_smc(struct pp_hwmgr *hwmgr, uint32_t smc_start_address,
const uint8_t *src, uint32_t byte_count, uint32_t limit);
int smu7_program_jump_on_start(struct pp_hwmgr *hwmgr);
diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu8_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu8_smumgr.c
index 76d4f12ceedf..f3f2b8fe8d63 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu8_smumgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu8_smumgr.c
@@ -758,7 +758,7 @@ static int smu8_smu_init(struct pp_hwmgr *hwmgr)
int ret = 0;
struct smu8_smumgr *smu8_smu;
- smu8_smu = kzalloc(sizeof(struct smu8_smumgr), GFP_KERNEL);
+ smu8_smu = kzalloc_obj(struct smu8_smumgr);
if (smu8_smu == NULL)
return -ENOMEM;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/tonga_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/tonga_smumgr.c
index 6fe6e6abb5d8..28fe988c2262 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/tonga_smumgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/tonga_smumgr.c
@@ -228,7 +228,7 @@ static int tonga_smu_init(struct pp_hwmgr *hwmgr)
{
struct tonga_smumgr *tonga_priv;
- tonga_priv = kzalloc(sizeof(struct tonga_smumgr), GFP_KERNEL);
+ tonga_priv = kzalloc_obj(struct tonga_smumgr);
if (tonga_priv == NULL)
return -ENOMEM;
@@ -3072,7 +3072,7 @@ static int tonga_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
struct tonga_mc_reg_table *ni_table = &smu_data->mc_reg_table;
uint8_t module_index = tonga_get_memory_modile_index(hwmgr);
- table = kzalloc(sizeof(pp_atomctrl_mc_reg_table), GFP_KERNEL);
+ table = kzalloc_obj(pp_atomctrl_mc_reg_table);
if (table == NULL)
return -ENOMEM;
@@ -3139,9 +3139,8 @@ static int tonga_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
static bool tonga_is_dpm_running(struct pp_hwmgr *hwmgr)
{
- return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device,
- CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON))
- ? true : false;
+ return PHM_READ_INDIRECT_FIELD(hwmgr->device,
+ CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON) == 1;
}
static int tonga_update_dpm_settings(struct pp_hwmgr *hwmgr,
diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega10_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega10_smumgr.c
index f9c0f117725d..39192adf441f 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega10_smumgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega10_smumgr.c
@@ -60,7 +60,7 @@ static int vega10_copy_table_from_smc(struct pp_hwmgr *hwmgr,
priv->smu_tables.entry[table_id].table_id,
NULL);
- amdgpu_asic_invalidate_hdp(adev, NULL);
+ amdgpu_hdp_invalidate(adev, NULL);
memcpy(table, priv->smu_tables.entry[table_id].table,
priv->smu_tables.entry[table_id].size);
@@ -90,7 +90,7 @@ static int vega10_copy_table_to_smc(struct pp_hwmgr *hwmgr,
memcpy(priv->smu_tables.entry[table_id].table, table,
priv->smu_tables.entry[table_id].size);
- amdgpu_asic_flush_hdp(adev, NULL);
+ amdgpu_hdp_flush(adev, NULL);
smum_send_msg_to_smc_with_parameter(hwmgr,
PPSMC_MSG_SetDriverDramAddrHigh,
@@ -218,7 +218,7 @@ static int vega10_smu_init(struct pp_hwmgr *hwmgr)
if (ret || !info.kptr)
return -EINVAL;
- priv = kzalloc(sizeof(struct vega10_smumgr), GFP_KERNEL);
+ priv = kzalloc_obj(struct vega10_smumgr);
if (!priv)
return -ENOMEM;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega12_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega12_smumgr.c
index d3ff6a831ed5..99db4cf8e11d 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega12_smumgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega12_smumgr.c
@@ -68,7 +68,7 @@ static int vega12_copy_table_from_smc(struct pp_hwmgr *hwmgr,
"[CopyTableFromSMC] Attempt to Transfer Table From SMU Failed!",
return -EINVAL);
- amdgpu_asic_invalidate_hdp(adev, NULL);
+ amdgpu_hdp_invalidate(adev, NULL);
memcpy(table, priv->smu_tables.entry[table_id].table,
priv->smu_tables.entry[table_id].size);
@@ -98,7 +98,7 @@ static int vega12_copy_table_to_smc(struct pp_hwmgr *hwmgr,
memcpy(priv->smu_tables.entry[table_id].table, table,
priv->smu_tables.entry[table_id].size);
- amdgpu_asic_flush_hdp(adev, NULL);
+ amdgpu_hdp_flush(adev, NULL);
PP_ASSERT_WITH_CODE(smum_send_msg_to_smc_with_parameter(hwmgr,
PPSMC_MSG_SetDriverDramAddrHigh,
@@ -221,7 +221,7 @@ static int vega12_smu_init(struct pp_hwmgr *hwmgr)
if (ret || !info.kptr)
return -EINVAL;
- priv = kzalloc(sizeof(struct vega12_smumgr), GFP_KERNEL);
+ priv = kzalloc_obj(struct vega12_smumgr);
if (!priv)
return -ENOMEM;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega20_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega20_smumgr.c
index a5c95b180672..b982c03f9e9a 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega20_smumgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega20_smumgr.c
@@ -192,7 +192,7 @@ static int vega20_copy_table_from_smc(struct pp_hwmgr *hwmgr,
"[CopyTableFromSMC] Attempt to Transfer Table From SMU Failed!",
return ret);
- amdgpu_asic_invalidate_hdp(adev, NULL);
+ amdgpu_hdp_invalidate(adev, NULL);
memcpy(table, priv->smu_tables.entry[table_id].table,
priv->smu_tables.entry[table_id].size);
@@ -223,7 +223,7 @@ static int vega20_copy_table_to_smc(struct pp_hwmgr *hwmgr,
memcpy(priv->smu_tables.entry[table_id].table, table,
priv->smu_tables.entry[table_id].size);
- amdgpu_asic_flush_hdp(adev, NULL);
+ amdgpu_hdp_flush(adev, NULL);
PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(hwmgr,
PPSMC_MSG_SetDriverDramAddrHigh,
@@ -256,7 +256,7 @@ int vega20_set_activity_monitor_coeff(struct pp_hwmgr *hwmgr,
memcpy(priv->smu_tables.entry[TABLE_ACTIVITY_MONITOR_COEFF].table, table,
priv->smu_tables.entry[TABLE_ACTIVITY_MONITOR_COEFF].size);
- amdgpu_asic_flush_hdp(adev, NULL);
+ amdgpu_hdp_flush(adev, NULL);
PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(hwmgr,
PPSMC_MSG_SetDriverDramAddrHigh,
@@ -306,7 +306,7 @@ int vega20_get_activity_monitor_coeff(struct pp_hwmgr *hwmgr,
"[GetActivityMonitor] Attempt to Transfer Table From SMU Failed!",
return ret);
- amdgpu_asic_invalidate_hdp(adev, NULL);
+ amdgpu_hdp_invalidate(adev, NULL);
memcpy(table, priv->smu_tables.entry[TABLE_ACTIVITY_MONITOR_COEFF].table,
priv->smu_tables.entry[TABLE_ACTIVITY_MONITOR_COEFF].size);
@@ -430,7 +430,7 @@ static int vega20_smu_init(struct pp_hwmgr *hwmgr)
if (ret || !info.kptr)
return -EINVAL;
- priv = kzalloc(sizeof(struct vega20_smumgr), GFP_KERNEL);
+ priv = kzalloc_obj(struct vega20_smumgr);
if (!priv)
return -ENOMEM;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/vegam_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vegam_smumgr.c
index 34c9f59b889a..cca6693853ec 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/vegam_smumgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vegam_smumgr.c
@@ -83,7 +83,7 @@ static int vegam_smu_init(struct pp_hwmgr *hwmgr)
{
struct vegam_smumgr *smu_data;
- smu_data = kzalloc(sizeof(struct vegam_smumgr), GFP_KERNEL);
+ smu_data = kzalloc_obj(struct vegam_smumgr);
if (smu_data == NULL)
return -ENOMEM;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/Makefile b/drivers/gpu/drm/amd/pm/swsmu/Makefile
index e5fdda49c96c..178b102a8845 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/Makefile
+++ b/drivers/gpu/drm/amd/pm/swsmu/Makefile
@@ -22,7 +22,7 @@
AMD_SWSMU_PATH = ../pm/swsmu
-SWSMU_LIBS = smu11 smu12 smu13 smu14
+SWSMU_LIBS = smu11 smu12 smu13 smu14 smu15
AMD_SWSMU = $(addsuffix /Makefile,$(addprefix $(FULL_AMD_PATH)/pm/swsmu/,$(SWSMU_LIBS)))
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index ed9dac00ebfb..762ec3cede96 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -46,6 +46,8 @@
#include "smu_v13_0_7_ppt.h"
#include "smu_v14_0_0_ppt.h"
#include "smu_v14_0_2_ppt.h"
+#include "smu_v15_0_0_ppt.h"
+#include "smu_v15_0_8_ppt.h"
#include "amd_pcie.h"
/*
@@ -68,7 +70,7 @@ static int smu_handle_task(struct smu_context *smu,
static int smu_reset(struct smu_context *smu);
static int smu_set_fan_speed_pwm(void *handle, u32 speed);
static int smu_set_fan_control_mode(void *handle, u32 value);
-static int smu_set_power_limit(void *handle, uint32_t limit);
+static int smu_set_power_limit(void *handle, uint32_t limit_type, uint32_t limit);
static int smu_set_fan_speed_rpm(void *handle, uint32_t speed);
static int smu_set_gfx_cgpg(struct smu_context *smu, bool enabled);
static int smu_set_mp1_state(void *handle, enum pp_mp1_state mp1_state);
@@ -76,6 +78,10 @@ static void smu_power_profile_mode_get(struct smu_context *smu,
enum PP_SMC_POWER_PROFILE profile_mode);
static void smu_power_profile_mode_put(struct smu_context *smu,
enum PP_SMC_POWER_PROFILE profile_mode);
+static enum smu_clk_type smu_convert_to_smuclk(enum pp_clock_type type);
+static int smu_od_edit_dpm_table(void *handle,
+ enum PP_OD_DPM_TABLE_COMMAND type,
+ long *input, uint32_t size);
static int smu_sys_get_pp_feature_mask(void *handle,
char *buf)
@@ -134,12 +140,17 @@ int smu_get_status_gfxoff(struct smu_context *smu, uint32_t *value)
}
int smu_set_soft_freq_range(struct smu_context *smu,
- enum smu_clk_type clk_type,
+ enum pp_clock_type type,
uint32_t min,
uint32_t max)
{
+ enum smu_clk_type clk_type;
int ret = 0;
+ clk_type = smu_convert_to_smuclk(type);
+ if (clk_type == SMU_CLK_COUNT)
+ return -EINVAL;
+
if (smu->ppt_funcs->set_soft_freq_limited_range)
ret = smu->ppt_funcs->set_soft_freq_limited_range(smu,
clk_type,
@@ -307,6 +318,26 @@ static int smu_dpm_set_vpe_enable(struct smu_context *smu,
return ret;
}
+static int smu_dpm_set_isp_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;
+
+ if (!smu->ppt_funcs->dpm_set_isp_enable)
+ return 0;
+
+ if (atomic_read(&power_gate->isp_gated) ^ enable)
+ return 0;
+
+ ret = smu->ppt_funcs->dpm_set_isp_enable(smu, enable);
+ if (!ret)
+ atomic_set(&power_gate->isp_gated, !enable);
+
+ return ret;
+}
+
static int smu_dpm_set_umsch_mm_enable(struct smu_context *smu,
bool enable)
{
@@ -408,6 +439,12 @@ static int smu_dpm_set_power_gate(void *handle,
dev_err(smu->adev->dev, "Failed to power %s VPE!\n",
gate ? "gate" : "ungate");
break;
+ case AMD_IP_BLOCK_TYPE_ISP:
+ ret = smu_dpm_set_isp_enable(smu, !gate);
+ if (ret)
+ dev_err(smu->adev->dev, "Failed to power %s ISP!\n",
+ gate ? "gate" : "ungate");
+ break;
default:
dev_err(smu->adev->dev, "Unsupported block type!\n");
return -EINVAL;
@@ -473,11 +510,14 @@ static void smu_restore_dpm_user_profile(struct smu_context *smu)
/* Enable restore flag */
smu->user_dpm_profile.flags |= SMU_DPM_USER_PROFILE_RESTORE;
- /* set the user dpm power limit */
- if (smu->user_dpm_profile.power_limit) {
- ret = smu_set_power_limit(smu, smu->user_dpm_profile.power_limit);
+ /* set the user dpm power limits */
+ for (int i = SMU_DEFAULT_PPT_LIMIT; i < SMU_LIMIT_TYPE_COUNT; i++) {
+ if (!smu->user_dpm_profile.power_limits[i])
+ continue;
+ ret = smu_set_power_limit(smu, i,
+ smu->user_dpm_profile.power_limits[i]);
if (ret)
- dev_err(smu->adev->dev, "Failed to set power limit value\n");
+ dev_err(smu->adev->dev, "Failed to set %d power limit value\n", i);
}
/* set the user dpm clock configurations */
@@ -574,6 +614,32 @@ bool is_support_cclk_dpm(struct amdgpu_device *adev)
return true;
}
+int amdgpu_smu_ras_send_msg(struct amdgpu_device *adev, enum smu_message_type msg,
+ uint32_t param, uint32_t *read_arg)
+{
+ struct smu_context *smu = adev->powerplay.pp_handle;
+ int ret = -EOPNOTSUPP;
+
+ if (!smu)
+ return ret;
+
+ if (smu->ppt_funcs && smu->ppt_funcs->ras_send_msg)
+ ret = smu->ppt_funcs->ras_send_msg(smu, msg, param, read_arg);
+
+ return ret;
+}
+
+int amdgpu_smu_ras_feature_is_enabled(struct amdgpu_device *adev,
+ enum smu_feature_mask mask)
+{
+ struct smu_context *smu = adev->powerplay.pp_handle;
+ int ret = 0;
+
+ if (smu->ppt_funcs && smu->ppt_funcs->feature_is_enabled)
+ ret = smu->ppt_funcs->feature_is_enabled(smu, mask);
+
+ return ret;
+}
static int smu_sys_get_pp_table(void *handle,
char **table)
@@ -585,7 +651,7 @@ static int smu_sys_get_pp_table(void *handle,
return -EOPNOTSUPP;
if (!smu_table->power_play_table && !smu_table->hardcode_pptable)
- return -EINVAL;
+ return -EOPNOTSUPP;
if (smu_table->hardcode_pptable)
*table = smu_table->hardcode_pptable;
@@ -638,12 +704,8 @@ static int smu_sys_set_pp_table(void *handle,
return ret;
}
-static int smu_get_driver_allowed_feature_mask(struct smu_context *smu)
+static int smu_init_driver_allowed_feature_mask(struct smu_context *smu)
{
- struct smu_feature *feature = &smu->smu_feature;
- uint32_t allowed_feature_mask[SMU_FEATURE_MAX/32];
- int ret = 0;
-
/*
* With SCPM enabled, the allowed featuremasks setting(via
* PPSMC_MSG_SetAllowedFeaturesMaskLow/High) is not permitted.
@@ -652,22 +714,13 @@ static int smu_get_driver_allowed_feature_mask(struct smu_context *smu)
* such scenario.
*/
if (smu->adev->scpm_enabled) {
- bitmap_fill(feature->allowed, SMU_FEATURE_MAX);
+ smu_feature_list_set_all(smu, SMU_FEATURE_LIST_ALLOWED);
return 0;
}
- bitmap_zero(feature->allowed, SMU_FEATURE_MAX);
-
- ret = smu_get_allowed_feature_mask(smu, allowed_feature_mask,
- SMU_FEATURE_MAX/32);
- if (ret)
- return ret;
-
- bitmap_or(feature->allowed, feature->allowed,
- (unsigned long *)allowed_feature_mask,
- feature->feature_num);
+ smu_feature_list_clear_all(smu, SMU_FEATURE_LIST_ALLOWED);
- return ret;
+ return smu_init_allowed_features(smu);
}
static int smu_set_funcs(struct amdgpu_device *adev)
@@ -694,6 +747,7 @@ static int smu_set_funcs(struct amdgpu_device *adev)
renoir_set_ppt_funcs(smu);
break;
case IP_VERSION(11, 5, 0):
+ case IP_VERSION(11, 5, 2):
vangogh_set_ppt_funcs(smu);
break;
case IP_VERSION(13, 0, 1):
@@ -739,12 +793,22 @@ static int smu_set_funcs(struct amdgpu_device *adev)
case IP_VERSION(14, 0, 0):
case IP_VERSION(14, 0, 1):
case IP_VERSION(14, 0, 4):
+ case IP_VERSION(14, 0, 5):
smu_v14_0_0_set_ppt_funcs(smu);
break;
case IP_VERSION(14, 0, 2):
case IP_VERSION(14, 0, 3):
smu_v14_0_2_set_ppt_funcs(smu);
break;
+ case IP_VERSION(15, 0, 0):
+ case IP_VERSION(15, 0, 5):
+ case IP_VERSION(15, 0, 9):
+ smu_v15_0_0_set_ppt_funcs(smu);
+ break;
+ case IP_VERSION(15, 0, 8):
+ smu_v15_0_8_set_ppt_funcs(smu);
+ smu->od_enabled = true;
+ break;
default:
return -EINVAL;
}
@@ -758,21 +822,19 @@ static int smu_early_init(struct amdgpu_ip_block *ip_block)
struct smu_context *smu;
int r;
- smu = kzalloc(sizeof(struct smu_context), GFP_KERNEL);
+ smu = kzalloc_obj(struct smu_context);
if (!smu)
return -ENOMEM;
smu->adev = adev;
smu->pm_enabled = !!amdgpu_dpm;
smu->is_apu = false;
- smu->smu_baco.state = SMU_BACO_STATE_NONE;
+ smu->smu_baco.state = SMU_BACO_STATE_EXIT;
smu->smu_baco.platform_support = false;
smu->smu_baco.maco_support = false;
smu->user_dpm_profile.fan_mode = -1;
smu->power_profile_mode = PP_SMC_POWER_PROFILE_UNKNOWN;
- mutex_init(&smu->message_lock);
-
adev->powerplay.pp_handle = smu;
adev->powerplay.pp_funcs = &swsmu_pm_funcs;
@@ -1002,6 +1064,21 @@ static int smu_fini_fb_allocations(struct smu_context *smu)
return 0;
}
+static void smu_update_gpu_addresses(struct smu_context *smu)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_table *pm_status_table = smu_table->tables + SMU_TABLE_PMSTATUSLOG;
+ struct smu_table *driver_table = &(smu_table->driver_table);
+ struct smu_table *dummy_read_1_table = &smu_table->dummy_read_1_table;
+
+ if (pm_status_table->bo)
+ pm_status_table->mc_address = amdgpu_bo_fb_aper_addr(pm_status_table->bo);
+ if (driver_table->bo)
+ driver_table->mc_address = amdgpu_bo_fb_aper_addr(driver_table->bo);
+ if (dummy_read_1_table->bo)
+ dummy_read_1_table->mc_address = amdgpu_bo_fb_aper_addr(dummy_read_1_table->bo);
+}
+
/**
* smu_alloc_memory_pool - allocate memory pool in the system memory
*
@@ -1025,7 +1102,10 @@ static int smu_alloc_memory_pool(struct smu_context *smu)
memory_pool->size = pool_size;
memory_pool->align = PAGE_SIZE;
- memory_pool->domain = AMDGPU_GEM_DOMAIN_GTT;
+ memory_pool->domain =
+ (adev->pm.smu_debug_mask & SMU_DEBUG_POOL_USE_VRAM) ?
+ AMDGPU_GEM_DOMAIN_VRAM :
+ AMDGPU_GEM_DOMAIN_GTT;
switch (pool_size) {
case SMU_MEMORY_POOL_SIZE_256_MB:
@@ -1252,27 +1332,39 @@ static void smu_init_xgmi_plpd_mode(struct smu_context *smu)
}
}
-static bool smu_is_workload_profile_available(struct smu_context *smu,
- u32 profile)
+static void smu_init_power_profile(struct smu_context *smu)
+{
+ if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_UNKNOWN)
+ smu->power_profile_mode =
+ PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
+ smu_power_profile_mode_get(smu, smu->power_profile_mode);
+}
+
+void smu_feature_cap_set(struct smu_context *smu, enum smu_feature_cap_id fea_id)
+{
+ struct smu_feature_cap *fea_cap = &smu->fea_cap;
+
+ if (fea_id >= SMU_FEATURE_CAP_ID__COUNT)
+ return;
+
+ set_bit(fea_id, fea_cap->cap_map);
+}
+
+bool smu_feature_cap_test(struct smu_context *smu, enum smu_feature_cap_id fea_id)
{
- if (profile >= PP_SMC_POWER_PROFILE_COUNT)
+ struct smu_feature_cap *fea_cap = &smu->fea_cap;
+
+ if (fea_id >= SMU_FEATURE_CAP_ID__COUNT)
return false;
- return smu->workload_map && smu->workload_map[profile].valid_mapping;
+
+ return test_bit(fea_id, fea_cap->cap_map);
}
-static void smu_init_power_profile(struct smu_context *smu)
+static void smu_feature_cap_init(struct smu_context *smu)
{
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_UNKNOWN) {
- if (smu->is_apu ||
- !smu_is_workload_profile_available(
- smu, PP_SMC_POWER_PROFILE_FULLSCREEN3D))
- smu->power_profile_mode =
- PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
- else
- smu->power_profile_mode =
- PP_SMC_POWER_PROFILE_FULLSCREEN3D;
- }
- smu_power_profile_mode_get(smu, smu->power_profile_mode);
+ struct smu_feature_cap *fea_cap = &smu->fea_cap;
+
+ bitmap_zero(fea_cap->cap_map, SMU_FEATURE_CAP_ID__COUNT);
}
static int smu_sw_init(struct amdgpu_ip_block *ip_block)
@@ -1282,9 +1374,7 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
int i, ret;
smu->pool_size = adev->pm.smu_prv_buffer_size;
- smu->smu_feature.feature_num = SMU_FEATURE_MAX;
- bitmap_zero(smu->smu_feature.supported, SMU_FEATURE_MAX);
- bitmap_zero(smu->smu_feature.allowed, SMU_FEATURE_MAX);
+ smu_feature_init(smu, SMU_FEATURE_NUM_DEFAULT);
INIT_WORK(&smu->throttling_logging_work, smu_throttling_logging_work_fn);
INIT_WORK(&smu->interrupt_work, smu_interrupt_work_fn);
@@ -1295,6 +1385,7 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 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.isp_gated, 1);
atomic_set(&smu->smu_power.power_gate.umsch_mm_gated, 1);
smu_init_power_profile(smu);
@@ -1306,6 +1397,8 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
INIT_DELAYED_WORK(&smu->swctf_delayed_work,
smu_swctf_delayed_work_handler);
+ smu_feature_cap_init(smu);
+
ret = smu_smc_table_sw_init(smu);
if (ret) {
dev_err(adev->dev, "Failed to sw init smc table!\n");
@@ -1570,23 +1663,26 @@ static void smu_wbrf_fini(struct smu_context *smu)
static int smu_smc_hw_setup(struct smu_context *smu)
{
- struct smu_feature *feature = &smu->smu_feature;
struct amdgpu_device *adev = smu->adev;
uint8_t pcie_gen = 0, pcie_width = 0;
- uint64_t features_supported;
+ struct smu_feature_bits features_supported;
int ret = 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):
+ case IP_VERSION(11, 5, 2):
case IP_VERSION(11, 0, 12):
if (adev->in_suspend && smu_is_dpm_running(smu)) {
dev_info(adev->dev, "dpm has been enabled\n");
ret = smu_system_features_control(smu, true);
- if (ret)
+ if (ret) {
dev_err(adev->dev, "Failed system features control!\n");
- return ret;
+ return ret;
+ }
+
+ return smu_enable_thermal_alert(smu);
}
break;
default:
@@ -1681,37 +1777,6 @@ static int smu_smc_hw_setup(struct smu_context *smu)
}
}
- ret = smu_system_features_control(smu, true);
- if (ret) {
- dev_err(adev->dev, "Failed to enable requested dpm features!\n");
- 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");
- return ret;
- }
- bitmap_copy(feature->supported,
- (unsigned long *)&features_supported,
- feature->feature_num);
-
- if (!smu_is_dpm_running(smu))
- dev_info(adev->dev, "dpm has been disabled\n");
-
- /*
- * Set initialized values (get from vbios) to dpm tables context such as
- * gfxclk, memclk, dcefclk, and etc. And enable the DPM feature for each
- * type of clks.
- */
- ret = smu_set_default_dpm_table(smu);
- if (ret) {
- dev_err(adev->dev, "Failed to setup default dpm clock tables!\n");
- return ret;
- }
-
if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN5)
pcie_gen = 4;
else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4)
@@ -1747,6 +1812,36 @@ static int smu_smc_hw_setup(struct smu_context *smu)
return ret;
}
+ ret = smu_system_features_control(smu, true);
+ if (ret) {
+ dev_err(adev->dev, "Failed to enable requested dpm features!\n");
+ 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");
+ return ret;
+ }
+ smu_feature_list_set_bits(smu, SMU_FEATURE_LIST_SUPPORTED,
+ features_supported.bits);
+
+ if (!smu_is_dpm_running(smu))
+ dev_info(adev->dev, "dpm has been disabled\n");
+
+ /*
+ * Set initialized values (get from vbios) to dpm tables context such as
+ * gfxclk, memclk, dcefclk, and etc. And enable the DPM feature for each
+ * type of clks.
+ */
+ ret = smu_set_default_dpm_table(smu);
+ if (ret) {
+ dev_err(adev->dev, "Failed to setup default dpm clock tables!\n");
+ return ret;
+ }
+
ret = smu_get_thermal_temperature_range(smu);
if (ret) {
dev_err(adev->dev, "Failed to get thermal temperature ranges!\n");
@@ -1789,6 +1884,9 @@ static int smu_start_smc_engine(struct smu_context *smu)
struct amdgpu_device *adev = smu->adev;
int ret = 0;
+ if (amdgpu_virt_xgmi_migrate_enabled(adev))
+ smu_update_gpu_addresses(smu);
+
smu->smc_fw_state = SMU_FW_INIT;
if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) {
@@ -1826,7 +1924,7 @@ static int smu_hw_init(struct amdgpu_ip_block *ip_block)
struct amdgpu_device *adev = ip_block->adev;
struct smu_context *smu = adev->powerplay.pp_handle;
- if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) {
+ if (amdgpu_sriov_multi_vf_mode(adev)) {
smu->pm_enabled = false;
return 0;
}
@@ -1851,7 +1949,6 @@ static int smu_hw_init(struct amdgpu_ip_block *ip_block)
for (i = 0; i < adev->vcn.num_vcn_inst; i++)
smu_dpm_set_vcn_enable(smu, true, i);
smu_dpm_set_jpeg_enable(smu, true);
- smu_dpm_set_vpe_enable(smu, true);
smu_dpm_set_umsch_mm_enable(smu, true);
smu_set_mall_enable(smu);
smu_set_gfx_cgpg(smu, true);
@@ -1860,7 +1957,7 @@ static int smu_hw_init(struct amdgpu_ip_block *ip_block)
if (!smu->pm_enabled)
return 0;
- ret = smu_get_driver_allowed_feature_mask(smu);
+ ret = smu_init_driver_allowed_feature_mask(smu);
if (ret)
return ret;
@@ -1933,6 +2030,7 @@ static int smu_disable_dpms(struct smu_context *smu)
case IP_VERSION(11, 0, 7):
case IP_VERSION(11, 0, 11):
case IP_VERSION(11, 5, 0):
+ case IP_VERSION(11, 5, 2):
case IP_VERSION(11, 0, 12):
case IP_VERSION(11, 0, 13):
return 0;
@@ -1966,6 +2064,12 @@ static int smu_disable_dpms(struct smu_context *smu)
smu->is_apu && (amdgpu_in_reset(adev) || adev->in_s0ix))
return 0;
+ /* vangogh s0ix */
+ if ((amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 5, 0) ||
+ amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 5, 2)) &&
+ adev->in_s0ix)
+ return 0;
+
/*
* For gpu reset, runpm and hibernation through BACO,
* BACO feature has to be kept enabled.
@@ -2035,9 +2139,8 @@ static int smu_reset_mp1_state(struct smu_context *smu)
int ret = 0;
if ((!adev->in_runpm) && (!adev->in_suspend) &&
- (!amdgpu_in_reset(adev)) && amdgpu_ip_version(adev, MP1_HWIP, 0) ==
- IP_VERSION(13, 0, 10) &&
- !amdgpu_device_has_display_hardware(adev))
+ (!amdgpu_in_reset(adev)) && !smu->is_apu &&
+ amdgpu_ip_version(adev, MP1_HWIP, 0) >= IP_VERSION(13, 0, 0))
ret = smu_set_mp1_state(smu, PP_MP1_STATE_UNLOAD);
return ret;
@@ -2049,17 +2152,16 @@ static int smu_hw_fini(struct amdgpu_ip_block *ip_block)
struct smu_context *smu = adev->powerplay.pp_handle;
int i, ret;
- if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev))
+ if (amdgpu_sriov_multi_vf_mode(adev))
return 0;
- for (i = 0; i < adev->vcn.num_vcn_inst; i++)
+ for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
smu_dpm_set_vcn_enable(smu, false, i);
+ adev->vcn.inst[i].cur_state = AMD_PG_STATE_GATE;
+ }
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;
+ smu_dpm_set_umsch_mm_enable(smu, false);
if (!smu->pm_enabled)
return 0;
@@ -2117,7 +2219,7 @@ static int smu_suspend(struct amdgpu_ip_block *ip_block)
int ret;
uint64_t count;
- if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev))
+ if (amdgpu_sriov_multi_vf_mode(adev))
return 0;
if (!smu->pm_enabled)
@@ -2153,7 +2255,7 @@ static int smu_resume(struct amdgpu_ip_block *ip_block)
struct amdgpu_device *adev = ip_block->adev;
struct smu_context *smu = adev->powerplay.pp_handle;
- if (amdgpu_sriov_vf(adev)&& !amdgpu_sriov_is_pp_one_vf(adev))
+ if (amdgpu_sriov_multi_vf_mode(adev))
return 0;
if (!smu->pm_enabled)
@@ -2326,7 +2428,12 @@ static int smu_adjust_power_state_dynamic(struct smu_context *smu,
if (smu_dpm_ctx->dpm_level != level) {
ret = smu_asic_set_performance_level(smu, level);
if (ret) {
- dev_err(smu->adev->dev, "Failed to set performance level!");
+ if (ret == -EOPNOTSUPP)
+ dev_info(smu->adev->dev, "set performance level %d not supported",
+ level);
+ else
+ dev_err(smu->adev->dev, "Failed to set performance level %d",
+ level);
return ret;
}
@@ -2401,7 +2508,11 @@ static int smu_switch_power_profile(void *handle,
smu_power_profile_mode_get(smu, type);
else
smu_power_profile_mode_put(smu, type);
- ret = smu_bump_power_profile_mode(smu, NULL, 0);
+ /* don't switch the active workload when paused */
+ if (smu->pause_workload)
+ ret = 0;
+ else
+ ret = smu_bump_power_profile_mode(smu, NULL, 0);
if (ret) {
if (enable)
smu_power_profile_mode_put(smu, type);
@@ -2414,6 +2525,35 @@ static int smu_switch_power_profile(void *handle,
return 0;
}
+static int smu_pause_power_profile(void *handle,
+ bool pause)
+{
+ struct smu_context *smu = handle;
+ struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
+ u32 workload_mask = 1 << PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
+ int ret;
+
+ if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
+ return -EOPNOTSUPP;
+
+ if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL &&
+ smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) {
+ smu->pause_workload = pause;
+
+ /* force to bootup default profile */
+ if (smu->pause_workload && smu->ppt_funcs->set_power_profile_mode)
+ ret = smu->ppt_funcs->set_power_profile_mode(smu,
+ workload_mask,
+ NULL,
+ 0);
+ else
+ ret = smu_bump_power_profile_mode(smu, NULL, 0);
+ return ret;
+ }
+
+ return 0;
+}
+
static enum amd_dpm_forced_level smu_get_performance_level(void *handle)
{
struct smu_context *smu = handle;
@@ -2672,6 +2812,25 @@ const struct amdgpu_ip_block_version smu_v14_0_ip_block = {
.funcs = &smu_ip_funcs,
};
+const struct amdgpu_ip_block_version smu_v15_0_ip_block = {
+ .type = AMD_IP_BLOCK_TYPE_SMC,
+ .major = 15,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &smu_ip_funcs,
+};
+
+const struct ras_smu_drv *smu_get_ras_smu_driver(void *handle)
+{
+ struct smu_context *smu = (struct smu_context *)handle;
+ const struct ras_smu_drv *tmp = NULL;
+ int ret;
+
+ ret = smu_get_ras_smu_drv(smu, &tmp);
+
+ return ret ? NULL : tmp;
+}
+
static int smu_load_microcode(void *handle)
{
struct smu_context *smu = handle;
@@ -2765,6 +2924,9 @@ int smu_get_power_limit(void *handle,
if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
return -EOPNOTSUPP;
+ if (!limit)
+ return -EINVAL;
+
switch (pp_power_type) {
case PP_PWR_TYPE_SUSTAINED:
limit_type = SMU_DEFAULT_PPT_LIMIT;
@@ -2796,17 +2958,21 @@ int smu_get_power_limit(void *handle,
if (limit_type != SMU_DEFAULT_PPT_LIMIT) {
if (smu->ppt_funcs->get_ppt_limit)
ret = smu->ppt_funcs->get_ppt_limit(smu, limit, limit_type, limit_level);
+ else
+ return -EOPNOTSUPP;
} else {
switch (limit_level) {
case SMU_PPT_LIMIT_CURRENT:
switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
case IP_VERSION(13, 0, 2):
case IP_VERSION(13, 0, 6):
+ case IP_VERSION(13, 0, 12):
case IP_VERSION(13, 0, 14):
case IP_VERSION(11, 0, 7):
case IP_VERSION(11, 0, 11):
case IP_VERSION(11, 0, 12):
case IP_VERSION(11, 0, 13):
+ case IP_VERSION(15, 0, 8):
ret = smu_get_asic_power_limits(smu,
&smu->current_power_limit,
NULL, NULL, NULL);
@@ -2833,50 +2999,34 @@ int smu_get_power_limit(void *handle,
return ret;
}
-static int smu_set_power_limit(void *handle, uint32_t limit)
+static int smu_set_power_limit(void *handle, uint32_t limit_type, uint32_t limit)
{
struct smu_context *smu = handle;
- uint32_t limit_type = limit >> 24;
int ret = 0;
if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
return -EOPNOTSUPP;
- limit &= (1<<24)-1;
- if (limit_type != SMU_DEFAULT_PPT_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) || (limit < smu->min_power_limit)) {
- dev_err(smu->adev->dev,
- "New power limit (%d) is out of range [%d,%d]\n",
- limit, smu->min_power_limit, smu->max_power_limit);
- return -EINVAL;
+ if (limit_type == SMU_DEFAULT_PPT_LIMIT) {
+ if (!limit)
+ limit = smu->current_power_limit;
+ if ((limit > smu->max_power_limit) || (limit < smu->min_power_limit)) {
+ dev_err(smu->adev->dev,
+ "New power limit (%d) is out of range [%d,%d]\n",
+ limit, smu->min_power_limit, smu->max_power_limit);
+ return -EINVAL;
+ }
}
- if (!limit)
- limit = smu->current_power_limit;
-
if (smu->ppt_funcs->set_power_limit) {
ret = smu->ppt_funcs->set_power_limit(smu, limit_type, limit);
- if (!ret && !(smu->user_dpm_profile.flags & SMU_DPM_USER_PROFILE_RESTORE))
- smu->user_dpm_profile.power_limit = limit;
+ if (ret)
+ return ret;
+ if (!(smu->user_dpm_profile.flags & SMU_DPM_USER_PROFILE_RESTORE))
+ smu->user_dpm_profile.power_limits[limit_type] = limit;
}
- return ret;
-}
-
-static int smu_print_smuclk_levels(struct smu_context *smu, enum smu_clk_type clk_type, char *buf)
-{
- int ret = 0;
-
- if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
- return -EOPNOTSUPP;
-
- if (smu->ppt_funcs->print_clk_levels)
- ret = smu->ppt_funcs->print_clk_levels(smu, clk_type, buf);
-
- return ret;
+ return 0;
}
static enum smu_clk_type smu_convert_to_smuclk(enum pp_clock_type type)
@@ -2904,10 +3054,18 @@ static enum smu_clk_type smu_convert_to_smuclk(enum pp_clock_type type)
clk_type = SMU_DCLK; break;
case PP_DCLK1:
clk_type = SMU_DCLK1; break;
+ case PP_ISPICLK:
+ clk_type = SMU_ISPICLK;
+ break;
+ case PP_ISPXCLK:
+ clk_type = SMU_ISPXCLK;
+ break;
case OD_SCLK:
clk_type = SMU_OD_SCLK; break;
case OD_MCLK:
clk_type = SMU_OD_MCLK; break;
+ case OD_FCLK:
+ clk_type = SMU_OD_FCLK; break;
case OD_VDDC_CURVE:
clk_type = SMU_OD_VDDC_CURVE; break;
case OD_RANGE:
@@ -2937,20 +3095,6 @@ static enum smu_clk_type smu_convert_to_smuclk(enum pp_clock_type type)
return clk_type;
}
-static int smu_print_ppclk_levels(void *handle,
- enum pp_clock_type type,
- char *buf)
-{
- struct smu_context *smu = handle;
- enum smu_clk_type clk_type;
-
- clk_type = smu_convert_to_smuclk(type);
- if (clk_type == SMU_CLK_COUNT)
- return -EINVAL;
-
- return smu_print_smuclk_levels(smu, clk_type, buf);
-}
-
static int smu_emit_ppclk_levels(void *handle, enum pp_clock_type type, char *buf, int *offset)
{
struct smu_context *smu = handle;
@@ -3029,10 +3173,19 @@ static int smu_read_sensor(void *handle,
*((uint32_t *)data) = pstate_table->uclk_pstate.peak * 100;
*size = 4;
break;
- case AMDGPU_PP_SENSOR_ENABLED_SMC_FEATURES_MASK:
- ret = smu_feature_get_enabled_mask(smu, (uint64_t *)data);
+ case AMDGPU_PP_SENSOR_ENABLED_SMC_FEATURES_MASK: {
+ struct smu_feature_bits feature_mask;
+ uint32_t features[2];
+
+ /* TBD: need to handle for > 64 bits */
+ ret = smu_feature_get_enabled_mask(smu, &feature_mask);
+ if (!ret) {
+ smu_feature_bits_to_arr32(&feature_mask, features, 64);
+ *(uint64_t *)data = *(uint64_t *)features;
+ }
*size = 8;
break;
+ }
case AMDGPU_PP_SENSOR_UVD_POWER:
*(uint32_t *)data = smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UVD_BIT) ? 1 : 0;
*size = 4;
@@ -3401,17 +3554,12 @@ bool smu_mode1_reset_is_support(struct smu_context *smu)
return ret;
}
-bool smu_mode2_reset_is_support(struct smu_context *smu)
+bool smu_link_reset_is_support(struct smu_context *smu)
{
- bool ret = false;
-
if (!smu->pm_enabled)
return false;
- if (smu->ppt_funcs && smu->ppt_funcs->mode2_reset_is_support)
- ret = smu->ppt_funcs->mode2_reset_is_support(smu);
-
- return ret;
+ return smu_feature_cap_test(smu, SMU_FEATURE_CAP_ID__LINK_RESET);
}
int smu_mode1_reset(struct smu_context *smu)
@@ -3444,6 +3592,19 @@ static int smu_mode2_reset(void *handle)
return ret;
}
+int smu_link_reset(struct smu_context *smu)
+{
+ int ret = 0;
+
+ if (!smu->pm_enabled)
+ return -EOPNOTSUPP;
+
+ if (smu->ppt_funcs->link_reset)
+ ret = smu->ppt_funcs->link_reset(smu);
+
+ return ret;
+}
+
static int smu_enable_gfx_features(void *handle)
{
struct smu_context *smu = handle;
@@ -3524,6 +3685,9 @@ static int smu_get_dpm_clock_table(void *handle,
static ssize_t smu_sys_get_gpu_metrics(void *handle, void **table)
{
struct smu_context *smu = handle;
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_driver_table *driver_tables = smu_table->driver_tables;
+ struct smu_driver_table *gpu_metrics_table;
if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
return -EOPNOTSUPP;
@@ -3531,6 +3695,14 @@ static ssize_t smu_sys_get_gpu_metrics(void *handle, void **table)
if (!smu->ppt_funcs->get_gpu_metrics)
return -EOPNOTSUPP;
+ gpu_metrics_table = &driver_tables[SMU_DRIVER_TABLE_GPU_METRICS];
+
+ /* If cached table is valid, return it */
+ if (smu_driver_table_is_valid(gpu_metrics_table)) {
+ *table = gpu_metrics_table->cache.buffer;
+ return gpu_metrics_table->cache.size;
+ }
+
return smu->ppt_funcs->get_gpu_metrics(smu, table);
}
@@ -3714,6 +3886,66 @@ int smu_set_pm_policy(struct smu_context *smu, enum pp_pm_policy p_type,
return ret;
}
+static ssize_t smu_sys_get_temp_metrics(void *handle, enum smu_temp_metric_type type, void *table)
+{
+ struct smu_context *smu = handle;
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_driver_table *driver_tables = smu_table->driver_tables;
+ enum smu_driver_table_id table_id;
+ struct smu_driver_table *temp_table;
+
+ if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
+ return -EOPNOTSUPP;
+
+ if (!smu->smu_temp.temp_funcs || !smu->smu_temp.temp_funcs->get_temp_metrics)
+ return -EOPNOTSUPP;
+
+ table_id = smu_metrics_get_temp_table_id(type);
+
+ if (table_id == SMU_DRIVER_TABLE_COUNT)
+ return -EINVAL;
+
+ temp_table = &driver_tables[table_id];
+
+ /* If the request is to get size alone, return the cached table size */
+ if (!table && temp_table->cache.size)
+ return temp_table->cache.size;
+
+ if (smu_driver_table_is_valid(temp_table)) {
+ memcpy(table, temp_table->cache.buffer, temp_table->cache.size);
+ return temp_table->cache.size;
+ }
+
+ return smu->smu_temp.temp_funcs->get_temp_metrics(smu, type, table);
+}
+
+static bool smu_temp_metrics_is_supported(void *handle, enum smu_temp_metric_type type)
+{
+ struct smu_context *smu = handle;
+ bool ret = false;
+
+ if (!smu->pm_enabled)
+ return false;
+
+ if (smu->smu_temp.temp_funcs && smu->smu_temp.temp_funcs->temp_metrics_is_supported)
+ ret = smu->smu_temp.temp_funcs->temp_metrics_is_supported(smu, type);
+
+ return ret;
+}
+
+static ssize_t smu_sys_get_xcp_metrics(void *handle, int xcp_id, void *table)
+{
+ struct smu_context *smu = handle;
+
+ if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
+ return -EOPNOTSUPP;
+
+ if (!smu->adev->xcp_mgr || !smu->ppt_funcs->get_xcp_metrics)
+ return -EOPNOTSUPP;
+
+ return smu->ppt_funcs->get_xcp_metrics(smu, xcp_id, table);
+}
+
static const struct amd_pm_funcs swsmu_pm_funcs = {
/* export for sysfs */
.set_fan_control_mode = smu_set_fan_control_mode,
@@ -3721,7 +3953,6 @@ static const struct amd_pm_funcs swsmu_pm_funcs = {
.set_fan_speed_pwm = smu_set_fan_speed_pwm,
.get_fan_speed_pwm = smu_get_fan_speed_pwm,
.force_clock_level = smu_force_ppclk_levels,
- .print_clock_levels = smu_print_ppclk_levels,
.emit_clock_levels = smu_emit_ppclk_levels,
.force_performance_level = smu_force_performance_level,
.read_sensor = smu_read_sensor,
@@ -3735,6 +3966,7 @@ static const struct amd_pm_funcs swsmu_pm_funcs = {
.get_pp_table = smu_sys_get_pp_table,
.set_pp_table = smu_sys_set_pp_table,
.switch_power_profile = smu_switch_power_profile,
+ .pause_power_profile = smu_pause_power_profile,
/* export to amdgpu */
.dispatch_tasks = smu_handle_dpm_task,
.load_firmware = smu_load_microcode,
@@ -3771,6 +4003,9 @@ static const struct amd_pm_funcs swsmu_pm_funcs = {
.get_uclk_dpm_states = smu_get_uclk_dpm_states,
.get_dpm_clock_table = smu_get_dpm_clock_table,
.get_smu_prv_buf_details = smu_get_prv_buffer_details,
+ .get_xcp_metrics = smu_sys_get_xcp_metrics,
+ .get_temp_metrics = smu_sys_get_temp_metrics,
+ .temp_metrics_is_supported = smu_temp_metrics_is_supported,
};
int smu_wait_for_event(struct smu_context *smu, enum smu_event_type event,
@@ -3917,6 +4152,18 @@ int smu_send_rma_reason(struct smu_context *smu)
return ret;
}
+/**
+ * smu_reset_sdma_is_supported - Check if SDMA reset is supported by SMU
+ * @smu: smu_context pointer
+ *
+ * This function checks if the SMU supports resetting the SDMA engine.
+ * It returns true if supported, false otherwise.
+ */
+bool smu_reset_sdma_is_supported(struct smu_context *smu)
+{
+ return smu_feature_cap_test(smu, SMU_FEATURE_CAP_ID__SDMA_RESET);
+}
+
int smu_reset_sdma(struct smu_context *smu, uint32_t inst_mask)
{
int ret = 0;
@@ -3926,3 +4173,16 @@ int smu_reset_sdma(struct smu_context *smu, uint32_t inst_mask)
return ret;
}
+
+bool smu_reset_vcn_is_supported(struct smu_context *smu)
+{
+ return smu_feature_cap_test(smu, SMU_FEATURE_CAP_ID__VCN_RESET);
+}
+
+int smu_reset_vcn(struct smu_context *smu, uint32_t inst_mask)
+{
+ if (smu->ppt_funcs && smu->ppt_funcs->dpm_reset_vcn)
+ smu->ppt_funcs->dpm_reset_vcn(smu, inst_mask);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
index 3630593bce61..d76e0b005308 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@ -41,6 +41,8 @@
#define SMU_CUSTOM_FAN_SPEED_RPM (1 << 1)
#define SMU_CUSTOM_FAN_SPEED_PWM (1 << 2)
+#define SMU_GPU_METRICS_CACHE_INTERVAL 5
+
// Power Throttlers
#define SMU_THROTTLER_PPT0_BIT 0
#define SMU_THROTTLER_PPT1_BIT 1
@@ -212,6 +214,7 @@ enum smu_power_src_type {
enum smu_ppt_limit_type {
SMU_DEFAULT_PPT_LIMIT = 0,
SMU_FAST_PPT_LIMIT,
+ SMU_LIMIT_TYPE_COUNT,
};
enum smu_ppt_limit_level {
@@ -231,7 +234,7 @@ enum smu_memory_pool_size {
struct smu_user_dpm_profile {
uint32_t fan_mode;
- uint32_t power_limit;
+ uint32_t power_limits[SMU_LIMIT_TYPE_COUNT];
uint32_t fan_speed_pwm;
uint32_t fan_speed_rpm;
uint32_t flags;
@@ -249,6 +252,14 @@ struct smu_user_dpm_profile {
tables[table_id].domain = d; \
} while (0)
+struct smu_table_cache {
+ void *buffer;
+ size_t size;
+ /* interval in ms*/
+ uint32_t interval;
+ unsigned long last_cache_time;
+};
+
struct smu_table {
uint64_t size;
uint32_t align;
@@ -257,6 +268,19 @@ struct smu_table {
void *cpu_addr;
struct amdgpu_bo *bo;
uint32_t version;
+ struct smu_table_cache cache;
+};
+
+enum smu_driver_table_id {
+ SMU_DRIVER_TABLE_GPU_METRICS = 0,
+ SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS,
+ SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS,
+ SMU_DRIVER_TABLE_COUNT,
+};
+
+struct smu_driver_table {
+ enum smu_driver_table_id id;
+ struct smu_table_cache cache;
};
enum smu_perf_level_designation {
@@ -282,6 +306,37 @@ struct smu_clock_info {
uint32_t max_bus_bandwidth;
};
+#define SMU_MAX_DPM_LEVELS 16
+
+struct smu_dpm_clk_level {
+ bool enabled;
+ uint32_t value;
+};
+
+#define SMU_DPM_TABLE_FINE_GRAINED BIT(0)
+
+struct smu_dpm_table {
+ enum smu_clk_type clk_type;
+ uint32_t count;
+ uint32_t flags;
+ struct smu_dpm_clk_level dpm_levels[SMU_MAX_DPM_LEVELS];
+};
+
+#define SMU_DPM_TABLE_MIN(table) \
+ ((table)->count > 0 ? (table)->dpm_levels[0].value : 0)
+
+#define SMU_DPM_TABLE_MAX(table) \
+ ((table)->count > 0 ? (table)->dpm_levels[(table)->count - 1].value : 0)
+
+#define SMU_MAX_PCIE_LEVELS 3
+
+struct smu_pcie_table {
+ uint8_t pcie_gen[SMU_MAX_PCIE_LEVELS];
+ uint8_t pcie_lane[SMU_MAX_PCIE_LEVELS];
+ uint16_t lclk_freq[SMU_MAX_PCIE_LEVELS];
+ uint32_t lclk_levels;
+};
+
struct smu_bios_boot_up_values {
uint32_t revision;
uint32_t gfxclk;
@@ -322,6 +377,7 @@ enum smu_table_id {
SMU_TABLE_ECCINFO,
SMU_TABLE_COMBO_PPTABLE,
SMU_TABLE_WIFIBAND,
+ SMU_TABLE_PMFW_SYSTEM_METRICS,
SMU_TABLE_COUNT,
};
@@ -333,6 +389,7 @@ struct smu_table_context {
void *metrics_table;
void *clocks_table;
void *watermarks_table;
+ struct mutex metrics_lock;
void *max_sustainable_clocks;
struct smu_bios_boot_up_values boot_values;
@@ -358,8 +415,7 @@ struct smu_table_context {
void *boot_overdrive_table;
void *user_overdrive_table;
- uint32_t gpu_metrics_table_size;
- void *gpu_metrics_table;
+ struct smu_driver_table driver_tables[SMU_DRIVER_TABLE_COUNT];
};
struct smu_context;
@@ -396,12 +452,17 @@ struct smu_dpm_context {
struct smu_dpm_policy_ctxt *dpm_policies;
};
+struct smu_temp_context {
+ const struct smu_temp_funcs *temp_funcs;
+};
+
struct smu_power_gate {
bool uvd_gated;
bool vce_gated;
atomic_t vcn_gated[AMDGPU_MAX_VCN_INSTANCES];
atomic_t jpeg_gated;
atomic_t vpe_gated;
+ atomic_t isp_gated;
atomic_t umsch_mm_gated;
};
@@ -411,11 +472,39 @@ struct smu_power_context {
struct smu_power_gate power_gate;
};
-#define SMU_FEATURE_MAX (64)
+#define SMU_FEATURE_NUM_DEFAULT (64)
+#define SMU_FEATURE_MAX (128)
+
+struct smu_feature_bits {
+ DECLARE_BITMAP(bits, SMU_FEATURE_MAX);
+};
+
+/*
+ * Helpers for initializing smu_feature_bits statically.
+ * Use SMU_FEATURE_BIT_INIT() which automatically handles array indexing:
+ * static const struct smu_feature_bits example = {
+ * .bits = {
+ * SMU_FEATURE_BIT_INIT(5),
+ * SMU_FEATURE_BIT_INIT(10),
+ * SMU_FEATURE_BIT_INIT(65),
+ * SMU_FEATURE_BIT_INIT(100)
+ * }
+ * };
+ */
+#define SMU_FEATURE_BITS_ELEM(bit) ((bit) / BITS_PER_LONG)
+#define SMU_FEATURE_BITS_POS(bit) ((bit) % BITS_PER_LONG)
+#define SMU_FEATURE_BIT_INIT(bit) \
+ [SMU_FEATURE_BITS_ELEM(bit)] = (1UL << SMU_FEATURE_BITS_POS(bit))
+
+enum smu_feature_list {
+ SMU_FEATURE_LIST_SUPPORTED,
+ SMU_FEATURE_LIST_ALLOWED,
+ SMU_FEATURE_LIST_MAX,
+};
+
struct smu_feature {
uint32_t feature_num;
- DECLARE_BITMAP(supported, SMU_FEATURE_MAX);
- DECLARE_BITMAP(allowed, SMU_FEATURE_MAX);
+ struct smu_feature_bits bits[SMU_FEATURE_LIST_MAX];
};
struct smu_clocks {
@@ -438,15 +527,16 @@ struct mclock_latency_table {
};
enum smu_reset_mode {
- SMU_RESET_MODE_0,
- SMU_RESET_MODE_1,
- SMU_RESET_MODE_2,
+ SMU_RESET_MODE_0,
+ SMU_RESET_MODE_1,
+ SMU_RESET_MODE_2,
+ SMU_RESET_MODE_3,
+ SMU_RESET_MODE_4,
};
enum smu_baco_state {
SMU_BACO_STATE_ENTER = 0,
SMU_BACO_STATE_EXIT,
- SMU_BACO_STATE_NONE,
};
struct smu_baco_context {
@@ -489,6 +579,87 @@ struct cmn2asic_mapping {
int map_to;
};
+#define SMU_MSG_MAX_ARGS 4
+
+/* Message flags for smu_msg_args */
+#define SMU_MSG_FLAG_ASYNC BIT(0) /* Async send - skip post-poll */
+#define SMU_MSG_FLAG_LOCK_HELD BIT(1) /* Caller holds ctl->lock */
+#define SMU_MSG_FLAG_FORCE_READ_ARG BIT(2) /* force read smu arg from pmfw */
+
+/* smu_msg_ctl flags */
+#define SMU_MSG_CTL_DEBUG_MAILBOX BIT(0) /* Debug mailbox supported */
+
+struct smu_msg_ctl;
+/**
+ * struct smu_msg_config - IP-level register configuration
+ * @msg_reg: Message register offset
+ * @resp_reg: Response register offset
+ * @arg_regs: Argument register offsets (up to SMU_MSG_MAX_ARGS)
+ * @num_arg_regs: Number of argument registers available
+ * @debug_msg_reg: Debug message register offset
+ * @debug_resp_reg: Debug response register offset
+ * @debug_param_reg: Debug parameter register offset
+ */
+struct smu_msg_config {
+ u32 msg_reg;
+ u32 resp_reg;
+ u32 arg_regs[SMU_MSG_MAX_ARGS];
+ int num_arg_regs;
+ u32 debug_msg_reg;
+ u32 debug_resp_reg;
+ u32 debug_param_reg;
+};
+
+/**
+ * struct smu_msg_args - Per-call message arguments
+ * @msg: Common message type (enum smu_message_type)
+ * @args: Input arguments
+ * @num_args: Number of input arguments
+ * @out_args: Output arguments (filled after successful send)
+ * @num_out_args: Number of output arguments to read
+ * @flags: Message flags (SMU_MSG_FLAG_*)
+ * @timeout: Per-message timeout in us (0 = use default)
+ */
+struct smu_msg_args {
+ enum smu_message_type msg;
+ u32 args[SMU_MSG_MAX_ARGS];
+ int num_args;
+ u32 out_args[SMU_MSG_MAX_ARGS];
+ int num_out_args;
+ u32 flags;
+ u32 timeout;
+};
+
+/**
+ * struct smu_msg_ops - IP-level protocol operations
+ * @send_msg: send message protocol
+ * @wait_response: wait for response (for split send/wait cases)
+ * @decode_response: Convert response register value to errno
+ * @send_debug_msg: send debug message
+ */
+struct smu_msg_ops {
+ int (*send_msg)(struct smu_msg_ctl *ctl, struct smu_msg_args *args);
+ int (*wait_response)(struct smu_msg_ctl *ctl, u32 timeout_us);
+ int (*decode_response)(u32 resp);
+ int (*send_debug_msg)(struct smu_msg_ctl *ctl, u32 msg, u32 param);
+};
+
+/**
+ * struct smu_msg_ctl - Per-device message control block
+ * This is a standalone control block that encapsulates everything
+ * needed for SMU messaging. The ops->send_msg implements the complete
+ * protocol including all filtering and error handling.
+ */
+struct smu_msg_ctl {
+ struct smu_context *smu;
+ struct mutex lock;
+ struct smu_msg_config config;
+ const struct smu_msg_ops *ops;
+ const struct cmn2asic_msg_mapping *message_map;
+ u32 default_timeout;
+ u32 flags;
+};
+
struct stb_context {
uint32_t stb_buf_size;
bool enabled;
@@ -509,27 +680,38 @@ enum smu_fw_status {
*/
#define SMU_WBRF_EVENT_HANDLING_PACE 10
+enum smu_feature_cap_id {
+ SMU_FEATURE_CAP_ID__LINK_RESET = 0,
+ SMU_FEATURE_CAP_ID__SDMA_RESET,
+ SMU_FEATURE_CAP_ID__VCN_RESET,
+ SMU_FEATURE_CAP_ID__COUNT,
+};
+
+struct smu_feature_cap {
+ DECLARE_BITMAP(cap_map, SMU_FEATURE_CAP_ID__COUNT);
+};
+
struct smu_context {
struct amdgpu_device *adev;
struct amdgpu_irq_src irq_source;
const struct pptable_funcs *ppt_funcs;
- const struct cmn2asic_msg_mapping *message_map;
const struct cmn2asic_mapping *clock_map;
const struct cmn2asic_mapping *feature_map;
const struct cmn2asic_mapping *table_map;
const struct cmn2asic_mapping *pwr_src_map;
const struct cmn2asic_mapping *workload_map;
- struct mutex message_lock;
uint64_t pool_size;
struct smu_table_context smu_table;
struct smu_dpm_context smu_dpm;
struct smu_power_context smu_power;
+ struct smu_temp_context smu_temp;
struct smu_feature smu_feature;
struct amd_pp_display_configuration *display_config;
struct smu_baco_context smu_baco;
struct smu_temperature_range thermal_range;
+ struct smu_feature_cap fea_cap;
void *od_settings;
struct smu_umd_pstate_table pstate_table;
@@ -558,6 +740,7 @@ struct smu_context {
/* asic agnostic workload mask */
uint32_t workload_mask;
+ bool pause_workload;
/* default/user workload preference */
uint32_t power_profile_mode;
uint32_t workload_refcount[PP_SMC_POWER_PROFILE_COUNT];
@@ -601,25 +784,42 @@ struct smu_context {
struct firmware pptable_firmware;
- u32 param_reg;
- u32 msg_reg;
- u32 resp_reg;
-
- u32 debug_param_reg;
- u32 debug_msg_reg;
- u32 debug_resp_reg;
-
struct delayed_work swctf_delayed_work;
/* data structures for wbrf feature support */
bool wbrf_supported;
struct notifier_block wbrf_notifier;
struct delayed_work wbrf_delayed_work;
+
+ /* SMU message control block */
+ struct smu_msg_ctl msg_ctl;
};
struct i2c_adapter;
/**
+ * struct smu_temp_funcs - Callbacks used to get temperature data.
+ */
+struct smu_temp_funcs {
+ /**
+ * @get_temp_metrics: Calibrate voltage/frequency curve to fit the system's
+ * power delivery and voltage margins. Required for adaptive
+ * @type Temperature metrics type(baseboard/gpuboard)
+ * Return: Size of &table
+ */
+ ssize_t (*get_temp_metrics)(struct smu_context *smu,
+ enum smu_temp_metric_type type, void *table);
+
+ /**
+ * @temp_metrics_is_support: Get if specific temperature metrics is supported
+ * @type Temperature metrics type(baseboard/gpuboard)
+ * Return: true if supported else false
+ */
+ bool (*temp_metrics_is_supported)(struct smu_context *smu, enum smu_temp_metric_type type);
+
+};
+
+/**
* struct pptable_funcs - Callbacks used to interact with the SMU.
*/
struct pptable_funcs {
@@ -631,11 +831,10 @@ struct pptable_funcs {
int (*run_btc)(struct smu_context *smu);
/**
- * @get_allowed_feature_mask: Get allowed feature mask.
- * &feature_mask: Array to store feature mask.
- * &num: Elements in &feature_mask.
+ * @init_allowed_features: Initialize allowed features bitmap.
+ * Directly sets allowed features using smu_feature wrapper functions.
*/
- int (*get_allowed_feature_mask)(struct smu_context *smu, uint32_t *feature_mask, uint32_t num);
+ int (*init_allowed_features)(struct smu_context *smu);
/**
* @get_current_power_state: Get the current power state.
@@ -659,15 +858,6 @@ struct pptable_funcs {
int (*populate_umd_state_clk)(struct smu_context *smu);
/**
- * @print_clk_levels: Print DPM clock levels for a clock domain
- * to buffer. Star current level.
- *
- * Used for sysfs interfaces.
- * Return: Number of characters written to the buffer
- */
- int (*print_clk_levels)(struct smu_context *smu, enum smu_clk_type clk_type, char *buf);
-
- /**
* @emit_clk_levels: Print DPM clock levels for a clock domain
* to buffer using sysfs_emit_at. Star current level.
*
@@ -1025,24 +1215,6 @@ struct pptable_funcs {
int (*system_features_control)(struct smu_context *smu, bool en);
/**
- * @send_smc_msg_with_param: Send a message with a parameter to the SMU.
- * &msg: Type of message.
- * &param: Message parameter.
- * &read_arg: SMU response (optional).
- */
- int (*send_smc_msg_with_param)(struct smu_context *smu,
- enum smu_message_type msg, uint32_t param, uint32_t *read_arg);
-
- /**
- * @send_smc_msg: Send a message to the SMU.
- * &msg: Type of message.
- * &read_arg: SMU response (optional).
- */
- int (*send_smc_msg)(struct smu_context *smu,
- enum smu_message_type msg,
- uint32_t *read_arg);
-
- /**
* @init_display_count: Notify the SMU of the number of display
* components in current display configuration.
*/
@@ -1059,7 +1231,8 @@ struct pptable_funcs {
* on the SMU.
* &feature_mask: Enabled feature mask.
*/
- int (*get_enabled_mask)(struct smu_context *smu, uint64_t *feature_mask);
+ int (*get_enabled_mask)(struct smu_context *smu,
+ struct smu_feature_bits *feature_mask);
/**
* @feature_is_enabled: Test if a feature is enabled.
@@ -1228,10 +1401,6 @@ struct pptable_funcs {
* @mode1_reset_is_support: Check if GPU supports mode1 reset.
*/
bool (*mode1_reset_is_support)(struct smu_context *smu);
- /**
- * @mode2_reset_is_support: Check if GPU supports mode2 reset.
- */
- bool (*mode2_reset_is_support)(struct smu_context *smu);
/**
* @mode1_reset: Perform mode1 reset.
@@ -1251,6 +1420,13 @@ struct pptable_funcs {
int (*enable_gfx_features)(struct smu_context *smu);
/**
+ * @link_reset: Perform link reset.
+ *
+ * The gfx device driver reset
+ */
+ int (*link_reset)(struct smu_context *smu);
+
+ /**
* @get_dpm_ultimate_freq: Get the hard frequency range of a clock
* domain in MHz.
*/
@@ -1378,6 +1554,11 @@ struct pptable_funcs {
int (*reset_sdma)(struct smu_context *smu, uint32_t inst_mask);
/**
+ * @reset_vcn: message SMU to soft reset vcn instance.
+ */
+ int (*dpm_reset_vcn)(struct smu_context *smu, uint32_t inst_mask);
+
+ /**
* @get_ecc_table: message SMU to get ECC INFO table.
*/
ssize_t (*get_ecc_info)(struct smu_context *smu, void *table);
@@ -1416,6 +1597,12 @@ struct pptable_funcs {
int (*dpm_set_vpe_enable)(struct smu_context *smu, bool enable);
/**
+ * @dpm_set_isp_enable: Enable/disable ISP engine dynamic power
+ * management.
+ */
+ int (*dpm_set_isp_enable)(struct smu_context *smu, bool enable);
+
+ /**
* @dpm_set_umsch_mm_enable: Enable/disable UMSCH engine dynamic power
* management.
*/
@@ -1446,6 +1633,27 @@ struct pptable_funcs {
*/
int (*set_wbrf_exclusion_ranges)(struct smu_context *smu,
struct freq_band_range *exclusion_ranges);
+ /**
+ * @get_xcp_metrics: Get a copy of the partition metrics table from SMU.
+ * Return: Size of table
+ */
+ ssize_t (*get_xcp_metrics)(struct smu_context *smu, int xcp_id,
+ void *table);
+ /**
+ * @ras_send_msg: Send a message with a parameter from Ras
+ * &msg: Type of message.
+ * &param: Message parameter.
+ * &read_arg: SMU response (optional).
+ */
+ int (*ras_send_msg)(struct smu_context *smu,
+ enum smu_message_type msg, uint32_t param, uint32_t *read_arg);
+
+
+ /**
+ * @get_ras_smu_drv: Get RAS smu driver interface
+ * Return: ras_smu_drv *
+ */
+ int (*get_ras_smu_drv)(struct smu_context *smu, const struct ras_smu_drv **ras_smu_drv);
};
typedef enum {
@@ -1499,6 +1707,7 @@ typedef enum {
METRICS_THROTTLER_RESIDENCY_THM_CORE,
METRICS_THROTTLER_RESIDENCY_THM_GFX,
METRICS_THROTTLER_RESIDENCY_THM_SOC,
+ METRICS_AVERAGE_NPUCLK,
} MetricsMember_t;
enum smu_cmn2asic_mapping_type {
@@ -1589,6 +1798,147 @@ typedef struct {
struct smu_dpm_policy *smu_get_pm_policy(struct smu_context *smu,
enum pp_pm_policy p_type);
+static inline enum smu_driver_table_id
+smu_metrics_get_temp_table_id(enum smu_temp_metric_type type)
+{
+ switch (type) {
+ case SMU_TEMP_METRIC_BASEBOARD:
+ return SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS;
+ case SMU_TEMP_METRIC_GPUBOARD:
+ return SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS;
+ default:
+ return SMU_DRIVER_TABLE_COUNT;
+ }
+
+ return SMU_DRIVER_TABLE_COUNT;
+}
+
+static inline void smu_table_cache_update_time(struct smu_table *table,
+ unsigned long time)
+{
+ table->cache.last_cache_time = time;
+}
+
+static inline bool smu_table_cache_is_valid(struct smu_table *table)
+{
+ if (!table->cache.buffer || !table->cache.last_cache_time ||
+ !table->cache.interval || !table->cache.size ||
+ time_after(jiffies,
+ table->cache.last_cache_time +
+ msecs_to_jiffies(table->cache.interval)))
+ return false;
+
+ return true;
+}
+
+static inline int smu_table_cache_init(struct smu_context *smu,
+ enum smu_table_id table_id, size_t size,
+ uint32_t cache_interval)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_table *tables = smu_table->tables;
+
+ tables[table_id].cache.buffer = kzalloc(size, GFP_KERNEL);
+ if (!tables[table_id].cache.buffer)
+ return -ENOMEM;
+
+ tables[table_id].cache.last_cache_time = 0;
+ tables[table_id].cache.interval = cache_interval;
+ tables[table_id].cache.size = size;
+
+ return 0;
+}
+
+static inline void smu_table_cache_fini(struct smu_context *smu,
+ enum smu_table_id table_id)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_table *tables = smu_table->tables;
+
+ if (tables[table_id].cache.buffer) {
+ kfree(tables[table_id].cache.buffer);
+ tables[table_id].cache.buffer = NULL;
+ tables[table_id].cache.last_cache_time = 0;
+ tables[table_id].cache.interval = 0;
+ }
+}
+
+static inline int smu_driver_table_init(struct smu_context *smu,
+ enum smu_driver_table_id table_id,
+ size_t size, uint32_t cache_interval)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_driver_table *driver_tables = smu_table->driver_tables;
+
+ if (table_id >= SMU_DRIVER_TABLE_COUNT)
+ return -EINVAL;
+
+ driver_tables[table_id].id = table_id;
+ driver_tables[table_id].cache.buffer = kzalloc(size, GFP_KERNEL);
+ if (!driver_tables[table_id].cache.buffer)
+ return -ENOMEM;
+
+ driver_tables[table_id].cache.last_cache_time = 0;
+ driver_tables[table_id].cache.interval = cache_interval;
+ driver_tables[table_id].cache.size = size;
+
+ return 0;
+}
+
+static inline void smu_driver_table_fini(struct smu_context *smu,
+ enum smu_driver_table_id table_id)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_driver_table *driver_tables = smu_table->driver_tables;
+
+ if (table_id >= SMU_DRIVER_TABLE_COUNT)
+ return;
+
+ if (driver_tables[table_id].cache.buffer) {
+ kfree(driver_tables[table_id].cache.buffer);
+ driver_tables[table_id].cache.buffer = NULL;
+ driver_tables[table_id].cache.last_cache_time = 0;
+ driver_tables[table_id].cache.interval = 0;
+ }
+}
+
+static inline bool smu_driver_table_is_valid(struct smu_driver_table *table)
+{
+ if (!table->cache.buffer || !table->cache.last_cache_time ||
+ !table->cache.interval || !table->cache.size ||
+ time_after(jiffies,
+ table->cache.last_cache_time +
+ msecs_to_jiffies(table->cache.interval)))
+ return false;
+
+ return true;
+}
+
+static inline void *smu_driver_table_ptr(struct smu_context *smu,
+ enum smu_driver_table_id table_id)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_driver_table *driver_tables = smu_table->driver_tables;
+
+ if (table_id >= SMU_DRIVER_TABLE_COUNT)
+ return NULL;
+
+ return driver_tables[table_id].cache.buffer;
+}
+
+static inline void
+smu_driver_table_update_cache_time(struct smu_context *smu,
+ enum smu_driver_table_id table_id)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_driver_table *driver_tables = smu_table->driver_tables;
+
+ if (table_id >= SMU_DRIVER_TABLE_COUNT)
+ return;
+
+ driver_tables[table_id].cache.last_cache_time = jiffies;
+}
+
#if !defined(SWSMU_CODE_LAYER_L2) && !defined(SWSMU_CODE_LAYER_L3) && !defined(SWSMU_CODE_LAYER_L4)
int smu_get_power_limit(void *handle,
uint32_t *limit,
@@ -1596,8 +1946,9 @@ int smu_get_power_limit(void *handle,
enum pp_power_type pp_power_type);
bool smu_mode1_reset_is_support(struct smu_context *smu);
-bool smu_mode2_reset_is_support(struct smu_context *smu);
+bool smu_link_reset_is_support(struct smu_context *smu);
int smu_mode1_reset(struct smu_context *smu);
+int smu_link_reset(struct smu_context *smu);
extern const struct amd_ip_funcs smu_ip_funcs;
@@ -1608,7 +1959,7 @@ int smu_write_watermarks_table(struct smu_context *smu);
int smu_get_dpm_freq_range(struct smu_context *smu, enum smu_clk_type clk_type,
uint32_t *min, uint32_t *max);
-int smu_set_soft_freq_range(struct smu_context *smu, enum smu_clk_type clk_type,
+int smu_set_soft_freq_range(struct smu_context *smu, enum pp_clock_type clk_type,
uint32_t min, uint32_t max);
int smu_set_gfx_power_up_by_imu(struct smu_context *smu);
@@ -1637,10 +1988,198 @@ int smu_send_hbm_bad_pages_num(struct smu_context *smu, uint32_t size);
int smu_send_hbm_bad_channel_flag(struct smu_context *smu, uint32_t size);
int smu_send_rma_reason(struct smu_context *smu);
int smu_reset_sdma(struct smu_context *smu, uint32_t inst_mask);
+bool smu_reset_sdma_is_supported(struct smu_context *smu);
+int smu_reset_vcn(struct smu_context *smu, uint32_t inst_mask);
+bool smu_reset_vcn_is_supported(struct smu_context *smu);
int smu_set_pm_policy(struct smu_context *smu, enum pp_pm_policy p_type,
int level);
ssize_t smu_get_pm_policy_info(struct smu_context *smu,
enum pp_pm_policy p_type, char *sysbuf);
+const struct ras_smu_drv *smu_get_ras_smu_driver(void *handle);
+int amdgpu_smu_ras_send_msg(struct amdgpu_device *adev, enum smu_message_type msg,
+ uint32_t param, uint32_t *readarg);
+int amdgpu_smu_ras_feature_is_enabled(struct amdgpu_device *adev,
+ enum smu_feature_mask mask);
#endif
+
+void smu_feature_cap_set(struct smu_context *smu, enum smu_feature_cap_id fea_id);
+bool smu_feature_cap_test(struct smu_context *smu, enum smu_feature_cap_id fea_id);
+
+static inline bool smu_feature_bits_is_set(const struct smu_feature_bits *bits,
+ unsigned int bit)
+{
+ if (bit >= SMU_FEATURE_MAX)
+ return false;
+
+ return test_bit(bit, bits->bits);
+}
+
+static inline void smu_feature_bits_set_bit(struct smu_feature_bits *bits,
+ unsigned int bit)
+{
+ if (bit < SMU_FEATURE_MAX)
+ __set_bit(bit, bits->bits);
+}
+
+static inline void smu_feature_bits_clear_bit(struct smu_feature_bits *bits,
+ unsigned int bit)
+{
+ if (bit < SMU_FEATURE_MAX)
+ __clear_bit(bit, bits->bits);
+}
+
+static inline void smu_feature_bits_clearall(struct smu_feature_bits *bits)
+{
+ bitmap_zero(bits->bits, SMU_FEATURE_MAX);
+}
+
+static inline void smu_feature_bits_fill(struct smu_feature_bits *bits)
+{
+ bitmap_fill(bits->bits, SMU_FEATURE_MAX);
+}
+
+static inline bool
+smu_feature_bits_test_mask(const struct smu_feature_bits *bits,
+ const unsigned long *mask)
+{
+ return bitmap_intersects(bits->bits, mask, SMU_FEATURE_MAX);
+}
+
+static inline void smu_feature_bits_from_arr32(struct smu_feature_bits *bits,
+ const uint32_t *arr,
+ unsigned int nbits)
+{
+ bitmap_from_arr32(bits->bits, arr, nbits);
+}
+
+static inline void
+smu_feature_bits_to_arr32(const struct smu_feature_bits *bits, uint32_t *arr,
+ unsigned int nbits)
+{
+ bitmap_to_arr32(arr, bits->bits, nbits);
+}
+
+static inline bool smu_feature_bits_empty(const struct smu_feature_bits *bits,
+ unsigned int nbits)
+{
+ return bitmap_empty(bits->bits, nbits);
+}
+
+static inline bool smu_feature_bits_full(const struct smu_feature_bits *bits,
+ unsigned int nbits)
+{
+ return bitmap_full(bits->bits, nbits);
+}
+
+static inline void smu_feature_bits_copy(struct smu_feature_bits *dst,
+ const unsigned long *src,
+ unsigned int nbits)
+{
+ bitmap_copy(dst->bits, src, nbits);
+}
+
+static inline struct smu_feature_bits *
+__smu_feature_get_list(struct smu_context *smu, enum smu_feature_list list)
+{
+ if (unlikely(list >= SMU_FEATURE_LIST_MAX)) {
+ dev_warn(smu->adev->dev, "Invalid feature list: %d\n", list);
+ return &smu->smu_feature.bits[SMU_FEATURE_LIST_SUPPORTED];
+ }
+
+ return &smu->smu_feature.bits[list];
+}
+
+static inline bool smu_feature_list_is_set(struct smu_context *smu,
+ enum smu_feature_list list,
+ unsigned int bit)
+{
+ if (bit >= smu->smu_feature.feature_num)
+ return false;
+
+ return smu_feature_bits_is_set(__smu_feature_get_list(smu, list), bit);
+}
+
+static inline void smu_feature_list_set_bit(struct smu_context *smu,
+ enum smu_feature_list list,
+ unsigned int bit)
+{
+ if (bit >= smu->smu_feature.feature_num)
+ return;
+
+ smu_feature_bits_set_bit(__smu_feature_get_list(smu, list), bit);
+}
+
+static inline void smu_feature_list_clear_bit(struct smu_context *smu,
+ enum smu_feature_list list,
+ unsigned int bit)
+{
+ if (bit >= smu->smu_feature.feature_num)
+ return;
+
+ smu_feature_bits_clear_bit(__smu_feature_get_list(smu, list), bit);
+}
+
+static inline void smu_feature_list_set_all(struct smu_context *smu,
+ enum smu_feature_list list)
+{
+ smu_feature_bits_fill(__smu_feature_get_list(smu, list));
+}
+
+static inline void smu_feature_list_clear_all(struct smu_context *smu,
+ enum smu_feature_list list)
+{
+ smu_feature_bits_clearall(__smu_feature_get_list(smu, list));
+}
+
+static inline bool smu_feature_list_is_empty(struct smu_context *smu,
+ enum smu_feature_list list)
+{
+ return smu_feature_bits_empty(__smu_feature_get_list(smu, list),
+ smu->smu_feature.feature_num);
+}
+
+static inline void smu_feature_list_set_bits(struct smu_context *smu,
+ enum smu_feature_list dst_list,
+ const unsigned long *src)
+{
+ smu_feature_bits_copy(__smu_feature_get_list(smu, dst_list), src,
+ smu->smu_feature.feature_num);
+}
+
+static inline void smu_feature_list_to_arr32(struct smu_context *smu,
+ enum smu_feature_list list,
+ uint32_t *arr)
+{
+ smu_feature_bits_to_arr32(__smu_feature_get_list(smu, list), arr,
+ smu->smu_feature.feature_num);
+}
+
+static inline void smu_feature_init(struct smu_context *smu, int feature_num)
+{
+ if (!feature_num || smu->smu_feature.feature_num != 0)
+ return;
+
+ smu->smu_feature.feature_num = feature_num;
+ smu_feature_list_clear_all(smu, SMU_FEATURE_LIST_SUPPORTED);
+ smu_feature_list_clear_all(smu, SMU_FEATURE_LIST_ALLOWED);
+}
+
+/*
+ * smu_safe_u16_nn - Make u16 safe by filtering negative overflow errors
+ * @val: Input u16 value, may contain invalid negative overflows
+ *
+ * Convert u16 to non-negative value. Cast to s16 to detect negative values
+ * caused by calculation errors. Return 0 for negative errors, return
+ * original value if valid.
+ *
+ * Return: Valid u16 value or 0
+ */
+static inline u16 smu_safe_u16_nn(u16 val)
+{
+ s16 tmp = (s16)val;
+
+ return tmp < 0 ? 0 : val;
+}
+
#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu14_driver_if_v14_0_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu14_driver_if_v14_0_0.h
index 1bc30db22f9c..cd44f4254134 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu14_driver_if_v14_0_0.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu14_driver_if_v14_0_0.h
@@ -106,6 +106,7 @@ typedef struct {
#define NUM_FCLK_DPM_LEVELS 8
#define NUM_MEM_PSTATE_LEVELS 4
+#define ISP_ALL_TILES_MASK 0x7FF
typedef struct {
uint32_t UClk;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_0.h
new file mode 100644
index 000000000000..47ddf533b08f
--- /dev/null
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_0.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2025 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef SMU15_DRIVER_IF_V15_0_0_H
+#define SMU15_DRIVER_IF_V15_0_0_H
+
+typedef struct {
+ int32_t value;
+ uint32_t numFractionalBits;
+} FloatInIntFormat_t;
+
+typedef enum {
+ DSPCLK_DCFCLK = 0,
+ DSPCLK_DISPCLK,
+ DSPCLK_PIXCLK,
+ DSPCLK_PHYCLK,
+ DSPCLK_COUNT,
+} DSPCLK_e;
+
+typedef struct {
+ uint16_t Freq; // in MHz
+ uint16_t Vid; // min voltage in SVI3 VID
+} DisplayClockTable_t;
+
+typedef struct {
+ uint16_t MinClock; // This is either DCFCLK or SOCCLK (in MHz)
+ uint16_t MaxClock; // This is either DCFCLK or SOCCLK (in MHz)
+ uint16_t MinMclk;
+ uint16_t MaxMclk;
+
+ uint8_t WmSetting;
+ uint8_t WmType; // Used for normal pstate change or memory retraining
+ uint8_t Padding[2];
+} WatermarkRowGeneric_t;
+
+#define NUM_WM_RANGES 4
+#define WM_PSTATE_CHG 0
+#define WM_RETRAINING 1
+
+typedef enum {
+ WM_SOCCLK = 0,
+ WM_DCFCLK,
+ WM_COUNT,
+} WM_CLOCK_e;
+
+typedef struct {
+ // Watermarks
+ WatermarkRowGeneric_t WatermarkRow[WM_COUNT][NUM_WM_RANGES];
+
+ uint32_t MmHubPadding[7]; // SMU internal use
+} Watermarks_t;
+
+typedef enum {
+ CUSTOM_DPM_SETTING_GFXCLK,
+ CUSTOM_DPM_SETTING_CCLK,
+ CUSTOM_DPM_SETTING_FCLK_CCX,
+ CUSTOM_DPM_SETTING_FCLK_GFX,
+ CUSTOM_DPM_SETTING_FCLK_STALLS,
+ CUSTOM_DPM_SETTING_LCLK,
+ CUSTOM_DPM_SETTING_COUNT,
+} CUSTOM_DPM_SETTING_e;
+
+typedef struct {
+ uint8_t ActiveHystLimit;
+ uint8_t IdleHystLimit;
+ uint8_t FPS;
+ uint8_t MinActiveFreqType;
+ FloatInIntFormat_t MinActiveFreq;
+ FloatInIntFormat_t PD_Data_limit;
+ FloatInIntFormat_t PD_Data_time_constant;
+ FloatInIntFormat_t PD_Data_error_coeff;
+ FloatInIntFormat_t PD_Data_error_rate_coeff;
+} DpmActivityMonitorCoeffExt_t;
+
+typedef struct {
+ DpmActivityMonitorCoeffExt_t DpmActivityMonitorCoeff[CUSTOM_DPM_SETTING_COUNT];
+} CustomDpmSettings_t;
+
+#define NUM_DCFCLK_DPM_LEVELS 8
+#define NUM_DISPCLK_DPM_LEVELS 8
+#define NUM_DPPCLK_DPM_LEVELS 8
+#define NUM_SOCCLK_DPM_LEVELS 8
+#define NUM_VCN_DPM_LEVELS 8
+#define NUM_SOC_VOLTAGE_LEVELS 8
+#define NUM_VPE_DPM_LEVELS 8
+#define NUM_FCLK_DPM_LEVELS 8
+#define NUM_MEM_PSTATE_LEVELS 4
+
+
+typedef struct {
+ uint32_t UClk;
+ uint32_t MemClk;
+ uint32_t Voltage;
+ uint8_t WckRatio;
+ uint8_t Spare[3];
+} MemPstateTable_t;
+
+//Freq in MHz
+//Voltage in milli volts with 2 fractional bits
+typedef struct {
+ uint32_t DcfClocks[NUM_DCFCLK_DPM_LEVELS];
+ uint32_t DispClocks[NUM_DISPCLK_DPM_LEVELS];
+ uint32_t DppClocks[NUM_DPPCLK_DPM_LEVELS];
+ uint32_t SocClocks[NUM_SOCCLK_DPM_LEVELS];
+ uint32_t VClocks[NUM_VCN_DPM_LEVELS];
+ uint32_t DClocks[NUM_VCN_DPM_LEVELS];
+ uint32_t VPEClocks[NUM_VPE_DPM_LEVELS];
+ uint32_t FclkClocks_Freq[NUM_FCLK_DPM_LEVELS];
+ uint32_t FclkClocks_Voltage[NUM_FCLK_DPM_LEVELS];
+ uint32_t SocVoltage[NUM_SOC_VOLTAGE_LEVELS];
+ MemPstateTable_t MemPstateTable[NUM_MEM_PSTATE_LEVELS];
+
+ uint8_t NumDcfClkLevelsEnabled;
+ uint8_t NumDispClkLevelsEnabled; //Applies to both Dispclk and Dppclk
+ uint8_t NumSocClkLevelsEnabled;
+ uint8_t VcnClkLevelsEnabled; //Applies to both Vclk and Dclk
+
+ uint8_t VpeClkLevelsEnabled;
+ uint8_t NumMemPstatesEnabled;
+ uint8_t NumFclkLevelsEnabled;
+ uint8_t spare;
+
+ uint32_t MinGfxClk;
+ uint32_t MaxGfxClk;
+} DpmClocks_t;
+
+typedef struct {
+ uint16_t CoreFrequency[16]; //Target core frequency [MHz]
+ uint16_t CorePower[16]; //CAC calculated core power [mW]
+ uint16_t CoreTemperature[16]; //TSEN measured core temperature [centi-C]
+ uint16_t GfxTemperature; //TSEN measured GFX temperature [centi-C]
+ uint16_t SocTemperature; //TSEN measured SOC temperature [centi-C]
+ uint16_t StapmOpnLimit; //Maximum IRM defined STAPM power limit [mW]
+ uint16_t StapmCurrentLimit; //Time filtered STAPM power limit [mW]
+ uint16_t InfrastructureCpuMaxFreq; //CCLK frequency limit enforced on classic cores [MHz]
+ uint16_t InfrastructureGfxMaxFreq; //GFXCLK frequency limit enforced on GFX [MHz]
+ uint16_t SkinTemp; //Maximum skin temperature reported by APU and HS2 chassis sensors [centi-C]
+ uint16_t GfxclkFrequency; //Time filtered target GFXCLK frequency [MHz]
+ uint16_t FclkFrequency; //Time filtered target FCLK frequency [MHz]
+ uint16_t GfxActivity; //Time filtered GFX busy % [0-100]
+ uint16_t SocclkFrequency; //Time filtered target SOCCLK frequency [MHz]
+ uint16_t VclkFrequency; //Time filtered target VCLK frequency [MHz]
+ uint16_t VcnActivity; //Time filtered VCN busy % [0-100]
+ uint16_t VpeclkFrequency; //Time filtered target VPECLK frequency [MHz]
+ uint16_t NpuclkFrequency; //Time filtered target NPUCLK frequency [MHz]
+ uint16_t NpuBusy[8]; //Time filtered NPU per-column busy % [0-100]
+ uint16_t DRAMReads; //Time filtered DRAM read bandwidth [MB/sec]
+ uint16_t DRAMWrites; //Time filtered DRAM write bandwidth [MB/sec]
+ uint16_t CoreC0Residency[16]; //Time filtered per-core C0 residency % [0-100]
+ uint16_t NpuPower; //Time filtered NPU power [mW]
+ uint32_t ApuPower; //Time filtered APU power [mW]
+ uint32_t GfxPower; //Time filtered GFX power [mW]
+ uint32_t dGpuPower; //Time filtered dGPU power [mW]
+ uint32_t SocketPower; //Time filtered power used for PPT/STAPM [APU+dGPU] [mW]
+ uint32_t AllCorePower; //Time filtered sum of core power across all cores in the socket [mW]
+ uint32_t FilterAlphaValue; //Metrics table alpha filter time constant [us]
+ uint32_t MetricsCounter; //Counter that is incremented on every metrics table update [PM_TIMER cycles]
+ uint16_t MemclkFrequency; //Time filtered target MEMCLK frequency [MHz]
+ uint16_t AieclkFrequency; //Time filtered target AIECLK frequency [MHz]
+ uint16_t NpuReads; //Time filtered NPU read bandwidth [MB/sec]
+ uint16_t NpuWrites; //Time filtered NPU write bandwidth [MB/sec]
+ uint32_t ThrottleResidency_PROCHOT; //Counter that is incremented on every metrics table update when PROCHOT was engaged [PM_TIMER cycles]
+ uint32_t ThrottleResidency_SPL; //Counter that is incremented on every metrics table update when SPL was engaged [PM_TIMER cycles]
+ uint32_t ThrottleResidency_FPPT; //Counter that is incremented on every metrics table update when fast PPT was engaged [PM_TIMER cycles]
+ uint32_t ThrottleResidency_SPPT; //Counter that is incremented on every metrics table update when slow PPT was engaged [PM_TIMER cycles]
+ uint32_t ThrottleResidency_THM_VDD; //Counter that is incremented on every metrics table update when VDD thermal throttling was engaged [PM_TIMER cycles]
+ uint32_t ThrottleResidency_THM_SOC; //Counter that is incremented on every metrics table update when SOC thermal throttling was engaged [PM_TIMER cycles]
+ uint16_t Psys; //Time filtered Psys power [mW]
+ uint16_t spare1;
+ uint32_t spare[6];
+} SmuMetrics_t;
+
+//ISP tile definitions
+typedef enum {
+ TILE_XTILE = 0, //ONO0
+ TILE_MTILE, //ONO1
+ TILE_PDP, //ONO2
+ TILE_CSTAT, //ONO2
+ TILE_LME, //ONO3
+ TILE_BYRP, //ONO4
+ TILE_GRBP, //ONO4
+ TILE_MCFP, //ONO4
+ TILE_YUVP, //ONO4
+ TILE_MCSC, //ONO4
+ TILE_GDC, //ONO5
+ TILE_MAX
+} TILE_NUM_e;
+
+// Tile Selection (Based on arguments)
+#define ISP_TILE_SEL(tile) (1<<tile)
+#define ISP_TILE_SEL_ALL 0x7FF
+
+// Workload bits
+#define WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT 0
+#define WORKLOAD_PPLIB_VIDEO_BIT 2
+#define WORKLOAD_PPLIB_VR_BIT 3
+#define WORKLOAD_PPLIB_COMPUTE_BIT 4
+#define WORKLOAD_PPLIB_CUSTOM_BIT 5
+#define WORKLOAD_PPLIB_COUNT 6
+
+#define TABLE_BIOS_IF 0 // Called by BIOS
+#define TABLE_WATERMARKS 1 // Called by DAL through VBIOS, for Medusa generation this should no longer be used
+#define TABLE_CUSTOM_DPM 2 // Called by Driver
+#define TABLE_BIOS_GPIO_CONFIG 3 // Called by BIOS
+#define TABLE_DPMCLOCKS 4 // Called by Driver and VBIOS
+#define TABLE_SPARE0 5 // Unused
+#define TABLE_SPARE1 6 // Unused
+#define TABLE_SMU_METRICS 7 // Called by Driver and SMF/PMF
+#define TABLE_COUNT 8
+
+#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_8.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_8.h
new file mode 100644
index 000000000000..6993d866183d
--- /dev/null
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_8.h
@@ -0,0 +1,295 @@
+/*
+ * Copyright 2025 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef SMU_15_0_8_DRIVER_IF_H
+#define SMU_15_0_8_DRIVER_IF_H
+
+//I2C Interface
+#define NUM_I2C_CONTROLLERS 8
+#define I2C_CONTROLLER_ENABLED 1
+#define I2C_CONTROLLER_DISABLED 0
+
+#define MAX_SW_I2C_COMMANDS 24
+
+typedef enum {
+ I2C_CONTROLLER_PORT_0,
+ I2C_CONTROLLER_PORT_COUNT,
+} I2cControllerPort_e;
+
+typedef enum {
+ /* 50 Kbits/s not supported anymore! */
+ UNSUPPORTED_1,
+ /* 100 Kbits/s */
+ I2C_SPEED_STANDARD_100K,
+ /* 400 Kbits/s */
+ I2C_SPEED_FAST_400K,
+ /* 1 Mbits/s (in fast mode) */
+ I2C_SPEED_FAST_PLUS_1M,
+ /* 1 Mbits/s (in high speed mode) not supported anymore!*/
+ UNSUPPORTED_2,
+ /* 2.3 Mbits/s not supported anymore! */
+ UNSUPPORTED_3,
+ I2C_SPEED_COUNT,
+} I2cSpeed_e;
+
+typedef enum {
+ I2C_CMD_READ,
+ I2C_CMD_WRITE,
+ I2C_CMD_COUNT,
+} I2cCmdType_e;
+
+#define CMDCONFIG_STOP_BIT 0
+#define CMDCONFIG_RESTART_BIT 1
+/* bit should be 0 for read, 1 for write */
+#define CMDCONFIG_READWRITE_BIT 2
+
+#define CMDCONFIG_STOP_MASK (1 << CMDCONFIG_STOP_BIT)
+#define CMDCONFIG_RESTART_MASK (1 << CMDCONFIG_RESTART_BIT)
+#define CMDCONFIG_READWRITE_MASK (1 << CMDCONFIG_READWRITE_BIT)
+
+/* 64 Bit register offsets for PPSMC_MSG_McaBankDumpDW, PPSMC_MSG_McaBankCeDumpDW messages
+ * eg to read MCA_BANK_OFFSET_SYND for CE index, call PPSMC_MSG_McaBankCeDumpDW twice,
+ * (index << 16 + MCA_BANK_OFFSET_SYND*8) argument for 1st DWORD, and
+ * ((index << 16 ) + MCA_BANK_OFFSET_SYND*8 + 4) argument for 2nd DWORD */
+typedef enum {
+ MCA_BANK_OFFSET_CTL = 0,
+ MCA_BANK_OFFSET_STATUS = 1,
+ MCA_BANK_OFFSET_ADDR = 2,
+ MCA_BANK_OFFSET_MISC = 3,
+ MCA_BANK_OFFSET_IPID = 5,
+ MCA_BANK_OFFSET_SYND = 6,
+ MCA_BANK_OFFSET_MAX = 16,
+} MCA_BANK_OFFSET_e;
+
+/* Firmware MP1 AID MCA Error Codes stored in MCA_MP_MP1:MCMP1_SYNDT0 errorinformation */
+typedef enum {
+ /* MMHUB */
+ CODE_DAGB0 = 0,
+ CODE_DAGB1 = 1,
+ CODE_DAGB2 = 2,
+ CODE_DAGB3 = 3,
+ CODE_DAGB4 = 4,
+ CODE_EA0 = 5,
+ CODE_EA1 = 6,
+ CODE_EA2 = 7,
+ CODE_EA3 = 8,
+ CODE_EA4 = 9,
+ CODE_UTCL2_ROUTER = 10,
+ CODE_VML2 = 11,
+ CODE_VML2_WALKER = 12,
+ CODE_MMCANE = 13,
+
+ /* VCN VCPU */
+ CODE_VIDD = 14,
+ CODE_VIDV = 15,
+ /* VCN JPEG */
+ CODE_JPEG0S = 16,
+ CODE_JPEG0D = 17,
+ CODE_JPEG1S = 18,
+ CODE_JPEG1D = 19,
+ CODE_JPEG2S = 20,
+ CODE_JPEG2D = 21,
+ CODE_JPEG3S = 22,
+ CODE_JPEG3D = 23,
+ CODE_JPEG4S = 24,
+ CODE_JPEG4D = 25,
+ CODE_JPEG5S = 26,
+ CODE_JPEG5D = 27,
+ CODE_JPEG6S = 28,
+ CODE_JPEG6D = 29,
+ CODE_JPEG7S = 30,
+ CODE_JPEG7D = 31,
+ /* VCN MMSCH */
+ CODE_MMSCHD = 32,
+
+ /* SDMA */
+ CODE_SDMA0 = 33,
+ CODE_SDMA1 = 34,
+ CODE_SDMA2 = 35,
+ CODE_SDMA3 = 36,
+
+ /* SOC */
+ CODE_HDP = 37,
+ CODE_ATHUB = 38,
+ CODE_IH = 39,
+ CODE_XHUB_POISON = 40,
+ CODE_SMN_SLVERR = 41,
+ CODE_WDT = 42,
+
+ CODE_UNKNOWN = 43,
+ CODE_DMA = 44,
+ CODE_COUNT = 45,
+} ERR_CODE_e;
+
+/* Firmware MP5 XCD MCA Error Codes stored in MCA_MP_MP5:MCMP5_SYNDT0 errorinformation */
+typedef enum {
+ /* SH POISON FED */
+ SH_FED_CODE = 0,
+ /* GCEA Pin UE_ERR regs */
+ GCEA_CODE = 1,
+ SQ_CODE = 2,
+ LDS_CODE = 3,
+ GDS_CODE = 4,
+ SP0_CODE = 5,
+ SP1_CODE = 6,
+ TCC_CODE = 7,
+ TCA_CODE = 8,
+ TCX_CODE = 9,
+ CPC_CODE = 10,
+ CPF_CODE = 11,
+ CPG_CODE = 12,
+ SPI_CODE = 13,
+ RLC_CODE = 14,
+ /* GCEA Pin, UE_EDC regs */
+ SQC_CODE = 15,
+ TA_CODE = 16,
+ TD_CODE = 17,
+ TCP_CODE = 18,
+ TCI_CODE = 19,
+ /* GC Router */
+ GC_ROUTER_CODE = 20,
+ VML2_CODE = 21,
+ VML2_WALKER_CODE = 22,
+ ATCL2_CODE = 23,
+ GC_CANE_CODE = 24,
+
+ /* SOC error codes 41-43 are common with ERR_CODE_e */
+ MP5_CODE_SMN_SLVERR = CODE_SMN_SLVERR,
+ MP5_CODE_UNKNOWN = CODE_UNKNOWN,
+} GC_ERROR_CODE_e;
+
+/* SW I2C Command Table */
+typedef struct {
+ /* Return data for read. Data to send for write*/
+ uint8_t ReadWriteData;
+ /* Includes whether associated command should have a stop or restart command,
+ * and is a read or write */
+ uint8_t CmdConfig;
+} SwI2cCmd_t;
+
+/* SW I2C Request Table */
+typedef struct {
+ /* CKSVII2C0(0) or //CKSVII2C1(1) */
+ uint8_t I2CcontrollerPort;
+ /* Use I2cSpeed_e to indicate speed to select */
+ uint8_t I2CSpeed;
+ /* Slave address of device */
+ uint8_t SlaveAddress;
+ /* Number of commands */
+ uint8_t NumCmds;
+ SwI2cCmd_t SwI2cCmds[MAX_SW_I2C_COMMANDS];
+} SwI2cRequest_t;
+
+typedef struct {
+ SwI2cRequest_t SwI2cRequest;
+ uint32_t Spare[8];
+ /* SMU internal use */
+ uint32_t MmHubPadding[8];
+} SwI2cRequestExternal_t;
+
+typedef enum {
+ PPCLK_UCLK,
+ PPCLK_COUNT,
+} PPCLK_e;
+
+typedef enum {
+ GPIO_INT_POLARITY_ACTIVE_LOW,
+ GPIO_INT_POLARITY_ACTIVE_HIGH,
+} GpioIntPolarity_e;
+
+/* TODO confirm if this is used in MI300 PPSMC_MSG_SetUclkDpmMode */
+typedef enum {
+ UCLK_DPM_MODE_BANDWIDTH,
+ UCLK_DPM_MODE_LATENCY,
+} UCLK_DPM_MODE_e;
+
+typedef struct {
+ /* 2 AVFS.PSM chains */
+ uint16_t AvgPsmCount_Chain0[13];
+ uint16_t AvgPsmCount_Chain1[15];
+ uint16_t MinPsmCount_Chain0[13];
+ uint16_t MinPsmCount_Chain1[15];
+ float MaxTemperature;
+
+ /* For voltage conversions, these are the array indexes
+ * 0:SOCIO
+ * 1:065_UCIE
+ * 2:075_UCIE
+ * 3:11_GTA
+ * 4:075_GTA */
+ float MinPsmVoltage[5];
+ float AvgPsmVoltage[5];
+} AvfsDebugTableMid_t;
+
+typedef struct {
+ /* 7 AVFS.PSM chains - not including TRO */
+ uint16_t AvgPsmCount_Chain0[15];
+ uint16_t AvgPsmCount_Chain1[15];
+ uint16_t AvgPsmCount_Chain2[13];
+ uint16_t AvgPsmCount_Chain3[13];
+ uint16_t AvgPsmCount_Chain4[15];
+ uint16_t AvgPsmCount_Chain5[15];
+ uint16_t AvgPsmCount_Chain6[5];
+ uint16_t MinPsmCount_Chain0[15];
+ uint16_t MinPsmCount_Chain1[15];
+ uint16_t MinPsmCount_Chain2[13];
+ uint16_t MinPsmCount_Chain3[13];
+ uint16_t MinPsmCount_Chain4[15];
+ uint16_t MinPsmCount_Chain5[15];
+ uint16_t MinPsmCount_Chain6[5];
+ float MaxTemperature;
+
+ /* For voltage conversions, these are the array indexes
+ * 0:VDDX */
+ float MinPsmVoltage;
+ float AvgPsmVoltage;
+} AvfsDebugTableAid_t;
+
+typedef struct {
+ /* 0-27 GFX, 28-29 SOC */
+ uint16_t avgPsmCount[30];
+ uint16_t minPsmCount[30];
+ float avgPsmVoltage[30];
+ float minPsmVoltage[30];
+} AvfsDebugTableXcd_t;
+
+/* Defines used for IH-based thermal interrupts to GFX driver - A/X only */
+#define IH_INTERRUPT_ID_TO_DRIVER 0xFE
+#define IH_INTERRUPT_CONTEXT_ID_THERMAL_THROTTLING 0x7
+#define IH_INTERRUPT_VFFLR_INT 0xA
+
+/* thermal over-temp mask defines for IH interrup to host */
+#define THROTTLER_PROCHOT_BIT 0
+#define THROTTLER_RESERVED 1
+/* AID, XCD, CCD throttling */
+#define THROTTLER_THERMAL_SOCKET_BIT 2
+/* VRHOT */
+#define THROTTLER_THERMAL_VR_BIT 3
+#define THROTTLER_THERMAL_HBM_BIT 4
+/* UEs are always reported, set flag to 0 to prevent clearing of UEs */
+#define ClearMcaOnRead_UE_FLAG_MASK 0x1
+/* Enable CE logging and clearing to driver */
+#define ClearMcaOnRead_CE_POLL_MASK 0x2
+/* AID MMHUB client IP CE Logging and clearing */
+#define ClearMcaOnRead_MMHUB_POLL_MASK 0x4
+
+#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_pmfw.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_pmfw.h
new file mode 100644
index 000000000000..acf7b2f43b0e
--- /dev/null
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_pmfw.h
@@ -0,0 +1,386 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef SMU_13_0_12_PMFW_H
+#define SMU_13_0_12_PMFW_H
+
+#define NUM_VCLK_DPM_LEVELS 4
+#define NUM_DCLK_DPM_LEVELS 4
+#define NUM_SOCCLK_DPM_LEVELS 4
+#define NUM_LCLK_DPM_LEVELS 4
+#define NUM_UCLK_DPM_LEVELS 4
+#define NUM_FCLK_DPM_LEVELS 4
+#define NUM_XGMI_DPM_LEVELS 2
+#define NUM_CXL_BITRATES 4
+#define NUM_PCIE_BITRATES 4
+#define NUM_XGMI_BITRATES 4
+#define NUM_XGMI_WIDTHS 3
+#define NUM_TDP_GROUPS 4
+#define NUM_SOC_P2S_TABLES 6
+#define NUM_GFX_P2S_TABLES 8
+#define NUM_PSM_DIDT_THRESHOLDS 3
+#define NUM_XVMIN_VMIN_THRESHOLDS 3
+
+#define PRODUCT_MODEL_NUMBER_LEN 20
+#define PRODUCT_NAME_LEN 64
+#define PRODUCT_SERIAL_LEN 20
+#define PRODUCT_MANUFACTURER_NAME_LEN 32
+#define PRODUCT_FRU_ID_LEN 32
+
+typedef enum {
+/*0*/ FEATURE_DATA_CALCULATION = 0,
+/*1*/ FEATURE_DPM_FCLK = 1,
+/*2*/ FEATURE_DPM_GFXCLK = 2,
+/*3*/ FEATURE_DPM_LCLK = 3,
+/*4*/ FEATURE_DPM_SOCCLK = 4,
+/*5*/ FEATURE_DPM_UCLK = 5,
+/*6*/ FEATURE_DPM_VCN = 6,
+/*7*/ FEATURE_DPM_XGMI = 7,
+/*8*/ FEATURE_DS_FCLK = 8,
+/*9*/ FEATURE_DS_GFXCLK = 9,
+/*10*/ FEATURE_DS_LCLK = 10,
+/*11*/ FEATURE_DS_MP0CLK = 11,
+/*12*/ FEATURE_DS_MP1CLK = 12,
+/*13*/ FEATURE_DS_MPIOCLK = 13,
+/*14*/ FEATURE_DS_SOCCLK = 14,
+/*15*/ FEATURE_DS_VCN = 15,
+/*16*/ FEATURE_APCC_DFLL = 16,
+/*17*/ FEATURE_APCC_PLUS = 17,
+/*18*/ FEATURE_PPT = 18,
+/*19*/ FEATURE_TDC = 19,
+/*20*/ FEATURE_THERMAL = 20,
+/*21*/ FEATURE_SOC_PCC = 21,
+/*22*/ FEATURE_PROCHOT = 22,
+/*23*/ FEATURE_FDD_AID_HBM = 23,
+/*24*/ FEATURE_FDD_AID_SOC = 24,
+/*25*/ FEATURE_FDD_XCD_EDC = 25,
+/*26*/ FEATURE_FDD_XCD_XVMIN = 26,
+/*27*/ FEATURE_FW_CTF = 27,
+/*28*/ FEATURE_SMU_CG = 28,
+/*29*/ FEATURE_PSI7 = 29,
+/*30*/ FEATURE_XGMI_PER_LINK_PWR_DOWN = 30,
+/*31*/ FEATURE_SOC_DC_RTC = 31,
+/*32*/ FEATURE_GFX_DC_RTC = 32,
+/*33*/ FEATURE_DVM_MIN_PSM = 33,
+/*34*/ FEATURE_PRC = 34,
+/*35*/ FEATURE_PSM_SQ_THROTTLER = 35,
+/*36*/ FEATURE_PIT = 36,
+/*37*/ FEATURE_DVO = 37,
+/*38*/ FEATURE_XVMINORPSM_CLKSTOP_DS = 38,
+/*39*/ FEATURE_GLOBAL_DPM = 39,
+/*40*/ FEATURE_HROM_EN = 40,
+
+/*41*/ NUM_FEATURES = 41
+} FEATURE_LIST_e;
+
+//enum for MPIO PCIe gen speed msgs
+typedef enum {
+ PCIE_LINK_SPEED_INDEX_TABLE_RESERVED,
+ PCIE_LINK_SPEED_INDEX_TABLE_GEN1,
+ PCIE_LINK_SPEED_INDEX_TABLE_GEN2,
+ PCIE_LINK_SPEED_INDEX_TABLE_GEN3,
+ PCIE_LINK_SPEED_INDEX_TABLE_GEN4,
+ PCIE_LINK_SPEED_INDEX_TABLE_GEN5,
+ PCIE_LINK_SPEED_INDEX_TABLE_COUNT
+} PCIE_LINK_SPEED_INDEX_TABLE_e;
+
+typedef enum {
+ GFX_GUARDBAND_OFFSET_0,
+ GFX_GUARDBAND_OFFSET_1,
+ GFX_GUARDBAND_OFFSET_2,
+ GFX_GUARDBAND_OFFSET_3,
+ GFX_GUARDBAND_OFFSET_4,
+ GFX_GUARDBAND_OFFSET_5,
+ GFX_GUARDBAND_OFFSET_6,
+ GFX_GUARDBAND_OFFSET_7,
+ GFX_GUARDBAND_OFFSET_COUNT
+} GFX_GUARDBAND_OFFSET_e;
+
+typedef enum {
+ GFX_DVM_MARGINHI_0,
+ GFX_DVM_MARGINHI_1,
+ GFX_DVM_MARGINHI_2,
+ GFX_DVM_MARGINHI_3,
+ GFX_DVM_MARGINHI_4,
+ GFX_DVM_MARGINHI_5,
+ GFX_DVM_MARGINHI_6,
+ GFX_DVM_MARGINHI_7,
+ GFX_DVM_MARGINLO_0,
+ GFX_DVM_MARGINLO_1,
+ GFX_DVM_MARGINLO_2,
+ GFX_DVM_MARGINLO_3,
+ GFX_DVM_MARGINLO_4,
+ GFX_DVM_MARGINLO_5,
+ GFX_DVM_MARGINLO_6,
+ GFX_DVM_MARGINLO_7,
+ GFX_DVM_MARGIN_COUNT
+} GFX_DVM_MARGIN_e;
+
+typedef enum{
+ SYSTEM_TEMP_UBB_FPGA,
+ SYSTEM_TEMP_UBB_FRONT,
+ SYSTEM_TEMP_UBB_BACK,
+ SYSTEM_TEMP_UBB_OAM7,
+ SYSTEM_TEMP_UBB_IBC,
+ SYSTEM_TEMP_UBB_UFPGA,
+ SYSTEM_TEMP_UBB_OAM1,
+ SYSTEM_TEMP_OAM_0_1_HSC,
+ SYSTEM_TEMP_OAM_2_3_HSC,
+ SYSTEM_TEMP_OAM_4_5_HSC,
+ SYSTEM_TEMP_OAM_6_7_HSC,
+ SYSTEM_TEMP_UBB_FPGA_0V72_VR,
+ SYSTEM_TEMP_UBB_FPGA_3V3_VR,
+ SYSTEM_TEMP_RETIMER_0_1_2_3_1V2_VR,
+ SYSTEM_TEMP_RETIMER_4_5_6_7_1V2_VR,
+ SYSTEM_TEMP_RETIMER_0_1_0V9_VR,
+ SYSTEM_TEMP_RETIMER_4_5_0V9_VR,
+ SYSTEM_TEMP_RETIMER_2_3_0V9_VR,
+ SYSTEM_TEMP_RETIMER_6_7_0V9_VR,
+ SYSTEM_TEMP_OAM_0_1_2_3_3V3_VR,
+ SYSTEM_TEMP_OAM_4_5_6_7_3V3_VR,
+ SYSTEM_TEMP_IBC_HSC,
+ SYSTEM_TEMP_IBC,
+ SYSTEM_TEMP_MAX_ENTRIES = 32
+} SYSTEM_TEMP_e;
+
+typedef enum{
+ NODE_TEMP_RETIMER,
+ NODE_TEMP_IBC_TEMP,
+ NODE_TEMP_IBC_2_TEMP,
+ NODE_TEMP_VDD18_VR_TEMP,
+ NODE_TEMP_04_HBM_B_VR_TEMP,
+ NODE_TEMP_04_HBM_D_VR_TEMP,
+ NODE_TEMP_MAX_TEMP_ENTRIES = 12
+} NODE_TEMP_e;
+
+typedef enum {
+ SVI_VDDCR_VDD0_TEMP,
+ SVI_VDDCR_VDD1_TEMP,
+ SVI_VDDCR_VDD2_TEMP,
+ SVI_VDDCR_VDD3_TEMP,
+ SVI_VDDCR_SOC_A_TEMP,
+ SVI_VDDCR_SOC_C_TEMP,
+ SVI_VDDCR_SOCIO_A_TEMP,
+ SVI_VDDCR_SOCIO_C_TEMP,
+ SVI_VDD_085_HBM_TEMP,
+ SVI_VDDCR_11_HBM_B_TEMP,
+ SVI_VDDCR_11_HBM_D_TEMP,
+ SVI_VDD_USR_TEMP,
+ SVI_VDDIO_11_E32_TEMP,
+ SVI_MAX_TEMP_ENTRIES, // 13
+} SVI_TEMP_e;
+
+typedef enum{
+ SYSTEM_POWER_UBB_POWER,
+ SYSTEM_POWER_UBB_POWER_THRESHOLD,
+ SYSTEM_POWER_MAX_ENTRIES_WO_RESERVED,
+ SYSTEM_POWER_MAX_ENTRIES = 4
+} SYSTEM_POWER_e;
+
+#define SMU_METRICS_TABLE_VERSION 0x15
+
+#define SMU_SYSTEM_METRICS_TABLE_VERSION 0x1
+
+typedef struct __attribute__((packed, aligned(4))) {
+ uint64_t AccumulationCounter;
+
+ //TEMPERATURE
+ uint32_t MaxSocketTemperature;
+ uint32_t MaxVrTemperature;
+ uint32_t MaxHbmTemperature;
+ uint64_t MaxSocketTemperatureAcc;
+ uint64_t MaxVrTemperatureAcc;
+ uint64_t MaxHbmTemperatureAcc;
+
+ //POWER
+ uint32_t SocketPowerLimit;
+ uint32_t SocketPower;
+
+ //ENERGY
+ uint64_t Timestamp;
+ uint64_t SocketEnergyAcc;
+ uint64_t XcdEnergyAcc;
+ uint64_t AidEnergyAcc;
+ uint64_t HbmEnergyAcc;
+
+ //FREQUENCY
+ uint32_t GfxclkFrequencyLimit;
+ uint32_t FclkFrequency;
+ uint32_t UclkFrequency;
+ uint32_t SocclkFrequency[4];
+ uint32_t VclkFrequency[4];
+ uint32_t DclkFrequency[4];
+ uint32_t LclkFrequency[4];
+ uint64_t GfxclkFrequencyAcc[8];
+
+ //FREQUENCY RANGE
+ uint32_t MaxLclkDpmRange;
+ uint32_t MinLclkDpmRange;
+
+ //XGMI
+ uint32_t XgmiWidth;
+ uint32_t XgmiBitrate;
+ uint64_t XgmiReadBandwidthAcc[8];
+ uint64_t XgmiWriteBandwidthAcc[8];
+
+ //ACTIVITY
+ uint32_t SocketGfxBusy;
+ uint32_t DramBandwidthUtilization;
+ uint64_t SocketGfxBusyAcc;
+ uint64_t DramBandwidthAcc;
+ uint32_t MaxDramBandwidth;
+ uint64_t DramBandwidthUtilizationAcc;
+ uint64_t PcieBandwidthAcc[4];
+
+ //THROTTLERS
+ uint32_t ProchotResidencyAcc;
+ uint32_t PptResidencyAcc;
+ uint32_t SocketThmResidencyAcc;
+ uint32_t VrThmResidencyAcc;
+ uint32_t HbmThmResidencyAcc;
+ uint32_t GfxLockXCDMak;
+
+ // New Items at end to maintain driver compatibility
+ uint32_t GfxclkFrequency[8];
+
+ //XGMI Data tranfser size
+ uint64_t XgmiReadDataSizeAcc[8];//in KByte
+ uint64_t XgmiWriteDataSizeAcc[8];//in KByte
+
+ //PCIE BW Data and error count
+ uint32_t PcieBandwidth[4];
+ uint32_t PCIeL0ToRecoveryCountAcc; // The Pcie counter itself is accumulated
+ uint32_t PCIenReplayAAcc; // The Pcie counter itself is accumulated
+ uint32_t PCIenReplayARolloverCountAcc; // The Pcie counter itself is accumulated
+ uint32_t PCIeNAKSentCountAcc; // The Pcie counter itself is accumulated
+ uint32_t PCIeNAKReceivedCountAcc; // The Pcie counter itself is accumulated
+
+ // VCN/JPEG ACTIVITY
+ uint32_t VcnBusy[4];
+ uint32_t JpegBusy[40];
+
+ // PCIE LINK Speed and width
+ uint32_t PCIeLinkSpeed;
+ uint32_t PCIeLinkWidth;
+
+ // PER XCD ACTIVITY
+ uint32_t GfxBusy[8];
+ uint64_t GfxBusyAcc[8];
+
+ //PCIE BW Data and error count
+ uint32_t PCIeOtherEndRecoveryAcc; // The Pcie counter itself is accumulated
+
+ //Total App Clock Counter
+ uint64_t GfxclkBelowHostLimitPptAcc[8];
+ uint64_t GfxclkBelowHostLimitThmAcc[8];
+ uint64_t GfxclkBelowHostLimitTotalAcc[8];
+ uint64_t GfxclkLowUtilizationAcc[8];
+
+ uint32_t AidTemperature[4];
+ uint32_t XcdTemperature[8];
+ uint32_t HbmTemperature[8];
+} MetricsTable_t;
+
+#define SMU_VF_METRICS_TABLE_MASK (1 << 31)
+#define SMU_VF_METRICS_TABLE_VERSION (0x6 | SMU_VF_METRICS_TABLE_MASK)
+
+#pragma pack(push, 4)
+typedef struct {
+ uint64_t AccumulationCounter; // Last update timestamp
+ uint16_t LabelVersion; // Defaults to 0.
+ uint16_t NodeIdentifier; // Unique identifier to each node on system.
+ int16_t SystemTemperatures[SYSTEM_TEMP_MAX_ENTRIES]; // Signed integer temperature value in Celsius, unused fields are set to 0xFFFF
+ int16_t NodeTemperatures[NODE_TEMP_MAX_TEMP_ENTRIES]; // Signed integer temperature value in Celsius, unused fields are set to 0xFFFF
+ int16_t VrTemperatures[SVI_MAX_TEMP_ENTRIES]; // Signed integer temperature value in Celsius
+ int16_t spare[7];
+
+ //NPM: NODE POWER MANAGEMENT
+ uint32_t NodePowerLimit;
+ uint32_t NodePower;
+ uint32_t GlobalPPTResidencyAcc;
+ uint16_t SystemPower[SYSTEM_POWER_MAX_ENTRIES]; // UBB Current Power and Power Threshold
+} SystemMetricsTable_t;
+#pragma pack(pop)
+
+typedef struct __attribute__((packed, aligned(4))) {
+ uint32_t AccumulationCounter;
+ uint32_t InstGfxclk_TargFreq;
+ uint64_t AccGfxclk_TargFreq;
+ uint64_t AccGfxRsmuDpm_Busy;
+ uint64_t AccGfxclkBelowHostLimitPpt;
+ uint64_t AccGfxclkBelowHostLimitThm;
+ uint64_t AccGfxclkBelowHostLimitTotal;
+ uint64_t AccGfxclkLowUtilization;
+} VfMetricsTable_t;
+
+/* FRU product information */
+typedef struct __attribute__((packed, aligned(4))) {
+ uint8_t ModelNumber[PRODUCT_MODEL_NUMBER_LEN];
+ uint8_t Name[PRODUCT_NAME_LEN];
+ uint8_t Serial[PRODUCT_SERIAL_LEN];
+ uint8_t ManufacturerName[PRODUCT_MANUFACTURER_NAME_LEN];
+ uint8_t FruId[PRODUCT_FRU_ID_LEN];
+} FRUProductInfo_t;
+
+#pragma pack(push, 4)
+typedef struct {
+ //FRU PRODUCT INFO
+ FRUProductInfo_t ProductInfo;
+
+ //POWER
+ uint32_t MaxSocketPowerLimit;
+
+ //FREQUENCY RANGE
+ uint32_t MaxGfxclkFrequency;
+ uint32_t MinGfxclkFrequency;
+ uint32_t FclkFrequencyTable[4];
+ uint32_t UclkFrequencyTable[4];
+ uint32_t SocclkFrequencyTable[4];
+ uint32_t VclkFrequencyTable[4];
+ uint32_t DclkFrequencyTable[4];
+ uint32_t LclkFrequencyTable[4];
+
+ //PSNs
+ uint64_t PublicSerialNumber_AID[4];
+ uint64_t PublicSerialNumber_XCD[8];
+
+ //XGMI
+ uint32_t MaxXgmiWidth;
+ uint32_t MaxXgmiBitrate;
+
+ // Telemetry
+ uint32_t InputTelemetryVoltageInmV;
+
+ // General info
+ uint32_t pldmVersion[2];
+
+ //Node Power Limit
+ uint32_t MaxNodePowerLimit;
+
+ // PPT1 Configuration
+ uint32_t PPT1Max;
+ uint32_t PPT1Min;
+ uint32_t PPT1Default;
+} StaticMetricsTable_t;
+#pragma pack(pop)
+
+#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_ppsmc.h
new file mode 100644
index 000000000000..d09b6ae9827e
--- /dev/null
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_ppsmc.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef SMU_13_0_12_PPSMC_H
+#define SMU_13_0_12_PPSMC_H
+
+// SMU Response Codes:
+#define PPSMC_Result_OK 0x1
+#define PPSMC_Result_Failed 0xFF
+#define PPSMC_Result_UnknownCmd 0xFE
+#define PPSMC_Result_CmdRejectedPrereq 0xFD
+#define PPSMC_Result_CmdRejectedBusy 0xFC
+
+// Message Definitions:
+#define PPSMC_MSG_TestMessage 0x1
+#define PPSMC_MSG_GetSmuVersion 0x2
+#define PPSMC_MSG_GfxDriverReset 0x3
+#define PPSMC_MSG_GetDriverIfVersion 0x4
+#define PPSMC_MSG_EnableAllSmuFeatures 0x5
+#define PPSMC_MSG_DisableAllSmuFeatures 0x6
+#define PPSMC_MSG_RequestI2cTransaction 0x7
+#define PPSMC_MSG_GetMetricsVersion 0x8
+#define PPSMC_MSG_GetMetricsTable 0x9
+#define PPSMC_MSG_GetEccInfoTable 0xA
+#define PPSMC_MSG_GetEnabledSmuFeaturesLow 0xB
+#define PPSMC_MSG_GetEnabledSmuFeaturesHigh 0xC
+#define PPSMC_MSG_SetDriverDramAddrHigh 0xD
+#define PPSMC_MSG_SetDriverDramAddrLow 0xE
+#define PPSMC_MSG_SetToolsDramAddrHigh 0xF
+#define PPSMC_MSG_SetToolsDramAddrLow 0x10
+#define PPSMC_MSG_SetSystemVirtualDramAddrHigh 0x11
+#define PPSMC_MSG_SetSystemVirtualDramAddrLow 0x12
+#define PPSMC_MSG_SetSoftMinByFreq 0x13
+#define PPSMC_MSG_SetSoftMaxByFreq 0x14
+#define PPSMC_MSG_GetMinDpmFreq 0x15
+#define PPSMC_MSG_GetMaxDpmFreq 0x16
+#define PPSMC_MSG_GetDpmFreqByIndex 0x17
+#define PPSMC_MSG_SetPptLimit 0x18
+#define PPSMC_MSG_GetPptLimit 0x19
+#define PPSMC_MSG_DramLogSetDramAddrHigh 0x1A
+#define PPSMC_MSG_DramLogSetDramAddrLow 0x1B
+#define PPSMC_MSG_DramLogSetDramSize 0x1C
+#define PPSMC_MSG_GetDebugData 0x1D
+#define PPSMC_MSG_HeavySBR 0x1E
+#define PPSMC_MSG_SetNumBadHbmPagesRetired 0x1F
+#define PPSMC_MSG_DFCstateControl 0x20
+#define PPSMC_MSG_GetGmiPwrDnHyst 0x21
+#define PPSMC_MSG_SetGmiPwrDnHyst 0x22
+#define PPSMC_MSG_GmiPwrDnControl 0x23
+#define PPSMC_MSG_EnterGfxoff 0x24
+#define PPSMC_MSG_ExitGfxoff 0x25
+#define PPSMC_MSG_EnableDeterminism 0x26
+#define PPSMC_MSG_DisableDeterminism 0x27
+#define PPSMC_MSG_DumpSTBtoDram 0x28
+#define PPSMC_MSG_STBtoDramLogSetDramAddrHigh 0x29
+#define PPSMC_MSG_STBtoDramLogSetDramAddrLow 0x2A
+#define PPSMC_MSG_STBtoDramLogSetDramSize 0x2B
+#define PPSMC_MSG_SetSystemVirtualSTBtoDramAddrHigh 0x2C
+#define PPSMC_MSG_SetSystemVirtualSTBtoDramAddrLow 0x2D
+#define PPSMC_MSG_GfxDriverResetRecovery 0x2E
+#define PPSMC_MSG_TriggerVFFLR 0x2F
+#define PPSMC_MSG_SetSoftMinGfxClk 0x30
+#define PPSMC_MSG_SetSoftMaxGfxClk 0x31
+#define PPSMC_MSG_GetMinGfxDpmFreq 0x32
+#define PPSMC_MSG_GetMaxGfxDpmFreq 0x33
+#define PPSMC_MSG_PrepareForDriverUnload 0x34
+#define PPSMC_MSG_ReadThrottlerLimit 0x35
+#define PPSMC_MSG_QueryValidMcaCount 0x36
+#define PPSMC_MSG_McaBankDumpDW 0x37
+#define PPSMC_MSG_GetCTFLimit 0x38
+#define PPSMC_MSG_ClearMcaOnRead 0x39
+#define PPSMC_MSG_QueryValidMcaCeCount 0x3A
+#define PPSMC_MSG_McaBankCeDumpDW 0x3B
+#define PPSMC_MSG_SelectPLPDMode 0x40
+#define PPSMC_MSG_PmLogReadSample 0x41
+#define PPSMC_MSG_PmLogGetTableVersion 0x42
+#define PPSMC_MSG_RmaDueToBadPageThreshold 0x43
+#define PPSMC_MSG_SetThrottlingPolicy 0x44
+#define PPSMC_MSG_SetPhaseDetectCSBWThreshold 0x45
+#define PPSMC_MSG_SetPhaseDetectFreqHigh 0x46
+#define PPSMC_MSG_SetPhaseDetectFreqLow 0x47
+#define PPSMC_MSG_SetPhaseDetectDownHysterisis 0x48
+#define PPSMC_MSG_SetPhaseDetectAlphaX1e6 0x49
+#define PPSMC_MSG_SetPhaseDetectOnOff 0x4A
+#define PPSMC_MSG_GetPhaseDetectResidency 0x4B
+#define PPSMC_MSG_UpdatePccWaitDecMaxStr 0x4C
+#define PPSMC_MSG_ResetSDMA 0x4D
+#define PPSMC_MSG_GetRasTableVersion 0x4E
+#define PPSMC_MSG_GetBadPageCount 0x50
+#define PPSMC_MSG_GetBadPageMcaAddress 0x51
+#define PPSMC_MSG_SetTimestamp 0x53
+#define PPSMC_MSG_SetTimestampHi 0x54
+#define PPSMC_MSG_GetTimestamp 0x55
+#define PPSMC_MSG_GetBadPageIpIdLoHi 0x57
+#define PPSMC_MSG_EraseRasTable 0x58
+#define PPSMC_MSG_GetStaticMetricsTable 0x59
+#define PPSMC_MSG_ResetVfArbitersByIndex 0x5A
+#define PPSMC_MSG_GetSystemMetricsTable 0x5C
+#define PPSMC_MSG_GetSystemMetricsVersion 0x5D
+#define PPSMC_MSG_ResetVCN 0x5E
+#define PPSMC_MSG_SetFastPptLimit 0x5F
+#define PPSMC_MSG_GetFastPptLimit 0x60
+#define PPSMC_Message_Count 0x61
+
+//PPSMC Reset Types for driver msg argument
+#define PPSMC_RESET_TYPE_DRIVER_MODE_1_RESET 0x1
+#define PPSMC_RESET_TYPE_DRIVER_MODE_2_RESET 0x2
+#define PPSMC_RESET_TYPE_DRIVER_MODE_3_RESET 0x3
+
+//PPSMC Reset Types for driver msg argument
+#define PPSMC_THROTTLING_LIMIT_TYPE_SOCKET 0x1
+#define PPSMC_THROTTLING_LIMIT_TYPE_HBM 0x2
+
+//CTF/Throttle Limit types
+#define PPSMC_AID_THM_TYPE 0x1
+#define PPSMC_CCD_THM_TYPE 0x2
+#define PPSMC_XCD_THM_TYPE 0x3
+#define PPSMC_HBM_THM_TYPE 0x4
+
+//PLPD modes
+#define PPSMC_PLPD_MODE_DEFAULT 0x1
+#define PPSMC_PLPD_MODE_OPTIMIZED 0x2
+
+typedef uint32_t PPSMC_Result;
+typedef uint32_t PPSMC_MSG;
+
+#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h
index 274b3e1cc4fb..01790a927930 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h
@@ -127,8 +127,9 @@ typedef enum {
VOLTAGE_GUARDBAND_COUNT
} GFX_GUARDBAND_e;
-#define SMU_METRICS_TABLE_VERSION 0xF
+#define SMU_METRICS_TABLE_VERSION 0x11
+// Unified metrics table for smu_v13_0_6
typedef struct __attribute__((packed, aligned(4))) {
uint32_t AccumulationCounter;
@@ -240,9 +241,13 @@ typedef struct __attribute__((packed, aligned(4))) {
uint32_t PCIeOtherEndRecoveryAcc; // The Pcie counter itself is accumulated
//Total App Clock Counter
- uint64_t GfxclkBelowHostLimitAcc[8];
-} MetricsTableX_t;
+ uint64_t GfxclkBelowHostLimitPptAcc[8];
+ uint64_t GfxclkBelowHostLimitThmAcc[8];
+ uint64_t GfxclkBelowHostLimitTotalAcc[8];
+ uint64_t GfxclkLowUtilizationAcc[8];
+} MetricsTableV0_t;
+// Metrics table for smu_v13_0_6 APUS
typedef struct __attribute__((packed, aligned(4))) {
uint32_t AccumulationCounter;
@@ -333,7 +338,116 @@ typedef struct __attribute__((packed, aligned(4))) {
// VCN/JPEG ACTIVITY
uint32_t VcnBusy[4];
uint32_t JpegBusy[32];
-} MetricsTableA_t;
+} MetricsTableV1_t;
+
+// Metrics table for smu_v13_0_12
+typedef struct __attribute__((packed, aligned(4))) {
+ uint64_t AccumulationCounter;
+
+ //TEMPERATURE
+ uint32_t MaxSocketTemperature;
+ uint32_t MaxVrTemperature;
+ uint32_t MaxHbmTemperature;
+ uint64_t MaxSocketTemperatureAcc;
+ uint64_t MaxVrTemperatureAcc;
+ uint64_t MaxHbmTemperatureAcc;
+
+ //POWER
+ uint32_t SocketPowerLimit;
+ uint32_t MaxSocketPowerLimit;
+ uint32_t SocketPower;
+
+ //ENERGY
+ uint64_t Timestamp;
+ uint64_t SocketEnergyAcc;
+ uint64_t CcdEnergyAcc;
+ uint64_t XcdEnergyAcc;
+ uint64_t AidEnergyAcc;
+ uint64_t HbmEnergyAcc;
+
+ //FREQUENCY
+ uint32_t GfxclkFrequencyLimit;
+ uint32_t FclkFrequency;
+ uint32_t UclkFrequency;
+ uint32_t SocclkFrequency[4];
+ uint32_t VclkFrequency[4];
+ uint32_t DclkFrequency[4];
+ uint32_t LclkFrequency[4];
+ uint64_t GfxclkFrequencyAcc[8];
+
+ //FREQUENCY RANGE
+ uint32_t MaxGfxclkFrequency;
+ uint32_t MinGfxclkFrequency;
+ uint32_t FclkFrequencyTable[4];
+ uint32_t UclkFrequencyTable[4];
+ uint32_t SocclkFrequencyTable[4];
+ uint32_t VclkFrequencyTable[4];
+ uint32_t DclkFrequencyTable[4];
+ uint32_t LclkFrequencyTable[4];
+ uint32_t MaxLclkDpmRange;
+ uint32_t MinLclkDpmRange;
+
+ //XGMI
+ uint32_t XgmiWidth;
+ uint32_t XgmiBitrate;
+ uint64_t XgmiReadBandwidthAcc[8];
+ uint64_t XgmiWriteBandwidthAcc[8];
+
+ //ACTIVITY
+ uint32_t SocketGfxBusy;
+ uint32_t DramBandwidthUtilization;
+ uint64_t SocketC0ResidencyAcc;
+ uint64_t SocketGfxBusyAcc;
+ uint64_t DramBandwidthAcc;
+ uint32_t MaxDramBandwidth;
+ uint64_t DramBandwidthUtilizationAcc;
+ uint64_t PcieBandwidthAcc[4];
+
+ //THROTTLERS
+ uint32_t ProchotResidencyAcc;
+ uint32_t PptResidencyAcc;
+ uint32_t SocketThmResidencyAcc;
+ uint32_t VrThmResidencyAcc;
+ uint32_t HbmThmResidencyAcc;
+ uint32_t GfxLockXCDMak;
+
+ // New Items at end to maintain driver compatibility
+ uint32_t GfxclkFrequency[8];
+
+ //PSNs
+ uint64_t PublicSerialNumber_AID[4];
+ uint64_t PublicSerialNumber_XCD[8];
+
+ //XGMI Data tranfser size
+ uint64_t XgmiReadDataSizeAcc[8];//in KByte
+ uint64_t XgmiWriteDataSizeAcc[8];//in KByte
+
+ //PCIE BW Data and error count
+ uint32_t PcieBandwidth[4];
+ uint32_t PCIeL0ToRecoveryCountAcc; // The Pcie counter itself is accumulated
+ uint32_t PCIenReplayAAcc; // The Pcie counter itself is accumulated
+ uint32_t PCIenReplayARolloverCountAcc; // The Pcie counter itself is accumulated
+ uint32_t PCIeNAKSentCountAcc; // The Pcie counter itself is accumulated
+ uint32_t PCIeNAKReceivedCountAcc; // The Pcie counter itself is accumulated
+
+ // VCN/JPEG ACTIVITY
+ uint32_t VcnBusy[4];
+ uint32_t JpegBusy[32];
+
+ // PCIE LINK Speed and width
+ uint32_t PCIeLinkSpeed;
+ uint32_t PCIeLinkWidth;
+
+ // PER XCD ACTIVITY
+ uint32_t GfxBusy[8];
+ uint64_t GfxBusyAcc[8];
+
+ //PCIE BW Data and error count
+ uint32_t PCIeOtherEndRecoveryAcc; // The Pcie counter itself is accumulated
+
+ //Total App Clock Counter
+ uint64_t GfxclkBelowHostLimitAcc[8];
+} MetricsTableV2_t;
#define SMU_VF_METRICS_TABLE_VERSION 0x5
@@ -345,4 +459,13 @@ typedef struct __attribute__((packed, aligned(4))) {
uint64_t AccGfxclkBelowHostLimit;
} VfMetricsTable_t;
+#pragma pack(push, 4)
+typedef struct {
+ // Telemetry
+ uint32_t InputTelemetryVoltageInmV;
+ // General info
+ uint32_t pldmVersion[2];
+} StaticMetricsTable_t;
+#pragma pack(pop)
+
#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_ppsmc.h
index 147bfb12fd75..63a088ef7169 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_ppsmc.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_ppsmc.h
@@ -92,9 +92,11 @@
#define PPSMC_MSG_McaBankCeDumpDW 0x3B
#define PPSMC_MSG_SelectPLPDMode 0x40
#define PPSMC_MSG_RmaDueToBadPageThreshold 0x43
-#define PPSMC_MSG_SelectPstatePolicy 0x44
+#define PPSMC_MSG_SetThrottlingPolicy 0x44
#define PPSMC_MSG_ResetSDMA 0x4D
-#define PPSMC_Message_Count 0x4E
+#define PPSMC_MSG_GetStaticMetricsTable 0x59
+#define PPSMC_MSG_ResetVCN 0x5B
+#define PPSMC_Message_Count 0x5C
//PPSMC Reset Types for driver msg argument
#define PPSMC_RESET_TYPE_DRIVER_MODE_1_RESET 0x1
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_pmfw.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_pmfw.h
new file mode 100644
index 000000000000..c3b67ffa1bfa
--- /dev/null
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_pmfw.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2025 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef SMU15_DRIVER_IF_V15_0_H
+#define SMU15_DRIVER_IF_V15_0_H
+
+#include "smu15_driver_if_v15_0_0.h"
+
+#pragma pack(push, 1)
+
+#define ENABLE_DEBUG_FEATURES
+
+// Firmware features
+// Feature Control Defines
+#define FEATURE_CCLK_DPM_BIT 0
+#define FEATURE_FAN_CONTROLLER_BIT 1
+#define FEATURE_DATA_CALCULATION_BIT 2
+#define FEATURE_PPT_BIT 3
+#define FEATURE_TDC_BIT 4
+#define FEATURE_THERMAL_BIT 5
+#define FEATURE_FIT_BIT 6
+#define FEATURE_EDC_BIT 7
+#define FEATURE_PLL_POWER_DOWN_BIT 8
+#define FEATURE_VDDOFF_BIT 9
+#define FEATURE_VCN_DPM_BIT 10
+#define FEATURE_DS_MPM_BIT 11
+#define FEATURE_FCLK_DPM_BIT 12
+#define FEATURE_SOCCLK_DPM_BIT 13
+#define FEATURE_DS_MPIO_BIT 14
+#define FEATURE_LCLK_DPM_BIT 15
+#define FEATURE_SHUBCLK_DPM_BIT 16
+#define FEATURE_DCFCLK_DPM_BIT 17
+#define FEATURE_ISP_DPM_BIT 18
+#define FEATURE_NPU_DPM_BIT 19
+#define FEATURE_GFX_DPM_BIT 20
+#define FEATURE_DS_GFXCLK_BIT 21
+#define FEATURE_DS_SOCCLK_BIT 22
+#define FEATURE_DS_LCLK_BIT 23
+#define FEATURE_LOW_POWER_DCNCLKS_BIT 24 // for all DISP clks
+#define FEATURE_DS_SHUBCLK_BIT 25
+#define FEATURE_VRHOT_BIT 26
+#define FEATURE_Z8_BIT 27
+#define FEATURE_PCC_BIT 28
+#define FEATURE_DS_FCLK_BIT 29
+#define FEATURE_DS_SMNCLK_BIT 30
+#define FEATURE_DS_MP1CLK_BIT 31
+#define FEATURE_SPM_BIT 32
+#define FEATURE_SMU_LOW_POWER_BIT 33
+#define FEATURE_SMART_L3_RINSER_BIT 34 // Amit: it is spare
+#define FEATURE_DS_DACCCLK_BIT 35
+#define FEATURE_PSI_BIT 36
+#define FEATURE_PROCHOT_BIT 37
+#define FEATURE_CPUOFF_BIT 38
+#define FEATURE_STAPM_BIT 39
+#define FEATURE_S0I3_BIT 40
+#define FEATURE_DF_LIGHT_CSTATE 41
+#define FEATURE_PERF_LIMIT_BIT 42
+#define FEATURE_CORE_DLDO_BIT 43
+#define FEATURE_DVO_BIT 44
+#define FEATURE_DS_VCN_BIT 45
+#define FEATURE_CPPC_BIT 46
+#define FEATURE_CPPC_PREFERRED_CORES 47
+#define FEATURE_DF_CSTATES_BIT 48
+#define FEATURE_CSTATE_BOOST_BIT 49
+#define FEATURE_ATHUB_PG_BIT 50
+#define FEATURE_VDDOFF_ECO_BIT 51
+#define FEATURE_SC_DIDT_BIT 52 //SC_DIDT
+#define FEATURE_CC6_BIT 53
+#define FEATURE_DS_UMCCLK_BIT 54
+#define FEATURE_DS_ISPCLK_BIT 55
+#define FEATURE_DS_HSPCLK_BIT 56
+#define FEATURE_P3T_BIT 57
+#define FEATURE_DS_NPUCLK_BIT 58
+#define FEATURE_DS_VPECLK_BIT 59
+#define FEATURE_VPE_DPM_BIT 60
+#define FEATURE_DACCCLK_DPM_BIT 61
+#define FEATURE_FP_DIDT 62
+#define FEATURE_MMHUB_PG_BIT 63
+#define NUM_FEATURES 64
+
+// Firmware Header/Footer
+struct SMU_Firmware_Footer {
+ uint32_t Signature;
+};
+typedef struct SMU_Firmware_Footer SMU_Firmware_Footer;
+
+// PSP3.0 Header Definition
+typedef struct {
+ uint32_t ImageVersion;
+ uint32_t ImageVersion2; // This is repeated because DW0 cannot be written in SRAM due to HW bug.
+ uint32_t Padding0[3];
+ uint32_t SizeFWSigned;
+ uint32_t Padding1[25];
+ uint32_t FirmwareType;
+ uint32_t Filler[32];
+} SMU_Firmware_Header;
+
+typedef struct {
+ // MP1_EXT_SCRATCH0
+ uint32_t DpmHandlerID : 8;
+ uint32_t ActivityMonitorID : 8;
+ uint32_t DpmTimerID : 8;
+ uint32_t DpmHubID : 4;
+ uint32_t DpmHubTask : 4;
+ // MP1_EXT_SCRATCH1
+ uint32_t CclkSyncStatus : 8;
+ uint32_t Ccx0CpuOff : 2;
+ uint32_t Ccx1CpuOff : 2;
+ uint32_t Ccx2CpuOff : 2;
+ uint32_t GfxOffStatus : 2;
+ uint32_t VddOff : 1;
+ uint32_t InWhisperMode : 1;
+ uint32_t ZstateStatus : 4;
+ uint32_t DcnIps2Status : 2;
+ uint32_t DstateFun : 4;
+ uint32_t DstateDev : 4;
+ // MP1_EXT_SCRATCH2
+ uint32_t P2JobHandler :24;
+ uint32_t RsmuPmiP2PendingCnt : 8;
+ // MP1_EXT_SCRATCH3
+ uint32_t PostCode :32;
+ // MP1_EXT_SCRATCH4
+ uint32_t MsgPortBusy :24;
+ uint32_t RsmuPmiP1Pending : 1;
+ uint32_t DfCstateExitPending : 1;
+ uint32_t Ccx0Pc6ExitPending : 1;
+ uint32_t Ccx1Pc6ExitPending : 1;
+ uint32_t Ccx2Pc6ExitPending : 1;
+ uint32_t WarmResetPending : 1;
+ uint32_t spare1 : 2;
+ // MP1_EXT_SCRATCH5
+ uint32_t IdleMask :32;
+ // MP1_EXT_SCRATCH6 = RTOS threads' status
+ // MP1_EXT_SCRATCH7 = RTOS Current Job
+} FwStatus_t;
+
+
+#pragma pack(pop)
+
+#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_ppsmc.h
new file mode 100644
index 000000000000..bf216f83e689
--- /dev/null
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_ppsmc.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2025 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __SMU_V15_0_0_PPSMC_H__
+#define __SMU_V15_0_0_PPSMC_H__
+
+
+/**
+* @file ppsmc.h
+*
+* @brief pplib (driver/host) to PMFW Interface
+*
+* Clients: Driver/Host via pplib.
+* Protocols:
+*
+* @date 2016 - 2024
+*/
+
+/*! @mainpage PMFW-PPS (PPLib) Message Interface
+ This documentation contains the subsections:\n\n
+ @ref ResponseCodes\n
+ @ref definitions\n
+ @ref enums\n
+*/
+
+/** @def PPS_PMFW_IF_VER
+* PPS (PPLib) to PMFW IF version 1.0
+*/
+#define PPS_PMFW_IF_VER "1.0" ///< Major.Minor
+
+/** @defgroup ResponseCodes PMFW Response Codes
+* @{
+*/
+// SMU Response Codes:
+#define PPSMC_Result_OK 0x1 ///< Message Response OK
+#define PPSMC_Result_Failed 0xFF ///< Message Response Failed
+#define PPSMC_Result_UnknownCmd 0xFE ///< Message Response Unknown Command
+#define PPSMC_Result_CmdRejectedPrereq 0xFD ///< Message Response Command Failed Prerequisite
+#define PPSMC_Result_CmdRejectedBusy 0xFC ///< Message Response Command Rejected due to PMFW is busy. Sender should retry sending this message
+/** @}*/
+
+/** @defgroup definitions Message definitions
+* @{
+*/
+// Message Definitions:
+#define PPSMC_MSG_TestMessage 0x01 ///< To check if PMFW is alive and responding. Requirement specified by PMFW team
+#define PPSMC_MSG_GetPmfwVersion 0x02 ///< Get PMFW version
+#define PPSMC_MSG_GetDriverIfVersion 0x03 ///< Get PMFW_DRIVER_IF version
+#define PPSMC_MSG_PowerDownVcn 0x04 ///< Power down VCN
+#define PPSMC_MSG_PowerUpVcn 0x05 ///< Power up VCN; VCN is power gated by default
+#define PPSMC_MSG_SetSoftMinGfxclk 0x06 ///< Set SoftMin for GFXCLK, argument is frequency in MHz
+#define PPSMC_MSG_PrepareMp1ForUnload 0x07 ///< Prepare PMFW for GFX driver unload
+#define PPSMC_MSG_TransferTableSmu2Dram 0x08 ///< Transfer driver interface table from PMFW SRAM to DRAM
+#define PPSMC_MSG_TransferTableDram2Smu 0x09 ///< Transfer driver interface table from DRAM to PMFW SRAM
+#define PPSMC_MSG_GfxDeviceDriverReset 0x0A ///< Request GFX mode 2 reset
+#define PPSMC_MSG_GetEnabledSmuFeatures 0x0B ///< Get enabled features in PMFW
+#define PPSMC_MSG_SetSoftMinFclk 0x0C ///< Set hard min for FCLK
+#define PPSMC_MSG_SetSoftMinVcn 0x0D ///< Set soft min for VCN clocks (VCLK and DCLK)
+
+#define PPSMC_MSG_EnableGfxImu 0x0E ///< Enable GFX IMU
+
+#define PPSMC_MSG_AllowGfxOff 0x0F ///< Inform PMFW of allowing GFXOFF entry
+#define PPSMC_MSG_DisallowGfxOff 0x10 ///< Inform PMFW of disallowing GFXOFF entry
+#define PPSMC_MSG_SetSoftMaxGfxClk 0x11 ///< Set soft max for GFX CLK
+
+#define PPSMC_MSG_SetSoftMaxSocclkByFreq 0x12 ///< Set soft max for SOC CLK
+#define PPSMC_MSG_SetSoftMaxFclkByFreq 0x13 ///< Set soft max for FCLK
+#define PPSMC_MSG_SetSoftMaxVcn 0x14 ///< Set soft max for VCN clocks (VCLK and DCLK)
+#define PPSMC_MSG_PowerDownJpeg 0x15 ///< Power down Jpeg
+#define PPSMC_MSG_PowerUpJpeg 0x16 ///< Power up Jpeg; VCN is power gated by default
+
+#define PPSMC_MSG_SetSoftMinSocclkByFreq 0x17 ///< Set soft min for SOC CLK
+#define PPSMC_MSG_AllowZstates 0x18 ///< Inform PMFM of allowing Zstate entry, i.e. no Miracast activity
+#define PPSMC_MSG_GetSmartShiftStatus 0x19 ///< Returns SmartShift enable vs disable
+#define PPSMC_MSG_PowerDownUmsch 0x1A ///< Power down VCN.UMSCH (aka VSCH) scheduler
+#define PPSMC_MSG_PowerUpUmsch 0x1B ///< Power up VCN.UMSCH (aka VSCH) scheduler
+#define PPSMC_MSG_PowerUpVpe 0x1C ///< Power up VPE
+#define PPSMC_MSG_PowerDownVpe 0x1D ///< Power down VPE
+#define PPSMC_MSG_EnableLSdma 0x1E ///< Enable LSDMA
+#define PPSMC_MSG_DisableLSdma 0x1F ///< Disable LSDMA
+#define PPSMC_MSG_SetSoftMaxVpe 0x20 ///<
+#define PPSMC_MSG_SetSoftMinVpe 0x21 ///<
+#define PPSMC_Message_Count 0x22 ///< Total number of PPSMC messages
+/** @}*/
+
+/**
+* @defgroup enums Enum Definitions
+* @{
+*/
+
+/** @enum Mode_Reset_e
+* Mode reset type, argument for PPSMC_MSG_GfxDeviceDriverReset
+*/
+//argument for PPSMC_MSG_GfxDeviceDriverReset
+typedef enum {
+ MODE1_RESET = 1, ///< Mode reset type 1
+ MODE2_RESET = 2 ///< Mode reset type 2
+} Mode_Reset_e;
+
+/** @}*/
+
+/** @enum ZStates_e
+* Zstate types, argument for PPSMC_MSG_AllowZstates
+*/
+//Argument for PPSMC_MSG_AllowZstates
+typedef enum {
+ DISALLOW_ZSTATES = 0, ///< Disallow Zstates
+ ALLOW_ZSTATES_Z8 = 8, ///< Allows Z8 only
+ ALLOW_ZSTATES_Z9 = 9, ///< Allows Z9 and Z8
+} ZStates_e;
+
+/** @}*/
+#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_8_pmfw.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_8_pmfw.h
new file mode 100644
index 000000000000..a3401c4cc20b
--- /dev/null
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_8_pmfw.h
@@ -0,0 +1,427 @@
+/*
+ * Copyright 2025 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef SMU_15_0_8_PMFW_H
+#define SMU_15_0_8_PMFW_H
+
+#define NUM_VCLK_DPM_LEVELS 4
+#define NUM_DCLK_DPM_LEVELS 4
+#define NUM_SOCCLK_DPM_LEVELS 4
+#define NUM_LCLK_DPM_LEVELS 4
+#define NUM_UCLK_DPM_LEVELS 4
+#define NUM_FCLK_DPM_LEVELS 4
+#define NUM_XGMI_DPM_LEVELS 2
+#define NUM_PCIE_BITRATES 4
+#define NUM_XGMI_BITRATES 4
+#define NUM_XGMI_WIDTHS 3
+#define NUM_GFX_P2S_TABLES 8
+#define NUM_PSM_DIDT_THRESHOLDS 3
+#define NUM_XCD_XVMIN_VMIN_THRESHOLDS 3
+
+#define PRODUCT_MODEL_NUMBER_LEN 20
+#define PRODUCT_NAME_LEN 64
+#define PRODUCT_SERIAL_LEN 20
+#define PRODUCT_MANUFACTURER_NAME_LEN 32
+#define PRODUCT_FRU_ID_LEN 32
+
+//Feature ID list
+#define FEATURE_ID_DATA_CALCULATION 1
+#define FEATURE_ID_DPM_FCLK 2
+#define FEATURE_ID_DPM_GFXCLK 3
+#define FEATURE_ID_DPM_SPARE_4 4
+#define FEATURE_ID_DPM_SPARE_5 5
+#define FEATURE_ID_DPM_UCLK 6
+#define FEATURE_ID_DPM_SPARE_7 7
+#define FEATURE_ID_DPM_XGMI 8
+#define FEATURE_ID_DS_FCLK 9
+#define FEATURE_ID_DS_GFXCLK 10
+#define FEATURE_ID_DS_LCLK 11
+#define FEATURE_ID_DS_MP0CLK 12
+#define FEATURE_ID_DS_MP1CLK 13
+#define FEATURE_ID_DS_MPIOCLK 14
+#define FEATURE_ID_DS_SOCCLK 15
+#define FEATURE_ID_DS_VCN 16
+#define FEATURE_ID_PPT 17
+#define FEATURE_ID_TDC 18
+#define FEATURE_ID_THERMAL 19
+#define FEATURE_ID_SOC_PCC 20
+#define FEATURE_ID_PROCHOT 21
+#define FEATURE_ID_XVMIN0_VMIN_AID 22
+#define FEATURE_ID_XVMIN1_DD_AID 23
+#define FEATURE_ID_XVMIN0_VMIN_XCD 24
+#define FEATURE_ID_XVMIN1_DD_XCD 25
+#define FEATURE_ID_FW_CTF 26
+#define FEATURE_ID_MGCG 27
+#define FEATURE_ID_PSI7 28
+#define FEATURE_ID_XGMI_PER_LINK_PWR_DOWN 29
+#define FEATURE_ID_SOC_DC_RTC 30
+#define FEATURE_ID_GFX_DC_RTC 31
+#define FEATURE_ID_DVM_MIN_PSM 32
+#define FEATURE_ID_PRC 33
+#define FEATURE_ID_PSM_DIDT 34
+#define FEATURE_ID_PIT 35
+#define FEATURE_ID_DVO 36
+#define FEATURE_ID_XVMIN_CLKSTOP_DS 37
+#define FEATURE_ID_HBM_THROTTLE_CTRL 38
+#define FEATURE_ID_DPM_GL2CLK 39
+#define FEATURE_ID_GC_CAC_EDC 40
+#define FEATURE_ID_DS_DMABECLK 41
+#define FEATURE_ID_DS_MPIFOECLK 42
+#define FEATURE_ID_DS_MPRASCLK 43
+#define FEATURE_ID_DS_MPNHTCLK 44
+#define FEATURE_ID_DS_FIOCLK 45
+#define FEATURE_ID_DS_DXIOCLK 46
+#define FEATURE_ID_PCC 47
+#define FEATURE_ID_OCP 48
+#define FEATURE_ID_TRO 49
+#define FEATURE_ID_GL2_CAC_EDC 50
+#define FEATURE_ID_SPARE_51 51
+#define FEATURE_ID_GL2_CGCG 52
+#define FEATURE_ID_XCAC 53
+#define FEATURE_ID_DS_GL2CLK 54
+#define FEATURE_ID_FCS_VIN_PCC 55
+#define FEATURE_ID_FCS_VDDX_OCP_WARN 56
+#define FEATURE_ID_FCS_PWRBRK 57
+#define FEATURE_ID_DF_CSTATE 58
+#define FEATURE_ID_ARO 59
+#define FEATURE_ID_PS_PsPowerLimit 60
+#define FEATURE_ID_PS_PsPowerFloor 61
+#define FEATURE_ID_OCPWARNRC 62
+#define FEATURE_ID_XGMI_FOLDING 63
+#define FEATURE_ID_SMU_CG 64
+#define NUM_FEATURES 65
+
+//MGCG Feature ID List
+#define WAFL_CG 0
+#define SMU_FUSE_CG_DEEPSLEEP 1
+#define SMUIO_CG 2
+#define RSMU_MGCG 3
+#define SMU_CLK_MGCG 4
+#define MP5_CG 5
+#define UMC_CG 6
+#define WAFL0_CLK 7
+#define WAFL1_CLK 8
+#define VCN_MGCG 9
+#define GL2_MGCG 10
+#define MGCG_NUM_FEATURES 11
+
+/* enum for MPIO PCIe gen speed msgs */
+typedef enum {
+ PCIE_LINK_SPEED_INDEX_TABLE_GEN1,
+ PCIE_LINK_SPEED_INDEX_TABLE_GEN2,
+ PCIE_LINK_SPEED_INDEX_TABLE_GEN3,
+ PCIE_LINK_SPEED_INDEX_TABLE_GEN4,
+ PCIE_LINK_SPEED_INDEX_TABLE_GEN5,
+ PCIE_LINK_SPEED_INDEX_TABLE_GEN6,
+ PCIE_LINK_SPEED_INDEX_TABLE_GEN6_ESM,
+ PCIE_LINK_SPEED_INDEX_TABLE_COUNT
+} PCIE_LINK_SPEED_INDEX_TABLE_e;
+
+typedef enum {
+ GFX_GUARDBAND_OFFSET_0,
+ GFX_GUARDBAND_OFFSET_1,
+ GFX_GUARDBAND_OFFSET_2,
+ GFX_GUARDBAND_OFFSET_3,
+ GFX_GUARDBAND_OFFSET_4,
+ GFX_GUARDBAND_OFFSET_5,
+ GFX_GUARDBAND_OFFSET_6,
+ GFX_GUARDBAND_OFFSET_7,
+ GFX_GUARDBAND_OFFSET_COUNT
+} GFX_GUARDBAND_OFFSET_e;
+
+typedef enum {
+ GFX_DVM_MARGINHI_0,
+ GFX_DVM_MARGINHI_1,
+ GFX_DVM_MARGINHI_2,
+ GFX_DVM_MARGINHI_3,
+ GFX_DVM_MARGINHI_4,
+ GFX_DVM_MARGINHI_5,
+ GFX_DVM_MARGINHI_6,
+ GFX_DVM_MARGINHI_7,
+ GFX_DVM_MARGINLO_0,
+ GFX_DVM_MARGINLO_1,
+ GFX_DVM_MARGINLO_2,
+ GFX_DVM_MARGINLO_3,
+ GFX_DVM_MARGINLO_4,
+ GFX_DVM_MARGINLO_5,
+ GFX_DVM_MARGINLO_6,
+ GFX_DVM_MARGINLO_7,
+ GFX_DVM_MARGIN_COUNT
+} GFX_DVM_MARGIN_e;
+
+typedef enum{
+ SYSTEM_TEMP_UBB_FPGA,
+ SYSTEM_TEMP_UBB_FRONT,
+ SYSTEM_TEMP_UBB_BACK,
+ SYSTEM_TEMP_UBB_OAM7,
+ SYSTEM_TEMP_UBB_IBC,
+ SYSTEM_TEMP_UBB_UFPGA,
+ SYSTEM_TEMP_UBB_OAM1,
+ SYSTEM_TEMP_OAM_0_1_HSC,
+ SYSTEM_TEMP_OAM_2_3_HSC,
+ SYSTEM_TEMP_OAM_4_5_HSC,
+ SYSTEM_TEMP_OAM_6_7_HSC,
+ SYSTEM_TEMP_UBB_FPGA_0V72_VR,
+ SYSTEM_TEMP_UBB_FPGA_3V3_VR,
+ SYSTEM_TEMP_RETIMER_0_1_2_3_1V2_VR,
+ SYSTEM_TEMP_RETIMER_4_5_6_7_1V2_VR,
+ SYSTEM_TEMP_RETIMER_0_1_0V9_VR,
+ SYSTEM_TEMP_RETIMER_4_5_0V9_VR,
+ SYSTEM_TEMP_RETIMER_2_3_0V9_VR,
+ SYSTEM_TEMP_RETIMER_6_7_0V9_VR,
+ SYSTEM_TEMP_OAM_0_1_2_3_3V3_VR,
+ SYSTEM_TEMP_OAM_4_5_6_7_3V3_VR,
+ SYSTEM_TEMP_IBC_HSC,
+ SYSTEM_TEMP_IBC,
+ SYSTEM_TEMP_MAX_ENTRIES = 32
+} SYSTEM_TEMP_e;
+
+typedef enum{
+ NODE_TEMP_RETIMER,
+ NODE_TEMP_IBC_TEMP,
+ NODE_TEMP_IBC_2_TEMP,
+ NODE_TEMP_VDD18_VR_TEMP,
+ NODE_TEMP_04_HBM_B_VR_TEMP,
+ NODE_TEMP_04_HBM_D_VR_TEMP,
+ NODE_TEMP_MAX_TEMP_ENTRIES = 12
+} NODE_TEMP_e;
+
+typedef enum {
+ SVI_PLANE_VDDCR_X0_TEMP,
+ SVI_PLANE_VDDCR_X1_TEMP,
+
+ SVI_PLANE_VDDIO_HBM_B_TEMP,
+ SVI_PLANE_VDDIO_HBM_D_TEMP,
+ SVI_PLANE_VDDIO_04_HBM_B_TEMP,
+ SVI_PLANE_VDDIO_04_HBM_D_TEMP,
+ SVI_PLANE_VDDCR_HBM_B_TEMP,
+ SVI_PLANE_VDDCR_HBM_D_TEMP,
+ SVI_PLANE_VDDCR_075_HBM_B_TEMP,
+ SVI_PLANE_VDDCR_075_HBM_D_TEMP,
+
+ SVI_PLANE_VDDIO_11_GTA_A_TEMP,
+ SVI_PLANE_VDDIO_11_GTA_C_TEMP,
+ SVI_PLANE_VDDAN_075_GTA_A_TEMP,
+ SVI_PLANE_VDDAN_075_GTA_C_TEMP,
+
+ SVI_PLANE_VDDCR_075_UCIE_TEMP,
+ SVI_PLANE_VDDIO_065_UCIEAA_TEMP,
+ SVI_PLANE_VDDIO_065_UCIEAM_A_TEMP,
+ SVI_PLANE_VDDIO_065_UCIEAM_C_TEMP,
+
+ SVI_PLANE_VDDCR_SOCIO_A_TEMP,
+ SVI_PLANE_VDDCR_SOCIO_C_TEMP,
+
+ SVI_PLANE_VDDAN_075_TEMP,
+ SVI_MAX_TEMP_ENTRIES, //22
+} SVI_TEMP_e;
+
+typedef enum{
+ SYSTEM_POWER_UBB_POWER,
+ SYSTEM_POWER_UBB_POWER_THRESHOLD,
+ SYSTEM_POWER_MAX_ENTRIES_WO_RESERVED,
+ SYSTEM_POWER_MAX_ENTRIES = 4
+} SYSTEM_POWER_e;
+
+#define SMU_METRICS_TABLE_VERSION 0xF
+
+typedef struct __attribute__((packed, aligned(4))) {
+ uint64_t AccumulationCounter;
+
+ //TEMPERATURE
+ uint32_t MaxSocketTemperature;
+ uint32_t MaxVrTemperature;
+ uint32_t HbmTemperature[12];
+ uint64_t MaxSocketTemperatureAcc;
+ uint64_t MaxVrTemperatureAcc;
+ uint64_t HbmTemperatureAcc[12];
+ uint32_t MidTemperature[2];
+ uint32_t AidTemperature[2];
+ uint32_t XcdTemperature[8];
+
+ //POWER
+ uint32_t SocketPowerLimit;
+ uint32_t SocketPower;
+
+ //ENERGY
+ uint64_t Timestamp;
+ uint64_t SocketEnergyAcc;
+ uint64_t HbmEnergyAcc;
+
+ //FREQUENCY
+ uint32_t GfxclkFrequencyLimit;
+ uint32_t FclkFrequency[2];
+ uint32_t UclkFrequency[2];
+ uint64_t GfxclkFrequencyAcc[8];
+ uint32_t GfxclkFrequency[8];
+ uint32_t SocclkFrequency[2];
+ uint32_t VclkFrequency[4];
+ uint32_t DclkFrequency[4];
+ uint32_t LclkFrequency[2];
+
+ //XGMI:
+ uint32_t XgmiWidth;
+ uint32_t XgmiBitrate;
+ uint64_t XgmiReadBandwidthAcc;
+ uint64_t XgmiWriteBandwidthAcc;
+
+ //ACTIVITY:
+ uint32_t SocketGfxBusy;
+ uint32_t DramBandwidthUtilization;
+ uint64_t SocketGfxBusyAcc;
+ uint64_t DramBandwidthAcc;
+ uint32_t MaxDramBandwidth;
+ uint64_t DramBandwidthUtilizationAcc;
+ uint64_t PcieBandwidthAcc[2];
+
+ //THROTTLERS
+ uint64_t ProchotResidencyAcc;
+ uint64_t PptResidencyAcc;
+ uint64_t SocketThmResidencyAcc;
+ uint64_t VrThmResidencyAcc;
+ uint64_t HbmThmResidencyAcc;
+
+ //PCIE BW Data and error count
+ uint32_t PcieBandwidth[2];
+ uint64_t PCIeL0ToRecoveryCountAcc;
+ uint64_t PCIenReplayAAcc;
+ uint64_t PCIenReplayARolloverCountAcc;
+ uint64_t PCIeNAKSentCountAcc;
+ uint64_t PCIeNAKReceivedCountAcc;
+ uint64_t PCIeOtherEndRecoveryAcc; // The Pcie counter itself is accumulated
+
+ // VCN/JPEG ACTIVITY
+ uint32_t VcnBusy[4];
+ uint32_t JpegBusy[40];
+
+ // PCIE LINK Speed and width
+ uint32_t PCIeLinkSpeed;
+ uint32_t PCIeLinkWidth;
+
+ // PER XCD ACTIVITY
+ uint32_t GfxBusy[8];
+ uint64_t GfxBusyAcc[8];
+
+ //NVML-Parity: Total App Clock Counter
+ uint64_t GfxclkBelowHostLimitPptAcc[8];
+ uint64_t GfxclkBelowHostLimitThmAcc[8];
+ uint64_t GfxclkBelowHostLimitTotalAcc[8];
+ uint64_t GfxclkLowUtilizationAcc[8];
+} MetricsTable_t;
+
+#define SMU_SYSTEM_METRICS_TABLE_VERSION 0x1
+
+#pragma pack(push, 4)
+typedef struct {
+ uint64_t AccumulationCounter; // Last update timestamp
+ uint16_t LabelVersion; //Defaults to 0.
+ uint16_t NodeIdentifier;
+ int16_t SystemTemperatures[SYSTEM_TEMP_MAX_ENTRIES]; // Signed integer temperature value in Celsius, unused fields are set to 0xFFFF
+ int16_t NodeTemperatures[NODE_TEMP_MAX_TEMP_ENTRIES]; // Signed integer temperature value in Celsius, unused fields are set to 0xFFFF
+ int16_t VrTemperatures[SVI_MAX_TEMP_ENTRIES]; // Signed integer temperature value in Celsius, 13 entries,
+ int16_t spare[7];
+
+ //NPM: NODE POWER MANAGEMENT
+ uint32_t NodePowerLimit;
+ uint32_t NodePower;
+ uint32_t GlobalPPTResidencyAcc;
+
+ uint16_t SystemPower[SYSTEM_POWER_MAX_ENTRIES]; // UBB Current Power and Power Threshold
+} SystemMetricsTable_t;
+#pragma pack(pop)
+
+#define SMU_VF_METRICS_TABLE_VERSION 0x5
+
+typedef struct __attribute__((packed, aligned(4))) {
+ uint32_t AccumulationCounter;
+ uint32_t InstGfxclk_TargFreq;
+ uint64_t AccGfxclk_TargFreq;
+ uint64_t AccGfxRsmuDpm_Busy;
+ uint64_t AccGfxclkBelowHostLimit;
+} VfMetricsTable_t;
+
+/* FRU product information */
+typedef struct __attribute__((aligned(4))) {
+ uint8_t ModelNumber[PRODUCT_MODEL_NUMBER_LEN];
+ uint8_t Name[PRODUCT_NAME_LEN];
+ uint8_t Serial[PRODUCT_SERIAL_LEN];
+ uint8_t ManufacturerName[PRODUCT_MANUFACTURER_NAME_LEN];
+ uint8_t FruId[PRODUCT_FRU_ID_LEN];
+} FRUProductInfo_t;
+
+#define SMU_STATIC_METRICS_TABLE_VERSION 0x1
+
+#pragma pack(push, 4)
+typedef struct {
+ //FRU PRODUCT INFO
+ FRUProductInfo_t ProductInfo; //from i2c
+
+ //POWER
+ uint32_t MaxSocketPowerLimit;
+
+ //FREQUENCY RANGE
+ uint32_t MaxGfxclkFrequency;
+ uint32_t MinGfxclkFrequency;
+ uint32_t MaxFclkFrequency;
+ uint32_t MinFclkFrequency;
+ uint32_t MaxGl2clkFrequency;
+ uint32_t MinGl2clkFrequency;
+ uint32_t UclkFrequencyTable[4];
+ uint32_t SocclkFrequency;
+ uint32_t LclkFrequency;
+ uint32_t VclkFrequency;
+ uint32_t DclkFrequency;
+
+ //CTF limits
+ uint32_t CTFLimit_MID;
+ uint32_t CTFLimit_AID;
+ uint32_t CTFLimit_XCD;
+ uint32_t CTFLimit_HBM;
+
+ //Thermal Throttling limits
+ uint32_t ThermalLimit_MID;
+ uint32_t ThermalLimit_AID;
+ uint32_t ThermalLimit_XCD;
+ uint32_t ThermalLimit_HBM;
+
+ //PSNs
+ uint64_t PublicSerialNumber_MID[2];
+ uint64_t PublicSerialNumber_AID[2];
+ uint64_t PublicSerialNumber_XCD[8];
+
+ //XGMI
+ uint32_t MaxXgmiWidth;
+ uint32_t MaxXgmiBitrate;
+
+ // Telemetry
+ uint32_t InputTelemetryVoltageInmV;
+
+ // General info
+ uint32_t pldmVersion[2];
+
+ uint32_t PPT1Max;
+ uint32_t PPT1Min;
+ uint32_t PPT1Default;
+} StaticMetricsTable_t;
+#pragma pack(pop)
+
+#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_8_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_8_ppsmc.h
new file mode 100644
index 000000000000..7ffb445f4c0c
--- /dev/null
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_8_ppsmc.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2025 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef SMU_15_0_8_PPSMC_H
+#define SMU_15_0_8_PPSMC_H
+
+/* SMU Response Codes */
+#define PPSMC_Result_OK 0x1
+#define PPSMC_Result_Failed 0xFF
+#define PPSMC_Result_UnknownCmd 0xFE
+#define PPSMC_Result_CmdRejectedPrereq 0xFD
+#define PPSMC_Result_CmdRejectedBusy 0xFC
+
+/* Message Definitions */
+#define PPSMC_MSG_TestMessage 0x1
+#define PPSMC_MSG_GetSmuVersion 0x2
+#define PPSMC_MSG_GfxDriverReset 0x3
+#define PPSMC_MSG_GetDriverIfVersion 0x4
+#define PPSMC_MSG_EnableAllSmuFeatures 0x5
+#define PPSMC_MSG_GetMetricsVersion 0x6
+#define PPSMC_MSG_GetMetricsTable 0x7
+#define PPSMC_MSG_GetEnabledSmuFeatures 0x8
+#define PPSMC_MSG_SetDriverDramAddr 0x9 //ARG0: low address, ARG1: high address
+#define PPSMC_MSG_SetToolsDramAddr 0xA //ARG0: low address, ARG1: high address
+//#define PPSMC_MSG_SetSystemVirtualDramAddr 0xB
+#define PPSMC_MSG_SetSoftMaxByFreq 0xC
+#define PPSMC_MSG_SetPptLimit 0xD
+#define PPSMC_MSG_GetPptLimit 0xE
+#define PPSMC_MSG_DramLogSetDramAddr 0xF //ARG0: low address, ARG1: high address, ARG2: size
+#define PPSMC_MSG_HeavySBR 0x10
+#define PPSMC_MSG_DFCstateControl 0x11
+#define PPSMC_MSG_GfxDriverResetRecovery 0x12
+#define PPSMC_MSG_TriggerVFFLR 0x13
+#define PPSMC_MSG_SetSoftMinGfxClk 0x14
+#define PPSMC_MSG_SetSoftMaxGfxClk 0x15
+#define PPSMC_MSG_PrepareForDriverUnload 0x16
+#define PPSMC_MSG_QueryValidMcaCount 0x17
+#define PPSMC_MSG_McaBankDumpDW 0x18
+#define PPSMC_MSG_ClearMcaOnRead 0x19
+#define PPSMC_MSG_QueryValidMcaCeCount 0x1A
+#define PPSMC_MSG_McaBankCeDumpDW 0x1B
+#define PPSMC_MSG_SelectPLPDMode 0x1C
+#define PPSMC_MSG_SetThrottlingPolicy 0x1D
+#define PPSMC_MSG_ResetSDMA 0x1E
+#define PPSMC_MSG_GetRasTableVersion 0x1F
+#define PPSMC_MSG_GetRmaStatus 0x20
+#define PPSMC_MSG_GetBadPageCount 0x21
+#define PPSMC_MSG_GetBadPageMcaAddress 0x22
+#define PPSMC_MSG_GetBadPagePaAddress 0x23
+#define PPSMC_MSG_SetTimestamp 0x24
+#define PPSMC_MSG_GetTimestamp 0x25
+#define PPSMC_MSG_GetRasPolicy 0x26
+#define PPSMC_MSG_GetBadPageIpIdLoHi 0x27
+#define PPSMC_MSG_EraseRasTable 0x28
+#define PPSMC_MSG_GetStaticMetricsTable 0x29
+#define PPSMC_MSG_ResetVfArbitersByIndex 0x2A
+#define PPSMC_MSG_GetBadPageSeverity 0x2B
+#define PPSMC_MSG_GetSystemMetricsTable 0x2C
+#define PPSMC_MSG_GetSystemMetricsVersion 0x2D
+#define PPSMC_MSG_ResetVCN 0x2E
+#define PPSMC_MSG_SetFastPptLimit 0x2F
+#define PPSMC_MSG_GetFastPptLimit 0x30
+#define PPSMC_MSG_SetSoftMinGl2clk 0x31
+#define PPSMC_MSG_SetSoftMaxGl2clk 0x32
+#define PPSMC_MSG_SetSoftMinFclk 0x33
+#define PPSMC_MSG_SetSoftMaxFclk 0x34
+#define PPSMC_Message_Count 0x35
+
+/* PSMC Reset Types for driver msg argument */
+#define PPSMC_RESET_TYPE_DRIVER_MODE_1_RESET 0x1
+#define PPSMC_RESET_TYPE_DRIVER_MODE_2_RESET 0x2
+#define PPSMC_RESET_TYPE_DRIVER_MODE_3_RESET 0x3
+
+/* PLPD modes */
+#define PPSMC_PLPD_MODE_DEFAULT 0x1
+#define PPSMC_PLPD_MODE_OPTIMIZED 0x2
+
+typedef uint32_t PPSMC_Result;
+typedef uint32_t PPSMC_MSG;
+
+#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
index e4cd6a0d13da..636ff90923d9 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
@@ -42,8 +42,10 @@
__SMU_DUMMY_MAP(SetPptLimit), \
__SMU_DUMMY_MAP(SetDriverDramAddrHigh), \
__SMU_DUMMY_MAP(SetDriverDramAddrLow), \
+ __SMU_DUMMY_MAP(SetDriverDramAddr), \
__SMU_DUMMY_MAP(SetToolsDramAddrHigh), \
__SMU_DUMMY_MAP(SetToolsDramAddrLow), \
+ __SMU_DUMMY_MAP(SetToolsDramAddr), \
__SMU_DUMMY_MAP(TransferTableSmu2Dram), \
__SMU_DUMMY_MAP(TransferTableDram2Smu), \
__SMU_DUMMY_MAP(UseDefaultPPTable), \
@@ -273,10 +275,31 @@
__SMU_DUMMY_MAP(GetMetricsVersion), \
__SMU_DUMMY_MAP(EnableUCLKShadow), \
__SMU_DUMMY_MAP(RmaDueToBadPageThreshold), \
- __SMU_DUMMY_MAP(SelectPstatePolicy), \
+ __SMU_DUMMY_MAP(SetThrottlingPolicy), \
__SMU_DUMMY_MAP(MALLPowerController), \
__SMU_DUMMY_MAP(MALLPowerState), \
- __SMU_DUMMY_MAP(ResetSDMA),
+ __SMU_DUMMY_MAP(ResetSDMA), \
+ __SMU_DUMMY_MAP(ResetVCN), \
+ __SMU_DUMMY_MAP(GetStaticMetricsTable), \
+ __SMU_DUMMY_MAP(GetSystemMetricsTable), \
+ __SMU_DUMMY_MAP(GetRASTableVersion), \
+ __SMU_DUMMY_MAP(GetBadPageCount), \
+ __SMU_DUMMY_MAP(GetBadPageMcaAddr), \
+ __SMU_DUMMY_MAP(SetTimestamp), \
+ __SMU_DUMMY_MAP(GetTimestamp), \
+ __SMU_DUMMY_MAP(GetBadPageIpid), \
+ __SMU_DUMMY_MAP(EraseRasTable), \
+ __SMU_DUMMY_MAP(SetFastPptLimit), \
+ __SMU_DUMMY_MAP(GetFastPptLimit), \
+ __SMU_DUMMY_MAP(AllowZstates), \
+ __SMU_DUMMY_MAP(GetSmartShiftStatus), \
+ __SMU_DUMMY_MAP(EnableLSdma), \
+ __SMU_DUMMY_MAP(DisableLSdma), \
+ __SMU_DUMMY_MAP(InitializeGfx), \
+ __SMU_DUMMY_MAP(SetSoftMaxFclk), \
+ __SMU_DUMMY_MAP(SetSoftMaxGl2clk), \
+ __SMU_DUMMY_MAP(SetSoftMinGl2clk), \
+ __SMU_DUMMY_MAP(GetSystemMetricsVersion),
#undef __SMU_DUMMY_MAP
#define __SMU_DUMMY_MAP(type) SMU_MSG_##type
@@ -303,9 +326,12 @@ enum smu_clk_type {
SMU_MCLK,
SMU_PCIE,
SMU_LCLK,
+ SMU_ISPICLK,
+ SMU_ISPXCLK,
SMU_OD_CCLK,
SMU_OD_SCLK,
SMU_OD_MCLK,
+ SMU_OD_FCLK,
SMU_OD_VDDC_CURVE,
SMU_OD_RANGE,
SMU_OD_VDDGFX_OFFSET,
@@ -316,6 +342,7 @@ enum smu_clk_type {
SMU_OD_FAN_MINIMUM_PWM,
SMU_OD_FAN_ZERO_RPM_ENABLE,
SMU_OD_FAN_ZERO_RPM_STOP_TEMP,
+ SMU_GL2CLK,
SMU_CLK_COUNT,
};
@@ -355,6 +382,7 @@ enum smu_clk_type {
__SMU_DUMMY_MAP(DS_FCLK), \
__SMU_DUMMY_MAP(DS_MP1CLK), \
__SMU_DUMMY_MAP(DS_MP0CLK), \
+ __SMU_DUMMY_MAP(DS_MPIOCLK), \
__SMU_DUMMY_MAP(XGMI_PER_LINK_PWR_DWN), \
__SMU_DUMMY_MAP(DPM_GFX_PACE), \
__SMU_DUMMY_MAP(MEM_VDDCI_SCALING), \
@@ -451,7 +479,17 @@ enum smu_clk_type {
__SMU_DUMMY_MAP(APT_PF_DCS), \
__SMU_DUMMY_MAP(GFX_EDC_XVMIN), \
__SMU_DUMMY_MAP(GFX_DIDT_XVMIN), \
- __SMU_DUMMY_MAP(FAN_ABNORMAL),
+ __SMU_DUMMY_MAP(FAN_ABNORMAL), \
+ __SMU_DUMMY_MAP(PIT), \
+ __SMU_DUMMY_MAP(DS_DMABECLK), \
+ __SMU_DUMMY_MAP(DS_MPIFOECLK), \
+ __SMU_DUMMY_MAP(DS_MPRASCLK), \
+ __SMU_DUMMY_MAP(DS_MPNHTCLK), \
+ __SMU_DUMMY_MAP(DS_FIOCLK), \
+ __SMU_DUMMY_MAP(DS_DXIOCLK), \
+ __SMU_DUMMY_MAP(DS_GL2CLK), \
+ __SMU_DUMMY_MAP(DPM_GL2CLK), \
+ __SMU_DUMMY_MAP(HROM_EN),
#undef __SMU_DUMMY_MAP
#define __SMU_DUMMY_MAP(feature) SMU_FEATURE_##feature##_BIT
@@ -463,6 +501,7 @@ enum smu_feature_mask {
/* Message category flags */
#define SMU_MSG_VF_FLAG (1U << 0)
#define SMU_MSG_RAS_PRI (1U << 1)
+#define SMU_MSG_NO_PRECHECK (1U << 2)
/* Firmware capability flags */
#define SMU_FW_CAP_RAS_PRI (1U << 0)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h
index ed8304d82831..dd94e8a9e218 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h
@@ -25,18 +25,6 @@
#include "amdgpu_smu.h"
-#define SMU11_DRIVER_IF_VERSION_INV 0xFFFFFFFF
-#define SMU11_DRIVER_IF_VERSION_ARCT 0x17
-#define SMU11_DRIVER_IF_VERSION_NV10 0x37
-#define SMU11_DRIVER_IF_VERSION_NV12 0x38
-#define SMU11_DRIVER_IF_VERSION_NV14 0x38
-#define SMU11_DRIVER_IF_VERSION_Sienna_Cichlid 0x40
-#define SMU11_DRIVER_IF_VERSION_Navy_Flounder 0xE
-#define SMU11_DRIVER_IF_VERSION_VANGOGH 0x03
-#define SMU11_DRIVER_IF_VERSION_Dimgrey_Cavefish 0xF
-#define SMU11_DRIVER_IF_VERSION_Beige_Goby 0xD
-#define SMU11_DRIVER_IF_VERSION_Cyan_Skillfish 0x8
-
/* MP Apertures */
#define MP0_Public 0x03800000
#define MP0_SRAM 0x03900000
@@ -53,7 +41,6 @@
#define SMU11_TOOL_SIZE 0x19000
-#define MAX_DPM_LEVELS 16
#define MAX_PCIE_CONF 2
#define CTF_OFFSET_EDGE 5
@@ -80,39 +67,21 @@ struct smu_11_0_max_sustainable_clocks {
uint32_t soc_clock;
};
-struct smu_11_0_dpm_clk_level {
- bool enabled;
- uint32_t value;
-};
-
-struct smu_11_0_dpm_table {
- uint32_t min; /* MHz */
- uint32_t max; /* MHz */
- uint32_t count;
- bool is_fine_grained;
- struct smu_11_0_dpm_clk_level dpm_levels[MAX_DPM_LEVELS];
-};
-
-struct smu_11_0_pcie_table {
- uint8_t pcie_gen[MAX_PCIE_CONF];
- uint8_t pcie_lane[MAX_PCIE_CONF];
-};
-
struct smu_11_0_dpm_tables {
- struct smu_11_0_dpm_table soc_table;
- struct smu_11_0_dpm_table gfx_table;
- struct smu_11_0_dpm_table uclk_table;
- struct smu_11_0_dpm_table eclk_table;
- struct smu_11_0_dpm_table vclk_table;
- struct smu_11_0_dpm_table vclk1_table;
- struct smu_11_0_dpm_table dclk_table;
- struct smu_11_0_dpm_table dclk1_table;
- struct smu_11_0_dpm_table dcef_table;
- struct smu_11_0_dpm_table pixel_table;
- struct smu_11_0_dpm_table display_table;
- struct smu_11_0_dpm_table phy_table;
- struct smu_11_0_dpm_table fclk_table;
- struct smu_11_0_pcie_table pcie_table;
+ struct smu_dpm_table soc_table;
+ struct smu_dpm_table gfx_table;
+ struct smu_dpm_table uclk_table;
+ struct smu_dpm_table eclk_table;
+ struct smu_dpm_table vclk_table;
+ struct smu_dpm_table vclk1_table;
+ struct smu_dpm_table dclk_table;
+ struct smu_dpm_table dclk1_table;
+ struct smu_dpm_table dcef_table;
+ struct smu_dpm_table pixel_table;
+ struct smu_dpm_table display_table;
+ struct smu_dpm_table phy_table;
+ struct smu_dpm_table fclk_table;
+ struct smu_pcie_table pcie_table;
};
struct smu_11_0_dpm_context {
@@ -167,8 +136,6 @@ int smu_v11_0_setup_pptable(struct smu_context *smu);
int smu_v11_0_get_vbios_bootup_values(struct smu_context *smu);
-int smu_v11_0_check_fw_version(struct smu_context *smu);
-
int smu_v11_0_set_driver_table_location(struct smu_context *smu);
int smu_v11_0_set_tool_table_location(struct smu_context *smu);
@@ -279,12 +246,7 @@ int smu_v11_0_get_dpm_level_count(struct smu_context *smu,
int smu_v11_0_set_single_dpm_table(struct smu_context *smu,
enum smu_clk_type clk_type,
- struct smu_11_0_dpm_table *single_dpm_table);
-
-int smu_v11_0_get_dpm_level_range(struct smu_context *smu,
- enum smu_clk_type clk_type,
- uint32_t *min_value,
- uint32_t *max_value);
+ struct smu_dpm_table *single_dpm_table);
int smu_v11_0_get_current_pcie_link_width_level(struct smu_context *smu);
@@ -306,7 +268,8 @@ int smu_v11_0_handle_passthrough_sbr(struct smu_context *smu, bool enable);
int smu_v11_0_restore_user_od_settings(struct smu_context *smu);
-void smu_v11_0_set_smu_mailbox_registers(struct smu_context *smu);
+void smu_v11_0_init_msg_ctl(struct smu_context *smu,
+ const struct cmn2asic_msg_mapping *message_map);
#endif
#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h
index 0886d8cffbd0..2346d9c6e162 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h
@@ -35,8 +35,6 @@
int smu_v12_0_check_fw_status(struct smu_context *smu);
-int smu_v12_0_check_fw_version(struct smu_context *smu);
-
int smu_v12_0_powergate_sdma(struct smu_context *smu, bool gate);
int smu_v12_0_powergate_vcn(struct smu_context *smu, bool gate);
@@ -62,5 +60,8 @@ int smu_v12_0_set_driver_table_location(struct smu_context *smu);
int smu_v12_0_get_vbios_bootup_values(struct smu_context *smu);
+void smu_v12_0_init_msg_ctl(struct smu_context *smu,
+ const struct cmn2asic_msg_mapping *message_map);
+
#endif
#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
index 8d4a96e23326..89bbda0670ef 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
@@ -44,7 +44,6 @@
#define SMU13_TOOL_SIZE 0x19000
-#define MAX_DPM_LEVELS 16
#define MAX_PCIE_CONF 3
#define CTF_OFFSET_EDGE 5
@@ -53,6 +52,11 @@
#define SMU_13_VCLK_SHIFT 16
+#define SMUQ10_TO_UINT(x) ((x) >> 10)
+#define SMUQ10_FRAC(x) ((x) & 0x3ff)
+#define SMUQ10_ROUND(x) ((SMUQ10_TO_UINT(x)) + ((SMUQ10_FRAC(x)) >= 0x200))
+#define SMU_V13_SOFT_FREQ_ROUND(x) ((x) + 1)
+
extern const int pmfw_decoded_link_speed[5];
extern const int pmfw_decoded_link_width[7];
@@ -68,39 +72,19 @@ struct smu_13_0_max_sustainable_clocks {
uint32_t soc_clock;
};
-struct smu_13_0_dpm_clk_level {
- bool enabled;
- uint32_t value;
-};
-
-struct smu_13_0_dpm_table {
- uint32_t min; /* MHz */
- uint32_t max; /* MHz */
- uint32_t count;
- bool is_fine_grained;
- struct smu_13_0_dpm_clk_level dpm_levels[MAX_DPM_LEVELS];
-};
-
-struct smu_13_0_pcie_table {
- uint8_t pcie_gen[MAX_PCIE_CONF];
- uint8_t pcie_lane[MAX_PCIE_CONF];
- uint16_t clk_freq[MAX_PCIE_CONF];
- uint32_t num_of_link_levels;
-};
-
struct smu_13_0_dpm_tables {
- struct smu_13_0_dpm_table soc_table;
- struct smu_13_0_dpm_table gfx_table;
- struct smu_13_0_dpm_table uclk_table;
- struct smu_13_0_dpm_table eclk_table;
- struct smu_13_0_dpm_table vclk_table;
- struct smu_13_0_dpm_table dclk_table;
- struct smu_13_0_dpm_table dcef_table;
- struct smu_13_0_dpm_table pixel_table;
- struct smu_13_0_dpm_table display_table;
- struct smu_13_0_dpm_table phy_table;
- struct smu_13_0_dpm_table fclk_table;
- struct smu_13_0_pcie_table pcie_table;
+ struct smu_dpm_table soc_table;
+ struct smu_dpm_table gfx_table;
+ struct smu_dpm_table uclk_table;
+ struct smu_dpm_table eclk_table;
+ struct smu_dpm_table vclk_table;
+ struct smu_dpm_table dclk_table;
+ struct smu_dpm_table dcef_table;
+ struct smu_dpm_table pixel_table;
+ struct smu_dpm_table display_table;
+ struct smu_dpm_table phy_table;
+ struct smu_dpm_table fclk_table;
+ struct smu_pcie_table pcie_table;
};
struct smu_13_0_dpm_context {
@@ -108,6 +92,7 @@ struct smu_13_0_dpm_context {
uint32_t workload_policy_mask;
uint32_t dcef_min_ds_clk;
uint64_t caps;
+ uint32_t board_volt;
};
enum smu_13_0_power_state {
@@ -147,8 +132,6 @@ int smu_v13_0_setup_pptable(struct smu_context *smu);
int smu_v13_0_get_vbios_bootup_values(struct smu_context *smu);
-int smu_v13_0_check_fw_version(struct smu_context *smu);
-
int smu_v13_0_set_driver_table_location(struct smu_context *smu);
int smu_v13_0_set_tool_table_location(struct smu_context *smu);
@@ -158,8 +141,6 @@ int smu_v13_0_notify_memory_pool_location(struct smu_context *smu);
int smu_v13_0_system_features_control(struct smu_context *smu,
bool en);
-int smu_v13_0_init_display_count(struct smu_context *smu, uint32_t count);
-
int smu_v13_0_set_allowed_mask(struct smu_context *smu);
int smu_v13_0_notify_display_change(struct smu_context *smu);
@@ -179,13 +160,6 @@ int smu_v13_0_disable_thermal_alert(struct smu_context *smu);
int smu_v13_0_get_gfx_vdd(struct smu_context *smu, uint32_t *value);
-int smu_v13_0_set_min_deep_sleep_dcefclk(struct smu_context *smu, uint32_t clk);
-
-int
-smu_v13_0_display_clock_voltage_request(struct smu_context *smu,
- struct pp_display_clock_request
- *clock_req);
-
uint32_t
smu_v13_0_get_fan_control_mode(struct smu_context *smu);
@@ -222,11 +196,6 @@ int smu_v13_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type c
int smu_v13_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type,
uint32_t min, uint32_t max, bool automatic);
-int smu_v13_0_set_hard_freq_limited_range(struct smu_context *smu,
- enum smu_clk_type clk_type,
- uint32_t min,
- uint32_t max);
-
int smu_v13_0_set_performance_level(struct smu_context *smu,
enum amd_dpm_forced_level level);
@@ -235,7 +204,7 @@ int smu_v13_0_set_power_source(struct smu_context *smu,
int smu_v13_0_set_single_dpm_table(struct smu_context *smu,
enum smu_clk_type clk_type,
- struct smu_13_0_dpm_table *single_dpm_table);
+ struct smu_dpm_table *single_dpm_table);
int smu_v13_0_get_dpm_freq_by_index(struct smu_context *smu,
enum smu_clk_type clk_type, uint16_t level,
@@ -281,7 +250,8 @@ int smu_v13_0_od_edit_dpm_table(struct smu_context *smu,
int smu_v13_0_set_default_dpm_tables(struct smu_context *smu);
-void smu_v13_0_set_smu_mailbox_registers(struct smu_context *smu);
+void smu_v13_0_init_msg_ctl(struct smu_context *smu,
+ const struct cmn2asic_msg_mapping *message_map);
int smu_v13_0_mode1_reset(struct smu_context *smu);
@@ -306,5 +276,6 @@ int smu_v13_0_get_boot_freq_by_index(struct smu_context *smu,
uint32_t *value);
void smu_v13_0_interrupt_work(struct smu_context *smu);
+void smu_v13_0_reset_custom_level(struct smu_context *smu);
#endif
#endif
diff --git a/drivers/gpu/drm/amd/pm/inc/smu_v13_0_0_pptable.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0_0_pptable.h
index 251ed011b3b0..251ed011b3b0 100644
--- a/drivers/gpu/drm/amd/pm/inc/smu_v13_0_0_pptable.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0_0_pptable.h
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h
index 29a4583db873..4eb40ff8aff2 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h
@@ -25,11 +25,6 @@
#include "amdgpu_smu.h"
-#define SMU14_DRIVER_IF_VERSION_INV 0xFFFFFFFF
-#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_0 0x7
-#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_1 0x6
-#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_2 0x2E
-
#define FEATURE_MASK(feature) (1ULL << feature)
/* MP Apertures */
@@ -43,7 +38,6 @@
#define smnMP1_FIRMWARE_FLAGS 0x3010024
#define smnMP1_PUB_CTRL 0x3010d10
-#define MAX_DPM_LEVELS 16
#define MAX_PCIE_CONF 3
#define SMU14_TOOL_SIZE 0x19000
@@ -57,6 +51,7 @@ extern const int decoded_link_width[8];
#define DECODE_GEN_SPEED(gen_speed_idx) (decoded_link_speed[gen_speed_idx])
#define DECODE_LANE_WIDTH(lane_width_idx) (decoded_link_width[lane_width_idx])
+#define SMU_V14_SOFT_FREQ_ROUND(x) ((x) + 1)
struct smu_14_0_max_sustainable_clocks {
uint32_t display_clock;
@@ -67,39 +62,19 @@ struct smu_14_0_max_sustainable_clocks {
uint32_t soc_clock;
};
-struct smu_14_0_dpm_clk_level {
- bool enabled;
- uint32_t value;
-};
-
-struct smu_14_0_dpm_table {
- uint32_t min; /* MHz */
- uint32_t max; /* MHz */
- uint32_t count;
- bool is_fine_grained;
- struct smu_14_0_dpm_clk_level dpm_levels[MAX_DPM_LEVELS];
-};
-
-struct smu_14_0_pcie_table {
- uint8_t pcie_gen[MAX_PCIE_CONF];
- uint8_t pcie_lane[MAX_PCIE_CONF];
- uint16_t clk_freq[MAX_PCIE_CONF];
- uint32_t num_of_link_levels;
-};
-
struct smu_14_0_dpm_tables {
- struct smu_14_0_dpm_table soc_table;
- struct smu_14_0_dpm_table gfx_table;
- struct smu_14_0_dpm_table uclk_table;
- struct smu_14_0_dpm_table eclk_table;
- struct smu_14_0_dpm_table vclk_table;
- struct smu_14_0_dpm_table dclk_table;
- struct smu_14_0_dpm_table dcef_table;
- struct smu_14_0_dpm_table pixel_table;
- struct smu_14_0_dpm_table display_table;
- struct smu_14_0_dpm_table phy_table;
- struct smu_14_0_dpm_table fclk_table;
- struct smu_14_0_pcie_table pcie_table;
+ struct smu_dpm_table soc_table;
+ struct smu_dpm_table gfx_table;
+ struct smu_dpm_table uclk_table;
+ struct smu_dpm_table eclk_table;
+ struct smu_dpm_table vclk_table;
+ struct smu_dpm_table dclk_table;
+ struct smu_dpm_table dcef_table;
+ struct smu_dpm_table pixel_table;
+ struct smu_dpm_table display_table;
+ struct smu_dpm_table phy_table;
+ struct smu_dpm_table fclk_table;
+ struct smu_pcie_table pcie_table;
};
struct smu_14_0_dpm_context {
@@ -144,8 +119,6 @@ int smu_v14_0_setup_pptable(struct smu_context *smu);
int smu_v14_0_get_vbios_bootup_values(struct smu_context *smu);
-int smu_v14_0_check_fw_version(struct smu_context *smu);
-
int smu_v14_0_set_driver_table_location(struct smu_context *smu);
int smu_v14_0_set_tool_table_location(struct smu_context *smu);
@@ -201,7 +174,7 @@ int smu_v14_0_set_power_source(struct smu_context *smu,
int smu_v14_0_set_single_dpm_table(struct smu_context *smu,
enum smu_clk_type clk_type,
- struct smu_14_0_dpm_table *single_dpm_table);
+ struct smu_dpm_table *single_dpm_table);
int smu_v14_0_gfx_ulv_control(struct smu_context *smu,
bool enablement);
@@ -236,10 +209,8 @@ int smu_v14_0_get_pptable_from_firmware(struct smu_context *smu,
uint32_t pptable_id);
int smu_v14_0_od_edit_dpm_table(struct smu_context *smu,
- enum PP_OD_DPM_TABLE_COMMAND type,
- long input[], uint32_t size);
-
-void smu_v14_0_set_smu_mailbox_registers(struct smu_context *smu);
+ enum PP_OD_DPM_TABLE_COMMAND type,
+ long input[], uint32_t size);
int smu_v14_0_enable_thermal_alert(struct smu_context *smu);
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h
new file mode 100644
index 000000000000..e6fd8be2cc4a
--- /dev/null
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2025 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __SMU_V15_0_H__
+#define __SMU_V15_0_H__
+
+#include "amdgpu_smu.h"
+
+#define SMU15_DRIVER_IF_VERSION_INV 0xFFFFFFFF
+#define SMU15_DRIVER_IF_VERSION_SMU_V15_0 0x7
+
+
+#define FEATURE_MASK(feature) (1ULL << feature)
+
+/* MP Apertures */
+#define MP0_Public 0x03800000
+#define MP0_SRAM 0x03900000
+#define MP1_Public 0x03b00000
+#define MP1_SRAM 0x03c00004
+
+/* address block */
+#define smnMP1_FIRMWARE_FLAGS 0x3010024
+#define smnMP1_PUB_CTRL 0x3010d10
+
+#define SMU15_DRIVER_IF_VERSION_SMU_V15_0_8 0x007D0000
+
+#define FEATURE_MASK(feature) (1ULL << feature)
+
+#define MAX_PCIE_CONF 3
+
+#define SMU15_TOOL_SIZE 0x19000
+
+#define CTF_OFFSET_EDGE 5
+#define CTF_OFFSET_HOTSPOT 5
+#define CTF_OFFSET_MEM 5
+
+extern const int decoded_link_speed[5];
+extern const int decoded_link_width[8];
+
+#define DECODE_GEN_SPEED(gen_speed_idx) (decoded_link_speed[gen_speed_idx])
+#define DECODE_LANE_WIDTH(lane_width_idx) (decoded_link_width[lane_width_idx])
+
+struct smu_15_0_max_sustainable_clocks {
+ uint32_t display_clock;
+ uint32_t phy_clock;
+ uint32_t pixel_clock;
+ uint32_t uclock;
+ uint32_t dcef_clock;
+ uint32_t soc_clock;
+};
+
+struct smu_15_0_dpm_tables {
+ struct smu_dpm_table soc_table;
+ struct smu_dpm_table gfx_table;
+ struct smu_dpm_table uclk_table;
+ struct smu_dpm_table eclk_table;
+ struct smu_dpm_table vclk_table;
+ struct smu_dpm_table dclk_table;
+ struct smu_dpm_table dcef_table;
+ struct smu_dpm_table pixel_table;
+ struct smu_dpm_table display_table;
+ struct smu_dpm_table phy_table;
+ struct smu_dpm_table fclk_table;
+ struct smu_pcie_table pcie_table;
+ struct smu_dpm_table gl2_table;
+};
+
+struct smu_15_0_dpm_context {
+ struct smu_15_0_dpm_tables dpm_tables;
+ uint32_t workload_policy_mask;
+ uint32_t dcef_min_ds_clk;
+ uint64_t caps;
+ uint32_t board_volt;
+};
+
+enum smu_15_0_power_state {
+ smu_15_0_POWER_STATE__D0 = 0,
+ smu_15_0_POWER_STATE__D1,
+ smu_15_0_POWER_STATE__D3, /* Sleep*/
+ smu_15_0_POWER_STATE__D4, /* Hibernate*/
+ smu_15_0_POWER_STATE__D5, /* Power off*/
+};
+
+struct smu_15_0_power_context {
+ uint32_t power_source;
+ uint8_t in_power_limit_boost_mode;
+ enum smu_15_0_power_state power_state;
+ atomic_t throttle_status;
+};
+
+#if defined(SWSMU_CODE_LAYER_L2) || defined(SWSMU_CODE_LAYER_L3)
+
+int smu_v15_0_init_microcode(struct smu_context *smu);
+
+void smu_v15_0_fini_microcode(struct smu_context *smu);
+
+int smu_v15_0_load_microcode(struct smu_context *smu);
+
+int smu_v15_0_init_smc_tables(struct smu_context *smu);
+
+int smu_v15_0_fini_smc_tables(struct smu_context *smu);
+
+int smu_v15_0_init_power(struct smu_context *smu);
+
+int smu_v15_0_fini_power(struct smu_context *smu);
+
+int smu_v15_0_check_fw_status(struct smu_context *smu);
+
+int smu_v15_0_setup_pptable(struct smu_context *smu);
+
+int smu_v15_0_get_vbios_bootup_values(struct smu_context *smu);
+
+int smu_v15_0_set_driver_table_location(struct smu_context *smu);
+
+int smu_v15_0_set_tool_table_location(struct smu_context *smu);
+
+int smu_v15_0_notify_memory_pool_location(struct smu_context *smu);
+
+int smu_v15_0_system_features_control(struct smu_context *smu,
+ bool en);
+
+int smu_v15_0_set_allowed_mask(struct smu_context *smu);
+
+int smu_v15_0_notify_display_change(struct smu_context *smu);
+
+int smu_v15_0_get_current_power_limit(struct smu_context *smu,
+ uint32_t *power_limit);
+
+int smu_v15_0_set_power_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t limit);
+
+int smu_v15_0_gfx_off_control(struct smu_context *smu, bool enable);
+
+int smu_v15_0_register_irq_handler(struct smu_context *smu);
+
+int smu_v15_0_baco_set_armd3_sequence(struct smu_context *smu,
+ enum smu_baco_seq baco_seq);
+
+int smu_v15_0_get_bamaco_support(struct smu_context *smu);
+
+enum smu_baco_state smu_v15_0_baco_get_state(struct smu_context *smu);
+
+int smu_v15_0_baco_set_state(struct smu_context *smu, enum smu_baco_state state);
+
+int smu_v15_0_baco_enter(struct smu_context *smu);
+int smu_v15_0_baco_exit(struct smu_context *smu);
+
+int smu_v15_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type clk_type,
+ uint32_t *min, uint32_t *max);
+
+int smu_v15_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type,
+ uint32_t min, uint32_t max, bool automatic);
+
+int smu_v15_0_set_hard_freq_limited_range(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t min,
+ uint32_t max);
+
+int smu_v15_0_set_performance_level(struct smu_context *smu,
+ enum amd_dpm_forced_level level);
+
+int smu_v15_0_set_power_source(struct smu_context *smu,
+ enum smu_power_src_type power_src);
+
+int smu_v15_0_set_single_dpm_table(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ struct smu_dpm_table *single_dpm_table);
+
+int smu_v15_0_gfx_ulv_control(struct smu_context *smu,
+ bool enablement);
+
+int smu_v15_0_wait_for_event(struct smu_context *smu, enum smu_event_type event,
+ uint64_t event_arg);
+
+int smu_v15_0_set_vcn_enable(struct smu_context *smu,
+ bool enable,
+ int inst);
+
+int smu_v15_0_set_jpeg_enable(struct smu_context *smu,
+ bool enable);
+
+int smu_v15_0_init_pptable_microcode(struct smu_context *smu);
+
+int smu_v15_0_run_btc(struct smu_context *smu);
+
+int smu_v15_0_gpo_control(struct smu_context *smu,
+ bool enablement);
+
+int smu_v15_0_deep_sleep_control(struct smu_context *smu,
+ bool enablement);
+
+int smu_v15_0_set_gfx_power_up_by_imu(struct smu_context *smu);
+
+int smu_v15_0_get_pptable_from_firmware(struct smu_context *smu,
+ void **table,
+ uint32_t *size,
+ uint32_t pptable_id);
+
+int smu_v15_0_od_edit_dpm_table(struct smu_context *smu,
+ enum PP_OD_DPM_TABLE_COMMAND type,
+ long input[], uint32_t size);
+
+int smu_v15_0_enable_thermal_alert(struct smu_context *smu);
+
+int smu_v15_0_disable_thermal_alert(struct smu_context *smu);
+
+#endif
+#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
index 8aa61a9f7778..54d3dba7d354 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
@@ -65,17 +65,17 @@
#define SMU_FEATURES_HIGH_MASK 0xFFFFFFFF00000000
#define SMU_FEATURES_HIGH_SHIFT 32
-#define SMC_DPM_FEATURE ( \
- FEATURE_DPM_PREFETCHER_MASK | \
- FEATURE_DPM_GFXCLK_MASK | \
- FEATURE_DPM_UCLK_MASK | \
- FEATURE_DPM_SOCCLK_MASK | \
- FEATURE_DPM_MP0CLK_MASK | \
- FEATURE_DPM_FCLK_MASK | \
- FEATURE_DPM_XGMI_MASK)
-
-/* possible frequency drift (1Mhz) */
-#define EPSILON 1
+#define SMU11_DRIVER_IF_VERSION_ARCT 0x17
+
+static const struct smu_feature_bits arcturus_dpm_features = {
+ .bits = { SMU_FEATURE_BIT_INIT(FEATURE_DPM_PREFETCHER_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_MP0CLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_XGMI_BIT) }
+};
#define smnPCIE_ESM_CTRL 0x111003D0
@@ -251,6 +251,7 @@ static int arcturus_tables_init(struct smu_context *smu)
{
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_table *tables = smu_table->tables;
+ int ret;
SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
@@ -268,16 +269,17 @@ static int arcturus_tables_init(struct smu_context *smu)
sizeof(DpmActivityMonitorCoeffInt_t), PAGE_SIZE,
AMDGPU_GEM_DOMAIN_VRAM);
- smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
+ smu_table->metrics_table = kzalloc_obj(SmuMetrics_t);
if (!smu_table->metrics_table)
return -ENOMEM;
smu_table->metrics_time = 0;
- smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_3);
- smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
- if (!smu_table->gpu_metrics_table) {
+ ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS,
+ sizeof(struct gpu_metrics_v1_3),
+ SMU_GPU_METRICS_CACHE_INTERVAL);
+ if (ret) {
kfree(smu_table->metrics_table);
- return -ENOMEM;
+ return ret;
}
return 0;
@@ -307,14 +309,13 @@ static int arcturus_allocate_dpm_context(struct smu_context *smu)
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
struct smu_dpm_policy *policy;
- smu_dpm->dpm_context = kzalloc(sizeof(struct smu_11_0_dpm_context),
- GFP_KERNEL);
+ smu_dpm->dpm_context = kzalloc_obj(struct smu_11_0_dpm_context);
if (!smu_dpm->dpm_context)
return -ENOMEM;
smu_dpm->dpm_context_size = sizeof(struct smu_11_0_dpm_context);
smu_dpm->dpm_policies =
- kzalloc(sizeof(struct smu_dpm_policy_ctxt), GFP_KERNEL);
+ kzalloc_obj(struct smu_dpm_policy_ctxt);
if (!smu_dpm->dpm_policies)
return -ENOMEM;
@@ -346,14 +347,9 @@ static int arcturus_init_smc_tables(struct smu_context *smu)
}
static int
-arcturus_get_allowed_feature_mask(struct smu_context *smu,
- uint32_t *feature_mask, uint32_t num)
+arcturus_init_allowed_features(struct smu_context *smu)
{
- if (num > 2)
- return -EINVAL;
-
- /* pptable will handle the features to enable */
- memset(feature_mask, 0xFF, sizeof(uint32_t) * num);
+ smu_feature_list_set_all(smu, SMU_FEATURE_LIST_ALLOWED);
return 0;
}
@@ -362,79 +358,75 @@ static int arcturus_set_default_dpm_table(struct smu_context *smu)
{
struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
PPTable_t *driver_ppt = smu->smu_table.driver_pptable;
- struct smu_11_0_dpm_table *dpm_table = NULL;
+ struct smu_dpm_table *dpm_table = NULL;
int ret = 0;
/* socclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.soc_table;
+ dpm_table->clk_type = SMU_SOCCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
SMU_SOCCLK,
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !driver_ppt->DpmDescriptor[PPCLK_SOCCLK].SnapToDiscrete;
+ if (!driver_ppt->DpmDescriptor[PPCLK_SOCCLK].SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.socclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* gfxclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.gfx_table;
+ dpm_table->clk_type = SMU_GFXCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
SMU_GFXCLK,
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !driver_ppt->DpmDescriptor[PPCLK_GFXCLK].SnapToDiscrete;
+ if (!driver_ppt->DpmDescriptor[PPCLK_GFXCLK].SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* memclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.uclk_table;
+ dpm_table->clk_type = SMU_UCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
SMU_UCLK,
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !driver_ppt->DpmDescriptor[PPCLK_UCLK].SnapToDiscrete;
+ if (!driver_ppt->DpmDescriptor[PPCLK_UCLK].SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.uclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* fclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.fclk_table;
+ dpm_table->clk_type = SMU_FCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
SMU_FCLK,
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !driver_ppt->DpmDescriptor[PPCLK_FCLK].SnapToDiscrete;
+ if (!driver_ppt->DpmDescriptor[PPCLK_FCLK].SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.fclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* XGMI PLPD is supported by 54.23.0 and onwards */
@@ -572,23 +564,20 @@ static int arcturus_populate_umd_state_clk(struct smu_context *smu)
{
struct smu_11_0_dpm_context *dpm_context =
smu->smu_dpm.dpm_context;
- struct smu_11_0_dpm_table *gfx_table =
- &dpm_context->dpm_tables.gfx_table;
- struct smu_11_0_dpm_table *mem_table =
- &dpm_context->dpm_tables.uclk_table;
- struct smu_11_0_dpm_table *soc_table =
- &dpm_context->dpm_tables.soc_table;
+ struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table;
+ struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table;
+ struct smu_dpm_table *soc_table = &dpm_context->dpm_tables.soc_table;
struct smu_umd_pstate_table *pstate_table =
&smu->pstate_table;
- pstate_table->gfxclk_pstate.min = gfx_table->min;
- pstate_table->gfxclk_pstate.peak = gfx_table->max;
+ pstate_table->gfxclk_pstate.min = SMU_DPM_TABLE_MIN(gfx_table);
+ pstate_table->gfxclk_pstate.peak = SMU_DPM_TABLE_MAX(gfx_table);
- pstate_table->uclk_pstate.min = mem_table->min;
- pstate_table->uclk_pstate.peak = mem_table->max;
+ pstate_table->uclk_pstate.min = SMU_DPM_TABLE_MIN(mem_table);
+ pstate_table->uclk_pstate.peak = SMU_DPM_TABLE_MAX(mem_table);
- pstate_table->socclk_pstate.min = soc_table->min;
- pstate_table->socclk_pstate.peak = soc_table->max;
+ pstate_table->socclk_pstate.min = SMU_DPM_TABLE_MIN(soc_table);
+ pstate_table->socclk_pstate.peak = SMU_DPM_TABLE_MAX(soc_table);
if (gfx_table->count > ARCTURUS_UMD_PSTATE_GFXCLK_LEVEL &&
mem_table->count > ARCTURUS_UMD_PSTATE_MCLK_LEVEL &&
@@ -611,29 +600,6 @@ static int arcturus_populate_umd_state_clk(struct smu_context *smu)
return 0;
}
-static void arcturus_get_clk_table(struct smu_context *smu,
- struct pp_clock_levels_with_latency *clocks,
- struct smu_11_0_dpm_table *dpm_table)
-{
- uint32_t i;
-
- clocks->num_levels = min_t(uint32_t,
- dpm_table->count,
- (uint32_t)PP_MAX_CLOCK_LEVELS);
-
- for (i = 0; i < clocks->num_levels; i++) {
- clocks->data[i].clocks_in_khz =
- dpm_table->dpm_levels[i].value * 1000;
- clocks->data[i].latency_in_us = 0;
- }
-}
-
-static int arcturus_freqs_in_same_level(int32_t frequency1,
- int32_t frequency2)
-{
- return (abs(frequency1 - frequency2) <= EPSILON);
-}
-
static int arcturus_get_smu_metrics_data(struct smu_context *smu,
MetricsMember_t member,
uint32_t *value)
@@ -800,15 +766,12 @@ static int arcturus_get_current_clk_freq_by_table(struct smu_context *smu,
static int arcturus_emit_clk_levels(struct smu_context *smu,
enum smu_clk_type type, char *buf, int *offset)
{
- int ret = 0;
- struct pp_clock_levels_with_latency clocks;
- struct smu_11_0_dpm_table *single_dpm_table;
- struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
- struct smu_11_0_dpm_context *dpm_context = NULL;
+ struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
+ struct smu_dpm_table *single_dpm_table;
+ struct smu_pcie_table *pcie_table;
uint32_t gen_speed, lane_width;
- uint32_t i, cur_value = 0;
- bool freq_match;
- unsigned int clock_mhz;
+ uint32_t cur_value = 0;
+ int ret = 0;
static const char attempt_string[] = "Attempt to get current";
if (amdgpu_ras_intr_triggered()) {
@@ -816,8 +779,6 @@ static int arcturus_emit_clk_levels(struct smu_context *smu,
return -EBUSY;
}
- dpm_context = smu_dpm->dpm_context;
-
switch (type) {
case SMU_SCLK:
ret = arcturus_get_current_clk_freq_by_table(smu, SMU_GFXCLK, &cur_value);
@@ -825,10 +786,11 @@ static int arcturus_emit_clk_levels(struct smu_context *smu,
dev_err(smu->adev->dev, "%s gfx clk Failed!", attempt_string);
return ret;
}
-
single_dpm_table = &(dpm_context->dpm_tables.gfx_table);
- arcturus_get_clk_table(smu, &clocks, single_dpm_table);
-
+ ret = smu_cmn_print_dpm_clk_levels(smu, single_dpm_table,
+ cur_value, buf, offset);
+ if (ret < 0)
+ return ret;
break;
case SMU_MCLK:
@@ -837,10 +799,11 @@ static int arcturus_emit_clk_levels(struct smu_context *smu,
dev_err(smu->adev->dev, "%s mclk Failed!", attempt_string);
return ret;
}
-
single_dpm_table = &(dpm_context->dpm_tables.uclk_table);
- arcturus_get_clk_table(smu, &clocks, single_dpm_table);
-
+ ret = smu_cmn_print_dpm_clk_levels(smu, single_dpm_table,
+ cur_value, buf, offset);
+ if (ret < 0)
+ return ret;
break;
case SMU_SOCCLK:
@@ -849,10 +812,11 @@ static int arcturus_emit_clk_levels(struct smu_context *smu,
dev_err(smu->adev->dev, "%s socclk Failed!", attempt_string);
return ret;
}
-
single_dpm_table = &(dpm_context->dpm_tables.soc_table);
- arcturus_get_clk_table(smu, &clocks, single_dpm_table);
-
+ ret = smu_cmn_print_dpm_clk_levels(smu, single_dpm_table,
+ cur_value, buf, offset);
+ if (ret < 0)
+ return ret;
break;
case SMU_FCLK:
@@ -861,10 +825,11 @@ static int arcturus_emit_clk_levels(struct smu_context *smu,
dev_err(smu->adev->dev, "%s fclk Failed!", attempt_string);
return ret;
}
-
single_dpm_table = &(dpm_context->dpm_tables.fclk_table);
- arcturus_get_clk_table(smu, &clocks, single_dpm_table);
-
+ ret = smu_cmn_print_dpm_clk_levels(smu, single_dpm_table,
+ cur_value, buf, offset);
+ if (ret < 0)
+ return ret;
break;
case SMU_VCLK:
@@ -873,10 +838,11 @@ static int arcturus_emit_clk_levels(struct smu_context *smu,
dev_err(smu->adev->dev, "%s vclk Failed!", attempt_string);
return ret;
}
-
single_dpm_table = &(dpm_context->dpm_tables.vclk_table);
- arcturus_get_clk_table(smu, &clocks, single_dpm_table);
-
+ ret = smu_cmn_print_dpm_clk_levels(smu, single_dpm_table,
+ cur_value, buf, offset);
+ if (ret < 0)
+ return ret;
break;
case SMU_DCLK:
@@ -885,56 +851,27 @@ static int arcturus_emit_clk_levels(struct smu_context *smu,
dev_err(smu->adev->dev, "%s dclk Failed!", attempt_string);
return ret;
}
-
single_dpm_table = &(dpm_context->dpm_tables.dclk_table);
- arcturus_get_clk_table(smu, &clocks, single_dpm_table);
-
+ ret = smu_cmn_print_dpm_clk_levels(smu, single_dpm_table,
+ cur_value, buf, offset);
+ if (ret < 0)
+ return ret;
break;
case SMU_PCIE:
gen_speed = smu_v11_0_get_current_pcie_link_speed_level(smu);
lane_width = smu_v11_0_get_current_pcie_link_width_level(smu);
- break;
-
- default:
- return -EINVAL;
- }
-
- switch (type) {
- case SMU_SCLK:
- case SMU_MCLK:
- case SMU_SOCCLK:
- case SMU_FCLK:
- case SMU_VCLK:
- case SMU_DCLK:
- /*
- * For DPM disabled case, there will be only one clock level.
- * And it's safe to assume that is always the current clock.
- */
- for (i = 0; i < clocks.num_levels; i++) {
- clock_mhz = clocks.data[i].clocks_in_khz / 1000;
- freq_match = arcturus_freqs_in_same_level(clock_mhz, cur_value);
- freq_match |= (clocks.num_levels == 1);
-
- *offset += sysfs_emit_at(buf, *offset, "%d: %uMhz %s\n",
- i, clock_mhz,
- freq_match ? "*" : "");
- }
- break;
-
- case SMU_PCIE:
- *offset += sysfs_emit_at(buf, *offset, "0: %s %s %dMhz *\n",
- (gen_speed == 0) ? "2.5GT/s," :
- (gen_speed == 1) ? "5.0GT/s," :
- (gen_speed == 2) ? "8.0GT/s," :
- (gen_speed == 3) ? "16.0GT/s," : "",
- (lane_width == 1) ? "x1" :
- (lane_width == 2) ? "x2" :
- (lane_width == 3) ? "x4" :
- (lane_width == 4) ? "x8" :
- (lane_width == 5) ? "x12" :
- (lane_width == 6) ? "x16" : "",
- smu->smu_table.boot_values.lclk / 100);
+ pcie_table = &(dpm_context->dpm_tables.pcie_table);
+ /* Populate with current state - arcturus only has boot level lclk */
+ pcie_table->lclk_levels = 1;
+ pcie_table->pcie_gen[0] = gen_speed;
+ pcie_table->pcie_lane[0] = lane_width;
+ pcie_table->lclk_freq[0] =
+ smu->smu_table.boot_values.lclk / 100;
+ ret = smu_cmn_print_pcie_levels(smu, pcie_table, gen_speed,
+ lane_width, buf, offset);
+ if (ret < 0)
+ return ret;
break;
default:
@@ -1003,7 +940,7 @@ static int arcturus_force_clk_levels(struct smu_context *smu,
enum smu_clk_type type, uint32_t mask)
{
struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
- struct smu_11_0_dpm_table *single_dpm_table = NULL;
+ struct smu_dpm_table *single_dpm_table = NULL;
uint32_t soft_min_level, soft_max_level;
int ret = 0;
@@ -1267,6 +1204,9 @@ static int arcturus_set_fan_speed_rpm(struct smu_context *smu,
uint32_t crystal_clock_freq = 2500;
uint32_t tach_period;
+ if (!speed || speed > UINT_MAX/8)
+ return -EINVAL;
+
tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
WREG32_SOC15(THM, 0, mmCG_TACH_CTRL_ARCT,
REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_TACH_CTRL_ARCT),
@@ -1344,7 +1284,7 @@ static int arcturus_get_power_limit(struct smu_context *smu,
*default_power_limit = power_limit;
if (max_power_limit)
*max_power_limit = power_limit;
- /**
+ /*
* No lower bound is imposed on the limit. Any unreasonable limit set
* will result in frequent throttling.
*/
@@ -1588,13 +1528,14 @@ static int arcturus_set_performance_level(struct smu_context *smu,
static bool arcturus_is_dpm_running(struct smu_context *smu)
{
int ret = 0;
- uint64_t feature_enabled;
+ struct smu_feature_bits feature_enabled;
ret = smu_cmn_get_enabled_mask(smu, &feature_enabled);
if (ret)
return false;
- return !!(feature_enabled & SMC_DPM_FEATURE);
+ return smu_feature_bits_test_mask(&feature_enabled,
+ arcturus_dpm_features.bits);
}
static int arcturus_dpm_set_vcn_enable(struct smu_context *smu,
@@ -1639,7 +1580,7 @@ static int arcturus_i2c_xfer(struct i2c_adapter *i2c_adap,
if (!adev->pm.dpm_enabled)
return -EBUSY;
- req = kzalloc(sizeof(*req), GFP_KERNEL);
+ req = kzalloc_obj(*req);
if (!req)
return -ENOMEM;
@@ -1742,10 +1683,10 @@ static int arcturus_i2c_control_init(struct smu_context *smu)
snprintf(control->name, sizeof(control->name), "AMDGPU SMU %d", i);
i2c_set_adapdata(control, smu_i2c);
- res = i2c_add_adapter(control);
+ res = devm_i2c_add_adapter(adev->dev, control);
if (res) {
DRM_ERROR("Failed to register hw i2c, err: %d\n", res);
- goto Out_err;
+ return res;
}
}
@@ -1753,27 +1694,12 @@ static int arcturus_i2c_control_init(struct smu_context *smu)
adev->pm.fru_eeprom_i2c_bus = &adev->pm.smu_i2c[1].adapter;
return 0;
-Out_err:
- for ( ; i >= 0; i--) {
- struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i];
- struct i2c_adapter *control = &smu_i2c->adapter;
-
- i2c_del_adapter(control);
- }
- return res;
}
static void arcturus_i2c_control_fini(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- int i;
-
- for (i = 0; i < MAX_SMU_I2C_BUSES; i++) {
- struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i];
- struct i2c_adapter *control = &smu_i2c->adapter;
- i2c_del_adapter(control);
- }
adev->pm.ras_eeprom_i2c_bus = NULL;
adev->pm.fru_eeprom_i2c_bus = NULL;
}
@@ -1886,15 +1812,15 @@ static uint16_t arcturus_get_current_pcie_link_speed(struct smu_context *smu)
static ssize_t arcturus_get_gpu_metrics(struct smu_context *smu,
void **table)
{
- struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v1_3 *gpu_metrics =
- (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table;
+ (struct gpu_metrics_v1_3 *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
SmuMetrics_t metrics;
int ret = 0;
ret = smu_cmn_get_metrics_table(smu,
&metrics,
- true);
+ false);
if (ret)
return ret;
@@ -1942,12 +1868,14 @@ static ssize_t arcturus_get_gpu_metrics(struct smu_context *smu,
*table = (void *)gpu_metrics;
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
return sizeof(struct gpu_metrics_v1_3);
}
static const struct pptable_funcs arcturus_ppt_funcs = {
/* init dpm */
- .get_allowed_feature_mask = arcturus_get_allowed_feature_mask,
+ .init_allowed_features = arcturus_init_allowed_features,
/* btc */
.run_btc = arcturus_run_btc,
/* dpm/clk tables */
@@ -1979,14 +1907,12 @@ static const struct pptable_funcs arcturus_ppt_funcs = {
/* pptable related */
.setup_pptable = arcturus_setup_pptable,
.get_vbios_bootup_values = smu_v11_0_get_vbios_bootup_values,
- .check_fw_version = smu_v11_0_check_fw_version,
+ .check_fw_version = smu_cmn_check_fw_version,
.write_pptable = smu_cmn_write_pptable,
.set_driver_table_location = smu_v11_0_set_driver_table_location,
.set_tool_table_location = smu_v11_0_set_tool_table_location,
.notify_memory_pool_location = smu_v11_0_notify_memory_pool_location,
.system_features_control = smu_v11_0_system_features_control,
- .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
- .send_smc_msg = smu_cmn_send_smc_msg,
.init_display_count = NULL,
.set_allowed_mask = smu_v11_0_set_allowed_mask,
.get_enabled_mask = smu_cmn_get_enabled_mask,
@@ -2029,11 +1955,11 @@ static const struct pptable_funcs arcturus_ppt_funcs = {
void arcturus_set_ppt_funcs(struct smu_context *smu)
{
smu->ppt_funcs = &arcturus_ppt_funcs;
- smu->message_map = arcturus_message_map;
smu->clock_map = arcturus_clk_map;
smu->feature_map = arcturus_feature_mask_map;
smu->table_map = arcturus_table_map;
smu->pwr_src_map = arcturus_pwr_src_map;
smu->workload_map = arcturus_workload_map;
- smu_v11_0_set_smu_mailbox_registers(smu);
+ smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_ARCT;
+ smu_v11_0_init_msg_ctl(smu, arcturus_message_map);
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c
index 9548bd3c624b..e6e009df9840 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c
@@ -60,11 +60,13 @@ static struct gfx_user_settings {
static uint32_t cyan_skillfish_sclk_default;
-#define FEATURE_MASK(feature) (1ULL << feature)
-#define SMC_DPM_FEATURE ( \
- FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_SOC_DPM_BIT) | \
- FEATURE_MASK(FEATURE_GFX_DPM_BIT))
+static const struct smu_feature_bits cyan_skillfish_dpm_features = {
+ .bits = {
+ SMU_FEATURE_BIT_INIT(FEATURE_FCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_SOC_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_GFX_DPM_BIT)
+ }
+};
static struct cmn2asic_msg_mapping cyan_skillfish_message_map[SMU_MSG_MAX_COUNT] = {
MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 0),
@@ -88,19 +90,21 @@ static int cyan_skillfish_tables_init(struct smu_context *smu)
{
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_table *tables = smu_table->tables;
+ int ret;
SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS,
sizeof(SmuMetrics_t),
PAGE_SIZE,
AMDGPU_GEM_DOMAIN_VRAM);
- smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
+ smu_table->metrics_table = kzalloc_obj(SmuMetrics_t);
if (!smu_table->metrics_table)
goto err0_out;
- smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_2);
- smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
- if (!smu_table->gpu_metrics_table)
+ ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS,
+ sizeof(struct gpu_metrics_v2_2),
+ SMU_GPU_METRICS_CACHE_INTERVAL);
+ if (ret)
goto err1_out;
smu_table->metrics_time = 0;
@@ -108,7 +112,6 @@ static int cyan_skillfish_tables_init(struct smu_context *smu)
return 0;
err1_out:
- smu_table->gpu_metrics_table_size = 0;
kfree(smu_table->metrics_table);
err0_out:
return -ENOMEM;
@@ -287,16 +290,14 @@ static int cyan_skillfish_get_current_clk_freq(struct smu_context *smu,
return cyan_skillfish_get_smu_metrics_data(smu, member_type, value);
}
-static int cyan_skillfish_print_clk_levels(struct smu_context *smu,
- enum smu_clk_type clk_type,
- char *buf)
+static int cyan_skillfish_emit_clk_levels(struct smu_context *smu,
+ enum smu_clk_type clk_type, char *buf,
+ int *offset)
{
- int ret = 0, size = 0;
+ int ret = 0, size = *offset, start_offset = *offset;
uint32_t cur_value = 0;
int i;
- smu_cmn_get_sysfs_buf(&buf, &size);
-
switch (clk_type) {
case SMU_OD_SCLK:
ret = cyan_skillfish_get_smu_metrics_data(smu, METRICS_CURR_GFXCLK, &cur_value);
@@ -353,14 +354,16 @@ static int cyan_skillfish_print_clk_levels(struct smu_context *smu,
return ret;
}
- return size;
+ *offset += size - start_offset;
+
+ return 0;
}
static bool cyan_skillfish_is_dpm_running(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
int ret = 0;
- uint64_t feature_enabled;
+ struct smu_feature_bits feature_enabled;
/* we need to re-init after suspend so return false */
if (adev->in_suspend)
@@ -377,15 +380,16 @@ static bool cyan_skillfish_is_dpm_running(struct smu_context *smu)
cyan_skillfish_get_smu_metrics_data(smu, METRICS_CURR_GFXCLK,
&cyan_skillfish_sclk_default);
- return !!(feature_enabled & SMC_DPM_FEATURE);
+ return smu_feature_bits_test_mask(&feature_enabled,
+ cyan_skillfish_dpm_features.bits);
}
static ssize_t cyan_skillfish_get_gpu_metrics(struct smu_context *smu,
void **table)
{
- struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v2_2 *gpu_metrics =
- (struct gpu_metrics_v2_2 *)smu_table->gpu_metrics_table;
+ (struct gpu_metrics_v2_2 *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
SmuMetrics_t metrics;
int i, ret = 0;
@@ -432,6 +436,8 @@ static ssize_t cyan_skillfish_get_gpu_metrics(struct smu_context *smu,
*table = (void *)gpu_metrics;
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
return sizeof(struct gpu_metrics_v2_2);
}
@@ -562,12 +568,13 @@ static int cyan_skillfish_get_dpm_ultimate_freq(struct smu_context *smu,
return 0;
}
-static int cyan_skillfish_get_enabled_mask(struct smu_context *smu,
- uint64_t *feature_mask)
+static int
+cyan_skillfish_get_enabled_mask(struct smu_context *smu,
+ struct smu_feature_bits *feature_mask)
{
if (!feature_mask)
return -EINVAL;
- memset(feature_mask, 0xff, sizeof(*feature_mask));
+ smu_feature_bits_fill(feature_mask);
return 0;
}
@@ -575,13 +582,13 @@ static int cyan_skillfish_get_enabled_mask(struct smu_context *smu,
static const struct pptable_funcs cyan_skillfish_ppt_funcs = {
.check_fw_status = smu_v11_0_check_fw_status,
- .check_fw_version = smu_v11_0_check_fw_version,
+ .check_fw_version = smu_cmn_check_fw_version,
.init_power = smu_v11_0_init_power,
.fini_power = smu_v11_0_fini_power,
.init_smc_tables = cyan_skillfish_init_smc_tables,
.fini_smc_tables = smu_v11_0_fini_smc_tables,
.read_sensor = cyan_skillfish_read_sensor,
- .print_clk_levels = cyan_skillfish_print_clk_levels,
+ .emit_clk_levels = cyan_skillfish_emit_clk_levels,
.get_enabled_mask = cyan_skillfish_get_enabled_mask,
.is_dpm_running = cyan_skillfish_is_dpm_running,
.get_gpu_metrics = cyan_skillfish_get_gpu_metrics,
@@ -589,8 +596,6 @@ static const struct pptable_funcs cyan_skillfish_ppt_funcs = {
.get_dpm_ultimate_freq = cyan_skillfish_get_dpm_ultimate_freq,
.register_irq_handler = smu_v11_0_register_irq_handler,
.notify_memory_pool_location = smu_v11_0_notify_memory_pool_location,
- .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
- .send_smc_msg = smu_cmn_send_smc_msg,
.set_driver_table_location = smu_v11_0_set_driver_table_location,
.interrupt_work = smu_v11_0_interrupt_work,
};
@@ -598,8 +603,8 @@ static const struct pptable_funcs cyan_skillfish_ppt_funcs = {
void cyan_skillfish_set_ppt_funcs(struct smu_context *smu)
{
smu->ppt_funcs = &cyan_skillfish_ppt_funcs;
- smu->message_map = cyan_skillfish_message_map;
smu->table_map = cyan_skillfish_table_map;
smu->is_apu = true;
- smu_v11_0_set_smu_mailbox_registers(smu);
+ smu->smc_driver_if_version = MP1_DRIVER_IF_VERSION;
+ smu_v11_0_init_msg_ctl(smu, cyan_skillfish_message_map);
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
index 7fad5dfb39c4..cd0457e13f54 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
@@ -58,19 +58,25 @@
#undef pr_info
#undef pr_debug
-#define FEATURE_MASK(feature) (1ULL << feature)
-#define SMC_DPM_FEATURE ( \
- FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) | \
- FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_GFX_PACE_BIT) | \
- FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_LINK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT))
+static const struct smu_feature_bits navi10_dpm_features = {
+ .bits = {
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_PREFETCHER_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFX_PACE_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_MP0CLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_LINK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_DCEFCLK_BIT)
+ }
+};
#define SMU_11_0_GFX_BUSY_THRESHOLD 15
+#define SMU11_DRIVER_IF_VERSION_NV10 0x37
+#define SMU11_DRIVER_IF_VERSION_NV12 0x38
+#define SMU11_DRIVER_IF_VERSION_NV14 0x38
+
static struct cmn2asic_msg_mapping navi10_message_map[SMU_MSG_MAX_COUNT] = {
MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1),
MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1),
@@ -275,89 +281,83 @@ static bool is_asic_secure(struct smu_context *smu)
}
static int
-navi10_get_allowed_feature_mask(struct smu_context *smu,
- uint32_t *feature_mask, uint32_t num)
+navi10_init_allowed_features(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- if (num > 2)
- return -EINVAL;
-
- memset(feature_mask, 0, sizeof(uint32_t) * num);
-
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT)
- | FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT)
- | FEATURE_MASK(FEATURE_RSMU_SMN_CG_BIT)
- | FEATURE_MASK(FEATURE_DS_SOCCLK_BIT)
- | FEATURE_MASK(FEATURE_PPT_BIT)
- | FEATURE_MASK(FEATURE_TDC_BIT)
- | FEATURE_MASK(FEATURE_GFX_EDC_BIT)
- | FEATURE_MASK(FEATURE_APCC_PLUS_BIT)
- | FEATURE_MASK(FEATURE_VR0HOT_BIT)
- | FEATURE_MASK(FEATURE_FAN_CONTROL_BIT)
- | FEATURE_MASK(FEATURE_THERMAL_BIT)
- | FEATURE_MASK(FEATURE_LED_DISPLAY_BIT)
- | FEATURE_MASK(FEATURE_DS_LCLK_BIT)
- | FEATURE_MASK(FEATURE_DS_DCEFCLK_BIT)
- | FEATURE_MASK(FEATURE_FW_DSTATE_BIT)
- | FEATURE_MASK(FEATURE_BACO_BIT)
- | FEATURE_MASK(FEATURE_GFX_SS_BIT)
- | FEATURE_MASK(FEATURE_APCC_DFLL_BIT)
- | FEATURE_MASK(FEATURE_FW_CTF_BIT)
- | FEATURE_MASK(FEATURE_OUT_OF_BAND_MONITOR_BIT)
- | FEATURE_MASK(FEATURE_TEMP_DEPENDENT_VMIN_BIT);
+ smu_feature_list_clear_all(smu, SMU_FEATURE_LIST_ALLOWED);
+
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_PREFETCHER_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_MP0CLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_RSMU_SMN_CG_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_SOCCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_PPT_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_TDC_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFX_EDC_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_APCC_PLUS_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_VR0HOT_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_FAN_CONTROL_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_THERMAL_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_LED_DISPLAY_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_LCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_DCEFCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_FW_DSTATE_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_BACO_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFX_SS_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_APCC_DFLL_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_FW_CTF_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_OUT_OF_BAND_MONITOR_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_TEMP_DEPENDENT_VMIN_BIT);
if (adev->pm.pp_feature & PP_SCLK_DPM_MASK)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_GFXCLK_BIT);
if (adev->pm.pp_feature & PP_PCIE_DPM_MASK)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_LINK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_LINK_BIT);
if (adev->pm.pp_feature & PP_DCEFCLK_DPM_MASK)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_DCEFCLK_BIT);
if (adev->pm.pp_feature & PP_ULV_MASK)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_ULV_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFX_ULV_BIT);
if (adev->pm.pp_feature & PP_SCLK_DEEP_SLEEP_MASK)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_GFXCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_GFXCLK_BIT);
if (adev->pm.pp_feature & PP_GFXOFF_MASK)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFXOFF_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFXOFF_BIT);
if (smu->adev->pg_flags & AMD_PG_SUPPORT_MMHUB)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_MMHUB_PG_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_MMHUB_PG_BIT);
if (smu->adev->pg_flags & AMD_PG_SUPPORT_ATHUB)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ATHUB_PG_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_ATHUB_PG_BIT);
if (smu->adev->pg_flags & AMD_PG_SUPPORT_VCN)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_VCN_PG_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_VCN_PG_BIT);
if (smu->adev->pg_flags & AMD_PG_SUPPORT_JPEG)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_JPEG_PG_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_JPEG_PG_BIT);
if (smu->dc_controlled_by_gpio)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ACDC_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_ACDC_BIT);
if (adev->pm.pp_feature & PP_SOCCLK_DPM_MASK)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_SOCCLK_BIT);
- /* DPM UCLK enablement should be skipped for navi10 A0 secure board */
if (!(is_asic_secure(smu) &&
(amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 0)) &&
(adev->rev_id == 0)) &&
- (adev->pm.pp_feature & PP_MCLK_DPM_MASK))
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_UCLK_BIT)
- | FEATURE_MASK(FEATURE_MEM_VDDCI_SCALING_BIT)
- | FEATURE_MASK(FEATURE_MEM_MVDD_SCALING_BIT);
+ (adev->pm.pp_feature & PP_MCLK_DPM_MASK)) {
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_UCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_MEM_VDDCI_SCALING_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_MEM_MVDD_SCALING_BIT);
+ }
- /* DS SOCCLK enablement should be skipped for navi10 A0 secure board */
if (is_asic_secure(smu) &&
(amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 0)) &&
(adev->rev_id == 0))
- *(uint64_t *)feature_mask &=
- ~FEATURE_MASK(FEATURE_DS_SOCCLK_BIT);
+ smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_SOCCLK_BIT);
return 0;
}
@@ -495,8 +495,8 @@ static int navi10_tables_init(struct smu_context *smu)
{
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_table *tables = smu_table->tables;
- struct smu_table *dummy_read_1_table =
- &smu_table->dummy_read_1_table;
+ struct smu_table *dummy_read_1_table = &smu_table->dummy_read_1_table;
+ int ret;
SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
@@ -520,18 +520,18 @@ static int navi10_tables_init(struct smu_context *smu)
dummy_read_1_table->align = PAGE_SIZE;
dummy_read_1_table->domain = AMDGPU_GEM_DOMAIN_VRAM;
- smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_NV1X_t),
- GFP_KERNEL);
+ smu_table->metrics_table = kzalloc_obj(SmuMetrics_NV1X_t);
if (!smu_table->metrics_table)
goto err0_out;
smu_table->metrics_time = 0;
- smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_3);
- smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
- if (!smu_table->gpu_metrics_table)
+ ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS,
+ sizeof(struct gpu_metrics_v1_3),
+ SMU_GPU_METRICS_CACHE_INTERVAL);
+ if (ret)
goto err1_out;
- smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL);
+ smu_table->watermarks_table = kzalloc_obj(Watermarks_t);
if (!smu_table->watermarks_table)
goto err2_out;
@@ -545,7 +545,7 @@ static int navi10_tables_init(struct smu_context *smu)
err3_out:
kfree(smu_table->watermarks_table);
err2_out:
- kfree(smu_table->gpu_metrics_table);
+ smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS);
err1_out:
kfree(smu_table->metrics_table);
err0_out:
@@ -938,8 +938,7 @@ static int navi10_allocate_dpm_context(struct smu_context *smu)
{
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
- smu_dpm->dpm_context = kzalloc(sizeof(struct smu_11_0_dpm_context),
- GFP_KERNEL);
+ smu_dpm->dpm_context = kzalloc_obj(struct smu_11_0_dpm_context);
if (!smu_dpm->dpm_context)
return -ENOMEM;
@@ -967,169 +966,160 @@ static int navi10_set_default_dpm_table(struct smu_context *smu)
{
struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
PPTable_t *driver_ppt = smu->smu_table.driver_pptable;
- struct smu_11_0_dpm_table *dpm_table;
+ struct smu_dpm_table *dpm_table;
int ret = 0;
/* socclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.soc_table;
+ dpm_table->clk_type = SMU_SOCCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
SMU_SOCCLK,
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !driver_ppt->DpmDescriptor[PPCLK_SOCCLK].SnapToDiscrete;
+ if (!driver_ppt->DpmDescriptor[PPCLK_SOCCLK].SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.socclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* gfxclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.gfx_table;
+ dpm_table->clk_type = SMU_GFXCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
SMU_GFXCLK,
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !driver_ppt->DpmDescriptor[PPCLK_GFXCLK].SnapToDiscrete;
+ if (!driver_ppt->DpmDescriptor[PPCLK_GFXCLK].SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* uclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.uclk_table;
+ dpm_table->clk_type = SMU_UCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
SMU_UCLK,
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !driver_ppt->DpmDescriptor[PPCLK_UCLK].SnapToDiscrete;
+ if (!driver_ppt->DpmDescriptor[PPCLK_UCLK].SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.uclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* vclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.vclk_table;
+ dpm_table->clk_type = SMU_VCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
SMU_VCLK,
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !driver_ppt->DpmDescriptor[PPCLK_VCLK].SnapToDiscrete;
+ if (!driver_ppt->DpmDescriptor[PPCLK_VCLK].SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.vclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* dclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.dclk_table;
+ dpm_table->clk_type = SMU_DCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
SMU_DCLK,
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !driver_ppt->DpmDescriptor[PPCLK_DCLK].SnapToDiscrete;
+ if (!driver_ppt->DpmDescriptor[PPCLK_DCLK].SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* dcefclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.dcef_table;
+ dpm_table->clk_type = SMU_DCEFCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
SMU_DCEFCLK,
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !driver_ppt->DpmDescriptor[PPCLK_DCEFCLK].SnapToDiscrete;
+ if (!driver_ppt->DpmDescriptor[PPCLK_DCEFCLK].SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* pixelclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.pixel_table;
+ dpm_table->clk_type = SMU_PIXCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
SMU_PIXCLK,
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !driver_ppt->DpmDescriptor[PPCLK_PIXCLK].SnapToDiscrete;
+ if (!driver_ppt->DpmDescriptor[PPCLK_PIXCLK].SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* displayclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.display_table;
+ dpm_table->clk_type = SMU_DISPCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
SMU_DISPCLK,
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !driver_ppt->DpmDescriptor[PPCLK_DISPCLK].SnapToDiscrete;
+ if (!driver_ppt->DpmDescriptor[PPCLK_DISPCLK].SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* phyclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.phy_table;
+ dpm_table->clk_type = SMU_PHYCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
SMU_PHYCLK,
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !driver_ppt->DpmDescriptor[PPCLK_PHYCLK].SnapToDiscrete;
+ if (!driver_ppt->DpmDescriptor[PPCLK_PHYCLK].SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
return 0;
@@ -1261,104 +1251,48 @@ static int navi10_emit_clk_levels(struct smu_context *smu,
{
uint16_t *curve_settings;
int ret = 0;
- uint32_t cur_value = 0, value = 0;
- uint32_t freq_values[3] = {0};
- uint32_t i, levels, mark_index = 0, count = 0;
+ uint32_t cur_value = 0;
+ uint32_t i;
struct smu_table_context *table_context = &smu->smu_table;
uint32_t gen_speed, lane_width;
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context;
- PPTable_t *pptable = (PPTable_t *)table_context->driver_pptable;
OverDriveTable_t *od_table =
(OverDriveTable_t *)table_context->overdrive_table;
struct smu_11_0_overdrive_table *od_settings = smu->od_settings;
+ struct smu_dpm_table *single_dpm_table = NULL;
+ struct smu_pcie_table *pcie_table;
uint32_t min_value, max_value;
switch (clk_type) {
case SMU_GFXCLK:
case SMU_SCLK:
+ single_dpm_table = &(dpm_context->dpm_tables.gfx_table);
+ break;
+ /* FCLK and SOC CLK mapped to SOCCLK in clock map table */
case SMU_SOCCLK:
+ case SMU_FCLK:
+ single_dpm_table = &(dpm_context->dpm_tables.soc_table);
+ break;
case SMU_MCLK:
case SMU_UCLK:
- case SMU_FCLK:
+ single_dpm_table = &(dpm_context->dpm_tables.uclk_table);
+ break;
case SMU_VCLK:
+ single_dpm_table = &(dpm_context->dpm_tables.vclk_table);
+ break;
case SMU_DCLK:
+ single_dpm_table = &(dpm_context->dpm_tables.dclk_table);
+ break;
case SMU_DCEFCLK:
- ret = navi10_get_current_clk_freq_by_table(smu, clk_type, &cur_value);
- if (ret)
- return ret;
-
- ret = smu_v11_0_get_dpm_level_count(smu, clk_type, &count);
- if (ret)
- return ret;
-
- ret = navi10_is_support_fine_grained_dpm(smu, clk_type);
- if (ret < 0)
- return ret;
-
- if (!ret) {
- for (i = 0; i < count; i++) {
- ret = smu_v11_0_get_dpm_freq_by_index(smu,
- clk_type, i, &value);
- if (ret)
- return ret;
-
- *offset += sysfs_emit_at(buf, *offset,
- "%d: %uMhz %s\n",
- i, value,
- cur_value == value ? "*" : "");
- }
- } else {
- ret = smu_v11_0_get_dpm_freq_by_index(smu,
- clk_type, 0, &freq_values[0]);
- if (ret)
- return ret;
- ret = smu_v11_0_get_dpm_freq_by_index(smu,
- clk_type,
- count - 1,
- &freq_values[2]);
- if (ret)
- return ret;
-
- freq_values[1] = cur_value;
- mark_index = cur_value == freq_values[0] ? 0 :
- cur_value == freq_values[2] ? 2 : 1;
-
- levels = 3;
- if (mark_index != 1) {
- levels = 2;
- freq_values[1] = freq_values[2];
- }
-
- for (i = 0; i < levels; i++) {
- *offset += sysfs_emit_at(buf, *offset,
- "%d: %uMhz %s\n",
- i, freq_values[i],
- i == mark_index ? "*" : "");
- }
- }
+ single_dpm_table = &(dpm_context->dpm_tables.dcef_table);
break;
case SMU_PCIE:
gen_speed = smu_v11_0_get_current_pcie_link_speed_level(smu);
lane_width = smu_v11_0_get_current_pcie_link_width_level(smu);
- for (i = 0; i < NUM_LINK_LEVELS; i++) {
- *offset += sysfs_emit_at(buf, *offset, "%d: %s %s %dMhz %s\n", i,
- (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 0) ? "2.5GT/s," :
- (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 1) ? "5.0GT/s," :
- (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 2) ? "8.0GT/s," :
- (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 3) ? "16.0GT/s," : "",
- (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 1) ? "x1" :
- (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 2) ? "x2" :
- (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 3) ? "x4" :
- (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 4) ? "x8" :
- (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 5) ? "x12" :
- (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 6) ? "x16" : "",
- pptable->LclkFreq[i],
- (gen_speed == dpm_context->dpm_tables.pcie_table.pcie_gen[i]) &&
- (lane_width == dpm_context->dpm_tables.pcie_table.pcie_lane[i]) ?
- "*" : "");
- }
- break;
+ pcie_table = &dpm_context->dpm_tables.pcie_table;
+ return smu_cmn_print_pcie_levels(smu, pcie_table, gen_speed,
+ lane_width, buf, offset);
case SMU_OD_SCLK:
if (!smu->od_enabled || !od_table || !od_settings)
return -EOPNOTSUPP;
@@ -1462,198 +1396,16 @@ static int navi10_emit_clk_levels(struct smu_context *smu,
break;
}
- return 0;
-}
-
-static int navi10_print_clk_levels(struct smu_context *smu,
- enum smu_clk_type clk_type, char *buf)
-{
- uint16_t *curve_settings;
- int i, levels, size = 0, ret = 0;
- uint32_t cur_value = 0, value = 0, count = 0;
- uint32_t freq_values[3] = {0};
- uint32_t mark_index = 0;
- struct smu_table_context *table_context = &smu->smu_table;
- uint32_t gen_speed, lane_width;
- struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
- struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context;
- PPTable_t *pptable = (PPTable_t *)table_context->driver_pptable;
- OverDriveTable_t *od_table =
- (OverDriveTable_t *)table_context->overdrive_table;
- struct smu_11_0_overdrive_table *od_settings = smu->od_settings;
- uint32_t min_value, max_value;
-
- smu_cmn_get_sysfs_buf(&buf, &size);
-
- switch (clk_type) {
- case SMU_GFXCLK:
- case SMU_SCLK:
- case SMU_SOCCLK:
- case SMU_MCLK:
- case SMU_UCLK:
- case SMU_FCLK:
- case SMU_VCLK:
- case SMU_DCLK:
- case SMU_DCEFCLK:
- ret = navi10_get_current_clk_freq_by_table(smu, clk_type, &cur_value);
- if (ret)
- return size;
-
- ret = smu_v11_0_get_dpm_level_count(smu, clk_type, &count);
+ if (single_dpm_table) {
+ ret = navi10_get_current_clk_freq_by_table(smu, clk_type,
+ &cur_value);
if (ret)
- return size;
-
- ret = navi10_is_support_fine_grained_dpm(smu, clk_type);
- if (ret < 0)
return ret;
-
- if (!ret) {
- for (i = 0; i < count; i++) {
- ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, i, &value);
- if (ret)
- return size;
-
- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value,
- cur_value == value ? "*" : "");
- }
- } else {
- ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, 0, &freq_values[0]);
- if (ret)
- return size;
- ret = smu_v11_0_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;
-
- levels = 3;
- if (mark_index != 1) {
- levels = 2;
- freq_values[1] = freq_values[2];
- }
-
- for (i = 0; i < levels; i++) {
- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, freq_values[i],
- i == mark_index ? "*" : "");
- }
- }
- break;
- case SMU_PCIE:
- gen_speed = smu_v11_0_get_current_pcie_link_speed_level(smu);
- lane_width = smu_v11_0_get_current_pcie_link_width_level(smu);
- for (i = 0; i < NUM_LINK_LEVELS; i++)
- size += sysfs_emit_at(buf, size, "%d: %s %s %dMhz %s\n", i,
- (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 0) ? "2.5GT/s," :
- (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 1) ? "5.0GT/s," :
- (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 2) ? "8.0GT/s," :
- (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 3) ? "16.0GT/s," : "",
- (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 1) ? "x1" :
- (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 2) ? "x2" :
- (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 3) ? "x4" :
- (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 4) ? "x8" :
- (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 5) ? "x12" :
- (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 6) ? "x16" : "",
- pptable->LclkFreq[i],
- (gen_speed == dpm_context->dpm_tables.pcie_table.pcie_gen[i]) &&
- (lane_width == dpm_context->dpm_tables.pcie_table.pcie_lane[i]) ?
- "*" : "");
- break;
- case SMU_OD_SCLK:
- if (!smu->od_enabled || !od_table || !od_settings)
- break;
- if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_LIMITS))
- break;
- size += sysfs_emit_at(buf, size, "OD_SCLK:\n");
- size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n",
- od_table->GfxclkFmin, od_table->GfxclkFmax);
- break;
- case SMU_OD_MCLK:
- if (!smu->od_enabled || !od_table || !od_settings)
- break;
- if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_UCLK_MAX))
- break;
- size += sysfs_emit_at(buf, size, "OD_MCLK:\n");
- size += sysfs_emit_at(buf, size, "1: %uMHz\n", od_table->UclkFmax);
- break;
- case SMU_OD_VDDC_CURVE:
- if (!smu->od_enabled || !od_table || !od_settings)
- break;
- if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_CURVE))
- break;
- size += sysfs_emit_at(buf, size, "OD_VDDC_CURVE:\n");
- for (i = 0; i < 3; i++) {
- switch (i) {
- case 0:
- curve_settings = &od_table->GfxclkFreq1;
- break;
- case 1:
- curve_settings = &od_table->GfxclkFreq2;
- break;
- case 2:
- curve_settings = &od_table->GfxclkFreq3;
- break;
- }
- size += sysfs_emit_at(buf, size, "%d: %uMHz %umV\n",
- i, curve_settings[0],
- curve_settings[1] / NAVI10_VOLTAGE_SCALE);
- }
- break;
- case SMU_OD_RANGE:
- if (!smu->od_enabled || !od_table || !od_settings)
- break;
- size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");
-
- if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_LIMITS)) {
- navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_GFXCLKFMIN,
- &min_value, NULL);
- navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_GFXCLKFMAX,
- NULL, &max_value);
- size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n",
- min_value, max_value);
- }
-
- if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_UCLK_MAX)) {
- navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_UCLKFMAX,
- &min_value, &max_value);
- size += sysfs_emit_at(buf, size, "MCLK: %7uMhz %10uMhz\n",
- min_value, max_value);
- }
-
- if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_CURVE)) {
- navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P1,
- &min_value, &max_value);
- size += sysfs_emit_at(buf, size, "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n",
- min_value, max_value);
- navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P1,
- &min_value, &max_value);
- size += sysfs_emit_at(buf, size, "VDDC_CURVE_VOLT[0]: %7dmV %11dmV\n",
- min_value, max_value);
- navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P2,
- &min_value, &max_value);
- size += sysfs_emit_at(buf, size, "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n",
- min_value, max_value);
- navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P2,
- &min_value, &max_value);
- size += sysfs_emit_at(buf, size, "VDDC_CURVE_VOLT[1]: %7dmV %11dmV\n",
- min_value, max_value);
- navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P3,
- &min_value, &max_value);
- size += sysfs_emit_at(buf, size, "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n",
- min_value, max_value);
- navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P3,
- &min_value, &max_value);
- size += sysfs_emit_at(buf, size, "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n",
- min_value, max_value);
- }
-
- break;
- default:
- break;
+ return smu_cmn_print_dpm_clk_levels(smu, single_dpm_table,
+ cur_value, buf, offset);
}
- return size;
+ return 0;
}
static int navi10_force_clk_levels(struct smu_context *smu,
@@ -1710,18 +1462,15 @@ static int navi10_populate_umd_state_clk(struct smu_context *smu)
{
struct smu_11_0_dpm_context *dpm_context =
smu->smu_dpm.dpm_context;
- struct smu_11_0_dpm_table *gfx_table =
- &dpm_context->dpm_tables.gfx_table;
- struct smu_11_0_dpm_table *mem_table =
- &dpm_context->dpm_tables.uclk_table;
- struct smu_11_0_dpm_table *soc_table =
- &dpm_context->dpm_tables.soc_table;
+ struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table;
+ struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table;
+ struct smu_dpm_table *soc_table = &dpm_context->dpm_tables.soc_table;
struct smu_umd_pstate_table *pstate_table =
&smu->pstate_table;
struct amdgpu_device *adev = smu->adev;
uint32_t sclk_freq;
- pstate_table->gfxclk_pstate.min = gfx_table->min;
+ pstate_table->gfxclk_pstate.min = SMU_DPM_TABLE_MIN(gfx_table);
switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
case IP_VERSION(11, 0, 0):
switch (adev->pdev->revision) {
@@ -1770,15 +1519,15 @@ static int navi10_populate_umd_state_clk(struct smu_context *smu)
}
pstate_table->gfxclk_pstate.peak = sclk_freq;
- pstate_table->uclk_pstate.min = mem_table->min;
- pstate_table->uclk_pstate.peak = mem_table->max;
+ pstate_table->uclk_pstate.min = SMU_DPM_TABLE_MIN(mem_table);
+ pstate_table->uclk_pstate.peak = SMU_DPM_TABLE_MAX(mem_table);
- pstate_table->socclk_pstate.min = soc_table->min;
- pstate_table->socclk_pstate.peak = soc_table->max;
+ pstate_table->socclk_pstate.min = SMU_DPM_TABLE_MIN(soc_table);
+ pstate_table->socclk_pstate.peak = SMU_DPM_TABLE_MAX(soc_table);
- if (gfx_table->max > NAVI10_UMD_PSTATE_PROFILING_GFXCLK &&
- mem_table->max > NAVI10_UMD_PSTATE_PROFILING_MEMCLK &&
- soc_table->max > NAVI10_UMD_PSTATE_PROFILING_SOCCLK) {
+ if (SMU_DPM_TABLE_MAX(gfx_table) > NAVI10_UMD_PSTATE_PROFILING_GFXCLK &&
+ SMU_DPM_TABLE_MAX(mem_table) > NAVI10_UMD_PSTATE_PROFILING_MEMCLK &&
+ SMU_DPM_TABLE_MAX(soc_table) > NAVI10_UMD_PSTATE_PROFILING_SOCCLK) {
pstate_table->gfxclk_pstate.standard =
NAVI10_UMD_PSTATE_PROFILING_GFXCLK;
pstate_table->uclk_pstate.standard =
@@ -1874,13 +1623,14 @@ static int navi10_display_config_changed(struct smu_context *smu)
static bool navi10_is_dpm_running(struct smu_context *smu)
{
int ret = 0;
- uint64_t feature_enabled;
+ struct smu_feature_bits feature_enabled;
ret = smu_cmn_get_enabled_mask(smu, &feature_enabled);
if (ret)
return false;
- return !!(feature_enabled & SMC_DPM_FEATURE);
+ return smu_feature_bits_test_mask(&feature_enabled,
+ navi10_dpm_features.bits);
}
static int navi10_get_fan_speed_rpm(struct smu_context *smu,
@@ -2444,34 +2194,37 @@ static int navi10_update_pcie_parameters(struct smu_context *smu,
struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
PPTable_t *pptable = smu->smu_table.driver_pptable;
uint32_t smu_pcie_arg;
- int ret, i;
+ int ret = 0;
+ int i;
/* lclk dpm table setup */
- for (i = 0; i < MAX_PCIE_CONF; i++) {
+ for (i = 0; i < NUM_LINK_LEVELS; i++) {
dpm_context->dpm_tables.pcie_table.pcie_gen[i] = pptable->PcieGenSpeed[i];
dpm_context->dpm_tables.pcie_table.pcie_lane[i] = pptable->PcieLaneCount[i];
+ dpm_context->dpm_tables.pcie_table.lclk_freq[i] =
+ pptable->LclkFreq[i];
}
+ dpm_context->dpm_tables.pcie_table.lclk_levels = NUM_LINK_LEVELS;
for (i = 0; i < NUM_LINK_LEVELS; i++) {
- smu_pcie_arg = (i << 16) |
- ((pptable->PcieGenSpeed[i] <= pcie_gen_cap) ? (pptable->PcieGenSpeed[i] << 8) :
- (pcie_gen_cap << 8)) | ((pptable->PcieLaneCount[i] <= pcie_width_cap) ?
- pptable->PcieLaneCount[i] : pcie_width_cap);
+ dpm_context->dpm_tables.pcie_table.pcie_gen[i] =
+ pptable->PcieGenSpeed[i] > pcie_gen_cap ?
+ pcie_gen_cap : pptable->PcieGenSpeed[i];
+ dpm_context->dpm_tables.pcie_table.pcie_lane[i] =
+ pptable->PcieLaneCount[i] > pcie_width_cap ?
+ pcie_width_cap : pptable->PcieLaneCount[i];
+ smu_pcie_arg = i << 16;
+ smu_pcie_arg |= dpm_context->dpm_tables.pcie_table.pcie_gen[i] << 8;
+ smu_pcie_arg |= dpm_context->dpm_tables.pcie_table.pcie_lane[i];
ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_OverridePcieParameters,
- smu_pcie_arg,
- NULL);
-
+ SMU_MSG_OverridePcieParameters,
+ smu_pcie_arg,
+ NULL);
if (ret)
return ret;
-
- if (pptable->PcieGenSpeed[i] > pcie_gen_cap)
- dpm_context->dpm_tables.pcie_table.pcie_gen[i] = pcie_gen_cap;
- if (pptable->PcieLaneCount[i] > pcie_width_cap)
- dpm_context->dpm_tables.pcie_table.pcie_lane[i] = pcie_width_cap;
}
- return 0;
+ return ret;
}
static inline void navi10_dump_od_table(struct smu_context *smu,
@@ -2885,7 +2638,7 @@ static int navi10_set_dummy_pstates_table_location(struct smu_context *smu)
dummy_table += 0x1000;
}
- amdgpu_asic_flush_hdp(smu->adev, NULL);
+ amdgpu_hdp_flush(smu->adev, NULL);
ret = smu_cmn_send_smc_msg_with_param(smu,
SMU_MSG_SET_DRIVER_DUMMY_TABLE_DRAM_ADDR_HIGH,
@@ -2960,7 +2713,8 @@ static ssize_t navi10_get_legacy_gpu_metrics(struct smu_context *smu,
{
struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v1_3 *gpu_metrics =
- (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table;
+ (struct gpu_metrics_v1_3 *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
SmuMetrics_legacy_t metrics;
int ret = 0;
@@ -3022,6 +2776,8 @@ static ssize_t navi10_get_legacy_gpu_metrics(struct smu_context *smu,
*table = (void *)gpu_metrics;
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
return sizeof(struct gpu_metrics_v1_3);
}
@@ -3040,7 +2796,7 @@ static int navi10_i2c_xfer(struct i2c_adapter *i2c_adap,
if (!adev->pm.dpm_enabled)
return -EBUSY;
- req = kzalloc(sizeof(*req), GFP_KERNEL);
+ req = kzalloc_obj(*req);
if (!req)
return -ENOMEM;
@@ -3142,10 +2898,10 @@ static int navi10_i2c_control_init(struct smu_context *smu)
control->quirks = &navi10_i2c_control_quirks;
i2c_set_adapdata(control, smu_i2c);
- res = i2c_add_adapter(control);
+ res = devm_i2c_add_adapter(adev->dev, control);
if (res) {
DRM_ERROR("Failed to register hw i2c, err: %d\n", res);
- goto Out_err;
+ return res;
}
}
@@ -3153,27 +2909,12 @@ static int navi10_i2c_control_init(struct smu_context *smu)
adev->pm.fru_eeprom_i2c_bus = &adev->pm.smu_i2c[1].adapter;
return 0;
-Out_err:
- for ( ; i >= 0; i--) {
- struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i];
- struct i2c_adapter *control = &smu_i2c->adapter;
-
- i2c_del_adapter(control);
- }
- return res;
}
static void navi10_i2c_control_fini(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- int i;
-
- for (i = 0; i < MAX_SMU_I2C_BUSES; i++) {
- struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i];
- struct i2c_adapter *control = &smu_i2c->adapter;
- i2c_del_adapter(control);
- }
adev->pm.ras_eeprom_i2c_bus = NULL;
adev->pm.fru_eeprom_i2c_bus = NULL;
}
@@ -3183,7 +2924,8 @@ static ssize_t navi10_get_gpu_metrics(struct smu_context *smu,
{
struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v1_3 *gpu_metrics =
- (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table;
+ (struct gpu_metrics_v1_3 *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
SmuMetrics_t metrics;
int ret = 0;
@@ -3247,6 +2989,8 @@ static ssize_t navi10_get_gpu_metrics(struct smu_context *smu,
*table = (void *)gpu_metrics;
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
return sizeof(struct gpu_metrics_v1_3);
}
@@ -3255,7 +2999,8 @@ static ssize_t navi12_get_legacy_gpu_metrics(struct smu_context *smu,
{
struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v1_3 *gpu_metrics =
- (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table;
+ (struct gpu_metrics_v1_3 *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
SmuMetrics_NV12_legacy_t metrics;
int ret = 0;
@@ -3322,6 +3067,8 @@ static ssize_t navi12_get_legacy_gpu_metrics(struct smu_context *smu,
*table = (void *)gpu_metrics;
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
return sizeof(struct gpu_metrics_v1_3);
}
@@ -3330,7 +3077,8 @@ static ssize_t navi12_get_gpu_metrics(struct smu_context *smu,
{
struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v1_3 *gpu_metrics =
- (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table;
+ (struct gpu_metrics_v1_3 *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
SmuMetrics_NV12_t metrics;
int ret = 0;
@@ -3399,6 +3147,8 @@ static ssize_t navi12_get_gpu_metrics(struct smu_context *smu,
*table = (void *)gpu_metrics;
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
return sizeof(struct gpu_metrics_v1_3);
}
@@ -3526,13 +3276,12 @@ static int navi10_set_config_table(struct smu_context *smu,
}
static const struct pptable_funcs navi10_ppt_funcs = {
- .get_allowed_feature_mask = navi10_get_allowed_feature_mask,
+ .init_allowed_features = navi10_init_allowed_features,
.set_default_dpm_table = navi10_set_default_dpm_table,
.dpm_set_vcn_enable = navi10_dpm_set_vcn_enable,
.dpm_set_jpeg_enable = navi10_dpm_set_jpeg_enable,
.i2c_init = navi10_i2c_control_init,
.i2c_fini = navi10_i2c_control_fini,
- .print_clk_levels = navi10_print_clk_levels,
.emit_clk_levels = navi10_emit_clk_levels,
.force_clk_levels = navi10_force_clk_levels,
.populate_umd_state_clk = navi10_populate_umd_state_clk,
@@ -3563,14 +3312,12 @@ static const struct pptable_funcs navi10_ppt_funcs = {
.check_fw_status = smu_v11_0_check_fw_status,
.setup_pptable = navi10_setup_pptable,
.get_vbios_bootup_values = smu_v11_0_get_vbios_bootup_values,
- .check_fw_version = smu_v11_0_check_fw_version,
+ .check_fw_version = smu_cmn_check_fw_version,
.write_pptable = smu_cmn_write_pptable,
.set_driver_table_location = smu_v11_0_set_driver_table_location,
.set_tool_table_location = smu_v11_0_set_tool_table_location,
.notify_memory_pool_location = smu_v11_0_notify_memory_pool_location,
.system_features_control = smu_v11_0_system_features_control,
- .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
- .send_smc_msg = smu_cmn_send_smc_msg,
.init_display_count = smu_v11_0_init_display_count,
.set_allowed_mask = smu_v11_0_set_allowed_mask,
.get_enabled_mask = smu_cmn_get_enabled_mask,
@@ -3618,12 +3365,26 @@ static const struct pptable_funcs navi10_ppt_funcs = {
void navi10_set_ppt_funcs(struct smu_context *smu)
{
+ struct amdgpu_device *adev = smu->adev;
+
smu->ppt_funcs = &navi10_ppt_funcs;
- smu->message_map = navi10_message_map;
smu->clock_map = navi10_clk_map;
smu->feature_map = navi10_feature_mask_map;
smu->table_map = navi10_table_map;
smu->pwr_src_map = navi10_pwr_src_map;
smu->workload_map = navi10_workload_map;
- smu_v11_0_set_smu_mailbox_registers(smu);
+
+ switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
+ case IP_VERSION(11, 0, 0):
+ smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_NV10;
+ break;
+ case IP_VERSION(11, 0, 9):
+ smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_NV12;
+ break;
+ case IP_VERSION(11, 0, 5):
+ smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_NV14;
+ break;
+ }
+
+ smu_v11_0_init_msg_ctl(smu, navi10_message_map);
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
index 19a25fdc2f5b..f799e489b481 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
@@ -60,16 +60,18 @@
#undef pr_info
#undef pr_debug
-#define FEATURE_MASK(feature) (1ULL << feature)
-#define SMC_DPM_FEATURE ( \
- FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) | \
- FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_LINK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_FCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT))
+static const struct smu_feature_bits sienna_cichlid_dpm_features = {
+ .bits = {
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_PREFETCHER_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_LINK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_DCEFCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_MP0CLK_BIT)
+ }
+};
#define SMU_11_0_7_GFX_BUSY_THRESHOLD 15
@@ -276,85 +278,82 @@ static const uint8_t sienna_cichlid_throttler_map[] = {
};
static int
-sienna_cichlid_get_allowed_feature_mask(struct smu_context *smu,
- uint32_t *feature_mask, uint32_t num)
+sienna_cichlid_init_allowed_features(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- if (num > 2)
- return -EINVAL;
-
- memset(feature_mask, 0, sizeof(uint32_t) * num);
-
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT)
- | FEATURE_MASK(FEATURE_DPM_FCLK_BIT)
- | FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT)
- | FEATURE_MASK(FEATURE_DS_SOCCLK_BIT)
- | FEATURE_MASK(FEATURE_DS_DCEFCLK_BIT)
- | FEATURE_MASK(FEATURE_DS_FCLK_BIT)
- | FEATURE_MASK(FEATURE_DS_UCLK_BIT)
- | FEATURE_MASK(FEATURE_FW_DSTATE_BIT)
- | FEATURE_MASK(FEATURE_DF_CSTATE_BIT)
- | FEATURE_MASK(FEATURE_RSMU_SMN_CG_BIT)
- | FEATURE_MASK(FEATURE_GFX_SS_BIT)
- | FEATURE_MASK(FEATURE_VR0HOT_BIT)
- | FEATURE_MASK(FEATURE_PPT_BIT)
- | FEATURE_MASK(FEATURE_TDC_BIT)
- | FEATURE_MASK(FEATURE_BACO_BIT)
- | FEATURE_MASK(FEATURE_APCC_DFLL_BIT)
- | FEATURE_MASK(FEATURE_FW_CTF_BIT)
- | FEATURE_MASK(FEATURE_FAN_CONTROL_BIT)
- | FEATURE_MASK(FEATURE_THERMAL_BIT)
- | FEATURE_MASK(FEATURE_OUT_OF_BAND_MONITOR_BIT);
+ smu_feature_list_clear_all(smu, SMU_FEATURE_LIST_ALLOWED);
+
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_PREFETCHER_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_FCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_MP0CLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_SOCCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_DCEFCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_FCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_UCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_FW_DSTATE_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DF_CSTATE_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_RSMU_SMN_CG_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFX_SS_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_VR0HOT_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_PPT_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_TDC_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_BACO_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_APCC_DFLL_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_FW_CTF_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_FAN_CONTROL_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_THERMAL_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_OUT_OF_BAND_MONITOR_BIT);
if (adev->pm.pp_feature & PP_SCLK_DPM_MASK) {
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_GFX_GPO_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_GFXCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_GFX_GPO_BIT);
}
if ((adev->pm.pp_feature & PP_GFX_DCS_MASK) &&
(amdgpu_ip_version(adev, MP1_HWIP, 0) > IP_VERSION(11, 0, 7)) &&
!(adev->flags & AMD_IS_APU))
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_DCS_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFX_DCS_BIT);
- if (adev->pm.pp_feature & PP_MCLK_DPM_MASK)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_UCLK_BIT)
- | FEATURE_MASK(FEATURE_MEM_VDDCI_SCALING_BIT)
- | FEATURE_MASK(FEATURE_MEM_MVDD_SCALING_BIT);
+ if (adev->pm.pp_feature & PP_MCLK_DPM_MASK) {
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_UCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_MEM_VDDCI_SCALING_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_MEM_MVDD_SCALING_BIT);
+ }
if (adev->pm.pp_feature & PP_PCIE_DPM_MASK)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_LINK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_LINK_BIT);
if (adev->pm.pp_feature & PP_DCEFCLK_DPM_MASK)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_DCEFCLK_BIT);
if (adev->pm.pp_feature & PP_SOCCLK_DPM_MASK)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_SOCCLK_BIT);
if (adev->pm.pp_feature & PP_ULV_MASK)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_ULV_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFX_ULV_BIT);
if (adev->pm.pp_feature & PP_SCLK_DEEP_SLEEP_MASK)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_GFXCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_GFXCLK_BIT);
if (adev->pm.pp_feature & PP_GFXOFF_MASK)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFXOFF_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFXOFF_BIT);
if (smu->adev->pg_flags & AMD_PG_SUPPORT_ATHUB)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ATHUB_PG_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_ATHUB_PG_BIT);
if (smu->adev->pg_flags & AMD_PG_SUPPORT_MMHUB)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_MMHUB_PG_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_MMHUB_PG_BIT);
if (smu->adev->pg_flags & AMD_PG_SUPPORT_VCN ||
smu->adev->pg_flags & AMD_PG_SUPPORT_JPEG)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_MM_DPM_PG_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_MM_DPM_PG_BIT);
if (smu->dc_controlled_by_gpio)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ACDC_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_ACDC_BIT);
if (amdgpu_device_should_use_aspm(adev))
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_LCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_LCLK_BIT);
return 0;
}
@@ -533,6 +532,7 @@ static int sienna_cichlid_tables_init(struct smu_context *smu)
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_table *tables = smu_table->tables;
int table_size;
+ int ret;
table_size = get_table_size(smu);
SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, table_size,
@@ -555,17 +555,18 @@ static int sienna_cichlid_tables_init(struct smu_context *smu)
SMU_TABLE_INIT(tables, SMU_TABLE_DRIVER_SMU_CONFIG, sizeof(DriverSmuConfigExternal_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
- smu_table->metrics_table = kzalloc(sizeof(SmuMetricsExternal_t), GFP_KERNEL);
+ smu_table->metrics_table = kzalloc_obj(SmuMetricsExternal_t);
if (!smu_table->metrics_table)
goto err0_out;
smu_table->metrics_time = 0;
- smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_3);
- smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
- if (!smu_table->gpu_metrics_table)
+ ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS,
+ sizeof(struct gpu_metrics_v1_3),
+ SMU_GPU_METRICS_CACHE_INTERVAL);
+ if (ret)
goto err1_out;
- smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL);
+ smu_table->watermarks_table = kzalloc_obj(Watermarks_t);
if (!smu_table->watermarks_table)
goto err2_out;
@@ -585,7 +586,7 @@ err4_out:
err3_out:
kfree(smu_table->watermarks_table);
err2_out:
- kfree(smu_table->gpu_metrics_table);
+ smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS);
err1_out:
kfree(smu_table->metrics_table);
err0_out:
@@ -920,8 +921,7 @@ static int sienna_cichlid_allocate_dpm_context(struct smu_context *smu)
{
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
- smu_dpm->dpm_context = kzalloc(sizeof(struct smu_11_0_dpm_context),
- GFP_KERNEL);
+ smu_dpm->dpm_context = kzalloc_obj(struct smu_11_0_dpm_context);
if (!smu_dpm->dpm_context)
return -ENOMEM;
@@ -954,13 +954,15 @@ static int sienna_cichlid_init_smc_tables(struct smu_context *smu)
static int sienna_cichlid_set_default_dpm_table(struct smu_context *smu)
{
struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
- struct smu_11_0_dpm_table *dpm_table;
+ struct smu_dpm_table *dpm_table;
struct amdgpu_device *adev = smu->adev;
int i, ret = 0;
DpmDescriptor_t *table_member;
+ uint16_t *lclk_freq;
/* socclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.soc_table;
+ dpm_table->clk_type = SMU_SOCCLK;
GET_PPTABLE_MEMBER(DpmDescriptor, &table_member);
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
@@ -968,68 +970,63 @@ static int sienna_cichlid_set_default_dpm_table(struct smu_context *smu)
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !table_member[PPCLK_SOCCLK].SnapToDiscrete;
+ if (!table_member[PPCLK_SOCCLK].SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.socclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* gfxclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.gfx_table;
+ dpm_table->clk_type = SMU_GFXCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
SMU_GFXCLK,
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !table_member[PPCLK_GFXCLK].SnapToDiscrete;
+ if (!table_member[PPCLK_GFXCLK].SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* uclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.uclk_table;
+ dpm_table->clk_type = SMU_UCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
SMU_UCLK,
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !table_member[PPCLK_UCLK].SnapToDiscrete;
+ if (!table_member[PPCLK_UCLK].SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.uclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* fclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.fclk_table;
+ dpm_table->clk_type = SMU_FCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
SMU_FCLK,
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !table_member[PPCLK_FCLK].SnapToDiscrete;
+ if (!table_member[PPCLK_FCLK].SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.fclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* vclk0/1 dpm table setup */
@@ -1038,20 +1035,20 @@ static int sienna_cichlid_set_default_dpm_table(struct smu_context *smu)
continue;
dpm_table = &dpm_context->dpm_tables.vclk_table;
+ dpm_table->clk_type = i ? SMU_VCLK1 : SMU_VCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_MM_DPM_PG_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
i ? SMU_VCLK1 : SMU_VCLK,
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !table_member[i ? PPCLK_VCLK_1 : PPCLK_VCLK_0].SnapToDiscrete;
+ if (!table_member[i ? PPCLK_VCLK_1 : PPCLK_VCLK_0]
+ .SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.vclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
}
@@ -1060,95 +1057,96 @@ static int sienna_cichlid_set_default_dpm_table(struct smu_context *smu)
if (adev->vcn.harvest_config & (1 << i))
continue;
dpm_table = &dpm_context->dpm_tables.dclk_table;
+ dpm_table->clk_type = i ? SMU_DCLK1 : SMU_DCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_MM_DPM_PG_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
i ? SMU_DCLK1 : SMU_DCLK,
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !table_member[i ? PPCLK_DCLK_1 : PPCLK_DCLK_0].SnapToDiscrete;
+ if (!table_member[i ? PPCLK_DCLK_1 : PPCLK_DCLK_0]
+ .SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
}
/* dcefclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.dcef_table;
+ dpm_table->clk_type = SMU_DCEFCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
SMU_DCEFCLK,
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !table_member[PPCLK_DCEFCLK].SnapToDiscrete;
+ if (!table_member[PPCLK_DCEFCLK].SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* pixelclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.pixel_table;
+ dpm_table->clk_type = SMU_PIXCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
SMU_PIXCLK,
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !table_member[PPCLK_PIXCLK].SnapToDiscrete;
+ if (!table_member[PPCLK_PIXCLK].SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* displayclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.display_table;
+ dpm_table->clk_type = SMU_DISPCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
SMU_DISPCLK,
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !table_member[PPCLK_DISPCLK].SnapToDiscrete;
+ if (!table_member[PPCLK_DISPCLK].SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* phyclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.phy_table;
+ dpm_table->clk_type = SMU_PHYCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
ret = smu_v11_0_set_single_dpm_table(smu,
SMU_PHYCLK,
dpm_table);
if (ret)
return ret;
- dpm_table->is_fine_grained =
- !table_member[PPCLK_PHYCLK].SnapToDiscrete;
+ if (!table_member[PPCLK_PHYCLK].SnapToDiscrete)
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
+ GET_PPTABLE_MEMBER(LclkFreq, &lclk_freq);
+ for (i = 0; i < NUM_LINK_LEVELS; i++)
+ dpm_context->dpm_tables.pcie_table.lclk_freq[i] = lclk_freq[i];
+ dpm_context->dpm_tables.pcie_table.lclk_levels = NUM_LINK_LEVELS;
+
return 0;
}
@@ -1269,102 +1267,56 @@ static void sienna_cichlid_get_od_setting_range(struct smu_11_0_7_overdrive_tabl
*max = od_table->max[setting];
}
-static int sienna_cichlid_print_clk_levels(struct smu_context *smu,
- enum smu_clk_type clk_type, char *buf)
+static int sienna_cichlid_emit_clk_levels(struct smu_context *smu,
+ enum smu_clk_type clk_type, char *buf,
+ int *offset)
{
struct amdgpu_device *adev = smu->adev;
struct smu_table_context *table_context = &smu->smu_table;
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context;
- uint16_t *table_member;
-
struct smu_11_0_7_overdrive_table *od_settings = smu->od_settings;
OverDriveTable_t *od_table =
(OverDriveTable_t *)table_context->overdrive_table;
- 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;
+ int size = *offset, ret = 0, start_offset = *offset;
+ uint32_t cur_value = 0;
+ struct smu_dpm_table *single_dpm_table = NULL;
+ struct smu_pcie_table *pcie_table;
uint32_t gen_speed, lane_width;
uint32_t min_value, max_value;
- smu_cmn_get_sysfs_buf(&buf, &size);
-
switch (clk_type) {
case SMU_GFXCLK:
case SMU_SCLK:
+ single_dpm_table = &(dpm_context->dpm_tables.gfx_table);
+ break;
case SMU_SOCCLK:
+ single_dpm_table = &(dpm_context->dpm_tables.soc_table);
+ break;
case SMU_MCLK:
case SMU_UCLK:
+ single_dpm_table = &(dpm_context->dpm_tables.uclk_table);
+ break;
case SMU_FCLK:
+ single_dpm_table = &(dpm_context->dpm_tables.fclk_table);
+ break;
case SMU_VCLK:
case SMU_VCLK1:
+ single_dpm_table = &(dpm_context->dpm_tables.vclk_table);
+ break;
case SMU_DCLK:
case SMU_DCLK1:
+ single_dpm_table = &(dpm_context->dpm_tables.dclk_table);
+ break;
case SMU_DCEFCLK:
- ret = sienna_cichlid_get_current_clk_freq_by_table(smu, clk_type, &cur_value);
- if (ret)
- goto print_clk_out;
-
- ret = smu_v11_0_get_dpm_level_count(smu, clk_type, &count);
- if (ret)
- goto print_clk_out;
-
- if (!sienna_cichlid_is_support_fine_grained_dpm(smu, clk_type)) {
- for (i = 0; i < count; i++) {
- ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, i, &value);
- if (ret)
- goto print_clk_out;
-
- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value,
- cur_value == value ? "*" : "");
- }
- } else {
- ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, 0, &freq_values[0]);
- if (ret)
- goto print_clk_out;
- ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, count - 1, &freq_values[2]);
- if (ret)
- goto print_clk_out;
-
- freq_values[1] = cur_value;
- mark_index = cur_value == freq_values[0] ? 0 :
- cur_value == freq_values[2] ? 2 : 1;
-
- count = 3;
- if (mark_index != 1) {
- count = 2;
- freq_values[1] = freq_values[2];
- }
-
- for (i = 0; i < count; i++) {
- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, freq_values[i],
- cur_value == freq_values[i] ? "*" : "");
- }
-
- }
+ single_dpm_table = &(dpm_context->dpm_tables.dcef_table);
break;
case SMU_PCIE:
gen_speed = smu_v11_0_get_current_pcie_link_speed_level(smu);
lane_width = smu_v11_0_get_current_pcie_link_width_level(smu);
- GET_PPTABLE_MEMBER(LclkFreq, &table_member);
- for (i = 0; i < NUM_LINK_LEVELS; i++)
- size += sysfs_emit_at(buf, size, "%d: %s %s %dMhz %s\n", i,
- (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 0) ? "2.5GT/s," :
- (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 1) ? "5.0GT/s," :
- (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 2) ? "8.0GT/s," :
- (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 3) ? "16.0GT/s," : "",
- (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 1) ? "x1" :
- (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 2) ? "x2" :
- (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 3) ? "x4" :
- (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 4) ? "x8" :
- (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 5) ? "x12" :
- (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 6) ? "x16" : "",
- table_member[i],
- (gen_speed == dpm_context->dpm_tables.pcie_table.pcie_gen[i]) &&
- (lane_width == dpm_context->dpm_tables.pcie_table.pcie_lane[i]) ?
- "*" : "");
- break;
+ pcie_table = &dpm_context->dpm_tables.pcie_table;
+ return smu_cmn_print_pcie_levels(smu, pcie_table, gen_speed,
+ lane_width, buf, offset);
case SMU_OD_SCLK:
if (!smu->od_enabled || !od_table || !od_settings)
break;
@@ -1433,8 +1385,18 @@ static int sienna_cichlid_print_clk_levels(struct smu_context *smu,
break;
}
-print_clk_out:
- return size;
+ if (single_dpm_table) {
+ ret = sienna_cichlid_get_current_clk_freq_by_table(
+ smu, clk_type, &cur_value);
+ if (ret)
+ return ret;
+ return smu_cmn_print_dpm_clk_levels(smu, single_dpm_table,
+ cur_value, buf, offset);
+ }
+
+ *offset += size - start_offset;
+
+ return 0;
}
static int sienna_cichlid_force_clk_levels(struct smu_context *smu,
@@ -1486,24 +1448,21 @@ static int sienna_cichlid_populate_umd_state_clk(struct smu_context *smu)
{
struct smu_11_0_dpm_context *dpm_context =
smu->smu_dpm.dpm_context;
- struct smu_11_0_dpm_table *gfx_table =
- &dpm_context->dpm_tables.gfx_table;
- struct smu_11_0_dpm_table *mem_table =
- &dpm_context->dpm_tables.uclk_table;
- struct smu_11_0_dpm_table *soc_table =
- &dpm_context->dpm_tables.soc_table;
+ struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table;
+ struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table;
+ struct smu_dpm_table *soc_table = &dpm_context->dpm_tables.soc_table;
struct smu_umd_pstate_table *pstate_table =
&smu->pstate_table;
struct amdgpu_device *adev = smu->adev;
- pstate_table->gfxclk_pstate.min = gfx_table->min;
- pstate_table->gfxclk_pstate.peak = gfx_table->max;
+ pstate_table->gfxclk_pstate.min = SMU_DPM_TABLE_MIN(gfx_table);
+ pstate_table->gfxclk_pstate.peak = SMU_DPM_TABLE_MAX(gfx_table);
- pstate_table->uclk_pstate.min = mem_table->min;
- pstate_table->uclk_pstate.peak = mem_table->max;
+ pstate_table->uclk_pstate.min = SMU_DPM_TABLE_MIN(mem_table);
+ pstate_table->uclk_pstate.peak = SMU_DPM_TABLE_MAX(mem_table);
- pstate_table->socclk_pstate.min = soc_table->min;
- pstate_table->socclk_pstate.peak = soc_table->max;
+ pstate_table->socclk_pstate.min = SMU_DPM_TABLE_MIN(soc_table);
+ pstate_table->socclk_pstate.peak = SMU_DPM_TABLE_MAX(soc_table);
switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
case IP_VERSION(11, 0, 7):
@@ -1576,13 +1535,14 @@ static int sienna_cichlid_display_config_changed(struct smu_context *smu)
static bool sienna_cichlid_is_dpm_running(struct smu_context *smu)
{
int ret = 0;
- uint64_t feature_enabled;
+ struct smu_feature_bits feature_enabled;
ret = smu_cmn_get_enabled_mask(smu, &feature_enabled);
if (ret)
return false;
- return !!(feature_enabled & SMC_DPM_FEATURE);
+ return smu_feature_bits_test_mask(&feature_enabled,
+ sienna_cichlid_dpm_features.bits);
}
static int sienna_cichlid_get_fan_speed_rpm(struct smu_context *smu,
@@ -2140,12 +2100,13 @@ static int sienna_cichlid_update_pcie_parameters(struct smu_context *smu,
uint8_t pcie_width_cap)
{
struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
- struct smu_11_0_pcie_table *pcie_table = &dpm_context->dpm_tables.pcie_table;
+ struct smu_pcie_table *pcie_table = &dpm_context->dpm_tables.pcie_table;
uint8_t *table_member1, *table_member2;
uint8_t min_gen_speed, max_gen_speed;
uint8_t min_lane_width, max_lane_width;
uint32_t smu_pcie_arg;
- int ret, i;
+ int ret = 0;
+ int i;
GET_PPTABLE_MEMBER(PcieGenSpeed, &table_member1);
GET_PPTABLE_MEMBER(PcieLaneCount, &table_member2);
@@ -2170,19 +2131,22 @@ static int sienna_cichlid_update_pcie_parameters(struct smu_context *smu,
pcie_table->pcie_lane[1] = max_lane_width;
for (i = 0; i < NUM_LINK_LEVELS; i++) {
- smu_pcie_arg = (i << 16 |
+ if (!(smu->adev->pm.pp_feature & PP_PCIE_DPM_MASK) ||
+ table_member1[i] > pcie_gen_cap || table_member2[i] > pcie_width_cap) {
+ smu_pcie_arg = (i << 16 |
pcie_table->pcie_gen[i] << 8 |
pcie_table->pcie_lane[i]);
- ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_OverridePcieParameters,
- smu_pcie_arg,
- NULL);
- if (ret)
- return ret;
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_OverridePcieParameters,
+ smu_pcie_arg,
+ NULL);
+ if (ret)
+ break;
+ }
}
- return 0;
+ return ret;
}
static int sienna_cichlid_get_dpm_ultimate_freq(struct smu_context *smu,
@@ -2542,7 +2506,7 @@ static int sienna_cichlid_i2c_xfer(struct i2c_adapter *i2c_adap,
if (!adev->pm.dpm_enabled)
return -EBUSY;
- req = kzalloc(sizeof(*req), GFP_KERNEL);
+ req = kzalloc_obj(*req);
if (!req)
return -ENOMEM;
@@ -2644,10 +2608,10 @@ static int sienna_cichlid_i2c_control_init(struct smu_context *smu)
control->quirks = &sienna_cichlid_i2c_control_quirks;
i2c_set_adapdata(control, smu_i2c);
- res = i2c_add_adapter(control);
+ res = devm_i2c_add_adapter(adev->dev, control);
if (res) {
DRM_ERROR("Failed to register hw i2c, err: %d\n", res);
- goto Out_err;
+ return res;
}
}
/* assign the buses used for the FRU EEPROM and RAS EEPROM */
@@ -2656,27 +2620,12 @@ static int sienna_cichlid_i2c_control_init(struct smu_context *smu)
adev->pm.fru_eeprom_i2c_bus = &adev->pm.smu_i2c[0].adapter;
return 0;
-Out_err:
- for ( ; i >= 0; i--) {
- struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i];
- struct i2c_adapter *control = &smu_i2c->adapter;
-
- i2c_del_adapter(control);
- }
- return res;
}
static void sienna_cichlid_i2c_control_fini(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- int i;
-
- for (i = 0; i < MAX_SMU_I2C_BUSES; i++) {
- struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i];
- struct i2c_adapter *control = &smu_i2c->adapter;
- i2c_del_adapter(control);
- }
adev->pm.ras_eeprom_i2c_bus = NULL;
adev->pm.fru_eeprom_i2c_bus = NULL;
}
@@ -2684,9 +2633,9 @@ static void sienna_cichlid_i2c_control_fini(struct smu_context *smu)
static ssize_t sienna_cichlid_get_gpu_metrics(struct smu_context *smu,
void **table)
{
- struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v1_3 *gpu_metrics =
- (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table;
+ (struct gpu_metrics_v1_3 *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
SmuMetricsExternal_t metrics_external;
SmuMetrics_t *metrics =
&(metrics_external.SmuMetrics);
@@ -2835,6 +2784,8 @@ static ssize_t sienna_cichlid_get_gpu_metrics(struct smu_context *smu,
*table = (void *)gpu_metrics;
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
return sizeof(struct gpu_metrics_v1_3);
}
@@ -3089,28 +3040,23 @@ static int sienna_cichlid_stb_get_data_direct(struct smu_context *smu,
return 0;
}
-static bool sienna_cichlid_is_mode2_reset_supported(struct smu_context *smu)
-{
- return true;
-}
-
static int sienna_cichlid_mode2_reset(struct smu_context *smu)
{
- int ret = 0, index;
+ struct smu_msg_ctl *ctl = &smu->msg_ctl;
struct amdgpu_device *adev = smu->adev;
+ int ret = 0;
int timeout = 100;
- index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG,
- SMU_MSG_DriverMode2Reset);
+ mutex_lock(&ctl->lock);
- mutex_lock(&smu->message_lock);
-
- ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index,
- SMU_RESET_MODE_2);
+ ret = smu_msg_send_async_locked(ctl, SMU_MSG_DriverMode2Reset,
+ SMU_RESET_MODE_2);
+ if (ret)
+ goto out;
- ret = smu_cmn_wait_for_response(smu);
+ ret = smu_msg_wait_response(ctl, 0);
while (ret != 0 && timeout) {
- ret = smu_cmn_wait_for_response(smu);
+ ret = smu_msg_wait_response(ctl, 0);
/* Wait a bit more time for getting ACK */
if (ret != 0) {
--timeout;
@@ -3128,23 +3074,23 @@ static int sienna_cichlid_mode2_reset(struct smu_context *smu)
goto out;
}
- dev_info(smu->adev->dev, "restore config space...\n");
+ dev_info(adev->dev, "restore config space...\n");
/* Restore the config space saved during init */
amdgpu_device_load_pci_state(adev->pdev);
out:
- mutex_unlock(&smu->message_lock);
+ mutex_unlock(&ctl->lock);
return ret;
}
static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
- .get_allowed_feature_mask = sienna_cichlid_get_allowed_feature_mask,
+ .init_allowed_features = sienna_cichlid_init_allowed_features,
.set_default_dpm_table = sienna_cichlid_set_default_dpm_table,
.dpm_set_vcn_enable = sienna_cichlid_dpm_set_vcn_enable,
.dpm_set_jpeg_enable = sienna_cichlid_dpm_set_jpeg_enable,
.i2c_init = sienna_cichlid_i2c_control_init,
.i2c_fini = sienna_cichlid_i2c_control_fini,
- .print_clk_levels = sienna_cichlid_print_clk_levels,
+ .emit_clk_levels = sienna_cichlid_emit_clk_levels,
.force_clk_levels = sienna_cichlid_force_clk_levels,
.populate_umd_state_clk = sienna_cichlid_populate_umd_state_clk,
.pre_display_config_changed = sienna_cichlid_pre_display_config_changed,
@@ -3173,14 +3119,12 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
.check_fw_status = smu_v11_0_check_fw_status,
.setup_pptable = sienna_cichlid_setup_pptable,
.get_vbios_bootup_values = smu_v11_0_get_vbios_bootup_values,
- .check_fw_version = smu_v11_0_check_fw_version,
+ .check_fw_version = smu_cmn_check_fw_version,
.write_pptable = smu_cmn_write_pptable,
.set_driver_table_location = smu_v11_0_set_driver_table_location,
.set_tool_table_location = smu_v11_0_set_tool_table_location,
.notify_memory_pool_location = smu_v11_0_notify_memory_pool_location,
.system_features_control = sienna_cichlid_system_features_control,
- .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
- .send_smc_msg = smu_cmn_send_smc_msg,
.init_display_count = NULL,
.set_allowed_mask = smu_v11_0_set_allowed_mask,
.get_enabled_mask = smu_cmn_get_enabled_mask,
@@ -3229,18 +3173,39 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
.get_default_config_table_settings = sienna_cichlid_get_default_config_table_settings,
.set_config_table = sienna_cichlid_set_config_table,
.get_unique_id = sienna_cichlid_get_unique_id,
- .mode2_reset_is_support = sienna_cichlid_is_mode2_reset_supported,
.mode2_reset = sienna_cichlid_mode2_reset,
};
+#define SMU11_DRIVER_IF_VERSION_Sienna_Cichlid 0x40
+#define SMU11_DRIVER_IF_VERSION_Navy_Flounder 0xE
+#define SMU11_DRIVER_IF_VERSION_Dimgrey_Cavefish 0xF
+#define SMU11_DRIVER_IF_VERSION_Beige_Goby 0xD
+
void sienna_cichlid_set_ppt_funcs(struct smu_context *smu)
{
+ struct amdgpu_device *adev = smu->adev;
+
smu->ppt_funcs = &sienna_cichlid_ppt_funcs;
- smu->message_map = sienna_cichlid_message_map;
smu->clock_map = sienna_cichlid_clk_map;
smu->feature_map = sienna_cichlid_feature_mask_map;
smu->table_map = sienna_cichlid_table_map;
smu->pwr_src_map = sienna_cichlid_pwr_src_map;
smu->workload_map = sienna_cichlid_workload_map;
- smu_v11_0_set_smu_mailbox_registers(smu);
+
+ switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
+ case IP_VERSION(11, 0, 7):
+ smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Sienna_Cichlid;
+ break;
+ case IP_VERSION(11, 0, 11):
+ smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Navy_Flounder;
+ break;
+ case IP_VERSION(11, 0, 12):
+ smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Dimgrey_Cavefish;
+ break;
+ case IP_VERSION(11, 0, 13):
+ smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Beige_Goby;
+ break;
+ }
+
+ smu_v11_0_init_msg_ctl(smu, sienna_cichlid_message_map);
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
index 189c6a32b6bd..d68ceee16d8f 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
@@ -192,81 +192,6 @@ int smu_v11_0_check_fw_status(struct smu_context *smu)
return -EIO;
}
-int smu_v11_0_check_fw_version(struct smu_context *smu)
-{
- struct amdgpu_device *adev = smu->adev;
- uint32_t if_version = 0xff, smu_version = 0xff;
- uint8_t smu_program, smu_major, smu_minor, smu_debug;
- int ret = 0;
-
- ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version);
- if (ret)
- return ret;
-
- smu_program = (smu_version >> 24) & 0xff;
- smu_major = (smu_version >> 16) & 0xff;
- smu_minor = (smu_version >> 8) & 0xff;
- smu_debug = (smu_version >> 0) & 0xff;
- if (smu->is_apu)
- adev->pm.fw_version = smu_version;
-
- switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
- case IP_VERSION(11, 0, 0):
- smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_NV10;
- break;
- case IP_VERSION(11, 0, 9):
- smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_NV12;
- break;
- case IP_VERSION(11, 0, 5):
- smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_NV14;
- break;
- case IP_VERSION(11, 0, 7):
- smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Sienna_Cichlid;
- break;
- case IP_VERSION(11, 0, 11):
- smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Navy_Flounder;
- break;
- case IP_VERSION(11, 5, 0):
- smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_VANGOGH;
- break;
- case IP_VERSION(11, 0, 12):
- smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Dimgrey_Cavefish;
- break;
- case IP_VERSION(11, 0, 13):
- smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Beige_Goby;
- break;
- case IP_VERSION(11, 0, 8):
- smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Cyan_Skillfish;
- break;
- case IP_VERSION(11, 0, 2):
- smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_ARCT;
- break;
- default:
- dev_err(smu->adev->dev, "smu unsupported IP version: 0x%x.\n",
- amdgpu_ip_version(adev, MP1_HWIP, 0));
- smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_INV;
- break;
- }
-
- /*
- * 1. if_version mismatch is not critical as our fw is designed
- * to be backward compatible.
- * 2. New fw usually brings some optimizations. But that's visible
- * only on the paired driver.
- * Considering above, we just leave user a verbal message instead
- * of halt driver loading.
- */
- if (if_version != smu->smc_driver_if_version) {
- dev_info(smu->adev->dev, "smu driver if version = 0x%08x, smu fw if version = 0x%08x, "
- "smu fw program = %d, version = 0x%08x (%d.%d.%d)\n",
- smu->smc_driver_if_version, if_version,
- smu_program, smu_version, smu_major, smu_minor, smu_debug);
- dev_info(smu->adev->dev, "SMU driver if version not matched\n");
- }
-
- return ret;
-}
-
static int smu_v11_0_set_pptable_v2_0(struct smu_context *smu, void **table, uint32_t *size)
{
struct amdgpu_device *adev = smu->adev;
@@ -377,7 +302,7 @@ int smu_v11_0_init_smc_tables(struct smu_context *smu)
}
smu_table->max_sustainable_clocks =
- kzalloc(sizeof(struct smu_11_0_max_sustainable_clocks), GFP_KERNEL);
+ kzalloc_obj(struct smu_11_0_max_sustainable_clocks);
if (!smu_table->max_sustainable_clocks) {
ret = -ENOMEM;
goto err1_out;
@@ -427,14 +352,13 @@ int smu_v11_0_fini_smc_tables(struct smu_context *smu)
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
- kfree(smu_table->gpu_metrics_table);
+ smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS);
kfree(smu_table->user_overdrive_table);
kfree(smu_table->boot_overdrive_table);
kfree(smu_table->overdrive_table);
kfree(smu_table->max_sustainable_clocks);
kfree(smu_table->driver_pptable);
kfree(smu_table->clocks_table);
- smu_table->gpu_metrics_table = NULL;
smu_table->user_overdrive_table = NULL;
smu_table->boot_overdrive_table = NULL;
smu_table->overdrive_table = NULL;
@@ -471,10 +395,11 @@ int smu_v11_0_init_power(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
struct smu_power_context *smu_power = &smu->smu_power;
- size_t size = amdgpu_ip_version(adev, MP1_HWIP, 0) ==
- IP_VERSION(11, 5, 0) ?
- sizeof(struct smu_11_5_power_context) :
- sizeof(struct smu_11_0_power_context);
+ u32 ip_version = amdgpu_ip_version(adev, MP1_HWIP, 0);
+ size_t size = ((ip_version == IP_VERSION(11, 5, 0)) ||
+ (ip_version == IP_VERSION(11, 5, 2))) ?
+ sizeof(struct smu_11_5_power_context) :
+ sizeof(struct smu_11_0_power_context);
smu_power->power_context = kzalloc(size, GFP_KERNEL);
if (!smu_power->power_context)
@@ -731,6 +656,7 @@ int smu_v11_0_init_display_count(struct smu_context *smu, uint32_t count)
*/
if (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 11) ||
amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 5, 0) ||
+ amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 5, 2) ||
amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 12) ||
amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 13))
return 0;
@@ -748,12 +674,13 @@ int smu_v11_0_set_allowed_mask(struct smu_context *smu)
int ret = 0;
uint32_t feature_mask[2];
- if (bitmap_empty(feature->allowed, SMU_FEATURE_MAX) || feature->feature_num < 64) {
+ if (smu_feature_list_is_empty(smu, SMU_FEATURE_LIST_ALLOWED) ||
+ feature->feature_num < SMU_FEATURE_NUM_DEFAULT) {
ret = -EINVAL;
goto failed;
}
- bitmap_to_arr32(feature_mask, feature->allowed, 64);
+ smu_feature_list_to_arr32(smu, SMU_FEATURE_LIST_ALLOWED, feature_mask);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetAllowedFeaturesMaskHigh,
feature_mask[1], NULL);
@@ -1019,7 +946,12 @@ int smu_v11_0_enable_thermal_alert(struct smu_context *smu)
int smu_v11_0_disable_thermal_alert(struct smu_context *smu)
{
- return amdgpu_irq_put(smu->adev, &smu->irq_source, 0);
+ int ret = 0;
+
+ if (smu->smu_table.thermal_controller_type)
+ ret = amdgpu_irq_put(smu->adev, &smu->irq_source, 0);
+
+ return ret;
}
static uint16_t convert_to_vddc(uint8_t vid)
@@ -1110,6 +1042,7 @@ int smu_v11_0_gfx_off_control(struct smu_context *smu, bool enable)
case IP_VERSION(11, 0, 12):
case IP_VERSION(11, 0, 13):
case IP_VERSION(11, 5, 0):
+ case IP_VERSION(11, 5, 2):
if (!(adev->pm.pp_feature & PP_GFXOFF_MASK))
return 0;
if (enable)
@@ -1200,7 +1133,7 @@ int smu_v11_0_set_fan_speed_rpm(struct smu_context *smu,
uint32_t crystal_clock_freq = 2500;
uint32_t tach_period;
- if (speed == 0)
+ if (!speed || speed > UINT_MAX/8)
return -EINVAL;
/*
* To prevent from possible overheat, some ASICs may have requirement
@@ -1850,12 +1783,9 @@ int smu_v11_0_set_performance_level(struct smu_context *smu,
{
struct smu_11_0_dpm_context *dpm_context =
smu->smu_dpm.dpm_context;
- struct smu_11_0_dpm_table *gfx_table =
- &dpm_context->dpm_tables.gfx_table;
- struct smu_11_0_dpm_table *mem_table =
- &dpm_context->dpm_tables.uclk_table;
- struct smu_11_0_dpm_table *soc_table =
- &dpm_context->dpm_tables.soc_table;
+ struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table;
+ struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table;
+ struct smu_dpm_table *soc_table = &dpm_context->dpm_tables.soc_table;
struct smu_umd_pstate_table *pstate_table =
&smu->pstate_table;
struct amdgpu_device *adev = smu->adev;
@@ -1867,22 +1797,22 @@ int smu_v11_0_set_performance_level(struct smu_context *smu,
switch (level) {
case AMD_DPM_FORCED_LEVEL_HIGH:
- sclk_min = sclk_max = gfx_table->max;
- mclk_min = mclk_max = mem_table->max;
- socclk_min = socclk_max = soc_table->max;
+ sclk_min = sclk_max = SMU_DPM_TABLE_MAX(gfx_table);
+ mclk_min = mclk_max = SMU_DPM_TABLE_MAX(mem_table);
+ socclk_min = socclk_max = SMU_DPM_TABLE_MAX(soc_table);
break;
case AMD_DPM_FORCED_LEVEL_LOW:
- sclk_min = sclk_max = gfx_table->min;
- mclk_min = mclk_max = mem_table->min;
- socclk_min = socclk_max = soc_table->min;
+ sclk_min = sclk_max = SMU_DPM_TABLE_MIN(gfx_table);
+ mclk_min = mclk_max = SMU_DPM_TABLE_MIN(mem_table);
+ socclk_min = socclk_max = SMU_DPM_TABLE_MIN(soc_table);
break;
case AMD_DPM_FORCED_LEVEL_AUTO:
- sclk_min = gfx_table->min;
- sclk_max = gfx_table->max;
- mclk_min = mem_table->min;
- mclk_max = mem_table->max;
- socclk_min = soc_table->min;
- socclk_max = soc_table->max;
+ sclk_min = SMU_DPM_TABLE_MIN(gfx_table);
+ sclk_max = SMU_DPM_TABLE_MAX(gfx_table);
+ mclk_min = SMU_DPM_TABLE_MIN(mem_table);
+ mclk_max = SMU_DPM_TABLE_MAX(mem_table);
+ socclk_min = SMU_DPM_TABLE_MIN(soc_table);
+ socclk_max = SMU_DPM_TABLE_MAX(soc_table);
auto_level = true;
break;
case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
@@ -2019,7 +1949,7 @@ int smu_v11_0_get_dpm_level_count(struct smu_context *smu,
int smu_v11_0_set_single_dpm_table(struct smu_context *smu,
enum smu_clk_type clk_type,
- struct smu_11_0_dpm_table *single_dpm_table)
+ struct smu_dpm_table *single_dpm_table)
{
int ret = 0;
uint32_t clk;
@@ -2045,55 +1975,11 @@ int smu_v11_0_set_single_dpm_table(struct smu_context *smu,
single_dpm_table->dpm_levels[i].value = clk;
single_dpm_table->dpm_levels[i].enabled = true;
-
- if (i == 0)
- single_dpm_table->min = clk;
- else if (i == single_dpm_table->count - 1)
- single_dpm_table->max = clk;
}
return 0;
}
-int smu_v11_0_get_dpm_level_range(struct smu_context *smu,
- enum smu_clk_type clk_type,
- uint32_t *min_value,
- uint32_t *max_value)
-{
- uint32_t level_count = 0;
- int ret = 0;
-
- if (!min_value && !max_value)
- return -EINVAL;
-
- if (min_value) {
- /* by default, level 0 clock value as min value */
- ret = smu_v11_0_get_dpm_freq_by_index(smu,
- clk_type,
- 0,
- min_value);
- if (ret)
- return ret;
- }
-
- if (max_value) {
- ret = smu_v11_0_get_dpm_level_count(smu,
- clk_type,
- &level_count);
- if (ret)
- return ret;
-
- ret = smu_v11_0_get_dpm_freq_by_index(smu,
- clk_type,
- level_count - 1,
- max_value);
- if (ret)
- return ret;
- }
-
- return ret;
-}
-
int smu_v11_0_get_current_pcie_link_width_level(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
@@ -2207,11 +2093,19 @@ int smu_v11_0_restore_user_od_settings(struct smu_context *smu)
return ret;
}
-void smu_v11_0_set_smu_mailbox_registers(struct smu_context *smu)
+void smu_v11_0_init_msg_ctl(struct smu_context *smu,
+ const struct cmn2asic_msg_mapping *message_map)
{
struct amdgpu_device *adev = smu->adev;
-
- smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82);
- smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66);
- smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90);
+ struct smu_msg_ctl *ctl = &smu->msg_ctl;
+
+ ctl->smu = smu;
+ mutex_init(&ctl->lock);
+ ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66);
+ ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90);
+ ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82);
+ ctl->config.num_arg_regs = 1;
+ ctl->ops = &smu_msg_v1_ops;
+ ctl->default_timeout = adev->usec_timeout * 20;
+ ctl->message_map = message_map;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
index a55ea76d7399..016a5c893fee 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
@@ -58,17 +58,19 @@
#define SMUIO_GFX_MISC_CNTL__SMU_GFX_cold_vs_gfxoff_MASK 0x00000001L
#define SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS_MASK 0x00000006L
-#define FEATURE_MASK(feature) (1ULL << feature)
-#define SMC_DPM_FEATURE ( \
- FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_VCN_DPM_BIT) | \
- FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_LCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT)| \
- FEATURE_MASK(FEATURE_GFX_DPM_BIT))
+static const struct smu_feature_bits vangogh_dpm_features = {
+ .bits = {
+ SMU_FEATURE_BIT_INIT(FEATURE_CCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_VCN_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_FCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_SOCCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_MP0CLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_LCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_SHUBCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DCFCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_GFX_DPM_BIT)
+ }
+};
static struct cmn2asic_msg_mapping vangogh_message_map[SMU_MSG_MAX_COUNT] = {
MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 0),
@@ -225,6 +227,7 @@ static int vangogh_tables_init(struct smu_context *smu)
{
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_table *tables = smu_table->tables;
+ int ret;
SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
@@ -242,18 +245,19 @@ static int vangogh_tables_init(struct smu_context *smu)
goto err0_out;
smu_table->metrics_time = 0;
- smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_2);
- smu_table->gpu_metrics_table_size = max(smu_table->gpu_metrics_table_size, sizeof(struct gpu_metrics_v2_3));
- smu_table->gpu_metrics_table_size = max(smu_table->gpu_metrics_table_size, sizeof(struct gpu_metrics_v2_4));
- smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
- if (!smu_table->gpu_metrics_table)
+ ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS,
+ max3(sizeof(struct gpu_metrics_v2_2),
+ sizeof(struct gpu_metrics_v2_3),
+ sizeof(struct gpu_metrics_v2_4)),
+ SMU_GPU_METRICS_CACHE_INTERVAL);
+ if (ret)
goto err1_out;
- smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL);
+ smu_table->watermarks_table = kzalloc_obj(Watermarks_t);
if (!smu_table->watermarks_table)
goto err2_out;
- smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL);
+ smu_table->clocks_table = kzalloc_obj(DpmClocks_t);
if (!smu_table->clocks_table)
goto err3_out;
@@ -262,7 +266,7 @@ static int vangogh_tables_init(struct smu_context *smu)
err3_out:
kfree(smu_table->watermarks_table);
err2_out:
- kfree(smu_table->gpu_metrics_table);
+ smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS);
err1_out:
kfree(smu_table->metrics_table);
err0_out:
@@ -429,8 +433,7 @@ static int vangogh_allocate_dpm_context(struct smu_context *smu)
{
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
- smu_dpm->dpm_context = kzalloc(sizeof(struct smu_11_0_dpm_context),
- GFP_KERNEL);
+ smu_dpm->dpm_context = kzalloc_obj(struct smu_11_0_dpm_context);
if (!smu_dpm->dpm_context)
return -ENOMEM;
@@ -502,7 +505,7 @@ static bool vangogh_is_dpm_running(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
int ret = 0;
- uint64_t feature_enabled;
+ struct smu_feature_bits feature_enabled;
/* we need to re-init after suspend so return false */
if (adev->in_suspend)
@@ -513,7 +516,8 @@ static bool vangogh_is_dpm_running(struct smu_context *smu)
if (ret)
return false;
- return !!(feature_enabled & SMC_DPM_FEATURE);
+ return smu_feature_bits_test_mask(&feature_enabled,
+ vangogh_dpm_features.bits);
}
static int vangogh_get_dpm_clk_limited(struct smu_context *smu, enum smu_clk_type clk_type,
@@ -559,13 +563,14 @@ static int vangogh_get_dpm_clk_limited(struct smu_context *smu, enum smu_clk_typ
return 0;
}
-static int vangogh_print_legacy_clk_levels(struct smu_context *smu,
- enum smu_clk_type clk_type, char *buf)
+static int vangogh_emit_legacy_clk_levels(struct smu_context *smu,
+ enum smu_clk_type clk_type, char *buf,
+ int *offset)
{
+ int i, idx, size = *offset, ret = 0, start_offset = *offset;
DpmClocks_t *clk_table = smu->smu_table.clocks_table;
SmuMetrics_legacy_t metrics;
struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
- int i, idx, size = 0, ret = 0;
uint32_t cur_value = 0, value = 0, count = 0;
bool cur_value_match_level = false;
@@ -575,8 +580,6 @@ static int vangogh_print_legacy_clk_levels(struct smu_context *smu,
if (ret)
return ret;
- smu_cmn_get_sysfs_buf(&buf, &size);
-
switch (clk_type) {
case SMU_OD_SCLK:
if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) {
@@ -658,16 +661,18 @@ static int vangogh_print_legacy_clk_levels(struct smu_context *smu,
break;
}
- return size;
+ *offset += size - start_offset;
+
+ return 0;
}
-static int vangogh_print_clk_levels(struct smu_context *smu,
- enum smu_clk_type clk_type, char *buf)
+static int vangogh_emit_clk_levels(struct smu_context *smu,
+ enum smu_clk_type clk_type, char *buf,
+ int *offset)
{
+ int i, idx, size = *offset, ret = 0, start_offset = *offset;
DpmClocks_t *clk_table = smu->smu_table.clocks_table;
SmuMetrics_t metrics;
- struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
- int i, idx, size = 0, ret = 0;
uint32_t cur_value = 0, value = 0, count = 0;
bool cur_value_match_level = false;
uint32_t min, max;
@@ -678,35 +683,27 @@ static int vangogh_print_clk_levels(struct smu_context *smu,
if (ret)
return ret;
- smu_cmn_get_sysfs_buf(&buf, &size);
-
switch (clk_type) {
case SMU_OD_SCLK:
- if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) {
- size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK");
- size += sysfs_emit_at(buf, size, "0: %10uMhz\n",
- (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq);
- size += sysfs_emit_at(buf, size, "1: %10uMhz\n",
- (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq);
- }
+ size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK");
+ size += sysfs_emit_at(buf, size, "0: %10uMhz\n",
+ (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq);
+ size += sysfs_emit_at(buf, size, "1: %10uMhz\n",
+ (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq);
break;
case SMU_OD_CCLK:
- if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) {
- size += sysfs_emit_at(buf, size, "CCLK_RANGE in Core%d:\n", smu->cpu_core_id_select);
- size += sysfs_emit_at(buf, size, "0: %10uMhz\n",
- (smu->cpu_actual_soft_min_freq > 0) ? smu->cpu_actual_soft_min_freq : smu->cpu_default_soft_min_freq);
- size += sysfs_emit_at(buf, size, "1: %10uMhz\n",
- (smu->cpu_actual_soft_max_freq > 0) ? smu->cpu_actual_soft_max_freq : smu->cpu_default_soft_max_freq);
- }
+ size += sysfs_emit_at(buf, size, "CCLK_RANGE in Core%d:\n", smu->cpu_core_id_select);
+ size += sysfs_emit_at(buf, size, "0: %10uMhz\n",
+ (smu->cpu_actual_soft_min_freq > 0) ? smu->cpu_actual_soft_min_freq : smu->cpu_default_soft_min_freq);
+ size += sysfs_emit_at(buf, size, "1: %10uMhz\n",
+ (smu->cpu_actual_soft_max_freq > 0) ? smu->cpu_actual_soft_max_freq : smu->cpu_default_soft_max_freq);
break;
case SMU_OD_RANGE:
- if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) {
- size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");
- size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n",
- smu->gfx_default_hard_min_freq, smu->gfx_default_soft_max_freq);
- size += sysfs_emit_at(buf, size, "CCLK: %7uMhz %10uMhz\n",
- smu->cpu_default_soft_min_freq, smu->cpu_default_soft_max_freq);
- }
+ size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");
+ size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n",
+ smu->gfx_default_hard_min_freq, smu->gfx_default_soft_max_freq);
+ size += sysfs_emit_at(buf, size, "CCLK: %7uMhz %10uMhz\n",
+ smu->cpu_default_soft_min_freq, smu->cpu_default_soft_max_freq);
break;
case SMU_SOCCLK:
/* the level 3 ~ 6 of socclk use the same frequency for vangogh */
@@ -786,18 +783,21 @@ static int vangogh_print_clk_levels(struct smu_context *smu,
break;
}
- return size;
+ *offset += size - start_offset;
+
+ return 0;
}
-static int vangogh_common_print_clk_levels(struct smu_context *smu,
- enum smu_clk_type clk_type, char *buf)
+static int vangogh_common_emit_clk_levels(struct smu_context *smu,
+ enum smu_clk_type clk_type, char *buf,
+ int *offset)
{
int ret = 0;
if (smu->smc_fw_if_version < 0x3)
- ret = vangogh_print_legacy_clk_levels(smu, clk_type, buf);
+ ret = vangogh_emit_legacy_clk_levels(smu, clk_type, buf, offset);
else
- ret = vangogh_print_clk_levels(smu, clk_type, buf);
+ ret = vangogh_emit_clk_levels(smu, clk_type, buf, offset);
return ret;
}
@@ -1657,9 +1657,9 @@ static int vangogh_set_watermarks_table(struct smu_context *smu,
static ssize_t vangogh_get_legacy_gpu_metrics_v2_3(struct smu_context *smu,
void **table)
{
- struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v2_3 *gpu_metrics =
- (struct gpu_metrics_v2_3 *)smu_table->gpu_metrics_table;
+ (struct gpu_metrics_v2_3 *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
SmuMetrics_legacy_t metrics;
int ret = 0;
@@ -1708,15 +1708,17 @@ static ssize_t vangogh_get_legacy_gpu_metrics_v2_3(struct smu_context *smu,
*table = (void *)gpu_metrics;
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
return sizeof(struct gpu_metrics_v2_3);
}
static ssize_t vangogh_get_legacy_gpu_metrics(struct smu_context *smu,
void **table)
{
- struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v2_2 *gpu_metrics =
- (struct gpu_metrics_v2_2 *)smu_table->gpu_metrics_table;
+ (struct gpu_metrics_v2_2 *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
SmuMetrics_legacy_t metrics;
int ret = 0;
@@ -1765,15 +1767,17 @@ static ssize_t vangogh_get_legacy_gpu_metrics(struct smu_context *smu,
*table = (void *)gpu_metrics;
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
return sizeof(struct gpu_metrics_v2_2);
}
static ssize_t vangogh_get_gpu_metrics_v2_3(struct smu_context *smu,
void **table)
{
- struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v2_3 *gpu_metrics =
- (struct gpu_metrics_v2_3 *)smu_table->gpu_metrics_table;
+ (struct gpu_metrics_v2_3 *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
SmuMetrics_t metrics;
int ret = 0;
@@ -1836,6 +1840,8 @@ static ssize_t vangogh_get_gpu_metrics_v2_3(struct smu_context *smu,
*table = (void *)gpu_metrics;
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
return sizeof(struct gpu_metrics_v2_3);
}
@@ -1843,9 +1849,9 @@ static ssize_t vangogh_get_gpu_metrics_v2_4(struct smu_context *smu,
void **table)
{
SmuMetrics_t metrics;
- struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v2_4 *gpu_metrics =
- (struct gpu_metrics_v2_4 *)smu_table->gpu_metrics_table;
+ (struct gpu_metrics_v2_4 *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
int ret = 0;
ret = smu_cmn_get_metrics_table(smu, &metrics, true);
@@ -1916,15 +1922,17 @@ static ssize_t vangogh_get_gpu_metrics_v2_4(struct smu_context *smu,
*table = (void *)gpu_metrics;
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
return sizeof(struct gpu_metrics_v2_4);
}
static ssize_t vangogh_get_gpu_metrics(struct smu_context *smu,
void **table)
{
- struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v2_2 *gpu_metrics =
- (struct gpu_metrics_v2_2 *)smu_table->gpu_metrics_table;
+ (struct gpu_metrics_v2_2 *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
SmuMetrics_t metrics;
int ret = 0;
@@ -1980,6 +1988,8 @@ static ssize_t vangogh_get_gpu_metrics(struct smu_context *smu,
*table = (void *)gpu_metrics;
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
return sizeof(struct gpu_metrics_v2_2);
}
@@ -2036,6 +2046,7 @@ static int vangogh_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TAB
if (input[0] >= smu->cpu_core_num) {
dev_err(smu->adev->dev, "core index is overflow, should be less than %d\n",
smu->cpu_core_num);
+ return -EINVAL;
}
smu->cpu_core_id_select = input[0];
if (input[1] == 0) {
@@ -2224,6 +2235,9 @@ static int vangogh_post_smu_init(struct smu_context *smu)
uint32_t total_cu = adev->gfx.config.max_cu_per_sh *
adev->gfx.config.max_sh_per_se * adev->gfx.config.max_shader_engines;
+ if (adev->in_s0ix)
+ return 0;
+
/* allow message will be sent after enable message on Vangogh*/
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT) &&
(adev->pg_flags & AMD_PG_SUPPORT_GFX_PG)) {
@@ -2261,18 +2275,12 @@ static int vangogh_post_smu_init(struct smu_context *smu)
static int vangogh_mode_reset(struct smu_context *smu, int type)
{
- int ret = 0, index = 0;
-
- index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG,
- SMU_MSG_GfxDeviceDriverReset);
- if (index < 0)
- return index == -EACCES ? 0 : index;
-
- mutex_lock(&smu->message_lock);
-
- ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index, type);
+ struct smu_msg_ctl *ctl = &smu->msg_ctl;
+ int ret;
- mutex_unlock(&smu->message_lock);
+ mutex_lock(&ctl->lock);
+ ret = smu_msg_send_async_locked(ctl, SMU_MSG_GfxDeviceDriverReset, type);
+ mutex_unlock(&ctl->lock);
mdelay(10);
@@ -2315,8 +2323,7 @@ static int vangogh_get_power_limit(struct smu_context *smu,
uint32_t *max_power_limit,
uint32_t *min_power_limit)
{
- struct smu_11_5_power_context *power_context =
- smu->smu_power.power_context;
+ struct smu_11_5_power_context *power_context = smu->smu_power.power_context;
uint32_t ppt_limit;
int ret = 0;
@@ -2352,12 +2359,11 @@ static int vangogh_get_power_limit(struct smu_context *smu,
}
static int vangogh_get_ppt_limit(struct smu_context *smu,
- uint32_t *ppt_limit,
- enum smu_ppt_limit_type type,
- enum smu_ppt_limit_level level)
+ uint32_t *ppt_limit,
+ enum smu_ppt_limit_type type,
+ enum smu_ppt_limit_level level)
{
- struct smu_11_5_power_context *power_context =
- smu->smu_power.power_context;
+ struct smu_11_5_power_context *power_context = smu->smu_power.power_context;
if (!power_context)
return -EOPNOTSUPP;
@@ -2406,7 +2412,6 @@ static int vangogh_set_power_limit(struct smu_context *smu,
smu->current_power_limit = ppt_limit;
break;
case SMU_FAST_PPT_LIMIT:
- ppt_limit &= ~(SMU_FAST_PPT_LIMIT << 24);
if (ppt_limit > power_context->max_fast_ppt_limit) {
dev_err(smu->adev->dev,
"New power limit (%d) is over the max allowed %d\n",
@@ -2507,15 +2512,13 @@ static u32 vangogh_get_gfxoff_entrycount(struct smu_context *smu, uint64_t *entr
static const struct pptable_funcs vangogh_ppt_funcs = {
.check_fw_status = smu_v11_0_check_fw_status,
- .check_fw_version = smu_v11_0_check_fw_version,
+ .check_fw_version = smu_cmn_check_fw_version,
.init_smc_tables = vangogh_init_smc_tables,
.fini_smc_tables = smu_v11_0_fini_smc_tables,
.init_power = smu_v11_0_init_power,
.fini_power = smu_v11_0_fini_power,
.register_irq_handler = smu_v11_0_register_irq_handler,
.notify_memory_pool_location = smu_v11_0_notify_memory_pool_location,
- .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
- .send_smc_msg = smu_cmn_send_smc_msg,
.dpm_set_vcn_enable = vangogh_dpm_set_vcn_enable,
.dpm_set_jpeg_enable = vangogh_dpm_set_jpeg_enable,
.is_dpm_running = vangogh_is_dpm_running,
@@ -2529,7 +2532,7 @@ static const struct pptable_funcs vangogh_ppt_funcs = {
.interrupt_work = smu_v11_0_interrupt_work,
.get_gpu_metrics = vangogh_common_get_gpu_metrics,
.od_edit_dpm_table = vangogh_od_edit_dpm_table,
- .print_clk_levels = vangogh_common_print_clk_levels,
+ .emit_clk_levels = vangogh_common_emit_clk_levels,
.set_default_dpm_table = vangogh_set_default_dpm_tables,
.set_fine_grain_gfx_freq_parameters = vangogh_set_fine_grain_gfx_freq_parameters,
.notify_rlc_state = vangogh_notify_rlc_state,
@@ -2555,10 +2558,10 @@ static const struct pptable_funcs vangogh_ppt_funcs = {
void vangogh_set_ppt_funcs(struct smu_context *smu)
{
smu->ppt_funcs = &vangogh_ppt_funcs;
- smu->message_map = vangogh_message_map;
smu->feature_map = vangogh_feature_mask_map;
smu->table_map = vangogh_table_map;
smu->workload_map = vangogh_workload_map;
smu->is_apu = true;
- smu_v11_0_set_smu_mailbox_registers(smu);
+ smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION;
+ smu_v11_0_init_msg_ctl(smu, vangogh_message_map);
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
index 37d82a71a2d7..75335da224c7 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
@@ -41,15 +41,6 @@
#undef pr_info
#undef pr_debug
-#define mmMP1_SMN_C2PMSG_66 0x0282
-#define mmMP1_SMN_C2PMSG_66_BASE_IDX 0
-
-#define mmMP1_SMN_C2PMSG_82 0x0292
-#define mmMP1_SMN_C2PMSG_82_BASE_IDX 0
-
-#define mmMP1_SMN_C2PMSG_90 0x029a
-#define mmMP1_SMN_C2PMSG_90_BASE_IDX 0
-
static struct cmn2asic_msg_mapping renoir_message_map[SMU_MSG_MAX_COUNT] = {
MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1),
MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1),
@@ -157,6 +148,7 @@ static int renoir_init_smc_tables(struct smu_context *smu)
{
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_table *tables = smu_table->tables;
+ int ret;
SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
@@ -165,22 +157,23 @@ static int renoir_init_smc_tables(struct smu_context *smu)
SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
- smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL);
+ smu_table->clocks_table = kzalloc_obj(DpmClocks_t);
if (!smu_table->clocks_table)
goto err0_out;
- smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
+ smu_table->metrics_table = kzalloc_obj(SmuMetrics_t);
if (!smu_table->metrics_table)
goto err1_out;
smu_table->metrics_time = 0;
- smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL);
+ smu_table->watermarks_table = kzalloc_obj(Watermarks_t);
if (!smu_table->watermarks_table)
goto err2_out;
- smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_2);
- smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
- if (!smu_table->gpu_metrics_table)
+ ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS,
+ sizeof(struct gpu_metrics_v2_2),
+ SMU_GPU_METRICS_CACHE_INTERVAL);
+ if (ret)
goto err3_out;
return 0;
@@ -470,7 +463,7 @@ static int renoir_od_edit_dpm_table(struct smu_context *smu,
static int renoir_set_fine_grain_gfx_freq_parameters(struct smu_context *smu)
{
uint32_t min = 0, max = 0;
- uint32_t ret = 0;
+ int ret = 0;
ret = smu_cmn_send_smc_msg_with_param(smu,
SMU_MSG_GetMinGfxclkFrequency,
@@ -491,13 +484,13 @@ static int renoir_set_fine_grain_gfx_freq_parameters(struct smu_context *smu)
return 0;
}
-static int renoir_print_clk_levels(struct smu_context *smu,
- enum smu_clk_type clk_type, char *buf)
+static int renoir_emit_clk_levels(struct smu_context *smu,
+ enum smu_clk_type clk_type, char *buf,
+ int *offset)
{
- int i, idx, size = 0, ret = 0;
uint32_t cur_value = 0, value = 0, count = 0, min = 0, max = 0;
+ int i, idx, size = *offset, ret = 0, start_offset = *offset;
SmuMetrics_t metrics;
- struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
bool cur_value_match_level = false;
memset(&metrics, 0, sizeof(metrics));
@@ -506,56 +499,50 @@ static int renoir_print_clk_levels(struct smu_context *smu,
if (ret)
return ret;
- smu_cmn_get_sysfs_buf(&buf, &size);
-
switch (clk_type) {
case SMU_OD_RANGE:
- if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) {
- ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_GetMinGfxclkFrequency,
- 0, &min);
- if (ret)
- return ret;
- ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_GetMaxGfxclkFrequency,
- 0, &max);
- if (ret)
- return ret;
- size += sysfs_emit_at(buf, size, "OD_RANGE\nSCLK: %10uMhz %10uMhz\n", min, max);
- }
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_GetMinGfxclkFrequency,
+ 0, &min);
+ if (ret)
+ return ret;
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_GetMaxGfxclkFrequency,
+ 0, &max);
+ if (ret)
+ return ret;
+ size += sysfs_emit_at(buf, size, "OD_RANGE\nSCLK: %10uMhz %10uMhz\n", min, max);
break;
case SMU_OD_SCLK:
- if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) {
- min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq;
- max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq;
- size += sysfs_emit_at(buf, size, "OD_SCLK\n");
- size += sysfs_emit_at(buf, size, "0:%10uMhz\n", min);
- size += sysfs_emit_at(buf, size, "1:%10uMhz\n", max);
- }
+ min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq;
+ max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq;
+ size += sysfs_emit_at(buf, size, "OD_SCLK\n");
+ size += sysfs_emit_at(buf, size, "0:%10uMhz\n", min);
+ size += sysfs_emit_at(buf, size, "1:%10uMhz\n", max);
break;
case SMU_GFXCLK:
case SMU_SCLK:
/* retirve table returned paramters unit is MHz */
cur_value = metrics.ClockFrequency[CLOCK_GFXCLK];
ret = renoir_get_dpm_ultimate_freq(smu, SMU_GFXCLK, &min, &max);
- if (!ret) {
- /* driver only know min/max gfx_clk, Add level 1 for all other gfx clks */
- if (cur_value == max)
- i = 2;
- else if (cur_value == min)
- i = 0;
- else
- i = 1;
-
- size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", min,
- i == 0 ? "*" : "");
- size += sysfs_emit_at(buf, size, "1: %uMhz %s\n",
- i == 1 ? cur_value : RENOIR_UMD_PSTATE_GFXCLK,
- i == 1 ? "*" : "");
- size += sysfs_emit_at(buf, size, "2: %uMhz %s\n", max,
- i == 2 ? "*" : "");
- }
- return size;
+ if (ret)
+ return ret;
+ /* driver only know min/max gfx_clk, Add level 1 for all other gfx clks */
+ if (cur_value == max)
+ i = 2;
+ else if (cur_value == min)
+ i = 0;
+ else
+ i = 1;
+ size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", min,
+ i == 0 ? "*" : "");
+ size += sysfs_emit_at(buf, size, "1: %uMhz %s\n",
+ i == 1 ? cur_value :
+ RENOIR_UMD_PSTATE_GFXCLK,
+ i == 1 ? "*" : "");
+ size += sysfs_emit_at(buf, size, "2: %uMhz %s\n", max,
+ i == 2 ? "*" : "");
+ break;
case SMU_SOCCLK:
count = NUM_SOCCLK_DPM_LEVELS;
cur_value = metrics.ClockFrequency[CLOCK_SOCCLK];
@@ -612,7 +599,9 @@ static int renoir_print_clk_levels(struct smu_context *smu,
break;
}
- return size;
+ *offset += size - start_offset;
+
+ return 0;
}
static enum amd_pm_state_type renoir_get_current_power_state(struct smu_context *smu)
@@ -1285,6 +1274,12 @@ static int renoir_read_sensor(struct smu_context *smu,
(uint32_t *)data);
*size = 4;
break;
+ case AMDGPU_PP_SENSOR_VCN_LOAD:
+ ret = renoir_get_smu_metrics_data(smu,
+ METRICS_AVERAGE_VCNACTIVITY,
+ (uint32_t *)data);
+ *size = 4;
+ break;
case AMDGPU_PP_SENSOR_EDGE_TEMP:
ret = renoir_get_smu_metrics_data(smu,
METRICS_TEMPERATURE_EDGE,
@@ -1369,9 +1364,9 @@ static bool renoir_is_dpm_running(struct smu_context *smu)
static ssize_t renoir_get_gpu_metrics(struct smu_context *smu,
void **table)
{
- struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v2_2 *gpu_metrics =
- (struct gpu_metrics_v2_2 *)smu_table->gpu_metrics_table;
+ (struct gpu_metrics_v2_2 *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
SmuMetrics_t metrics;
int ret = 0;
@@ -1427,6 +1422,8 @@ static ssize_t renoir_get_gpu_metrics(struct smu_context *smu,
*table = (void *)gpu_metrics;
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
return sizeof(struct gpu_metrics_v2_2);
}
@@ -1437,18 +1434,18 @@ static int renoir_gfx_state_change_set(struct smu_context *smu, uint32_t state)
}
static int renoir_get_enabled_mask(struct smu_context *smu,
- uint64_t *feature_mask)
+ struct smu_feature_bits *feature_mask)
{
if (!feature_mask)
return -EINVAL;
- memset(feature_mask, 0xff, sizeof(*feature_mask));
+ smu_feature_bits_fill(feature_mask);
return 0;
}
static const struct pptable_funcs renoir_ppt_funcs = {
.set_power_state = NULL,
- .print_clk_levels = renoir_print_clk_levels,
+ .emit_clk_levels = renoir_emit_clk_levels,
.get_current_power_state = renoir_get_current_power_state,
.dpm_set_vcn_enable = renoir_dpm_set_vcn_enable,
.dpm_set_jpeg_enable = renoir_dpm_set_jpeg_enable,
@@ -1460,10 +1457,8 @@ static const struct pptable_funcs renoir_ppt_funcs = {
.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,
+ .check_fw_version = smu_cmn_check_fw_version,
.powergate_sdma = smu_v12_0_powergate_sdma,
- .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
- .send_smc_msg = smu_cmn_send_smc_msg,
.set_gfx_cgpg = smu_v12_0_set_gfx_cgpg,
.gfx_off_control = smu_v12_0_gfx_off_control,
.get_gfx_off_status = smu_v12_0_get_gfxoff_status,
@@ -1489,16 +1484,11 @@ static const struct pptable_funcs renoir_ppt_funcs = {
void renoir_set_ppt_funcs(struct smu_context *smu)
{
- struct amdgpu_device *adev = smu->adev;
-
smu->ppt_funcs = &renoir_ppt_funcs;
- smu->message_map = renoir_message_map;
smu->clock_map = renoir_clk_map;
smu->table_map = renoir_table_map;
smu->workload_map = renoir_workload_map;
smu->smc_driver_if_version = SMU12_DRIVER_IF_VERSION;
smu->is_apu = true;
- smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82);
- smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66);
- smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90);
+ smu_v12_0_init_msg_ctl(smu, renoir_message_map);
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c
index 3d3cd546f0ad..f09da4d14510 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c
@@ -70,43 +70,6 @@ int smu_v12_0_check_fw_status(struct smu_context *smu)
return -EIO;
}
-int smu_v12_0_check_fw_version(struct smu_context *smu)
-{
- struct amdgpu_device *adev = smu->adev;
- uint32_t if_version = 0xff, smu_version = 0xff;
- uint8_t smu_program, smu_major, smu_minor, smu_debug;
- int ret = 0;
-
- ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version);
- if (ret)
- return ret;
-
- smu_program = (smu_version >> 24) & 0xff;
- smu_major = (smu_version >> 16) & 0xff;
- smu_minor = (smu_version >> 8) & 0xff;
- smu_debug = (smu_version >> 0) & 0xff;
- if (smu->is_apu)
- adev->pm.fw_version = smu_version;
-
- /*
- * 1. if_version mismatch is not critical as our fw is designed
- * to be backward compatible.
- * 2. New fw usually brings some optimizations. But that's visible
- * only on the paired driver.
- * Considering above, we just leave user a verbal message instead
- * of halt driver loading.
- */
- if (if_version != smu->smc_driver_if_version) {
- dev_info(smu->adev->dev, "smu driver if version = 0x%08x, smu fw if version = 0x%08x, "
- "smu fw program = %d, smu fw version = 0x%08x (%d.%d.%d)\n",
- smu->smc_driver_if_version, if_version,
- smu_program, smu_version, smu_major, smu_minor, smu_debug);
- dev_info(smu->adev->dev, "SMU driver if version not matched\n");
- }
-
- return ret;
-}
-
int smu_v12_0_powergate_sdma(struct smu_context *smu, bool gate)
{
if (!smu->is_apu)
@@ -192,8 +155,7 @@ int smu_v12_0_fini_smc_tables(struct smu_context *smu)
kfree(smu_table->watermarks_table);
smu_table->watermarks_table = NULL;
- kfree(smu_table->gpu_metrics_table);
- smu_table->gpu_metrics_table = NULL;
+ smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS);
return 0;
}
@@ -406,3 +368,20 @@ int smu_v12_0_get_vbios_bootup_values(struct smu_context *smu)
return 0;
}
+
+void smu_v12_0_init_msg_ctl(struct smu_context *smu,
+ const struct cmn2asic_msg_mapping *message_map)
+{
+ struct amdgpu_device *adev = smu->adev;
+ struct smu_msg_ctl *ctl = &smu->msg_ctl;
+
+ ctl->smu = smu;
+ mutex_init(&ctl->lock);
+ ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66);
+ ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90);
+ ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82);
+ ctl->config.num_arg_regs = 1;
+ ctl->ops = &smu_msg_v1_ops;
+ ctl->default_timeout = adev->usec_timeout * 20;
+ ctl->message_map = message_map;
+}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/Makefile b/drivers/gpu/drm/amd/pm/swsmu/smu13/Makefile
index 7f3493b6c53c..51f1fa9789ab 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/Makefile
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/Makefile
@@ -24,7 +24,7 @@
# It provides the smu management services for the driver.
SMU13_MGR = smu_v13_0.o aldebaran_ppt.o yellow_carp_ppt.o smu_v13_0_0_ppt.o smu_v13_0_4_ppt.o \
- smu_v13_0_5_ppt.o smu_v13_0_7_ppt.o smu_v13_0_6_ppt.o
+ smu_v13_0_5_ppt.o smu_v13_0_7_ppt.o smu_v13_0_6_ppt.o smu_v13_0_12_ppt.o
AMD_SWSMU_SMU13MGR = $(addprefix $(AMD_SWSMU_PATH)/smu13/,$(SMU13_MGR))
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c
index 83163d7c7f00..9d8b1227388f 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c
@@ -61,18 +61,18 @@
[smu_feature] = {1, (aldebaran_feature)}
#define FEATURE_MASK(feature) (1ULL << feature)
-#define SMC_DPM_FEATURE ( \
- FEATURE_MASK(FEATURE_DATA_CALCULATIONS) | \
- FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_FCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_LCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_XGMI_BIT) | \
- FEATURE_MASK(FEATURE_DPM_VCN_BIT))
-
-/* possible frequency drift (1Mhz) */
-#define EPSILON 1
+static const struct smu_feature_bits aldebaran_dpm_features = {
+ .bits = {
+ SMU_FEATURE_BIT_INIT(FEATURE_DATA_CALCULATIONS),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_LCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_XGMI_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_VCN_BIT)
+ }
+};
#define smnPCIE_ESM_CTRL 0x111003D0
@@ -228,6 +228,7 @@ static int aldebaran_tables_init(struct smu_context *smu)
{
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_table *tables = smu_table->tables;
+ int ret;
SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
@@ -244,22 +245,23 @@ static int aldebaran_tables_init(struct smu_context *smu)
SMU_TABLE_INIT(tables, SMU_TABLE_ECCINFO, sizeof(EccInfoTable_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
- smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
+ smu_table->metrics_table = kzalloc_obj(SmuMetrics_t);
if (!smu_table->metrics_table)
return -ENOMEM;
smu_table->metrics_time = 0;
- smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_3);
- smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
- if (!smu_table->gpu_metrics_table) {
+ ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS,
+ sizeof(struct gpu_metrics_v1_3),
+ SMU_GPU_METRICS_CACHE_INTERVAL);
+ if (ret) {
kfree(smu_table->metrics_table);
- return -ENOMEM;
+ return ret;
}
smu_table->ecc_table = kzalloc(tables[SMU_TABLE_ECCINFO].size, GFP_KERNEL);
if (!smu_table->ecc_table) {
kfree(smu_table->metrics_table);
- kfree(smu_table->gpu_metrics_table);
+ smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS);
return -ENOMEM;
}
@@ -292,14 +294,13 @@ static int aldebaran_allocate_dpm_context(struct smu_context *smu)
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
struct smu_dpm_policy *policy;
- smu_dpm->dpm_context = kzalloc(sizeof(struct smu_13_0_dpm_context),
- GFP_KERNEL);
+ smu_dpm->dpm_context = kzalloc_obj(struct smu_13_0_dpm_context);
if (!smu_dpm->dpm_context)
return -ENOMEM;
smu_dpm->dpm_context_size = sizeof(struct smu_13_0_dpm_context);
smu_dpm->dpm_policies =
- kzalloc(sizeof(struct smu_dpm_policy_ctxt), GFP_KERNEL);
+ kzalloc_obj(struct smu_dpm_policy_ctxt);
if (!smu_dpm->dpm_policies)
return -ENOMEM;
@@ -330,14 +331,64 @@ static int aldebaran_init_smc_tables(struct smu_context *smu)
return smu_v13_0_init_smc_tables(smu);
}
-static int aldebaran_get_allowed_feature_mask(struct smu_context *smu,
- uint32_t *feature_mask, uint32_t num)
+static int aldebaran_init_allowed_features(struct smu_context *smu)
{
- if (num > 2)
- return -EINVAL;
+ smu_feature_list_set_all(smu, SMU_FEATURE_LIST_ALLOWED);
- /* pptable will handle the features to enable */
- memset(feature_mask, 0xFF, sizeof(uint32_t) * num);
+ return 0;
+}
+
+static int aldebaran_get_dpm_ultimate_freq(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t *min, uint32_t *max)
+{
+ struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
+ struct smu_dpm_table *dpm_table;
+ uint32_t min_clk, max_clk;
+
+ if (amdgpu_sriov_vf(smu->adev)) {
+ switch (clk_type) {
+ case SMU_MCLK:
+ case SMU_UCLK:
+ dpm_table = &dpm_context->dpm_tables.uclk_table;
+ break;
+ case SMU_GFXCLK:
+ case SMU_SCLK:
+ dpm_table = &dpm_context->dpm_tables.gfx_table;
+ break;
+ case SMU_SOCCLK:
+ dpm_table = &dpm_context->dpm_tables.soc_table;
+ break;
+ case SMU_FCLK:
+ dpm_table = &dpm_context->dpm_tables.fclk_table;
+ break;
+ case SMU_VCLK:
+ dpm_table = &dpm_context->dpm_tables.vclk_table;
+ break;
+ case SMU_DCLK:
+ dpm_table = &dpm_context->dpm_tables.dclk_table;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ min_clk = SMU_DPM_TABLE_MIN(dpm_table);
+ max_clk = SMU_DPM_TABLE_MAX(dpm_table);
+
+ if (min) {
+ if (!min_clk)
+ return -ENODATA;
+ *min = min_clk;
+ }
+ if (max) {
+ if (!max_clk)
+ return -ENODATA;
+ *max = max_clk;
+ }
+
+ } else {
+ return smu_v13_0_get_dpm_ultimate_freq(smu, clk_type, min, max);
+ }
return 0;
}
@@ -345,12 +396,13 @@ static int aldebaran_get_allowed_feature_mask(struct smu_context *smu,
static int aldebaran_set_default_dpm_table(struct smu_context *smu)
{
struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
- struct smu_13_0_dpm_table *dpm_table = NULL;
+ struct smu_dpm_table *dpm_table = NULL;
PPTable_t *pptable = smu->smu_table.driver_pptable;
int ret = 0;
/* socclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.soc_table;
+ dpm_table->clk_type = SMU_SOCCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
ret = smu_v13_0_set_single_dpm_table(smu,
SMU_SOCCLK,
@@ -361,12 +413,11 @@ static int aldebaran_set_default_dpm_table(struct smu_context *smu)
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.socclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* gfxclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.gfx_table;
+ dpm_table->clk_type = SMU_GFXCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) {
/* in the case of gfxclk, only fine-grained dpm is honored */
dpm_table->count = 2;
@@ -374,18 +425,16 @@ static int aldebaran_set_default_dpm_table(struct smu_context *smu)
dpm_table->dpm_levels[0].enabled = true;
dpm_table->dpm_levels[1].value = pptable->GfxclkFmax;
dpm_table->dpm_levels[1].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[1].value;
+ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* memclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.uclk_table;
+ dpm_table->clk_type = SMU_UCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
ret = smu_v13_0_set_single_dpm_table(smu,
SMU_UCLK,
@@ -396,12 +445,11 @@ static int aldebaran_set_default_dpm_table(struct smu_context *smu)
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.uclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* fclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.fclk_table;
+ dpm_table->clk_type = SMU_FCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT)) {
ret = smu_v13_0_set_single_dpm_table(smu,
SMU_FCLK,
@@ -412,8 +460,6 @@ static int aldebaran_set_default_dpm_table(struct smu_context *smu)
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.fclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
return 0;
@@ -538,29 +584,26 @@ static int aldebaran_populate_umd_state_clk(struct smu_context *smu)
{
struct smu_13_0_dpm_context *dpm_context =
smu->smu_dpm.dpm_context;
- struct smu_13_0_dpm_table *gfx_table =
- &dpm_context->dpm_tables.gfx_table;
- struct smu_13_0_dpm_table *mem_table =
- &dpm_context->dpm_tables.uclk_table;
- struct smu_13_0_dpm_table *soc_table =
- &dpm_context->dpm_tables.soc_table;
+ struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table;
+ struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table;
+ struct smu_dpm_table *soc_table = &dpm_context->dpm_tables.soc_table;
struct smu_umd_pstate_table *pstate_table =
&smu->pstate_table;
- pstate_table->gfxclk_pstate.min = gfx_table->min;
- pstate_table->gfxclk_pstate.peak = gfx_table->max;
- pstate_table->gfxclk_pstate.curr.min = gfx_table->min;
- pstate_table->gfxclk_pstate.curr.max = gfx_table->max;
+ pstate_table->gfxclk_pstate.min = SMU_DPM_TABLE_MIN(gfx_table);
+ pstate_table->gfxclk_pstate.peak = SMU_DPM_TABLE_MAX(gfx_table);
+ pstate_table->gfxclk_pstate.curr.min = SMU_DPM_TABLE_MIN(gfx_table);
+ pstate_table->gfxclk_pstate.curr.max = SMU_DPM_TABLE_MAX(gfx_table);
- pstate_table->uclk_pstate.min = mem_table->min;
- pstate_table->uclk_pstate.peak = mem_table->max;
- pstate_table->uclk_pstate.curr.min = mem_table->min;
- pstate_table->uclk_pstate.curr.max = mem_table->max;
+ pstate_table->uclk_pstate.min = SMU_DPM_TABLE_MIN(mem_table);
+ pstate_table->uclk_pstate.peak = SMU_DPM_TABLE_MAX(mem_table);
+ pstate_table->uclk_pstate.curr.min = SMU_DPM_TABLE_MIN(mem_table);
+ pstate_table->uclk_pstate.curr.max = SMU_DPM_TABLE_MAX(mem_table);
- pstate_table->socclk_pstate.min = soc_table->min;
- pstate_table->socclk_pstate.peak = soc_table->max;
- pstate_table->socclk_pstate.curr.min = soc_table->min;
- pstate_table->socclk_pstate.curr.max = soc_table->max;
+ pstate_table->socclk_pstate.min = SMU_DPM_TABLE_MIN(soc_table);
+ pstate_table->socclk_pstate.peak = SMU_DPM_TABLE_MAX(soc_table);
+ pstate_table->socclk_pstate.curr.min = SMU_DPM_TABLE_MIN(soc_table);
+ pstate_table->socclk_pstate.curr.max = SMU_DPM_TABLE_MAX(soc_table);
if (gfx_table->count > ALDEBARAN_UMD_PSTATE_GFXCLK_LEVEL &&
mem_table->count > ALDEBARAN_UMD_PSTATE_MCLK_LEVEL &&
@@ -583,30 +626,6 @@ static int aldebaran_populate_umd_state_clk(struct smu_context *smu)
return 0;
}
-static void aldebaran_get_clk_table(struct smu_context *smu,
- struct pp_clock_levels_with_latency *clocks,
- struct smu_13_0_dpm_table *dpm_table)
-{
- uint32_t i;
-
- clocks->num_levels = min_t(uint32_t,
- dpm_table->count,
- (uint32_t)PP_MAX_CLOCK_LEVELS);
-
- for (i = 0; i < clocks->num_levels; i++) {
- clocks->data[i].clocks_in_khz =
- dpm_table->dpm_levels[i].value * 1000;
- clocks->data[i].latency_in_us = 0;
- }
-
-}
-
-static int aldebaran_freqs_in_same_level(int32_t frequency1,
- int32_t frequency2)
-{
- return (abs(frequency1 - frequency2) <= EPSILON);
-}
-
static int aldebaran_get_smu_metrics_data(struct smu_context *smu,
MetricsMember_t member,
uint32_t *value)
@@ -773,16 +792,10 @@ static int aldebaran_emit_clk_levels(struct smu_context *smu,
{
int ret = 0;
struct smu_umd_pstate_table *pstate_table = &smu->pstate_table;
- struct pp_clock_levels_with_latency clocks;
- struct smu_13_0_dpm_table *single_dpm_table;
+ struct smu_dpm_table *single_dpm_table = NULL;
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
struct smu_13_0_dpm_context *dpm_context = NULL;
- uint32_t i;
- int display_levels;
- uint32_t freq_values[3] = {0};
- uint32_t min_clk, max_clk, cur_value = 0;
- bool freq_match;
- unsigned int clock_mhz;
+ uint32_t cur_value = 0;
static const char attempt_string[] = "Attempt to get current";
if (amdgpu_ras_intr_triggered()) {
@@ -793,134 +806,50 @@ static int aldebaran_emit_clk_levels(struct smu_context *smu,
dpm_context = smu_dpm->dpm_context;
switch (type) {
-
case SMU_OD_SCLK:
*offset += sysfs_emit_at(buf, *offset, "%s:\n", "OD_SCLK");
*offset += sysfs_emit_at(buf, *offset, "0: %uMhz\n1: %uMhz\n",
- pstate_table->gfxclk_pstate.curr.min,
- pstate_table->gfxclk_pstate.curr.max);
+ pstate_table->gfxclk_pstate.curr.min,
+ pstate_table->gfxclk_pstate.curr.max);
return 0;
- case SMU_SCLK:
- ret = aldebaran_get_current_clk_freq_by_table(smu, SMU_GFXCLK, &cur_value);
- if (ret) {
- dev_err(smu->adev->dev, "%s gfx clk Failed!", attempt_string);
- return ret;
- }
-
- single_dpm_table = &(dpm_context->dpm_tables.gfx_table);
- aldebaran_get_clk_table(smu, &clocks, single_dpm_table);
-
- display_levels = (clocks.num_levels == 1) ? 1 : 2;
-
- min_clk = pstate_table->gfxclk_pstate.curr.min;
- max_clk = pstate_table->gfxclk_pstate.curr.max;
-
- freq_values[0] = min_clk;
- freq_values[1] = max_clk;
-
- /* fine-grained dpm has only 2 levels */
- if (cur_value > min_clk && cur_value < max_clk) {
- display_levels++;
- freq_values[2] = max_clk;
- freq_values[1] = cur_value;
- }
- break;
-
case SMU_OD_MCLK:
*offset += sysfs_emit_at(buf, *offset, "%s:\n", "OD_MCLK");
*offset += sysfs_emit_at(buf, *offset, "0: %uMhz\n1: %uMhz\n",
- pstate_table->uclk_pstate.curr.min,
- pstate_table->uclk_pstate.curr.max);
+ pstate_table->uclk_pstate.curr.min,
+ pstate_table->uclk_pstate.curr.max);
return 0;
- case SMU_MCLK:
- ret = aldebaran_get_current_clk_freq_by_table(smu, SMU_UCLK, &cur_value);
- if (ret) {
- dev_err(smu->adev->dev, "%s mclk Failed!", attempt_string);
- return ret;
- }
+ case SMU_SCLK:
+ single_dpm_table = &(dpm_context->dpm_tables.gfx_table);
+ break;
+ case SMU_MCLK:
single_dpm_table = &(dpm_context->dpm_tables.uclk_table);
- aldebaran_get_clk_table(smu, &clocks, single_dpm_table);
break;
-
case SMU_SOCCLK:
- ret = aldebaran_get_current_clk_freq_by_table(smu, SMU_SOCCLK, &cur_value);
- if (ret) {
- dev_err(smu->adev->dev, "%s socclk Failed!", attempt_string);
- return ret;
- }
-
single_dpm_table = &(dpm_context->dpm_tables.soc_table);
- aldebaran_get_clk_table(smu, &clocks, single_dpm_table);
break;
-
case SMU_FCLK:
- ret = aldebaran_get_current_clk_freq_by_table(smu, SMU_FCLK, &cur_value);
- if (ret) {
- dev_err(smu->adev->dev, "%s fclk Failed!", attempt_string);
- return ret;
- }
-
single_dpm_table = &(dpm_context->dpm_tables.fclk_table);
- aldebaran_get_clk_table(smu, &clocks, single_dpm_table);
break;
-
case SMU_VCLK:
- ret = aldebaran_get_current_clk_freq_by_table(smu, SMU_VCLK, &cur_value);
- if (ret) {
- dev_err(smu->adev->dev, "%s vclk Failed!", attempt_string);
- return ret;
- }
-
single_dpm_table = &(dpm_context->dpm_tables.vclk_table);
- aldebaran_get_clk_table(smu, &clocks, single_dpm_table);
break;
-
case SMU_DCLK:
- ret = aldebaran_get_current_clk_freq_by_table(smu, SMU_DCLK, &cur_value);
- if (ret) {
- dev_err(smu->adev->dev, "%s dclk Failed!", attempt_string);
- return ret;
- }
-
single_dpm_table = &(dpm_context->dpm_tables.dclk_table);
- aldebaran_get_clk_table(smu, &clocks, single_dpm_table);
break;
-
default:
return -EINVAL;
}
- switch (type) {
- case SMU_SCLK:
- for (i = 0; i < display_levels; i++) {
- clock_mhz = freq_values[i];
- freq_match = aldebaran_freqs_in_same_level(clock_mhz, cur_value);
- freq_match |= (display_levels == 1);
-
- *offset += sysfs_emit_at(buf, *offset, "%d: %uMhz %s\n", i,
- clock_mhz,
- (freq_match) ? "*" : "");
- }
- break;
-
- case SMU_MCLK:
- case SMU_SOCCLK:
- case SMU_FCLK:
- case SMU_VCLK:
- case SMU_DCLK:
- for (i = 0; i < clocks.num_levels; i++) {
- clock_mhz = clocks.data[i].clocks_in_khz / 1000;
- freq_match = aldebaran_freqs_in_same_level(clock_mhz, cur_value);
- freq_match |= (clocks.num_levels == 1);
-
- *offset += sysfs_emit_at(buf, *offset, "%d: %uMhz %s\n",
- i, clock_mhz,
- (freq_match) ? "*" : "");
+ if (single_dpm_table) {
+ ret = aldebaran_get_current_clk_freq_by_table(smu, type,
+ &cur_value);
+ if (ret) {
+ dev_err(smu->adev->dev, "%s Failed!", attempt_string);
+ return ret;
}
- break;
- default:
- return -EINVAL;
+ return smu_cmn_print_dpm_clk_levels(smu, single_dpm_table,
+ cur_value, buf, offset);
}
return 0;
@@ -985,7 +914,7 @@ static int aldebaran_force_clk_levels(struct smu_context *smu,
enum smu_clk_type type, uint32_t mask)
{
struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
- struct smu_13_0_dpm_table *single_dpm_table = NULL;
+ struct smu_dpm_table *single_dpm_table = NULL;
uint32_t soft_min_level, soft_max_level;
int ret = 0;
@@ -1267,22 +1196,27 @@ static int aldebaran_set_performance_level(struct smu_context *smu,
{
struct smu_dpm_context *smu_dpm = &(smu->smu_dpm);
struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context;
- struct smu_13_0_dpm_table *gfx_table =
- &dpm_context->dpm_tables.gfx_table;
+ struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table;
struct smu_umd_pstate_table *pstate_table = &smu->pstate_table;
+ int r;
/* Disable determinism if switching to another mode */
if ((smu_dpm->dpm_level == AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) &&
(level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM)) {
smu_cmn_send_smc_msg(smu, SMU_MSG_DisableDeterminism, NULL);
- pstate_table->gfxclk_pstate.curr.max = gfx_table->max;
+ pstate_table->gfxclk_pstate.curr.max =
+ SMU_DPM_TABLE_MAX(gfx_table);
}
switch (level) {
case AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM:
return 0;
-
+ case AMD_DPM_FORCED_LEVEL_AUTO:
+ r = smu_v13_0_set_performance_level(smu, level);
+ if (!r)
+ smu_v13_0_reset_custom_level(smu);
+ return r;
case AMD_DPM_FORCED_LEVEL_HIGH:
case AMD_DPM_FORCED_LEVEL_LOW:
case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
@@ -1312,7 +1246,8 @@ static int aldebaran_set_soft_freq_limited_range(struct smu_context *smu,
if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK)
return -EINVAL;
-
+ min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.gfx_table);
+ max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.gfx_table);
if ((smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
&& (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM))
return -EINVAL;
@@ -1339,16 +1274,13 @@ static int aldebaran_set_soft_freq_limited_range(struct smu_context *smu,
}
if (smu_dpm->dpm_level == AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) {
- if (!max || (max < dpm_context->dpm_tables.gfx_table.min) ||
- (max > dpm_context->dpm_tables.gfx_table.max)) {
+ if (!max || (max < min_clk) || (max > max_clk)) {
dev_warn(adev->dev,
"Invalid max frequency %d MHz specified for determinism\n", max);
return -EINVAL;
}
/* Restore default min/max clocks and enable determinism */
- min_clk = dpm_context->dpm_tables.gfx_table.min;
- max_clk = dpm_context->dpm_tables.gfx_table.max;
ret = smu_v13_0_set_soft_freq_limited_range(smu, SMU_GFXCLK, min_clk, max_clk, false);
if (!ret) {
usleep_range(500, 1000);
@@ -1389,11 +1321,14 @@ static int aldebaran_usr_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_
dev_err(smu->adev->dev, "Input parameter number not correct\n");
return -EINVAL;
}
-
+ min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.gfx_table);
+ max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.gfx_table);
if (input[0] == 0) {
- if (input[1] < dpm_context->dpm_tables.gfx_table.min) {
- dev_warn(smu->adev->dev, "Minimum GFX clk (%ld) MHz specified is less than the minimum allowed (%d) MHz\n",
- input[1], dpm_context->dpm_tables.gfx_table.min);
+ if (input[1] < min_clk) {
+ dev_warn(
+ smu->adev->dev,
+ "Minimum GFX clk (%ld) MHz specified is less than the minimum allowed (%d) MHz\n",
+ input[1], min_clk);
pstate_table->gfxclk_pstate.custom.min =
pstate_table->gfxclk_pstate.curr.min;
return -EINVAL;
@@ -1401,9 +1336,11 @@ static int aldebaran_usr_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_
pstate_table->gfxclk_pstate.custom.min = input[1];
} else if (input[0] == 1) {
- if (input[1] > dpm_context->dpm_tables.gfx_table.max) {
- dev_warn(smu->adev->dev, "Maximum GFX clk (%ld) MHz specified is greater than the maximum allowed (%d) MHz\n",
- input[1], dpm_context->dpm_tables.gfx_table.max);
+ if (input[1] > max_clk) {
+ dev_warn(
+ smu->adev->dev,
+ "Maximum GFX clk (%ld) MHz specified is greater than the maximum allowed (%d) MHz\n",
+ input[1], max_clk);
pstate_table->gfxclk_pstate.custom.max =
pstate_table->gfxclk_pstate.curr.max;
return -EINVAL;
@@ -1420,10 +1357,16 @@ static int aldebaran_usr_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_
return -EINVAL;
} else {
/* Use the default frequencies for manual and determinism mode */
- min_clk = dpm_context->dpm_tables.gfx_table.min;
- max_clk = dpm_context->dpm_tables.gfx_table.max;
-
- return aldebaran_set_soft_freq_limited_range(smu, SMU_GFXCLK, min_clk, max_clk, false);
+ min_clk = SMU_DPM_TABLE_MIN(
+ &dpm_context->dpm_tables.gfx_table);
+ max_clk = SMU_DPM_TABLE_MAX(
+ &dpm_context->dpm_tables.gfx_table);
+
+ ret = aldebaran_set_soft_freq_limited_range(
+ smu, SMU_GFXCLK, min_clk, max_clk, false);
+ if (ret)
+ return ret;
+ smu_v13_0_reset_custom_level(smu);
}
break;
case PP_OD_COMMIT_DPM_TABLE:
@@ -1455,12 +1398,13 @@ static int aldebaran_usr_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_
static bool aldebaran_is_dpm_running(struct smu_context *smu)
{
int ret;
- uint64_t feature_enabled;
+ struct smu_feature_bits feature_enabled;
ret = smu_cmn_get_enabled_mask(smu, &feature_enabled);
if (ret)
return false;
- return !!(feature_enabled & SMC_DPM_FEATURE);
+ return smu_feature_bits_test_mask(&feature_enabled,
+ aldebaran_dpm_features.bits);
}
static int aldebaran_i2c_xfer(struct i2c_adapter *i2c_adap,
@@ -1478,7 +1422,7 @@ static int aldebaran_i2c_xfer(struct i2c_adapter *i2c_adap,
if (!adev->pm.dpm_enabled)
return -EBUSY;
- req = kzalloc(sizeof(*req), GFP_KERNEL);
+ req = kzalloc_obj(*req);
if (!req)
return -ENOMEM;
@@ -1577,33 +1521,22 @@ static int aldebaran_i2c_control_init(struct smu_context *smu)
control->quirks = &aldebaran_i2c_control_quirks;
i2c_set_adapdata(control, smu_i2c);
- res = i2c_add_adapter(control);
+ res = devm_i2c_add_adapter(adev->dev, control);
if (res) {
DRM_ERROR("Failed to register hw i2c, err: %d\n", res);
- goto Out_err;
+ return res;
}
adev->pm.ras_eeprom_i2c_bus = &adev->pm.smu_i2c[0].adapter;
adev->pm.fru_eeprom_i2c_bus = &adev->pm.smu_i2c[0].adapter;
return 0;
-Out_err:
- i2c_del_adapter(control);
-
- return res;
}
static void aldebaran_i2c_control_fini(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- int i;
-
- for (i = 0; i < MAX_SMU_I2C_BUSES; i++) {
- struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i];
- struct i2c_adapter *control = &smu_i2c->adapter;
- i2c_del_adapter(control);
- }
adev->pm.ras_eeprom_i2c_bus = NULL;
adev->pm.fru_eeprom_i2c_bus = NULL;
}
@@ -1709,15 +1642,15 @@ static int aldebaran_get_current_pcie_link_speed(struct smu_context *smu)
static ssize_t aldebaran_get_gpu_metrics(struct smu_context *smu,
void **table)
{
- struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v1_3 *gpu_metrics =
- (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table;
+ (struct gpu_metrics_v1_3 *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
SmuMetrics_t metrics;
int i, ret = 0;
ret = smu_cmn_get_metrics_table(smu,
&metrics,
- true);
+ false);
if (ret)
return ret;
@@ -1783,6 +1716,8 @@ static ssize_t aldebaran_get_gpu_metrics(struct smu_context *smu,
*table = (void *)gpu_metrics;
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
return sizeof(struct gpu_metrics_v1_3);
}
@@ -1892,26 +1827,29 @@ static int aldebaran_mode1_reset(struct smu_context *smu)
static int aldebaran_mode2_reset(struct smu_context *smu)
{
- int ret = 0, index;
+ struct smu_msg_ctl *ctl = &smu->msg_ctl;
struct amdgpu_device *adev = smu->adev;
+ int ret = 0;
int timeout = 10;
- index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG,
- SMU_MSG_GfxDeviceDriverReset);
- if (index < 0 )
- return -EINVAL;
- mutex_lock(&smu->message_lock);
+ mutex_lock(&ctl->lock);
+
if (smu->smc_fw_version >= 0x00441400) {
- ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index, SMU_RESET_MODE_2);
+ ret = smu_msg_send_async_locked(ctl, SMU_MSG_GfxDeviceDriverReset,
+ SMU_RESET_MODE_2);
+ if (ret)
+ goto out;
+
/* This is similar to FLR, wait till max FLR timeout */
msleep(100);
- dev_dbg(smu->adev->dev, "restore config space...\n");
+ dev_dbg(adev->dev, "restore config space...\n");
/* Restore the config space saved during init */
amdgpu_device_load_pci_state(adev->pdev);
- dev_dbg(smu->adev->dev, "wait for reset ack\n");
+ dev_dbg(adev->dev, "wait for reset ack\n");
+ ret = -ETIME;
while (ret == -ETIME && timeout) {
- ret = smu_cmn_wait_for_response(smu);
+ ret = smu_msg_wait_response(ctl, 0);
/* Wait a bit more time for getting ACK */
if (ret == -ETIME) {
--timeout;
@@ -1919,7 +1857,7 @@ static int aldebaran_mode2_reset(struct smu_context *smu)
continue;
}
- if (ret != 1) {
+ if (ret != 0) {
dev_err(adev->dev, "failed to send mode2 message \tparam: 0x%08x response %#x\n",
SMU_RESET_MODE_2, ret);
goto out;
@@ -1929,12 +1867,11 @@ static int aldebaran_mode2_reset(struct smu_context *smu)
} else {
dev_err(adev->dev, "smu fw 0x%x does not support MSG_GfxDeviceDriverReset MSG\n",
smu->smc_fw_version);
+ ret = -EOPNOTSUPP;
}
- if (ret == 1)
- ret = 0;
out:
- mutex_unlock(&smu->message_lock);
+ mutex_unlock(&ctl->lock);
return ret;
}
@@ -1976,11 +1913,6 @@ static bool aldebaran_is_mode1_reset_supported(struct smu_context *smu)
return true;
}
-static bool aldebaran_is_mode2_reset_supported(struct smu_context *smu)
-{
- return true;
-}
-
static int aldebaran_set_mp1_state(struct smu_context *smu,
enum pp_mp1_state mp1_state)
{
@@ -2034,7 +1966,7 @@ static int aldebaran_send_hbm_bad_channel_flag(struct smu_context *smu,
static const struct pptable_funcs aldebaran_ppt_funcs = {
/* init dpm */
- .get_allowed_feature_mask = aldebaran_get_allowed_feature_mask,
+ .init_allowed_features = aldebaran_init_allowed_features,
/* dpm/clk tables */
.set_default_dpm_table = aldebaran_set_default_dpm_table,
.populate_umd_state_clk = aldebaran_populate_umd_state_clk,
@@ -2057,14 +1989,12 @@ static const struct pptable_funcs aldebaran_ppt_funcs = {
/* pptable related */
.setup_pptable = aldebaran_setup_pptable,
.get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values,
- .check_fw_version = smu_v13_0_check_fw_version,
+ .check_fw_version = smu_cmn_check_fw_version,
.write_pptable = smu_cmn_write_pptable,
.set_driver_table_location = smu_v13_0_set_driver_table_location,
.set_tool_table_location = smu_v13_0_set_tool_table_location,
.notify_memory_pool_location = smu_v13_0_notify_memory_pool_location,
.system_features_control = aldebaran_system_features_control,
- .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
- .send_smc_msg = smu_cmn_send_smc_msg,
.get_enabled_mask = smu_cmn_get_enabled_mask,
.feature_is_enabled = smu_cmn_feature_is_enabled,
.disable_all_features_with_exception = smu_cmn_disable_all_features_with_exception,
@@ -2077,7 +2007,7 @@ static const struct pptable_funcs aldebaran_ppt_funcs = {
.set_azalia_d3_pme = smu_v13_0_set_azalia_d3_pme,
.get_max_sustainable_clocks_by_dc = smu_v13_0_get_max_sustainable_clocks_by_dc,
.get_bamaco_support = aldebaran_get_bamaco_support,
- .get_dpm_ultimate_freq = smu_v13_0_get_dpm_ultimate_freq,
+ .get_dpm_ultimate_freq = aldebaran_get_dpm_ultimate_freq,
.set_soft_freq_limited_range = aldebaran_set_soft_freq_limited_range,
.od_edit_dpm_table = aldebaran_usr_edit_dpm_table,
.set_df_cstate = aldebaran_set_df_cstate,
@@ -2086,7 +2016,6 @@ static const struct pptable_funcs aldebaran_ppt_funcs = {
.set_pp_feature_mask = smu_cmn_set_pp_feature_mask,
.get_gpu_metrics = aldebaran_get_gpu_metrics,
.mode1_reset_is_support = aldebaran_is_mode1_reset_supported,
- .mode2_reset_is_support = aldebaran_is_mode2_reset_supported,
.smu_handle_passthrough_sbr = aldebaran_smu_handle_passthrough_sbr,
.mode1_reset = aldebaran_mode1_reset,
.set_mp1_state = aldebaran_set_mp1_state,
@@ -2102,10 +2031,9 @@ static const struct pptable_funcs aldebaran_ppt_funcs = {
void aldebaran_set_ppt_funcs(struct smu_context *smu)
{
smu->ppt_funcs = &aldebaran_ppt_funcs;
- smu->message_map = aldebaran_message_map;
smu->clock_map = aldebaran_clk_map;
smu->feature_map = aldebaran_feature_mask_map;
smu->table_map = aldebaran_table_map;
smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_ALDE;
- smu_v13_0_set_smu_mailbox_registers(smu);
+ smu_v13_0_init_msg_ctl(smu, aldebaran_message_map);
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
index fbbdfa54f6a2..be9a7a32de99 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
@@ -58,6 +58,7 @@
MODULE_FIRMWARE("amdgpu/aldebaran_smc.bin");
MODULE_FIRMWARE("amdgpu/smu_13_0_0.bin");
+MODULE_FIRMWARE("amdgpu/smu_13_0_0_kicker.bin");
MODULE_FIRMWARE("amdgpu/smu_13_0_7.bin");
MODULE_FIRMWARE("amdgpu/smu_13_0_10.bin");
@@ -92,7 +93,7 @@ const int pmfw_decoded_link_width[7] = {0, 1, 2, 4, 8, 12, 16};
int smu_v13_0_init_microcode(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- char ucode_prefix[15];
+ char ucode_prefix[30];
int err = 0;
const struct smc_firmware_header_v1_0 *hdr;
const struct common_firmware_header *header;
@@ -103,8 +104,13 @@ int smu_v13_0_init_microcode(struct smu_context *smu)
return 0;
amdgpu_ucode_ip_version_decode(adev, MP1_HWIP, ucode_prefix, sizeof(ucode_prefix));
- err = amdgpu_ucode_request(adev, &adev->pm.fw, AMDGPU_UCODE_REQUIRED,
- "amdgpu/%s.bin", ucode_prefix);
+
+ if (amdgpu_is_kicker_fw(adev))
+ err = amdgpu_ucode_request(adev, &adev->pm.fw, AMDGPU_UCODE_REQUIRED,
+ "amdgpu/%s_kicker.bin", ucode_prefix);
+ else
+ err = amdgpu_ucode_request(adev, &adev->pm.fw, AMDGPU_UCODE_REQUIRED,
+ "amdgpu/%s.bin", ucode_prefix);
if (err)
goto out;
@@ -252,50 +258,6 @@ int smu_v13_0_check_fw_status(struct smu_context *smu)
return -EIO;
}
-int smu_v13_0_check_fw_version(struct smu_context *smu)
-{
- struct amdgpu_device *adev = smu->adev;
- uint32_t if_version = 0xff, smu_version = 0xff;
- uint8_t smu_program, smu_major, smu_minor, smu_debug;
- int ret = 0;
-
- ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version);
- if (ret)
- return ret;
-
- smu_program = (smu_version >> 24) & 0xff;
- smu_major = (smu_version >> 16) & 0xff;
- smu_minor = (smu_version >> 8) & 0xff;
- smu_debug = (smu_version >> 0) & 0xff;
- if (smu->is_apu ||
- amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 6) ||
- amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 14))
- adev->pm.fw_version = smu_version;
-
- /* only for dGPU w/ SMU13*/
- if (adev->pm.fw)
- dev_dbg(smu->adev->dev, "smu fw reported program %d, version = 0x%08x (%d.%d.%d)\n",
- smu_program, smu_version, smu_major, smu_minor, smu_debug);
-
- /*
- * 1. if_version mismatch is not critical as our fw is designed
- * to be backward compatible.
- * 2. New fw usually brings some optimizations. But that's visible
- * only on the paired driver.
- * Considering above, we just leave user a verbal message instead
- * of halt driver loading.
- */
- if (if_version != smu->smc_driver_if_version) {
- dev_info(adev->dev, "smu driver if version = 0x%08x, smu fw if version = 0x%08x, "
- "smu fw program = %d, smu fw version = 0x%08x (%d.%d.%d)\n",
- smu->smc_driver_if_version, if_version,
- smu_program, smu_version, smu_major, smu_minor, smu_debug);
- dev_info(adev->dev, "SMU driver if version not matched\n");
- }
-
- return ret;
-}
-
static int smu_v13_0_set_pptable_v2_0(struct smu_context *smu, void **table, uint32_t *size)
{
struct amdgpu_device *adev = smu->adev;
@@ -445,7 +407,7 @@ int smu_v13_0_init_smc_tables(struct smu_context *smu)
}
smu_table->max_sustainable_clocks =
- kzalloc(sizeof(struct smu_13_0_max_sustainable_clocks), GFP_KERNEL);
+ kzalloc_obj(struct smu_13_0_max_sustainable_clocks);
if (!smu_table->max_sustainable_clocks) {
ret = -ENOMEM;
goto err1_out;
@@ -503,14 +465,13 @@ int smu_v13_0_fini_smc_tables(struct smu_context *smu)
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
- kfree(smu_table->gpu_metrics_table);
+ smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS);
kfree(smu_table->combo_pptable);
kfree(smu_table->user_overdrive_table);
kfree(smu_table->boot_overdrive_table);
kfree(smu_table->overdrive_table);
kfree(smu_table->max_sustainable_clocks);
kfree(smu_table->driver_pptable);
- smu_table->gpu_metrics_table = NULL;
smu_table->combo_pptable = NULL;
smu_table->user_overdrive_table = NULL;
smu_table->boot_overdrive_table = NULL;
@@ -550,8 +511,7 @@ int smu_v13_0_init_power(struct smu_context *smu)
if (smu_power->power_context || smu_power->power_context_size != 0)
return -EINVAL;
- smu_power->power_context = kzalloc(sizeof(struct smu_13_0_power_context),
- GFP_KERNEL);
+ smu_power->power_context = kzalloc_obj(struct smu_13_0_power_context);
if (!smu_power->power_context)
return -ENOMEM;
smu_power->power_context_size = sizeof(struct smu_13_0_power_context);
@@ -712,18 +672,6 @@ int smu_v13_0_notify_memory_pool_location(struct smu_context *smu)
return ret;
}
-int smu_v13_0_set_min_deep_sleep_dcefclk(struct smu_context *smu, uint32_t clk)
-{
- int ret;
-
- ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_SetMinDeepSleepDcefclk, clk, NULL);
- if (ret)
- dev_err(smu->adev->dev, "SMU13 attempt to set divider for DCEFCLK Failed!");
-
- return ret;
-}
-
int smu_v13_0_set_driver_table_location(struct smu_context *smu)
{
struct smu_table *driver_table = &smu->smu_table.driver_table;
@@ -764,29 +712,17 @@ int smu_v13_0_set_tool_table_location(struct smu_context *smu)
return ret;
}
-int smu_v13_0_init_display_count(struct smu_context *smu, uint32_t count)
-{
- int ret = 0;
-
- if (!smu->pm_enabled)
- return ret;
-
- ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, count, NULL);
-
- return ret;
-}
-
int smu_v13_0_set_allowed_mask(struct smu_context *smu)
{
struct smu_feature *feature = &smu->smu_feature;
int ret = 0;
uint32_t feature_mask[2];
- if (bitmap_empty(feature->allowed, SMU_FEATURE_MAX) ||
- feature->feature_num < 64)
+ if (smu_feature_list_is_empty(smu, SMU_FEATURE_LIST_ALLOWED) ||
+ feature->feature_num < SMU_FEATURE_NUM_DEFAULT)
return -EINVAL;
- bitmap_to_arr32(feature_mask, feature->allowed, 64);
+ smu_feature_list_to_arr32(smu, SMU_FEATURE_LIST_ALLOWED, feature_mask);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetAllowedFeaturesMaskHigh,
feature_mask[1], NULL);
@@ -1076,56 +1012,6 @@ int smu_v13_0_get_gfx_vdd(struct smu_context *smu, uint32_t *value)
}
-int
-smu_v13_0_display_clock_voltage_request(struct smu_context *smu,
- struct pp_display_clock_request
- *clock_req)
-{
- enum amd_pp_clock_type clk_type = clock_req->clock_type;
- int ret = 0;
- enum smu_clk_type clk_select = 0;
- uint32_t clk_freq = clock_req->clock_freq_in_khz / 1000;
-
- if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) ||
- smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
- switch (clk_type) {
- case amd_pp_dcef_clock:
- clk_select = SMU_DCEFCLK;
- break;
- case amd_pp_disp_clock:
- clk_select = SMU_DISPCLK;
- break;
- case amd_pp_pixel_clock:
- clk_select = SMU_PIXCLK;
- break;
- case amd_pp_phy_clock:
- clk_select = SMU_PHYCLK;
- break;
- case amd_pp_mem_clock:
- clk_select = SMU_UCLK;
- break;
- default:
- dev_info(smu->adev->dev, "[%s] Invalid Clock Type!", __func__);
- ret = -EINVAL;
- break;
- }
-
- if (ret)
- goto failed;
-
- if (clk_select == SMU_UCLK && smu->disable_uclk_switch)
- return 0;
-
- ret = smu_v13_0_set_hard_freq_limited_range(smu, clk_select, clk_freq, 0);
-
- if (clk_select == SMU_UCLK)
- smu->hard_min_uclk_req_from_dal = clk_freq;
- }
-
-failed:
- return ret;
-}
-
uint32_t smu_v13_0_get_fan_control_mode(struct smu_context *smu)
{
if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_FAN_CONTROL_BIT))
@@ -1229,7 +1115,7 @@ int smu_v13_0_set_fan_speed_rpm(struct smu_context *smu,
uint32_t tach_period;
int ret;
- if (!speed)
+ if (!speed || speed > UINT_MAX/8)
return -EINVAL;
ret = smu_v13_0_auto_fan_control(smu, 0);
@@ -1625,6 +1511,7 @@ int smu_v13_0_set_soft_freq_limited_range(struct smu_context *smu,
return clk_id;
if (max > 0) {
+ max = SMU_V13_SOFT_FREQ_ROUND(max);
if (automatic)
param = (uint32_t)((clk_id << 16) | 0xffff);
else
@@ -1650,62 +1537,17 @@ out:
return ret;
}
-int smu_v13_0_set_hard_freq_limited_range(struct smu_context *smu,
- enum smu_clk_type clk_type,
- uint32_t min,
- uint32_t max)
-{
- int ret = 0, clk_id = 0;
- uint32_t param;
-
- if (min <= 0 && max <= 0)
- return -EINVAL;
-
- if (!smu_cmn_clk_dpm_is_enabled(smu, clk_type))
- return 0;
-
- clk_id = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_CLK,
- clk_type);
- if (clk_id < 0)
- return clk_id;
-
- if (max > 0) {
- param = (uint32_t)((clk_id << 16) | (max & 0xffff));
- ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMaxByFreq,
- param, NULL);
- if (ret)
- return ret;
- }
-
- if (min > 0) {
- param = (uint32_t)((clk_id << 16) | (min & 0xffff));
- ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinByFreq,
- param, NULL);
- if (ret)
- return ret;
- }
-
- return ret;
-}
-
int smu_v13_0_set_performance_level(struct smu_context *smu,
enum amd_dpm_forced_level level)
{
struct smu_13_0_dpm_context *dpm_context =
smu->smu_dpm.dpm_context;
- struct smu_13_0_dpm_table *gfx_table =
- &dpm_context->dpm_tables.gfx_table;
- struct smu_13_0_dpm_table *mem_table =
- &dpm_context->dpm_tables.uclk_table;
- struct smu_13_0_dpm_table *soc_table =
- &dpm_context->dpm_tables.soc_table;
- struct smu_13_0_dpm_table *vclk_table =
- &dpm_context->dpm_tables.vclk_table;
- struct smu_13_0_dpm_table *dclk_table =
- &dpm_context->dpm_tables.dclk_table;
- struct smu_13_0_dpm_table *fclk_table =
- &dpm_context->dpm_tables.fclk_table;
+ struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table;
+ struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table;
+ struct smu_dpm_table *soc_table = &dpm_context->dpm_tables.soc_table;
+ struct smu_dpm_table *vclk_table = &dpm_context->dpm_tables.vclk_table;
+ struct smu_dpm_table *dclk_table = &dpm_context->dpm_tables.dclk_table;
+ struct smu_dpm_table *fclk_table = &dpm_context->dpm_tables.fclk_table;
struct smu_umd_pstate_table *pstate_table =
&smu->pstate_table;
struct amdgpu_device *adev = smu->adev;
@@ -1720,34 +1562,34 @@ int smu_v13_0_set_performance_level(struct smu_context *smu,
switch (level) {
case AMD_DPM_FORCED_LEVEL_HIGH:
- sclk_min = sclk_max = gfx_table->max;
- mclk_min = mclk_max = mem_table->max;
- socclk_min = socclk_max = soc_table->max;
- vclk_min = vclk_max = vclk_table->max;
- dclk_min = dclk_max = dclk_table->max;
- fclk_min = fclk_max = fclk_table->max;
+ sclk_min = sclk_max = SMU_DPM_TABLE_MAX(gfx_table);
+ mclk_min = mclk_max = SMU_DPM_TABLE_MAX(mem_table);
+ socclk_min = socclk_max = SMU_DPM_TABLE_MAX(soc_table);
+ vclk_min = vclk_max = SMU_DPM_TABLE_MAX(vclk_table);
+ dclk_min = dclk_max = SMU_DPM_TABLE_MAX(dclk_table);
+ fclk_min = fclk_max = SMU_DPM_TABLE_MAX(fclk_table);
break;
case AMD_DPM_FORCED_LEVEL_LOW:
- sclk_min = sclk_max = gfx_table->min;
- mclk_min = mclk_max = mem_table->min;
- socclk_min = socclk_max = soc_table->min;
- vclk_min = vclk_max = vclk_table->min;
- dclk_min = dclk_max = dclk_table->min;
- fclk_min = fclk_max = fclk_table->min;
+ sclk_min = sclk_max = SMU_DPM_TABLE_MIN(gfx_table);
+ mclk_min = mclk_max = SMU_DPM_TABLE_MIN(mem_table);
+ socclk_min = socclk_max = SMU_DPM_TABLE_MIN(soc_table);
+ vclk_min = vclk_max = SMU_DPM_TABLE_MIN(vclk_table);
+ dclk_min = dclk_max = SMU_DPM_TABLE_MIN(dclk_table);
+ fclk_min = fclk_max = SMU_DPM_TABLE_MIN(fclk_table);
break;
case AMD_DPM_FORCED_LEVEL_AUTO:
- sclk_min = gfx_table->min;
- sclk_max = gfx_table->max;
- mclk_min = mem_table->min;
- mclk_max = mem_table->max;
- socclk_min = soc_table->min;
- socclk_max = soc_table->max;
- vclk_min = vclk_table->min;
- vclk_max = vclk_table->max;
- dclk_min = dclk_table->min;
- dclk_max = dclk_table->max;
- fclk_min = fclk_table->min;
- fclk_max = fclk_table->max;
+ sclk_min = SMU_DPM_TABLE_MIN(gfx_table);
+ sclk_max = SMU_DPM_TABLE_MAX(gfx_table);
+ mclk_min = SMU_DPM_TABLE_MIN(mem_table);
+ mclk_max = SMU_DPM_TABLE_MAX(mem_table);
+ socclk_min = SMU_DPM_TABLE_MIN(soc_table);
+ socclk_max = SMU_DPM_TABLE_MAX(soc_table);
+ vclk_min = SMU_DPM_TABLE_MIN(vclk_table);
+ vclk_max = SMU_DPM_TABLE_MAX(vclk_table);
+ dclk_min = SMU_DPM_TABLE_MIN(dclk_table);
+ dclk_max = SMU_DPM_TABLE_MAX(dclk_table);
+ fclk_min = SMU_DPM_TABLE_MIN(fclk_table);
+ fclk_max = SMU_DPM_TABLE_MAX(fclk_table);
auto_level = true;
break;
case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
@@ -2018,11 +1860,12 @@ static int smu_v13_0_get_fine_grained_status(struct smu_context *smu,
int smu_v13_0_set_single_dpm_table(struct smu_context *smu,
enum smu_clk_type clk_type,
- struct smu_13_0_dpm_table *single_dpm_table)
+ struct smu_dpm_table *single_dpm_table)
{
int ret = 0;
uint32_t clk;
int i;
+ bool is_fine_grained;
ret = smu_v13_0_get_dpm_level_count(smu,
clk_type,
@@ -2033,13 +1876,14 @@ int smu_v13_0_set_single_dpm_table(struct smu_context *smu,
}
if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) != IP_VERSION(13, 0, 2)) {
- ret = smu_v13_0_get_fine_grained_status(smu,
- clk_type,
- &single_dpm_table->is_fine_grained);
+ ret = smu_v13_0_get_fine_grained_status(smu, clk_type,
+ &is_fine_grained);
if (ret) {
dev_err(smu->adev->dev, "[%s] failed to get fine grained status!\n", __func__);
return ret;
}
+ if (is_fine_grained)
+ single_dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
}
for (i = 0; i < single_dpm_table->count; i++) {
@@ -2054,11 +1898,6 @@ int smu_v13_0_set_single_dpm_table(struct smu_context *smu,
single_dpm_table->dpm_levels[i].value = clk;
single_dpm_table->dpm_levels[i].enabled = true;
-
- if (i == 0)
- single_dpm_table->min = clk;
- else if (i == single_dpm_table->count - 1)
- single_dpm_table->max = clk;
}
return 0;
@@ -2363,18 +2202,21 @@ int smu_v13_0_baco_exit(struct smu_context *smu)
int smu_v13_0_set_gfx_power_up_by_imu(struct smu_context *smu)
{
- uint16_t index;
+ struct smu_msg_ctl *ctl = &smu->msg_ctl;
struct amdgpu_device *adev = smu->adev;
+ int ret;
if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_EnableGfxImu,
ENABLE_IMU_ARG_GFXOFF_ENABLE, NULL);
}
- index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG,
- SMU_MSG_EnableGfxImu);
- return smu_cmn_send_msg_without_waiting(smu, index,
- ENABLE_IMU_ARG_GFXOFF_ENABLE);
+ mutex_lock(&ctl->lock);
+ ret = smu_msg_send_async_locked(ctl, SMU_MSG_EnableGfxImu,
+ ENABLE_IMU_ARG_GFXOFF_ENABLE);
+ mutex_unlock(&ctl->lock);
+
+ return ret;
}
int smu_v13_0_od_edit_dpm_table(struct smu_context *smu,
@@ -2467,13 +2309,22 @@ int smu_v13_0_set_default_dpm_tables(struct smu_context *smu)
smu_table->clocks_table, false);
}
-void smu_v13_0_set_smu_mailbox_registers(struct smu_context *smu)
+void smu_v13_0_init_msg_ctl(struct smu_context *smu,
+ const struct cmn2asic_msg_mapping *message_map)
{
struct amdgpu_device *adev = smu->adev;
+ struct smu_msg_ctl *ctl = &smu->msg_ctl;
- smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82);
- smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66);
- smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90);
+ ctl->smu = smu;
+ mutex_init(&ctl->lock);
+ ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66);
+ ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90);
+ ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82);
+ ctl->config.num_arg_regs = 1;
+ ctl->ops = &smu_msg_v1_ops;
+ ctl->default_timeout = adev->usec_timeout * 20;
+ ctl->message_map = message_map;
+ ctl->flags = 0;
}
int smu_v13_0_mode1_reset(struct smu_context *smu)
@@ -2492,11 +2343,11 @@ int smu_v13_0_update_pcie_parameters(struct smu_context *smu,
uint8_t pcie_width_cap)
{
struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
- struct smu_13_0_pcie_table *pcie_table =
- &dpm_context->dpm_tables.pcie_table;
- int num_of_levels = pcie_table->num_of_link_levels;
+ struct smu_pcie_table *pcie_table = &dpm_context->dpm_tables.pcie_table;
+ int num_of_levels = pcie_table->lclk_levels;
uint32_t smu_pcie_arg;
- int ret, i;
+ int ret = 0;
+ int i;
if (!num_of_levels)
return 0;
@@ -2512,30 +2363,38 @@ int smu_v13_0_update_pcie_parameters(struct smu_context *smu,
for (i = 0; i < num_of_levels; i++) {
pcie_table->pcie_gen[i] = pcie_gen_cap;
pcie_table->pcie_lane[i] = pcie_width_cap;
+ smu_pcie_arg = i << 16;
+ smu_pcie_arg |= pcie_table->pcie_gen[i] << 8;
+ smu_pcie_arg |= pcie_table->pcie_lane[i];
+
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_OverridePcieParameters,
+ smu_pcie_arg,
+ NULL);
+ if (ret)
+ break;
}
} else {
for (i = 0; i < num_of_levels; i++) {
- if (pcie_table->pcie_gen[i] > pcie_gen_cap)
+ if (pcie_table->pcie_gen[i] > pcie_gen_cap ||
+ pcie_table->pcie_lane[i] > pcie_width_cap) {
pcie_table->pcie_gen[i] = pcie_gen_cap;
- if (pcie_table->pcie_lane[i] > pcie_width_cap)
pcie_table->pcie_lane[i] = pcie_width_cap;
+ smu_pcie_arg = i << 16;
+ smu_pcie_arg |= pcie_table->pcie_gen[i] << 8;
+ smu_pcie_arg |= pcie_table->pcie_lane[i];
+
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_OverridePcieParameters,
+ smu_pcie_arg,
+ NULL);
+ if (ret)
+ break;
+ }
}
}
- for (i = 0; i < num_of_levels; i++) {
- smu_pcie_arg = i << 16;
- smu_pcie_arg |= pcie_table->pcie_gen[i] << 8;
- smu_pcie_arg |= pcie_table->pcie_lane[i];
-
- ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_OverridePcieParameters,
- smu_pcie_arg,
- NULL);
- if (ret)
- return ret;
- }
-
- return 0;
+ return ret;
}
int smu_v13_0_disable_pmfw_state(struct smu_context *smu)
@@ -2598,3 +2457,15 @@ int smu_v13_0_set_wbrf_exclusion_ranges(struct smu_context *smu,
return ret;
}
+
+void smu_v13_0_reset_custom_level(struct smu_context *smu)
+{
+ struct smu_umd_pstate_table *pstate_table = &smu->pstate_table;
+
+ pstate_table->uclk_pstate.custom.min = 0;
+ pstate_table->uclk_pstate.custom.max = 0;
+ pstate_table->gfxclk_pstate.custom.min = 0;
+ pstate_table->gfxclk_pstate.custom.max = 0;
+ pstate_table->fclk_pstate.custom.min = 0;
+ pstate_table->fclk_pstate.custom.max = 0;
+}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
index 0551a3311217..acbd7046d8a5 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
@@ -59,26 +59,23 @@
#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c))
-#define FEATURE_MASK(feature) (1ULL << feature)
-#define SMC_DPM_FEATURE ( \
- FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_LINK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_FCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT))
+static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu,
+ int od_feature_bit,
+ int32_t *min, int32_t *max);
+
+static const struct smu_feature_bits smu_v13_0_0_dpm_features = {
+ .bits = {
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_LINK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_MP0CLK_BIT)
+ }
+};
#define MP0_MP1_DATA_REGION_SIZE_COMBOPPTABLE 0x4000
-#define mmMP1_SMN_C2PMSG_66 0x0282
-#define mmMP1_SMN_C2PMSG_66_BASE_IDX 0
-
-#define mmMP1_SMN_C2PMSG_82 0x0292
-#define mmMP1_SMN_C2PMSG_82_BASE_IDX 0
-
-#define mmMP1_SMN_C2PMSG_90 0x029a
-#define mmMP1_SMN_C2PMSG_90_BASE_IDX 0
-
#define mmMP1_SMN_C2PMSG_75 0x028b
#define mmMP1_SMN_C2PMSG_75_BASE_IDX 0
@@ -126,7 +123,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] =
MSG_MAP(DisableSmuFeaturesHigh, PPSMC_MSG_DisableSmuFeaturesHigh, 1),
MSG_MAP(GetEnabledSmuFeaturesLow, PPSMC_MSG_GetRunningSmuFeaturesLow, 1),
MSG_MAP(GetEnabledSmuFeaturesHigh, PPSMC_MSG_GetRunningSmuFeaturesHigh, 1),
- MSG_MAP(SetWorkloadMask, PPSMC_MSG_SetWorkloadMask, 1),
+ MSG_MAP(SetWorkloadMask, PPSMC_MSG_SetWorkloadMask, 0),
MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit, 0),
MSG_MAP(SetDriverDramAddrHigh, PPSMC_MSG_SetDriverDramAddrHigh, 1),
MSG_MAP(SetDriverDramAddrLow, PPSMC_MSG_SetDriverDramAddrLow, 1),
@@ -140,7 +137,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] =
MSG_MAP(ExitBaco, PPSMC_MSG_ExitBaco, 0),
MSG_MAP(SetSoftMinByFreq, PPSMC_MSG_SetSoftMinByFreq, 1),
MSG_MAP(SetSoftMaxByFreq, PPSMC_MSG_SetSoftMaxByFreq, 1),
- MSG_MAP(SetHardMinByFreq, PPSMC_MSG_SetHardMinByFreq, 1),
+ MSG_MAP(SetHardMinByFreq, PPSMC_MSG_SetHardMinByFreq, 0),
MSG_MAP(SetHardMaxByFreq, PPSMC_MSG_SetHardMaxByFreq, 0),
MSG_MAP(GetMinDpmFreq, PPSMC_MSG_GetMinDpmFreq, 1),
MSG_MAP(GetMaxDpmFreq, PPSMC_MSG_GetMaxDpmFreq, 1),
@@ -149,7 +146,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] =
MSG_MAP(PowerDownVcn, PPSMC_MSG_PowerDownVcn, 0),
MSG_MAP(PowerUpJpeg, PPSMC_MSG_PowerUpJpeg, 0),
MSG_MAP(PowerDownJpeg, PPSMC_MSG_PowerDownJpeg, 0),
- MSG_MAP(GetDcModeMaxDpmFreq, PPSMC_MSG_GetDcModeMaxDpmFreq, 1),
+ MSG_MAP(GetDcModeMaxDpmFreq, PPSMC_MSG_GetDcModeMaxDpmFreq, 0),
MSG_MAP(OverridePcieParameters, PPSMC_MSG_OverridePcieParameters, 0),
MSG_MAP(DramLogSetDramAddrHigh, PPSMC_MSG_DramLogSetDramAddrHigh, 0),
MSG_MAP(DramLogSetDramAddrLow, PPSMC_MSG_DramLogSetDramAddrLow, 0),
@@ -296,49 +293,44 @@ static const uint8_t smu_v13_0_0_throttler_map[] = {
};
static int
-smu_v13_0_0_get_allowed_feature_mask(struct smu_context *smu,
- uint32_t *feature_mask, uint32_t num)
+smu_v13_0_0_init_allowed_features(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- if (num > 2)
- return -EINVAL;
-
- memset(feature_mask, 0xff, sizeof(uint32_t) * num);
+ smu_feature_list_set_all(smu, SMU_FEATURE_LIST_ALLOWED);
if (!(adev->pm.pp_feature & PP_SCLK_DPM_MASK)) {
- *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT);
- *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_GFX_IMU_BIT);
+ smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_GFXCLK_BIT);
+ smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFX_IMU_BIT);
}
if (!(adev->pg_flags & AMD_PG_SUPPORT_ATHUB) ||
!(adev->pg_flags & AMD_PG_SUPPORT_MMHUB))
- *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_ATHUB_MMHUB_PG_BIT);
+ smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_ATHUB_MMHUB_PG_BIT);
if (!(adev->pm.pp_feature & PP_SOCCLK_DPM_MASK))
- *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT);
+ smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_SOCCLK_BIT);
- /* PMFW 78.58 contains a critical fix for gfxoff feature */
if ((smu->smc_fw_version < 0x004e3a00) ||
!(adev->pm.pp_feature & PP_GFXOFF_MASK))
- *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_GFXOFF_BIT);
+ smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFXOFF_BIT);
if (!(adev->pm.pp_feature & PP_MCLK_DPM_MASK)) {
- *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DPM_UCLK_BIT);
- *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_VMEMP_SCALING_BIT);
- *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_VDDIO_MEM_SCALING_BIT);
+ smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_UCLK_BIT);
+ smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_VMEMP_SCALING_BIT);
+ smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_VDDIO_MEM_SCALING_BIT);
}
if (!(adev->pm.pp_feature & PP_SCLK_DEEP_SLEEP_MASK))
- *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DS_GFXCLK_BIT);
+ smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_GFXCLK_BIT);
if (!(adev->pm.pp_feature & PP_PCIE_DPM_MASK)) {
- *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DPM_LINK_BIT);
- *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DS_LCLK_BIT);
+ smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_LINK_BIT);
+ smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_LCLK_BIT);
}
if (!(adev->pm.pp_feature & PP_ULV_MASK))
- *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_GFX_ULV_BIT);
+ smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFX_ULV_BIT);
return 0;
}
@@ -482,6 +474,7 @@ static int smu_v13_0_0_tables_init(struct smu_context *smu)
{
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_table *tables = smu_table->tables;
+ int ret;
SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
@@ -506,17 +499,18 @@ static int smu_v13_0_0_tables_init(struct smu_context *smu)
sizeof(WifiBandEntryTable_t), PAGE_SIZE,
AMDGPU_GEM_DOMAIN_VRAM);
- smu_table->metrics_table = kzalloc(sizeof(SmuMetricsExternal_t), GFP_KERNEL);
+ smu_table->metrics_table = kzalloc_obj(SmuMetricsExternal_t);
if (!smu_table->metrics_table)
goto err0_out;
smu_table->metrics_time = 0;
- smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_3);
- smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
- if (!smu_table->gpu_metrics_table)
+ ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS,
+ sizeof(struct gpu_metrics_v1_3),
+ SMU_GPU_METRICS_CACHE_INTERVAL);
+ if (ret)
goto err1_out;
- smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL);
+ smu_table->watermarks_table = kzalloc_obj(Watermarks_t);
if (!smu_table->watermarks_table)
goto err2_out;
@@ -529,7 +523,7 @@ static int smu_v13_0_0_tables_init(struct smu_context *smu)
err3_out:
kfree(smu_table->watermarks_table);
err2_out:
- kfree(smu_table->gpu_metrics_table);
+ smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS);
err1_out:
kfree(smu_table->metrics_table);
err0_out:
@@ -540,8 +534,7 @@ static int smu_v13_0_0_allocate_dpm_context(struct smu_context *smu)
{
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
- smu_dpm->dpm_context = kzalloc(sizeof(struct smu_13_0_dpm_context),
- GFP_KERNEL);
+ smu_dpm->dpm_context = kzalloc_obj(struct smu_13_0_dpm_context);
if (!smu_dpm->dpm_context)
return -ENOMEM;
@@ -571,13 +564,12 @@ static int smu_v13_0_0_set_default_dpm_table(struct smu_context *smu)
struct smu_table_context *table_context = &smu->smu_table;
PPTable_t *pptable = table_context->driver_pptable;
SkuTable_t *skutable = &pptable->SkuTable;
- struct smu_13_0_dpm_table *dpm_table;
- struct smu_13_0_pcie_table *pcie_table;
- uint32_t link_level;
+ struct smu_dpm_table *dpm_table;
int ret = 0;
/* socclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.soc_table;
+ dpm_table->clk_type = SMU_SOCCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
ret = smu_v13_0_set_single_dpm_table(smu,
SMU_SOCCLK,
@@ -588,12 +580,11 @@ static int smu_v13_0_0_set_default_dpm_table(struct smu_context *smu)
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.socclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* gfxclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.gfx_table;
+ dpm_table->clk_type = SMU_GFXCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) {
ret = smu_v13_0_set_single_dpm_table(smu,
SMU_GFXCLK,
@@ -615,18 +606,16 @@ static int smu_v13_0_0_set_default_dpm_table(struct smu_context *smu)
skutable->DriverReportedClocks.GameClockAc)) {
dpm_table->dpm_levels[dpm_table->count - 1].value =
skutable->DriverReportedClocks.GameClockAc;
- dpm_table->max = skutable->DriverReportedClocks.GameClockAc;
}
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* uclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.uclk_table;
+ dpm_table->clk_type = SMU_UCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
ret = smu_v13_0_set_single_dpm_table(smu,
SMU_UCLK,
@@ -637,12 +626,11 @@ static int smu_v13_0_0_set_default_dpm_table(struct smu_context *smu)
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.uclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* fclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.fclk_table;
+ dpm_table->clk_type = SMU_FCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT)) {
ret = smu_v13_0_set_single_dpm_table(smu,
SMU_FCLK,
@@ -653,12 +641,11 @@ static int smu_v13_0_0_set_default_dpm_table(struct smu_context *smu)
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.fclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* vclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.vclk_table;
+ dpm_table->clk_type = SMU_VCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_VCLK_BIT)) {
ret = smu_v13_0_set_single_dpm_table(smu,
SMU_VCLK,
@@ -669,12 +656,11 @@ static int smu_v13_0_0_set_default_dpm_table(struct smu_context *smu)
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.vclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* dclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.dclk_table;
+ dpm_table->clk_type = SMU_DCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCLK_BIT)) {
ret = smu_v13_0_set_single_dpm_table(smu,
SMU_DCLK,
@@ -685,30 +671,11 @@ static int smu_v13_0_0_set_default_dpm_table(struct smu_context *smu)
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
- }
-
- /* lclk dpm table setup */
- pcie_table = &dpm_context->dpm_tables.pcie_table;
- pcie_table->num_of_link_levels = 0;
- for (link_level = 0; link_level < NUM_LINK_LEVELS; link_level++) {
- if (!skutable->PcieGenSpeed[link_level] &&
- !skutable->PcieLaneCount[link_level] &&
- !skutable->LclkFreq[link_level])
- continue;
-
- pcie_table->pcie_gen[pcie_table->num_of_link_levels] =
- skutable->PcieGenSpeed[link_level];
- pcie_table->pcie_lane[pcie_table->num_of_link_levels] =
- skutable->PcieLaneCount[link_level];
- pcie_table->clk_freq[pcie_table->num_of_link_levels] =
- skutable->LclkFreq[link_level];
- pcie_table->num_of_link_levels++;
}
/* dcefclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.dcef_table;
+ dpm_table->clk_type = SMU_DCEFCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCN_BIT)) {
ret = smu_v13_0_set_single_dpm_table(smu,
SMU_DCEFCLK,
@@ -719,8 +686,6 @@ static int smu_v13_0_0_set_default_dpm_table(struct smu_context *smu)
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
return 0;
@@ -729,13 +694,14 @@ static int smu_v13_0_0_set_default_dpm_table(struct smu_context *smu)
static bool smu_v13_0_0_is_dpm_running(struct smu_context *smu)
{
int ret = 0;
- uint64_t feature_enabled;
+ struct smu_feature_bits feature_enabled;
ret = smu_cmn_get_enabled_mask(smu, &feature_enabled);
if (ret)
return false;
- return !!(feature_enabled & SMC_DPM_FEATURE);
+ return smu_feature_bits_test_mask(&feature_enabled,
+ smu_v13_0_0_dpm_features.bits);
}
static int smu_v13_0_0_system_features_control(struct smu_context *smu,
@@ -807,13 +773,13 @@ static int smu_v13_0_0_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->AverageGfxclkFrequencyPreDs;
break;
case METRICS_AVERAGE_FCLK:
- if (metrics->AverageUclkActivity <= SMU_13_0_0_BUSY_THRESHOLD)
+ if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_0_BUSY_THRESHOLD)
*value = metrics->AverageFclkFrequencyPostDs;
else
*value = metrics->AverageFclkFrequencyPreDs;
break;
case METRICS_AVERAGE_UCLK:
- if (metrics->AverageUclkActivity <= SMU_13_0_0_BUSY_THRESHOLD)
+ if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_0_BUSY_THRESHOLD)
*value = metrics->AverageMemclkFrequencyPostDs;
else
*value = metrics->AverageMemclkFrequencyPreDs;
@@ -834,7 +800,11 @@ static int smu_v13_0_0_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->AverageGfxActivity;
break;
case METRICS_AVERAGE_MEMACTIVITY:
- *value = metrics->AverageUclkActivity;
+ *value = smu_safe_u16_nn(metrics->AverageUclkActivity);
+ break;
+ case METRICS_AVERAGE_VCNACTIVITY:
+ *value = max(metrics->Vcn0ActivityPercentage,
+ metrics->Vcn1ActivityPercentage);
break;
case METRICS_AVERAGE_SOCKETPOWER:
*value = metrics->AverageSocketPower << 8;
@@ -892,7 +862,7 @@ static int smu_v13_0_0_get_dpm_ultimate_freq(struct smu_context *smu,
{
struct smu_13_0_dpm_context *dpm_context =
smu->smu_dpm.dpm_context;
- struct smu_13_0_dpm_table *dpm_table;
+ struct smu_dpm_table *dpm_table;
switch (clk_type) {
case SMU_MCLK:
@@ -929,9 +899,9 @@ static int smu_v13_0_0_get_dpm_ultimate_freq(struct smu_context *smu,
}
if (min)
- *min = dpm_table->min;
+ *min = SMU_DPM_TABLE_MIN(dpm_table);
if (max)
- *max = dpm_table->max;
+ *max = SMU_DPM_TABLE_MAX(dpm_table);
return 0;
}
@@ -962,6 +932,12 @@ static int smu_v13_0_0_read_sensor(struct smu_context *smu,
(uint32_t *)data);
*size = 4;
break;
+ case AMDGPU_PP_SENSOR_VCN_LOAD:
+ ret = smu_v13_0_0_get_smu_metrics_data(smu,
+ METRICS_AVERAGE_VCNACTIVITY,
+ (uint32_t *)data);
+ *size = 4;
+ break;
case AMDGPU_PP_SENSOR_GPU_AVG_POWER:
ret = smu_v13_0_0_get_smu_metrics_data(smu,
METRICS_AVERAGE_SOCKETPOWER,
@@ -1071,8 +1047,35 @@ static bool smu_v13_0_0_is_od_feature_supported(struct smu_context *smu,
PPTable_t *pptable = smu->smu_table.driver_pptable;
const OverDriveLimits_t * const overdrive_upperlimits =
&pptable->SkuTable.OverDriveLimitsBasicMax;
+ int32_t min_value, max_value;
+ bool feature_enabled;
+
+ switch (od_feature_bit) {
+ case PP_OD_FEATURE_FAN_CURVE_BIT:
+ feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit));
+ if (feature_enabled) {
+ smu_v13_0_0_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_TEMP,
+ &min_value, &max_value);
+ if (!min_value && !max_value) {
+ feature_enabled = false;
+ goto out;
+ }
+
+ smu_v13_0_0_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_PWM,
+ &min_value, &max_value);
+ if (!min_value && !max_value) {
+ feature_enabled = false;
+ goto out;
+ }
+ }
+ break;
+ default:
+ feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit));
+ break;
+ }
- return overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit);
+out:
+ return feature_enabled;
}
static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu,
@@ -1194,26 +1197,24 @@ static int smu_v13_0_0_upload_overdrive_table(struct smu_context *smu,
return ret;
}
-static int smu_v13_0_0_print_clk_levels(struct smu_context *smu,
- enum smu_clk_type clk_type,
- char *buf)
+static int smu_v13_0_0_emit_clk_levels(struct smu_context *smu,
+ enum smu_clk_type clk_type, char *buf,
+ int *offset)
{
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context;
OverDriveTableExternal_t *od_table =
(OverDriveTableExternal_t *)smu->smu_table.overdrive_table;
- struct smu_13_0_dpm_table *single_dpm_table;
- struct smu_13_0_pcie_table *pcie_table;
+ int i, curr_freq, size = *offset, start_offset = *offset;
+ struct smu_dpm_table *single_dpm_table = NULL;
+ struct smu_pcie_table *pcie_table;
uint32_t gen_speed, lane_width;
- int i, curr_freq, size = 0;
int32_t min_value, max_value;
int ret = 0;
- smu_cmn_get_sysfs_buf(&buf, &size);
-
if (amdgpu_ras_intr_triggered()) {
- size += sysfs_emit_at(buf, size, "unavailable\n");
- return size;
+ sysfs_emit_at(buf, size, "unavailable\n");
+ return -EBUSY;
}
switch (clk_type) {
@@ -1240,61 +1241,6 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu,
case SMU_DCEFCLK:
single_dpm_table = &(dpm_context->dpm_tables.dcef_table);
break;
- default:
- break;
- }
-
- switch (clk_type) {
- case SMU_SCLK:
- case SMU_MCLK:
- case SMU_SOCCLK:
- case SMU_FCLK:
- case SMU_VCLK:
- case SMU_VCLK1:
- case SMU_DCLK:
- case SMU_DCLK1:
- case SMU_DCEFCLK:
- ret = smu_v13_0_0_get_current_clk_freq_by_table(smu, clk_type, &curr_freq);
- if (ret) {
- dev_err(smu->adev->dev, "Failed to get current clock freq!");
- return ret;
- }
-
- if (single_dpm_table->is_fine_grained) {
- /*
- * For fine grained dpms, there are only two dpm levels:
- * - level 0 -> min clock freq
- * - level 1 -> max clock freq
- * And the current clock frequency can be any value between them.
- * So, if the current clock frequency is not at level 0 or level 1,
- * we will fake it as three dpm levels:
- * - level 0 -> min clock freq
- * - level 1 -> current actual clock freq
- * - level 2 -> max clock freq
- */
- if ((single_dpm_table->dpm_levels[0].value != curr_freq) &&
- (single_dpm_table->dpm_levels[1].value != curr_freq)) {
- size += sysfs_emit_at(buf, size, "0: %uMhz\n",
- single_dpm_table->dpm_levels[0].value);
- size += sysfs_emit_at(buf, size, "1: %uMhz *\n",
- curr_freq);
- size += sysfs_emit_at(buf, size, "2: %uMhz\n",
- single_dpm_table->dpm_levels[1].value);
- } else {
- size += sysfs_emit_at(buf, size, "0: %uMhz %s\n",
- single_dpm_table->dpm_levels[0].value,
- single_dpm_table->dpm_levels[0].value == curr_freq ? "*" : "");
- size += sysfs_emit_at(buf, size, "1: %uMhz %s\n",
- single_dpm_table->dpm_levels[1].value,
- single_dpm_table->dpm_levels[1].value == curr_freq ? "*" : "");
- }
- } else {
- for (i = 0; i < single_dpm_table->count; i++)
- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
- i, single_dpm_table->dpm_levels[i].value,
- single_dpm_table->dpm_levels[i].value == curr_freq ? "*" : "");
- }
- break;
case SMU_PCIE:
ret = smu_v13_0_0_get_smu_metrics_data(smu,
METRICS_PCIE_RATE,
@@ -1309,24 +1255,10 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu,
return ret;
pcie_table = &(dpm_context->dpm_tables.pcie_table);
- for (i = 0; i < pcie_table->num_of_link_levels; i++)
- size += sysfs_emit_at(buf, size, "%d: %s %s %dMhz %s\n", i,
- (pcie_table->pcie_gen[i] == 0) ? "2.5GT/s," :
- (pcie_table->pcie_gen[i] == 1) ? "5.0GT/s," :
- (pcie_table->pcie_gen[i] == 2) ? "8.0GT/s," :
- (pcie_table->pcie_gen[i] == 3) ? "16.0GT/s," : "",
- (pcie_table->pcie_lane[i] == 1) ? "x1" :
- (pcie_table->pcie_lane[i] == 2) ? "x2" :
- (pcie_table->pcie_lane[i] == 3) ? "x4" :
- (pcie_table->pcie_lane[i] == 4) ? "x8" :
- (pcie_table->pcie_lane[i] == 5) ? "x12" :
- (pcie_table->pcie_lane[i] == 6) ? "x16" : "",
- pcie_table->clk_freq[i],
- (gen_speed == DECODE_GEN_SPEED(pcie_table->pcie_gen[i])) &&
- (lane_width == DECODE_LANE_WIDTH(pcie_table->pcie_lane[i])) ?
- "*" : "");
- break;
-
+ return smu_cmn_print_pcie_levels(smu, pcie_table,
+ SMU_DPM_PCIE_GEN_IDX(gen_speed),
+ SMU_DPM_PCIE_WIDTH_IDX(lane_width),
+ buf, offset);
case SMU_OD_SCLK:
if (!smu_v13_0_0_is_od_feature_supported(smu,
PP_OD_FEATURE_GFXCLK_BIT))
@@ -1544,7 +1476,21 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu,
break;
}
- return size;
+ if (single_dpm_table) {
+ ret = smu_v13_0_0_get_current_clk_freq_by_table(smu, clk_type,
+ &curr_freq);
+ if (ret) {
+ dev_err(smu->adev->dev,
+ "Failed to get current clock freq!");
+ return ret;
+ }
+ return smu_cmn_print_dpm_clk_levels(smu, single_dpm_table,
+ curr_freq, buf, offset);
+ }
+
+ *offset += size - start_offset;
+
+ return 0;
}
@@ -1998,7 +1944,7 @@ static int smu_v13_0_0_force_clk_levels(struct smu_context *smu,
{
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context;
- struct smu_13_0_dpm_table *single_dpm_table;
+ struct smu_dpm_table *single_dpm_table;
uint32_t soft_min_level, soft_max_level;
uint32_t min_freq, max_freq;
int ret = 0;
@@ -2044,7 +1990,7 @@ static int smu_v13_0_0_force_clk_levels(struct smu_context *smu,
case SMU_VCLK1:
case SMU_DCLK:
case SMU_DCLK1:
- if (single_dpm_table->is_fine_grained) {
+ if (single_dpm_table->flags & SMU_DPM_TABLE_FINE_GRAINED) {
/* There is only 2 levels for fine grained DPM */
soft_max_level = (soft_max_level >= 1 ? 1 : 0);
soft_min_level = (soft_min_level >= 1 ? 1 : 0);
@@ -2114,11 +2060,12 @@ static int smu_v13_0_0_get_thermal_temperature_range(struct smu_context *smu,
static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu,
void **table)
{
- struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v1_3 *gpu_metrics =
- (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table;
+ (struct gpu_metrics_v1_3 *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
SmuMetricsExternal_t metrics_ext;
SmuMetrics_t *metrics = &metrics_ext.SmuMetrics;
+ uint32_t mp1_ver = amdgpu_ip_version(smu->adev, MP1_HWIP, 0);
int ret = 0;
ret = smu_cmn_get_metrics_table(smu,
@@ -2138,19 +2085,24 @@ static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu,
metrics->AvgTemperature[TEMP_VR_MEM1]);
gpu_metrics->average_gfx_activity = metrics->AverageGfxActivity;
- gpu_metrics->average_umc_activity = metrics->AverageUclkActivity;
+ gpu_metrics->average_umc_activity = smu_safe_u16_nn(metrics->AverageUclkActivity);
gpu_metrics->average_mm_activity = max(metrics->Vcn0ActivityPercentage,
metrics->Vcn1ActivityPercentage);
gpu_metrics->average_socket_power = metrics->AverageSocketPower;
- gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
+
+ if ((mp1_ver == IP_VERSION(13, 0, 0) && smu->smc_fw_version <= 0x004e1e00) ||
+ (mp1_ver == IP_VERSION(13, 0, 10) && smu->smc_fw_version <= 0x00500800))
+ gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
+ else
+ gpu_metrics->energy_accumulator = UINT_MAX;
if (metrics->AverageGfxActivity <= SMU_13_0_0_BUSY_THRESHOLD)
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs;
else
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPreDs;
- if (metrics->AverageUclkActivity <= SMU_13_0_0_BUSY_THRESHOLD)
+ if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_0_BUSY_THRESHOLD)
gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPostDs;
else
gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPreDs;
@@ -2190,6 +2142,8 @@ static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu,
*table = (void *)gpu_metrics;
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
return sizeof(struct gpu_metrics_v1_3);
}
@@ -2299,7 +2253,8 @@ static int smu_v13_0_0_restore_user_od_settings(struct smu_context *smu)
user_od_table->OverDriveTable.FeatureCtrlMask = BIT(PP_OD_FEATURE_GFXCLK_BIT) |
BIT(PP_OD_FEATURE_UCLK_BIT) |
BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT) |
- BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+ BIT(PP_OD_FEATURE_FAN_CURVE_BIT) |
+ BIT(PP_OD_FEATURE_ZERO_FAN_BIT);
res = smu_v13_0_0_upload_overdrive_table(smu, user_od_table);
user_od_table->OverDriveTable.FeatureCtrlMask = 0;
if (res == 0)
@@ -2312,18 +2267,12 @@ static int smu_v13_0_0_populate_umd_state_clk(struct smu_context *smu)
{
struct smu_13_0_dpm_context *dpm_context =
smu->smu_dpm.dpm_context;
- struct smu_13_0_dpm_table *gfx_table =
- &dpm_context->dpm_tables.gfx_table;
- struct smu_13_0_dpm_table *mem_table =
- &dpm_context->dpm_tables.uclk_table;
- struct smu_13_0_dpm_table *soc_table =
- &dpm_context->dpm_tables.soc_table;
- struct smu_13_0_dpm_table *vclk_table =
- &dpm_context->dpm_tables.vclk_table;
- struct smu_13_0_dpm_table *dclk_table =
- &dpm_context->dpm_tables.dclk_table;
- struct smu_13_0_dpm_table *fclk_table =
- &dpm_context->dpm_tables.fclk_table;
+ struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table;
+ struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table;
+ struct smu_dpm_table *soc_table = &dpm_context->dpm_tables.soc_table;
+ struct smu_dpm_table *vclk_table = &dpm_context->dpm_tables.vclk_table;
+ struct smu_dpm_table *dclk_table = &dpm_context->dpm_tables.dclk_table;
+ struct smu_dpm_table *fclk_table = &dpm_context->dpm_tables.fclk_table;
struct smu_umd_pstate_table *pstate_table =
&smu->pstate_table;
struct smu_table_context *table_context = &smu->smu_table;
@@ -2331,38 +2280,39 @@ static int smu_v13_0_0_populate_umd_state_clk(struct smu_context *smu)
DriverReportedClocks_t driver_clocks =
pptable->SkuTable.DriverReportedClocks;
- pstate_table->gfxclk_pstate.min = gfx_table->min;
+ pstate_table->gfxclk_pstate.min = SMU_DPM_TABLE_MIN(gfx_table);
if (driver_clocks.GameClockAc &&
- (driver_clocks.GameClockAc < gfx_table->max))
+ (driver_clocks.GameClockAc < SMU_DPM_TABLE_MAX(gfx_table)))
pstate_table->gfxclk_pstate.peak = driver_clocks.GameClockAc;
else
- pstate_table->gfxclk_pstate.peak = gfx_table->max;
+ pstate_table->gfxclk_pstate.peak = SMU_DPM_TABLE_MAX(gfx_table);
- pstate_table->uclk_pstate.min = mem_table->min;
- pstate_table->uclk_pstate.peak = mem_table->max;
+ pstate_table->uclk_pstate.min = SMU_DPM_TABLE_MIN(mem_table);
+ pstate_table->uclk_pstate.peak = SMU_DPM_TABLE_MAX(mem_table);
- pstate_table->socclk_pstate.min = soc_table->min;
- pstate_table->socclk_pstate.peak = soc_table->max;
+ pstate_table->socclk_pstate.min = SMU_DPM_TABLE_MIN(soc_table);
+ pstate_table->socclk_pstate.peak = SMU_DPM_TABLE_MAX(soc_table);
- pstate_table->vclk_pstate.min = vclk_table->min;
- pstate_table->vclk_pstate.peak = vclk_table->max;
+ pstate_table->vclk_pstate.min = SMU_DPM_TABLE_MIN(vclk_table);
+ pstate_table->vclk_pstate.peak = SMU_DPM_TABLE_MAX(vclk_table);
- pstate_table->dclk_pstate.min = dclk_table->min;
- pstate_table->dclk_pstate.peak = dclk_table->max;
+ pstate_table->dclk_pstate.min = SMU_DPM_TABLE_MIN(dclk_table);
+ pstate_table->dclk_pstate.peak = SMU_DPM_TABLE_MAX(dclk_table);
- pstate_table->fclk_pstate.min = fclk_table->min;
- pstate_table->fclk_pstate.peak = fclk_table->max;
+ pstate_table->fclk_pstate.min = SMU_DPM_TABLE_MIN(fclk_table);
+ pstate_table->fclk_pstate.peak = SMU_DPM_TABLE_MAX(fclk_table);
if (driver_clocks.BaseClockAc &&
- driver_clocks.BaseClockAc < gfx_table->max)
+ driver_clocks.BaseClockAc < SMU_DPM_TABLE_MAX(gfx_table))
pstate_table->gfxclk_pstate.standard = driver_clocks.BaseClockAc;
else
- pstate_table->gfxclk_pstate.standard = gfx_table->max;
- pstate_table->uclk_pstate.standard = mem_table->max;
- pstate_table->socclk_pstate.standard = soc_table->min;
- pstate_table->vclk_pstate.standard = vclk_table->min;
- pstate_table->dclk_pstate.standard = dclk_table->min;
- pstate_table->fclk_pstate.standard = fclk_table->min;
+ pstate_table->gfxclk_pstate.standard =
+ SMU_DPM_TABLE_MAX(gfx_table);
+ pstate_table->uclk_pstate.standard = SMU_DPM_TABLE_MAX(mem_table);
+ pstate_table->socclk_pstate.standard = SMU_DPM_TABLE_MIN(soc_table);
+ pstate_table->vclk_pstate.standard = SMU_DPM_TABLE_MIN(vclk_table);
+ pstate_table->dclk_pstate.standard = SMU_DPM_TABLE_MIN(dclk_table);
+ pstate_table->fclk_pstate.standard = SMU_DPM_TABLE_MIN(fclk_table);
return 0;
}
@@ -2440,28 +2390,33 @@ static int smu_v13_0_0_enable_mgpu_fan_boost(struct smu_context *smu)
}
static int smu_v13_0_0_get_power_limit(struct smu_context *smu,
- uint32_t *current_power_limit,
- uint32_t *default_power_limit,
- uint32_t *max_power_limit,
- uint32_t *min_power_limit)
+ uint32_t *current_power_limit,
+ uint32_t *default_power_limit,
+ uint32_t *max_power_limit,
+ uint32_t *min_power_limit)
{
struct smu_table_context *table_context = &smu->smu_table;
struct smu_13_0_0_powerplay_table *powerplay_table =
(struct smu_13_0_0_powerplay_table *)table_context->power_play_table;
PPTable_t *pptable = table_context->driver_pptable;
SkuTable_t *skutable = &pptable->SkuTable;
- uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0;
- uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
-
- if (smu_v13_0_get_current_power_limit(smu, &power_limit))
- power_limit = smu->adev->pm.ac_power ?
+ uint32_t pp_limit = smu->adev->pm.ac_power ?
skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] :
skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0];
+ uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
+ uint32_t min_limit = min_t(uint32_t, pp_limit, msg_limit);
+ uint32_t max_limit = max_t(uint32_t, pp_limit, msg_limit);
+ uint32_t od_percent_upper = 0, od_percent_lower = 0;
+ int ret;
+
+ if (current_power_limit) {
+ ret = smu_v13_0_get_current_power_limit(smu, current_power_limit);
+ if (ret)
+ *current_power_limit = pp_limit;
+ }
- if (current_power_limit)
- *current_power_limit = power_limit;
if (default_power_limit)
- *default_power_limit = power_limit;
+ *default_power_limit = pp_limit;
if (powerplay_table) {
if (smu->od_enabled &&
@@ -2475,15 +2430,15 @@ static int smu_v13_0_0_get_power_limit(struct smu_context *smu,
}
dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
- od_percent_upper, od_percent_lower, power_limit);
+ od_percent_upper, od_percent_lower, pp_limit);
if (max_power_limit) {
- *max_power_limit = msg_limit * (100 + od_percent_upper);
+ *max_power_limit = max_limit * (100 + od_percent_upper);
*max_power_limit /= 100;
}
if (min_power_limit) {
- *min_power_limit = power_limit * (100 - od_percent_lower);
+ *min_power_limit = min_limit * (100 - od_percent_lower);
*min_power_limit /= 100;
}
@@ -2702,21 +2657,11 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
static bool smu_v13_0_0_is_mode1_reset_supported(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- u32 smu_version;
- int ret;
/* SRIOV does not support SMU mode1 reset */
if (amdgpu_sriov_vf(adev))
return false;
- /* PMFW support is available since 78.41 */
- ret = smu_cmn_get_smc_version(smu, NULL, &smu_version);
- if (ret)
- return false;
-
- if (smu_version < 0x004e2900)
- return false;
-
return true;
}
@@ -2735,7 +2680,7 @@ static int smu_v13_0_0_i2c_xfer(struct i2c_adapter *i2c_adap,
if (!adev->pm.dpm_enabled)
return -EBUSY;
- req = kzalloc(sizeof(*req), GFP_KERNEL);
+ req = kzalloc_obj(*req);
if (!req)
return -ENOMEM;
@@ -2835,10 +2780,10 @@ static int smu_v13_0_0_i2c_control_init(struct smu_context *smu)
control->quirks = &smu_v13_0_0_i2c_control_quirks;
i2c_set_adapdata(control, smu_i2c);
- res = i2c_add_adapter(control);
+ res = devm_i2c_add_adapter(adev->dev, control);
if (res) {
DRM_ERROR("Failed to register hw i2c, err: %d\n", res);
- goto Out_err;
+ return res;
}
}
@@ -2848,27 +2793,12 @@ static int smu_v13_0_0_i2c_control_init(struct smu_context *smu)
adev->pm.fru_eeprom_i2c_bus = &adev->pm.smu_i2c[0].adapter;
return 0;
-Out_err:
- for ( ; i >= 0; i--) {
- struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i];
- struct i2c_adapter *control = &smu_i2c->adapter;
-
- i2c_del_adapter(control);
- }
- return res;
}
static void smu_v13_0_0_i2c_control_fini(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- int i;
-
- for (i = 0; i < MAX_SMU_I2C_BUSES; i++) {
- struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i];
- struct i2c_adapter *control = &smu_i2c->adapter;
- i2c_del_adapter(control);
- }
adev->pm.ras_eeprom_i2c_bus = NULL;
adev->pm.fru_eeprom_i2c_bus = NULL;
}
@@ -2876,17 +2806,19 @@ static void smu_v13_0_0_i2c_control_fini(struct smu_context *smu)
static int smu_v13_0_0_set_mp1_state(struct smu_context *smu,
enum pp_mp1_state mp1_state)
{
+ uint32_t param;
int ret;
switch (mp1_state) {
case PP_MP1_STATE_UNLOAD:
- ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_PrepareMp1ForUnload,
- 0x55, NULL);
-
- if (!ret && smu->smu_baco.state == SMU_BACO_STATE_EXIT)
- ret = smu_v13_0_disable_pmfw_state(smu);
-
+ /*
+ * NOTE: Param 0x55 comes from PMFW 80.31.0, ignored in older versions.
+ * No PMFW version check required.
+ */
+ param = amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 10) ?
+ 0x55 : 0x00;
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PrepareMp1ForUnload,
+ param, NULL);
break;
default:
/* Ignore others */
@@ -2930,8 +2862,9 @@ static int smu_v13_0_0_mode1_reset(struct smu_context *smu)
/* SMU 13_0_0 PMFW supports RAS fatal error reset from 78.77 */
smu_v13_0_0_set_mode1_reset_param(smu, 0x004e4d00, &param);
- ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_Mode1Reset, param, NULL);
+ ret = smu_cmn_send_debug_smc_msg_with_param(smu,
+ DEBUGSMC_MSG_Mode1Reset, param);
+
break;
case IP_VERSION(13, 0, 10):
@@ -2947,8 +2880,13 @@ static int smu_v13_0_0_mode1_reset(struct smu_context *smu)
break;
}
- if (!ret)
+ if (!ret) {
+ /* disable mmio access while doing mode 1 reset*/
+ smu->adev->no_hw_access = true;
+ /* ensure no_hw_access is globally visible before any MMIO */
+ smp_mb();
msleep(SMU13_MODE1_RESET_WAIT_TIME_IN_MS);
+ }
return ret;
}
@@ -2977,17 +2915,18 @@ static int smu_v13_0_0_enable_gfx_features(struct smu_context *smu)
return -EOPNOTSUPP;
}
-static void smu_v13_0_0_set_smu_mailbox_registers(struct smu_context *smu)
+static void smu_v13_0_0_init_msg_ctl(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
+ struct smu_msg_ctl *ctl = &smu->msg_ctl;
- smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82);
- smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66);
- smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90);
+ smu_v13_0_init_msg_ctl(smu, smu_v13_0_0_message_map);
- smu->debug_param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_53);
- smu->debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_75);
- smu->debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_54);
+ /* Set up debug mailbox registers */
+ ctl->config.debug_param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_53);
+ ctl->config.debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_75);
+ ctl->config.debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_54);
+ ctl->flags |= SMU_MSG_CTL_DEBUG_MAILBOX;
}
static int smu_v13_0_0_smu_send_bad_mem_page_num(struct smu_context *smu,
@@ -3140,8 +3079,91 @@ static int smu_v13_0_0_set_power_limit(struct smu_context *smu,
return 0;
}
+static int smu_v13_0_0_update_pcie_parameters(struct smu_context *smu,
+ uint8_t pcie_gen_cap,
+ uint8_t pcie_width_cap)
+{
+ struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
+ struct smu_pcie_table *pcie_table = &dpm_context->dpm_tables.pcie_table;
+ int num_of_levels;
+ uint32_t smu_pcie_arg;
+ uint32_t link_level;
+ struct smu_table_context *table_context = &smu->smu_table;
+ PPTable_t *pptable = table_context->driver_pptable;
+ SkuTable_t *skutable = &pptable->SkuTable;
+ int ret = 0;
+ int i;
+
+ pcie_table->lclk_levels = 0;
+
+ for (link_level = 0; link_level < NUM_LINK_LEVELS; link_level++) {
+ if (!skutable->PcieGenSpeed[link_level] &&
+ !skutable->PcieLaneCount[link_level] &&
+ !skutable->LclkFreq[link_level])
+ continue;
+
+ pcie_table->pcie_gen[pcie_table->lclk_levels] =
+ skutable->PcieGenSpeed[link_level];
+ pcie_table->pcie_lane[pcie_table->lclk_levels] =
+ skutable->PcieLaneCount[link_level];
+ pcie_table->lclk_freq[pcie_table->lclk_levels] =
+ skutable->LclkFreq[link_level];
+ pcie_table->lclk_levels++;
+ }
+
+ num_of_levels = pcie_table->lclk_levels;
+ if (!num_of_levels)
+ return 0;
+
+ if (!(smu->adev->pm.pp_feature & PP_PCIE_DPM_MASK)) {
+ if (pcie_table->pcie_gen[num_of_levels - 1] < pcie_gen_cap)
+ pcie_gen_cap = pcie_table->pcie_gen[num_of_levels - 1];
+
+ if (pcie_table->pcie_lane[num_of_levels - 1] < pcie_width_cap)
+ pcie_width_cap = pcie_table->pcie_lane[num_of_levels - 1];
+
+ /* Force all levels to use the same settings */
+ for (i = 0; i < num_of_levels; i++) {
+ pcie_table->pcie_gen[i] = pcie_gen_cap;
+ pcie_table->pcie_lane[i] = pcie_width_cap;
+ smu_pcie_arg = i << 16;
+ smu_pcie_arg |= pcie_table->pcie_gen[i] << 8;
+ smu_pcie_arg |= pcie_table->pcie_lane[i];
+
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_OverridePcieParameters,
+ smu_pcie_arg,
+ NULL);
+ if (ret)
+ break;
+ }
+ } else {
+ for (i = 0; i < num_of_levels; i++) {
+ if (pcie_table->pcie_gen[i] > pcie_gen_cap ||
+ pcie_table->pcie_lane[i] > pcie_width_cap) {
+ pcie_table->pcie_gen[i] = pcie_table->pcie_gen[i] > pcie_gen_cap ?
+ pcie_gen_cap : pcie_table->pcie_gen[i];
+ pcie_table->pcie_lane[i] = pcie_table->pcie_lane[i] > pcie_width_cap ?
+ pcie_width_cap : pcie_table->pcie_lane[i];
+ smu_pcie_arg = i << 16;
+ smu_pcie_arg |= pcie_table->pcie_gen[i] << 8;
+ smu_pcie_arg |= pcie_table->pcie_lane[i];
+
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_OverridePcieParameters,
+ smu_pcie_arg,
+ NULL);
+ if (ret)
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
- .get_allowed_feature_mask = smu_v13_0_0_get_allowed_feature_mask,
+ .init_allowed_features = smu_v13_0_0_init_allowed_features,
.set_default_dpm_table = smu_v13_0_0_set_default_dpm_table,
.i2c_init = smu_v13_0_0_i2c_control_init,
.i2c_fini = smu_v13_0_0_i2c_control_fini,
@@ -3155,7 +3177,7 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
.fini_power = smu_v13_0_fini_power,
.check_fw_status = smu_v13_0_check_fw_status,
.setup_pptable = smu_v13_0_0_setup_pptable,
- .check_fw_version = smu_v13_0_check_fw_version,
+ .check_fw_version = smu_cmn_check_fw_version,
.write_pptable = smu_cmn_write_pptable,
.set_driver_table_location = smu_v13_0_set_driver_table_location,
.system_features_control = smu_v13_0_0_system_features_control,
@@ -3167,9 +3189,9 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
.get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values,
.read_sensor = smu_v13_0_0_read_sensor,
.feature_is_enabled = smu_cmn_feature_is_enabled,
- .print_clk_levels = smu_v13_0_0_print_clk_levels,
+ .emit_clk_levels = smu_v13_0_0_emit_clk_levels,
.force_clk_levels = smu_v13_0_0_force_clk_levels,
- .update_pcie_parameters = smu_v13_0_update_pcie_parameters,
+ .update_pcie_parameters = smu_v13_0_0_update_pcie_parameters,
.get_thermal_temperature_range = smu_v13_0_0_get_thermal_temperature_range,
.register_irq_handler = smu_v13_0_register_irq_handler,
.enable_thermal_alert = smu_v13_0_enable_thermal_alert,
@@ -3226,12 +3248,16 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
void smu_v13_0_0_set_ppt_funcs(struct smu_context *smu)
{
smu->ppt_funcs = &smu_v13_0_0_ppt_funcs;
- smu->message_map = smu_v13_0_0_message_map;
smu->clock_map = smu_v13_0_0_clk_map;
smu->feature_map = smu_v13_0_0_feature_mask_map;
smu->table_map = smu_v13_0_0_table_map;
smu->pwr_src_map = smu_v13_0_0_pwr_src_map;
smu->workload_map = smu_v13_0_0_workload_map;
smu->smc_driver_if_version = SMU13_0_0_DRIVER_IF_VERSION;
- smu_v13_0_0_set_smu_mailbox_registers(smu);
+ smu_v13_0_0_init_msg_ctl(smu);
+
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) ==
+ IP_VERSION(13, 0, 10) &&
+ !amdgpu_device_has_display_hardware(smu->adev))
+ smu->adev->pm.pp_feature &= ~PP_GFXOFF_MASK;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c
new file mode 100644
index 000000000000..fe929bd89058
--- /dev/null
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c
@@ -0,0 +1,1155 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#define SWSMU_CODE_LAYER_L2
+
+#include <linux/firmware.h>
+#include "amdgpu.h"
+#include "amdgpu_smu.h"
+#include "smu_v13_0_12_pmfw.h"
+#include "smu_v13_0_6_ppt.h"
+#include "smu_v13_0_12_ppsmc.h"
+#include "smu_v13_0.h"
+#include "amdgpu_xgmi.h"
+#include "amdgpu_fru_eeprom.h"
+#include <linux/pci.h>
+#include "smu_cmn.h"
+#include "amdgpu_ras.h"
+
+#undef MP1_Public
+#undef smnMP1_FIRMWARE_FLAGS
+
+/*
+ * DO NOT use these for err/warn/info/debug messages.
+ * Use dev_err, dev_warn, dev_info and dev_dbg instead.
+ * They are more MGPU friendly.
+ */
+#undef pr_err
+#undef pr_warn
+#undef pr_info
+#undef pr_debug
+
+#define hbm_stack_mask_valid(umc_mask) \
+ (((umc_mask) & 0x3) == 0x3)
+
+#define for_each_hbm_stack(stack_idx, umc_mask) \
+ for ((stack_idx) = 0; (umc_mask); \
+ (umc_mask) >>= 2, (stack_idx)++) \
+
+#define SMU_13_0_12_FEA_MAP(smu_feature, smu_13_0_12_feature) \
+ [smu_feature] = { 1, (smu_13_0_12_feature) }
+
+static const struct smu_feature_bits smu_v13_0_12_dpm_features = {
+ .bits = {
+ SMU_FEATURE_BIT_INIT(FEATURE_DATA_CALCULATION),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK)
+ }
+};
+
+#define NUM_JPEG_RINGS_FW 10
+#define NUM_JPEG_RINGS_GPU_METRICS(gpu_metrics) \
+ (ARRAY_SIZE(gpu_metrics->jpeg_busy) / 4)
+
+const struct cmn2asic_mapping smu_v13_0_12_feature_mask_map[SMU_FEATURE_COUNT] = {
+ SMU_13_0_12_FEA_MAP(SMU_FEATURE_DATA_CALCULATIONS_BIT, FEATURE_DATA_CALCULATION),
+ SMU_13_0_12_FEA_MAP(SMU_FEATURE_DPM_GFXCLK_BIT, FEATURE_DPM_GFXCLK),
+ SMU_13_0_12_FEA_MAP(SMU_FEATURE_DPM_FCLK_BIT, FEATURE_DPM_FCLK),
+ SMU_13_0_12_FEA_MAP(SMU_FEATURE_DS_GFXCLK_BIT, FEATURE_DS_GFXCLK),
+ SMU_13_0_12_FEA_MAP(SMU_FEATURE_DS_SOCCLK_BIT, FEATURE_DS_SOCCLK),
+ SMU_13_0_12_FEA_MAP(SMU_FEATURE_DS_LCLK_BIT, FEATURE_DS_LCLK),
+ SMU_13_0_12_FEA_MAP(SMU_FEATURE_DS_FCLK_BIT, FEATURE_DS_FCLK),
+ SMU_13_0_12_FEA_MAP(SMU_FEATURE_PPT_BIT, FEATURE_PPT),
+ SMU_13_0_12_FEA_MAP(SMU_FEATURE_TDC_BIT, FEATURE_TDC),
+ SMU_13_0_12_FEA_MAP(SMU_FEATURE_APCC_DFLL_BIT, FEATURE_APCC_DFLL),
+ SMU_13_0_12_FEA_MAP(SMU_FEATURE_MP1_CG_BIT, FEATURE_SMU_CG),
+ SMU_13_0_12_FEA_MAP(SMU_FEATURE_FW_CTF_BIT, FEATURE_FW_CTF),
+ SMU_13_0_12_FEA_MAP(SMU_FEATURE_THERMAL_BIT, FEATURE_THERMAL),
+ SMU_13_0_12_FEA_MAP(SMU_FEATURE_SOC_PCC_BIT, FEATURE_SOC_PCC),
+ SMU_13_0_12_FEA_MAP(SMU_FEATURE_XGMI_PER_LINK_PWR_DWN_BIT, FEATURE_XGMI_PER_LINK_PWR_DOWN),
+ SMU_13_0_12_FEA_MAP(SMU_FEATURE_DS_VCN_BIT, FEATURE_DS_VCN),
+ SMU_13_0_12_FEA_MAP(SMU_FEATURE_DS_MP1CLK_BIT, FEATURE_DS_MP1CLK),
+ SMU_13_0_12_FEA_MAP(SMU_FEATURE_DS_MPIOCLK_BIT, FEATURE_DS_MPIOCLK),
+ SMU_13_0_12_FEA_MAP(SMU_FEATURE_DS_MP0CLK_BIT, FEATURE_DS_MP0CLK),
+ SMU_13_0_12_FEA_MAP(SMU_FEATURE_PIT_BIT, FEATURE_PIT),
+ SMU_13_0_12_FEA_MAP(SMU_FEATURE_HROM_EN_BIT, FEATURE_HROM_EN),
+};
+
+const struct cmn2asic_msg_mapping smu_v13_0_12_message_map[SMU_MSG_MAX_COUNT] = {
+ MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 0),
+ MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1),
+ MSG_MAP(GetDriverIfVersion, PPSMC_MSG_GetDriverIfVersion, 1),
+ MSG_MAP(EnableAllSmuFeatures, PPSMC_MSG_EnableAllSmuFeatures, 0),
+ MSG_MAP(DisableAllSmuFeatures, PPSMC_MSG_DisableAllSmuFeatures, 0),
+ MSG_MAP(RequestI2cTransaction, PPSMC_MSG_RequestI2cTransaction, 0),
+ MSG_MAP(GetMetricsTable, PPSMC_MSG_GetMetricsTable, 1),
+ MSG_MAP(GetMetricsVersion, PPSMC_MSG_GetMetricsVersion, 1),
+ MSG_MAP(GetEnabledSmuFeaturesHigh, PPSMC_MSG_GetEnabledSmuFeaturesHigh, 1),
+ MSG_MAP(GetEnabledSmuFeaturesLow, PPSMC_MSG_GetEnabledSmuFeaturesLow, 1),
+ MSG_MAP(SetDriverDramAddrHigh, PPSMC_MSG_SetDriverDramAddrHigh, 1),
+ MSG_MAP(SetDriverDramAddrLow, PPSMC_MSG_SetDriverDramAddrLow, 1),
+ MSG_MAP(SetToolsDramAddrHigh, PPSMC_MSG_SetToolsDramAddrHigh, 0),
+ MSG_MAP(SetToolsDramAddrLow, PPSMC_MSG_SetToolsDramAddrLow, 0),
+ MSG_MAP(SetSoftMinByFreq, PPSMC_MSG_SetSoftMinByFreq, 0),
+ MSG_MAP(SetSoftMaxByFreq, PPSMC_MSG_SetSoftMaxByFreq, 1),
+ MSG_MAP(GetMinDpmFreq, PPSMC_MSG_GetMinDpmFreq, 1),
+ MSG_MAP(GetMaxDpmFreq, PPSMC_MSG_GetMaxDpmFreq, 1),
+ MSG_MAP(GetDpmFreqByIndex, PPSMC_MSG_GetDpmFreqByIndex, 1),
+ MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit, 0),
+ MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit, 1),
+ MSG_MAP(GfxDeviceDriverReset, PPSMC_MSG_GfxDriverReset, SMU_MSG_RAS_PRI | SMU_MSG_NO_PRECHECK),
+ MSG_MAP(DramLogSetDramAddrHigh, PPSMC_MSG_DramLogSetDramAddrHigh, 0),
+ MSG_MAP(DramLogSetDramAddrLow, PPSMC_MSG_DramLogSetDramAddrLow, 0),
+ MSG_MAP(DramLogSetDramSize, PPSMC_MSG_DramLogSetDramSize, 0),
+ MSG_MAP(GetDebugData, PPSMC_MSG_GetDebugData, 0),
+ MSG_MAP(SetNumBadHbmPagesRetired, PPSMC_MSG_SetNumBadHbmPagesRetired, 0),
+ MSG_MAP(DFCstateControl, PPSMC_MSG_DFCstateControl, 0),
+ MSG_MAP(GetGmiPwrDnHyst, PPSMC_MSG_GetGmiPwrDnHyst, 0),
+ MSG_MAP(SetGmiPwrDnHyst, PPSMC_MSG_SetGmiPwrDnHyst, 0),
+ MSG_MAP(GmiPwrDnControl, PPSMC_MSG_GmiPwrDnControl, 0),
+ MSG_MAP(EnterGfxoff, PPSMC_MSG_EnterGfxoff, 0),
+ MSG_MAP(ExitGfxoff, PPSMC_MSG_ExitGfxoff, 0),
+ MSG_MAP(EnableDeterminism, PPSMC_MSG_EnableDeterminism, 0),
+ MSG_MAP(DisableDeterminism, PPSMC_MSG_DisableDeterminism, 0),
+ MSG_MAP(GfxDriverResetRecovery, PPSMC_MSG_GfxDriverResetRecovery, 0),
+ MSG_MAP(GetMinGfxclkFrequency, PPSMC_MSG_GetMinGfxDpmFreq, 1),
+ MSG_MAP(GetMaxGfxclkFrequency, PPSMC_MSG_GetMaxGfxDpmFreq, 1),
+ MSG_MAP(SetSoftMinGfxclk, PPSMC_MSG_SetSoftMinGfxClk, 1),
+ MSG_MAP(SetSoftMaxGfxClk, PPSMC_MSG_SetSoftMaxGfxClk, 1),
+ MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareForDriverUnload, 0),
+ MSG_MAP(GetCTFLimit, PPSMC_MSG_GetCTFLimit, 0),
+ MSG_MAP(GetThermalLimit, PPSMC_MSG_ReadThrottlerLimit, 0),
+ MSG_MAP(ClearMcaOnRead, PPSMC_MSG_ClearMcaOnRead, 0),
+ MSG_MAP(QueryValidMcaCount, PPSMC_MSG_QueryValidMcaCount, SMU_MSG_RAS_PRI),
+ MSG_MAP(QueryValidMcaCeCount, PPSMC_MSG_QueryValidMcaCeCount, SMU_MSG_RAS_PRI),
+ MSG_MAP(McaBankDumpDW, PPSMC_MSG_McaBankDumpDW, SMU_MSG_RAS_PRI),
+ MSG_MAP(McaBankCeDumpDW, PPSMC_MSG_McaBankCeDumpDW, SMU_MSG_RAS_PRI),
+ MSG_MAP(SelectPLPDMode, PPSMC_MSG_SelectPLPDMode, 0),
+ MSG_MAP(RmaDueToBadPageThreshold, PPSMC_MSG_RmaDueToBadPageThreshold, 0),
+ MSG_MAP(SetThrottlingPolicy, PPSMC_MSG_SetThrottlingPolicy, 0),
+ MSG_MAP(ResetSDMA, PPSMC_MSG_ResetSDMA, 0),
+ MSG_MAP(ResetVCN, PPSMC_MSG_ResetVCN, 0),
+ MSG_MAP(GetStaticMetricsTable, PPSMC_MSG_GetStaticMetricsTable, 1),
+ MSG_MAP(GetSystemMetricsTable, PPSMC_MSG_GetSystemMetricsTable, 1),
+ MSG_MAP(GetRASTableVersion, PPSMC_MSG_GetRasTableVersion, 0),
+ MSG_MAP(GetBadPageCount, PPSMC_MSG_GetBadPageCount, 0),
+ MSG_MAP(GetBadPageMcaAddr, PPSMC_MSG_GetBadPageMcaAddress, 0),
+ MSG_MAP(SetTimestamp, PPSMC_MSG_SetTimestamp, 0),
+ MSG_MAP(GetTimestamp, PPSMC_MSG_GetTimestamp, 0),
+ MSG_MAP(GetBadPageIpid, PPSMC_MSG_GetBadPageIpIdLoHi, 0),
+ MSG_MAP(EraseRasTable, PPSMC_MSG_EraseRasTable, 0),
+ MSG_MAP(SetFastPptLimit, PPSMC_MSG_SetFastPptLimit, 1),
+ MSG_MAP(GetFastPptLimit, PPSMC_MSG_GetFastPptLimit, 1),
+};
+
+int smu_v13_0_12_tables_init(struct smu_context *smu)
+{
+ struct amdgpu_baseboard_temp_metrics_v1_0 *baseboard_temp_metrics;
+ struct amdgpu_gpuboard_temp_metrics_v1_0 *gpuboard_temp_metrics;
+ int ret;
+
+ ret = smu_table_cache_init(smu, SMU_TABLE_PMFW_SYSTEM_METRICS,
+ smu_v13_0_12_get_system_metrics_size(), 5);
+
+ if (ret)
+ return ret;
+
+ ret = smu_driver_table_init(smu,
+ SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS,
+ sizeof(*baseboard_temp_metrics), 50);
+ if (ret)
+ return ret;
+ /* Initialize base board temperature metrics */
+ baseboard_temp_metrics = (struct amdgpu_baseboard_temp_metrics_v1_0 *)
+ smu_driver_table_ptr(smu,
+ SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS);
+ smu_cmn_init_baseboard_temp_metrics(baseboard_temp_metrics, 1, 0);
+ /* Initialize GPU board temperature metrics */
+ ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS,
+ sizeof(*gpuboard_temp_metrics), 50);
+ if (ret) {
+ smu_table_cache_fini(smu, SMU_TABLE_PMFW_SYSTEM_METRICS);
+ smu_driver_table_fini(smu,
+ SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS);
+ return ret;
+ }
+ gpuboard_temp_metrics = (struct amdgpu_gpuboard_temp_metrics_v1_0 *)
+ smu_driver_table_ptr(smu,
+ SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS);
+ smu_cmn_init_gpuboard_temp_metrics(gpuboard_temp_metrics, 1, 0);
+
+ return 0;
+}
+
+void smu_v13_0_12_tables_fini(struct smu_context *smu)
+{
+ smu_driver_table_fini(smu, SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS);
+ smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS);
+ smu_table_cache_fini(smu, SMU_TABLE_PMFW_SYSTEM_METRICS);
+}
+
+static int smu_v13_0_12_get_enabled_mask(struct smu_context *smu,
+ struct smu_feature_bits *feature_mask)
+{
+ int ret;
+
+ ret = smu_cmn_get_enabled_mask(smu, feature_mask);
+
+ if (ret == -EIO) {
+ smu_feature_bits_clearall(feature_mask);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int smu_v13_0_12_fru_get_product_info(struct smu_context *smu,
+ StaticMetricsTable_t *static_metrics)
+{
+ struct amdgpu_fru_info *fru_info;
+ struct amdgpu_device *adev = smu->adev;
+
+ if (!adev->fru_info) {
+ adev->fru_info = kzalloc_obj(*adev->fru_info);
+ if (!adev->fru_info)
+ return -ENOMEM;
+ }
+
+ fru_info = adev->fru_info;
+ strscpy(fru_info->product_number, static_metrics->ProductInfo.ModelNumber,
+ sizeof(fru_info->product_number));
+ strscpy(fru_info->product_name, static_metrics->ProductInfo.Name,
+ sizeof(fru_info->product_name));
+ strscpy(fru_info->serial, static_metrics->ProductInfo.Serial,
+ sizeof(fru_info->serial));
+ strscpy(fru_info->manufacturer_name, static_metrics->ProductInfo.ManufacturerName,
+ sizeof(fru_info->manufacturer_name));
+ strscpy(fru_info->fru_id, static_metrics->ProductInfo.FruId,
+ sizeof(fru_info->fru_id));
+
+ return 0;
+}
+
+int smu_v13_0_12_get_max_metrics_size(void)
+{
+ return max(sizeof(StaticMetricsTable_t), sizeof(MetricsTable_t));
+}
+
+size_t smu_v13_0_12_get_system_metrics_size(void)
+{
+ return sizeof(SystemMetricsTable_t);
+}
+
+static void smu_v13_0_12_init_xgmi_data(struct smu_context *smu,
+ StaticMetricsTable_t *static_metrics)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ uint16_t max_speed;
+ uint8_t max_width;
+ int ret;
+
+ if (smu_table->tables[SMU_TABLE_SMU_METRICS].version >= 0x13) {
+ max_width = (uint8_t)SMUQ10_ROUND(static_metrics->MaxXgmiWidth);
+ max_speed =
+ (uint16_t)SMUQ10_ROUND(static_metrics->MaxXgmiBitrate);
+ ret = 0;
+ } else {
+ MetricsTable_t *metrics = (MetricsTable_t *)smu_table->metrics_table;
+
+ ret = smu_v13_0_6_get_metrics_table(smu, NULL, true);
+ if (!ret) {
+ max_width = (uint8_t)metrics->XgmiWidth;
+ max_speed = (uint16_t)metrics->XgmiBitrate;
+ }
+ }
+ if (!ret)
+ amgpu_xgmi_set_max_speed_width(smu->adev, max_speed, max_width);
+}
+
+int smu_v13_0_12_setup_driver_pptable(struct smu_context *smu)
+{
+ struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
+ struct smu_table_context *smu_table = &smu->smu_table;
+ StaticMetricsTable_t *static_metrics = (StaticMetricsTable_t *)smu_table->metrics_table;
+ struct PPTable_t *pptable =
+ (struct PPTable_t *)smu_table->driver_pptable;
+ uint32_t table_version;
+ int ret, i, n;
+
+ if (!pptable->Init) {
+ ret = smu_v13_0_6_get_static_metrics_table(smu);
+ if (ret)
+ return ret;
+
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetMetricsVersion,
+ &table_version);
+ if (ret)
+ return ret;
+ smu_table->tables[SMU_TABLE_SMU_METRICS].version =
+ table_version;
+
+ pptable->MaxSocketPowerLimit =
+ SMUQ10_ROUND(static_metrics->MaxSocketPowerLimit);
+ pptable->MaxGfxclkFrequency =
+ SMUQ10_ROUND(static_metrics->MaxGfxclkFrequency);
+ pptable->MinGfxclkFrequency =
+ SMUQ10_ROUND(static_metrics->MinGfxclkFrequency);
+
+ for (i = 0; i < 4; ++i) {
+ pptable->FclkFrequencyTable[i] =
+ SMUQ10_ROUND(static_metrics->FclkFrequencyTable[i]);
+ pptable->UclkFrequencyTable[i] =
+ SMUQ10_ROUND(static_metrics->UclkFrequencyTable[i]);
+ pptable->SocclkFrequencyTable[i] =
+ SMUQ10_ROUND(static_metrics->SocclkFrequencyTable[i]);
+ pptable->VclkFrequencyTable[i] =
+ SMUQ10_ROUND(static_metrics->VclkFrequencyTable[i]);
+ pptable->DclkFrequencyTable[i] =
+ SMUQ10_ROUND(static_metrics->DclkFrequencyTable[i]);
+ pptable->LclkFrequencyTable[i] =
+ SMUQ10_ROUND(static_metrics->LclkFrequencyTable[i]);
+ }
+
+ /* use AID0 serial number by default */
+ pptable->PublicSerialNumber_AID =
+ static_metrics->PublicSerialNumber_AID[0];
+
+ amdgpu_device_set_uid(smu->adev->uid_info, AMDGPU_UID_TYPE_SOC,
+ 0, pptable->PublicSerialNumber_AID);
+ n = ARRAY_SIZE(static_metrics->PublicSerialNumber_AID);
+ for (i = 0; i < n; i++) {
+ amdgpu_device_set_uid(
+ smu->adev->uid_info, AMDGPU_UID_TYPE_AID, i,
+ static_metrics->PublicSerialNumber_AID[i]);
+ }
+ n = ARRAY_SIZE(static_metrics->PublicSerialNumber_XCD);
+ for (i = 0; i < n; i++) {
+ amdgpu_device_set_uid(
+ smu->adev->uid_info, AMDGPU_UID_TYPE_XCD, i,
+ static_metrics->PublicSerialNumber_XCD[i]);
+ }
+
+ ret = smu_v13_0_12_fru_get_product_info(smu, static_metrics);
+ if (ret)
+ return ret;
+
+ if (smu_v13_0_6_cap_supported(smu, SMU_CAP(BOARD_VOLTAGE))) {
+ if (!static_metrics->InputTelemetryVoltageInmV) {
+ dev_warn(smu->adev->dev, "Invalid board voltage %d\n",
+ static_metrics->InputTelemetryVoltageInmV);
+ }
+ dpm_context->board_volt = static_metrics->InputTelemetryVoltageInmV;
+ }
+ if (smu_v13_0_6_cap_supported(smu, SMU_CAP(PLDM_VERSION)) &&
+ static_metrics->pldmVersion[0] != 0xFFFFFFFF)
+ smu->adev->firmware.pldm_version =
+ static_metrics->pldmVersion[0];
+ if (smu_v13_0_6_cap_supported(smu, SMU_CAP(NPM_METRICS)))
+ pptable->MaxNodePowerLimit =
+ SMUQ10_ROUND(static_metrics->MaxNodePowerLimit);
+ if (smu_v13_0_6_cap_supported(smu, SMU_CAP(FAST_PPT)) &&
+ static_metrics->PPT1Max) {
+ pptable->PPT1Max = static_metrics->PPT1Max;
+ pptable->PPT1Min = static_metrics->PPT1Min;
+ pptable->PPT1Default = static_metrics->PPT1Default;
+ }
+ smu_v13_0_12_init_xgmi_data(smu, static_metrics);
+ pptable->Init = true;
+ }
+
+ return 0;
+}
+
+bool smu_v13_0_12_is_dpm_running(struct smu_context *smu)
+{
+ int ret;
+ struct smu_feature_bits feature_enabled;
+
+ ret = smu_v13_0_12_get_enabled_mask(smu, &feature_enabled);
+
+ if (ret)
+ return false;
+
+ return smu_feature_bits_test_mask(&feature_enabled,
+ smu_v13_0_12_dpm_features.bits);
+}
+
+int smu_v13_0_12_get_smu_metrics_data(struct smu_context *smu,
+ MetricsMember_t member,
+ uint32_t *value)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ MetricsTable_t *metrics = (MetricsTable_t *)smu_table->metrics_table;
+ struct amdgpu_device *adev = smu->adev;
+ int xcc_id;
+
+ /* For clocks with multiple instances, only report the first one */
+ switch (member) {
+ case METRICS_CURR_GFXCLK:
+ case METRICS_AVERAGE_GFXCLK:
+ xcc_id = GET_INST(GC, 0);
+ *value = SMUQ10_ROUND(metrics->GfxclkFrequency[xcc_id]);
+ break;
+ case METRICS_CURR_SOCCLK:
+ case METRICS_AVERAGE_SOCCLK:
+ *value = SMUQ10_ROUND(metrics->SocclkFrequency[0]);
+ break;
+ case METRICS_CURR_UCLK:
+ case METRICS_AVERAGE_UCLK:
+ *value = SMUQ10_ROUND(metrics->UclkFrequency);
+ break;
+ case METRICS_CURR_VCLK:
+ *value = SMUQ10_ROUND(metrics->VclkFrequency[0]);
+ break;
+ case METRICS_CURR_DCLK:
+ *value = SMUQ10_ROUND(metrics->DclkFrequency[0]);
+ break;
+ case METRICS_CURR_FCLK:
+ *value = SMUQ10_ROUND(metrics->FclkFrequency);
+ break;
+ case METRICS_AVERAGE_GFXACTIVITY:
+ *value = SMUQ10_ROUND(metrics->SocketGfxBusy);
+ break;
+ case METRICS_AVERAGE_MEMACTIVITY:
+ *value = SMUQ10_ROUND(metrics->DramBandwidthUtilization);
+ break;
+ case METRICS_CURR_SOCKETPOWER:
+ *value = SMUQ10_ROUND(metrics->SocketPower) << 8;
+ break;
+ case METRICS_TEMPERATURE_HOTSPOT:
+ *value = SMUQ10_ROUND(metrics->MaxSocketTemperature) *
+ SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+ break;
+ case METRICS_TEMPERATURE_MEM:
+ *value = SMUQ10_ROUND(metrics->MaxHbmTemperature) *
+ SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+ break;
+ /* This is the max of all VRs and not just SOC VR.
+ * No need to define another data type for the same.
+ */
+ case METRICS_TEMPERATURE_VRSOC:
+ *value = SMUQ10_ROUND(metrics->MaxVrTemperature) *
+ SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+ break;
+ default:
+ *value = UINT_MAX;
+ break;
+ }
+
+ return 0;
+}
+
+static int smu_v13_0_12_get_system_metrics_table(struct smu_context *smu)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_table *table = &smu_table->driver_table;
+ struct smu_table *tables = smu_table->tables;
+ struct smu_table *sys_table;
+ int ret;
+
+ sys_table = &tables[SMU_TABLE_PMFW_SYSTEM_METRICS];
+ if (smu_table_cache_is_valid(sys_table))
+ return 0;
+
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetSystemMetricsTable, NULL);
+ if (ret) {
+ dev_info(smu->adev->dev,
+ "Failed to export system metrics table!\n");
+ return ret;
+ }
+
+ amdgpu_hdp_invalidate(smu->adev, NULL);
+
+ ret = smu_cmn_vram_cpy(smu, sys_table->cache.buffer,
+ table->cpu_addr,
+ smu_v13_0_12_get_system_metrics_size());
+ if (ret)
+ return ret;
+
+ smu_table_cache_update_time(sys_table, jiffies);
+
+ return 0;
+}
+
+static enum amdgpu_node_temp smu_v13_0_12_get_node_sensor_type(NODE_TEMP_e type)
+{
+ switch (type) {
+ case NODE_TEMP_RETIMER:
+ return AMDGPU_RETIMER_X_TEMP;
+ case NODE_TEMP_IBC_TEMP:
+ return AMDGPU_OAM_X_IBC_TEMP;
+ case NODE_TEMP_IBC_2_TEMP:
+ return AMDGPU_OAM_X_IBC_2_TEMP;
+ case NODE_TEMP_VDD18_VR_TEMP:
+ return AMDGPU_OAM_X_VDD18_VR_TEMP;
+ case NODE_TEMP_04_HBM_B_VR_TEMP:
+ return AMDGPU_OAM_X_04_HBM_B_VR_TEMP;
+ case NODE_TEMP_04_HBM_D_VR_TEMP:
+ return AMDGPU_OAM_X_04_HBM_D_VR_TEMP;
+ default:
+ return -EINVAL;
+ }
+}
+
+static enum amdgpu_vr_temp smu_v13_0_12_get_vr_sensor_type(SVI_TEMP_e type)
+{
+ switch (type) {
+ case SVI_VDDCR_VDD0_TEMP:
+ return AMDGPU_VDDCR_VDD0_TEMP;
+ case SVI_VDDCR_VDD1_TEMP:
+ return AMDGPU_VDDCR_VDD1_TEMP;
+ case SVI_VDDCR_VDD2_TEMP:
+ return AMDGPU_VDDCR_VDD2_TEMP;
+ case SVI_VDDCR_VDD3_TEMP:
+ return AMDGPU_VDDCR_VDD3_TEMP;
+ case SVI_VDDCR_SOC_A_TEMP:
+ return AMDGPU_VDDCR_SOC_A_TEMP;
+ case SVI_VDDCR_SOC_C_TEMP:
+ return AMDGPU_VDDCR_SOC_C_TEMP;
+ case SVI_VDDCR_SOCIO_A_TEMP:
+ return AMDGPU_VDDCR_SOCIO_A_TEMP;
+ case SVI_VDDCR_SOCIO_C_TEMP:
+ return AMDGPU_VDDCR_SOCIO_C_TEMP;
+ case SVI_VDD_085_HBM_TEMP:
+ return AMDGPU_VDD_085_HBM_TEMP;
+ case SVI_VDDCR_11_HBM_B_TEMP:
+ return AMDGPU_VDDCR_11_HBM_B_TEMP;
+ case SVI_VDDCR_11_HBM_D_TEMP:
+ return AMDGPU_VDDCR_11_HBM_D_TEMP;
+ case SVI_VDD_USR_TEMP:
+ return AMDGPU_VDD_USR_TEMP;
+ case SVI_VDDIO_11_E32_TEMP:
+ return AMDGPU_VDDIO_11_E32_TEMP;
+ default:
+ return -EINVAL;
+ }
+}
+
+static enum amdgpu_system_temp smu_v13_0_12_get_system_sensor_type(SYSTEM_TEMP_e type)
+{
+ switch (type) {
+ case SYSTEM_TEMP_UBB_FPGA:
+ return AMDGPU_UBB_FPGA_TEMP;
+ case SYSTEM_TEMP_UBB_FRONT:
+ return AMDGPU_UBB_FRONT_TEMP;
+ case SYSTEM_TEMP_UBB_BACK:
+ return AMDGPU_UBB_BACK_TEMP;
+ case SYSTEM_TEMP_UBB_OAM7:
+ return AMDGPU_UBB_OAM7_TEMP;
+ case SYSTEM_TEMP_UBB_IBC:
+ return AMDGPU_UBB_IBC_TEMP;
+ case SYSTEM_TEMP_UBB_UFPGA:
+ return AMDGPU_UBB_UFPGA_TEMP;
+ case SYSTEM_TEMP_UBB_OAM1:
+ return AMDGPU_UBB_OAM1_TEMP;
+ case SYSTEM_TEMP_OAM_0_1_HSC:
+ return AMDGPU_OAM_0_1_HSC_TEMP;
+ case SYSTEM_TEMP_OAM_2_3_HSC:
+ return AMDGPU_OAM_2_3_HSC_TEMP;
+ case SYSTEM_TEMP_OAM_4_5_HSC:
+ return AMDGPU_OAM_4_5_HSC_TEMP;
+ case SYSTEM_TEMP_OAM_6_7_HSC:
+ return AMDGPU_OAM_6_7_HSC_TEMP;
+ case SYSTEM_TEMP_UBB_FPGA_0V72_VR:
+ return AMDGPU_UBB_FPGA_0V72_VR_TEMP;
+ case SYSTEM_TEMP_UBB_FPGA_3V3_VR:
+ return AMDGPU_UBB_FPGA_3V3_VR_TEMP;
+ case SYSTEM_TEMP_RETIMER_0_1_2_3_1V2_VR:
+ return AMDGPU_RETIMER_0_1_2_3_1V2_VR_TEMP;
+ case SYSTEM_TEMP_RETIMER_4_5_6_7_1V2_VR:
+ return AMDGPU_RETIMER_4_5_6_7_1V2_VR_TEMP;
+ case SYSTEM_TEMP_RETIMER_0_1_0V9_VR:
+ return AMDGPU_RETIMER_0_1_0V9_VR_TEMP;
+ case SYSTEM_TEMP_RETIMER_4_5_0V9_VR:
+ return AMDGPU_RETIMER_4_5_0V9_VR_TEMP;
+ case SYSTEM_TEMP_RETIMER_2_3_0V9_VR:
+ return AMDGPU_RETIMER_2_3_0V9_VR_TEMP;
+ case SYSTEM_TEMP_RETIMER_6_7_0V9_VR:
+ return AMDGPU_RETIMER_6_7_0V9_VR_TEMP;
+ case SYSTEM_TEMP_OAM_0_1_2_3_3V3_VR:
+ return AMDGPU_OAM_0_1_2_3_3V3_VR_TEMP;
+ case SYSTEM_TEMP_OAM_4_5_6_7_3V3_VR:
+ return AMDGPU_OAM_4_5_6_7_3V3_VR_TEMP;
+ case SYSTEM_TEMP_IBC_HSC:
+ return AMDGPU_IBC_HSC_TEMP;
+ case SYSTEM_TEMP_IBC:
+ return AMDGPU_IBC_TEMP;
+ default:
+ return -EINVAL;
+ }
+}
+
+static bool smu_v13_0_12_is_temp_metrics_supported(struct smu_context *smu,
+ enum smu_temp_metric_type type)
+{
+ switch (type) {
+ case SMU_TEMP_METRIC_BASEBOARD:
+ if (smu->adev->gmc.xgmi.physical_node_id == 0 &&
+ smu->adev->gmc.xgmi.num_physical_nodes > 1 &&
+ smu_v13_0_6_cap_supported(smu, SMU_CAP(TEMP_METRICS)))
+ return true;
+ break;
+ case SMU_TEMP_METRIC_GPUBOARD:
+ return smu_v13_0_6_cap_supported(smu, SMU_CAP(TEMP_METRICS));
+ default:
+ break;
+ }
+
+ return false;
+}
+
+int smu_v13_0_12_get_system_power(struct smu_context *smu,
+ enum amd_pp_sensors sensor,
+ uint32_t *value)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_table *tables = smu_table->tables;
+ SystemMetricsTable_t *metrics;
+ struct smu_table *sys_table;
+ int ret;
+
+ if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(SYSTEM_POWER_METRICS)))
+ return -EOPNOTSUPP;
+
+ ret = smu_v13_0_12_get_system_metrics_table(smu);
+ if (ret)
+ return ret;
+
+ sys_table = &tables[SMU_TABLE_PMFW_SYSTEM_METRICS];
+ metrics = (SystemMetricsTable_t *)sys_table->cache.buffer;
+
+ switch (sensor) {
+ case AMDGPU_PP_SENSOR_UBB_POWER:
+ *value = metrics->SystemPower[SYSTEM_POWER_UBB_POWER];
+ break;
+ case AMDGPU_PP_SENSOR_UBB_POWER_LIMIT:
+ *value = metrics->SystemPower[SYSTEM_POWER_UBB_POWER_THRESHOLD];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+int smu_v13_0_12_get_npm_data(struct smu_context *smu,
+ enum amd_pp_sensors sensor,
+ uint32_t *value)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct PPTable_t *pptable =
+ (struct PPTable_t *)smu_table->driver_pptable;
+ struct smu_table *tables = smu_table->tables;
+ SystemMetricsTable_t *metrics;
+ struct smu_table *sys_table;
+ int ret;
+
+ if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(NPM_METRICS)))
+ return -EOPNOTSUPP;
+
+ if (sensor == AMDGPU_PP_SENSOR_MAXNODEPOWERLIMIT) {
+ *value = pptable->MaxNodePowerLimit;
+ return 0;
+ }
+
+ ret = smu_v13_0_12_get_system_metrics_table(smu);
+ if (ret)
+ return ret;
+
+ sys_table = &tables[SMU_TABLE_PMFW_SYSTEM_METRICS];
+ metrics = (SystemMetricsTable_t *)sys_table->cache.buffer;
+
+ switch (sensor) {
+ case AMDGPU_PP_SENSOR_NODEPOWERLIMIT:
+ *value = SMUQ10_ROUND(metrics->NodePowerLimit);
+ break;
+ case AMDGPU_PP_SENSOR_NODEPOWER:
+ *value = SMUQ10_ROUND(metrics->NodePower);
+ break;
+ case AMDGPU_PP_SENSOR_GPPTRESIDENCY:
+ *value = SMUQ10_ROUND(metrics->GlobalPPTResidencyAcc);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static ssize_t smu_v13_0_12_get_temp_metrics(struct smu_context *smu,
+ enum smu_temp_metric_type type, void *table)
+{
+ struct amdgpu_baseboard_temp_metrics_v1_0 *baseboard_temp_metrics;
+ struct amdgpu_gpuboard_temp_metrics_v1_0 *gpuboard_temp_metrics;
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_table *tables = smu_table->tables;
+ enum smu_driver_table_id table_id;
+ SystemMetricsTable_t *metrics;
+ struct smu_table *sys_table;
+ int ret, sensor_type;
+ u32 idx, sensors;
+ ssize_t size;
+
+ ret = smu_v13_0_12_get_system_metrics_table(smu);
+ if (ret)
+ return ret;
+
+ sys_table = &tables[SMU_TABLE_PMFW_SYSTEM_METRICS];
+ metrics = (SystemMetricsTable_t *)sys_table->cache.buffer;
+
+ switch (type) {
+ case SMU_TEMP_METRIC_GPUBOARD:
+ table_id = SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS;
+ gpuboard_temp_metrics =
+ (struct amdgpu_gpuboard_temp_metrics_v1_0 *)
+ smu_driver_table_ptr(smu, table_id);
+ size = sizeof(*gpuboard_temp_metrics);
+
+ gpuboard_temp_metrics->accumulation_counter = metrics->AccumulationCounter;
+ gpuboard_temp_metrics->label_version = metrics->LabelVersion;
+ gpuboard_temp_metrics->node_id = metrics->NodeIdentifier;
+
+ idx = 0;
+ for (sensors = 0; sensors < NODE_TEMP_MAX_TEMP_ENTRIES; sensors++) {
+ if (metrics->NodeTemperatures[sensors] != -1) {
+ sensor_type = smu_v13_0_12_get_node_sensor_type(sensors);
+ gpuboard_temp_metrics->node_temp[idx] =
+ ((int)metrics->NodeTemperatures[sensors]) & 0xFFFFFF;
+ gpuboard_temp_metrics->node_temp[idx] |= (sensor_type << 24);
+ idx++;
+ }
+ }
+
+ idx = 0;
+
+ for (sensors = 0; sensors < SVI_MAX_TEMP_ENTRIES; sensors++) {
+ if (metrics->VrTemperatures[sensors] != -1) {
+ sensor_type = smu_v13_0_12_get_vr_sensor_type(sensors);
+ gpuboard_temp_metrics->vr_temp[idx] =
+ ((int)metrics->VrTemperatures[sensors]) & 0xFFFFFF;
+ gpuboard_temp_metrics->vr_temp[idx] |= (sensor_type << 24);
+ idx++;
+ }
+ }
+ memcpy(table, gpuboard_temp_metrics, size);
+ break;
+ case SMU_TEMP_METRIC_BASEBOARD:
+ table_id = SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS;
+ baseboard_temp_metrics =
+ (struct amdgpu_baseboard_temp_metrics_v1_0 *)
+ smu_driver_table_ptr(smu, table_id);
+ size = sizeof(*baseboard_temp_metrics);
+
+ baseboard_temp_metrics->accumulation_counter = metrics->AccumulationCounter;
+ baseboard_temp_metrics->label_version = metrics->LabelVersion;
+ baseboard_temp_metrics->node_id = metrics->NodeIdentifier;
+
+ idx = 0;
+ for (sensors = 0; sensors < SYSTEM_TEMP_MAX_ENTRIES; sensors++) {
+ if (metrics->SystemTemperatures[sensors] != -1) {
+ sensor_type = smu_v13_0_12_get_system_sensor_type(sensors);
+ baseboard_temp_metrics->system_temp[idx] =
+ ((int)metrics->SystemTemperatures[sensors]) & 0xFFFFFF;
+ baseboard_temp_metrics->system_temp[idx] |= (sensor_type << 24);
+ idx++;
+ }
+ }
+ memcpy(table, baseboard_temp_metrics, size);
+ break;
+ default:
+ return -EINVAL;
+ }
+ smu_driver_table_update_cache_time(smu, table_id);
+
+ return size;
+}
+
+ssize_t smu_v13_0_12_get_xcp_metrics(struct smu_context *smu, struct amdgpu_xcp *xcp, void *table, void *smu_metrics)
+{
+ const u8 num_jpeg_rings = NUM_JPEG_RINGS_FW;
+ struct smu_v13_0_6_partition_metrics *xcp_metrics;
+ struct amdgpu_device *adev = smu->adev;
+ MetricsTable_t *metrics;
+ int inst, j, k, idx;
+ u32 inst_mask;
+
+ metrics = (MetricsTable_t *)smu_metrics;
+ xcp_metrics = (struct smu_v13_0_6_partition_metrics *)table;
+ amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_VCN, &inst_mask);
+ idx = 0;
+ for_each_inst(k, inst_mask) {
+ /* Both JPEG and VCN has same instance */
+ inst = GET_INST(VCN, k);
+ for (j = 0; j < num_jpeg_rings; ++j) {
+ xcp_metrics->jpeg_busy[(idx * num_jpeg_rings) + j] =
+ SMUQ10_ROUND(metrics->
+ JpegBusy[(inst * num_jpeg_rings) + j]);
+ }
+ xcp_metrics->vcn_busy[idx] =
+ SMUQ10_ROUND(metrics->VcnBusy[inst]);
+ xcp_metrics->current_vclk0[idx] = SMUQ10_ROUND(
+ metrics->VclkFrequency[inst]);
+ xcp_metrics->current_dclk0[idx] = SMUQ10_ROUND(
+ metrics->DclkFrequency[inst]);
+ xcp_metrics->current_socclk[idx] = SMUQ10_ROUND(
+ metrics->SocclkFrequency[inst]);
+
+ idx++;
+ }
+
+ xcp_metrics->current_uclk =
+ SMUQ10_ROUND(metrics->UclkFrequency);
+
+ amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_GFX, &inst_mask);
+ idx = 0;
+ for_each_inst(k, inst_mask) {
+ inst = GET_INST(GC, k);
+ xcp_metrics->current_gfxclk[idx] = SMUQ10_ROUND(metrics->GfxclkFrequency[inst]);
+ xcp_metrics->gfx_busy_inst[idx] = SMUQ10_ROUND(metrics->GfxBusy[inst]);
+ xcp_metrics->gfx_busy_acc[idx] = SMUQ10_ROUND(metrics->GfxBusyAcc[inst]);
+ if (smu_v13_0_6_cap_supported(smu, SMU_CAP(HST_LIMIT_METRICS))) {
+ xcp_metrics->gfx_below_host_limit_ppt_acc[idx] = SMUQ10_ROUND(metrics->GfxclkBelowHostLimitPptAcc[inst]);
+ xcp_metrics->gfx_below_host_limit_thm_acc[idx] = SMUQ10_ROUND(metrics->GfxclkBelowHostLimitThmAcc[inst]);
+ xcp_metrics->gfx_low_utilization_acc[idx] = SMUQ10_ROUND(metrics->GfxclkLowUtilizationAcc[inst]);
+ xcp_metrics->gfx_below_host_limit_total_acc[idx] = SMUQ10_ROUND(metrics->GfxclkBelowHostLimitTotalAcc[inst]);
+ }
+ idx++;
+ }
+
+ xcp_metrics->accumulation_counter = metrics->AccumulationCounter;
+ xcp_metrics->firmware_timestamp = metrics->Timestamp;
+
+ return sizeof(*xcp_metrics);
+}
+
+void smu_v13_0_12_get_gpu_metrics(struct smu_context *smu, void **table,
+ void *smu_metrics,
+ struct smu_v13_0_6_gpu_metrics *gpu_metrics)
+{
+ struct amdgpu_device *adev = smu->adev;
+ int ret = 0, xcc_id, inst, i, j, idx;
+ u8 num_jpeg_rings_gpu_metrics;
+ MetricsTable_t *metrics;
+
+ metrics = (MetricsTable_t *)smu_metrics;
+
+ gpu_metrics->temperature_hotspot =
+ SMUQ10_ROUND(metrics->MaxSocketTemperature);
+ /* Individual HBM stack temperature is not reported */
+ gpu_metrics->temperature_mem =
+ SMUQ10_ROUND(metrics->MaxHbmTemperature);
+ /* Reports max temperature of all voltage rails */
+ gpu_metrics->temperature_vrsoc =
+ SMUQ10_ROUND(metrics->MaxVrTemperature);
+
+ if (smu_v13_0_6_cap_supported(smu,
+ SMU_CAP(TEMP_AID_XCD_HBM))) {
+ if (adev->umc.active_mask) {
+ u64 mask = adev->umc.active_mask;
+ int out_idx = 0;
+ int stack_idx;
+
+ if (unlikely(hweight64(mask) / 2 > SMU_13_0_6_MAX_HBM_STACKS)) {
+ dev_warn(adev->dev, "Invalid umc mask %lld\n", mask);
+ } else {
+ for_each_hbm_stack(stack_idx, mask) {
+ if (!hbm_stack_mask_valid(mask))
+ continue;
+ gpu_metrics->temperature_hbm[out_idx++] =
+ metrics->HbmTemperature[stack_idx];
+ }
+ }
+ }
+ idx = 0;
+ for_each_inst(i, adev->aid_mask) {
+ gpu_metrics->temperature_aid[idx] = metrics->AidTemperature[i];
+ idx++;
+ }
+ }
+
+ gpu_metrics->average_gfx_activity =
+ SMUQ10_ROUND(metrics->SocketGfxBusy);
+ gpu_metrics->average_umc_activity =
+ SMUQ10_ROUND(metrics->DramBandwidthUtilization);
+
+ gpu_metrics->mem_max_bandwidth =
+ SMUQ10_ROUND(metrics->MaxDramBandwidth);
+
+ gpu_metrics->curr_socket_power =
+ SMUQ10_ROUND(metrics->SocketPower);
+ /* Energy counter reported in 15.259uJ (2^-16) units */
+ gpu_metrics->energy_accumulator = metrics->SocketEnergyAcc;
+
+ for (i = 0; i < MAX_GFX_CLKS; i++) {
+ xcc_id = GET_INST(GC, i);
+ if (xcc_id >= 0)
+ gpu_metrics->current_gfxclk[i] =
+ SMUQ10_ROUND(metrics->GfxclkFrequency[xcc_id]);
+
+ if (i < MAX_CLKS) {
+ gpu_metrics->current_socclk[i] =
+ SMUQ10_ROUND(metrics->SocclkFrequency[i]);
+ inst = GET_INST(VCN, i);
+ if (inst >= 0) {
+ gpu_metrics->current_vclk0[i] =
+ SMUQ10_ROUND(metrics->VclkFrequency[inst]);
+ gpu_metrics->current_dclk0[i] =
+ SMUQ10_ROUND(metrics->DclkFrequency[inst]);
+ }
+ }
+ }
+
+ gpu_metrics->current_uclk = SMUQ10_ROUND(metrics->UclkFrequency);
+
+ /* Total accumulated cycle counter */
+ gpu_metrics->accumulation_counter = metrics->AccumulationCounter;
+
+ /* Accumulated throttler residencies */
+ gpu_metrics->prochot_residency_acc = metrics->ProchotResidencyAcc;
+ gpu_metrics->ppt_residency_acc = metrics->PptResidencyAcc;
+ gpu_metrics->socket_thm_residency_acc = metrics->SocketThmResidencyAcc;
+ gpu_metrics->vr_thm_residency_acc = metrics->VrThmResidencyAcc;
+ gpu_metrics->hbm_thm_residency_acc = metrics->HbmThmResidencyAcc;
+
+ /* Clock Lock Status. Each bit corresponds to each GFXCLK instance */
+ gpu_metrics->gfxclk_lock_status = metrics->GfxLockXCDMak >> GET_INST(GC, 0);
+
+ gpu_metrics->pcie_link_width = metrics->PCIeLinkWidth;
+ gpu_metrics->pcie_link_speed =
+ pcie_gen_to_speed(metrics->PCIeLinkSpeed);
+ gpu_metrics->pcie_bandwidth_acc =
+ SMUQ10_ROUND(metrics->PcieBandwidthAcc[0]);
+ gpu_metrics->pcie_bandwidth_inst =
+ SMUQ10_ROUND(metrics->PcieBandwidth[0]);
+ gpu_metrics->pcie_l0_to_recov_count_acc = metrics->PCIeL0ToRecoveryCountAcc;
+ gpu_metrics->pcie_replay_count_acc = metrics->PCIenReplayAAcc;
+ gpu_metrics->pcie_replay_rover_count_acc =
+ metrics->PCIenReplayARolloverCountAcc;
+ gpu_metrics->pcie_nak_sent_count_acc = metrics->PCIeNAKSentCountAcc;
+ gpu_metrics->pcie_nak_rcvd_count_acc = metrics->PCIeNAKReceivedCountAcc;
+ gpu_metrics->pcie_lc_perf_other_end_recovery = metrics->PCIeOtherEndRecoveryAcc;
+
+ gpu_metrics->system_clock_counter = ktime_get_boottime_ns();
+
+ gpu_metrics->gfx_activity_acc = SMUQ10_ROUND(metrics->SocketGfxBusyAcc);
+ gpu_metrics->mem_activity_acc = SMUQ10_ROUND(metrics->DramBandwidthUtilizationAcc);
+
+ for (i = 0; i < NUM_XGMI_LINKS; i++) {
+ j = amdgpu_xgmi_get_ext_link(adev, i);
+ if (j < 0 || j >= NUM_XGMI_LINKS)
+ continue;
+ gpu_metrics->xgmi_read_data_acc[j] =
+ SMUQ10_ROUND(metrics->XgmiReadDataSizeAcc[i]);
+ gpu_metrics->xgmi_write_data_acc[j] =
+ SMUQ10_ROUND(metrics->XgmiWriteDataSizeAcc[i]);
+ ret = amdgpu_get_xgmi_link_status(adev, i);
+ if (ret >= 0)
+ gpu_metrics->xgmi_link_status[j] = ret;
+ }
+
+ num_jpeg_rings_gpu_metrics = NUM_JPEG_RINGS_GPU_METRICS(gpu_metrics);
+ for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
+ inst = GET_INST(VCN, i);
+
+ for (j = 0; j < num_jpeg_rings_gpu_metrics; ++j) {
+ gpu_metrics->jpeg_busy[(i * num_jpeg_rings_gpu_metrics) +
+ j] =
+ SMUQ10_ROUND(
+ metrics->JpegBusy[(inst *
+ NUM_JPEG_RINGS_FW) +
+ j]);
+ }
+ gpu_metrics->vcn_busy[i] = SMUQ10_ROUND(metrics->VcnBusy[inst]);
+ }
+
+ for (i = 0; i < NUM_XCC(adev->gfx.xcc_mask); ++i) {
+ inst = GET_INST(GC, i);
+ gpu_metrics->gfx_busy_inst[i] =
+ SMUQ10_ROUND(metrics->GfxBusy[inst]);
+ gpu_metrics->gfx_busy_acc[i] =
+ SMUQ10_ROUND(metrics->GfxBusyAcc[inst]);
+ if (smu_v13_0_6_cap_supported(smu,
+ SMU_CAP(HST_LIMIT_METRICS))) {
+ gpu_metrics
+ ->gfx_below_host_limit_ppt_acc[i] = SMUQ10_ROUND(
+ metrics->GfxclkBelowHostLimitPptAcc[inst]);
+ gpu_metrics
+ ->gfx_below_host_limit_thm_acc[i] = SMUQ10_ROUND(
+ metrics->GfxclkBelowHostLimitThmAcc[inst]);
+ gpu_metrics->gfx_low_utilization_acc[i] = SMUQ10_ROUND(
+ metrics->GfxclkLowUtilizationAcc[inst]);
+ gpu_metrics->gfx_below_host_limit_total_acc
+ [i] = SMUQ10_ROUND(
+ metrics->GfxclkBelowHostLimitTotalAcc[inst]);
+ }
+ if (smu_v13_0_6_cap_supported(smu,
+ SMU_CAP(TEMP_AID_XCD_HBM)))
+ gpu_metrics->temperature_xcd[i] = metrics->XcdTemperature[inst];
+ }
+
+ gpu_metrics->xgmi_link_width = metrics->XgmiWidth;
+ gpu_metrics->xgmi_link_speed = metrics->XgmiBitrate;
+
+ gpu_metrics->firmware_timestamp = metrics->Timestamp;
+}
+
+const struct smu_temp_funcs smu_v13_0_12_temp_funcs = {
+ .temp_metrics_is_supported = smu_v13_0_12_is_temp_metrics_supported,
+ .get_temp_metrics = smu_v13_0_12_get_temp_metrics,
+};
+
+static int smu_v13_0_12_get_ras_table_version(struct amdgpu_device *adev,
+ uint32_t *table_version)
+{
+ struct smu_context *smu = adev->powerplay.pp_handle;
+
+ return smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_GetRASTableVersion, 0, table_version);
+}
+
+static int smu_v13_0_12_get_badpage_count(struct amdgpu_device *adev, uint32_t *count,
+ uint32_t timeout)
+{
+ struct smu_context *smu = adev->powerplay.pp_handle;
+ uint64_t end, now;
+ int ret = 0;
+
+ now = (uint64_t)ktime_to_ms(ktime_get());
+ end = now + timeout;
+ do {
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_GetBadPageCount, 0, count);
+ /* eeprom is not ready */
+ if (ret != -EBUSY)
+ return ret;
+ mdelay(10);
+ now = (uint64_t)ktime_to_ms(ktime_get());
+ } while (now < end);
+
+ dev_err(adev->dev,
+ "smu get bad page count timeout!\n");
+ return ret;
+}
+
+static int smu_v13_0_12_set_timestamp(struct amdgpu_device *adev, uint64_t timestamp)
+{
+ struct smu_context *smu = adev->powerplay.pp_handle;
+
+ return smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_SetTimestamp, (uint32_t)timestamp, 0);
+}
+
+static int smu_v13_0_12_get_timestamp(struct amdgpu_device *adev,
+ uint16_t index, uint64_t *timestamp)
+{
+ struct smu_context *smu = adev->powerplay.pp_handle;
+ uint32_t temp;
+ int ret;
+
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_GetTimestamp, index, &temp);
+ if (!ret)
+ *timestamp = temp;
+
+ return ret;
+}
+
+static int smu_v13_0_12_get_badpage_ipid(struct amdgpu_device *adev,
+ uint16_t index, uint64_t *ipid)
+{
+ struct smu_context *smu = adev->powerplay.pp_handle;
+ uint32_t temp_arg, temp_ipid_lo, temp_ipid_high;
+ int ret;
+
+ temp_arg = index | (1 << 16);
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_GetBadPageIpid, temp_arg, &temp_ipid_lo);
+ if (ret)
+ return ret;
+
+ temp_arg = index | (2 << 16);
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_GetBadPageIpid, temp_arg, &temp_ipid_high);
+ if (!ret)
+ *ipid = (uint64_t)temp_ipid_high << 32 | temp_ipid_lo;
+ return ret;
+}
+
+static int smu_v13_0_12_erase_ras_table(struct amdgpu_device *adev,
+ uint32_t *result)
+{
+ struct smu_context *smu = adev->powerplay.pp_handle;
+
+ return smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_EraseRasTable, 0, result);
+}
+
+static int smu_v13_0_12_get_badpage_mca_addr(struct amdgpu_device *adev,
+ uint16_t index, uint64_t *mca_addr)
+{
+ struct smu_context *smu = adev->powerplay.pp_handle;
+ uint32_t temp_arg, temp_addr_lo, temp_addr_high;
+ int ret;
+
+ temp_arg = index | (1 << 16);
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_GetBadPageMcaAddr, temp_arg, &temp_addr_lo);
+ if (ret)
+ return ret;
+
+ temp_arg = index | (2 << 16);
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_GetBadPageMcaAddr, temp_arg, &temp_addr_high);
+ if (!ret)
+ *mca_addr = (uint64_t)temp_addr_high << 32 | temp_addr_lo;
+ return ret;
+}
+
+static const struct ras_eeprom_smu_funcs smu_v13_0_12_eeprom_smu_funcs = {
+ .get_ras_table_version = smu_v13_0_12_get_ras_table_version,
+ .get_badpage_count = smu_v13_0_12_get_badpage_count,
+ .get_badpage_mca_addr = smu_v13_0_12_get_badpage_mca_addr,
+ .set_timestamp = smu_v13_0_12_set_timestamp,
+ .get_timestamp = smu_v13_0_12_get_timestamp,
+ .get_badpage_ipid = smu_v13_0_12_get_badpage_ipid,
+ .erase_ras_table = smu_v13_0_12_erase_ras_table,
+};
+
+static void smu_v13_0_12_ras_smu_feature_flags(struct amdgpu_device *adev, uint64_t *flags)
+{
+ struct smu_context *smu = adev->powerplay.pp_handle;
+
+ if (!flags)
+ return;
+
+ *flags = 0ULL;
+
+ if (smu_v13_0_6_cap_supported(smu, SMU_CAP(RAS_EEPROM)))
+ *flags |= RAS_SMU_FEATURE_BIT__RAS_EEPROM;
+
+}
+
+const struct ras_smu_drv smu_v13_0_12_ras_smu_drv = {
+ .smu_eeprom_funcs = &smu_v13_0_12_eeprom_smu_funcs,
+ .ras_smu_feature_flags = smu_v13_0_12_ras_smu_feature_flags,
+};
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c
index b081ae3e8f43..ba91bf590eed 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c
@@ -52,24 +52,25 @@
#define mmMP1_SMN_C2PMSG_90 0x029a
#define mmMP1_SMN_C2PMSG_90_BASE_IDX 1
-#define FEATURE_MASK(feature) (1ULL << feature)
-
#define SMU_13_0_4_UMD_PSTATE_GFXCLK 938
#define SMU_13_0_4_UMD_PSTATE_SOCCLK 938
#define SMU_13_0_4_UMD_PSTATE_FCLK 1875
-#define SMC_DPM_FEATURE ( \
- FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_VCN_DPM_BIT) | \
- FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_LCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_ISP_DPM_BIT) | \
- FEATURE_MASK(FEATURE_IPU_DPM_BIT) | \
- FEATURE_MASK(FEATURE_GFX_DPM_BIT))
+static const struct smu_feature_bits smu_v13_0_4_dpm_features = {
+ .bits = {
+ SMU_FEATURE_BIT_INIT(FEATURE_CCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_VCN_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_FCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_SOCCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_MP0CLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_LCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_SHUBCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DCFCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_ISP_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_IPU_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_GFX_DPM_BIT)
+ }
+};
static struct cmn2asic_msg_mapping smu_v13_0_4_message_map[SMU_MSG_MAX_COUNT] = {
MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1),
@@ -151,6 +152,7 @@ static int smu_v13_0_4_init_smc_tables(struct smu_context *smu)
{
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_table *tables = smu_table->tables;
+ int ret;
SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
@@ -159,22 +161,23 @@ static int smu_v13_0_4_init_smc_tables(struct smu_context *smu)
SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
- smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL);
+ smu_table->clocks_table = kzalloc_obj(DpmClocks_t);
if (!smu_table->clocks_table)
goto err0_out;
- smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
+ smu_table->metrics_table = kzalloc_obj(SmuMetrics_t);
if (!smu_table->metrics_table)
goto err1_out;
smu_table->metrics_time = 0;
- smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL);
+ smu_table->watermarks_table = kzalloc_obj(Watermarks_t);
if (!smu_table->watermarks_table)
goto err2_out;
- smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_1);
- smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
- if (!smu_table->gpu_metrics_table)
+ ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS,
+ sizeof(struct gpu_metrics_v2_1),
+ SMU_GPU_METRICS_CACHE_INTERVAL);
+ if (ret)
goto err3_out;
return 0;
@@ -202,8 +205,7 @@ static int smu_v13_0_4_fini_smc_tables(struct smu_context *smu)
kfree(smu_table->watermarks_table);
smu_table->watermarks_table = NULL;
- kfree(smu_table->gpu_metrics_table);
- smu_table->gpu_metrics_table = NULL;
+ smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS);
return 0;
}
@@ -211,14 +213,15 @@ static int smu_v13_0_4_fini_smc_tables(struct smu_context *smu)
static bool smu_v13_0_4_is_dpm_running(struct smu_context *smu)
{
int ret = 0;
- uint64_t feature_enabled;
+ struct smu_feature_bits feature_enabled;
ret = smu_cmn_get_enabled_mask(smu, &feature_enabled);
if (ret)
return false;
- return !!(feature_enabled & SMC_DPM_FEATURE);
+ return smu_feature_bits_test_mask(&feature_enabled,
+ smu_v13_0_4_dpm_features.bits);
}
static int smu_v13_0_4_system_features_control(struct smu_context *smu, bool en)
@@ -247,9 +250,9 @@ static int smu_v13_0_4_system_features_control(struct smu_context *smu, bool en)
static ssize_t smu_v13_0_4_get_gpu_metrics(struct smu_context *smu,
void **table)
{
- struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v2_1 *gpu_metrics =
- (struct gpu_metrics_v2_1 *)smu_table->gpu_metrics_table;
+ (struct gpu_metrics_v2_1 *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
SmuMetrics_t metrics;
int ret = 0;
@@ -294,6 +297,8 @@ static ssize_t smu_v13_0_4_get_gpu_metrics(struct smu_context *smu,
*table = (void *)gpu_metrics;
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
return sizeof(struct gpu_metrics_v2_1);
}
@@ -494,15 +499,14 @@ static int smu_v13_0_4_get_dpm_level_count(struct smu_context *smu,
return 0;
}
-static int smu_v13_0_4_print_clk_levels(struct smu_context *smu,
- enum smu_clk_type clk_type, char *buf)
+static int smu_v13_0_4_emit_clk_levels(struct smu_context *smu,
+ enum smu_clk_type clk_type, char *buf,
+ int *offset)
{
- int i, idx, size = 0, ret = 0;
+ int i, idx, size = *offset, ret = 0, start_offset = *offset;
uint32_t cur_value = 0, value = 0, count = 0;
uint32_t min, max;
- smu_cmn_get_sysfs_buf(&buf, &size);
-
switch (clk_type) {
case SMU_OD_SCLK:
size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK");
@@ -524,17 +528,17 @@ static int smu_v13_0_4_print_clk_levels(struct smu_context *smu,
case SMU_FCLK:
ret = smu_v13_0_4_get_current_clk_freq(smu, clk_type, &cur_value);
if (ret)
- break;
+ return ret;
ret = smu_v13_0_4_get_dpm_level_count(smu, clk_type, &count);
if (ret)
- break;
+ return ret;
for (i = 0; i < count; i++) {
idx = (clk_type == SMU_FCLK || clk_type == SMU_MCLK) ? (count - i - 1) : i;
ret = smu_v13_0_4_get_dpm_freq_by_index(smu, clk_type, idx, &value);
if (ret)
- break;
+ return ret;
size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value,
cur_value == value ? "*" : "");
@@ -544,7 +548,7 @@ static int smu_v13_0_4_print_clk_levels(struct smu_context *smu,
case SMU_SCLK:
ret = smu_v13_0_4_get_current_clk_freq(smu, clk_type, &cur_value);
if (ret)
- break;
+ return ret;
min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq;
max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq;
if (cur_value == max)
@@ -565,7 +569,9 @@ static int smu_v13_0_4_print_clk_levels(struct smu_context *smu,
break;
}
- return size;
+ *offset += size - start_offset;
+
+ return 0;
}
static int smu_v13_0_4_read_sensor(struct smu_context *smu,
@@ -1092,13 +1098,11 @@ static int smu_v13_0_4_set_fine_grain_gfx_freq_parameters(struct smu_context *sm
static const struct pptable_funcs smu_v13_0_4_ppt_funcs = {
.check_fw_status = smu_v13_0_check_fw_status,
- .check_fw_version = smu_v13_0_check_fw_version,
+ .check_fw_version = smu_cmn_check_fw_version,
.init_smc_tables = smu_v13_0_4_init_smc_tables,
.fini_smc_tables = smu_v13_0_4_fini_smc_tables,
.get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values,
.system_features_control = smu_v13_0_4_system_features_control,
- .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
- .send_smc_msg = smu_cmn_send_smc_msg,
.dpm_set_vcn_enable = smu_v13_0_set_vcn_enable,
.dpm_set_jpeg_enable = smu_v13_0_set_jpeg_enable,
.set_default_dpm_table = smu_v13_0_set_default_dpm_tables,
@@ -1113,20 +1117,27 @@ static const struct pptable_funcs smu_v13_0_4_ppt_funcs = {
.mode2_reset = smu_v13_0_4_mode2_reset,
.get_dpm_ultimate_freq = smu_v13_0_4_get_dpm_ultimate_freq,
.od_edit_dpm_table = smu_v13_0_od_edit_dpm_table,
- .print_clk_levels = smu_v13_0_4_print_clk_levels,
+ .emit_clk_levels = smu_v13_0_4_emit_clk_levels,
.force_clk_levels = smu_v13_0_4_force_clk_levels,
.set_performance_level = smu_v13_0_4_set_performance_level,
.set_fine_grain_gfx_freq_parameters = smu_v13_0_4_set_fine_grain_gfx_freq_parameters,
.set_gfx_power_up_by_imu = smu_v13_0_set_gfx_power_up_by_imu,
};
-static void smu_v13_0_4_set_smu_mailbox_registers(struct smu_context *smu)
+static void smu_v13_0_4_init_msg_ctl(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
-
- smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82);
- smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66);
- smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90);
+ struct smu_msg_ctl *ctl = &smu->msg_ctl;
+
+ ctl->smu = smu;
+ mutex_init(&ctl->lock);
+ ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66);
+ ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90);
+ ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82);
+ ctl->config.num_arg_regs = 1;
+ ctl->ops = &smu_msg_v1_ops;
+ ctl->default_timeout = adev->usec_timeout * 20;
+ ctl->message_map = smu_v13_0_4_message_map;
}
void smu_v13_0_4_set_ppt_funcs(struct smu_context *smu)
@@ -1134,14 +1145,13 @@ void smu_v13_0_4_set_ppt_funcs(struct smu_context *smu)
struct amdgpu_device *adev = smu->adev;
smu->ppt_funcs = &smu_v13_0_4_ppt_funcs;
- smu->message_map = smu_v13_0_4_message_map;
smu->feature_map = smu_v13_0_4_feature_mask_map;
smu->table_map = smu_v13_0_4_table_map;
smu->smc_driver_if_version = SMU13_0_4_DRIVER_IF_VERSION;
smu->is_apu = true;
if (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 4))
- smu_v13_0_4_set_smu_mailbox_registers(smu);
+ smu_v13_0_4_init_msg_ctl(smu);
else
- smu_v13_0_set_smu_mailbox_registers(smu);
+ smu_v13_0_init_msg_ctl(smu, smu_v13_0_4_message_map);
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c
index f5db181ef489..27372a60e83d 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c
@@ -51,17 +51,19 @@
#define mmMP1_C2PMSG_33 (0xbee261 + 0xb00000 / 4)
#define mmMP1_C2PMSG_33_BASE_IDX 0
-#define FEATURE_MASK(feature) (1ULL << feature)
-#define SMC_DPM_FEATURE ( \
- FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_LCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_GFX_DPM_BIT) | \
- FEATURE_MASK(FEATURE_VCN_DPM_BIT) | \
- FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT)| \
- FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT)| \
- FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT))
+static const struct smu_feature_bits smu_v13_0_5_dpm_features = {
+ .bits = {
+ SMU_FEATURE_BIT_INIT(FEATURE_CCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_FCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_LCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_GFX_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_VCN_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DCFCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_SOCCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_MP0CLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_SHUBCLK_DPM_BIT)
+ }
+};
static struct cmn2asic_msg_mapping smu_v13_0_5_message_map[SMU_MSG_MAX_COUNT] = {
MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1),
@@ -125,6 +127,7 @@ static int smu_v13_0_5_init_smc_tables(struct smu_context *smu)
{
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_table *tables = smu_table->tables;
+ int ret;
SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
@@ -133,22 +136,23 @@ static int smu_v13_0_5_init_smc_tables(struct smu_context *smu)
SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
- smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL);
+ smu_table->clocks_table = kzalloc_obj(DpmClocks_t);
if (!smu_table->clocks_table)
goto err0_out;
- smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
+ smu_table->metrics_table = kzalloc_obj(SmuMetrics_t);
if (!smu_table->metrics_table)
goto err1_out;
smu_table->metrics_time = 0;
- smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL);
+ smu_table->watermarks_table = kzalloc_obj(Watermarks_t);
if (!smu_table->watermarks_table)
goto err2_out;
- smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_1);
- smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
- if (!smu_table->gpu_metrics_table)
+ ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS,
+ sizeof(struct gpu_metrics_v2_1),
+ SMU_GPU_METRICS_CACHE_INTERVAL);
+ if (ret)
goto err3_out;
return 0;
@@ -176,8 +180,7 @@ static int smu_v13_0_5_fini_smc_tables(struct smu_context *smu)
kfree(smu_table->watermarks_table);
smu_table->watermarks_table = NULL;
- kfree(smu_table->gpu_metrics_table);
- smu_table->gpu_metrics_table = NULL;
+ smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS);
return 0;
}
@@ -229,14 +232,15 @@ static int smu_v13_0_5_dpm_set_jpeg_enable(struct smu_context *smu, bool enable)
static bool smu_v13_0_5_is_dpm_running(struct smu_context *smu)
{
int ret = 0;
- uint64_t feature_enabled;
+ struct smu_feature_bits feature_enabled;
ret = smu_cmn_get_enabled_mask(smu, &feature_enabled);
if (ret)
return false;
- return !!(feature_enabled & SMC_DPM_FEATURE);
+ return smu_feature_bits_test_mask(&feature_enabled,
+ smu_v13_0_5_dpm_features.bits);
}
static int smu_v13_0_5_mode_reset(struct smu_context *smu, int type)
@@ -466,11 +470,11 @@ static int smu_v13_0_5_set_watermarks_table(struct smu_context *smu,
}
static ssize_t smu_v13_0_5_get_gpu_metrics(struct smu_context *smu,
- void **table)
+ void **table)
{
- struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v2_1 *gpu_metrics =
- (struct gpu_metrics_v2_1 *)smu_table->gpu_metrics_table;
+ (struct gpu_metrics_v2_1 *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
SmuMetrics_t metrics;
int ret = 0;
@@ -500,6 +504,8 @@ static ssize_t smu_v13_0_5_get_gpu_metrics(struct smu_context *smu,
*table = (void *)gpu_metrics;
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
return sizeof(struct gpu_metrics_v2_1);
}
@@ -858,15 +864,14 @@ out:
return ret;
}
-static int smu_v13_0_5_print_clk_levels(struct smu_context *smu,
- enum smu_clk_type clk_type, char *buf)
+static int smu_v13_0_5_emit_clk_levels(struct smu_context *smu,
+ enum smu_clk_type clk_type, char *buf,
+ int *offset)
{
- int i, idx, size = 0, ret = 0;
+ int i, idx, size = *offset, ret = 0, start_offset = *offset;
uint32_t cur_value = 0, value = 0, count = 0;
uint32_t min = 0, max = 0;
- smu_cmn_get_sysfs_buf(&buf, &size);
-
switch (clk_type) {
case SMU_OD_SCLK:
size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK");
@@ -886,17 +891,17 @@ static int smu_v13_0_5_print_clk_levels(struct smu_context *smu,
case SMU_MCLK:
ret = smu_v13_0_5_get_current_clk_freq(smu, clk_type, &cur_value);
if (ret)
- goto print_clk_out;
+ return ret;
ret = smu_v13_0_5_get_dpm_level_count(smu, clk_type, &count);
if (ret)
- goto print_clk_out;
+ return ret;
for (i = 0; i < count; i++) {
idx = (clk_type == SMU_MCLK) ? (count - i - 1) : i;
ret = smu_v13_0_5_get_dpm_freq_by_index(smu, clk_type, idx, &value);
if (ret)
- goto print_clk_out;
+ return ret;
size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value,
cur_value == value ? "*" : "");
@@ -906,7 +911,7 @@ static int smu_v13_0_5_print_clk_levels(struct smu_context *smu,
case SMU_SCLK:
ret = smu_v13_0_5_get_current_clk_freq(smu, clk_type, &cur_value);
if (ret)
- goto print_clk_out;
+ return ret;
min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq;
max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq;
if (cur_value == max)
@@ -927,8 +932,9 @@ static int smu_v13_0_5_print_clk_levels(struct smu_context *smu,
break;
}
-print_clk_out:
- return size;
+ *offset += size - start_offset;
+
+ return 0;
}
@@ -1096,13 +1102,11 @@ static int smu_v13_0_5_set_fine_grain_gfx_freq_parameters(struct smu_context *sm
static const struct pptable_funcs smu_v13_0_5_ppt_funcs = {
.check_fw_status = smu_v13_0_check_fw_status,
- .check_fw_version = smu_v13_0_check_fw_version,
+ .check_fw_version = smu_cmn_check_fw_version,
.init_smc_tables = smu_v13_0_5_init_smc_tables,
.fini_smc_tables = smu_v13_0_5_fini_smc_tables,
.get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values,
.system_features_control = smu_v13_0_5_system_features_control,
- .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
- .send_smc_msg = smu_cmn_send_smc_msg,
.dpm_set_vcn_enable = smu_v13_0_5_dpm_set_vcn_enable,
.dpm_set_jpeg_enable = smu_v13_0_5_dpm_set_jpeg_enable,
.set_default_dpm_table = smu_v13_0_5_set_default_dpm_tables,
@@ -1117,23 +1121,34 @@ static const struct pptable_funcs smu_v13_0_5_ppt_funcs = {
.mode2_reset = smu_v13_0_5_mode2_reset,
.get_dpm_ultimate_freq = smu_v13_0_5_get_dpm_ultimate_freq,
.od_edit_dpm_table = smu_v13_0_5_od_edit_dpm_table,
- .print_clk_levels = smu_v13_0_5_print_clk_levels,
+ .emit_clk_levels = smu_v13_0_5_emit_clk_levels,
.force_clk_levels = smu_v13_0_5_force_clk_levels,
.set_performance_level = smu_v13_0_5_set_performance_level,
.set_fine_grain_gfx_freq_parameters = smu_v13_0_5_set_fine_grain_gfx_freq_parameters,
};
-void smu_v13_0_5_set_ppt_funcs(struct smu_context *smu)
+static void smu_v13_0_5_init_msg_ctl(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
+ struct smu_msg_ctl *ctl = &smu->msg_ctl;
+
+ ctl->smu = smu;
+ mutex_init(&ctl->lock);
+ ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_2);
+ ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_33);
+ ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_34);
+ ctl->config.num_arg_regs = 1;
+ ctl->ops = &smu_msg_v1_ops;
+ ctl->default_timeout = adev->usec_timeout * 20;
+ ctl->message_map = smu_v13_0_5_message_map;
+}
+void smu_v13_0_5_set_ppt_funcs(struct smu_context *smu)
+{
smu->ppt_funcs = &smu_v13_0_5_ppt_funcs;
- smu->message_map = smu_v13_0_5_message_map;
smu->feature_map = smu_v13_0_5_feature_mask_map;
smu->table_map = smu_v13_0_5_table_map;
smu->is_apu = true;
smu->smc_driver_if_version = SMU13_0_5_DRIVER_IF_VERSION;
- smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_34);
- smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_2);
- smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_33);
+ smu_v13_0_5_init_msg_ctl(smu);
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
index da7bd9227afe..b12388134489 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
@@ -76,15 +76,18 @@ MODULE_FIRMWARE("amdgpu/smu_13_0_14.bin");
[smu_feature] = { 1, (smu_13_0_6_feature) }
#define FEATURE_MASK(feature) (1ULL << feature)
-#define SMC_DPM_FEATURE \
- (FEATURE_MASK(FEATURE_DATA_CALCULATION) | \
- FEATURE_MASK(FEATURE_DPM_GFXCLK) | FEATURE_MASK(FEATURE_DPM_UCLK) | \
- FEATURE_MASK(FEATURE_DPM_SOCCLK) | FEATURE_MASK(FEATURE_DPM_FCLK) | \
- FEATURE_MASK(FEATURE_DPM_LCLK) | FEATURE_MASK(FEATURE_DPM_XGMI) | \
- FEATURE_MASK(FEATURE_DPM_VCN))
-
-/* possible frequency drift (1Mhz) */
-#define EPSILON 1
+static const struct smu_feature_bits smu_v13_0_6_dpm_features = {
+ .bits = {
+ SMU_FEATURE_BIT_INIT(FEATURE_DATA_CALCULATION),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_LCLK),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_XGMI),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_VCN)
+ }
+};
#define smnPCIE_ESM_CTRL 0x93D0
#define smnPCIE_LC_LINK_WIDTH_CNTL 0x1a340288
@@ -95,31 +98,10 @@ MODULE_FIRMWARE("amdgpu/smu_13_0_14.bin");
#define smnPCIE_LC_SPEED_CNTL 0x1a340290
#define PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK 0xE0
#define PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT 0x5
-#define LINK_SPEED_MAX 4
-#define SMU_13_0_6_DSCLK_THRESHOLD 140
-
+#define LINK_SPEED_MAX 4
#define MCA_BANK_IPID(_ip, _hwid, _type) \
[AMDGPU_MCA_IP_##_ip] = { .hwid = _hwid, .mcatype = _type, }
-#define SMU_CAP(x) SMU_13_0_6_CAPS_##x
-
-enum smu_v13_0_6_caps {
- SMU_CAP(DPM),
- SMU_CAP(UNI_METRICS),
- SMU_CAP(DPM_POLICY),
- SMU_CAP(OTHER_END_METRICS),
- SMU_CAP(SET_UCLK_MAX),
- SMU_CAP(PCIE_METRICS),
- SMU_CAP(HST_LIMIT_METRICS),
- SMU_CAP(MCA_DEBUG_MODE),
- SMU_CAP(PER_INST_METRICS),
- SMU_CAP(CTF_LIMIT),
- SMU_CAP(RMA_MSG),
- SMU_CAP(ACA_SYND),
- SMU_CAP(SDMA_RESET),
- SMU_CAP(ALL),
-};
-
struct mca_bank_ipid {
enum amdgpu_mca_ip ip;
uint16_t hwid;
@@ -162,9 +144,9 @@ static const struct cmn2asic_msg_mapping smu_v13_0_6_message_map[SMU_MSG_MAX_COU
MSG_MAP(GetMinDpmFreq, PPSMC_MSG_GetMinDpmFreq, 1),
MSG_MAP(GetMaxDpmFreq, PPSMC_MSG_GetMaxDpmFreq, 1),
MSG_MAP(GetDpmFreqByIndex, PPSMC_MSG_GetDpmFreqByIndex, 1),
- MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit, 0),
+ MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit, 1),
MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit, 1),
- MSG_MAP(GfxDeviceDriverReset, PPSMC_MSG_GfxDriverReset, SMU_MSG_RAS_PRI),
+ MSG_MAP(GfxDeviceDriverReset, PPSMC_MSG_GfxDriverReset, SMU_MSG_RAS_PRI | SMU_MSG_NO_PRECHECK),
MSG_MAP(DramLogSetDramAddrHigh, PPSMC_MSG_DramLogSetDramAddrHigh, 0),
MSG_MAP(DramLogSetDramAddrLow, PPSMC_MSG_DramLogSetDramAddrLow, 0),
MSG_MAP(DramLogSetDramSize, PPSMC_MSG_DramLogSetDramSize, 0),
@@ -193,8 +175,10 @@ static const struct cmn2asic_msg_mapping smu_v13_0_6_message_map[SMU_MSG_MAX_COU
MSG_MAP(McaBankCeDumpDW, PPSMC_MSG_McaBankCeDumpDW, SMU_MSG_RAS_PRI),
MSG_MAP(SelectPLPDMode, PPSMC_MSG_SelectPLPDMode, 0),
MSG_MAP(RmaDueToBadPageThreshold, PPSMC_MSG_RmaDueToBadPageThreshold, 0),
- MSG_MAP(SelectPstatePolicy, PPSMC_MSG_SelectPstatePolicy, 0),
+ MSG_MAP(SetThrottlingPolicy, PPSMC_MSG_SetThrottlingPolicy, 0),
MSG_MAP(ResetSDMA, PPSMC_MSG_ResetSDMA, 0),
+ MSG_MAP(ResetVCN, PPSMC_MSG_ResetVCN, 0),
+ MSG_MAP(GetStaticMetricsTable, PPSMC_MSG_GetStaticMetricsTable, 1),
};
// clang-format on
@@ -231,7 +215,11 @@ static const struct cmn2asic_mapping smu_v13_0_6_feature_mask_map[SMU_FEATURE_CO
SMU_13_0_6_FEA_MAP(SMU_FEATURE_FW_CTF_BIT, FEATURE_FW_CTF),
SMU_13_0_6_FEA_MAP(SMU_FEATURE_THERMAL_BIT, FEATURE_THERMAL),
SMU_13_0_6_FEA_MAP(SMU_FEATURE_XGMI_PER_LINK_PWR_DWN_BIT, FEATURE_XGMI_PER_LINK_PWR_DOWN),
- SMU_13_0_6_FEA_MAP(SMU_FEATURE_DF_CSTATE_BIT, FEATURE_DF_CSTATE),
+ SMU_13_0_6_FEA_MAP(SMU_FEATURE_DF_CSTATE_BIT, FEATURE_DF_CSTATE),
+ SMU_13_0_6_FEA_MAP(SMU_FEATURE_DS_VCN_BIT, FEATURE_DS_VCN),
+ SMU_13_0_6_FEA_MAP(SMU_FEATURE_DS_MP1CLK_BIT, FEATURE_DS_MP1CLK),
+ SMU_13_0_6_FEA_MAP(SMU_FEATURE_DS_MPIOCLK_BIT, FEATURE_DS_MPIOCLK),
+ SMU_13_0_6_FEA_MAP(SMU_FEATURE_DS_MP0CLK_BIT, FEATURE_DS_MP0CLK),
};
#define TABLE_PMSTATUSLOG 0
@@ -253,35 +241,33 @@ static const uint8_t smu_v13_0_6_throttler_map[] = {
[THROTTLER_PROCHOT_BIT] = (SMU_THROTTLER_PROCHOT_GFX_BIT),
};
-struct PPTable_t {
- uint32_t MaxSocketPowerLimit;
- uint32_t MaxGfxclkFrequency;
- uint32_t MinGfxclkFrequency;
- uint32_t FclkFrequencyTable[4];
- uint32_t UclkFrequencyTable[4];
- uint32_t SocclkFrequencyTable[4];
- uint32_t VclkFrequencyTable[4];
- uint32_t DclkFrequencyTable[4];
- uint32_t LclkFrequencyTable[4];
- uint32_t MaxLclkDpmRange;
- uint32_t MinLclkDpmRange;
- uint64_t PublicSerialNumber_AID;
- bool Init;
-};
-
-#define SMUQ10_TO_UINT(x) ((x) >> 10)
-#define SMUQ10_FRAC(x) ((x) & 0x3ff)
-#define SMUQ10_ROUND(x) ((SMUQ10_TO_UINT(x)) + ((SMUQ10_FRAC(x)) >= 0x200))
-#define GET_METRIC_FIELD(field, flag) ((flag) ?\
- (metrics_a->field) : (metrics_x->field))
+#define GET_GPU_METRIC_FIELD(field, version) ((version == METRICS_VERSION_V0) ?\
+ (metrics_v0->field) : (metrics_v2->field))
+#define GET_METRIC_FIELD(field, version) ((version == METRICS_VERSION_V1) ?\
+ (metrics_v1->field) : GET_GPU_METRIC_FIELD(field, version))
+#define METRICS_TABLE_SIZE (max3(sizeof(MetricsTableV0_t),\
+ sizeof(MetricsTableV1_t),\
+ sizeof(MetricsTableV2_t)))
struct smu_v13_0_6_dpm_map {
enum smu_clk_type clk_type;
uint32_t feature_num;
- struct smu_13_0_dpm_table *dpm_table;
+ struct smu_dpm_table *dpm_table;
uint32_t *freq_table;
};
+static inline int smu_v13_0_6_get_metrics_version(struct smu_context *smu)
+{
+ if ((smu->adev->flags & AMD_IS_APU) &&
+ smu->smc_fw_version <= 0x4556900)
+ return METRICS_VERSION_V1;
+ else if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) ==
+ IP_VERSION(13, 0, 12))
+ return METRICS_VERSION_V2;
+
+ return METRICS_VERSION_V0;
+}
+
static inline void smu_v13_0_6_cap_set(struct smu_context *smu,
enum smu_v13_0_6_caps cap)
{
@@ -298,8 +284,8 @@ static inline void smu_v13_0_6_cap_clear(struct smu_context *smu,
dpm_context->caps &= ~BIT_ULL(cap);
}
-static inline bool smu_v13_0_6_cap_supported(struct smu_context *smu,
- enum smu_v13_0_6_caps cap)
+bool smu_v13_0_6_cap_supported(struct smu_context *smu,
+ enum smu_v13_0_6_caps cap)
{
struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
@@ -309,7 +295,6 @@ static inline bool smu_v13_0_6_cap_supported(struct smu_context *smu,
static void smu_v13_0_14_init_caps(struct smu_context *smu)
{
enum smu_v13_0_6_caps default_cap_list[] = { SMU_CAP(DPM),
- SMU_CAP(UNI_METRICS),
SMU_CAP(SET_UCLK_MAX),
SMU_CAP(DPM_POLICY),
SMU_CAP(PCIE_METRICS),
@@ -324,23 +309,29 @@ static void smu_v13_0_14_init_caps(struct smu_context *smu)
if (fw_ver >= 0x05550E00)
smu_v13_0_6_cap_set(smu, SMU_CAP(OTHER_END_METRICS));
- if (fw_ver >= 0x05551000)
- smu_v13_0_6_cap_set(smu, SMU_CAP(HST_LIMIT_METRICS));
if (fw_ver >= 0x05550B00)
smu_v13_0_6_cap_set(smu, SMU_CAP(PER_INST_METRICS));
if (fw_ver >= 0x5551200)
smu_v13_0_6_cap_set(smu, SMU_CAP(SDMA_RESET));
+ if (fw_ver >= 0x5551800)
+ smu_v13_0_6_cap_set(smu, SMU_CAP(VCN_RESET));
+ if (fw_ver >= 0x5551600) {
+ smu_v13_0_6_cap_set(smu, SMU_CAP(STATIC_METRICS));
+ smu_v13_0_6_cap_set(smu, SMU_CAP(BOARD_VOLTAGE));
+ smu_v13_0_6_cap_set(smu, SMU_CAP(PLDM_VERSION));
+ }
}
static void smu_v13_0_12_init_caps(struct smu_context *smu)
{
enum smu_v13_0_6_caps default_cap_list[] = { SMU_CAP(DPM),
- SMU_CAP(UNI_METRICS),
SMU_CAP(PCIE_METRICS),
SMU_CAP(CTF_LIMIT),
SMU_CAP(MCA_DEBUG_MODE),
SMU_CAP(RMA_MSG),
- SMU_CAP(ACA_SYND) };
+ SMU_CAP(ACA_SYND),
+ SMU_CAP(OTHER_END_METRICS),
+ SMU_CAP(PER_INST_METRICS) };
uint32_t fw_ver = smu->smc_fw_version;
for (int i = 0; i < ARRAY_SIZE(default_cap_list); i++)
@@ -351,12 +342,45 @@ static void smu_v13_0_12_init_caps(struct smu_context *smu)
if (fw_ver >= 0x00561700)
smu_v13_0_6_cap_set(smu, SMU_CAP(SDMA_RESET));
+
+ if (fw_ver >= 0x00561E00)
+ smu_v13_0_6_cap_set(smu, SMU_CAP(STATIC_METRICS));
+
+ if (fw_ver >= 0x00562500)
+ smu_v13_0_6_cap_set(smu, SMU_CAP(HST_LIMIT_METRICS));
+
+ if (fw_ver >= 0x04560100) {
+ smu_v13_0_6_cap_set(smu, SMU_CAP(BOARD_VOLTAGE));
+ smu_v13_0_6_cap_set(smu, SMU_CAP(PLDM_VERSION));
+ }
+
+ if (fw_ver > 0x04560900)
+ smu_v13_0_6_cap_set(smu, SMU_CAP(VCN_RESET));
+
+ if (fw_ver >= 0x04560D00) {
+ smu_v13_0_6_cap_set(smu, SMU_CAP(FAST_PPT));
+ if (smu->adev->gmc.xgmi.physical_node_id == 0)
+ smu_v13_0_6_cap_set(smu, SMU_CAP(SYSTEM_POWER_METRICS));
+ }
+
+ if (fw_ver >= 0x04560700) {
+ if (fw_ver >= 0x04560900) {
+ smu_v13_0_6_cap_set(smu, SMU_CAP(TEMP_METRICS));
+ if (smu->adev->gmc.xgmi.physical_node_id == 0)
+ smu_v13_0_6_cap_set(smu, SMU_CAP(NPM_METRICS));
+ } else if (!amdgpu_sriov_vf(smu->adev))
+ smu_v13_0_6_cap_set(smu, SMU_CAP(TEMP_METRICS));
+ } else {
+ smu_v13_0_12_tables_fini(smu);
+ }
+
+ if (fw_ver >= 0x04561000)
+ smu_v13_0_6_cap_set(smu, SMU_CAP(TEMP_AID_XCD_HBM));
}
static void smu_v13_0_6_init_caps(struct smu_context *smu)
{
enum smu_v13_0_6_caps default_cap_list[] = { SMU_CAP(DPM),
- SMU_CAP(UNI_METRICS),
SMU_CAP(SET_UCLK_MAX),
SMU_CAP(DPM_POLICY),
SMU_CAP(PCIE_METRICS),
@@ -382,10 +406,6 @@ static void smu_v13_0_6_init_caps(struct smu_context *smu)
smu_v13_0_6_cap_clear(smu, SMU_CAP(RMA_MSG));
smu_v13_0_6_cap_clear(smu, SMU_CAP(ACA_SYND));
- if (fw_ver <= 0x4556900)
- smu_v13_0_6_cap_clear(smu, SMU_CAP(UNI_METRICS));
- if (fw_ver >= 0x04556F00)
- smu_v13_0_6_cap_set(smu, SMU_CAP(HST_LIMIT_METRICS));
if (fw_ver >= 0x04556A00)
smu_v13_0_6_cap_set(smu, SMU_CAP(PER_INST_METRICS));
} else {
@@ -405,13 +425,45 @@ static void smu_v13_0_6_init_caps(struct smu_context *smu)
smu_v13_0_6_cap_clear(smu, SMU_CAP(RMA_MSG));
if (fw_ver < 0x00555600)
smu_v13_0_6_cap_clear(smu, SMU_CAP(ACA_SYND));
- if (pgm == 0 && fw_ver >= 0x557900)
+ if ((pgm == 7 && fw_ver >= 0x7550E00) ||
+ (pgm == 0 && fw_ver >= 0x00557E00))
smu_v13_0_6_cap_set(smu, SMU_CAP(HST_LIMIT_METRICS));
+
+ if (amdgpu_sriov_vf(adev)) {
+ if (fw_ver >= 0x00558200)
+ amdgpu_virt_attr_set(&adev->virt.virt_caps,
+ AMDGPU_VIRT_CAP_POWER_LIMIT,
+ AMDGPU_CAP_ATTR_RW);
+ if ((pgm == 0 && fw_ver >= 0x00558000) ||
+ (pgm == 7 && fw_ver >= 0x7551000)) {
+ smu_v13_0_6_cap_set(smu,
+ SMU_CAP(STATIC_METRICS));
+ smu_v13_0_6_cap_set(smu,
+ SMU_CAP(BOARD_VOLTAGE));
+ smu_v13_0_6_cap_set(smu, SMU_CAP(PLDM_VERSION));
+ }
+ } else {
+ if ((pgm == 0 && fw_ver >= 0x00557F01) ||
+ (pgm == 7 && fw_ver >= 0x7551000)) {
+ smu_v13_0_6_cap_set(smu,
+ SMU_CAP(STATIC_METRICS));
+ smu_v13_0_6_cap_set(smu,
+ SMU_CAP(BOARD_VOLTAGE));
+ }
+ if ((pgm == 0 && fw_ver >= 0x00558000) ||
+ (pgm == 7 && fw_ver >= 0x7551000))
+ smu_v13_0_6_cap_set(smu, SMU_CAP(PLDM_VERSION));
+ }
}
if (((pgm == 7) && (fw_ver >= 0x7550700)) ||
((pgm == 0) && (fw_ver >= 0x00557900)) ||
((pgm == 4) && (fw_ver >= 0x4557000)))
smu_v13_0_6_cap_set(smu, SMU_CAP(SDMA_RESET));
+
+ if ((pgm == 0 && fw_ver >= 0x00558200) ||
+ (pgm == 4 && fw_ver >= 0x04557100) ||
+ (pgm == 7 && fw_ver >= 0x07551400))
+ smu_v13_0_6_cap_set(smu, SMU_CAP(VCN_RESET));
}
static void smu_v13_0_x_init_caps(struct smu_context *smu)
@@ -430,7 +482,7 @@ static int smu_v13_0_6_check_fw_version(struct smu_context *smu)
{
int r;
- r = smu_v13_0_check_fw_version(smu);
+ r = smu_cmn_check_fw_version(smu);
/* Initialize caps flags once fw version is fetched */
if (!r)
smu_v13_0_x_init_caps(smu);
@@ -450,8 +502,9 @@ static int smu_v13_0_6_init_microcode(struct smu_context *smu)
int var = (adev->pdev->device & 0xF);
char ucode_prefix[15];
- /* No need to load P2S tables in IOV mode */
- if (amdgpu_sriov_vf(adev))
+ /* No need to load P2S tables in IOV mode or for smu v13.0.12 */
+ if (amdgpu_sriov_vf(adev) ||
+ (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12)))
return 0;
if (!(adev->flags & AMD_IS_APU)) {
@@ -507,14 +560,20 @@ static int smu_v13_0_6_tables_init(struct smu_context *smu)
{
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_table *tables = smu_table->tables;
+ struct smu_v13_0_6_gpu_metrics *gpu_metrics;
+ void *driver_pptable __free(kfree) = NULL;
+ void *metrics_table __free(kfree) = NULL;
struct amdgpu_device *adev = smu->adev;
+ int gpu_metrcs_size = METRICS_TABLE_SIZE;
+ int ret;
if (!(adev->flags & AMD_IS_APU))
SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU13_TOOL_SIZE,
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS,
- max(sizeof(MetricsTableX_t), sizeof(MetricsTableA_t)),
+ max(gpu_metrcs_size,
+ smu_v13_0_12_get_max_metrics_size()),
PAGE_SIZE,
AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT);
@@ -522,28 +581,42 @@ static int smu_v13_0_6_tables_init(struct smu_context *smu)
PAGE_SIZE,
AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT);
- smu_table->metrics_table = kzalloc(max(sizeof(MetricsTableX_t),
- sizeof(MetricsTableA_t)), GFP_KERNEL);
- if (!smu_table->metrics_table)
+ SMU_TABLE_INIT(tables, SMU_TABLE_PMFW_SYSTEM_METRICS,
+ smu_v13_0_12_get_system_metrics_size(), PAGE_SIZE,
+ AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT);
+
+ metrics_table = kzalloc(METRICS_TABLE_SIZE, GFP_KERNEL);
+ if (!metrics_table)
return -ENOMEM;
smu_table->metrics_time = 0;
- smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_7);
- smu_table->gpu_metrics_table =
- kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
- if (!smu_table->gpu_metrics_table) {
- kfree(smu_table->metrics_table);
+ driver_pptable = kzalloc_obj(struct PPTable_t);
+ if (!driver_pptable)
return -ENOMEM;
- }
- smu_table->driver_pptable =
- kzalloc(sizeof(struct PPTable_t), GFP_KERNEL);
- if (!smu_table->driver_pptable) {
- kfree(smu_table->metrics_table);
- kfree(smu_table->gpu_metrics_table);
- return -ENOMEM;
+ ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS,
+ sizeof(struct smu_v13_0_6_gpu_metrics),
+ SMU_GPU_METRICS_CACHE_INTERVAL);
+ if (ret)
+ return ret;
+
+ gpu_metrics = (struct smu_v13_0_6_gpu_metrics *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
+ smu_v13_0_6_gpu_metrics_init(gpu_metrics, 1, 9);
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) ==
+ IP_VERSION(13, 0, 12)) {
+ ret = smu_v13_0_12_tables_init(smu);
+ if (ret) {
+ smu_driver_table_fini(smu,
+ SMU_DRIVER_TABLE_GPU_METRICS);
+ return ret;
+ }
}
+ smu_table->metrics_table = no_free_ptr(metrics_table);
+ smu_table->driver_pptable = no_free_ptr(driver_pptable);
+
return 0;
}
@@ -570,7 +643,7 @@ static int smu_v13_0_6_select_policy_soc_pstate(struct smu_context *smu,
return -EINVAL;
}
- ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SelectPstatePolicy,
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetThrottlingPolicy,
param, NULL);
if (ret)
@@ -621,13 +694,13 @@ static int smu_v13_0_6_allocate_dpm_context(struct smu_context *smu)
struct smu_dpm_policy *policy;
smu_dpm->dpm_context =
- kzalloc(sizeof(struct smu_13_0_dpm_context), GFP_KERNEL);
+ kzalloc_obj(struct smu_13_0_dpm_context);
if (!smu_dpm->dpm_context)
return -ENOMEM;
smu_dpm->dpm_context_size = sizeof(struct smu_13_0_dpm_context);
smu_dpm->dpm_policies =
- kzalloc(sizeof(struct smu_dpm_policy_ctxt), GFP_KERNEL);
+ kzalloc_obj(struct smu_dpm_policy_ctxt);
if (!smu_dpm->dpm_policies) {
kfree(smu_dpm->dpm_context);
return -ENOMEM;
@@ -672,21 +745,22 @@ static int smu_v13_0_6_init_smc_tables(struct smu_context *smu)
return ret;
}
-static int smu_v13_0_6_get_allowed_feature_mask(struct smu_context *smu,
- uint32_t *feature_mask,
- uint32_t num)
+static int smu_v13_0_6_fini_smc_tables(struct smu_context *smu)
{
- if (num > 2)
- return -EINVAL;
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12))
+ smu_v13_0_12_tables_fini(smu);
+ return smu_v13_0_fini_smc_tables(smu);
+}
- /* pptable will handle the features to enable */
- memset(feature_mask, 0xFF, sizeof(uint32_t) * num);
+static int smu_v13_0_6_init_allowed_features(struct smu_context *smu)
+{
+ smu_feature_list_set_all(smu, SMU_FEATURE_LIST_ALLOWED);
return 0;
}
-static int smu_v13_0_6_get_metrics_table(struct smu_context *smu,
- void *metrics_table, bool bypass_cache)
+int smu_v13_0_6_get_metrics_table(struct smu_context *smu, void *metrics_table,
+ bool bypass_cache)
{
struct smu_table_context *smu_table = &smu->smu_table;
uint32_t table_size = smu_table->tables[SMU_TABLE_SMU_METRICS].size;
@@ -703,8 +777,15 @@ static int smu_v13_0_6_get_metrics_table(struct smu_context *smu,
return ret;
}
- amdgpu_asic_invalidate_hdp(smu->adev, NULL);
- memcpy(smu_table->metrics_table, table->cpu_addr, table_size);
+ amdgpu_hdp_invalidate(smu->adev, NULL);
+ ret = smu_cmn_vram_cpy(smu, smu_table->metrics_table,
+ table->cpu_addr, table_size);
+ if (ret)
+ return ret;
+
+ if (!memchr_inv(smu_table->metrics_table, 0xff,
+ min(16, table_size)))
+ return -EHWPOISON;
smu_table->metrics_time = jiffies;
}
@@ -740,10 +821,8 @@ static ssize_t smu_v13_0_6_get_pm_metrics(struct smu_context *smu,
memset(&pm_metrics->common_header, 0,
sizeof(pm_metrics->common_header));
- if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 6))
- pm_metrics->common_header.mp1_ip_discovery_version = IP_VERSION(13, 0, 6);
- if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 14))
- pm_metrics->common_header.mp1_ip_discovery_version = IP_VERSION(13, 0, 14);
+ pm_metrics->common_header.mp1_ip_discovery_version =
+ amdgpu_ip_version(smu->adev, MP1_HWIP, 0);
pm_metrics->common_header.pmfw_version = pmfw_version;
pm_metrics->common_header.pmmetrics_version = table_version;
pm_metrics->common_header.structure_size =
@@ -752,16 +831,77 @@ static ssize_t smu_v13_0_6_get_pm_metrics(struct smu_context *smu,
return pm_metrics->common_header.structure_size;
}
+static void smu_v13_0_6_fill_static_metrics_table(struct smu_context *smu,
+ StaticMetricsTable_t *static_metrics)
+{
+ struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
+
+ if (!static_metrics->InputTelemetryVoltageInmV) {
+ dev_warn(smu->adev->dev, "Invalid board voltage %d\n",
+ static_metrics->InputTelemetryVoltageInmV);
+ }
+
+ dpm_context->board_volt = static_metrics->InputTelemetryVoltageInmV;
+
+ if (smu_v13_0_6_cap_supported(smu, SMU_CAP(PLDM_VERSION)) &&
+ static_metrics->pldmVersion[0] != 0xFFFFFFFF)
+ smu->adev->firmware.pldm_version =
+ static_metrics->pldmVersion[0];
+}
+
+int smu_v13_0_6_get_static_metrics_table(struct smu_context *smu)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ uint32_t table_size = smu_table->tables[SMU_TABLE_SMU_METRICS].size;
+ struct smu_table *table = &smu_table->driver_table;
+ int ret;
+
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetStaticMetricsTable, NULL);
+ if (ret) {
+ dev_info(smu->adev->dev,
+ "Failed to export static metrics table!\n");
+ return ret;
+ }
+
+ amdgpu_hdp_invalidate(smu->adev, NULL);
+
+ return smu_cmn_vram_cpy(smu, smu_table->metrics_table,
+ table->cpu_addr, table_size);
+}
+
+static void smu_v13_0_6_update_caps(struct smu_context *smu)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct PPTable_t *pptable =
+ (struct PPTable_t *)smu_table->driver_pptable;
+
+ if (smu_v13_0_6_cap_supported(smu, SMU_CAP(FAST_PPT)) &&
+ !pptable->PPT1Max)
+ smu_v13_0_6_cap_clear(smu, SMU_CAP(FAST_PPT));
+}
+
static int smu_v13_0_6_setup_driver_pptable(struct smu_context *smu)
{
struct smu_table_context *smu_table = &smu->smu_table;
- MetricsTableX_t *metrics_x = (MetricsTableX_t *)smu_table->metrics_table;
- MetricsTableA_t *metrics_a = (MetricsTableA_t *)smu_table->metrics_table;
+ StaticMetricsTable_t *static_metrics = (StaticMetricsTable_t *)smu_table->metrics_table;
+ MetricsTableV0_t *metrics_v0 = (MetricsTableV0_t *)smu_table->metrics_table;
+ MetricsTableV1_t *metrics_v1 = (MetricsTableV1_t *)smu_table->metrics_table;
+ MetricsTableV2_t *metrics_v2 = (MetricsTableV2_t *)smu_table->metrics_table;
struct PPTable_t *pptable =
(struct PPTable_t *)smu_table->driver_pptable;
- bool flag = !smu_v13_0_6_cap_supported(smu, SMU_CAP(UNI_METRICS));
- int ret, i, retry = 100;
+ int version = smu_v13_0_6_get_metrics_version(smu);
+ int ret, i, retry = 100, n;
uint32_t table_version;
+ uint16_t max_speed;
+ uint8_t max_width;
+
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12) &&
+ smu_v13_0_6_cap_supported(smu, SMU_CAP(STATIC_METRICS))) {
+ ret = smu_v13_0_12_setup_driver_pptable(smu);
+ if (ret)
+ return ret;
+ goto out;
+ }
/* Store one-time values in driver PPTable */
if (!pptable->Init) {
@@ -771,7 +911,7 @@ static int smu_v13_0_6_setup_driver_pptable(struct smu_context *smu)
return ret;
/* Ensure that metrics have been updated */
- if (GET_METRIC_FIELD(AccumulationCounter, flag))
+ if (GET_METRIC_FIELD(AccumulationCounter, version))
break;
usleep_range(1000, 1100);
@@ -788,33 +928,61 @@ static int smu_v13_0_6_setup_driver_pptable(struct smu_context *smu)
table_version;
pptable->MaxSocketPowerLimit =
- SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketPowerLimit, flag));
+ SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketPowerLimit, version));
pptable->MaxGfxclkFrequency =
- SMUQ10_ROUND(GET_METRIC_FIELD(MaxGfxclkFrequency, flag));
+ SMUQ10_ROUND(GET_METRIC_FIELD(MaxGfxclkFrequency, version));
pptable->MinGfxclkFrequency =
- SMUQ10_ROUND(GET_METRIC_FIELD(MinGfxclkFrequency, flag));
+ SMUQ10_ROUND(GET_METRIC_FIELD(MinGfxclkFrequency, version));
+ max_width = (uint8_t)GET_METRIC_FIELD(XgmiWidth, version);
+ max_speed = (uint16_t)GET_METRIC_FIELD(XgmiBitrate, version);
+ amgpu_xgmi_set_max_speed_width(smu->adev, max_speed, max_width);
for (i = 0; i < 4; ++i) {
pptable->FclkFrequencyTable[i] =
- SMUQ10_ROUND(GET_METRIC_FIELD(FclkFrequencyTable, flag)[i]);
+ SMUQ10_ROUND(GET_METRIC_FIELD(FclkFrequencyTable, version)[i]);
pptable->UclkFrequencyTable[i] =
- SMUQ10_ROUND(GET_METRIC_FIELD(UclkFrequencyTable, flag)[i]);
+ SMUQ10_ROUND(GET_METRIC_FIELD(UclkFrequencyTable, version)[i]);
pptable->SocclkFrequencyTable[i] = SMUQ10_ROUND(
- GET_METRIC_FIELD(SocclkFrequencyTable, flag)[i]);
+ GET_METRIC_FIELD(SocclkFrequencyTable, version)[i]);
pptable->VclkFrequencyTable[i] =
- SMUQ10_ROUND(GET_METRIC_FIELD(VclkFrequencyTable, flag)[i]);
+ SMUQ10_ROUND(GET_METRIC_FIELD(VclkFrequencyTable, version)[i]);
pptable->DclkFrequencyTable[i] =
- SMUQ10_ROUND(GET_METRIC_FIELD(DclkFrequencyTable, flag)[i]);
+ SMUQ10_ROUND(GET_METRIC_FIELD(DclkFrequencyTable, version)[i]);
pptable->LclkFrequencyTable[i] =
- SMUQ10_ROUND(GET_METRIC_FIELD(LclkFrequencyTable, flag)[i]);
+ SMUQ10_ROUND(GET_METRIC_FIELD(LclkFrequencyTable, version)[i]);
}
/* use AID0 serial number by default */
- pptable->PublicSerialNumber_AID = GET_METRIC_FIELD(PublicSerialNumber_AID, flag)[0];
+ pptable->PublicSerialNumber_AID =
+ GET_METRIC_FIELD(PublicSerialNumber_AID, version)[0];
+
+ amdgpu_device_set_uid(smu->adev->uid_info, AMDGPU_UID_TYPE_SOC,
+ 0, pptable->PublicSerialNumber_AID);
+ n = ARRAY_SIZE(metrics_v0->PublicSerialNumber_AID);
+ for (i = 0; i < n; i++) {
+ amdgpu_device_set_uid(
+ smu->adev->uid_info, AMDGPU_UID_TYPE_AID, i,
+ GET_METRIC_FIELD(PublicSerialNumber_AID,
+ version)[i]);
+ }
+ n = ARRAY_SIZE(metrics_v0->PublicSerialNumber_XCD);
+ for (i = 0; i < n; i++) {
+ amdgpu_device_set_uid(
+ smu->adev->uid_info, AMDGPU_UID_TYPE_XCD, i,
+ GET_METRIC_FIELD(PublicSerialNumber_XCD,
+ version)[i]);
+ }
pptable->Init = true;
+ if (smu_v13_0_6_cap_supported(smu, SMU_CAP(STATIC_METRICS))) {
+ ret = smu_v13_0_6_get_static_metrics_table(smu);
+ if (ret)
+ return ret;
+ smu_v13_0_6_fill_static_metrics_table(smu, static_metrics);
+ }
}
-
+out:
+ smu_v13_0_6_update_caps(smu);
return 0;
}
@@ -822,51 +990,50 @@ static int smu_v13_0_6_get_dpm_ultimate_freq(struct smu_context *smu,
enum smu_clk_type clk_type,
uint32_t *min, uint32_t *max)
{
+ struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
struct smu_table_context *smu_table = &smu->smu_table;
struct PPTable_t *pptable =
(struct PPTable_t *)smu_table->driver_pptable;
- uint32_t clock_limit = 0, param;
+ struct smu_dpm_table *dpm_table;
+ uint32_t min_clk, max_clk, param;
int ret = 0, clk_id = 0;
- if (!smu_cmn_clk_dpm_is_enabled(smu, clk_type)) {
+ /* Use dpm tables, if data is already fetched */
+ if (pptable->Init) {
switch (clk_type) {
case SMU_MCLK:
case SMU_UCLK:
- if (pptable->Init)
- clock_limit = pptable->UclkFrequencyTable[0];
+ dpm_table = &dpm_context->dpm_tables.uclk_table;
break;
case SMU_GFXCLK:
case SMU_SCLK:
- if (pptable->Init)
- clock_limit = pptable->MinGfxclkFrequency;
+ dpm_table = &dpm_context->dpm_tables.gfx_table;
break;
case SMU_SOCCLK:
- if (pptable->Init)
- clock_limit = pptable->SocclkFrequencyTable[0];
+ dpm_table = &dpm_context->dpm_tables.soc_table;
break;
case SMU_FCLK:
- if (pptable->Init)
- clock_limit = pptable->FclkFrequencyTable[0];
+ dpm_table = &dpm_context->dpm_tables.fclk_table;
break;
case SMU_VCLK:
- if (pptable->Init)
- clock_limit = pptable->VclkFrequencyTable[0];
+ dpm_table = &dpm_context->dpm_tables.vclk_table;
break;
case SMU_DCLK:
- if (pptable->Init)
- clock_limit = pptable->DclkFrequencyTable[0];
+ dpm_table = &dpm_context->dpm_tables.dclk_table;
break;
default:
- break;
+ return -EINVAL;
}
+ min_clk = SMU_DPM_TABLE_MIN(dpm_table);
+ max_clk = SMU_DPM_TABLE_MAX(dpm_table);
if (min)
- *min = clock_limit;
-
+ *min = min_clk;
if (max)
- *max = clock_limit;
+ *max = max_clk;
- return 0;
+ if (min_clk && max_clk)
+ return 0;
}
if (!(clk_type == SMU_GFXCLK || clk_type == SMU_SCLK)) {
@@ -929,7 +1096,7 @@ static int smu_v13_0_6_set_default_dpm_table(struct smu_context *smu)
{
struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
struct smu_table_context *smu_table = &smu->smu_table;
- struct smu_13_0_dpm_table *dpm_table = NULL;
+ struct smu_dpm_table *dpm_table = NULL;
struct PPTable_t *pptable =
(struct PPTable_t *)smu_table->driver_pptable;
uint32_t gfxclkmin, gfxclkmax, levels;
@@ -965,6 +1132,8 @@ static int smu_v13_0_6_set_default_dpm_table(struct smu_context *smu)
smu_v13_0_6_pm_policy_init(smu);
/* gfxclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.gfx_table;
+ dpm_table->clk_type = SMU_GFXCLK;
+ dpm_table->flags = SMU_DPM_TABLE_FINE_GRAINED;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) {
/* In the case of gfxclk, only fine-grained dpm is honored.
* Get min/max values from FW.
@@ -973,20 +1142,15 @@ static int smu_v13_0_6_set_default_dpm_table(struct smu_context *smu)
&gfxclkmin, &gfxclkmax);
if (ret)
return ret;
-
dpm_table->count = 2;
dpm_table->dpm_levels[0].value = gfxclkmin;
dpm_table->dpm_levels[0].enabled = true;
dpm_table->dpm_levels[1].value = gfxclkmax;
dpm_table->dpm_levels[1].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[1].value;
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = pptable->MinGfxclkFrequency;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
for (j = 0; j < ARRAY_SIZE(dpm_map); j++) {
@@ -999,15 +1163,12 @@ static int smu_v13_0_6_set_default_dpm_table(struct smu_context *smu)
return ret;
}
dpm_table->count = levels;
+ dpm_table->clk_type = dpm_map[j].clk_type;
for (i = 0; i < dpm_table->count; ++i) {
dpm_table->dpm_levels[i].value =
dpm_map[j].freq_table[i];
dpm_table->dpm_levels[i].enabled = true;
-
}
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[levels - 1].value;
-
}
return 0;
@@ -1044,28 +1205,32 @@ static int smu_v13_0_6_check_fw_status(struct smu_context *smu)
static int smu_v13_0_6_populate_umd_state_clk(struct smu_context *smu)
{
struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
- struct smu_13_0_dpm_table *gfx_table =
- &dpm_context->dpm_tables.gfx_table;
- struct smu_13_0_dpm_table *mem_table =
- &dpm_context->dpm_tables.uclk_table;
- struct smu_13_0_dpm_table *soc_table =
- &dpm_context->dpm_tables.soc_table;
+ struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table;
+ struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table;
+ struct smu_dpm_table *soc_table = &dpm_context->dpm_tables.soc_table;
+ struct smu_dpm_table *fclk_table = &dpm_context->dpm_tables.fclk_table;
struct smu_umd_pstate_table *pstate_table = &smu->pstate_table;
- pstate_table->gfxclk_pstate.min = gfx_table->min;
- pstate_table->gfxclk_pstate.peak = gfx_table->max;
- pstate_table->gfxclk_pstate.curr.min = gfx_table->min;
- pstate_table->gfxclk_pstate.curr.max = gfx_table->max;
+ pstate_table->gfxclk_pstate.min = SMU_DPM_TABLE_MIN(gfx_table);
+ pstate_table->gfxclk_pstate.peak = SMU_DPM_TABLE_MAX(gfx_table);
+ pstate_table->gfxclk_pstate.curr.min = SMU_DPM_TABLE_MIN(gfx_table);
+ pstate_table->gfxclk_pstate.curr.max = SMU_DPM_TABLE_MAX(gfx_table);
- pstate_table->uclk_pstate.min = mem_table->min;
- pstate_table->uclk_pstate.peak = mem_table->max;
- pstate_table->uclk_pstate.curr.min = mem_table->min;
- pstate_table->uclk_pstate.curr.max = mem_table->max;
+ pstate_table->uclk_pstate.min = SMU_DPM_TABLE_MIN(mem_table);
+ pstate_table->uclk_pstate.peak = SMU_DPM_TABLE_MAX(mem_table);
+ pstate_table->uclk_pstate.curr.min = SMU_DPM_TABLE_MIN(mem_table);
+ pstate_table->uclk_pstate.curr.max = SMU_DPM_TABLE_MAX(mem_table);
- pstate_table->socclk_pstate.min = soc_table->min;
- pstate_table->socclk_pstate.peak = soc_table->max;
- pstate_table->socclk_pstate.curr.min = soc_table->min;
- pstate_table->socclk_pstate.curr.max = soc_table->max;
+ pstate_table->socclk_pstate.min = SMU_DPM_TABLE_MIN(soc_table);
+ pstate_table->socclk_pstate.peak = SMU_DPM_TABLE_MAX(soc_table);
+ pstate_table->socclk_pstate.curr.min = SMU_DPM_TABLE_MIN(soc_table);
+ pstate_table->socclk_pstate.curr.max = SMU_DPM_TABLE_MAX(soc_table);
+
+ pstate_table->fclk_pstate.min = SMU_DPM_TABLE_MIN(fclk_table);
+ pstate_table->fclk_pstate.peak = SMU_DPM_TABLE_MAX(fclk_table);
+ pstate_table->fclk_pstate.curr.min = SMU_DPM_TABLE_MIN(fclk_table);
+ pstate_table->fclk_pstate.curr.max = SMU_DPM_TABLE_MAX(fclk_table);
+ pstate_table->fclk_pstate.standard = SMU_DPM_TABLE_MIN(fclk_table);
if (gfx_table->count > SMU_13_0_6_UMD_PSTATE_GFXCLK_LEVEL &&
mem_table->count > SMU_13_0_6_UMD_PSTATE_MCLK_LEVEL &&
@@ -1088,31 +1253,6 @@ static int smu_v13_0_6_populate_umd_state_clk(struct smu_context *smu)
return 0;
}
-static int smu_v13_0_6_get_clk_table(struct smu_context *smu,
- struct pp_clock_levels_with_latency *clocks,
- struct smu_13_0_dpm_table *dpm_table)
-{
- int i, count;
-
- count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS :
- dpm_table->count;
- clocks->num_levels = count;
-
- for (i = 0; i < count; i++) {
- clocks->data[i].clocks_in_khz =
- dpm_table->dpm_levels[i].value * 1000;
- clocks->data[i].latency_in_us = 0;
- }
-
- return 0;
-}
-
-static int smu_v13_0_6_freqs_in_same_level(int32_t frequency1,
- int32_t frequency2)
-{
- return (abs(frequency1 - frequency2) <= EPSILON);
-}
-
static uint32_t smu_v13_0_6_get_throttler_status(struct smu_context *smu)
{
struct smu_power_context *smu_power = &smu->smu_power;
@@ -1130,9 +1270,10 @@ static int smu_v13_0_6_get_smu_metrics_data(struct smu_context *smu,
uint32_t *value)
{
struct smu_table_context *smu_table = &smu->smu_table;
- MetricsTableX_t *metrics_x = (MetricsTableX_t *)smu_table->metrics_table;
- MetricsTableA_t *metrics_a = (MetricsTableA_t *)smu_table->metrics_table;
- bool flag = !smu_v13_0_6_cap_supported(smu, SMU_CAP(UNI_METRICS));
+ MetricsTableV0_t *metrics_v0 = (MetricsTableV0_t *)smu_table->metrics_table;
+ MetricsTableV1_t *metrics_v1 = (MetricsTableV1_t *)smu_table->metrics_table;
+ MetricsTableV2_t *metrics_v2 = (MetricsTableV2_t *)smu_table->metrics_table;
+ int version = smu_v13_0_6_get_metrics_version(smu);
struct amdgpu_device *adev = smu->adev;
int ret = 0;
int xcc_id;
@@ -1141,56 +1282,60 @@ static int smu_v13_0_6_get_smu_metrics_data(struct smu_context *smu,
if (ret)
return ret;
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12) &&
+ smu_v13_0_6_cap_supported(smu, SMU_CAP(STATIC_METRICS)))
+ return smu_v13_0_12_get_smu_metrics_data(smu, member, value);
+
/* For clocks with multiple instances, only report the first one */
switch (member) {
case METRICS_CURR_GFXCLK:
case METRICS_AVERAGE_GFXCLK:
if (smu_v13_0_6_cap_supported(smu, SMU_CAP(DPM))) {
xcc_id = GET_INST(GC, 0);
- *value = SMUQ10_ROUND(GET_METRIC_FIELD(GfxclkFrequency, flag)[xcc_id]);
+ *value = SMUQ10_ROUND(GET_METRIC_FIELD(GfxclkFrequency, version)[xcc_id]);
} else {
*value = 0;
}
break;
case METRICS_CURR_SOCCLK:
case METRICS_AVERAGE_SOCCLK:
- *value = SMUQ10_ROUND(GET_METRIC_FIELD(SocclkFrequency, flag)[0]);
+ *value = SMUQ10_ROUND(GET_METRIC_FIELD(SocclkFrequency, version)[0]);
break;
case METRICS_CURR_UCLK:
case METRICS_AVERAGE_UCLK:
- *value = SMUQ10_ROUND(GET_METRIC_FIELD(UclkFrequency, flag));
+ *value = SMUQ10_ROUND(GET_METRIC_FIELD(UclkFrequency, version));
break;
case METRICS_CURR_VCLK:
- *value = SMUQ10_ROUND(GET_METRIC_FIELD(VclkFrequency, flag)[0]);
+ *value = SMUQ10_ROUND(GET_METRIC_FIELD(VclkFrequency, version)[0]);
break;
case METRICS_CURR_DCLK:
- *value = SMUQ10_ROUND(GET_METRIC_FIELD(DclkFrequency, flag)[0]);
+ *value = SMUQ10_ROUND(GET_METRIC_FIELD(DclkFrequency, version)[0]);
break;
case METRICS_CURR_FCLK:
- *value = SMUQ10_ROUND(GET_METRIC_FIELD(FclkFrequency, flag));
+ *value = SMUQ10_ROUND(GET_METRIC_FIELD(FclkFrequency, version));
break;
case METRICS_AVERAGE_GFXACTIVITY:
- *value = SMUQ10_ROUND(GET_METRIC_FIELD(SocketGfxBusy, flag));
+ *value = SMUQ10_ROUND(GET_METRIC_FIELD(SocketGfxBusy, version));
break;
case METRICS_AVERAGE_MEMACTIVITY:
- *value = SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilization, flag));
+ *value = SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilization, version));
break;
case METRICS_CURR_SOCKETPOWER:
- *value = SMUQ10_ROUND(GET_METRIC_FIELD(SocketPower, flag)) << 8;
+ *value = SMUQ10_ROUND(GET_METRIC_FIELD(SocketPower, version)) << 8;
break;
case METRICS_TEMPERATURE_HOTSPOT:
- *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketTemperature, flag)) *
+ *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketTemperature, version)) *
SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
break;
case METRICS_TEMPERATURE_MEM:
- *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxHbmTemperature, flag)) *
+ *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxHbmTemperature, version)) *
SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
break;
/* This is the max of all VRs and not just SOC VR.
* No need to define another data type for the same.
*/
case METRICS_TEMPERATURE_VRSOC:
- *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxVrTemperature, flag)) *
+ *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxVrTemperature, version)) *
SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
break;
default:
@@ -1212,9 +1357,11 @@ static int smu_v13_0_6_get_current_clk_freq_by_table(struct smu_context *smu,
switch (clk_type) {
case SMU_GFXCLK:
+ case SMU_SCLK:
member_type = METRICS_CURR_GFXCLK;
break;
case SMU_UCLK:
+ case SMU_MCLK:
member_type = METRICS_CURR_UCLK;
break;
case SMU_SOCCLK:
@@ -1236,73 +1383,20 @@ static int smu_v13_0_6_get_current_clk_freq_by_table(struct smu_context *smu,
return smu_v13_0_6_get_smu_metrics_data(smu, member_type, value);
}
-static int smu_v13_0_6_print_clks(struct smu_context *smu, char *buf, int size,
- struct smu_13_0_dpm_table *single_dpm_table,
- uint32_t curr_clk, const char *clk_name)
-{
- struct pp_clock_levels_with_latency clocks;
- int i, ret, level = -1;
- uint32_t clk1, clk2;
-
- ret = smu_v13_0_6_get_clk_table(smu, &clocks, single_dpm_table);
- if (ret) {
- dev_err(smu->adev->dev, "Attempt to get %s clk levels failed!",
- clk_name);
- return ret;
- }
-
- if (!clocks.num_levels)
- return -EINVAL;
-
- if (curr_clk < SMU_13_0_6_DSCLK_THRESHOLD) {
- size = sysfs_emit_at(buf, size, "S: %uMhz *\n", curr_clk);
- for (i = 0; i < clocks.num_levels; i++)
- size += sysfs_emit_at(buf, size, "%d: %uMhz\n", i,
- clocks.data[i].clocks_in_khz /
- 1000);
-
- } else {
- if ((clocks.num_levels == 1) ||
- (curr_clk < (clocks.data[0].clocks_in_khz / 1000)))
- level = 0;
- for (i = 0; i < clocks.num_levels; i++) {
- clk1 = clocks.data[i].clocks_in_khz / 1000;
-
- if (i < (clocks.num_levels - 1))
- clk2 = clocks.data[i + 1].clocks_in_khz / 1000;
-
- if (curr_clk == clk1) {
- level = i;
- } else if (curr_clk >= clk1 && curr_clk < clk2) {
- level = (curr_clk - clk1) <= (clk2 - curr_clk) ?
- i :
- i + 1;
- }
-
- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i,
- clk1, (level == i) ? "*" : "");
- }
- }
-
- return size;
-}
-
-static int smu_v13_0_6_print_clk_levels(struct smu_context *smu,
- enum smu_clk_type type, char *buf)
+static int smu_v13_0_6_emit_clk_levels(struct smu_context *smu,
+ enum smu_clk_type type, char *buf,
+ int *offset)
{
- int now, size = 0;
+ int now, size = *offset, start_offset = *offset;
int ret = 0;
struct smu_umd_pstate_table *pstate_table = &smu->pstate_table;
- struct smu_13_0_dpm_table *single_dpm_table;
+ struct smu_dpm_table *single_dpm_table = NULL;
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
struct smu_13_0_dpm_context *dpm_context = NULL;
- uint32_t min_clk, max_clk;
-
- smu_cmn_get_sysfs_buf(&buf, &size);
if (amdgpu_ras_intr_triggered()) {
- size += sysfs_emit_at(buf, size, "unavailable\n");
- return size;
+ sysfs_emit_at(buf, size, "unavailable\n");
+ return -EBUSY;
}
dpm_context = smu_dpm->dpm_context;
@@ -1314,126 +1408,63 @@ static int smu_v13_0_6_print_clk_levels(struct smu_context *smu,
pstate_table->gfxclk_pstate.curr.min,
pstate_table->gfxclk_pstate.curr.max);
break;
- case SMU_SCLK:
- ret = smu_v13_0_6_get_current_clk_freq_by_table(smu, SMU_GFXCLK,
- &now);
- if (ret) {
- dev_err(smu->adev->dev,
- "Attempt to get current gfx clk Failed!");
- return ret;
- }
-
- min_clk = pstate_table->gfxclk_pstate.curr.min;
- max_clk = pstate_table->gfxclk_pstate.curr.max;
-
- if (now < SMU_13_0_6_DSCLK_THRESHOLD) {
- size += sysfs_emit_at(buf, size, "S: %uMhz *\n",
- now);
- size += sysfs_emit_at(buf, size, "0: %uMhz\n",
- min_clk);
- size += sysfs_emit_at(buf, size, "1: %uMhz\n",
- max_clk);
-
- } else if (!smu_v13_0_6_freqs_in_same_level(now, min_clk) &&
- !smu_v13_0_6_freqs_in_same_level(now, max_clk)) {
- size += sysfs_emit_at(buf, size, "0: %uMhz\n",
- min_clk);
- size += sysfs_emit_at(buf, size, "1: %uMhz *\n",
- now);
- size += sysfs_emit_at(buf, size, "2: %uMhz\n",
- max_clk);
- } else {
- size += sysfs_emit_at(buf, size, "0: %uMhz %s\n",
- min_clk,
- smu_v13_0_6_freqs_in_same_level(now, min_clk) ? "*" : "");
- size += sysfs_emit_at(buf, size, "1: %uMhz %s\n",
- max_clk,
- smu_v13_0_6_freqs_in_same_level(now, max_clk) ? "*" : "");
- }
-
- break;
-
case SMU_OD_MCLK:
+ if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(SET_UCLK_MAX)))
+ return -EOPNOTSUPP;
+
size += sysfs_emit_at(buf, size, "%s:\n", "OD_MCLK");
size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n",
pstate_table->uclk_pstate.curr.min,
pstate_table->uclk_pstate.curr.max);
break;
- case SMU_MCLK:
- ret = smu_v13_0_6_get_current_clk_freq_by_table(smu, SMU_UCLK,
- &now);
- if (ret) {
- dev_err(smu->adev->dev,
- "Attempt to get current mclk Failed!");
- return ret;
- }
+ case SMU_OD_FCLK:
+ if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT))
+ return -EOPNOTSUPP;
+ size += sysfs_emit_at(buf, size, "%s:\n", "OD_FCLK");
+ size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n",
+ pstate_table->fclk_pstate.curr.min,
+ pstate_table->fclk_pstate.curr.max);
+ break;
+ case SMU_SCLK:
+ case SMU_GFXCLK:
+ single_dpm_table = &(dpm_context->dpm_tables.gfx_table);
+ break;
+ case SMU_MCLK:
+ case SMU_UCLK:
single_dpm_table = &(dpm_context->dpm_tables.uclk_table);
-
- return smu_v13_0_6_print_clks(smu, buf, size, single_dpm_table,
- now, "mclk");
-
+ break;
case SMU_SOCCLK:
- ret = smu_v13_0_6_get_current_clk_freq_by_table(smu, SMU_SOCCLK,
- &now);
- if (ret) {
- dev_err(smu->adev->dev,
- "Attempt to get current socclk Failed!");
- return ret;
- }
-
single_dpm_table = &(dpm_context->dpm_tables.soc_table);
-
- return smu_v13_0_6_print_clks(smu, buf, size, single_dpm_table,
- now, "socclk");
-
+ break;
case SMU_FCLK:
- ret = smu_v13_0_6_get_current_clk_freq_by_table(smu, SMU_FCLK,
- &now);
- if (ret) {
- dev_err(smu->adev->dev,
- "Attempt to get current fclk Failed!");
- return ret;
- }
-
single_dpm_table = &(dpm_context->dpm_tables.fclk_table);
-
- return smu_v13_0_6_print_clks(smu, buf, size, single_dpm_table,
- now, "fclk");
-
+ break;
case SMU_VCLK:
- ret = smu_v13_0_6_get_current_clk_freq_by_table(smu, SMU_VCLK,
- &now);
- if (ret) {
- dev_err(smu->adev->dev,
- "Attempt to get current vclk Failed!");
- return ret;
- }
-
single_dpm_table = &(dpm_context->dpm_tables.vclk_table);
-
- return smu_v13_0_6_print_clks(smu, buf, size, single_dpm_table,
- now, "vclk");
-
+ break;
case SMU_DCLK:
- ret = smu_v13_0_6_get_current_clk_freq_by_table(smu, SMU_DCLK,
- &now);
+ single_dpm_table = &(dpm_context->dpm_tables.dclk_table);
+ break;
+ default:
+ break;
+ }
+
+ if (single_dpm_table) {
+ ret = smu_v13_0_6_get_current_clk_freq_by_table(smu, type,
+ &now);
if (ret) {
dev_err(smu->adev->dev,
- "Attempt to get current dclk Failed!");
+ "Attempt to get current clk Failed!");
return ret;
}
-
- single_dpm_table = &(dpm_context->dpm_tables.dclk_table);
-
- return smu_v13_0_6_print_clks(smu, buf, size, single_dpm_table,
- now, "dclk");
-
- default:
- break;
+ return smu_cmn_print_dpm_clk_levels(smu, single_dpm_table, now,
+ buf, offset);
}
- return size;
+ *offset += size - start_offset;
+
+ return 0;
}
static int smu_v13_0_6_upload_dpm_level(struct smu_context *smu, bool max,
@@ -1499,7 +1530,7 @@ static int smu_v13_0_6_force_clk_levels(struct smu_context *smu,
enum smu_clk_type type, uint32_t mask)
{
struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
- struct smu_13_0_dpm_table *single_dpm_table = NULL;
+ struct smu_dpm_table *single_dpm_table = NULL;
uint32_t soft_min_level, soft_max_level;
int ret = 0;
@@ -1609,6 +1640,7 @@ static int smu_v13_0_6_read_sensor(struct smu_context *smu,
enum amd_pp_sensors sensor, void *data,
uint32_t *size)
{
+ struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
int ret = 0;
if (amdgpu_ras_intr_triggered())
@@ -1653,6 +1685,31 @@ static int smu_v13_0_6_read_sensor(struct smu_context *smu,
ret = smu_v13_0_get_gfx_vdd(smu, (uint32_t *)data);
*size = 4;
break;
+ case AMDGPU_PP_SENSOR_VDDBOARD:
+ if (smu_v13_0_6_cap_supported(smu, SMU_CAP(BOARD_VOLTAGE))) {
+ *(uint32_t *)data = dpm_context->board_volt;
+ *size = 4;
+ break;
+ } else {
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ case AMDGPU_PP_SENSOR_NODEPOWERLIMIT:
+ case AMDGPU_PP_SENSOR_NODEPOWER:
+ case AMDGPU_PP_SENSOR_GPPTRESIDENCY:
+ case AMDGPU_PP_SENSOR_MAXNODEPOWERLIMIT:
+ ret = smu_v13_0_12_get_npm_data(smu, sensor, (uint32_t *)data);
+ if (ret)
+ return ret;
+ *size = 4;
+ break;
+ case AMDGPU_PP_SENSOR_UBB_POWER:
+ case AMDGPU_PP_SENSOR_UBB_POWER_LIMIT:
+ ret = smu_v13_0_12_get_system_power(smu, sensor, (uint32_t *)data);
+ if (ret)
+ return ret;
+ *size = 4;
+ break;
case AMDGPU_PP_SENSOR_GPU_AVG_POWER:
default:
ret = -EOPNOTSUPP;
@@ -1684,7 +1741,7 @@ static int smu_v13_0_6_get_power_limit(struct smu_context *smu,
if (current_power_limit)
*current_power_limit = power_limit;
if (default_power_limit)
- *default_power_limit = power_limit;
+ *default_power_limit = pptable->MaxSocketPowerLimit;
if (max_power_limit) {
*max_power_limit = pptable->MaxSocketPowerLimit;
@@ -1699,9 +1756,66 @@ static int smu_v13_0_6_set_power_limit(struct smu_context *smu,
enum smu_ppt_limit_type limit_type,
uint32_t limit)
{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct PPTable_t *pptable =
+ (struct PPTable_t *)smu_table->driver_pptable;
+ int ret;
+
+ if (limit_type == SMU_FAST_PPT_LIMIT) {
+ if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(FAST_PPT)))
+ return -EOPNOTSUPP;
+ if (limit > pptable->PPT1Max || limit < pptable->PPT1Min) {
+ dev_err(smu->adev->dev,
+ "New power limit (%d) should be between min %d max %d\n",
+ limit, pptable->PPT1Min, pptable->PPT1Max);
+ return -EINVAL;
+ }
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetFastPptLimit,
+ limit, NULL);
+ if (ret)
+ dev_err(smu->adev->dev, "Set fast PPT limit failed!\n");
+ return ret;
+ }
+
return smu_v13_0_set_power_limit(smu, limit_type, limit);
}
+static int smu_v13_0_6_get_ppt_limit(struct smu_context *smu,
+ uint32_t *ppt_limit,
+ enum smu_ppt_limit_type type,
+ enum smu_ppt_limit_level level)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct PPTable_t *pptable =
+ (struct PPTable_t *)smu_table->driver_pptable;
+ int ret = 0;
+
+ if (type == SMU_FAST_PPT_LIMIT) {
+ if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(FAST_PPT)))
+ return -EOPNOTSUPP;
+ switch (level) {
+ case SMU_PPT_LIMIT_MAX:
+ *ppt_limit = pptable->PPT1Max;
+ break;
+ case SMU_PPT_LIMIT_CURRENT:
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetFastPptLimit, ppt_limit);
+ if (ret)
+ dev_err(smu->adev->dev, "Get fast PPT limit failed!\n");
+ break;
+ case SMU_PPT_LIMIT_DEFAULT:
+ *ppt_limit = pptable->PPT1Default;
+ break;
+ case SMU_PPT_LIMIT_MIN:
+ *ppt_limit = pptable->PPT1Min;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return ret;
+ }
+ return -EOPNOTSUPP;
+}
+
static int smu_v13_0_6_irq_process(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry)
@@ -1882,10 +1996,8 @@ static int smu_v13_0_6_set_performance_level(struct smu_context *smu,
{
struct smu_dpm_context *smu_dpm = &(smu->smu_dpm);
struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context;
- struct smu_13_0_dpm_table *gfx_table =
- &dpm_context->dpm_tables.gfx_table;
- struct smu_13_0_dpm_table *uclk_table =
- &dpm_context->dpm_tables.uclk_table;
+ struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table;
+ struct smu_dpm_table *uclk_table = &dpm_context->dpm_tables.uclk_table;
struct smu_umd_pstate_table *pstate_table = &smu->pstate_table;
int ret;
@@ -1893,7 +2005,8 @@ static int smu_v13_0_6_set_performance_level(struct smu_context *smu,
if ((smu_dpm->dpm_level == AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) &&
(level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM)) {
smu_cmn_send_smc_msg(smu, SMU_MSG_DisableDeterminism, NULL);
- pstate_table->gfxclk_pstate.curr.max = gfx_table->max;
+ pstate_table->gfxclk_pstate.curr.max =
+ SMU_DPM_TABLE_MAX(gfx_table);
}
switch (level) {
@@ -1901,26 +2014,34 @@ static int smu_v13_0_6_set_performance_level(struct smu_context *smu,
return 0;
case AMD_DPM_FORCED_LEVEL_AUTO:
- if ((gfx_table->min != pstate_table->gfxclk_pstate.curr.min) ||
- (gfx_table->max != pstate_table->gfxclk_pstate.curr.max)) {
+ if ((SMU_DPM_TABLE_MIN(gfx_table) !=
+ pstate_table->gfxclk_pstate.curr.min) ||
+ (SMU_DPM_TABLE_MAX(gfx_table) !=
+ pstate_table->gfxclk_pstate.curr.max)) {
ret = smu_v13_0_6_set_gfx_soft_freq_limited_range(
- smu, gfx_table->min, gfx_table->max);
+ smu, SMU_DPM_TABLE_MIN(gfx_table),
+ SMU_DPM_TABLE_MAX(gfx_table));
if (ret)
return ret;
- pstate_table->gfxclk_pstate.curr.min = gfx_table->min;
- pstate_table->gfxclk_pstate.curr.max = gfx_table->max;
+ pstate_table->gfxclk_pstate.curr.min =
+ SMU_DPM_TABLE_MIN(gfx_table);
+ pstate_table->gfxclk_pstate.curr.max =
+ SMU_DPM_TABLE_MAX(gfx_table);
}
- if (uclk_table->max != pstate_table->uclk_pstate.curr.max) {
+ if (SMU_DPM_TABLE_MAX(uclk_table) !=
+ pstate_table->uclk_pstate.curr.max) {
/* Min UCLK is not expected to be changed */
ret = smu_v13_0_set_soft_freq_limited_range(
- smu, SMU_UCLK, 0, uclk_table->max, false);
+ smu, SMU_UCLK, 0, SMU_DPM_TABLE_MAX(uclk_table),
+ false);
if (ret)
return ret;
- pstate_table->uclk_pstate.curr.max = uclk_table->max;
+ pstate_table->uclk_pstate.curr.max =
+ SMU_DPM_TABLE_MAX(uclk_table);
}
- pstate_table->uclk_pstate.custom.max = 0;
+ smu_v13_0_reset_custom_level(smu);
return 0;
case AMD_DPM_FORCED_LEVEL_MANUAL:
@@ -1929,7 +2050,7 @@ static int smu_v13_0_6_set_performance_level(struct smu_context *smu,
break;
}
- return -EINVAL;
+ return -EOPNOTSUPP;
}
static int smu_v13_0_6_set_soft_freq_limited_range(struct smu_context *smu,
@@ -1946,7 +2067,7 @@ static int smu_v13_0_6_set_soft_freq_limited_range(struct smu_context *smu,
int ret = 0;
if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK &&
- clk_type != SMU_UCLK)
+ clk_type != SMU_UCLK && clk_type != SMU_FCLK)
return -EINVAL;
if ((smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) &&
@@ -1954,9 +2075,9 @@ static int smu_v13_0_6_set_soft_freq_limited_range(struct smu_context *smu,
return -EINVAL;
if (smu_dpm->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) {
- if (min >= max) {
+ if (min > max) {
dev_err(smu->adev->dev,
- "Minimum clk should be less than the maximum allowed clock\n");
+ "Minimum clk should be less/equal to the maximum allowed clock\n");
return -EINVAL;
}
@@ -1987,12 +2108,22 @@ static int smu_v13_0_6_set_soft_freq_limited_range(struct smu_context *smu,
pstate_table->uclk_pstate.curr.max = max;
}
+ if (clk_type == SMU_FCLK) {
+ if (max == pstate_table->fclk_pstate.curr.max)
+ return 0;
+
+ ret = smu_v13_0_set_soft_freq_limited_range(smu, SMU_FCLK, 0, max, false);
+ if (!ret)
+ pstate_table->fclk_pstate.curr.max = max;
+ }
+
return ret;
}
if (smu_dpm->dpm_level == AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) {
- if (!max || (max < dpm_context->dpm_tables.gfx_table.min) ||
- (max > dpm_context->dpm_tables.gfx_table.max)) {
+ min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.gfx_table);
+ max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.gfx_table);
+ if (!max || (max < min_clk) || (max > max_clk)) {
dev_warn(
adev->dev,
"Invalid max frequency %d MHz specified for determinism\n",
@@ -2001,10 +2132,8 @@ static int smu_v13_0_6_set_soft_freq_limited_range(struct smu_context *smu,
}
/* Restore default min/max clocks and enable determinism */
- min_clk = dpm_context->dpm_tables.gfx_table.min;
- max_clk = dpm_context->dpm_tables.gfx_table.max;
ret = smu_v13_0_6_set_gfx_soft_freq_limited_range(smu, min_clk,
- max_clk);
+ max_clk);
if (!ret) {
usleep_range(500, 1000);
ret = smu_cmn_send_smc_msg_with_param(
@@ -2029,6 +2158,8 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu,
{
struct smu_dpm_context *smu_dpm = &(smu->smu_dpm);
struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context;
+ struct smu_dpm_table *uclk_table = &dpm_context->dpm_tables.uclk_table;
+ struct smu_dpm_table *fclk_table = &dpm_context->dpm_tables.fclk_table;
struct smu_umd_pstate_table *pstate_table = &smu->pstate_table;
uint32_t min_clk;
uint32_t max_clk;
@@ -2046,14 +2177,14 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu,
"Input parameter number not correct\n");
return -EINVAL;
}
-
+ min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.gfx_table);
+ max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.gfx_table);
if (input[0] == 0) {
- if (input[1] < dpm_context->dpm_tables.gfx_table.min) {
+ if (input[1] < min_clk) {
dev_warn(
smu->adev->dev,
"Minimum GFX clk (%ld) MHz specified is less than the minimum allowed (%d) MHz\n",
- input[1],
- dpm_context->dpm_tables.gfx_table.min);
+ input[1], min_clk);
pstate_table->gfxclk_pstate.custom.min =
pstate_table->gfxclk_pstate.curr.min;
return -EINVAL;
@@ -2061,12 +2192,11 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu,
pstate_table->gfxclk_pstate.custom.min = input[1];
} else if (input[0] == 1) {
- if (input[1] > dpm_context->dpm_tables.gfx_table.max) {
+ if (input[1] > max_clk) {
dev_warn(
smu->adev->dev,
"Maximum GFX clk (%ld) MHz specified is greater than the maximum allowed (%d) MHz\n",
- input[1],
- dpm_context->dpm_tables.gfx_table.max);
+ input[1], max_clk);
pstate_table->gfxclk_pstate.custom.max =
pstate_table->gfxclk_pstate.curr.max;
return -EINVAL;
@@ -2090,18 +2220,18 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu,
"UCLK_LIMITS setting not supported!\n");
return -EOPNOTSUPP;
}
-
+ max_clk =
+ SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.uclk_table);
if (input[0] == 0) {
dev_info(smu->adev->dev,
"Setting min UCLK level is not supported");
return -EINVAL;
} else if (input[0] == 1) {
- if (input[1] > dpm_context->dpm_tables.uclk_table.max) {
+ if (input[1] > max_clk) {
dev_warn(
smu->adev->dev,
"Maximum UCLK (%ld) MHz specified is greater than the maximum allowed (%d) MHz\n",
- input[1],
- dpm_context->dpm_tables.uclk_table.max);
+ input[1], max_clk);
pstate_table->uclk_pstate.custom.max =
pstate_table->uclk_pstate.curr.max;
return -EINVAL;
@@ -2110,6 +2240,40 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu,
pstate_table->uclk_pstate.custom.max = input[1];
}
break;
+ case PP_OD_EDIT_FCLK_TABLE:
+ if (size != 2) {
+ dev_err(smu->adev->dev,
+ "Input parameter number not correct\n");
+ return -EINVAL;
+ }
+
+ if (!smu_cmn_feature_is_enabled(smu,
+ SMU_FEATURE_DPM_FCLK_BIT)) {
+ dev_warn(smu->adev->dev,
+ "FCLK limits setting not supported!\n");
+ return -EOPNOTSUPP;
+ }
+
+ max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.fclk_table);
+ if (input[0] == 0) {
+ dev_info(smu->adev->dev,
+ "Setting min FCLK level is not supported\n");
+ return -EOPNOTSUPP;
+ } else if (input[0] == 1) {
+ if (input[1] > max_clk) {
+ dev_warn(smu->adev->dev,
+ "Maximum FCLK (%ld) MHz specified is greater than the maximum allowed (%d) MHz\n",
+ input[1], max_clk);
+ pstate_table->fclk_pstate.custom.max =
+ pstate_table->fclk_pstate.curr.max;
+ return -EINVAL;
+ }
+
+ pstate_table->fclk_pstate.custom.max = input[1];
+ } else {
+ return -EINVAL;
+ }
+ break;
case PP_OD_RESTORE_DEFAULT_TABLE:
if (size != 0) {
@@ -2118,8 +2282,10 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu,
return -EINVAL;
} else {
/* Use the default frequencies for manual and determinism mode */
- min_clk = dpm_context->dpm_tables.gfx_table.min;
- max_clk = dpm_context->dpm_tables.gfx_table.max;
+ min_clk = SMU_DPM_TABLE_MIN(
+ &dpm_context->dpm_tables.gfx_table);
+ max_clk = SMU_DPM_TABLE_MAX(
+ &dpm_context->dpm_tables.gfx_table);
ret = smu_v13_0_6_set_soft_freq_limited_range(
smu, SMU_GFXCLK, min_clk, max_clk, false);
@@ -2127,13 +2293,28 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu,
if (ret)
return ret;
- min_clk = dpm_context->dpm_tables.uclk_table.min;
- max_clk = dpm_context->dpm_tables.uclk_table.max;
- ret = smu_v13_0_6_set_soft_freq_limited_range(
- smu, SMU_UCLK, min_clk, max_clk, false);
- if (ret)
- return ret;
- pstate_table->uclk_pstate.custom.max = 0;
+ if (SMU_DPM_TABLE_MAX(uclk_table) !=
+ pstate_table->uclk_pstate.curr.max) {
+ min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.uclk_table);
+ max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.uclk_table);
+ ret = smu_v13_0_6_set_soft_freq_limited_range(smu,
+ SMU_UCLK, min_clk,
+ max_clk, false);
+ if (ret)
+ return ret;
+ }
+
+ if (SMU_DPM_TABLE_MAX(fclk_table) !=
+ pstate_table->fclk_pstate.curr.max) {
+ max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.fclk_table);
+ min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.fclk_table);
+ ret = smu_v13_0_6_set_soft_freq_limited_range(smu,
+ SMU_FCLK, min_clk,
+ max_clk, false);
+ if (ret)
+ return ret;
+ }
+ smu_v13_0_reset_custom_level(smu);
}
break;
case PP_OD_COMMIT_DPM_TABLE:
@@ -2159,6 +2340,16 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu,
if (ret)
return ret;
+ if (pstate_table->fclk_pstate.custom.max) {
+ min_clk = pstate_table->fclk_pstate.curr.min;
+ max_clk = pstate_table->fclk_pstate.custom.max;
+ ret = smu_v13_0_6_set_soft_freq_limited_range(smu,
+ SMU_FCLK, min_clk,
+ max_clk, false);
+ if (ret)
+ return ret;
+ }
+
if (!pstate_table->uclk_pstate.custom.max)
return 0;
@@ -2176,14 +2367,14 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu,
}
static int smu_v13_0_6_get_enabled_mask(struct smu_context *smu,
- uint64_t *feature_mask)
+ struct smu_feature_bits *feature_mask)
{
int ret;
ret = smu_cmn_get_enabled_mask(smu, feature_mask);
if (ret == -EIO && !smu_v13_0_6_cap_supported(smu, SMU_CAP(DPM))) {
- *feature_mask = 0;
+ smu_feature_bits_clearall(feature_mask);
ret = 0;
}
@@ -2193,14 +2384,18 @@ static int smu_v13_0_6_get_enabled_mask(struct smu_context *smu,
static bool smu_v13_0_6_is_dpm_running(struct smu_context *smu)
{
int ret;
- uint64_t feature_enabled;
+ struct smu_feature_bits feature_enabled;
+
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12))
+ return smu_v13_0_12_is_dpm_running(smu);
ret = smu_v13_0_6_get_enabled_mask(smu, &feature_enabled);
if (ret)
return false;
- return !!(feature_enabled & SMC_DPM_FEATURE);
+ return smu_feature_bits_test_mask(&feature_enabled,
+ smu_v13_0_6_dpm_features.bits);
}
static int smu_v13_0_6_request_i2c_xfer(struct smu_context *smu,
@@ -2217,13 +2412,15 @@ static int smu_v13_0_6_request_i2c_xfer(struct smu_context *smu,
table_size = smu_table->tables[SMU_TABLE_I2C_COMMANDS].size;
- memcpy(table->cpu_addr, table_data, table_size);
+ ret = smu_cmn_vram_cpy(smu, table->cpu_addr, table_data, table_size);
+ if (ret)
+ return ret;
+
/* Flush hdp cache */
- amdgpu_asic_flush_hdp(adev, NULL);
- ret = smu_cmn_send_smc_msg(smu, SMU_MSG_RequestI2cTransaction,
- NULL);
+ amdgpu_hdp_flush(adev, NULL);
- return ret;
+ return smu_cmn_send_smc_msg(smu, SMU_MSG_RequestI2cTransaction,
+ NULL);
}
static int smu_v13_0_6_i2c_xfer(struct i2c_adapter *i2c_adap,
@@ -2241,7 +2438,7 @@ static int smu_v13_0_6_i2c_xfer(struct i2c_adapter *i2c_adap,
if (!adev->pm.dpm_enabled)
return -EBUSY;
- req = kzalloc(sizeof(*req), GFP_KERNEL);
+ req = kzalloc_obj(*req);
if (!req)
return -ENOMEM;
@@ -2345,10 +2542,10 @@ static int smu_v13_0_6_i2c_control_init(struct smu_context *smu)
control->quirks = &smu_v13_0_6_i2c_control_quirks;
i2c_set_adapdata(control, smu_i2c);
- res = i2c_add_adapter(control);
+ res = devm_i2c_add_adapter(adev->dev, control);
if (res) {
DRM_ERROR("Failed to register hw i2c, err: %d\n", res);
- goto Out_err;
+ return res;
}
}
@@ -2356,27 +2553,12 @@ static int smu_v13_0_6_i2c_control_init(struct smu_context *smu)
adev->pm.fru_eeprom_i2c_bus = &adev->pm.smu_i2c[0].adapter;
return 0;
-Out_err:
- for ( ; i >= 0; i--) {
- struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i];
- struct i2c_adapter *control = &smu_i2c->adapter;
-
- i2c_del_adapter(control);
- }
- return res;
}
static void smu_v13_0_6_i2c_control_fini(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- int i;
-
- for (i = 0; i < MAX_SMU_I2C_BUSES; i++) {
- struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i];
- struct i2c_adapter *control = &smu_i2c->adapter;
- i2c_del_adapter(control);
- }
adev->pm.ras_eeprom_i2c_bus = NULL;
adev->pm.fru_eeprom_i2c_bus = NULL;
}
@@ -2473,87 +2655,213 @@ static int smu_v13_0_6_get_current_pcie_link_speed(struct smu_context *smu)
return pcie_gen_to_speed(speed_level + 1);
}
-static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table)
+static ssize_t smu_v13_0_6_get_xcp_metrics(struct smu_context *smu, int xcp_id,
+ void *table)
{
+ const u8 num_jpeg_rings = AMDGPU_MAX_JPEG_RINGS_4_0_3;
+ int version = smu_v13_0_6_get_metrics_version(smu);
+ struct smu_v13_0_6_partition_metrics *xcp_metrics;
struct smu_table_context *smu_table = &smu->smu_table;
- struct gpu_metrics_v1_7 *gpu_metrics =
- (struct gpu_metrics_v1_7 *)smu_table->gpu_metrics_table;
- bool flag = !smu_v13_0_6_cap_supported(smu, SMU_CAP(UNI_METRICS));
- int ret = 0, xcc_id, inst, i, j, k, idx;
struct amdgpu_device *adev = smu->adev;
- MetricsTableX_t *metrics_x;
- MetricsTableA_t *metrics_a;
+ int ret, inst, i, j, k, idx;
+ MetricsTableV0_t *metrics_v0;
+ MetricsTableV1_t *metrics_v1;
+ MetricsTableV2_t *metrics_v2;
struct amdgpu_xcp *xcp;
- u16 link_width_level;
u32 inst_mask;
bool per_inst;
- metrics_x = kzalloc(max(sizeof(MetricsTableX_t), sizeof(MetricsTableA_t)), GFP_KERNEL);
- ret = smu_v13_0_6_get_metrics_table(smu, metrics_x, true);
- if (ret) {
- kfree(metrics_x);
+ if (!table)
+ return sizeof(*xcp_metrics);
+
+ for_each_xcp(adev->xcp_mgr, xcp, i) {
+ if (xcp->id == xcp_id)
+ break;
+ }
+ if (i == adev->xcp_mgr->num_xcps)
+ return -EINVAL;
+
+ xcp_metrics = (struct smu_v13_0_6_partition_metrics *)table;
+ smu_v13_0_6_partition_metrics_init(xcp_metrics, 1, 1);
+
+ ret = smu_v13_0_6_get_metrics_table(smu, NULL, false);
+ if (ret)
return ret;
+
+ metrics_v0 = (MetricsTableV0_t *)smu_table->metrics_table;
+
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) ==
+ IP_VERSION(13, 0, 12) &&
+ smu_v13_0_6_cap_supported(smu, SMU_CAP(STATIC_METRICS)))
+ return smu_v13_0_12_get_xcp_metrics(smu, xcp, table,
+ metrics_v0);
+
+ metrics_v1 = (MetricsTableV1_t *)smu_table->metrics_table;
+ metrics_v2 = (MetricsTableV2_t *)smu_table->metrics_table;
+
+ per_inst = smu_v13_0_6_cap_supported(smu, SMU_CAP(PER_INST_METRICS));
+
+ amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_VCN, &inst_mask);
+ idx = 0;
+ for_each_inst(k, inst_mask) {
+ /* Both JPEG and VCN has same instances */
+ inst = GET_INST(VCN, k);
+
+ for (j = 0; j < num_jpeg_rings; ++j) {
+ xcp_metrics->jpeg_busy[(idx * num_jpeg_rings) + j] =
+ SMUQ10_ROUND(GET_METRIC_FIELD(
+ JpegBusy,
+ version)[(inst * num_jpeg_rings) + j]);
+ }
+ xcp_metrics->vcn_busy[idx] =
+ SMUQ10_ROUND(GET_METRIC_FIELD(VcnBusy, version)[inst]);
+
+ xcp_metrics->current_vclk0[idx] = SMUQ10_ROUND(
+ GET_METRIC_FIELD(VclkFrequency, version)[inst]);
+ xcp_metrics->current_dclk0[idx] = SMUQ10_ROUND(
+ GET_METRIC_FIELD(DclkFrequency, version)[inst]);
+ xcp_metrics->current_socclk[idx] = SMUQ10_ROUND(
+ GET_METRIC_FIELD(SocclkFrequency, version)[inst]);
+
+ idx++;
}
- metrics_a = (MetricsTableA_t *)metrics_x;
+ xcp_metrics->current_uclk =
+ SMUQ10_ROUND(GET_METRIC_FIELD(UclkFrequency, version));
- smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 7);
+ if (per_inst) {
+ amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_GFX, &inst_mask);
+ idx = 0;
+ for_each_inst(k, inst_mask) {
+ inst = GET_INST(GC, k);
+ xcp_metrics->current_gfxclk[idx] =
+ SMUQ10_ROUND(GET_METRIC_FIELD(GfxclkFrequency,
+ version)[inst]);
+
+ xcp_metrics->gfx_busy_inst[idx] = SMUQ10_ROUND(
+ GET_GPU_METRIC_FIELD(GfxBusy, version)[inst]);
+ xcp_metrics->gfx_busy_acc[idx] = SMUQ10_ROUND(
+ GET_GPU_METRIC_FIELD(GfxBusyAcc,
+ version)[inst]);
+ if (smu_v13_0_6_cap_supported(
+ smu, SMU_CAP(HST_LIMIT_METRICS))) {
+ xcp_metrics->gfx_below_host_limit_ppt_acc
+ [idx] = SMUQ10_ROUND(
+ metrics_v0->GfxclkBelowHostLimitPptAcc
+ [inst]);
+ xcp_metrics->gfx_below_host_limit_thm_acc
+ [idx] = SMUQ10_ROUND(
+ metrics_v0->GfxclkBelowHostLimitThmAcc
+ [inst]);
+ xcp_metrics->gfx_low_utilization_acc
+ [idx] = SMUQ10_ROUND(
+ metrics_v0
+ ->GfxclkLowUtilizationAcc[inst]);
+ xcp_metrics->gfx_below_host_limit_total_acc
+ [idx] = SMUQ10_ROUND(
+ metrics_v0->GfxclkBelowHostLimitTotalAcc
+ [inst]);
+ }
+ idx++;
+ }
+ }
+ xcp_metrics->accumulation_counter = GET_METRIC_FIELD(AccumulationCounter, version);
+ xcp_metrics->firmware_timestamp = GET_METRIC_FIELD(Timestamp, version);
+
+ return sizeof(*xcp_metrics);
+}
+
+static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table)
+{
+ struct smu_v13_0_6_gpu_metrics *gpu_metrics;
+ int version = smu_v13_0_6_get_metrics_version(smu);
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct amdgpu_device *adev = smu->adev;
+ int ret = 0, xcc_id, inst, i, j;
+ MetricsTableV0_t *metrics_v0;
+ MetricsTableV1_t *metrics_v1;
+ MetricsTableV2_t *metrics_v2;
+ u16 link_width_level;
+ u8 num_jpeg_rings;
+ bool per_inst;
+
+ ret = smu_v13_0_6_get_metrics_table(smu, NULL, false);
+ if (ret)
+ return ret;
+
+ metrics_v0 = (MetricsTableV0_t *)smu_table->metrics_table;
+ gpu_metrics = (struct smu_v13_0_6_gpu_metrics *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12) &&
+ smu_v13_0_6_cap_supported(smu, SMU_CAP(STATIC_METRICS))) {
+ smu_v13_0_12_get_gpu_metrics(smu, table, metrics_v0,
+ gpu_metrics);
+ goto fill;
+ }
+
+ metrics_v1 = (MetricsTableV1_t *)smu_table->metrics_table;
+ metrics_v2 = (MetricsTableV2_t *)smu_table->metrics_table;
gpu_metrics->temperature_hotspot =
- SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketTemperature, flag));
+ SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketTemperature, version));
/* Individual HBM stack temperature is not reported */
gpu_metrics->temperature_mem =
- SMUQ10_ROUND(GET_METRIC_FIELD(MaxHbmTemperature, flag));
+ SMUQ10_ROUND(GET_METRIC_FIELD(MaxHbmTemperature, version));
/* Reports max temperature of all voltage rails */
gpu_metrics->temperature_vrsoc =
- SMUQ10_ROUND(GET_METRIC_FIELD(MaxVrTemperature, flag));
+ SMUQ10_ROUND(GET_METRIC_FIELD(MaxVrTemperature, version));
gpu_metrics->average_gfx_activity =
- SMUQ10_ROUND(GET_METRIC_FIELD(SocketGfxBusy, flag));
+ SMUQ10_ROUND(GET_METRIC_FIELD(SocketGfxBusy, version));
gpu_metrics->average_umc_activity =
- SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilization, flag));
+ SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilization, version));
gpu_metrics->mem_max_bandwidth =
- SMUQ10_ROUND(GET_METRIC_FIELD(MaxDramBandwidth, flag));
+ SMUQ10_ROUND(GET_METRIC_FIELD(MaxDramBandwidth, version));
gpu_metrics->curr_socket_power =
- SMUQ10_ROUND(GET_METRIC_FIELD(SocketPower, flag));
+ SMUQ10_ROUND(GET_METRIC_FIELD(SocketPower, version));
/* Energy counter reported in 15.259uJ (2^-16) units */
- gpu_metrics->energy_accumulator = GET_METRIC_FIELD(SocketEnergyAcc, flag);
+ gpu_metrics->energy_accumulator = GET_METRIC_FIELD(SocketEnergyAcc, version);
for (i = 0; i < MAX_GFX_CLKS; i++) {
xcc_id = GET_INST(GC, i);
if (xcc_id >= 0)
gpu_metrics->current_gfxclk[i] =
- SMUQ10_ROUND(GET_METRIC_FIELD(GfxclkFrequency, flag)[xcc_id]);
+ SMUQ10_ROUND(GET_METRIC_FIELD(GfxclkFrequency, version)[xcc_id]);
if (i < MAX_CLKS) {
gpu_metrics->current_socclk[i] =
- SMUQ10_ROUND(GET_METRIC_FIELD(SocclkFrequency, flag)[i]);
+ SMUQ10_ROUND(GET_METRIC_FIELD(SocclkFrequency, version)[i]);
inst = GET_INST(VCN, i);
if (inst >= 0) {
gpu_metrics->current_vclk0[i] =
- SMUQ10_ROUND(GET_METRIC_FIELD(VclkFrequency, flag)[inst]);
+ SMUQ10_ROUND(GET_METRIC_FIELD(VclkFrequency,
+ version)[inst]);
gpu_metrics->current_dclk0[i] =
- SMUQ10_ROUND(GET_METRIC_FIELD(DclkFrequency, flag)[inst]);
+ SMUQ10_ROUND(GET_METRIC_FIELD(DclkFrequency,
+ version)[inst]);
}
}
}
- gpu_metrics->current_uclk = SMUQ10_ROUND(GET_METRIC_FIELD(UclkFrequency, flag));
+ gpu_metrics->current_uclk = SMUQ10_ROUND(GET_METRIC_FIELD(UclkFrequency, version));
/* Total accumulated cycle counter */
- gpu_metrics->accumulation_counter = GET_METRIC_FIELD(AccumulationCounter, flag);
+ gpu_metrics->accumulation_counter = GET_METRIC_FIELD(AccumulationCounter, version);
/* Accumulated throttler residencies */
- gpu_metrics->prochot_residency_acc = GET_METRIC_FIELD(ProchotResidencyAcc, flag);
- gpu_metrics->ppt_residency_acc = GET_METRIC_FIELD(PptResidencyAcc, flag);
- gpu_metrics->socket_thm_residency_acc = GET_METRIC_FIELD(SocketThmResidencyAcc, flag);
- gpu_metrics->vr_thm_residency_acc = GET_METRIC_FIELD(VrThmResidencyAcc, flag);
- gpu_metrics->hbm_thm_residency_acc = GET_METRIC_FIELD(HbmThmResidencyAcc, flag);
+ gpu_metrics->prochot_residency_acc = GET_METRIC_FIELD(ProchotResidencyAcc, version);
+ gpu_metrics->ppt_residency_acc = GET_METRIC_FIELD(PptResidencyAcc, version);
+ gpu_metrics->socket_thm_residency_acc = GET_METRIC_FIELD(SocketThmResidencyAcc, version);
+ gpu_metrics->vr_thm_residency_acc = GET_METRIC_FIELD(VrThmResidencyAcc, version);
+ gpu_metrics->hbm_thm_residency_acc =
+ GET_METRIC_FIELD(HbmThmResidencyAcc, version);
/* Clock Lock Status. Each bit corresponds to each GFXCLK instance */
- gpu_metrics->gfxclk_lock_status = GET_METRIC_FIELD(GfxLockXCDMak, flag) >> GET_INST(GC, 0);
+ gpu_metrics->gfxclk_lock_status = GET_METRIC_FIELD(GfxLockXCDMak,
+ version) >> GET_INST(GC, 0);
if (!(adev->flags & AMD_IS_APU)) {
/*Check smu version, PCIE link speed and width will be reported from pmfw metric
@@ -2561,9 +2869,9 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table
* for pf from registers
*/
if (smu_v13_0_6_cap_supported(smu, SMU_CAP(PCIE_METRICS))) {
- gpu_metrics->pcie_link_width = metrics_x->PCIeLinkWidth;
+ gpu_metrics->pcie_link_width = GET_GPU_METRIC_FIELD(PCIeLinkWidth, version);
gpu_metrics->pcie_link_speed =
- pcie_gen_to_speed(metrics_x->PCIeLinkSpeed);
+ pcie_gen_to_speed(GET_GPU_METRIC_FIELD(PCIeLinkSpeed, version));
} else if (!amdgpu_sriov_vf(adev)) {
link_width_level = smu_v13_0_6_get_current_pcie_link_width_level(smu);
if (link_width_level > MAX_LINK_WIDTH)
@@ -2576,92 +2884,101 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table
}
gpu_metrics->pcie_bandwidth_acc =
- SMUQ10_ROUND(metrics_x->PcieBandwidthAcc[0]);
+ SMUQ10_ROUND(GET_GPU_METRIC_FIELD(PcieBandwidthAcc, version)[0]);
gpu_metrics->pcie_bandwidth_inst =
- SMUQ10_ROUND(metrics_x->PcieBandwidth[0]);
+ SMUQ10_ROUND(GET_GPU_METRIC_FIELD(PcieBandwidth, version)[0]);
gpu_metrics->pcie_l0_to_recov_count_acc =
- metrics_x->PCIeL0ToRecoveryCountAcc;
+ GET_GPU_METRIC_FIELD(PCIeL0ToRecoveryCountAcc, version);
gpu_metrics->pcie_replay_count_acc =
- metrics_x->PCIenReplayAAcc;
+ GET_GPU_METRIC_FIELD(PCIenReplayAAcc, version);
gpu_metrics->pcie_replay_rover_count_acc =
- metrics_x->PCIenReplayARolloverCountAcc;
+ GET_GPU_METRIC_FIELD(PCIenReplayARolloverCountAcc, version);
gpu_metrics->pcie_nak_sent_count_acc =
- metrics_x->PCIeNAKSentCountAcc;
+ GET_GPU_METRIC_FIELD(PCIeNAKSentCountAcc, version);
gpu_metrics->pcie_nak_rcvd_count_acc =
- metrics_x->PCIeNAKReceivedCountAcc;
+ GET_GPU_METRIC_FIELD(PCIeNAKReceivedCountAcc, version);
if (smu_v13_0_6_cap_supported(smu, SMU_CAP(OTHER_END_METRICS)))
gpu_metrics->pcie_lc_perf_other_end_recovery =
- metrics_x->PCIeOtherEndRecoveryAcc;
+ GET_GPU_METRIC_FIELD(PCIeOtherEndRecoveryAcc, version);
}
gpu_metrics->system_clock_counter = ktime_get_boottime_ns();
gpu_metrics->gfx_activity_acc =
- SMUQ10_ROUND(GET_METRIC_FIELD(SocketGfxBusyAcc, flag));
+ SMUQ10_ROUND(GET_METRIC_FIELD(SocketGfxBusyAcc, version));
gpu_metrics->mem_activity_acc =
- SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilizationAcc, flag));
+ SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilizationAcc, version));
for (i = 0; i < NUM_XGMI_LINKS; i++) {
- gpu_metrics->xgmi_read_data_acc[i] =
- SMUQ10_ROUND(GET_METRIC_FIELD(XgmiReadDataSizeAcc, flag)[i]);
- gpu_metrics->xgmi_write_data_acc[i] =
- SMUQ10_ROUND(GET_METRIC_FIELD(XgmiWriteDataSizeAcc, flag)[i]);
+ j = amdgpu_xgmi_get_ext_link(adev, i);
+ if (j < 0 || j >= NUM_XGMI_LINKS)
+ continue;
+ gpu_metrics->xgmi_read_data_acc[j] = SMUQ10_ROUND(
+ GET_METRIC_FIELD(XgmiReadDataSizeAcc, version)[i]);
+ gpu_metrics->xgmi_write_data_acc[j] = SMUQ10_ROUND(
+ GET_METRIC_FIELD(XgmiWriteDataSizeAcc, version)[i]);
ret = amdgpu_get_xgmi_link_status(adev, i);
if (ret >= 0)
- gpu_metrics->xgmi_link_status[i] = ret;
+ gpu_metrics->xgmi_link_status[j] = ret;
}
- gpu_metrics->num_partition = adev->xcp_mgr->num_xcps;
-
per_inst = smu_v13_0_6_cap_supported(smu, SMU_CAP(PER_INST_METRICS));
- for_each_xcp(adev->xcp_mgr, xcp, i) {
- amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_VCN, &inst_mask);
- idx = 0;
- for_each_inst(k, inst_mask) {
- /* Both JPEG and VCN has same instances */
- inst = GET_INST(VCN, k);
-
- for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j) {
- gpu_metrics->xcp_stats[i].jpeg_busy
- [(idx * adev->jpeg.num_jpeg_rings) + j] =
- SMUQ10_ROUND(GET_METRIC_FIELD(JpegBusy, flag)
- [(inst * adev->jpeg.num_jpeg_rings) + j]);
- }
- gpu_metrics->xcp_stats[i].vcn_busy[idx] =
- SMUQ10_ROUND(GET_METRIC_FIELD(VcnBusy, flag)[inst]);
- idx++;
-
- }
-
- if (per_inst) {
- amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_GFX, &inst_mask);
- idx = 0;
- for_each_inst(k, inst_mask) {
- inst = GET_INST(GC, k);
- gpu_metrics->xcp_stats[i].gfx_busy_inst[idx] =
- SMUQ10_ROUND(metrics_x->GfxBusy[inst]);
- gpu_metrics->xcp_stats[i].gfx_busy_acc[idx] =
- SMUQ10_ROUND(metrics_x->GfxBusyAcc[inst]);
-
- if (smu_v13_0_6_cap_supported(
- smu, SMU_CAP(HST_LIMIT_METRICS)))
- gpu_metrics->xcp_stats[i].gfx_below_host_limit_acc[idx] =
- SMUQ10_ROUND(metrics_x->GfxclkBelowHostLimitAcc
- [inst]);
- idx++;
+ num_jpeg_rings = AMDGPU_MAX_JPEG_RINGS_4_0_3;
+ for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) {
+ inst = GET_INST(JPEG, i);
+ for (j = 0; j < num_jpeg_rings; ++j)
+ gpu_metrics->jpeg_busy[(i * num_jpeg_rings) + j] =
+ SMUQ10_ROUND(GET_METRIC_FIELD(
+ JpegBusy,
+ version)[(inst * num_jpeg_rings) + j]);
+ }
+ for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
+ inst = GET_INST(VCN, i);
+ gpu_metrics->vcn_busy[i] =
+ SMUQ10_ROUND(GET_METRIC_FIELD(VcnBusy, version)[inst]);
+ }
+
+ if (per_inst) {
+ for (i = 0; i < NUM_XCC(adev->gfx.xcc_mask); ++i) {
+ inst = GET_INST(GC, i);
+ gpu_metrics->gfx_busy_inst[i] = SMUQ10_ROUND(
+ GET_GPU_METRIC_FIELD(GfxBusy, version)[inst]);
+ gpu_metrics->gfx_busy_acc[i] = SMUQ10_ROUND(
+ GET_GPU_METRIC_FIELD(GfxBusyAcc,
+ version)[inst]);
+ if (smu_v13_0_6_cap_supported(
+ smu, SMU_CAP(HST_LIMIT_METRICS))) {
+ gpu_metrics->gfx_below_host_limit_ppt_acc
+ [i] = SMUQ10_ROUND(
+ metrics_v0->GfxclkBelowHostLimitPptAcc
+ [inst]);
+ gpu_metrics->gfx_below_host_limit_thm_acc
+ [i] = SMUQ10_ROUND(
+ metrics_v0->GfxclkBelowHostLimitThmAcc
+ [inst]);
+ gpu_metrics->gfx_low_utilization_acc
+ [i] = SMUQ10_ROUND(
+ metrics_v0
+ ->GfxclkLowUtilizationAcc[inst]);
+ gpu_metrics->gfx_below_host_limit_total_acc
+ [i] = SMUQ10_ROUND(
+ metrics_v0->GfxclkBelowHostLimitTotalAcc
+ [inst]);
}
}
}
- gpu_metrics->xgmi_link_width = SMUQ10_ROUND(GET_METRIC_FIELD(XgmiWidth, flag));
- gpu_metrics->xgmi_link_speed = SMUQ10_ROUND(GET_METRIC_FIELD(XgmiBitrate, flag));
+ gpu_metrics->xgmi_link_width = GET_METRIC_FIELD(XgmiWidth, version);
+ gpu_metrics->xgmi_link_speed = GET_METRIC_FIELD(XgmiBitrate, version);
- gpu_metrics->firmware_timestamp = GET_METRIC_FIELD(Timestamp, flag);
+ gpu_metrics->firmware_timestamp = GET_METRIC_FIELD(Timestamp, version);
- *table = (void *)gpu_metrics;
- kfree(metrics_x);
+fill:
+ *table = gpu_metrics;
+
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
return sizeof(*gpu_metrics);
}
@@ -2679,24 +2996,22 @@ static void smu_v13_0_6_restore_pci_config(struct smu_context *smu)
static int smu_v13_0_6_mode2_reset(struct smu_context *smu)
{
- int ret = 0, index;
+ struct smu_msg_ctl *ctl = &smu->msg_ctl;
struct amdgpu_device *adev = smu->adev;
+ int ret = 0;
int timeout = 10;
- index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG,
- SMU_MSG_GfxDeviceDriverReset);
- if (index < 0)
- return index;
+ mutex_lock(&ctl->lock);
- mutex_lock(&smu->message_lock);
-
- ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index,
- SMU_RESET_MODE_2);
+ ret = smu_msg_send_async_locked(ctl, SMU_MSG_GfxDeviceDriverReset,
+ SMU_RESET_MODE_2);
+ if (ret)
+ goto out;
/* Reset takes a bit longer, wait for 200ms. */
msleep(200);
- dev_dbg(smu->adev->dev, "restore config space...\n");
+ dev_dbg(adev->dev, "restore config space...\n");
/* Restore the config space saved during init */
amdgpu_device_load_pci_state(adev->pdev);
@@ -2714,9 +3029,9 @@ static int smu_v13_0_6_mode2_reset(struct smu_context *smu)
if (!(adev->flags & AMD_IS_APU))
smu_v13_0_6_restore_pci_config(smu);
- dev_dbg(smu->adev->dev, "wait for reset ack\n");
+ dev_dbg(adev->dev, "wait for reset ack\n");
do {
- ret = smu_cmn_wait_for_response(smu);
+ ret = smu_msg_wait_response(ctl, 0);
/* Wait a bit more time for getting ACK */
if (ret == -ETIME) {
--timeout;
@@ -2730,7 +3045,7 @@ static int smu_v13_0_6_mode2_reset(struct smu_context *smu)
} while (ret == -ETIME && timeout);
out:
- mutex_unlock(&smu->message_lock);
+ mutex_unlock(&ctl->lock);
if (ret)
dev_err(adev->dev, "failed to send mode2 reset, error code %d",
@@ -2828,14 +3143,29 @@ static int smu_v13_0_6_mode1_reset(struct smu_context *smu)
return ret;
}
+static int smu_v13_0_6_link_reset(struct smu_context *smu)
+{
+ int ret = 0;
+
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GfxDeviceDriverReset,
+ SMU_RESET_MODE_4, NULL);
+ return ret;
+}
+
static bool smu_v13_0_6_is_mode1_reset_supported(struct smu_context *smu)
{
return true;
}
-static bool smu_v13_0_6_is_mode2_reset_supported(struct smu_context *smu)
+static inline bool smu_v13_0_6_is_link_reset_supported(struct smu_context *smu)
{
- return true;
+ struct amdgpu_device *adev = smu->adev;
+ int var = (adev->pdev->device & 0xF);
+
+ if (var == 0x0 || var == 0x1 || var == 0x3)
+ return true;
+
+ return false;
}
static int smu_v13_0_6_smu_send_hbm_bad_page_num(struct smu_context *smu,
@@ -2871,11 +3201,31 @@ static int smu_v13_0_6_send_rma_reason(struct smu_context *smu)
return ret;
}
+/**
+ * smu_v13_0_6_reset_sdma_is_supported - Check if SDMA reset is supported
+ * @smu: smu_context pointer
+ *
+ * This function checks if the SMU supports resetting the SDMA engine.
+ * It returns false if the capability is not supported.
+ */
+static bool smu_v13_0_6_reset_sdma_is_supported(struct smu_context *smu)
+{
+ bool ret = true;
+
+ if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(SDMA_RESET))) {
+ dev_info(smu->adev->dev,
+ "SDMA reset capability is not supported\n");
+ ret = false;
+ }
+
+ return ret;
+}
+
static int smu_v13_0_6_reset_sdma(struct smu_context *smu, uint32_t inst_mask)
{
int ret = 0;
- if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(SDMA_RESET)))
+ if (!smu_v13_0_6_reset_sdma_is_supported(smu))
return -EOPNOTSUPP;
ret = smu_cmn_send_smc_msg_with_param(smu,
@@ -2888,6 +3238,67 @@ static int smu_v13_0_6_reset_sdma(struct smu_context *smu, uint32_t inst_mask)
return ret;
}
+static bool smu_v13_0_6_reset_vcn_is_supported(struct smu_context *smu)
+{
+ return smu_v13_0_6_cap_supported(smu, SMU_CAP(VCN_RESET));
+}
+
+static int smu_v13_0_6_reset_vcn(struct smu_context *smu, uint32_t inst_mask)
+{
+ int ret = 0;
+
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ResetVCN, inst_mask, NULL);
+ if (ret)
+ dev_err(smu->adev->dev,
+ "failed to send ResetVCN event with mask 0x%x\n",
+ inst_mask);
+ return ret;
+}
+
+static int smu_v13_0_6_ras_send_msg(struct smu_context *smu, enum smu_message_type msg, uint32_t param, uint32_t *read_arg)
+{
+ struct amdgpu_device *adev = smu->adev;
+ int ret;
+
+ if (amdgpu_sriov_vf(adev))
+ return -EOPNOTSUPP;
+
+ switch (msg) {
+ case SMU_MSG_QueryValidMcaCount:
+ case SMU_MSG_QueryValidMcaCeCount:
+ case SMU_MSG_McaBankDumpDW:
+ case SMU_MSG_McaBankCeDumpDW:
+ case SMU_MSG_ClearMcaOnRead:
+ case SMU_MSG_GetRASTableVersion:
+ case SMU_MSG_GetBadPageCount:
+ case SMU_MSG_GetBadPageMcaAddr:
+ case SMU_MSG_SetTimestamp:
+ case SMU_MSG_GetTimestamp:
+ case SMU_MSG_GetBadPageIpid:
+ case SMU_MSG_EraseRasTable:
+ ret = smu_cmn_send_smc_msg_with_param(smu, msg, param, read_arg);
+ break;
+ default:
+ ret = -EPERM;
+ }
+
+ return ret;
+}
+
+static int smu_v13_0_6_post_init(struct smu_context *smu)
+{
+ if (smu_v13_0_6_is_link_reset_supported(smu))
+ smu_feature_cap_set(smu, SMU_FEATURE_CAP_ID__LINK_RESET);
+
+ if (smu_v13_0_6_reset_sdma_is_supported(smu))
+ smu_feature_cap_set(smu, SMU_FEATURE_CAP_ID__SDMA_RESET);
+
+ if (smu_v13_0_6_reset_vcn_is_supported(smu))
+ smu_feature_cap_set(smu, SMU_FEATURE_CAP_ID__VCN_RESET);
+
+ return 0;
+}
+
static int mca_smu_set_debug_mode(struct amdgpu_device *adev, bool enable)
{
struct smu_context *smu = adev->powerplay.pp_handle;
@@ -3504,13 +3915,42 @@ static const struct aca_smu_funcs smu_v13_0_6_aca_smu_funcs = {
.parse_error_code = aca_smu_parse_error_code,
};
+static void smu_v13_0_6_set_temp_funcs(struct smu_context *smu)
+{
+ smu->smu_temp.temp_funcs = (amdgpu_ip_version(smu->adev, MP1_HWIP, 0)
+ == IP_VERSION(13, 0, 12)) ? &smu_v13_0_12_temp_funcs : NULL;
+}
+
+static int smu_v13_0_6_get_ras_smu_drv(struct smu_context *smu, const struct ras_smu_drv **ras_smu_drv)
+{
+ if (!ras_smu_drv)
+ return -EINVAL;
+
+ if (amdgpu_sriov_vf(smu->adev))
+ return -EOPNOTSUPP;
+
+ if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_HROM_EN_BIT))
+ smu_v13_0_6_cap_set(smu, SMU_CAP(RAS_EEPROM));
+
+ switch (amdgpu_ip_version(smu->adev, MP1_HWIP, 0)) {
+ case IP_VERSION(13, 0, 12):
+ *ras_smu_drv = &smu_v13_0_12_ras_smu_drv;
+ break;
+ default:
+ *ras_smu_drv = NULL;
+ break;
+ }
+
+ return 0;
+}
+
static const struct pptable_funcs smu_v13_0_6_ppt_funcs = {
/* init dpm */
- .get_allowed_feature_mask = smu_v13_0_6_get_allowed_feature_mask,
+ .init_allowed_features = smu_v13_0_6_init_allowed_features,
/* dpm/clk tables */
.set_default_dpm_table = smu_v13_0_6_set_default_dpm_table,
.populate_umd_state_clk = smu_v13_0_6_populate_umd_state_clk,
- .print_clk_levels = smu_v13_0_6_print_clk_levels,
+ .emit_clk_levels = smu_v13_0_6_emit_clk_levels,
.force_clk_levels = smu_v13_0_6_force_clk_levels,
.read_sensor = smu_v13_0_6_read_sensor,
.set_performance_level = smu_v13_0_6_set_performance_level,
@@ -3520,7 +3960,7 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = {
.init_microcode = smu_v13_0_6_init_microcode,
.fini_microcode = smu_v13_0_fini_microcode,
.init_smc_tables = smu_v13_0_6_init_smc_tables,
- .fini_smc_tables = smu_v13_0_fini_smc_tables,
+ .fini_smc_tables = smu_v13_0_6_fini_smc_tables,
.init_power = smu_v13_0_init_power,
.fini_power = smu_v13_0_fini_power,
.check_fw_status = smu_v13_0_6_check_fw_status,
@@ -3530,11 +3970,10 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = {
.set_tool_table_location = smu_v13_0_set_tool_table_location,
.notify_memory_pool_location = smu_v13_0_notify_memory_pool_location,
.system_features_control = smu_v13_0_6_system_features_control,
- .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
- .send_smc_msg = smu_cmn_send_smc_msg,
.get_enabled_mask = smu_v13_0_6_get_enabled_mask,
.feature_is_enabled = smu_cmn_feature_is_enabled,
.set_power_limit = smu_v13_0_6_set_power_limit,
+ .get_ppt_limit = smu_v13_0_6_get_ppt_limit,
.set_xgmi_pstate = smu_v13_0_set_xgmi_pstate,
.register_irq_handler = smu_v13_0_6_register_irq_handler,
.enable_thermal_alert = smu_v13_0_enable_thermal_alert,
@@ -3548,29 +3987,40 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = {
.get_pp_feature_mask = smu_cmn_get_pp_feature_mask,
.get_gpu_metrics = smu_v13_0_6_get_gpu_metrics,
.get_pm_metrics = smu_v13_0_6_get_pm_metrics,
+ .get_xcp_metrics = smu_v13_0_6_get_xcp_metrics,
.get_thermal_temperature_range = smu_v13_0_6_get_thermal_temperature_range,
.mode1_reset_is_support = smu_v13_0_6_is_mode1_reset_supported,
- .mode2_reset_is_support = smu_v13_0_6_is_mode2_reset_supported,
.mode1_reset = smu_v13_0_6_mode1_reset,
.mode2_reset = smu_v13_0_6_mode2_reset,
+ .link_reset = smu_v13_0_6_link_reset,
.wait_for_event = smu_v13_0_wait_for_event,
.i2c_init = smu_v13_0_6_i2c_control_init,
.i2c_fini = smu_v13_0_6_i2c_control_fini,
.send_hbm_bad_pages_num = smu_v13_0_6_smu_send_hbm_bad_page_num,
.send_rma_reason = smu_v13_0_6_send_rma_reason,
.reset_sdma = smu_v13_0_6_reset_sdma,
+ .dpm_reset_vcn = smu_v13_0_6_reset_vcn,
+ .post_init = smu_v13_0_6_post_init,
+ .ras_send_msg = smu_v13_0_6_ras_send_msg,
+ .get_ras_smu_drv = smu_v13_0_6_get_ras_smu_drv,
};
void smu_v13_0_6_set_ppt_funcs(struct smu_context *smu)
{
+ const struct cmn2asic_msg_mapping *message_map;
+
smu->ppt_funcs = &smu_v13_0_6_ppt_funcs;
- smu->message_map = smu_v13_0_6_message_map;
+ message_map = (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12)) ?
+ smu_v13_0_12_message_map : smu_v13_0_6_message_map;
smu->clock_map = smu_v13_0_6_clk_map;
- smu->feature_map = smu_v13_0_6_feature_mask_map;
+ smu->feature_map = (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12)) ?
+ smu_v13_0_12_feature_mask_map : smu_v13_0_6_feature_mask_map;
smu->table_map = smu_v13_0_6_table_map;
- smu->smc_driver_if_version = SMU13_0_6_DRIVER_IF_VERSION;
+ smu->smc_driver_if_version = SMU_IGNORE_IF_VERSION;
smu->smc_fw_caps |= SMU_FW_CAP_RAS_PRI;
- smu_v13_0_set_smu_mailbox_registers(smu);
+ smu_v13_0_init_msg_ctl(smu, message_map);
+ smu_v13_0_6_set_temp_funcs(smu);
amdgpu_mca_smu_init_funcs(smu->adev, &smu_v13_0_6_mca_smu_funcs);
amdgpu_aca_set_smu_funcs(smu->adev, &smu_v13_0_6_aca_smu_funcs);
}
+
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h
index f0fa42a645c0..a150fc88902c 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h
@@ -26,7 +26,259 @@
#define SMU_13_0_6_UMD_PSTATE_GFXCLK_LEVEL 0x2
#define SMU_13_0_6_UMD_PSTATE_SOCCLK_LEVEL 0x4
#define SMU_13_0_6_UMD_PSTATE_MCLK_LEVEL 0x2
+#define SMU_CAP(x) SMU_13_0_6_CAPS_##x
+
+typedef enum {
+/*0*/ METRICS_VERSION_V0 = 0,
+/*1*/ METRICS_VERSION_V1 = 1,
+/*2*/ METRICS_VERSION_V2 = 2,
+
+/*3*/ NUM_METRICS = 3
+} METRICS_LIST_e;
+
+struct PPTable_t {
+ uint32_t MaxSocketPowerLimit;
+ uint32_t MaxGfxclkFrequency;
+ uint32_t MinGfxclkFrequency;
+ uint32_t FclkFrequencyTable[4];
+ uint32_t UclkFrequencyTable[4];
+ uint32_t SocclkFrequencyTable[4];
+ uint32_t VclkFrequencyTable[4];
+ uint32_t DclkFrequencyTable[4];
+ uint32_t LclkFrequencyTable[4];
+ uint32_t MaxLclkDpmRange;
+ uint32_t MinLclkDpmRange;
+ uint64_t PublicSerialNumber_AID;
+ uint32_t MaxNodePowerLimit;
+ uint32_t PPT1Max;
+ uint32_t PPT1Min;
+ uint32_t PPT1Default;
+ bool Init;
+};
+
+enum smu_v13_0_6_caps {
+ SMU_CAP(DPM),
+ SMU_CAP(DPM_POLICY),
+ SMU_CAP(OTHER_END_METRICS),
+ SMU_CAP(SET_UCLK_MAX),
+ SMU_CAP(PCIE_METRICS),
+ SMU_CAP(MCA_DEBUG_MODE),
+ SMU_CAP(PER_INST_METRICS),
+ SMU_CAP(CTF_LIMIT),
+ SMU_CAP(RMA_MSG),
+ SMU_CAP(ACA_SYND),
+ SMU_CAP(SDMA_RESET),
+ SMU_CAP(VCN_RESET),
+ SMU_CAP(STATIC_METRICS),
+ SMU_CAP(HST_LIMIT_METRICS),
+ SMU_CAP(BOARD_VOLTAGE),
+ SMU_CAP(PLDM_VERSION),
+ SMU_CAP(TEMP_METRICS),
+ SMU_CAP(NPM_METRICS),
+ SMU_CAP(RAS_EEPROM),
+ SMU_CAP(FAST_PPT),
+ SMU_CAP(SYSTEM_POWER_METRICS),
+ SMU_CAP(TEMP_AID_XCD_HBM),
+ SMU_CAP(ALL),
+};
+
+#define SMU_13_0_6_NUM_XGMI_LINKS 8
+#define SMU_13_0_6_MAX_GFX_CLKS 8
+#define SMU_13_0_6_MAX_CLKS 4
+#define SMU_13_0_6_MAX_XCC 8
+#define SMU_13_0_6_MAX_VCN 4
+#define SMU_13_0_6_MAX_JPEG 40
+#define SMU_13_0_6_MAX_AID 4
+#define SMU_13_0_6_MAX_HBM_STACKS 8
extern void smu_v13_0_6_set_ppt_funcs(struct smu_context *smu);
+bool smu_v13_0_6_cap_supported(struct smu_context *smu, enum smu_v13_0_6_caps cap);
+int smu_v13_0_6_get_static_metrics_table(struct smu_context *smu);
+int smu_v13_0_6_get_metrics_table(struct smu_context *smu, void *metrics_table,
+ bool bypass_cache);
+
+bool smu_v13_0_12_is_dpm_running(struct smu_context *smu);
+int smu_v13_0_12_get_max_metrics_size(void);
+size_t smu_v13_0_12_get_system_metrics_size(void);
+int smu_v13_0_12_setup_driver_pptable(struct smu_context *smu);
+int smu_v13_0_12_get_smu_metrics_data(struct smu_context *smu,
+ MetricsMember_t member, uint32_t *value);
+ssize_t smu_v13_0_12_get_xcp_metrics(struct smu_context *smu,
+ struct amdgpu_xcp *xcp, void *table,
+ void *smu_metrics);
+int smu_v13_0_12_tables_init(struct smu_context *smu);
+void smu_v13_0_12_tables_fini(struct smu_context *smu);
+int smu_v13_0_12_get_npm_data(struct smu_context *smu,
+ enum amd_pp_sensors sensor,
+ uint32_t *value);
+int smu_v13_0_12_get_system_power(struct smu_context *smu,
+ enum amd_pp_sensors sensor,
+ uint32_t *value);
+extern const struct cmn2asic_mapping smu_v13_0_12_feature_mask_map[];
+extern const struct cmn2asic_msg_mapping smu_v13_0_12_message_map[];
+extern const struct smu_temp_funcs smu_v13_0_12_temp_funcs;
+extern const struct ras_smu_drv smu_v13_0_12_ras_smu_drv;
+
+#if defined(SWSMU_CODE_LAYER_L2)
+#include "smu_cmn.h"
+
+/* SMUv 13.0.6 GPU metrics*/
+#define SMU_13_0_6_METRICS_FIELDS(SMU_SCALAR, SMU_ARRAY) \
+ SMU_SCALAR(SMU_MATTR(TEMPERATURE_HOTSPOT), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(U16), temperature_hotspot); \
+ SMU_SCALAR(SMU_MATTR(TEMPERATURE_MEM), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(U16), temperature_mem); \
+ SMU_SCALAR(SMU_MATTR(TEMPERATURE_VRSOC), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(U16), temperature_vrsoc); \
+ SMU_SCALAR(SMU_MATTR(CURR_SOCKET_POWER), SMU_MUNIT(POWER_1), \
+ SMU_MTYPE(U16), curr_socket_power); \
+ SMU_SCALAR(SMU_MATTR(AVERAGE_GFX_ACTIVITY), SMU_MUNIT(PERCENT), \
+ SMU_MTYPE(U16), average_gfx_activity); \
+ SMU_SCALAR(SMU_MATTR(AVERAGE_UMC_ACTIVITY), SMU_MUNIT(PERCENT), \
+ SMU_MTYPE(U16), average_umc_activity); \
+ SMU_SCALAR(SMU_MATTR(MEM_MAX_BANDWIDTH), SMU_MUNIT(BW_1), \
+ SMU_MTYPE(U64), mem_max_bandwidth); \
+ SMU_SCALAR(SMU_MATTR(ENERGY_ACCUMULATOR), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), energy_accumulator); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_CLOCK_COUNTER), SMU_MUNIT(TIME_1), \
+ SMU_MTYPE(U64), system_clock_counter); \
+ SMU_SCALAR(SMU_MATTR(ACCUMULATION_COUNTER), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), accumulation_counter); \
+ SMU_SCALAR(SMU_MATTR(PROCHOT_RESIDENCY_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U32), prochot_residency_acc); \
+ SMU_SCALAR(SMU_MATTR(PPT_RESIDENCY_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U32), ppt_residency_acc); \
+ SMU_SCALAR(SMU_MATTR(SOCKET_THM_RESIDENCY_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U32), socket_thm_residency_acc); \
+ SMU_SCALAR(SMU_MATTR(VR_THM_RESIDENCY_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U32), vr_thm_residency_acc); \
+ SMU_SCALAR(SMU_MATTR(HBM_THM_RESIDENCY_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U32), hbm_thm_residency_acc); \
+ SMU_SCALAR(SMU_MATTR(GFXCLK_LOCK_STATUS), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U32), gfxclk_lock_status); \
+ SMU_SCALAR(SMU_MATTR(PCIE_LINK_WIDTH), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U16), pcie_link_width); \
+ SMU_SCALAR(SMU_MATTR(PCIE_LINK_SPEED), SMU_MUNIT(SPEED_2), \
+ SMU_MTYPE(U16), pcie_link_speed); \
+ SMU_SCALAR(SMU_MATTR(XGMI_LINK_WIDTH), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U16), xgmi_link_width); \
+ SMU_SCALAR(SMU_MATTR(XGMI_LINK_SPEED), SMU_MUNIT(SPEED_1), \
+ SMU_MTYPE(U16), xgmi_link_speed); \
+ SMU_SCALAR(SMU_MATTR(GFX_ACTIVITY_ACC), SMU_MUNIT(PERCENT), \
+ SMU_MTYPE(U32), gfx_activity_acc); \
+ SMU_SCALAR(SMU_MATTR(MEM_ACTIVITY_ACC), SMU_MUNIT(PERCENT), \
+ SMU_MTYPE(U32), mem_activity_acc); \
+ SMU_SCALAR(SMU_MATTR(PCIE_BANDWIDTH_ACC), SMU_MUNIT(PERCENT), \
+ SMU_MTYPE(U64), pcie_bandwidth_acc); \
+ SMU_SCALAR(SMU_MATTR(PCIE_BANDWIDTH_INST), SMU_MUNIT(BW_1), \
+ SMU_MTYPE(U64), pcie_bandwidth_inst); \
+ SMU_SCALAR(SMU_MATTR(PCIE_L0_TO_RECOV_COUNT_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), pcie_l0_to_recov_count_acc); \
+ SMU_SCALAR(SMU_MATTR(PCIE_REPLAY_COUNT_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), pcie_replay_count_acc); \
+ SMU_SCALAR(SMU_MATTR(PCIE_REPLAY_ROVER_COUNT_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), pcie_replay_rover_count_acc); \
+ SMU_SCALAR(SMU_MATTR(PCIE_NAK_SENT_COUNT_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U32), pcie_nak_sent_count_acc); \
+ SMU_SCALAR(SMU_MATTR(PCIE_NAK_RCVD_COUNT_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U32), pcie_nak_rcvd_count_acc); \
+ SMU_ARRAY(SMU_MATTR(XGMI_READ_DATA_ACC), SMU_MUNIT(DATA_1), \
+ SMU_MTYPE(U64), xgmi_read_data_acc, \
+ SMU_13_0_6_NUM_XGMI_LINKS); \
+ SMU_ARRAY(SMU_MATTR(XGMI_WRITE_DATA_ACC), SMU_MUNIT(DATA_1), \
+ SMU_MTYPE(U64), xgmi_write_data_acc, \
+ SMU_13_0_6_NUM_XGMI_LINKS); \
+ SMU_ARRAY(SMU_MATTR(XGMI_LINK_STATUS), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U16), xgmi_link_status, \
+ SMU_13_0_6_NUM_XGMI_LINKS); \
+ SMU_SCALAR(SMU_MATTR(FIRMWARE_TIMESTAMP), SMU_MUNIT(TIME_2), \
+ SMU_MTYPE(U64), firmware_timestamp); \
+ SMU_ARRAY(SMU_MATTR(CURRENT_GFXCLK), SMU_MUNIT(CLOCK_1), \
+ SMU_MTYPE(U16), current_gfxclk, SMU_13_0_6_MAX_GFX_CLKS); \
+ SMU_ARRAY(SMU_MATTR(CURRENT_SOCCLK), SMU_MUNIT(CLOCK_1), \
+ SMU_MTYPE(U16), current_socclk, SMU_13_0_6_MAX_CLKS); \
+ SMU_ARRAY(SMU_MATTR(CURRENT_VCLK0), SMU_MUNIT(CLOCK_1), \
+ SMU_MTYPE(U16), current_vclk0, SMU_13_0_6_MAX_CLKS); \
+ SMU_ARRAY(SMU_MATTR(CURRENT_DCLK0), SMU_MUNIT(CLOCK_1), \
+ SMU_MTYPE(U16), current_dclk0, SMU_13_0_6_MAX_CLKS); \
+ SMU_SCALAR(SMU_MATTR(CURRENT_UCLK), SMU_MUNIT(CLOCK_1), \
+ SMU_MTYPE(U16), current_uclk); \
+ SMU_SCALAR(SMU_MATTR(PCIE_LC_PERF_OTHER_END_RECOVERY), \
+ SMU_MUNIT(NONE), SMU_MTYPE(U32), \
+ pcie_lc_perf_other_end_recovery); \
+ SMU_ARRAY(SMU_MATTR(GFX_BUSY_INST), SMU_MUNIT(PERCENT), \
+ SMU_MTYPE(U32), gfx_busy_inst, SMU_13_0_6_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(JPEG_BUSY), SMU_MUNIT(PERCENT), SMU_MTYPE(U16), \
+ jpeg_busy, SMU_13_0_6_MAX_JPEG); \
+ SMU_ARRAY(SMU_MATTR(VCN_BUSY), SMU_MUNIT(PERCENT), SMU_MTYPE(U16), \
+ vcn_busy, SMU_13_0_6_MAX_VCN); \
+ SMU_ARRAY(SMU_MATTR(GFX_BUSY_ACC), SMU_MUNIT(PERCENT), SMU_MTYPE(U64), \
+ gfx_busy_acc, SMU_13_0_6_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_PPT_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), gfx_below_host_limit_ppt_acc, \
+ SMU_13_0_6_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_THM_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), gfx_below_host_limit_thm_acc, \
+ SMU_13_0_6_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(GFX_LOW_UTILIZATION_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), gfx_low_utilization_acc, \
+ SMU_13_0_6_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_TOTAL_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), gfx_below_host_limit_total_acc, \
+ SMU_13_0_6_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(TEMPERATURE_HBM), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(U16), temperature_hbm, \
+ SMU_13_0_6_MAX_HBM_STACKS); \
+ SMU_ARRAY(SMU_MATTR(TEMPERATURE_AID), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(U16), temperature_aid, SMU_13_0_6_MAX_AID); \
+ SMU_ARRAY(SMU_MATTR(TEMPERATURE_XCD), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(U16), temperature_xcd, SMU_13_0_6_MAX_XCC); \
+
+
+DECLARE_SMU_METRICS_CLASS(smu_v13_0_6_gpu_metrics, SMU_13_0_6_METRICS_FIELDS);
+void smu_v13_0_12_get_gpu_metrics(struct smu_context *smu, void **table,
+ void *smu_metrics,
+ struct smu_v13_0_6_gpu_metrics *gpu_metrics);
+
+#define SMU_13_0_6_PARTITION_METRICS_FIELDS(SMU_SCALAR, SMU_ARRAY) \
+ SMU_ARRAY(SMU_MATTR(CURRENT_GFXCLK), SMU_MUNIT(CLOCK_1), \
+ SMU_MTYPE(U16), current_gfxclk, SMU_13_0_6_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(CURRENT_SOCCLK), SMU_MUNIT(CLOCK_1), \
+ SMU_MTYPE(U16), current_socclk, SMU_13_0_6_MAX_CLKS); \
+ SMU_ARRAY(SMU_MATTR(CURRENT_VCLK0), SMU_MUNIT(CLOCK_1), \
+ SMU_MTYPE(U16), current_vclk0, SMU_13_0_6_MAX_CLKS); \
+ SMU_ARRAY(SMU_MATTR(CURRENT_DCLK0), SMU_MUNIT(CLOCK_1), \
+ SMU_MTYPE(U16), current_dclk0, SMU_13_0_6_MAX_CLKS); \
+ SMU_SCALAR(SMU_MATTR(CURRENT_UCLK), SMU_MUNIT(CLOCK_1), \
+ SMU_MTYPE(U16), current_uclk); \
+ SMU_ARRAY(SMU_MATTR(GFX_BUSY_INST), SMU_MUNIT(PERCENT), \
+ SMU_MTYPE(U32), gfx_busy_inst, SMU_13_0_6_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(JPEG_BUSY), SMU_MUNIT(PERCENT), SMU_MTYPE(U16), \
+ jpeg_busy, SMU_13_0_6_MAX_JPEG); \
+ SMU_ARRAY(SMU_MATTR(VCN_BUSY), SMU_MUNIT(PERCENT), SMU_MTYPE(U16), \
+ vcn_busy, SMU_13_0_6_MAX_VCN); \
+ SMU_ARRAY(SMU_MATTR(GFX_BUSY_ACC), SMU_MUNIT(PERCENT), SMU_MTYPE(U64), \
+ gfx_busy_acc, SMU_13_0_6_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_PPT_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), gfx_below_host_limit_ppt_acc, \
+ SMU_13_0_6_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_THM_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), gfx_below_host_limit_thm_acc, \
+ SMU_13_0_6_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(GFX_LOW_UTILIZATION_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), gfx_low_utilization_acc, \
+ SMU_13_0_6_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_TOTAL_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), gfx_below_host_limit_total_acc, \
+ SMU_13_0_6_MAX_XCC); \
+ SMU_SCALAR(SMU_MATTR(ACCUMULATION_COUNTER), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), accumulation_counter); \
+ SMU_SCALAR(SMU_MATTR(FIRMWARE_TIMESTAMP), SMU_MUNIT(TIME_2), \
+ SMU_MTYPE(U64), firmware_timestamp);
+
+DECLARE_SMU_METRICS_CLASS(smu_v13_0_6_partition_metrics,
+ SMU_13_0_6_PARTITION_METRICS_FIELDS);
+
+#endif /* SWSMU_CODE_LAYER_L2 */
#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
index 55ef18517b0f..42c9ceeb4f7d 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
@@ -59,19 +59,36 @@
#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c))
-#define FEATURE_MASK(feature) (1ULL << feature)
-#define SMC_DPM_FEATURE ( \
- FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_LINK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_FCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT))
+static void smu_v13_0_7_get_od_setting_limits(struct smu_context *smu,
+ int od_feature_bit,
+ int32_t *min, int32_t *max);
+
+static const struct smu_feature_bits smu_v13_0_7_dpm_features = {
+ .bits = {
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_LINK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_MP0CLK_BIT)
+ }
+};
#define smnMP1_FIRMWARE_FLAGS_SMU_13_0_7 0x3b10028
#define MP0_MP1_DATA_REGION_SIZE_COMBOPPTABLE 0x4000
+#define mmMP1_SMN_C2PMSG_75 0x028b
+#define mmMP1_SMN_C2PMSG_75_BASE_IDX 0
+
+#define mmMP1_SMN_C2PMSG_53 0x0275
+#define mmMP1_SMN_C2PMSG_53_BASE_IDX 0
+
+#define mmMP1_SMN_C2PMSG_54 0x0276
+#define mmMP1_SMN_C2PMSG_54_BASE_IDX 0
+
+#define DEBUGSMC_MSG_Mode1Reset 2
+
#define PP_OD_FEATURE_GFXCLK_FMIN 0
#define PP_OD_FEATURE_GFXCLK_FMAX 1
#define PP_OD_FEATURE_UCLK_FMIN 2
@@ -265,71 +282,67 @@ static const uint8_t smu_v13_0_7_throttler_map[] = {
};
static int
-smu_v13_0_7_get_allowed_feature_mask(struct smu_context *smu,
- uint32_t *feature_mask, uint32_t num)
+smu_v13_0_7_init_allowed_features(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- if (num > 2)
- return -EINVAL;
-
- memset(feature_mask, 0, sizeof(uint32_t) * num);
+ smu_feature_list_clear_all(smu, SMU_FEATURE_LIST_ALLOWED);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_FW_DATA_READ_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_FW_DATA_READ_BIT);
if (adev->pm.pp_feature & PP_SCLK_DPM_MASK) {
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_IMU_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_GFX_POWER_OPTIMIZER_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_GFXCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFX_IMU_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_GFX_POWER_OPTIMIZER_BIT);
}
if (adev->pm.pp_feature & PP_GFXOFF_MASK)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFXOFF_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFXOFF_BIT);
if (adev->pm.pp_feature & PP_MCLK_DPM_MASK) {
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_UCLK_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_FCLK_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_VMEMP_SCALING_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_VDDIO_MEM_SCALING_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_UCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_FCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_VMEMP_SCALING_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_VDDIO_MEM_SCALING_BIT);
}
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_SOCCLK_BIT);
if (adev->pm.pp_feature & PP_PCIE_DPM_MASK)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_LINK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_LINK_BIT);
if (adev->pm.pp_feature & PP_SCLK_DEEP_SLEEP_MASK)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_GFXCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_GFXCLK_BIT);
if (adev->pm.pp_feature & PP_ULV_MASK)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_ULV_BIT);
-
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_LCLK_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_MM_DPM_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_VCN_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_FCLK_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DF_CSTATE_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_THROTTLERS_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_VR0HOT_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_FW_CTF_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_FAN_CONTROL_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_SOCCLK_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFXCLK_SPREAD_SPECTRUM_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_MEM_TEMP_READ_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_FW_DSTATE_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_SOC_MPCLK_DS_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_BACO_MPCLK_DS_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_PCC_DFLL_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_SOC_CG_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_BACO_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFX_ULV_BIT);
+
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_LCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_MP0CLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_MM_DPM_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_VCN_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_FCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DF_CSTATE_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_THROTTLERS_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_VR0HOT_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_FW_CTF_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_FAN_CONTROL_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_SOCCLK_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFXCLK_SPREAD_SPECTRUM_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_MEM_TEMP_READ_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_FW_DSTATE_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_SOC_MPCLK_DS_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_BACO_MPCLK_DS_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFX_PCC_DFLL_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_SOC_CG_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_BACO_BIT);
if (adev->pm.pp_feature & PP_DCEFCLK_DPM_MASK)
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_DCN_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_DCN_BIT);
if ((adev->pg_flags & AMD_PG_SUPPORT_ATHUB) &&
(adev->pg_flags & AMD_PG_SUPPORT_MMHUB))
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ATHUB_MMHUB_PG_BIT);
+ smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_ATHUB_MMHUB_PG_BIT);
return 0;
}
@@ -497,6 +510,7 @@ static int smu_v13_0_7_tables_init(struct smu_context *smu)
{
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_table *tables = smu_table->tables;
+ int ret;
SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
@@ -520,24 +534,25 @@ static int smu_v13_0_7_tables_init(struct smu_context *smu)
sizeof(WifiBandEntryTable_t), PAGE_SIZE,
AMDGPU_GEM_DOMAIN_VRAM);
- smu_table->metrics_table = kzalloc(sizeof(SmuMetricsExternal_t), GFP_KERNEL);
+ smu_table->metrics_table = kzalloc_obj(SmuMetricsExternal_t);
if (!smu_table->metrics_table)
goto err0_out;
smu_table->metrics_time = 0;
- smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_3);
- smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
- if (!smu_table->gpu_metrics_table)
+ ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS,
+ sizeof(struct gpu_metrics_v1_3),
+ SMU_GPU_METRICS_CACHE_INTERVAL);
+ if (ret)
goto err1_out;
- smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL);
+ smu_table->watermarks_table = kzalloc_obj(Watermarks_t);
if (!smu_table->watermarks_table)
goto err2_out;
return 0;
err2_out:
- kfree(smu_table->gpu_metrics_table);
+ smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS);
err1_out:
kfree(smu_table->metrics_table);
err0_out:
@@ -548,8 +563,7 @@ static int smu_v13_0_7_allocate_dpm_context(struct smu_context *smu)
{
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
- smu_dpm->dpm_context = kzalloc(sizeof(struct smu_13_0_dpm_context),
- GFP_KERNEL);
+ smu_dpm->dpm_context = kzalloc_obj(struct smu_13_0_dpm_context);
if (!smu_dpm->dpm_context)
return -ENOMEM;
@@ -578,13 +592,12 @@ static int smu_v13_0_7_set_default_dpm_table(struct smu_context *smu)
struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
PPTable_t *driver_ppt = smu->smu_table.driver_pptable;
SkuTable_t *skutable = &driver_ppt->SkuTable;
- struct smu_13_0_dpm_table *dpm_table;
- struct smu_13_0_pcie_table *pcie_table;
- uint32_t link_level;
+ struct smu_dpm_table *dpm_table;
int ret = 0;
/* socclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.soc_table;
+ dpm_table->clk_type = SMU_SOCCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
ret = smu_v13_0_set_single_dpm_table(smu,
SMU_SOCCLK,
@@ -595,12 +608,11 @@ static int smu_v13_0_7_set_default_dpm_table(struct smu_context *smu)
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.socclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* gfxclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.gfx_table;
+ dpm_table->clk_type = SMU_GFXCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) {
ret = smu_v13_0_set_single_dpm_table(smu,
SMU_GFXCLK,
@@ -613,18 +625,16 @@ static int smu_v13_0_7_set_default_dpm_table(struct smu_context *smu)
skutable->DriverReportedClocks.GameClockAc)) {
dpm_table->dpm_levels[dpm_table->count - 1].value =
skutable->DriverReportedClocks.GameClockAc;
- dpm_table->max = skutable->DriverReportedClocks.GameClockAc;
}
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* uclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.uclk_table;
+ dpm_table->clk_type = SMU_UCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
ret = smu_v13_0_set_single_dpm_table(smu,
SMU_UCLK,
@@ -635,12 +645,11 @@ static int smu_v13_0_7_set_default_dpm_table(struct smu_context *smu)
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.uclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* fclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.fclk_table;
+ dpm_table->clk_type = SMU_FCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT)) {
ret = smu_v13_0_set_single_dpm_table(smu,
SMU_FCLK,
@@ -651,12 +660,11 @@ static int smu_v13_0_7_set_default_dpm_table(struct smu_context *smu)
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.fclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* vclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.vclk_table;
+ dpm_table->clk_type = SMU_VCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_VCLK_BIT)) {
ret = smu_v13_0_set_single_dpm_table(smu,
SMU_VCLK,
@@ -667,12 +675,11 @@ static int smu_v13_0_7_set_default_dpm_table(struct smu_context *smu)
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.vclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* dclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.dclk_table;
+ dpm_table->clk_type = SMU_DCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCLK_BIT)) {
ret = smu_v13_0_set_single_dpm_table(smu,
SMU_DCLK,
@@ -683,30 +690,11 @@ static int smu_v13_0_7_set_default_dpm_table(struct smu_context *smu)
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
- }
-
- /* lclk dpm table setup */
- pcie_table = &dpm_context->dpm_tables.pcie_table;
- pcie_table->num_of_link_levels = 0;
- for (link_level = 0; link_level < NUM_LINK_LEVELS; link_level++) {
- if (!skutable->PcieGenSpeed[link_level] &&
- !skutable->PcieLaneCount[link_level] &&
- !skutable->LclkFreq[link_level])
- continue;
-
- pcie_table->pcie_gen[pcie_table->num_of_link_levels] =
- skutable->PcieGenSpeed[link_level];
- pcie_table->pcie_lane[pcie_table->num_of_link_levels] =
- skutable->PcieLaneCount[link_level];
- pcie_table->clk_freq[pcie_table->num_of_link_levels] =
- skutable->LclkFreq[link_level];
- pcie_table->num_of_link_levels++;
}
/* dcefclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.dcef_table;
+ dpm_table->clk_type = SMU_DCEFCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCN_BIT)) {
ret = smu_v13_0_set_single_dpm_table(smu,
SMU_DCEFCLK,
@@ -717,8 +705,6 @@ static int smu_v13_0_7_set_default_dpm_table(struct smu_context *smu)
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
return 0;
@@ -727,13 +713,14 @@ static int smu_v13_0_7_set_default_dpm_table(struct smu_context *smu)
static bool smu_v13_0_7_is_dpm_running(struct smu_context *smu)
{
int ret = 0;
- uint64_t feature_enabled;
+ struct smu_feature_bits feature_enabled;
ret = smu_cmn_get_enabled_mask(smu, &feature_enabled);
if (ret)
return false;
- return !!(feature_enabled & SMC_DPM_FEATURE);
+ return smu_feature_bits_test_mask(&feature_enabled,
+ smu_v13_0_7_dpm_features.bits);
}
static uint32_t smu_v13_0_7_get_throttler_status(SmuMetrics_t *metrics)
@@ -796,17 +783,21 @@ static int smu_v13_0_7_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->AverageGfxclkFrequencyPreDs;
break;
case METRICS_AVERAGE_FCLK:
- if (metrics->AverageUclkActivity <= SMU_13_0_7_BUSY_THRESHOLD)
+ if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_7_BUSY_THRESHOLD)
*value = metrics->AverageFclkFrequencyPostDs;
else
*value = metrics->AverageFclkFrequencyPreDs;
break;
case METRICS_AVERAGE_UCLK:
- if (metrics->AverageUclkActivity <= SMU_13_0_7_BUSY_THRESHOLD)
+ if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_7_BUSY_THRESHOLD)
*value = metrics->AverageMemclkFrequencyPostDs;
else
*value = metrics->AverageMemclkFrequencyPreDs;
break;
+ case METRICS_AVERAGE_VCNACTIVITY:
+ *value = max(metrics->Vcn0ActivityPercentage,
+ metrics->Vcn1ActivityPercentage);
+ break;
case METRICS_AVERAGE_VCLK:
*value = metrics->AverageVclk0Frequency;
break;
@@ -823,7 +814,7 @@ static int smu_v13_0_7_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->AverageGfxActivity;
break;
case METRICS_AVERAGE_MEMACTIVITY:
- *value = metrics->AverageUclkActivity;
+ *value = smu_safe_u16_nn(metrics->AverageUclkActivity);
break;
case METRICS_AVERAGE_SOCKETPOWER:
*value = metrics->AverageSocketPower << 8;
@@ -881,7 +872,7 @@ static int smu_v13_0_7_get_dpm_ultimate_freq(struct smu_context *smu,
{
struct smu_13_0_dpm_context *dpm_context =
smu->smu_dpm.dpm_context;
- struct smu_13_0_dpm_table *dpm_table;
+ struct smu_dpm_table *dpm_table;
switch (clk_type) {
case SMU_MCLK:
@@ -918,9 +909,9 @@ static int smu_v13_0_7_get_dpm_ultimate_freq(struct smu_context *smu,
}
if (min)
- *min = dpm_table->min;
+ *min = SMU_DPM_TABLE_MIN(dpm_table);
if (max)
- *max = dpm_table->max;
+ *max = SMU_DPM_TABLE_MAX(dpm_table);
return 0;
}
@@ -951,6 +942,12 @@ static int smu_v13_0_7_read_sensor(struct smu_context *smu,
(uint32_t *)data);
*size = 4;
break;
+ case AMDGPU_PP_SENSOR_VCN_LOAD:
+ ret = smu_v13_0_7_get_smu_metrics_data(smu,
+ METRICS_AVERAGE_VCNACTIVITY,
+ (uint32_t *)data);
+ *size = 4;
+ break;
case AMDGPU_PP_SENSOR_GPU_AVG_POWER:
ret = smu_v13_0_7_get_smu_metrics_data(smu,
METRICS_AVERAGE_SOCKETPOWER,
@@ -1060,8 +1057,35 @@ static bool smu_v13_0_7_is_od_feature_supported(struct smu_context *smu,
PPTable_t *pptable = smu->smu_table.driver_pptable;
const OverDriveLimits_t * const overdrive_upperlimits =
&pptable->SkuTable.OverDriveLimitsBasicMax;
+ int32_t min_value, max_value;
+ bool feature_enabled;
- return overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit);
+ switch (od_feature_bit) {
+ case PP_OD_FEATURE_FAN_CURVE_BIT:
+ feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit));
+ if (feature_enabled) {
+ smu_v13_0_7_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_TEMP,
+ &min_value, &max_value);
+ if (!min_value && !max_value) {
+ feature_enabled = false;
+ goto out;
+ }
+
+ smu_v13_0_7_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_PWM,
+ &min_value, &max_value);
+ if (!min_value && !max_value) {
+ feature_enabled = false;
+ goto out;
+ }
+ }
+ break;
+ default:
+ feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit));
+ break;
+ }
+
+out:
+ return feature_enabled;
}
static void smu_v13_0_7_get_od_setting_limits(struct smu_context *smu,
@@ -1183,26 +1207,24 @@ static int smu_v13_0_7_upload_overdrive_table(struct smu_context *smu,
return ret;
}
-static int smu_v13_0_7_print_clk_levels(struct smu_context *smu,
- enum smu_clk_type clk_type,
- char *buf)
+static int smu_v13_0_7_emit_clk_levels(struct smu_context *smu,
+ enum smu_clk_type clk_type, char *buf,
+ int *offset)
{
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context;
OverDriveTableExternal_t *od_table =
(OverDriveTableExternal_t *)smu->smu_table.overdrive_table;
- struct smu_13_0_dpm_table *single_dpm_table;
- struct smu_13_0_pcie_table *pcie_table;
+ int i, curr_freq, size = *offset, start_offset = *offset;
+ struct smu_dpm_table *single_dpm_table = NULL;
+ struct smu_pcie_table *pcie_table;
uint32_t gen_speed, lane_width;
- int i, curr_freq, size = 0;
int32_t min_value, max_value;
int ret = 0;
- smu_cmn_get_sysfs_buf(&buf, &size);
-
if (amdgpu_ras_intr_triggered()) {
- size += sysfs_emit_at(buf, size, "unavailable\n");
- return size;
+ sysfs_emit_at(buf, size, "unavailable\n");
+ return -EBUSY;
}
switch (clk_type) {
@@ -1229,61 +1251,6 @@ static int smu_v13_0_7_print_clk_levels(struct smu_context *smu,
case SMU_DCEFCLK:
single_dpm_table = &(dpm_context->dpm_tables.dcef_table);
break;
- default:
- break;
- }
-
- switch (clk_type) {
- case SMU_SCLK:
- case SMU_MCLK:
- case SMU_SOCCLK:
- case SMU_FCLK:
- case SMU_VCLK:
- case SMU_VCLK1:
- case SMU_DCLK:
- case SMU_DCLK1:
- case SMU_DCEFCLK:
- ret = smu_v13_0_7_get_current_clk_freq_by_table(smu, clk_type, &curr_freq);
- if (ret) {
- dev_err(smu->adev->dev, "Failed to get current clock freq!");
- return ret;
- }
-
- if (single_dpm_table->is_fine_grained) {
- /*
- * For fine grained dpms, there are only two dpm levels:
- * - level 0 -> min clock freq
- * - level 1 -> max clock freq
- * And the current clock frequency can be any value between them.
- * So, if the current clock frequency is not at level 0 or level 1,
- * we will fake it as three dpm levels:
- * - level 0 -> min clock freq
- * - level 1 -> current actual clock freq
- * - level 2 -> max clock freq
- */
- if ((single_dpm_table->dpm_levels[0].value != curr_freq) &&
- (single_dpm_table->dpm_levels[1].value != curr_freq)) {
- size += sysfs_emit_at(buf, size, "0: %uMhz\n",
- single_dpm_table->dpm_levels[0].value);
- size += sysfs_emit_at(buf, size, "1: %uMhz *\n",
- curr_freq);
- size += sysfs_emit_at(buf, size, "2: %uMhz\n",
- single_dpm_table->dpm_levels[1].value);
- } else {
- size += sysfs_emit_at(buf, size, "0: %uMhz %s\n",
- single_dpm_table->dpm_levels[0].value,
- single_dpm_table->dpm_levels[0].value == curr_freq ? "*" : "");
- size += sysfs_emit_at(buf, size, "1: %uMhz %s\n",
- single_dpm_table->dpm_levels[1].value,
- single_dpm_table->dpm_levels[1].value == curr_freq ? "*" : "");
- }
- } else {
- for (i = 0; i < single_dpm_table->count; i++)
- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
- i, single_dpm_table->dpm_levels[i].value,
- single_dpm_table->dpm_levels[i].value == curr_freq ? "*" : "");
- }
- break;
case SMU_PCIE:
ret = smu_v13_0_7_get_smu_metrics_data(smu,
METRICS_PCIE_RATE,
@@ -1298,24 +1265,10 @@ static int smu_v13_0_7_print_clk_levels(struct smu_context *smu,
return ret;
pcie_table = &(dpm_context->dpm_tables.pcie_table);
- for (i = 0; i < pcie_table->num_of_link_levels; i++)
- size += sysfs_emit_at(buf, size, "%d: %s %s %dMhz %s\n", i,
- (pcie_table->pcie_gen[i] == 0) ? "2.5GT/s," :
- (pcie_table->pcie_gen[i] == 1) ? "5.0GT/s," :
- (pcie_table->pcie_gen[i] == 2) ? "8.0GT/s," :
- (pcie_table->pcie_gen[i] == 3) ? "16.0GT/s," : "",
- (pcie_table->pcie_lane[i] == 1) ? "x1" :
- (pcie_table->pcie_lane[i] == 2) ? "x2" :
- (pcie_table->pcie_lane[i] == 3) ? "x4" :
- (pcie_table->pcie_lane[i] == 4) ? "x8" :
- (pcie_table->pcie_lane[i] == 5) ? "x12" :
- (pcie_table->pcie_lane[i] == 6) ? "x16" : "",
- pcie_table->clk_freq[i],
- (gen_speed == DECODE_GEN_SPEED(pcie_table->pcie_gen[i])) &&
- (lane_width == DECODE_LANE_WIDTH(pcie_table->pcie_lane[i])) ?
- "*" : "");
- break;
-
+ return smu_cmn_print_pcie_levels(smu, pcie_table,
+ SMU_DPM_PCIE_GEN_IDX(gen_speed),
+ SMU_DPM_PCIE_WIDTH_IDX(lane_width),
+ buf, offset);
case SMU_OD_SCLK:
if (!smu_v13_0_7_is_od_feature_supported(smu,
PP_OD_FEATURE_GFXCLK_BIT))
@@ -1533,7 +1486,21 @@ static int smu_v13_0_7_print_clk_levels(struct smu_context *smu,
break;
}
- return size;
+ if (single_dpm_table) {
+ ret = smu_v13_0_7_get_current_clk_freq_by_table(smu, clk_type,
+ &curr_freq);
+ if (ret) {
+ dev_err(smu->adev->dev,
+ "Failed to get current clock freq!");
+ return ret;
+ }
+ return smu_cmn_print_dpm_clk_levels(smu, single_dpm_table,
+ curr_freq, buf, offset);
+ }
+
+ *offset += size - start_offset;
+
+ return 0;
}
static int smu_v13_0_7_od_restore_table_single(struct smu_context *smu, long input)
@@ -1987,7 +1954,7 @@ static int smu_v13_0_7_force_clk_levels(struct smu_context *smu,
{
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context;
- struct smu_13_0_dpm_table *single_dpm_table;
+ struct smu_dpm_table *single_dpm_table;
uint32_t soft_min_level, soft_max_level;
uint32_t min_freq, max_freq;
int ret = 0;
@@ -2033,7 +2000,7 @@ static int smu_v13_0_7_force_clk_levels(struct smu_context *smu,
case SMU_VCLK1:
case SMU_DCLK:
case SMU_DCLK1:
- if (single_dpm_table->is_fine_grained) {
+ if (single_dpm_table->flags & SMU_DPM_TABLE_FINE_GRAINED) {
/* There is only 2 levels for fine grained DPM */
soft_max_level = (soft_max_level >= 1 ? 1 : 0);
soft_min_level = (soft_min_level >= 1 ? 1 : 0);
@@ -2100,9 +2067,9 @@ static int smu_v13_0_7_get_thermal_temperature_range(struct smu_context *smu,
static ssize_t smu_v13_0_7_get_gpu_metrics(struct smu_context *smu,
void **table)
{
- struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v1_3 *gpu_metrics =
- (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table;
+ (struct gpu_metrics_v1_3 *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
SmuMetricsExternal_t metrics_ext;
SmuMetrics_t *metrics = &metrics_ext.SmuMetrics;
int ret = 0;
@@ -2124,19 +2091,20 @@ static ssize_t smu_v13_0_7_get_gpu_metrics(struct smu_context *smu,
metrics->AvgTemperature[TEMP_VR_MEM1]);
gpu_metrics->average_gfx_activity = metrics->AverageGfxActivity;
- gpu_metrics->average_umc_activity = metrics->AverageUclkActivity;
+ gpu_metrics->average_umc_activity = smu_safe_u16_nn(metrics->AverageUclkActivity);
gpu_metrics->average_mm_activity = max(metrics->Vcn0ActivityPercentage,
metrics->Vcn1ActivityPercentage);
gpu_metrics->average_socket_power = metrics->AverageSocketPower;
- gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
+ gpu_metrics->energy_accumulator = smu->smc_fw_version <= 0x00521400 ?
+ metrics->EnergyAccumulator : UINT_MAX;
if (metrics->AverageGfxActivity <= SMU_13_0_7_BUSY_THRESHOLD)
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs;
else
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPreDs;
- if (metrics->AverageUclkActivity <= SMU_13_0_7_BUSY_THRESHOLD)
+ if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_7_BUSY_THRESHOLD)
gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPostDs;
else
gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPreDs;
@@ -2176,6 +2144,8 @@ static ssize_t smu_v13_0_7_get_gpu_metrics(struct smu_context *smu,
*table = (void *)gpu_metrics;
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
return sizeof(struct gpu_metrics_v1_3);
}
@@ -2285,7 +2255,8 @@ static int smu_v13_0_7_restore_user_od_settings(struct smu_context *smu)
user_od_table->OverDriveTable.FeatureCtrlMask = BIT(PP_OD_FEATURE_GFXCLK_BIT) |
BIT(PP_OD_FEATURE_UCLK_BIT) |
BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT) |
- BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+ BIT(PP_OD_FEATURE_FAN_CURVE_BIT) |
+ BIT(PP_OD_FEATURE_ZERO_FAN_BIT);
res = smu_v13_0_7_upload_overdrive_table(smu, user_od_table);
user_od_table->OverDriveTable.FeatureCtrlMask = 0;
if (res == 0)
@@ -2298,18 +2269,12 @@ static int smu_v13_0_7_populate_umd_state_clk(struct smu_context *smu)
{
struct smu_13_0_dpm_context *dpm_context =
smu->smu_dpm.dpm_context;
- struct smu_13_0_dpm_table *gfx_table =
- &dpm_context->dpm_tables.gfx_table;
- struct smu_13_0_dpm_table *mem_table =
- &dpm_context->dpm_tables.uclk_table;
- struct smu_13_0_dpm_table *soc_table =
- &dpm_context->dpm_tables.soc_table;
- struct smu_13_0_dpm_table *vclk_table =
- &dpm_context->dpm_tables.vclk_table;
- struct smu_13_0_dpm_table *dclk_table =
- &dpm_context->dpm_tables.dclk_table;
- struct smu_13_0_dpm_table *fclk_table =
- &dpm_context->dpm_tables.fclk_table;
+ struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table;
+ struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table;
+ struct smu_dpm_table *soc_table = &dpm_context->dpm_tables.soc_table;
+ struct smu_dpm_table *vclk_table = &dpm_context->dpm_tables.vclk_table;
+ struct smu_dpm_table *dclk_table = &dpm_context->dpm_tables.dclk_table;
+ struct smu_dpm_table *fclk_table = &dpm_context->dpm_tables.fclk_table;
struct smu_umd_pstate_table *pstate_table =
&smu->pstate_table;
struct smu_table_context *table_context = &smu->smu_table;
@@ -2317,38 +2282,39 @@ static int smu_v13_0_7_populate_umd_state_clk(struct smu_context *smu)
DriverReportedClocks_t driver_clocks =
pptable->SkuTable.DriverReportedClocks;
- pstate_table->gfxclk_pstate.min = gfx_table->min;
+ pstate_table->gfxclk_pstate.min = SMU_DPM_TABLE_MIN(gfx_table);
if (driver_clocks.GameClockAc &&
- (driver_clocks.GameClockAc < gfx_table->max))
+ (driver_clocks.GameClockAc < SMU_DPM_TABLE_MAX(gfx_table)))
pstate_table->gfxclk_pstate.peak = driver_clocks.GameClockAc;
else
- pstate_table->gfxclk_pstate.peak = gfx_table->max;
+ pstate_table->gfxclk_pstate.peak = SMU_DPM_TABLE_MAX(gfx_table);
- pstate_table->uclk_pstate.min = mem_table->min;
- pstate_table->uclk_pstate.peak = mem_table->max;
+ pstate_table->uclk_pstate.min = SMU_DPM_TABLE_MIN(mem_table);
+ pstate_table->uclk_pstate.peak = SMU_DPM_TABLE_MAX(mem_table);
- pstate_table->socclk_pstate.min = soc_table->min;
- pstate_table->socclk_pstate.peak = soc_table->max;
+ pstate_table->socclk_pstate.min = SMU_DPM_TABLE_MIN(soc_table);
+ pstate_table->socclk_pstate.peak = SMU_DPM_TABLE_MAX(soc_table);
- pstate_table->vclk_pstate.min = vclk_table->min;
- pstate_table->vclk_pstate.peak = vclk_table->max;
+ pstate_table->vclk_pstate.min = SMU_DPM_TABLE_MIN(vclk_table);
+ pstate_table->vclk_pstate.peak = SMU_DPM_TABLE_MAX(vclk_table);
- pstate_table->dclk_pstate.min = dclk_table->min;
- pstate_table->dclk_pstate.peak = dclk_table->max;
+ pstate_table->dclk_pstate.min = SMU_DPM_TABLE_MIN(dclk_table);
+ pstate_table->dclk_pstate.peak = SMU_DPM_TABLE_MAX(dclk_table);
- pstate_table->fclk_pstate.min = fclk_table->min;
- pstate_table->fclk_pstate.peak = fclk_table->max;
+ pstate_table->fclk_pstate.min = SMU_DPM_TABLE_MIN(fclk_table);
+ pstate_table->fclk_pstate.peak = SMU_DPM_TABLE_MAX(fclk_table);
if (driver_clocks.BaseClockAc &&
- driver_clocks.BaseClockAc < gfx_table->max)
+ driver_clocks.BaseClockAc < SMU_DPM_TABLE_MAX(gfx_table))
pstate_table->gfxclk_pstate.standard = driver_clocks.BaseClockAc;
else
- pstate_table->gfxclk_pstate.standard = gfx_table->max;
- pstate_table->uclk_pstate.standard = mem_table->max;
- pstate_table->socclk_pstate.standard = soc_table->min;
- pstate_table->vclk_pstate.standard = vclk_table->min;
- pstate_table->dclk_pstate.standard = dclk_table->min;
- pstate_table->fclk_pstate.standard = fclk_table->min;
+ pstate_table->gfxclk_pstate.standard =
+ SMU_DPM_TABLE_MAX(gfx_table);
+ pstate_table->uclk_pstate.standard = SMU_DPM_TABLE_MAX(mem_table);
+ pstate_table->socclk_pstate.standard = SMU_DPM_TABLE_MIN(soc_table);
+ pstate_table->vclk_pstate.standard = SMU_DPM_TABLE_MIN(vclk_table);
+ pstate_table->dclk_pstate.standard = SMU_DPM_TABLE_MIN(dclk_table);
+ pstate_table->fclk_pstate.standard = SMU_DPM_TABLE_MIN(fclk_table);
return 0;
}
@@ -2406,28 +2372,33 @@ static int smu_v13_0_7_enable_mgpu_fan_boost(struct smu_context *smu)
}
static int smu_v13_0_7_get_power_limit(struct smu_context *smu,
- uint32_t *current_power_limit,
- uint32_t *default_power_limit,
- uint32_t *max_power_limit,
- uint32_t *min_power_limit)
+ uint32_t *current_power_limit,
+ uint32_t *default_power_limit,
+ uint32_t *max_power_limit,
+ uint32_t *min_power_limit)
{
struct smu_table_context *table_context = &smu->smu_table;
struct smu_13_0_7_powerplay_table *powerplay_table =
(struct smu_13_0_7_powerplay_table *)table_context->power_play_table;
PPTable_t *pptable = table_context->driver_pptable;
SkuTable_t *skutable = &pptable->SkuTable;
- uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0;
- uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
-
- if (smu_v13_0_get_current_power_limit(smu, &power_limit))
- power_limit = smu->adev->pm.ac_power ?
+ uint32_t pp_limit = smu->adev->pm.ac_power ?
skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] :
skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0];
+ uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
+ uint32_t min_limit = min_t(uint32_t, pp_limit, msg_limit);
+ uint32_t max_limit = max_t(uint32_t, pp_limit, msg_limit);
+ uint32_t od_percent_upper = 0, od_percent_lower = 0;
+ int ret;
+
+ if (current_power_limit) {
+ ret = smu_v13_0_get_current_power_limit(smu, current_power_limit);
+ if (ret)
+ *current_power_limit = pp_limit;
+ }
- if (current_power_limit)
- *current_power_limit = power_limit;
if (default_power_limit)
- *default_power_limit = power_limit;
+ *default_power_limit = pp_limit;
if (powerplay_table) {
if (smu->od_enabled &&
@@ -2441,15 +2412,15 @@ static int smu_v13_0_7_get_power_limit(struct smu_context *smu,
}
dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
- od_percent_upper, od_percent_lower, power_limit);
+ od_percent_upper, od_percent_lower, pp_limit);
if (max_power_limit) {
- *max_power_limit = msg_limit * (100 + od_percent_upper);
+ *max_power_limit = max_limit * (100 + od_percent_upper);
*max_power_limit /= 100;
}
if (min_power_limit) {
- *min_power_limit = power_limit * (100 - od_percent_lower);
+ *min_power_limit = min_limit * (100 - od_percent_lower);
*min_power_limit /= 100;
}
@@ -2466,9 +2437,8 @@ static int smu_v13_0_7_get_power_profile_mode(struct smu_context *smu, char *buf
if (!buf)
return -EINVAL;
- activity_monitor_external = kcalloc(PP_SMC_POWER_PROFILE_COUNT,
- sizeof(*activity_monitor_external),
- GFP_KERNEL);
+ activity_monitor_external = kzalloc_objs(*activity_monitor_external,
+ PP_SMC_POWER_PROFILE_COUNT);
if (!activity_monitor_external)
return -ENOMEM;
@@ -2729,8 +2699,120 @@ static int smu_v13_0_7_set_power_limit(struct smu_context *smu,
return 0;
}
+static int smu_v13_0_7_update_pcie_parameters(struct smu_context *smu,
+ uint8_t pcie_gen_cap,
+ uint8_t pcie_width_cap)
+{
+ struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
+ struct smu_pcie_table *pcie_table = &dpm_context->dpm_tables.pcie_table;
+ int num_of_levels;
+ int link_level;
+ uint32_t smu_pcie_arg;
+ struct smu_table_context *table_context = &smu->smu_table;
+ PPTable_t *pptable = table_context->driver_pptable;
+ SkuTable_t *skutable = &pptable->SkuTable;
+ int ret = 0;
+ int i;
+
+ pcie_table->lclk_levels = 0;
+ for (link_level = 0; link_level < NUM_LINK_LEVELS; link_level++) {
+ if (!skutable->PcieGenSpeed[link_level] &&
+ !skutable->PcieLaneCount[link_level] &&
+ !skutable->LclkFreq[link_level])
+ continue;
+
+ pcie_table->pcie_gen[pcie_table->lclk_levels] =
+ skutable->PcieGenSpeed[link_level];
+ pcie_table->pcie_lane[pcie_table->lclk_levels] =
+ skutable->PcieLaneCount[link_level];
+ pcie_table->lclk_freq[pcie_table->lclk_levels] =
+ skutable->LclkFreq[link_level];
+ pcie_table->lclk_levels++;
+ }
+
+ num_of_levels = pcie_table->lclk_levels;
+ if (!num_of_levels)
+ return 0;
+
+ if (!(smu->adev->pm.pp_feature & PP_PCIE_DPM_MASK)) {
+ if (pcie_table->pcie_gen[num_of_levels - 1] < pcie_gen_cap)
+ pcie_gen_cap = pcie_table->pcie_gen[num_of_levels - 1];
+
+ if (pcie_table->pcie_lane[num_of_levels - 1] < pcie_width_cap)
+ pcie_width_cap = pcie_table->pcie_lane[num_of_levels - 1];
+
+ /* Force all levels to use the same settings */
+ for (i = 0; i < num_of_levels; i++) {
+ pcie_table->pcie_gen[i] = pcie_gen_cap;
+ pcie_table->pcie_lane[i] = pcie_width_cap;
+ smu_pcie_arg = i << 16;
+ smu_pcie_arg |= pcie_table->pcie_gen[i] << 8;
+ smu_pcie_arg |= pcie_table->pcie_lane[i];
+
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_OverridePcieParameters,
+ smu_pcie_arg,
+ NULL);
+ if (ret)
+ break;
+ }
+ } else {
+ for (i = 0; i < num_of_levels; i++) {
+ if (pcie_table->pcie_gen[i] > pcie_gen_cap ||
+ pcie_table->pcie_lane[i] > pcie_width_cap) {
+ pcie_table->pcie_gen[i] = pcie_table->pcie_gen[i] > pcie_gen_cap ?
+ pcie_gen_cap : pcie_table->pcie_gen[i];
+ pcie_table->pcie_lane[i] = pcie_table->pcie_lane[i] > pcie_width_cap ?
+ pcie_width_cap : pcie_table->pcie_lane[i];
+ smu_pcie_arg = i << 16;
+ smu_pcie_arg |= pcie_table->pcie_gen[i] << 8;
+ smu_pcie_arg |= pcie_table->pcie_lane[i];
+
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_OverridePcieParameters,
+ smu_pcie_arg,
+ NULL);
+ if (ret)
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int smu_v13_0_7_mode1_reset(struct smu_context *smu)
+{
+ int ret;
+
+ ret = smu_cmn_send_debug_smc_msg(smu, DEBUGSMC_MSG_Mode1Reset);
+ if (!ret) {
+ /* disable mmio access while doing mode 1 reset*/
+ smu->adev->no_hw_access = true;
+ /* ensure no_hw_access is globally visible before any MMIO */
+ smp_mb();
+ msleep(SMU13_MODE1_RESET_WAIT_TIME_IN_MS);
+ }
+
+ return ret;
+}
+
+static void smu_v13_0_7_init_msg_ctl(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+ struct smu_msg_ctl *ctl = &smu->msg_ctl;
+
+ smu_v13_0_init_msg_ctl(smu, smu_v13_0_7_message_map);
+
+ /* Set up debug mailbox registers */
+ ctl->config.debug_param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_53);
+ ctl->config.debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_75);
+ ctl->config.debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_54);
+ ctl->flags |= SMU_MSG_CTL_DEBUG_MAILBOX;
+}
+
static const struct pptable_funcs smu_v13_0_7_ppt_funcs = {
- .get_allowed_feature_mask = smu_v13_0_7_get_allowed_feature_mask,
+ .init_allowed_features = smu_v13_0_7_init_allowed_features,
.set_default_dpm_table = smu_v13_0_7_set_default_dpm_table,
.is_dpm_running = smu_v13_0_7_is_dpm_running,
.init_microcode = smu_v13_0_init_microcode,
@@ -2742,7 +2824,7 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = {
.fini_power = smu_v13_0_fini_power,
.check_fw_status = smu_v13_0_7_check_fw_status,
.setup_pptable = smu_v13_0_7_setup_pptable,
- .check_fw_version = smu_v13_0_check_fw_version,
+ .check_fw_version = smu_cmn_check_fw_version,
.write_pptable = smu_cmn_write_pptable,
.set_driver_table_location = smu_v13_0_set_driver_table_location,
.system_features_control = smu_v13_0_system_features_control,
@@ -2756,9 +2838,9 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = {
.get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values,
.read_sensor = smu_v13_0_7_read_sensor,
.feature_is_enabled = smu_cmn_feature_is_enabled,
- .print_clk_levels = smu_v13_0_7_print_clk_levels,
+ .emit_clk_levels = smu_v13_0_7_emit_clk_levels,
.force_clk_levels = smu_v13_0_7_force_clk_levels,
- .update_pcie_parameters = smu_v13_0_update_pcie_parameters,
+ .update_pcie_parameters = smu_v13_0_7_update_pcie_parameters,
.get_thermal_temperature_range = smu_v13_0_7_get_thermal_temperature_range,
.register_irq_handler = smu_v13_0_register_irq_handler,
.enable_thermal_alert = smu_v13_0_enable_thermal_alert,
@@ -2790,7 +2872,7 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = {
.baco_enter = smu_v13_0_baco_enter,
.baco_exit = smu_v13_0_baco_exit,
.mode1_reset_is_support = smu_v13_0_7_is_mode1_reset_supported,
- .mode1_reset = smu_v13_0_mode1_reset,
+ .mode1_reset = smu_v13_0_7_mode1_reset,
.set_mp1_state = smu_v13_0_7_set_mp1_state,
.set_df_cstate = smu_v13_0_7_set_df_cstate,
.gpo_control = smu_v13_0_gpo_control,
@@ -2803,13 +2885,11 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = {
void smu_v13_0_7_set_ppt_funcs(struct smu_context *smu)
{
smu->ppt_funcs = &smu_v13_0_7_ppt_funcs;
- smu->message_map = smu_v13_0_7_message_map;
smu->clock_map = smu_v13_0_7_clk_map;
smu->feature_map = smu_v13_0_7_feature_mask_map;
smu->table_map = smu_v13_0_7_table_map;
smu->pwr_src_map = smu_v13_0_7_pwr_src_map;
smu->workload_map = smu_v13_0_7_workload_map;
smu->smc_driver_if_version = SMU13_0_7_DRIVER_IF_VERSION;
- smu_v13_0_set_smu_mailbox_registers(smu);
- smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
+ smu_v13_0_7_init_msg_ctl(smu);
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c
index 73b4506ef5a8..7bf88ffd311b 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c
@@ -55,17 +55,19 @@
#define SMU_13_0_1_UMD_PSTATE_SOCCLK 678
#define SMU_13_0_1_UMD_PSTATE_FCLK 1800
-#define FEATURE_MASK(feature) (1ULL << feature)
-#define SMC_DPM_FEATURE ( \
- FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_VCN_DPM_BIT) | \
- FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_LCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT)| \
- FEATURE_MASK(FEATURE_GFX_DPM_BIT))
+static const struct smu_feature_bits yellow_carp_dpm_features = {
+ .bits = {
+ SMU_FEATURE_BIT_INIT(FEATURE_CCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_VCN_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_FCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_SOCCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_MP0CLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_LCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_SHUBCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DCFCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_GFX_DPM_BIT)
+ }
+};
static struct cmn2asic_msg_mapping yellow_carp_message_map[SMU_MSG_MAX_COUNT] = {
MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1),
@@ -152,6 +154,7 @@ static int yellow_carp_init_smc_tables(struct smu_context *smu)
{
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_table *tables = smu_table->tables;
+ int ret;
SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
@@ -160,22 +163,23 @@ static int yellow_carp_init_smc_tables(struct smu_context *smu)
SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
- smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL);
+ smu_table->clocks_table = kzalloc_obj(DpmClocks_t);
if (!smu_table->clocks_table)
goto err0_out;
- smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
+ smu_table->metrics_table = kzalloc_obj(SmuMetrics_t);
if (!smu_table->metrics_table)
goto err1_out;
smu_table->metrics_time = 0;
- smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL);
+ smu_table->watermarks_table = kzalloc_obj(Watermarks_t);
if (!smu_table->watermarks_table)
goto err2_out;
- smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_1);
- smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
- if (!smu_table->gpu_metrics_table)
+ ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS,
+ sizeof(struct gpu_metrics_v2_1),
+ SMU_GPU_METRICS_CACHE_INTERVAL);
+ if (ret)
goto err3_out;
return 0;
@@ -203,8 +207,7 @@ static int yellow_carp_fini_smc_tables(struct smu_context *smu)
kfree(smu_table->watermarks_table);
smu_table->watermarks_table = NULL;
- kfree(smu_table->gpu_metrics_table);
- smu_table->gpu_metrics_table = NULL;
+ smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS);
return 0;
}
@@ -256,14 +259,15 @@ static int yellow_carp_dpm_set_jpeg_enable(struct smu_context *smu, bool enable)
static bool yellow_carp_is_dpm_running(struct smu_context *smu)
{
int ret = 0;
- uint64_t feature_enabled;
+ struct smu_feature_bits feature_enabled;
ret = smu_cmn_get_enabled_mask(smu, &feature_enabled);
if (ret)
return false;
- return !!(feature_enabled & SMC_DPM_FEATURE);
+ return smu_feature_bits_test_mask(&feature_enabled,
+ yellow_carp_dpm_features.bits);
}
static int yellow_carp_post_smu_init(struct smu_context *smu)
@@ -557,11 +561,11 @@ static int yellow_carp_set_watermarks_table(struct smu_context *smu,
}
static ssize_t yellow_carp_get_gpu_metrics(struct smu_context *smu,
- void **table)
+ void **table)
{
- struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v2_1 *gpu_metrics =
- (struct gpu_metrics_v2_1 *)smu_table->gpu_metrics_table;
+ (struct gpu_metrics_v2_1 *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
SmuMetrics_t metrics;
int ret = 0;
@@ -606,6 +610,8 @@ static ssize_t yellow_carp_get_gpu_metrics(struct smu_context *smu,
*table = (void *)gpu_metrics;
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
return sizeof(struct gpu_metrics_v2_1);
}
@@ -1038,16 +1044,15 @@ static uint32_t yellow_carp_get_umd_pstate_clk_default(struct smu_context *smu,
return clk_limit;
}
-static int yellow_carp_print_clk_levels(struct smu_context *smu,
- enum smu_clk_type clk_type, char *buf)
+static int yellow_carp_emit_clk_levels(struct smu_context *smu,
+ enum smu_clk_type clk_type, char *buf,
+ int *offset)
{
- int i, idx, size = 0, ret = 0;
+ int i, idx, size = *offset, ret = 0, start_offset = *offset;
uint32_t cur_value = 0, value = 0, count = 0;
uint32_t min, max;
uint32_t clk_limit = 0;
- smu_cmn_get_sysfs_buf(&buf, &size);
-
switch (clk_type) {
case SMU_OD_SCLK:
size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK");
@@ -1068,17 +1073,17 @@ static int yellow_carp_print_clk_levels(struct smu_context *smu,
case SMU_FCLK:
ret = yellow_carp_get_current_clk_freq(smu, clk_type, &cur_value);
if (ret)
- goto print_clk_out;
+ return ret;
ret = yellow_carp_get_dpm_level_count(smu, clk_type, &count);
if (ret)
- goto print_clk_out;
+ return ret;
for (i = 0; i < count; i++) {
idx = (clk_type == SMU_FCLK || clk_type == SMU_MCLK) ? (count - i - 1) : i;
ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, idx, &value);
if (ret)
- goto print_clk_out;
+ return ret;
size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value,
cur_value == value ? "*" : "");
@@ -1089,7 +1094,7 @@ static int yellow_carp_print_clk_levels(struct smu_context *smu,
clk_limit = yellow_carp_get_umd_pstate_clk_default(smu, clk_type);
ret = yellow_carp_get_current_clk_freq(smu, clk_type, &cur_value);
if (ret)
- goto print_clk_out;
+ return ret;
min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq;
max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq;
if (cur_value == max)
@@ -1110,8 +1115,9 @@ static int yellow_carp_print_clk_levels(struct smu_context *smu,
break;
}
-print_clk_out:
- return size;
+ *offset += size - start_offset;
+
+ return 0;
}
static int yellow_carp_force_clk_levels(struct smu_context *smu,
@@ -1325,13 +1331,11 @@ static int yellow_carp_set_fine_grain_gfx_freq_parameters(struct smu_context *sm
static const struct pptable_funcs yellow_carp_ppt_funcs = {
.check_fw_status = smu_v13_0_check_fw_status,
- .check_fw_version = smu_v13_0_check_fw_version,
+ .check_fw_version = smu_cmn_check_fw_version,
.init_smc_tables = yellow_carp_init_smc_tables,
.fini_smc_tables = yellow_carp_fini_smc_tables,
.get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values,
.system_features_control = yellow_carp_system_features_control,
- .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
- .send_smc_msg = smu_cmn_send_smc_msg,
.dpm_set_vcn_enable = yellow_carp_dpm_set_vcn_enable,
.dpm_set_jpeg_enable = yellow_carp_dpm_set_jpeg_enable,
.set_default_dpm_table = yellow_carp_set_default_dpm_tables,
@@ -1348,7 +1352,7 @@ static const struct pptable_funcs yellow_carp_ppt_funcs = {
.mode2_reset = yellow_carp_mode2_reset,
.get_dpm_ultimate_freq = yellow_carp_get_dpm_ultimate_freq,
.od_edit_dpm_table = yellow_carp_od_edit_dpm_table,
- .print_clk_levels = yellow_carp_print_clk_levels,
+ .emit_clk_levels = yellow_carp_emit_clk_levels,
.force_clk_levels = yellow_carp_force_clk_levels,
.set_performance_level = yellow_carp_set_performance_level,
.set_fine_grain_gfx_freq_parameters = yellow_carp_set_fine_grain_gfx_freq_parameters,
@@ -1357,10 +1361,9 @@ static const struct pptable_funcs yellow_carp_ppt_funcs = {
void yellow_carp_set_ppt_funcs(struct smu_context *smu)
{
smu->ppt_funcs = &yellow_carp_ppt_funcs;
- smu->message_map = yellow_carp_message_map;
smu->feature_map = yellow_carp_feature_mask_map;
smu->table_map = yellow_carp_table_map;
smu->is_apu = true;
smu->smc_driver_if_version = SMU13_YELLOW_CARP_DRIVER_IF_VERSION;
- smu_v13_0_set_smu_mailbox_registers(smu);
+ smu_v13_0_init_msg_ctl(smu, yellow_carp_message_map);
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c
index ddb6444406d2..d0a8df1aa6b6 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c
@@ -62,13 +62,14 @@ const int decoded_link_width[8] = {0, 1, 2, 4, 8, 12, 16, 32};
MODULE_FIRMWARE("amdgpu/smu_14_0_2.bin");
MODULE_FIRMWARE("amdgpu/smu_14_0_3.bin");
+MODULE_FIRMWARE("amdgpu/smu_14_0_3_kicker.bin");
#define ENABLE_IMU_ARG_GFXOFF_ENABLE 1
int smu_v14_0_init_microcode(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- char ucode_prefix[15];
+ char ucode_prefix[30];
int err = 0;
const struct smc_firmware_header_v1_0 *hdr;
const struct common_firmware_header *header;
@@ -79,8 +80,12 @@ int smu_v14_0_init_microcode(struct smu_context *smu)
return 0;
amdgpu_ucode_ip_version_decode(adev, MP1_HWIP, ucode_prefix, sizeof(ucode_prefix));
- err = amdgpu_ucode_request(adev, &adev->pm.fw, AMDGPU_UCODE_REQUIRED,
- "amdgpu/%s.bin", ucode_prefix);
+ if (amdgpu_is_kicker_fw(adev))
+ err = amdgpu_ucode_request(adev, &adev->pm.fw, AMDGPU_UCODE_REQUIRED,
+ "amdgpu/%s_kicker.bin", ucode_prefix);
+ else
+ err = amdgpu_ucode_request(adev, &adev->pm.fw, AMDGPU_UCODE_REQUIRED,
+ "amdgpu/%s.bin", ucode_prefix);
if (err)
goto out;
@@ -224,66 +229,6 @@ int smu_v14_0_check_fw_status(struct smu_context *smu)
return -EIO;
}
-int smu_v14_0_check_fw_version(struct smu_context *smu)
-{
- struct amdgpu_device *adev = smu->adev;
- uint32_t if_version = 0xff, smu_version = 0xff;
- uint8_t smu_program, smu_major, smu_minor, smu_debug;
- int ret = 0;
-
- ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version);
- if (ret)
- return ret;
-
- smu_program = (smu_version >> 24) & 0xff;
- smu_major = (smu_version >> 16) & 0xff;
- smu_minor = (smu_version >> 8) & 0xff;
- smu_debug = (smu_version >> 0) & 0xff;
- if (smu->is_apu)
- adev->pm.fw_version = smu_version;
-
- switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
- case IP_VERSION(14, 0, 0):
- case IP_VERSION(14, 0, 4):
- smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_SMU_V14_0_0;
- break;
- case IP_VERSION(14, 0, 1):
- smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_SMU_V14_0_1;
- break;
- case IP_VERSION(14, 0, 2):
- case IP_VERSION(14, 0, 3):
- smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_SMU_V14_0_2;
- break;
- default:
- dev_err(adev->dev, "smu unsupported IP version: 0x%x.\n",
- amdgpu_ip_version(adev, MP1_HWIP, 0));
- smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_INV;
- break;
- }
-
- if (adev->pm.fw)
- dev_dbg(smu->adev->dev, "smu fw reported program %d, version = 0x%08x (%d.%d.%d)\n",
- smu_program, smu_version, smu_major, smu_minor, smu_debug);
-
- /*
- * 1. if_version mismatch is not critical as our fw is designed
- * to be backward compatible.
- * 2. New fw usually brings some optimizations. But that's visible
- * only on the paired driver.
- * Considering above, we just leave user a verbal message instead
- * of halt driver loading.
- */
- if (if_version != smu->smc_driver_if_version) {
- dev_info(adev->dev, "smu driver if version = 0x%08x, smu fw if version = 0x%08x, "
- "smu fw program = %d, smu fw version = 0x%08x (%d.%d.%d)\n",
- smu->smc_driver_if_version, if_version,
- smu_program, smu_version, smu_major, smu_minor, smu_debug);
- dev_info(adev->dev, "SMU driver if version not matched\n");
- }
-
- return ret;
-}
-
static int smu_v14_0_set_pptable_v2_0(struct smu_context *smu, void **table, uint32_t *size)
{
struct amdgpu_device *adev = smu->adev;
@@ -433,7 +378,7 @@ int smu_v14_0_init_smc_tables(struct smu_context *smu)
}
smu_table->max_sustainable_clocks =
- kzalloc(sizeof(struct smu_14_0_max_sustainable_clocks), GFP_KERNEL);
+ kzalloc_obj(struct smu_14_0_max_sustainable_clocks);
if (!smu_table->max_sustainable_clocks) {
ret = -ENOMEM;
goto err1_out;
@@ -490,13 +435,12 @@ int smu_v14_0_fini_smc_tables(struct smu_context *smu)
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
- kfree(smu_table->gpu_metrics_table);
+ smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS);
kfree(smu_table->combo_pptable);
kfree(smu_table->boot_overdrive_table);
kfree(smu_table->overdrive_table);
kfree(smu_table->max_sustainable_clocks);
kfree(smu_table->driver_pptable);
- smu_table->gpu_metrics_table = NULL;
smu_table->combo_pptable = NULL;
smu_table->boot_overdrive_table = NULL;
smu_table->overdrive_table = NULL;
@@ -533,8 +477,7 @@ int smu_v14_0_init_power(struct smu_context *smu)
if (smu_power->power_context || smu_power->power_context_size != 0)
return -EINVAL;
- smu_power->power_context = kzalloc(sizeof(struct smu_14_0_dpm_context),
- GFP_KERNEL);
+ smu_power->power_context = kzalloc_obj(struct smu_14_0_dpm_context);
if (!smu_power->power_context)
return -ENOMEM;
smu_power->power_context_size = sizeof(struct smu_14_0_dpm_context);
@@ -741,11 +684,11 @@ int smu_v14_0_set_allowed_mask(struct smu_context *smu)
int ret = 0;
uint32_t feature_mask[2];
- if (bitmap_empty(feature->allowed, SMU_FEATURE_MAX) ||
- feature->feature_num < 64)
+ if (smu_feature_list_is_empty(smu, SMU_FEATURE_LIST_ALLOWED) ||
+ feature->feature_num < SMU_FEATURE_NUM_DEFAULT)
return -EINVAL;
- bitmap_to_arr32(feature_mask, feature->allowed, 64);
+ smu_feature_list_to_arr32(smu, SMU_FEATURE_LIST_ALLOWED, feature_mask);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetAllowedFeaturesMaskHigh,
feature_mask[1], NULL);
@@ -769,6 +712,7 @@ int smu_v14_0_gfx_off_control(struct smu_context *smu, bool enable)
case IP_VERSION(14, 0, 2):
case IP_VERSION(14, 0, 3):
case IP_VERSION(14, 0, 4):
+ case IP_VERSION(14, 0, 5):
if (!(adev->pm.pp_feature & PP_GFXOFF_MASK))
return 0;
if (enable)
@@ -948,6 +892,14 @@ static int smu_v14_0_irq_process(struct amdgpu_device *adev,
uint32_t client_id = entry->client_id;
uint32_t src_id = entry->src_id;
+ /*
+ * ctxid is used to distinguish different
+ * events for SMCToHost interrupt.
+ */
+ uint32_t ctxid = entry->src_data[0];
+ uint32_t data;
+ uint32_t high;
+
if (client_id == SOC15_IH_CLIENTID_THM) {
switch (src_id) {
case THM_11_0__SRCID__THM_DIG_THERM_L2H:
@@ -962,6 +914,50 @@ static int smu_v14_0_irq_process(struct amdgpu_device *adev,
src_id);
break;
}
+ } else if (client_id == SOC15_IH_CLIENTID_MP1) {
+ if (src_id == SMU_IH_INTERRUPT_ID_TO_DRIVER) {
+ /* ACK SMUToHost interrupt */
+ data = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL);
+ data = REG_SET_FIELD(data, MP1_SMN_IH_SW_INT_CTRL, INT_ACK, 1);
+ WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL, data);
+
+ switch (ctxid) {
+ case SMU_IH_INTERRUPT_CONTEXT_ID_FAN_ABNORMAL:
+ high = smu->thermal_range.software_shutdown_temp +
+ smu->thermal_range.software_shutdown_temp_offset;
+ high = min_t(typeof(high),
+ SMU_THERMAL_MAXIMUM_ALERT_TEMP,
+ high);
+ dev_emerg(adev->dev, "Reduce soft CTF limit to %d (by an offset %d)\n",
+ high,
+ smu->thermal_range.software_shutdown_temp_offset);
+
+ data = RREG32_SOC15(THM, 0, regTHM_THERMAL_INT_CTRL);
+ data = REG_SET_FIELD(data, THM_THERMAL_INT_CTRL,
+ DIG_THERM_INTH,
+ (high & 0xff));
+ data = data & (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK);
+ WREG32_SOC15(THM, 0, regTHM_THERMAL_INT_CTRL, data);
+ break;
+ case SMU_IH_INTERRUPT_CONTEXT_ID_FAN_RECOVERY:
+ high = min_t(typeof(high),
+ SMU_THERMAL_MAXIMUM_ALERT_TEMP,
+ smu->thermal_range.software_shutdown_temp);
+ dev_emerg(adev->dev, "Recover soft CTF limit to %d\n", high);
+
+ data = RREG32_SOC15(THM, 0, regTHM_THERMAL_INT_CTRL);
+ data = REG_SET_FIELD(data, THM_THERMAL_INT_CTRL,
+ DIG_THERM_INTH,
+ (high & 0xff));
+ data = data & (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK);
+ WREG32_SOC15(THM, 0, regTHM_THERMAL_INT_CTRL, data);
+ break;
+ default:
+ dev_dbg(adev->dev, "Unhandled context id %d from client:%d!\n",
+ ctxid, client_id);
+ break;
+ }
+ }
}
return 0;
@@ -1119,6 +1115,7 @@ int smu_v14_0_set_soft_freq_limited_range(struct smu_context *smu,
return clk_id;
if (max > 0) {
+ max = SMU_V14_SOFT_FREQ_ROUND(max);
if (automatic)
param = (uint32_t)((clk_id << 16) | 0xffff);
else
@@ -1188,18 +1185,12 @@ int smu_v14_0_set_performance_level(struct smu_context *smu,
{
struct smu_14_0_dpm_context *dpm_context =
smu->smu_dpm.dpm_context;
- struct smu_14_0_dpm_table *gfx_table =
- &dpm_context->dpm_tables.gfx_table;
- struct smu_14_0_dpm_table *mem_table =
- &dpm_context->dpm_tables.uclk_table;
- struct smu_14_0_dpm_table *soc_table =
- &dpm_context->dpm_tables.soc_table;
- struct smu_14_0_dpm_table *vclk_table =
- &dpm_context->dpm_tables.vclk_table;
- struct smu_14_0_dpm_table *dclk_table =
- &dpm_context->dpm_tables.dclk_table;
- struct smu_14_0_dpm_table *fclk_table =
- &dpm_context->dpm_tables.fclk_table;
+ struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table;
+ struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table;
+ struct smu_dpm_table *soc_table = &dpm_context->dpm_tables.soc_table;
+ struct smu_dpm_table *vclk_table = &dpm_context->dpm_tables.vclk_table;
+ struct smu_dpm_table *dclk_table = &dpm_context->dpm_tables.dclk_table;
+ struct smu_dpm_table *fclk_table = &dpm_context->dpm_tables.fclk_table;
struct smu_umd_pstate_table *pstate_table =
&smu->pstate_table;
struct amdgpu_device *adev = smu->adev;
@@ -1214,34 +1205,34 @@ int smu_v14_0_set_performance_level(struct smu_context *smu,
switch (level) {
case AMD_DPM_FORCED_LEVEL_HIGH:
- sclk_min = sclk_max = gfx_table->max;
- mclk_min = mclk_max = mem_table->max;
- socclk_min = socclk_max = soc_table->max;
- vclk_min = vclk_max = vclk_table->max;
- dclk_min = dclk_max = dclk_table->max;
- fclk_min = fclk_max = fclk_table->max;
+ sclk_min = sclk_max = SMU_DPM_TABLE_MAX(gfx_table);
+ mclk_min = mclk_max = SMU_DPM_TABLE_MAX(mem_table);
+ socclk_min = socclk_max = SMU_DPM_TABLE_MAX(soc_table);
+ vclk_min = vclk_max = SMU_DPM_TABLE_MAX(vclk_table);
+ dclk_min = dclk_max = SMU_DPM_TABLE_MAX(dclk_table);
+ fclk_min = fclk_max = SMU_DPM_TABLE_MAX(fclk_table);
break;
case AMD_DPM_FORCED_LEVEL_LOW:
- sclk_min = sclk_max = gfx_table->min;
- mclk_min = mclk_max = mem_table->min;
- socclk_min = socclk_max = soc_table->min;
- vclk_min = vclk_max = vclk_table->min;
- dclk_min = dclk_max = dclk_table->min;
- fclk_min = fclk_max = fclk_table->min;
+ sclk_min = sclk_max = SMU_DPM_TABLE_MIN(gfx_table);
+ mclk_min = mclk_max = SMU_DPM_TABLE_MIN(mem_table);
+ socclk_min = socclk_max = SMU_DPM_TABLE_MIN(soc_table);
+ vclk_min = vclk_max = SMU_DPM_TABLE_MIN(vclk_table);
+ dclk_min = dclk_max = SMU_DPM_TABLE_MIN(dclk_table);
+ fclk_min = fclk_max = SMU_DPM_TABLE_MIN(fclk_table);
break;
case AMD_DPM_FORCED_LEVEL_AUTO:
- sclk_min = gfx_table->min;
- sclk_max = gfx_table->max;
- mclk_min = mem_table->min;
- mclk_max = mem_table->max;
- socclk_min = soc_table->min;
- socclk_max = soc_table->max;
- vclk_min = vclk_table->min;
- vclk_max = vclk_table->max;
- dclk_min = dclk_table->min;
- dclk_max = dclk_table->max;
- fclk_min = fclk_table->min;
- fclk_max = fclk_table->max;
+ sclk_min = SMU_DPM_TABLE_MIN(gfx_table);
+ sclk_max = SMU_DPM_TABLE_MAX(gfx_table);
+ mclk_min = SMU_DPM_TABLE_MIN(mem_table);
+ mclk_max = SMU_DPM_TABLE_MAX(mem_table);
+ socclk_min = SMU_DPM_TABLE_MIN(soc_table);
+ socclk_max = SMU_DPM_TABLE_MAX(soc_table);
+ vclk_min = SMU_DPM_TABLE_MIN(vclk_table);
+ vclk_max = SMU_DPM_TABLE_MAX(vclk_table);
+ dclk_min = SMU_DPM_TABLE_MIN(dclk_table);
+ dclk_max = SMU_DPM_TABLE_MAX(dclk_table);
+ fclk_min = SMU_DPM_TABLE_MIN(fclk_table);
+ fclk_max = SMU_DPM_TABLE_MAX(fclk_table);
auto_level = true;
break;
case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
@@ -1463,11 +1454,12 @@ static int smu_v14_0_get_fine_grained_status(struct smu_context *smu,
int smu_v14_0_set_single_dpm_table(struct smu_context *smu,
enum smu_clk_type clk_type,
- struct smu_14_0_dpm_table *single_dpm_table)
+ struct smu_dpm_table *single_dpm_table)
{
int ret = 0;
uint32_t clk;
int i;
+ bool is_fine_grained;
ret = smu_v14_0_get_dpm_level_count(smu,
clk_type,
@@ -1477,13 +1469,14 @@ int smu_v14_0_set_single_dpm_table(struct smu_context *smu,
return ret;
}
- ret = smu_v14_0_get_fine_grained_status(smu,
- clk_type,
- &single_dpm_table->is_fine_grained);
+ ret = smu_v14_0_get_fine_grained_status(smu, clk_type,
+ &is_fine_grained);
if (ret) {
dev_err(smu->adev->dev, "[%s] failed to get fine grained status!\n", __func__);
return ret;
}
+ if (is_fine_grained)
+ single_dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
for (i = 0; i < single_dpm_table->count; i++) {
ret = smu_v14_0_get_dpm_freq_by_index(smu,
@@ -1497,11 +1490,6 @@ int smu_v14_0_set_single_dpm_table(struct smu_context *smu,
single_dpm_table->dpm_levels[i].value = clk;
single_dpm_table->dpm_levels[i].enabled = true;
-
- if (i == 0)
- single_dpm_table->min = clk;
- else if (i == single_dpm_table->count - 1)
- single_dpm_table->max = clk;
}
return 0;
@@ -1785,17 +1773,21 @@ int smu_v14_0_baco_exit(struct smu_context *smu)
int smu_v14_0_set_gfx_power_up_by_imu(struct smu_context *smu)
{
- uint16_t index;
+ struct smu_msg_ctl *ctl = &smu->msg_ctl;
struct amdgpu_device *adev = smu->adev;
+ int ret;
if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_EnableGfxImu,
ENABLE_IMU_ARG_GFXOFF_ENABLE, NULL);
}
- index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG,
- SMU_MSG_EnableGfxImu);
- return smu_cmn_send_msg_without_waiting(smu, index, ENABLE_IMU_ARG_GFXOFF_ENABLE);
+ mutex_lock(&ctl->lock);
+ ret = smu_msg_send_async_locked(ctl, SMU_MSG_EnableGfxImu,
+ ENABLE_IMU_ARG_GFXOFF_ENABLE);
+ mutex_unlock(&ctl->lock);
+
+ return ret;
}
int smu_v14_0_set_default_dpm_tables(struct smu_context *smu)
@@ -1880,6 +1872,11 @@ int smu_v14_0_od_edit_dpm_table(struct smu_context *smu,
dev_err(smu->adev->dev, "Set soft max sclk failed!");
return ret;
}
+ if (smu->gfx_actual_hard_min_freq != smu->gfx_default_hard_min_freq ||
+ smu->gfx_actual_soft_max_freq != smu->gfx_default_soft_max_freq)
+ smu->user_dpm_profile.user_od = true;
+ else
+ smu->user_dpm_profile.user_od = false;
break;
default:
return -ENOSYS;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
index 84f9b007b59f..75719c47a41e 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
@@ -65,6 +65,9 @@
#define SMU_MALL_PG_CONFIG_DEFAULT SMU_MALL_PG_CONFIG_DRIVER_CONTROL_ALWAYS_ON
+#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_0 0x7
+#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_1 0x6
+
#define SMU_14_0_0_UMD_PSTATE_GFXCLK 700
#define SMU_14_0_0_UMD_PSTATE_SOCCLK 678
#define SMU_14_0_0_UMD_PSTATE_FCLK 1800
@@ -72,19 +75,21 @@
#define SMU_14_0_4_UMD_PSTATE_GFXCLK 938
#define SMU_14_0_4_UMD_PSTATE_SOCCLK 938
-#define FEATURE_MASK(feature) (1ULL << feature)
-#define SMC_DPM_FEATURE ( \
- FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_VCN_DPM_BIT) | \
- FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_LCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT) | \
- FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT)| \
- FEATURE_MASK(FEATURE_ISP_DPM_BIT)| \
- FEATURE_MASK(FEATURE_IPU_DPM_BIT) | \
- FEATURE_MASK(FEATURE_GFX_DPM_BIT) | \
- FEATURE_MASK(FEATURE_VPE_DPM_BIT))
+static const struct smu_feature_bits smu_v14_0_0_dpm_features = {
+ .bits = {
+ SMU_FEATURE_BIT_INIT(FEATURE_CCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_VCN_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_FCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_SOCCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_LCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_SHUBCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DCFCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_ISP_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_IPU_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_GFX_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_VPE_DPM_BIT)
+ }
+};
enum smu_mall_pg_config {
SMU_MALL_PG_CONFIG_PMFW_CONTROL = 0,
@@ -186,6 +191,7 @@ static int smu_v14_0_0_init_smc_tables(struct smu_context *smu)
{
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_table *tables = smu_table->tables;
+ int ret;
SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
@@ -194,7 +200,7 @@ static int smu_v14_0_0_init_smc_tables(struct smu_context *smu)
SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
- smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
+ smu_table->metrics_table = kzalloc_obj(SmuMetrics_t);
if (!smu_table->metrics_table)
goto err0_out;
smu_table->metrics_time = 0;
@@ -203,13 +209,14 @@ static int smu_v14_0_0_init_smc_tables(struct smu_context *smu)
if (!smu_table->clocks_table)
goto err1_out;
- smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL);
+ smu_table->watermarks_table = kzalloc_obj(Watermarks_t);
if (!smu_table->watermarks_table)
goto err2_out;
- smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v3_0);
- smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
- if (!smu_table->gpu_metrics_table)
+ ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS,
+ sizeof(struct gpu_metrics_v3_0),
+ SMU_GPU_METRICS_CACHE_INTERVAL);
+ if (ret)
goto err3_out;
return 0;
@@ -237,8 +244,7 @@ static int smu_v14_0_0_fini_smc_tables(struct smu_context *smu)
kfree(smu_table->watermarks_table);
smu_table->watermarks_table = NULL;
- kfree(smu_table->gpu_metrics_table);
- smu_table->gpu_metrics_table = NULL;
+ smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS);
return 0;
}
@@ -469,14 +475,15 @@ static int smu_v14_0_0_read_sensor(struct smu_context *smu,
static bool smu_v14_0_0_is_dpm_running(struct smu_context *smu)
{
int ret = 0;
- uint64_t feature_enabled;
+ struct smu_feature_bits feature_enabled;
ret = smu_cmn_get_enabled_mask(smu, &feature_enabled);
if (ret)
return false;
- return !!(feature_enabled & SMC_DPM_FEATURE);
+ return smu_feature_bits_test_mask(&feature_enabled,
+ smu_v14_0_0_dpm_features.bits);
}
static int smu_v14_0_0_set_watermarks_table(struct smu_context *smu,
@@ -538,11 +545,11 @@ static int smu_v14_0_0_set_watermarks_table(struct smu_context *smu,
}
static ssize_t smu_v14_0_0_get_gpu_metrics(struct smu_context *smu,
- void **table)
+ void **table)
{
- struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v3_0 *gpu_metrics =
- (struct gpu_metrics_v3_0 *)smu_table->gpu_metrics_table;
+ (struct gpu_metrics_v3_0 *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
SmuMetrics_t metrics;
int ret = 0;
@@ -611,6 +618,8 @@ static ssize_t smu_v14_0_0_get_gpu_metrics(struct smu_context *smu,
*table = (void *)gpu_metrics;
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
return sizeof(struct gpu_metrics_v3_0);
}
@@ -1129,15 +1138,14 @@ static int smu_v14_0_common_get_dpm_level_count(struct smu_context *smu,
return 0;
}
-static int smu_v14_0_0_print_clk_levels(struct smu_context *smu,
- enum smu_clk_type clk_type, char *buf)
+static int smu_v14_0_0_emit_clk_levels(struct smu_context *smu,
+ enum smu_clk_type clk_type, char *buf,
+ int *offset)
{
- int i, idx, ret = 0, size = 0;
+ int i, idx, ret = 0, size = *offset, start_offset = *offset;
uint32_t cur_value = 0, value = 0, count = 0;
uint32_t min, max;
- smu_cmn_get_sysfs_buf(&buf, &size);
-
switch (clk_type) {
case SMU_OD_SCLK:
size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK");
@@ -1161,17 +1169,17 @@ static int smu_v14_0_0_print_clk_levels(struct smu_context *smu,
case SMU_FCLK:
ret = smu_v14_0_0_get_current_clk_freq(smu, clk_type, &cur_value);
if (ret)
- break;
+ return ret;
ret = smu_v14_0_common_get_dpm_level_count(smu, clk_type, &count);
if (ret)
- break;
+ return ret;
for (i = 0; i < count; i++) {
idx = (clk_type == SMU_MCLK) ? (count - i - 1) : i;
ret = smu_v14_0_common_get_dpm_freq_by_index(smu, clk_type, idx, &value);
if (ret)
- break;
+ return ret;
size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value,
cur_value == value ? "*" : "");
@@ -1181,7 +1189,7 @@ static int smu_v14_0_0_print_clk_levels(struct smu_context *smu,
case SMU_SCLK:
ret = smu_v14_0_0_get_current_clk_freq(smu, clk_type, &cur_value);
if (ret)
- break;
+ return ret;
min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq;
max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq;
if (cur_value == max)
@@ -1202,16 +1210,20 @@ static int smu_v14_0_0_print_clk_levels(struct smu_context *smu,
break;
}
- return size;
+ *offset += size - start_offset;
+
+ return 0;
}
static int smu_v14_0_0_set_soft_freq_limited_range(struct smu_context *smu,
enum smu_clk_type clk_type,
- uint32_t min,
- uint32_t max)
+ u32 min,
+ u32 max,
+ bool __always_unused automatic)
{
- enum smu_message_type msg_set_min, msg_set_max;
- int ret = 0;
+ enum smu_message_type msg_set_min = SMU_MSG_MAX_COUNT;
+ enum smu_message_type msg_set_max = SMU_MSG_MAX_COUNT;
+ int ret = -EINVAL;
if (!smu_v14_0_0_clk_dpm_is_enabled(smu, clk_type))
return -EINVAL;
@@ -1219,7 +1231,8 @@ static int smu_v14_0_0_set_soft_freq_limited_range(struct smu_context *smu,
switch (clk_type) {
case SMU_GFXCLK:
case SMU_SCLK:
- msg_set_min = SMU_MSG_SetHardMinGfxClk;
+ /* SoftMin lets PMFW throttle gfxclk; HardMin would override SoftMax. */
+ msg_set_min = SMU_MSG_SetSoftMinGfxclk;
msg_set_max = SMU_MSG_SetSoftMaxGfxClk;
break;
case SMU_FCLK:
@@ -1240,16 +1253,23 @@ static int smu_v14_0_0_set_soft_freq_limited_range(struct smu_context *smu,
msg_set_min = SMU_MSG_SetHardMinVcn1;
msg_set_max = SMU_MSG_SetSoftMaxVcn1;
break;
+ case SMU_ISPICLK:
+ msg_set_min = SMU_MSG_SetHardMinIspiclkByFreq;
+ break;
+ case SMU_ISPXCLK:
+ msg_set_min = SMU_MSG_SetHardMinIspxclkByFreq;
+ break;
default:
return -EINVAL;
}
- ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_min, min, NULL);
- if (ret)
- return ret;
+ if (min && msg_set_min != SMU_MSG_MAX_COUNT)
+ ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_min, min, NULL);
+
+ if (max && msg_set_max != SMU_MSG_MAX_COUNT)
+ ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_max, max, NULL);
- return smu_cmn_send_smc_msg_with_param(smu, msg_set_max,
- max, NULL);
+ return ret;
}
static int smu_v14_0_0_force_clk_levels(struct smu_context *smu,
@@ -1278,7 +1298,7 @@ static int smu_v14_0_0_force_clk_levels(struct smu_context *smu,
if (ret)
break;
- ret = smu_v14_0_0_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq);
+ ret = smu_v14_0_0_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq, false);
break;
default:
ret = -EINVAL;
@@ -1426,7 +1446,8 @@ static int smu_v14_0_common_set_performance_level(struct smu_context *smu,
ret = smu_v14_0_0_set_soft_freq_limited_range(smu,
SMU_SCLK,
sclk_min,
- sclk_max);
+ sclk_max,
+ false);
if (ret)
return ret;
@@ -1438,7 +1459,8 @@ static int smu_v14_0_common_set_performance_level(struct smu_context *smu,
ret = smu_v14_0_0_set_soft_freq_limited_range(smu,
SMU_FCLK,
fclk_min,
- fclk_max);
+ fclk_max,
+ false);
if (ret)
return ret;
}
@@ -1447,7 +1469,8 @@ static int smu_v14_0_common_set_performance_level(struct smu_context *smu,
ret = smu_v14_0_0_set_soft_freq_limited_range(smu,
SMU_SOCCLK,
socclk_min,
- socclk_max);
+ socclk_max,
+ false);
if (ret)
return ret;
}
@@ -1456,7 +1479,8 @@ static int smu_v14_0_common_set_performance_level(struct smu_context *smu,
ret = smu_v14_0_0_set_soft_freq_limited_range(smu,
SMU_VCLK,
vclk_min,
- vclk_max);
+ vclk_max,
+ false);
if (ret)
return ret;
}
@@ -1465,7 +1489,8 @@ static int smu_v14_0_common_set_performance_level(struct smu_context *smu,
ret = smu_v14_0_0_set_soft_freq_limited_range(smu,
SMU_VCLK1,
vclk1_min,
- vclk1_max);
+ vclk1_max,
+ false);
if (ret)
return ret;
}
@@ -1474,7 +1499,8 @@ static int smu_v14_0_common_set_performance_level(struct smu_context *smu,
ret = smu_v14_0_0_set_soft_freq_limited_range(smu,
SMU_DCLK,
dclk_min,
- dclk_max);
+ dclk_max,
+ false);
if (ret)
return ret;
}
@@ -1483,7 +1509,8 @@ static int smu_v14_0_common_set_performance_level(struct smu_context *smu,
ret = smu_v14_0_0_set_soft_freq_limited_range(smu,
SMU_DCLK1,
dclk1_min,
- dclk1_max);
+ dclk1_max,
+ false);
if (ret)
return ret;
}
@@ -1497,9 +1524,10 @@ static int smu_v14_0_1_set_fine_grain_gfx_freq_parameters(struct smu_context *sm
smu->gfx_default_hard_min_freq = clk_table->MinGfxClk;
smu->gfx_default_soft_max_freq = clk_table->MaxGfxClk;
- smu->gfx_actual_hard_min_freq = 0;
- smu->gfx_actual_soft_max_freq = 0;
-
+ if (smu->gfx_actual_hard_min_freq == 0)
+ smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
+ if (smu->gfx_actual_soft_max_freq == 0)
+ smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
return 0;
}
@@ -1509,8 +1537,10 @@ static int smu_v14_0_0_set_fine_grain_gfx_freq_parameters(struct smu_context *sm
smu->gfx_default_hard_min_freq = clk_table->MinGfxClk;
smu->gfx_default_soft_max_freq = clk_table->MaxGfxClk;
- smu->gfx_actual_hard_min_freq = 0;
- smu->gfx_actual_soft_max_freq = 0;
+ if (smu->gfx_actual_hard_min_freq == 0)
+ smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
+ if (smu->gfx_actual_soft_max_freq == 0)
+ smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
return 0;
}
@@ -1533,6 +1563,14 @@ static int smu_v14_0_0_set_vpe_enable(struct smu_context *smu,
0, NULL);
}
+static int smu_v14_0_0_set_isp_enable(struct smu_context *smu,
+ bool enable)
+{
+ return smu_cmn_send_smc_msg_with_param(smu, enable ?
+ SMU_MSG_PowerUpIspByTile : SMU_MSG_PowerDownIspByTile,
+ ISP_ALL_TILES_MASK, NULL);
+}
+
static int smu_v14_0_0_set_umsch_mm_enable(struct smu_context *smu,
bool enable)
{
@@ -1640,15 +1678,36 @@ static int smu_v14_0_common_set_mall_enable(struct smu_context *smu)
return ret;
}
+static int smu_v14_0_0_restore_user_od_settings(struct smu_context *smu)
+{
+ int ret;
+
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk,
+ smu->gfx_actual_hard_min_freq,
+ NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to restore hard min sclk!\n");
+ return ret;
+ }
+
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk,
+ smu->gfx_actual_soft_max_freq,
+ NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to restore soft max sclk!\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static const struct pptable_funcs smu_v14_0_0_ppt_funcs = {
.check_fw_status = smu_v14_0_check_fw_status,
- .check_fw_version = smu_v14_0_check_fw_version,
+ .check_fw_version = smu_cmn_check_fw_version,
.init_smc_tables = smu_v14_0_0_init_smc_tables,
.fini_smc_tables = smu_v14_0_0_fini_smc_tables,
.get_vbios_bootup_values = smu_v14_0_get_vbios_bootup_values,
.system_features_control = smu_v14_0_0_system_features_control,
- .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
- .send_smc_msg = smu_cmn_send_smc_msg,
.dpm_set_vcn_enable = smu_v14_0_set_vcn_enable,
.dpm_set_jpeg_enable = smu_v14_0_set_jpeg_enable,
.set_default_dpm_table = smu_v14_0_set_default_dpm_tables,
@@ -1662,35 +1721,56 @@ static const struct pptable_funcs smu_v14_0_0_ppt_funcs = {
.gfx_off_control = smu_v14_0_gfx_off_control,
.mode2_reset = smu_v14_0_0_mode2_reset,
.get_dpm_ultimate_freq = smu_v14_0_common_get_dpm_ultimate_freq,
+ .set_soft_freq_limited_range = smu_v14_0_0_set_soft_freq_limited_range,
+ .restore_user_od_settings = smu_v14_0_0_restore_user_od_settings,
.od_edit_dpm_table = smu_v14_0_od_edit_dpm_table,
- .print_clk_levels = smu_v14_0_0_print_clk_levels,
+ .emit_clk_levels = smu_v14_0_0_emit_clk_levels,
.force_clk_levels = smu_v14_0_0_force_clk_levels,
.set_performance_level = smu_v14_0_common_set_performance_level,
.set_fine_grain_gfx_freq_parameters = smu_v14_0_common_set_fine_grain_gfx_freq_parameters,
.set_gfx_power_up_by_imu = smu_v14_0_set_gfx_power_up_by_imu,
.dpm_set_vpe_enable = smu_v14_0_0_set_vpe_enable,
+ .dpm_set_isp_enable = smu_v14_0_0_set_isp_enable,
.dpm_set_umsch_mm_enable = smu_v14_0_0_set_umsch_mm_enable,
.get_dpm_clock_table = smu_v14_0_common_get_dpm_table,
.set_mall_enable = smu_v14_0_common_set_mall_enable,
};
-static void smu_v14_0_0_set_smu_mailbox_registers(struct smu_context *smu)
+static void smu_v14_0_0_init_msg_ctl(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
-
- smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82);
- smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66);
- smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90);
+ struct smu_msg_ctl *ctl = &smu->msg_ctl;
+
+ ctl->smu = smu;
+ mutex_init(&ctl->lock);
+ ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66);
+ ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90);
+ ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82);
+ ctl->config.num_arg_regs = 1;
+ ctl->ops = &smu_msg_v1_ops;
+ ctl->default_timeout = adev->usec_timeout * 20;
+ ctl->message_map = smu_v14_0_0_message_map;
}
void smu_v14_0_0_set_ppt_funcs(struct smu_context *smu)
{
+ struct amdgpu_device *adev = smu->adev;
smu->ppt_funcs = &smu_v14_0_0_ppt_funcs;
- smu->message_map = smu_v14_0_0_message_map;
smu->feature_map = smu_v14_0_0_feature_mask_map;
smu->table_map = smu_v14_0_0_table_map;
smu->is_apu = true;
- smu_v14_0_0_set_smu_mailbox_registers(smu);
+ switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
+ case IP_VERSION(14, 0, 0):
+ case IP_VERSION(14, 0, 4):
+ case IP_VERSION(14, 0, 5):
+ smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_SMU_V14_0_0;
+ break;
+ case IP_VERSION(14, 0, 1):
+ smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_SMU_V14_0_1;
+ break;
+ }
+
+ smu_v14_0_0_init_msg_ctl(smu);
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
index 3f1fcf8c4ee8..a6a88e7b2668 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
@@ -56,13 +56,19 @@
#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c))
-#define FEATURE_MASK(feature) (1ULL << feature)
-#define SMC_DPM_FEATURE ( \
- FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_LINK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \
- FEATURE_MASK(FEATURE_DPM_FCLK_BIT))
+static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu,
+ int od_feature_bit,
+ int32_t *min, int32_t *max);
+
+static const struct smu_feature_bits smu_v14_0_2_dpm_features = {
+ .bits = { SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_LINK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK_BIT) }
+};
+
+#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_2 0x2E
#define MP0_MP1_DATA_REGION_SIZE_COMBOPPTABLE 0x4000
#define DEBUGSMC_MSG_Mode1Reset 2
@@ -79,6 +85,7 @@
#define PP_OD_FEATURE_FAN_ACOUSTIC_TARGET 8
#define PP_OD_FEATURE_FAN_TARGET_TEMPERATURE 9
#define PP_OD_FEATURE_FAN_MINIMUM_PWM 10
+#define PP_OD_FEATURE_FAN_ZERO_RPM_ENABLE 11
static struct cmn2asic_msg_mapping smu_v14_0_2_message_map[SMU_MSG_MAX_COUNT] = {
MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1),
@@ -263,53 +270,9 @@ static const uint8_t smu_v14_0_2_throttler_map[] = {
[THROTTLER_FIT_BIT] = (SMU_THROTTLER_FIT_BIT),
};
-static int
-smu_v14_0_2_get_allowed_feature_mask(struct smu_context *smu,
- uint32_t *feature_mask, uint32_t num)
+static int smu_v14_0_2_init_allowed_features(struct smu_context *smu)
{
- struct amdgpu_device *adev = smu->adev;
- /*u32 smu_version;*/
-
- if (num > 2)
- return -EINVAL;
-
- memset(feature_mask, 0xff, sizeof(uint32_t) * num);
-
- if (adev->pm.pp_feature & PP_SCLK_DPM_MASK) {
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT);
- *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_IMU_BIT);
- }
-#if 0
- if (!(adev->pg_flags & AMD_PG_SUPPORT_ATHUB) ||
- !(adev->pg_flags & AMD_PG_SUPPORT_MMHUB))
- *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_ATHUB_MMHUB_PG_BIT);
-
- if (!(adev->pm.pp_feature & PP_SOCCLK_DPM_MASK))
- *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT);
-
- /* PMFW 78.58 contains a critical fix for gfxoff feature */
- smu_cmn_get_smc_version(smu, NULL, &smu_version);
- if ((smu_version < 0x004e3a00) ||
- !(adev->pm.pp_feature & PP_GFXOFF_MASK))
- *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_GFXOFF_BIT);
-
- if (!(adev->pm.pp_feature & PP_MCLK_DPM_MASK)) {
- *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DPM_UCLK_BIT);
- *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_VMEMP_SCALING_BIT);
- *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_VDDIO_MEM_SCALING_BIT);
- }
-
- if (!(adev->pm.pp_feature & PP_SCLK_DEEP_SLEEP_MASK))
- *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DS_GFXCLK_BIT);
-
- if (!(adev->pm.pp_feature & PP_PCIE_DPM_MASK)) {
- *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DPM_LINK_BIT);
- *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DS_LCLK_BIT);
- }
-
- if (!(adev->pm.pp_feature & PP_ULV_MASK))
- *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_GFX_ULV_BIT);
-#endif
+ smu_feature_list_set_all(smu, SMU_FEATURE_LIST_ALLOWED);
return 0;
}
@@ -414,6 +377,7 @@ static int smu_v14_0_2_tables_init(struct smu_context *smu)
{
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_table *tables = smu_table->tables;
+ int ret;
SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
@@ -435,17 +399,18 @@ static int smu_v14_0_2_tables_init(struct smu_context *smu)
SMU_TABLE_INIT(tables, SMU_TABLE_ECCINFO, sizeof(EccInfoTable_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
- smu_table->metrics_table = kzalloc(sizeof(SmuMetricsExternal_t), GFP_KERNEL);
+ smu_table->metrics_table = kzalloc_obj(SmuMetricsExternal_t);
if (!smu_table->metrics_table)
goto err0_out;
smu_table->metrics_time = 0;
- smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_3);
- smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
- if (!smu_table->gpu_metrics_table)
+ ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS,
+ sizeof(struct gpu_metrics_v1_3),
+ SMU_GPU_METRICS_CACHE_INTERVAL);
+ if (ret)
goto err1_out;
- smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL);
+ smu_table->watermarks_table = kzalloc_obj(Watermarks_t);
if (!smu_table->watermarks_table)
goto err2_out;
@@ -458,7 +423,7 @@ static int smu_v14_0_2_tables_init(struct smu_context *smu)
err3_out:
kfree(smu_table->watermarks_table);
err2_out:
- kfree(smu_table->gpu_metrics_table);
+ smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS);
err1_out:
kfree(smu_table->metrics_table);
err0_out:
@@ -469,8 +434,7 @@ static int smu_v14_0_2_allocate_dpm_context(struct smu_context *smu)
{
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
- smu_dpm->dpm_context = kzalloc(sizeof(struct smu_14_0_dpm_context),
- GFP_KERNEL);
+ smu_dpm->dpm_context = kzalloc_obj(struct smu_14_0_dpm_context);
if (!smu_dpm->dpm_context)
return -ENOMEM;
@@ -500,13 +464,12 @@ static int smu_v14_0_2_set_default_dpm_table(struct smu_context *smu)
struct smu_table_context *table_context = &smu->smu_table;
PPTable_t *pptable = table_context->driver_pptable;
SkuTable_t *skutable = &pptable->SkuTable;
- struct smu_14_0_dpm_table *dpm_table;
- struct smu_14_0_pcie_table *pcie_table;
- uint32_t link_level;
+ struct smu_dpm_table *dpm_table;
int ret = 0;
/* socclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.soc_table;
+ dpm_table->clk_type = SMU_SOCCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
ret = smu_v14_0_set_single_dpm_table(smu,
SMU_SOCCLK,
@@ -517,12 +480,11 @@ static int smu_v14_0_2_set_default_dpm_table(struct smu_context *smu)
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.socclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* gfxclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.gfx_table;
+ dpm_table->clk_type = SMU_GFXCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) {
ret = smu_v14_0_set_single_dpm_table(smu,
SMU_GFXCLK,
@@ -544,18 +506,16 @@ static int smu_v14_0_2_set_default_dpm_table(struct smu_context *smu)
skutable->DriverReportedClocks.GameClockAc)) {
dpm_table->dpm_levels[dpm_table->count - 1].value =
skutable->DriverReportedClocks.GameClockAc;
- dpm_table->max = skutable->DriverReportedClocks.GameClockAc;
}
} else {
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* uclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.uclk_table;
+ dpm_table->clk_type = SMU_UCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
ret = smu_v14_0_set_single_dpm_table(smu,
SMU_UCLK,
@@ -566,12 +526,11 @@ static int smu_v14_0_2_set_default_dpm_table(struct smu_context *smu)
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.uclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* fclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.fclk_table;
+ dpm_table->clk_type = SMU_FCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT)) {
ret = smu_v14_0_set_single_dpm_table(smu,
SMU_FCLK,
@@ -582,12 +541,11 @@ static int smu_v14_0_2_set_default_dpm_table(struct smu_context *smu)
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.fclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* vclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.vclk_table;
+ dpm_table->clk_type = SMU_VCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_VCLK_BIT)) {
ret = smu_v14_0_set_single_dpm_table(smu,
SMU_VCLK,
@@ -598,12 +556,11 @@ static int smu_v14_0_2_set_default_dpm_table(struct smu_context *smu)
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.vclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
/* dclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.dclk_table;
+ dpm_table->clk_type = SMU_DCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCLK_BIT)) {
ret = smu_v14_0_set_single_dpm_table(smu,
SMU_DCLK,
@@ -614,33 +571,11 @@ static int smu_v14_0_2_set_default_dpm_table(struct smu_context *smu)
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
- }
-
- /* lclk dpm table setup */
- pcie_table = &dpm_context->dpm_tables.pcie_table;
- pcie_table->num_of_link_levels = 0;
- for (link_level = 0; link_level < NUM_LINK_LEVELS; link_level++) {
- if (!skutable->PcieGenSpeed[link_level] &&
- !skutable->PcieLaneCount[link_level] &&
- !skutable->LclkFreq[link_level])
- continue;
-
- pcie_table->pcie_gen[pcie_table->num_of_link_levels] =
- skutable->PcieGenSpeed[link_level];
- pcie_table->pcie_lane[pcie_table->num_of_link_levels] =
- skutable->PcieLaneCount[link_level];
- pcie_table->clk_freq[pcie_table->num_of_link_levels] =
- skutable->LclkFreq[link_level];
- pcie_table->num_of_link_levels++;
-
- if (link_level == 0)
- link_level++;
}
/* dcefclk dpm table setup */
dpm_table = &dpm_context->dpm_tables.dcef_table;
+ dpm_table->clk_type = SMU_DCEFCLK;
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCN_BIT)) {
ret = smu_v14_0_set_single_dpm_table(smu,
SMU_DCEFCLK,
@@ -651,8 +586,6 @@ static int smu_v14_0_2_set_default_dpm_table(struct smu_context *smu)
dpm_table->count = 1;
dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100;
dpm_table->dpm_levels[0].enabled = true;
- dpm_table->min = dpm_table->dpm_levels[0].value;
- dpm_table->max = dpm_table->dpm_levels[0].value;
}
return 0;
@@ -661,13 +594,14 @@ static int smu_v14_0_2_set_default_dpm_table(struct smu_context *smu)
static bool smu_v14_0_2_is_dpm_running(struct smu_context *smu)
{
int ret = 0;
- uint64_t feature_enabled;
+ struct smu_feature_bits feature_enabled;
ret = smu_cmn_get_enabled_mask(smu, &feature_enabled);
if (ret)
return false;
- return !!(feature_enabled & SMC_DPM_FEATURE);
+ return smu_feature_bits_test_mask(&feature_enabled,
+ smu_v14_0_2_dpm_features.bits);
}
static uint32_t smu_v14_0_2_get_throttler_status(SmuMetrics_t *metrics)
@@ -727,13 +661,13 @@ static int smu_v14_0_2_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->AverageGfxclkFrequencyPreDs;
break;
case METRICS_AVERAGE_FCLK:
- if (metrics->AverageUclkActivity <= SMU_14_0_2_BUSY_THRESHOLD)
+ if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_14_0_2_BUSY_THRESHOLD)
*value = metrics->AverageFclkFrequencyPostDs;
else
*value = metrics->AverageFclkFrequencyPreDs;
break;
case METRICS_AVERAGE_UCLK:
- if (metrics->AverageUclkActivity <= SMU_14_0_2_BUSY_THRESHOLD)
+ if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_14_0_2_BUSY_THRESHOLD)
*value = metrics->AverageMemclkFrequencyPostDs;
else
*value = metrics->AverageMemclkFrequencyPreDs;
@@ -754,7 +688,11 @@ static int smu_v14_0_2_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->AverageGfxActivity;
break;
case METRICS_AVERAGE_MEMACTIVITY:
- *value = metrics->AverageUclkActivity;
+ *value = smu_safe_u16_nn(metrics->AverageUclkActivity);
+ break;
+ case METRICS_AVERAGE_VCNACTIVITY:
+ *value = max(metrics->AverageVcn0ActivityPercentage,
+ metrics->Vcn1ActivityPercentage);
break;
case METRICS_AVERAGE_SOCKETPOWER:
*value = metrics->AverageSocketPower << 8;
@@ -812,7 +750,7 @@ static int smu_v14_0_2_get_dpm_ultimate_freq(struct smu_context *smu,
{
struct smu_14_0_dpm_context *dpm_context =
smu->smu_dpm.dpm_context;
- struct smu_14_0_dpm_table *dpm_table;
+ struct smu_dpm_table *dpm_table;
switch (clk_type) {
case SMU_MCLK:
@@ -849,9 +787,9 @@ static int smu_v14_0_2_get_dpm_ultimate_freq(struct smu_context *smu,
}
if (min)
- *min = dpm_table->min;
+ *min = SMU_DPM_TABLE_MIN(dpm_table);
if (max)
- *max = dpm_table->max;
+ *max = SMU_DPM_TABLE_MAX(dpm_table);
return 0;
}
@@ -882,6 +820,12 @@ static int smu_v14_0_2_read_sensor(struct smu_context *smu,
(uint32_t *)data);
*size = 4;
break;
+ case AMDGPU_PP_SENSOR_VCN_LOAD:
+ ret = smu_v14_0_2_get_smu_metrics_data(smu,
+ METRICS_AVERAGE_VCNACTIVITY,
+ (uint32_t *)data);
+ *size = 4;
+ break;
case AMDGPU_PP_SENSOR_GPU_AVG_POWER:
ret = smu_v14_0_2_get_smu_metrics_data(smu,
METRICS_AVERAGE_SOCKETPOWER,
@@ -984,8 +928,35 @@ static bool smu_v14_0_2_is_od_feature_supported(struct smu_context *smu,
PPTable_t *pptable = smu->smu_table.driver_pptable;
const OverDriveLimits_t * const overdrive_upperlimits =
&pptable->SkuTable.OverDriveLimitsBasicMax;
+ int32_t min_value, max_value;
+ bool feature_enabled;
+
+ switch (od_feature_bit) {
+ case PP_OD_FEATURE_FAN_CURVE_BIT:
+ feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit));
+ if (feature_enabled) {
+ smu_v14_0_2_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_TEMP,
+ &min_value, &max_value);
+ if (!min_value && !max_value) {
+ feature_enabled = false;
+ goto out;
+ }
+
+ smu_v14_0_2_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_PWM,
+ &min_value, &max_value);
+ if (!min_value && !max_value) {
+ feature_enabled = false;
+ goto out;
+ }
+ }
+ break;
+ default:
+ feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit));
+ break;
+ }
- return overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit);
+out:
+ return feature_enabled;
}
static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu,
@@ -1042,6 +1013,10 @@ static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu,
od_min_setting = overdrive_lowerlimits->FanMinimumPwm;
od_max_setting = overdrive_upperlimits->FanMinimumPwm;
break;
+ case PP_OD_FEATURE_FAN_ZERO_RPM_ENABLE:
+ od_min_setting = overdrive_lowerlimits->FanZeroRpmEnable;
+ od_max_setting = overdrive_upperlimits->FanZeroRpmEnable;
+ break;
default:
od_min_setting = od_max_setting = INT_MAX;
break;
@@ -1053,26 +1028,24 @@ static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu,
*max = od_max_setting;
}
-static int smu_v14_0_2_print_clk_levels(struct smu_context *smu,
- enum smu_clk_type clk_type,
- char *buf)
+static int smu_v14_0_2_emit_clk_levels(struct smu_context *smu,
+ enum smu_clk_type clk_type, char *buf,
+ int *offset)
{
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
struct smu_14_0_dpm_context *dpm_context = smu_dpm->dpm_context;
OverDriveTableExternal_t *od_table =
(OverDriveTableExternal_t *)smu->smu_table.overdrive_table;
- struct smu_14_0_dpm_table *single_dpm_table;
- struct smu_14_0_pcie_table *pcie_table;
+ struct smu_dpm_table *single_dpm_table = NULL;
+ struct smu_pcie_table *pcie_table;
uint32_t gen_speed, lane_width;
- int i, curr_freq, size = 0;
+ int i, curr_freq, size = *offset, start_offset = *offset;
int32_t min_value, max_value;
int ret = 0;
- smu_cmn_get_sysfs_buf(&buf, &size);
-
if (amdgpu_ras_intr_triggered()) {
- size += sysfs_emit_at(buf, size, "unavailable\n");
- return size;
+ sysfs_emit_at(buf, size, "unavailable\n");
+ return -EBUSY;
}
switch (clk_type) {
@@ -1099,61 +1072,6 @@ static int smu_v14_0_2_print_clk_levels(struct smu_context *smu,
case SMU_DCEFCLK:
single_dpm_table = &(dpm_context->dpm_tables.dcef_table);
break;
- default:
- break;
- }
-
- switch (clk_type) {
- case SMU_SCLK:
- case SMU_MCLK:
- case SMU_SOCCLK:
- case SMU_FCLK:
- case SMU_VCLK:
- case SMU_VCLK1:
- case SMU_DCLK:
- case SMU_DCLK1:
- case SMU_DCEFCLK:
- ret = smu_v14_0_2_get_current_clk_freq_by_table(smu, clk_type, &curr_freq);
- if (ret) {
- dev_err(smu->adev->dev, "Failed to get current clock freq!");
- return ret;
- }
-
- if (single_dpm_table->is_fine_grained) {
- /*
- * For fine grained dpms, there are only two dpm levels:
- * - level 0 -> min clock freq
- * - level 1 -> max clock freq
- * And the current clock frequency can be any value between them.
- * So, if the current clock frequency is not at level 0 or level 1,
- * we will fake it as three dpm levels:
- * - level 0 -> min clock freq
- * - level 1 -> current actual clock freq
- * - level 2 -> max clock freq
- */
- if ((single_dpm_table->dpm_levels[0].value != curr_freq) &&
- (single_dpm_table->dpm_levels[1].value != curr_freq)) {
- size += sysfs_emit_at(buf, size, "0: %uMhz\n",
- single_dpm_table->dpm_levels[0].value);
- size += sysfs_emit_at(buf, size, "1: %uMhz *\n",
- curr_freq);
- size += sysfs_emit_at(buf, size, "2: %uMhz\n",
- single_dpm_table->dpm_levels[1].value);
- } else {
- size += sysfs_emit_at(buf, size, "0: %uMhz %s\n",
- single_dpm_table->dpm_levels[0].value,
- single_dpm_table->dpm_levels[0].value == curr_freq ? "*" : "");
- size += sysfs_emit_at(buf, size, "1: %uMhz %s\n",
- single_dpm_table->dpm_levels[1].value,
- single_dpm_table->dpm_levels[1].value == curr_freq ? "*" : "");
- }
- } else {
- for (i = 0; i < single_dpm_table->count; i++)
- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
- i, single_dpm_table->dpm_levels[i].value,
- single_dpm_table->dpm_levels[i].value == curr_freq ? "*" : "");
- }
- break;
case SMU_PCIE:
ret = smu_v14_0_2_get_smu_metrics_data(smu,
METRICS_PCIE_RATE,
@@ -1168,25 +1086,10 @@ static int smu_v14_0_2_print_clk_levels(struct smu_context *smu,
return ret;
pcie_table = &(dpm_context->dpm_tables.pcie_table);
- for (i = 0; i < pcie_table->num_of_link_levels; i++)
- size += sysfs_emit_at(buf, size, "%d: %s %s %dMhz %s\n", i,
- (pcie_table->pcie_gen[i] == 0) ? "2.5GT/s," :
- (pcie_table->pcie_gen[i] == 1) ? "5.0GT/s," :
- (pcie_table->pcie_gen[i] == 2) ? "8.0GT/s," :
- (pcie_table->pcie_gen[i] == 3) ? "16.0GT/s," :
- (pcie_table->pcie_gen[i] == 4) ? "32.0GT/s," : "",
- (pcie_table->pcie_lane[i] == 1) ? "x1" :
- (pcie_table->pcie_lane[i] == 2) ? "x2" :
- (pcie_table->pcie_lane[i] == 3) ? "x4" :
- (pcie_table->pcie_lane[i] == 4) ? "x8" :
- (pcie_table->pcie_lane[i] == 5) ? "x12" :
- (pcie_table->pcie_lane[i] == 6) ? "x16" :
- (pcie_table->pcie_lane[i] == 7) ? "x32" : "",
- pcie_table->clk_freq[i],
- (gen_speed == DECODE_GEN_SPEED(pcie_table->pcie_gen[i])) &&
- (lane_width == DECODE_LANE_WIDTH(pcie_table->pcie_lane[i])) ?
- "*" : "");
- break;
+ return smu_cmn_print_pcie_levels(smu, pcie_table,
+ SMU_DPM_PCIE_GEN_IDX(gen_speed),
+ SMU_DPM_PCIE_WIDTH_IDX(lane_width),
+ buf, offset);
case SMU_OD_SCLK:
if (!smu_v14_0_2_is_od_feature_supported(smu,
@@ -1320,6 +1223,24 @@ static int smu_v14_0_2_print_clk_levels(struct smu_context *smu,
min_value, max_value);
break;
+ case SMU_OD_FAN_ZERO_RPM_ENABLE:
+ if (!smu_v14_0_2_is_od_feature_supported(smu,
+ PP_OD_FEATURE_ZERO_FAN_BIT))
+ break;
+
+ size += sysfs_emit_at(buf, size, "FAN_ZERO_RPM_ENABLE:\n");
+ size += sysfs_emit_at(buf, size, "%d\n",
+ (int)od_table->OverDriveTable.FanZeroRpmEnable);
+
+ size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");
+ smu_v14_0_2_get_od_setting_limits(smu,
+ PP_OD_FEATURE_FAN_ZERO_RPM_ENABLE,
+ &min_value,
+ &max_value);
+ size += sysfs_emit_at(buf, size, "ZERO_RPM_ENABLE: %u %u\n",
+ min_value, max_value);
+ break;
+
case SMU_OD_RANGE:
if (!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT) &&
!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_UCLK_BIT) &&
@@ -1364,7 +1285,21 @@ static int smu_v14_0_2_print_clk_levels(struct smu_context *smu,
break;
}
- return size;
+ if (single_dpm_table) {
+ ret = smu_v14_0_2_get_current_clk_freq_by_table(smu, clk_type,
+ &curr_freq);
+ if (ret) {
+ dev_err(smu->adev->dev,
+ "Failed to get current clock freq!");
+ return ret;
+ }
+ return smu_cmn_print_dpm_clk_levels(smu, single_dpm_table,
+ curr_freq, buf, offset);
+ }
+
+ *offset += size - start_offset;
+
+ return 0;
}
static int smu_v14_0_2_force_clk_levels(struct smu_context *smu,
@@ -1373,7 +1308,7 @@ static int smu_v14_0_2_force_clk_levels(struct smu_context *smu,
{
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
struct smu_14_0_dpm_context *dpm_context = smu_dpm->dpm_context;
- struct smu_14_0_dpm_table *single_dpm_table;
+ struct smu_dpm_table *single_dpm_table;
uint32_t soft_min_level, soft_max_level;
uint32_t min_freq, max_freq;
int ret = 0;
@@ -1419,7 +1354,7 @@ static int smu_v14_0_2_force_clk_levels(struct smu_context *smu,
case SMU_VCLK1:
case SMU_DCLK:
case SMU_DCLK1:
- if (single_dpm_table->is_fine_grained) {
+ if (single_dpm_table->flags & SMU_DPM_TABLE_FINE_GRAINED) {
/* There is only 2 levels for fine grained DPM */
soft_max_level = (soft_max_level >= 1 ? 1 : 0);
soft_min_level = (soft_min_level >= 1 ? 1 : 0);
@@ -1452,50 +1387,81 @@ static int smu_v14_0_2_update_pcie_parameters(struct smu_context *smu,
uint8_t pcie_width_cap)
{
struct smu_14_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
- struct smu_14_0_pcie_table *pcie_table =
+ struct smu_pcie_table *pcie_table =
&dpm_context->dpm_tables.pcie_table;
- int num_of_levels = pcie_table->num_of_link_levels;
+ int lclk_levels;
uint32_t smu_pcie_arg;
- int ret, i;
+ uint32_t link_level;
+ struct smu_table_context *table_context = &smu->smu_table;
+ PPTable_t *pptable = table_context->driver_pptable;
+ SkuTable_t *skutable = &pptable->SkuTable;
+ int ret = 0;
+ int i;
+
+ pcie_table->lclk_levels = 0;
+ for (link_level = 0; link_level < NUM_LINK_LEVELS; link_level++) {
+ if (!skutable->PcieGenSpeed[link_level] &&
+ !skutable->PcieLaneCount[link_level] &&
+ !skutable->LclkFreq[link_level])
+ continue;
- if (!num_of_levels)
+ pcie_table->pcie_gen[pcie_table->lclk_levels] =
+ skutable->PcieGenSpeed[link_level];
+ pcie_table->pcie_lane[pcie_table->lclk_levels] =
+ skutable->PcieLaneCount[link_level];
+ pcie_table->lclk_freq[pcie_table->lclk_levels] =
+ skutable->LclkFreq[link_level];
+ pcie_table->lclk_levels++;
+ }
+ lclk_levels = pcie_table->lclk_levels;
+ if (!lclk_levels)
return 0;
if (!(smu->adev->pm.pp_feature & PP_PCIE_DPM_MASK)) {
- if (pcie_table->pcie_gen[num_of_levels - 1] < pcie_gen_cap)
- pcie_gen_cap = pcie_table->pcie_gen[num_of_levels - 1];
+ if (pcie_table->pcie_gen[lclk_levels - 1] < pcie_gen_cap)
+ pcie_gen_cap = pcie_table->pcie_gen[lclk_levels - 1];
- if (pcie_table->pcie_lane[num_of_levels - 1] < pcie_width_cap)
- pcie_width_cap = pcie_table->pcie_lane[num_of_levels - 1];
+ if (pcie_table->pcie_lane[lclk_levels - 1] < pcie_width_cap)
+ pcie_width_cap = pcie_table->pcie_lane[lclk_levels - 1];
/* Force all levels to use the same settings */
- for (i = 0; i < num_of_levels; i++) {
+ for (i = 0; i < lclk_levels; i++) {
pcie_table->pcie_gen[i] = pcie_gen_cap;
pcie_table->pcie_lane[i] = pcie_width_cap;
+ smu_pcie_arg = i << 16;
+ smu_pcie_arg |= pcie_table->pcie_gen[i] << 8;
+ smu_pcie_arg |= pcie_table->pcie_lane[i];
+
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_OverridePcieParameters,
+ smu_pcie_arg,
+ NULL);
+ if (ret)
+ break;
}
} else {
- for (i = 0; i < num_of_levels; i++) {
- if (pcie_table->pcie_gen[i] > pcie_gen_cap)
- pcie_table->pcie_gen[i] = pcie_gen_cap;
- if (pcie_table->pcie_lane[i] > pcie_width_cap)
- pcie_table->pcie_lane[i] = pcie_width_cap;
- }
- }
-
- for (i = 0; i < num_of_levels; i++) {
- smu_pcie_arg = i << 16;
- smu_pcie_arg |= pcie_table->pcie_gen[i] << 8;
- smu_pcie_arg |= pcie_table->pcie_lane[i];
-
- ret = smu_cmn_send_smc_msg_with_param(smu,
+ for (i = 0; i < lclk_levels; i++) {
+ if (pcie_table->pcie_gen[i] > pcie_gen_cap ||
+ pcie_table->pcie_lane[i] > pcie_width_cap) {
+ pcie_table->pcie_gen[i] = pcie_table->pcie_gen[i] > pcie_gen_cap ?
+ pcie_gen_cap : pcie_table->pcie_gen[i];
+ pcie_table->pcie_lane[i] = pcie_table->pcie_lane[i] > pcie_width_cap ?
+ pcie_width_cap : pcie_table->pcie_lane[i];
+ smu_pcie_arg = i << 16;
+ smu_pcie_arg |= pcie_table->pcie_gen[i] << 8;
+ smu_pcie_arg |= pcie_table->pcie_lane[i];
+
+ ret = smu_cmn_send_smc_msg_with_param(smu,
SMU_MSG_OverridePcieParameters,
smu_pcie_arg,
NULL);
- if (ret)
- return ret;
+ if (ret)
+ break;
+ }
+ }
}
- return 0;
+ return ret;
}
static const struct smu_temperature_range smu14_thermal_policy[] = {
@@ -1541,18 +1507,12 @@ static int smu_v14_0_2_populate_umd_state_clk(struct smu_context *smu)
{
struct smu_14_0_dpm_context *dpm_context =
smu->smu_dpm.dpm_context;
- struct smu_14_0_dpm_table *gfx_table =
- &dpm_context->dpm_tables.gfx_table;
- struct smu_14_0_dpm_table *mem_table =
- &dpm_context->dpm_tables.uclk_table;
- struct smu_14_0_dpm_table *soc_table =
- &dpm_context->dpm_tables.soc_table;
- struct smu_14_0_dpm_table *vclk_table =
- &dpm_context->dpm_tables.vclk_table;
- struct smu_14_0_dpm_table *dclk_table =
- &dpm_context->dpm_tables.dclk_table;
- struct smu_14_0_dpm_table *fclk_table =
- &dpm_context->dpm_tables.fclk_table;
+ struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table;
+ struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table;
+ struct smu_dpm_table *soc_table = &dpm_context->dpm_tables.soc_table;
+ struct smu_dpm_table *vclk_table = &dpm_context->dpm_tables.vclk_table;
+ struct smu_dpm_table *dclk_table = &dpm_context->dpm_tables.dclk_table;
+ struct smu_dpm_table *fclk_table = &dpm_context->dpm_tables.fclk_table;
struct smu_umd_pstate_table *pstate_table =
&smu->pstate_table;
struct smu_table_context *table_context = &smu->smu_table;
@@ -1560,38 +1520,39 @@ static int smu_v14_0_2_populate_umd_state_clk(struct smu_context *smu)
DriverReportedClocks_t driver_clocks =
pptable->SkuTable.DriverReportedClocks;
- pstate_table->gfxclk_pstate.min = gfx_table->min;
+ pstate_table->gfxclk_pstate.min = SMU_DPM_TABLE_MIN(gfx_table);
if (driver_clocks.GameClockAc &&
- (driver_clocks.GameClockAc < gfx_table->max))
+ (driver_clocks.GameClockAc < SMU_DPM_TABLE_MAX(gfx_table)))
pstate_table->gfxclk_pstate.peak = driver_clocks.GameClockAc;
else
- pstate_table->gfxclk_pstate.peak = gfx_table->max;
+ pstate_table->gfxclk_pstate.peak = SMU_DPM_TABLE_MAX(gfx_table);
- pstate_table->uclk_pstate.min = mem_table->min;
- pstate_table->uclk_pstate.peak = mem_table->max;
+ pstate_table->uclk_pstate.min = SMU_DPM_TABLE_MIN(mem_table);
+ pstate_table->uclk_pstate.peak = SMU_DPM_TABLE_MAX(mem_table);
- pstate_table->socclk_pstate.min = soc_table->min;
- pstate_table->socclk_pstate.peak = soc_table->max;
+ pstate_table->socclk_pstate.min = SMU_DPM_TABLE_MIN(soc_table);
+ pstate_table->socclk_pstate.peak = SMU_DPM_TABLE_MAX(soc_table);
- pstate_table->vclk_pstate.min = vclk_table->min;
- pstate_table->vclk_pstate.peak = vclk_table->max;
+ pstate_table->vclk_pstate.min = SMU_DPM_TABLE_MIN(vclk_table);
+ pstate_table->vclk_pstate.peak = SMU_DPM_TABLE_MAX(vclk_table);
- pstate_table->dclk_pstate.min = dclk_table->min;
- pstate_table->dclk_pstate.peak = dclk_table->max;
+ pstate_table->dclk_pstate.min = SMU_DPM_TABLE_MIN(dclk_table);
+ pstate_table->dclk_pstate.peak = SMU_DPM_TABLE_MAX(dclk_table);
- pstate_table->fclk_pstate.min = fclk_table->min;
- pstate_table->fclk_pstate.peak = fclk_table->max;
+ pstate_table->fclk_pstate.min = SMU_DPM_TABLE_MIN(fclk_table);
+ pstate_table->fclk_pstate.peak = SMU_DPM_TABLE_MAX(fclk_table);
if (driver_clocks.BaseClockAc &&
- driver_clocks.BaseClockAc < gfx_table->max)
+ driver_clocks.BaseClockAc < SMU_DPM_TABLE_MAX(gfx_table))
pstate_table->gfxclk_pstate.standard = driver_clocks.BaseClockAc;
else
- pstate_table->gfxclk_pstate.standard = gfx_table->max;
- pstate_table->uclk_pstate.standard = mem_table->max;
- pstate_table->socclk_pstate.standard = soc_table->min;
- pstate_table->vclk_pstate.standard = vclk_table->min;
- pstate_table->dclk_pstate.standard = dclk_table->min;
- pstate_table->fclk_pstate.standard = fclk_table->min;
+ pstate_table->gfxclk_pstate.standard =
+ SMU_DPM_TABLE_MAX(gfx_table);
+ pstate_table->uclk_pstate.standard = SMU_DPM_TABLE_MAX(mem_table);
+ pstate_table->socclk_pstate.standard = SMU_DPM_TABLE_MIN(soc_table);
+ pstate_table->vclk_pstate.standard = SMU_DPM_TABLE_MIN(vclk_table);
+ pstate_table->dclk_pstate.standard = SMU_DPM_TABLE_MIN(dclk_table);
+ pstate_table->fclk_pstate.standard = SMU_DPM_TABLE_MIN(fclk_table);
return 0;
}
@@ -1656,26 +1617,51 @@ static int smu_v14_0_2_get_power_limit(struct smu_context *smu,
uint32_t *min_power_limit)
{
struct smu_table_context *table_context = &smu->smu_table;
+ struct smu_14_0_2_powerplay_table *powerplay_table =
+ table_context->power_play_table;
PPTable_t *pptable = table_context->driver_pptable;
CustomSkuTable_t *skutable = &pptable->CustomSkuTable;
- uint32_t power_limit;
+ uint32_t pp_limit = smu->adev->pm.ac_power ?
+ skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] :
+ skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0];
uint32_t msg_limit = pptable->SkuTable.MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
+ uint32_t min_limit = min_t(uint32_t, pp_limit, msg_limit);
+ uint32_t max_limit = max_t(uint32_t, pp_limit, msg_limit);
+ int16_t od_percent_upper = 0, od_percent_lower = 0;
+ int ret;
- if (smu_v14_0_get_current_power_limit(smu, &power_limit))
- power_limit = smu->adev->pm.ac_power ?
- skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] :
- skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0];
+ if (current_power_limit) {
+ ret = smu_v14_0_get_current_power_limit(smu, current_power_limit);
+ if (ret)
+ *current_power_limit = pp_limit;
+ }
- if (current_power_limit)
- *current_power_limit = power_limit;
if (default_power_limit)
- *default_power_limit = power_limit;
+ *default_power_limit = pp_limit;
+
+ if (powerplay_table) {
+ if (smu->od_enabled &&
+ smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_PPT_BIT)) {
+ od_percent_upper = pptable->SkuTable.OverDriveLimitsBasicMax.Ppt;
+ od_percent_lower = pptable->SkuTable.OverDriveLimitsBasicMin.Ppt;
+ } else if (smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_PPT_BIT)) {
+ od_percent_upper = 0;
+ od_percent_lower = pptable->SkuTable.OverDriveLimitsBasicMin.Ppt;
+ }
+ }
- if (max_power_limit)
- *max_power_limit = msg_limit;
+ dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
+ od_percent_upper, od_percent_lower, pp_limit);
- if (min_power_limit)
- *min_power_limit = 0;
+ if (max_power_limit) {
+ *max_power_limit = max_limit * (100 + od_percent_upper);
+ *max_power_limit /= 100;
+ }
+
+ if (min_power_limit) {
+ *min_power_limit = min_limit * (100 + od_percent_lower);
+ *min_power_limit /= 100;
+ }
return 0;
}
@@ -1926,7 +1912,7 @@ static int smu_v14_0_2_i2c_xfer(struct i2c_adapter *i2c_adap,
if (!adev->pm.dpm_enabled)
return -EBUSY;
- req = kzalloc(sizeof(*req), GFP_KERNEL);
+ req = kzalloc_obj(*req);
if (!req)
return -ENOMEM;
@@ -2026,10 +2012,10 @@ static int smu_v14_0_2_i2c_control_init(struct smu_context *smu)
control->quirks = &smu_v14_0_2_i2c_control_quirks;
i2c_set_adapdata(control, smu_i2c);
- res = i2c_add_adapter(control);
+ res = devm_i2c_add_adapter(adev->dev, control);
if (res) {
DRM_ERROR("Failed to register hw i2c, err: %d\n", res);
- goto Out_err;
+ return res;
}
}
@@ -2039,27 +2025,12 @@ static int smu_v14_0_2_i2c_control_init(struct smu_context *smu)
adev->pm.fru_eeprom_i2c_bus = &adev->pm.smu_i2c[0].adapter;
return 0;
-Out_err:
- for ( ; i >= 0; i--) {
- struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i];
- struct i2c_adapter *control = &smu_i2c->adapter;
-
- i2c_del_adapter(control);
- }
- return res;
}
static void smu_v14_0_2_i2c_control_fini(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- int i;
-
- for (i = 0; i < MAX_SMU_I2C_BUSES; i++) {
- struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i];
- struct i2c_adapter *control = &smu_i2c->adapter;
- i2c_del_adapter(control);
- }
adev->pm.ras_eeprom_i2c_bus = NULL;
adev->pm.fru_eeprom_i2c_bus = NULL;
}
@@ -2096,10 +2067,15 @@ static int smu_v14_0_2_mode1_reset(struct smu_context *smu)
ret = smu_cmn_send_debug_smc_msg(smu, DEBUGSMC_MSG_Mode1Reset);
if (!ret) {
- if (amdgpu_emu_mode == 1)
+ if (amdgpu_emu_mode == 1) {
msleep(50000);
- else
+ } else {
+ /* disable mmio access while doing mode 1 reset*/
+ smu->adev->no_hw_access = true;
+ /* ensure no_hw_access is globally visible before any MMIO */
+ smp_mb();
msleep(1000);
+ }
}
return ret;
@@ -2125,25 +2101,35 @@ static int smu_v14_0_2_enable_gfx_features(struct smu_context *smu)
return -EOPNOTSUPP;
}
-static void smu_v14_0_2_set_smu_mailbox_registers(struct smu_context *smu)
+static void smu_v14_0_2_init_msg_ctl(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
-
- smu->param_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_82);
- smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_66);
- smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_90);
-
- smu->debug_param_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_53);
- smu->debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_75);
- smu->debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_54);
+ struct smu_msg_ctl *ctl = &smu->msg_ctl;
+
+ ctl->smu = smu;
+ mutex_init(&ctl->lock);
+ ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_66);
+ ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_90);
+ ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_82);
+ ctl->config.num_arg_regs = 1;
+ ctl->ops = &smu_msg_v1_ops;
+ ctl->default_timeout = adev->usec_timeout * 20;
+ ctl->message_map = smu_v14_0_2_message_map;
+ ctl->flags = 0;
+
+ /* Set up debug mailbox registers */
+ ctl->config.debug_param_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_53);
+ ctl->config.debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_75);
+ ctl->config.debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_54);
+ ctl->flags |= SMU_MSG_CTL_DEBUG_MAILBOX;
}
static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu,
void **table)
{
- struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v1_3 *gpu_metrics =
- (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table;
+ (struct gpu_metrics_v1_3 *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
SmuMetricsExternal_t metrics_ext;
SmuMetrics_t *metrics = &metrics_ext.SmuMetrics;
int ret = 0;
@@ -2165,19 +2151,18 @@ static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu,
metrics->AvgTemperature[TEMP_VR_MEM1]);
gpu_metrics->average_gfx_activity = metrics->AverageGfxActivity;
- gpu_metrics->average_umc_activity = metrics->AverageUclkActivity;
+ gpu_metrics->average_umc_activity = smu_safe_u16_nn(metrics->AverageUclkActivity);
gpu_metrics->average_mm_activity = max(metrics->AverageVcn0ActivityPercentage,
metrics->Vcn1ActivityPercentage);
gpu_metrics->average_socket_power = metrics->AverageSocketPower;
- gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
if (metrics->AverageGfxActivity <= SMU_14_0_2_BUSY_THRESHOLD)
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs;
else
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPreDs;
- if (metrics->AverageUclkActivity <= SMU_14_0_2_BUSY_THRESHOLD)
+ if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_14_0_2_BUSY_THRESHOLD)
gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPostDs;
else
gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPreDs;
@@ -2217,6 +2202,8 @@ static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu,
*table = (void *)gpu_metrics;
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
return sizeof(struct gpu_metrics_v1_3);
}
@@ -2230,17 +2217,61 @@ static void smu_v14_0_2_dump_od_table(struct smu_context *smu,
od_table->OverDriveTable.UclkFmax);
}
+#define OD_ERROR_MSG_MAP(msg) \
+ [msg] = #msg
+
+static const char *od_error_message[] = {
+ OD_ERROR_MSG_MAP(OD_REQUEST_ADVANCED_NOT_SUPPORTED),
+ OD_ERROR_MSG_MAP(OD_UNSUPPORTED_FEATURE),
+ OD_ERROR_MSG_MAP(OD_INVALID_FEATURE_COMBO_ERROR),
+ OD_ERROR_MSG_MAP(OD_GFXCLK_VF_CURVE_OFFSET_ERROR),
+ OD_ERROR_MSG_MAP(OD_VDD_GFX_VMAX_ERROR),
+ OD_ERROR_MSG_MAP(OD_VDD_SOC_VMAX_ERROR),
+ OD_ERROR_MSG_MAP(OD_PPT_ERROR),
+ OD_ERROR_MSG_MAP(OD_FAN_MIN_PWM_ERROR),
+ OD_ERROR_MSG_MAP(OD_FAN_ACOUSTIC_TARGET_ERROR),
+ OD_ERROR_MSG_MAP(OD_FAN_ACOUSTIC_LIMIT_ERROR),
+ OD_ERROR_MSG_MAP(OD_FAN_TARGET_TEMP_ERROR),
+ OD_ERROR_MSG_MAP(OD_FAN_ZERO_RPM_STOP_TEMP_ERROR),
+ OD_ERROR_MSG_MAP(OD_FAN_CURVE_PWM_ERROR),
+ OD_ERROR_MSG_MAP(OD_FAN_CURVE_TEMP_ERROR),
+ OD_ERROR_MSG_MAP(OD_FULL_CTRL_GFXCLK_ERROR),
+ OD_ERROR_MSG_MAP(OD_FULL_CTRL_UCLK_ERROR),
+ OD_ERROR_MSG_MAP(OD_FULL_CTRL_FCLK_ERROR),
+ OD_ERROR_MSG_MAP(OD_FULL_CTRL_VDD_GFX_ERROR),
+ OD_ERROR_MSG_MAP(OD_FULL_CTRL_VDD_SOC_ERROR),
+ OD_ERROR_MSG_MAP(OD_TDC_ERROR),
+ OD_ERROR_MSG_MAP(OD_GFXCLK_ERROR),
+ OD_ERROR_MSG_MAP(OD_UCLK_ERROR),
+ OD_ERROR_MSG_MAP(OD_FCLK_ERROR),
+ OD_ERROR_MSG_MAP(OD_OP_TEMP_ERROR),
+ OD_ERROR_MSG_MAP(OD_OP_GFX_EDC_ERROR),
+ OD_ERROR_MSG_MAP(OD_OP_GFX_PCC_ERROR),
+ OD_ERROR_MSG_MAP(OD_POWER_FEATURE_CTRL_ERROR),
+};
+
static int smu_v14_0_2_upload_overdrive_table(struct smu_context *smu,
OverDriveTableExternal_t *od_table)
{
- int ret;
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_OVERDRIVE,
- 0,
- (void *)od_table,
- true);
- if (ret)
- dev_err(smu->adev->dev, "Failed to upload overdrive table!\n");
+ uint32_t read_arg = 0;
+ int ret, od_error_type;
+
+ ret = smu_cmn_update_table_read_arg(smu,
+ SMU_TABLE_OVERDRIVE,
+ 0,
+ (void *)od_table,
+ &read_arg,
+ true);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to upload overdrive table, ret:%d\n", ret);
+ if ((read_arg & 0xff) == TABLE_TRANSFER_FAILED) {
+ od_error_type = read_arg >> 16;
+ dev_err(smu->adev->dev, "Invalid overdrive table content: %s (%d)\n",
+ od_error_type < ARRAY_SIZE(od_error_message) ?
+ od_error_message[od_error_type] : "unknown",
+ od_error_type);
+ }
+ }
return ret;
}
@@ -2260,7 +2291,9 @@ static void smu_v14_0_2_set_supported_od_feature_mask(struct smu_context *smu)
OD_OPS_SUPPORT_FAN_TARGET_TEMPERATURE_RETRIEVE |
OD_OPS_SUPPORT_FAN_TARGET_TEMPERATURE_SET |
OD_OPS_SUPPORT_FAN_MINIMUM_PWM_RETRIEVE |
- OD_OPS_SUPPORT_FAN_MINIMUM_PWM_SET;
+ OD_OPS_SUPPORT_FAN_MINIMUM_PWM_SET |
+ OD_OPS_SUPPORT_FAN_ZERO_RPM_ENABLE_RETRIEVE |
+ OD_OPS_SUPPORT_FAN_ZERO_RPM_ENABLE_SET;
}
static int smu_v14_0_2_get_overdrive_table(struct smu_context *smu,
@@ -2339,6 +2372,8 @@ static int smu_v14_0_2_set_default_od_settings(struct smu_context *smu)
user_od_table_bak.OverDriveTable.FanTargetTemperature;
user_od_table->OverDriveTable.FanMinimumPwm =
user_od_table_bak.OverDriveTable.FanMinimumPwm;
+ user_od_table->OverDriveTable.FanZeroRpmEnable =
+ user_od_table_bak.OverDriveTable.FanZeroRpmEnable;
}
smu_v14_0_2_set_supported_od_feature_mask(smu);
@@ -2356,7 +2391,8 @@ static int smu_v14_0_2_restore_user_od_settings(struct smu_context *smu)
user_od_table->OverDriveTable.FeatureCtrlMask = BIT(PP_OD_FEATURE_GFXCLK_BIT) |
BIT(PP_OD_FEATURE_UCLK_BIT) |
BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT) |
- BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+ BIT(PP_OD_FEATURE_FAN_CURVE_BIT) |
+ BIT(PP_OD_FEATURE_ZERO_FAN_BIT);
res = smu_v14_0_2_upload_overdrive_table(smu, user_od_table);
user_od_table->OverDriveTable.FeatureCtrlMask = 0;
if (res == 0)
@@ -2385,6 +2421,12 @@ static int smu_v14_0_2_od_restore_table_single(struct smu_context *smu, long inp
}
od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+ od_table->OverDriveTable.FeatureCtrlMask &= ~BIT(PP_OD_FEATURE_FAN_LEGACY_BIT);
+ break;
+ case PP_OD_EDIT_FAN_ZERO_RPM_ENABLE:
+ od_table->OverDriveTable.FanZeroRpmEnable =
+ boot_overdrive_table->OverDriveTable.FanZeroRpmEnable;
+ od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT);
break;
case PP_OD_EDIT_ACOUSTIC_LIMIT:
od_table->OverDriveTable.AcousticLimitRpmThreshold =
@@ -2408,7 +2450,8 @@ static int smu_v14_0_2_od_restore_table_single(struct smu_context *smu, long inp
od_table->OverDriveTable.FanMinimumPwm =
boot_overdrive_table->OverDriveTable.FanMinimumPwm;
od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
- od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+ od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_LEGACY_BIT);
+ od_table->OverDriveTable.FeatureCtrlMask &= ~BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
break;
default:
dev_info(adev->dev, "Invalid table index: %ld\n", input);
@@ -2578,6 +2621,7 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu,
od_table->OverDriveTable.FanLinearPwmPoints[input[0]] = input[2];
od_table->OverDriveTable.FanMode = FAN_MODE_MANUAL_LINEAR;
od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+ od_table->OverDriveTable.FeatureCtrlMask &= ~BIT(PP_OD_FEATURE_FAN_LEGACY_BIT);
break;
case PP_OD_EDIT_ACOUSTIC_LIMIT:
@@ -2647,7 +2691,7 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu,
break;
case PP_OD_EDIT_FAN_MINIMUM_PWM:
- if (!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_FAN_CURVE_BIT)) {
+ if (!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_FAN_LEGACY_BIT)) {
dev_warn(adev->dev, "Fan curve setting not supported!\n");
return -ENOTSUPP;
}
@@ -2665,7 +2709,29 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu,
od_table->OverDriveTable.FanMinimumPwm = input[0];
od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
- od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+ od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_LEGACY_BIT);
+ od_table->OverDriveTable.FeatureCtrlMask &= ~BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+ break;
+
+ case PP_OD_EDIT_FAN_ZERO_RPM_ENABLE:
+ if (!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_ZERO_FAN_BIT)) {
+ dev_warn(adev->dev, "Zero RPM setting not supported!\n");
+ return -ENOTSUPP;
+ }
+
+ smu_v14_0_2_get_od_setting_limits(smu,
+ PP_OD_FEATURE_FAN_ZERO_RPM_ENABLE,
+ &minimum,
+ &maximum);
+ if (input[0] < minimum ||
+ input[0] > maximum) {
+ dev_info(adev->dev, "zero RPM enable setting(%ld) must be within [%d, %d]!\n",
+ input[0], minimum, maximum);
+ return -EINVAL;
+ }
+
+ od_table->OverDriveTable.FanZeroRpmEnable = input[0];
+ od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT);
break;
case PP_OD_RESTORE_DEFAULT_TABLE:
@@ -2771,7 +2837,7 @@ static int smu_v14_0_2_set_power_limit(struct smu_context *smu,
}
static const struct pptable_funcs smu_v14_0_2_ppt_funcs = {
- .get_allowed_feature_mask = smu_v14_0_2_get_allowed_feature_mask,
+ .init_allowed_features = smu_v14_0_2_init_allowed_features,
.set_default_dpm_table = smu_v14_0_2_set_default_dpm_table,
.i2c_init = smu_v14_0_2_i2c_control_init,
.i2c_fini = smu_v14_0_2_i2c_control_fini,
@@ -2785,7 +2851,7 @@ static const struct pptable_funcs smu_v14_0_2_ppt_funcs = {
.fini_power = smu_v14_0_fini_power,
.check_fw_status = smu_v14_0_check_fw_status,
.setup_pptable = smu_v14_0_2_setup_pptable,
- .check_fw_version = smu_v14_0_check_fw_version,
+ .check_fw_version = smu_cmn_check_fw_version,
.set_driver_table_location = smu_v14_0_set_driver_table_location,
.system_features_control = smu_v14_0_system_features_control,
.set_allowed_mask = smu_v14_0_set_allowed_mask,
@@ -2796,7 +2862,7 @@ static const struct pptable_funcs smu_v14_0_2_ppt_funcs = {
.get_vbios_bootup_values = smu_v14_0_get_vbios_bootup_values,
.read_sensor = smu_v14_0_2_read_sensor,
.feature_is_enabled = smu_cmn_feature_is_enabled,
- .print_clk_levels = smu_v14_0_2_print_clk_levels,
+ .emit_clk_levels = smu_v14_0_2_emit_clk_levels,
.force_clk_levels = smu_v14_0_2_force_clk_levels,
.update_pcie_parameters = smu_v14_0_2_update_pcie_parameters,
.get_thermal_temperature_range = smu_v14_0_2_get_thermal_temperature_range,
@@ -2845,11 +2911,11 @@ static const struct pptable_funcs smu_v14_0_2_ppt_funcs = {
void smu_v14_0_2_set_ppt_funcs(struct smu_context *smu)
{
smu->ppt_funcs = &smu_v14_0_2_ppt_funcs;
- smu->message_map = smu_v14_0_2_message_map;
smu->clock_map = smu_v14_0_2_clk_map;
smu->feature_map = smu_v14_0_2_feature_mask_map;
smu->table_map = smu_v14_0_2_table_map;
smu->pwr_src_map = smu_v14_0_2_pwr_src_map;
smu->workload_map = smu_v14_0_2_workload_map;
- smu_v14_0_2_set_smu_mailbox_registers(smu);
+ smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_SMU_V14_0_2;
+ smu_v14_0_2_init_msg_ctl(smu);
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/Makefile b/drivers/gpu/drm/amd/pm/swsmu/smu15/Makefile
new file mode 100644
index 000000000000..fa083ad46c0f
--- /dev/null
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/Makefile
@@ -0,0 +1,30 @@
+#
+# Copyright 2025 Advanced Micro Devices, Inc.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+#
+# Makefile for the 'smu manager' sub-component of powerplay.
+# It provides the smu management services for the driver.
+
+SMU15_MGR = smu_v15_0.o smu_v15_0_0_ppt.o smu_v15_0_8_ppt.o
+
+AMD_SWSMU_SMU15MGR = $(addprefix $(AMD_SWSMU_PATH)/smu15/,$(SMU15_MGR))
+
+AMD_POWERPLAY_FILES += $(AMD_SWSMU_SMU15MGR)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c
new file mode 100644
index 000000000000..8fc99e93ac53
--- /dev/null
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c
@@ -0,0 +1,1757 @@
+/*
+ * Copyright 2023 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/reboot.h>
+
+#define SWSMU_CODE_LAYER_L3
+
+#include "amdgpu.h"
+#include "amdgpu_smu.h"
+#include "atomfirmware.h"
+#include "amdgpu_atomfirmware.h"
+#include "amdgpu_atombios.h"
+#include "smu_v15_0.h"
+#include "soc15_common.h"
+#include "atom.h"
+#include "amdgpu_ras.h"
+#include "smu_cmn.h"
+
+#include "asic_reg/thm/thm_15_0_0_offset.h"
+#include "asic_reg/thm/thm_15_0_0_sh_mask.h"
+#include "asic_reg/mp/mp_15_0_0_offset.h"
+#include "asic_reg/mp/mp_15_0_0_sh_mask.h"
+
+#define regMP1_SMN_IH_SW_INT_mp1_15_0_0 0x0341
+#define regMP1_SMN_IH_SW_INT_mp1_15_0_0_BASE_IDX 0
+#define regMP1_SMN_IH_SW_INT_CTRL_mp1_15_0_0 0x0342
+#define regMP1_SMN_IH_SW_INT_CTRL_mp1_15_0_0_BASE_IDX 0
+
+/*
+ * DO NOT use these for err/warn/info/debug messages.
+ * Use dev_err, dev_warn, dev_info and dev_dbg instead.
+ * They are more MGPU friendly.
+ */
+#undef pr_err
+#undef pr_warn
+#undef pr_info
+#undef pr_debug
+
+#define ENABLE_IMU_ARG_GFXOFF_ENABLE 1
+
+int smu_v15_0_init_microcode(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+ char ucode_prefix[15];
+ int err = 0;
+ const struct smc_firmware_header_v1_0 *hdr;
+ const struct common_firmware_header *header;
+ struct amdgpu_firmware_info *ucode = NULL;
+
+ /* doesn't need to load smu firmware in IOV mode */
+ if (amdgpu_sriov_vf(adev))
+ return 0;
+
+ amdgpu_ucode_ip_version_decode(adev, MP1_HWIP, ucode_prefix, sizeof(ucode_prefix));
+ err = amdgpu_ucode_request(adev, &adev->pm.fw, AMDGPU_UCODE_REQUIRED,
+ "amdgpu/%s.bin", ucode_prefix);
+ if (err)
+ goto out;
+
+ hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data;
+ amdgpu_ucode_print_smc_hdr(&hdr->header);
+ adev->pm.fw_version = le32_to_cpu(hdr->header.ucode_version);
+
+ if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
+ ucode = &adev->firmware.ucode[AMDGPU_UCODE_ID_SMC];
+ ucode->ucode_id = AMDGPU_UCODE_ID_SMC;
+ ucode->fw = adev->pm.fw;
+ header = (const struct common_firmware_header *)ucode->fw->data;
+ adev->firmware.fw_size +=
+ ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE);
+ }
+
+out:
+ if (err)
+ amdgpu_ucode_release(&adev->pm.fw);
+ return err;
+}
+
+void smu_v15_0_fini_microcode(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+
+ amdgpu_ucode_release(&adev->pm.fw);
+ adev->pm.fw_version = 0;
+}
+
+int smu_v15_0_load_microcode(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+ const uint32_t *src;
+ const struct smc_firmware_header_v1_0 *hdr;
+ uint32_t addr_start = MP1_SRAM;
+ uint32_t i;
+ uint32_t smc_fw_size;
+ uint32_t mp1_fw_flags;
+
+ hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data;
+ src = (const uint32_t *)(adev->pm.fw->data +
+ le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+ smc_fw_size = hdr->header.ucode_size_bytes;
+
+ for (i = 1; i < smc_fw_size/4 - 1; i++) {
+ WREG32_PCIE(addr_start, src[i]);
+ addr_start += 4;
+ }
+
+
+ for (i = 0; i < adev->usec_timeout; i++) {
+ if (smu->is_apu)
+ mp1_fw_flags = RREG32_PCIE(MP1_Public |
+ (smnMP1_FIRMWARE_FLAGS & 0xffffffff));
+
+ if ((mp1_fw_flags & MP1_CRU1_MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) >>
+ MP1_CRU1_MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED__SHIFT)
+ break;
+ udelay(1);
+ }
+
+ if (i == adev->usec_timeout)
+ return -ETIME;
+
+ return 0;
+}
+
+int smu_v15_0_init_pptable_microcode(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+ struct amdgpu_firmware_info *ucode = NULL;
+ uint32_t size = 0, pptable_id = 0;
+ int ret = 0;
+ void *table;
+
+ /* doesn't need to load smu firmware in IOV mode */
+ if (amdgpu_sriov_vf(adev))
+ return 0;
+
+ if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
+ return 0;
+
+ if (!adev->scpm_enabled)
+ return 0;
+
+ /* override pptable_id from driver parameter */
+ if (amdgpu_smu_pptable_id >= 0) {
+ pptable_id = amdgpu_smu_pptable_id;
+ dev_info(adev->dev, "override pptable id %d\n", pptable_id);
+ } else {
+ pptable_id = smu->smu_table.boot_values.pp_table_id;
+ }
+
+ /* "pptable_id == 0" means vbios carries the pptable. */
+ if (!pptable_id)
+ return 0;
+
+ ret = smu_v15_0_get_pptable_from_firmware(smu, &table, &size, pptable_id);
+ if (ret)
+ return ret;
+
+ smu->pptable_firmware.data = table;
+ smu->pptable_firmware.size = size;
+
+ ucode = &adev->firmware.ucode[AMDGPU_UCODE_ID_PPTABLE];
+ ucode->ucode_id = AMDGPU_UCODE_ID_PPTABLE;
+ ucode->fw = &smu->pptable_firmware;
+ adev->firmware.fw_size +=
+ ALIGN(smu->pptable_firmware.size, PAGE_SIZE);
+
+ return 0;
+}
+
+int smu_v15_0_check_fw_status(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+ uint32_t mp1_fw_flags = 0;
+
+ if (smu->is_apu)
+ mp1_fw_flags = RREG32_PCIE(MP1_Public |
+ (smnMP1_FIRMWARE_FLAGS & 0xffffffff));
+
+
+ if ((mp1_fw_flags & MP1_CRU1_MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) >>
+ MP1_CRU1_MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED__SHIFT)
+ return 0;
+
+ return -EIO;
+}
+
+static int smu_v15_0_set_pptable_v2_0(struct smu_context *smu, void **table, uint32_t *size)
+{
+ struct amdgpu_device *adev = smu->adev;
+ uint32_t ppt_offset_bytes;
+ const struct smc_firmware_header_v2_0 *v2;
+
+ v2 = (const struct smc_firmware_header_v2_0 *) adev->pm.fw->data;
+
+ ppt_offset_bytes = le32_to_cpu(v2->ppt_offset_bytes);
+ *size = le32_to_cpu(v2->ppt_size_bytes);
+ *table = (uint8_t *)v2 + ppt_offset_bytes;
+
+ return 0;
+}
+
+static int smu_v15_0_set_pptable_v2_1(struct smu_context *smu, void **table,
+ uint32_t *size, uint32_t pptable_id)
+{
+ struct amdgpu_device *adev = smu->adev;
+ const struct smc_firmware_header_v2_1 *v2_1;
+ struct smc_soft_pptable_entry *entries;
+ uint32_t pptable_count = 0;
+ int i = 0;
+
+ v2_1 = (const struct smc_firmware_header_v2_1 *) adev->pm.fw->data;
+ entries = (struct smc_soft_pptable_entry *)
+ ((uint8_t *)v2_1 + le32_to_cpu(v2_1->pptable_entry_offset));
+ pptable_count = le32_to_cpu(v2_1->pptable_count);
+ for (i = 0; i < pptable_count; i++) {
+ if (le32_to_cpu(entries[i].id) == pptable_id) {
+ *table = ((uint8_t *)v2_1 + le32_to_cpu(entries[i].ppt_offset_bytes));
+ *size = le32_to_cpu(entries[i].ppt_size_bytes);
+ break;
+ }
+ }
+
+ if (i == pptable_count)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int smu_v15_0_get_pptable_from_vbios(struct smu_context *smu, void **table, uint32_t *size)
+{
+ struct amdgpu_device *adev = smu->adev;
+ uint16_t atom_table_size;
+ uint8_t frev, crev;
+ int ret, index;
+
+ dev_info(adev->dev, "use vbios provided pptable\n");
+ index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
+ powerplayinfo);
+
+ ret = amdgpu_atombios_get_data_table(adev, index, &atom_table_size, &frev, &crev,
+ (uint8_t **)table);
+ if (ret)
+ return ret;
+
+ if (size)
+ *size = atom_table_size;
+
+ return 0;
+}
+
+int smu_v15_0_get_pptable_from_firmware(struct smu_context *smu,
+ void **table,
+ uint32_t *size,
+ uint32_t pptable_id)
+{
+ const struct smc_firmware_header_v1_0 *hdr;
+ struct amdgpu_device *adev = smu->adev;
+ uint16_t version_major, version_minor;
+ int ret;
+
+ hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data;
+ if (!hdr)
+ return -EINVAL;
+
+ dev_info(adev->dev, "use driver provided pptable %d\n", pptable_id);
+
+ version_major = le16_to_cpu(hdr->header.header_version_major);
+ version_minor = le16_to_cpu(hdr->header.header_version_minor);
+ if (version_major != 2) {
+ dev_err(adev->dev, "Unsupported smu firmware version %d.%d\n",
+ version_major, version_minor);
+ return -EINVAL;
+ }
+
+ switch (version_minor) {
+ case 0:
+ ret = smu_v15_0_set_pptable_v2_0(smu, table, size);
+ break;
+ case 1:
+ ret = smu_v15_0_set_pptable_v2_1(smu, table, size, pptable_id);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+int smu_v15_0_setup_pptable(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+ uint32_t size = 0, pptable_id = 0;
+ void *table;
+ int ret = 0;
+
+ /* override pptable_id from driver parameter */
+ if (amdgpu_smu_pptable_id >= 0) {
+ pptable_id = amdgpu_smu_pptable_id;
+ dev_info(adev->dev, "override pptable id %d\n", pptable_id);
+ } else {
+ pptable_id = smu->smu_table.boot_values.pp_table_id;
+ }
+
+ /* force using vbios pptable in sriov mode */
+ if ((amdgpu_sriov_vf(adev) || !pptable_id) && (amdgpu_emu_mode != 1))
+ ret = smu_v15_0_get_pptable_from_vbios(smu, &table, &size);
+ else
+ ret = smu_v15_0_get_pptable_from_firmware(smu, &table, &size, pptable_id);
+
+ if (ret)
+ return ret;
+
+ if (!smu->smu_table.power_play_table)
+ smu->smu_table.power_play_table = table;
+ if (!smu->smu_table.power_play_table_size)
+ smu->smu_table.power_play_table_size = size;
+
+ return 0;
+}
+
+int smu_v15_0_init_smc_tables(struct smu_context *smu)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_table *tables = smu_table->tables;
+ int ret = 0;
+
+ smu_table->driver_pptable =
+ kzalloc(tables[SMU_TABLE_PPTABLE].size, GFP_KERNEL);
+ if (!smu_table->driver_pptable) {
+ ret = -ENOMEM;
+ goto err0_out;
+ }
+
+ smu_table->max_sustainable_clocks =
+ kzalloc_obj(struct smu_15_0_max_sustainable_clocks);
+ if (!smu_table->max_sustainable_clocks) {
+ ret = -ENOMEM;
+ goto err1_out;
+ }
+
+ if (tables[SMU_TABLE_OVERDRIVE].size) {
+ smu_table->overdrive_table =
+ kzalloc(tables[SMU_TABLE_OVERDRIVE].size, GFP_KERNEL);
+ if (!smu_table->overdrive_table) {
+ ret = -ENOMEM;
+ goto err2_out;
+ }
+
+ smu_table->boot_overdrive_table =
+ kzalloc(tables[SMU_TABLE_OVERDRIVE].size, GFP_KERNEL);
+ if (!smu_table->boot_overdrive_table) {
+ ret = -ENOMEM;
+ goto err3_out;
+ }
+
+ smu_table->user_overdrive_table =
+ kzalloc(tables[SMU_TABLE_OVERDRIVE].size, GFP_KERNEL);
+ if (!smu_table->user_overdrive_table) {
+ ret = -ENOMEM;
+ goto err4_out;
+ }
+ }
+
+ smu_table->combo_pptable =
+ kzalloc(tables[SMU_TABLE_COMBO_PPTABLE].size, GFP_KERNEL);
+ if (!smu_table->combo_pptable) {
+ ret = -ENOMEM;
+ goto err5_out;
+ }
+
+ return 0;
+
+err5_out:
+ kfree(smu_table->user_overdrive_table);
+err4_out:
+ kfree(smu_table->boot_overdrive_table);
+err3_out:
+ kfree(smu_table->overdrive_table);
+err2_out:
+ kfree(smu_table->max_sustainable_clocks);
+err1_out:
+ kfree(smu_table->driver_pptable);
+err0_out:
+ return ret;
+}
+
+int smu_v15_0_fini_smc_tables(struct smu_context *smu)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
+
+ smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+ kfree(smu_table->combo_pptable);
+ kfree(smu_table->boot_overdrive_table);
+ kfree(smu_table->overdrive_table);
+ kfree(smu_table->max_sustainable_clocks);
+ kfree(smu_table->driver_pptable);
+ smu_table->combo_pptable = NULL;
+ smu_table->boot_overdrive_table = NULL;
+ smu_table->overdrive_table = NULL;
+ smu_table->max_sustainable_clocks = NULL;
+ smu_table->driver_pptable = NULL;
+ kfree(smu_table->hardcode_pptable);
+ smu_table->hardcode_pptable = NULL;
+
+ kfree(smu_table->ecc_table);
+ kfree(smu_table->metrics_table);
+ kfree(smu_table->watermarks_table);
+ smu_table->ecc_table = NULL;
+ smu_table->metrics_table = NULL;
+ smu_table->watermarks_table = NULL;
+ smu_table->metrics_time = 0;
+
+ kfree(smu_dpm->dpm_policies);
+ kfree(smu_dpm->dpm_context);
+ kfree(smu_dpm->golden_dpm_context);
+ kfree(smu_dpm->dpm_current_power_state);
+ kfree(smu_dpm->dpm_request_power_state);
+ smu_dpm->dpm_policies = NULL;
+ smu_dpm->dpm_context = NULL;
+ smu_dpm->golden_dpm_context = NULL;
+ smu_dpm->dpm_context_size = 0;
+ smu_dpm->dpm_current_power_state = NULL;
+ smu_dpm->dpm_request_power_state = NULL;
+
+ return 0;
+}
+
+int smu_v15_0_init_power(struct smu_context *smu)
+{
+ struct smu_power_context *smu_power = &smu->smu_power;
+
+ if (smu_power->power_context || smu_power->power_context_size != 0)
+ return -EINVAL;
+
+ smu_power->power_context = kzalloc_obj(struct smu_15_0_dpm_context);
+ if (!smu_power->power_context)
+ return -ENOMEM;
+ smu_power->power_context_size = sizeof(struct smu_15_0_dpm_context);
+
+ return 0;
+}
+
+int smu_v15_0_fini_power(struct smu_context *smu)
+{
+ struct smu_power_context *smu_power = &smu->smu_power;
+
+ if (!smu_power->power_context || smu_power->power_context_size == 0)
+ return -EINVAL;
+
+ kfree(smu_power->power_context);
+ smu_power->power_context = NULL;
+ smu_power->power_context_size = 0;
+
+ return 0;
+}
+
+int smu_v15_0_get_vbios_bootup_values(struct smu_context *smu)
+{
+ int ret, index;
+ uint16_t size;
+ uint8_t frev, crev;
+ struct atom_common_table_header *header;
+ struct atom_firmware_info_v3_4 *v_3_4;
+ struct atom_firmware_info_v3_3 *v_3_3;
+ struct atom_firmware_info_v3_1 *v_3_1;
+ struct atom_smu_info_v3_6 *smu_info_v3_6;
+ struct atom_smu_info_v4_0 *smu_info_v4_0;
+
+ index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
+ firmwareinfo);
+
+ ret = amdgpu_atombios_get_data_table(smu->adev, index, &size, &frev, &crev,
+ (uint8_t **)&header);
+ if (ret)
+ return ret;
+
+ if (header->format_revision != 3) {
+ dev_err(smu->adev->dev, "unknown atom_firmware_info version! for smu15\n");
+ return -EINVAL;
+ }
+
+ switch (header->content_revision) {
+ case 0:
+ case 1:
+ case 2:
+ v_3_1 = (struct atom_firmware_info_v3_1 *)header;
+ smu->smu_table.boot_values.revision = v_3_1->firmware_revision;
+ smu->smu_table.boot_values.gfxclk = v_3_1->bootup_sclk_in10khz;
+ smu->smu_table.boot_values.uclk = v_3_1->bootup_mclk_in10khz;
+ smu->smu_table.boot_values.socclk = 0;
+ smu->smu_table.boot_values.dcefclk = 0;
+ smu->smu_table.boot_values.vddc = v_3_1->bootup_vddc_mv;
+ smu->smu_table.boot_values.vddci = v_3_1->bootup_vddci_mv;
+ smu->smu_table.boot_values.mvddc = v_3_1->bootup_mvddc_mv;
+ smu->smu_table.boot_values.vdd_gfx = v_3_1->bootup_vddgfx_mv;
+ smu->smu_table.boot_values.cooling_id = v_3_1->coolingsolution_id;
+ smu->smu_table.boot_values.pp_table_id = 0;
+ break;
+ case 3:
+ v_3_3 = (struct atom_firmware_info_v3_3 *)header;
+ smu->smu_table.boot_values.revision = v_3_3->firmware_revision;
+ smu->smu_table.boot_values.gfxclk = v_3_3->bootup_sclk_in10khz;
+ smu->smu_table.boot_values.uclk = v_3_3->bootup_mclk_in10khz;
+ smu->smu_table.boot_values.socclk = 0;
+ smu->smu_table.boot_values.dcefclk = 0;
+ smu->smu_table.boot_values.vddc = v_3_3->bootup_vddc_mv;
+ smu->smu_table.boot_values.vddci = v_3_3->bootup_vddci_mv;
+ smu->smu_table.boot_values.mvddc = v_3_3->bootup_mvddc_mv;
+ smu->smu_table.boot_values.vdd_gfx = v_3_3->bootup_vddgfx_mv;
+ smu->smu_table.boot_values.cooling_id = v_3_3->coolingsolution_id;
+ smu->smu_table.boot_values.pp_table_id = v_3_3->pplib_pptable_id;
+ break;
+ case 4:
+ default:
+ v_3_4 = (struct atom_firmware_info_v3_4 *)header;
+ smu->smu_table.boot_values.revision = v_3_4->firmware_revision;
+ smu->smu_table.boot_values.gfxclk = v_3_4->bootup_sclk_in10khz;
+ smu->smu_table.boot_values.uclk = v_3_4->bootup_mclk_in10khz;
+ smu->smu_table.boot_values.socclk = 0;
+ smu->smu_table.boot_values.dcefclk = 0;
+ smu->smu_table.boot_values.vddc = v_3_4->bootup_vddc_mv;
+ smu->smu_table.boot_values.vddci = v_3_4->bootup_vddci_mv;
+ smu->smu_table.boot_values.mvddc = v_3_4->bootup_mvddc_mv;
+ smu->smu_table.boot_values.vdd_gfx = v_3_4->bootup_vddgfx_mv;
+ smu->smu_table.boot_values.cooling_id = v_3_4->coolingsolution_id;
+ smu->smu_table.boot_values.pp_table_id = v_3_4->pplib_pptable_id;
+ break;
+ }
+
+ smu->smu_table.boot_values.format_revision = header->format_revision;
+ smu->smu_table.boot_values.content_revision = header->content_revision;
+
+ index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
+ smu_info);
+ if (!amdgpu_atombios_get_data_table(smu->adev, index, &size, &frev, &crev,
+ (uint8_t **)&header)) {
+
+ if ((frev == 3) && (crev == 6)) {
+ smu_info_v3_6 = (struct atom_smu_info_v3_6 *)header;
+
+ smu->smu_table.boot_values.socclk = smu_info_v3_6->bootup_socclk_10khz;
+ smu->smu_table.boot_values.vclk = smu_info_v3_6->bootup_vclk_10khz;
+ smu->smu_table.boot_values.dclk = smu_info_v3_6->bootup_dclk_10khz;
+ smu->smu_table.boot_values.fclk = smu_info_v3_6->bootup_fclk_10khz;
+ } else if ((frev == 3) && (crev == 1)) {
+ return 0;
+ } else if ((frev == 4) && (crev == 0)) {
+ smu_info_v4_0 = (struct atom_smu_info_v4_0 *)header;
+
+ smu->smu_table.boot_values.socclk = smu_info_v4_0->bootup_socclk_10khz;
+ smu->smu_table.boot_values.dcefclk = smu_info_v4_0->bootup_dcefclk_10khz;
+ smu->smu_table.boot_values.vclk = smu_info_v4_0->bootup_vclk0_10khz;
+ smu->smu_table.boot_values.dclk = smu_info_v4_0->bootup_dclk0_10khz;
+ smu->smu_table.boot_values.fclk = smu_info_v4_0->bootup_fclk_10khz;
+ } else {
+ dev_warn(smu->adev->dev, "Unexpected and unhandled version: %d.%d\n",
+ (uint32_t)frev, (uint32_t)crev);
+ }
+ }
+
+ return 0;
+}
+
+
+int smu_v15_0_notify_memory_pool_location(struct smu_context *smu)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_table *memory_pool = &smu_table->memory_pool;
+ uint32_t params[3];
+
+ if (memory_pool->size == 0 || memory_pool->cpu_addr == NULL)
+ return 0;
+
+ /* SMU_MSG_DramLogSetDramAddr: ARG0=low, ARG1=high, ARG2=size */
+ params[0] = lower_32_bits(memory_pool->mc_address);
+ params[1] = upper_32_bits(memory_pool->mc_address);
+ params[2] = (u32)memory_pool->size;
+
+ return smu_cmn_send_smc_msg_with_params(smu,
+ SMU_MSG_DramLogSetDramAddr,
+ params, ARRAY_SIZE(params),
+ NULL, 0);
+}
+
+int smu_v15_0_set_driver_table_location(struct smu_context *smu)
+{
+ struct smu_table *driver_table = &smu->smu_table.driver_table;
+ const uint32_t params[] = {
+ lower_32_bits(driver_table->mc_address),
+ upper_32_bits(driver_table->mc_address),
+ };
+
+ return smu_cmn_send_smc_msg_with_params(smu, SMU_MSG_SetDriverDramAddr,
+ params, ARRAY_SIZE(params),
+ NULL, 0);
+}
+
+int smu_v15_0_set_tool_table_location(struct smu_context *smu)
+{
+ struct smu_table *tool_table = &smu->smu_table.tables[SMU_TABLE_PMSTATUSLOG];
+ const uint32_t params[] = {
+ lower_32_bits(tool_table->mc_address),
+ upper_32_bits(tool_table->mc_address),
+ };
+
+ /* SMU_MSG_SetToolsDramAddr: ARG0=low, ARG1=high */
+ return smu_cmn_send_smc_msg_with_params(smu, SMU_MSG_SetToolsDramAddr,
+ params, ARRAY_SIZE(params),
+ NULL, 0);
+}
+
+int smu_v15_0_set_allowed_mask(struct smu_context *smu)
+{
+ struct smu_feature *feature = &smu->smu_feature;
+ int ret = 0;
+ uint32_t feature_mask[2];
+
+ if (smu_feature_list_is_empty(smu, SMU_FEATURE_LIST_ALLOWED) ||
+ feature->feature_num < SMU_FEATURE_NUM_DEFAULT)
+ return -EINVAL;
+
+ smu_feature_list_to_arr32(smu, SMU_FEATURE_LIST_ALLOWED, feature_mask);
+
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetAllowedFeaturesMaskHigh,
+ feature_mask[1], NULL);
+ if (ret)
+ return ret;
+
+ return smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_SetAllowedFeaturesMaskLow,
+ feature_mask[0],
+ NULL);
+}
+
+int smu_v15_0_gfx_off_control(struct smu_context *smu, bool enable)
+{
+ int ret = 0;
+ struct amdgpu_device *adev = smu->adev;
+
+ switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
+ case IP_VERSION(15, 0, 0):
+ case IP_VERSION(15, 0, 9):
+ if (!(adev->pm.pp_feature & PP_GFXOFF_MASK))
+ return 0;
+ if (enable)
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_AllowGfxOff, NULL);
+ else
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_DisallowGfxOff, NULL);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+int smu_v15_0_system_features_control(struct smu_context *smu, bool en)
+{
+ return smu_cmn_send_smc_msg(smu, (en ? SMU_MSG_EnableAllSmuFeatures :
+ SMU_MSG_DisableAllSmuFeatures), NULL);
+}
+
+int smu_v15_0_notify_display_change(struct smu_context *smu)
+{
+ int ret = 0;
+
+ if (!smu->pm_enabled)
+ return ret;
+
+ if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT) &&
+ smu->adev->gmc.vram_type == AMDGPU_VRAM_TYPE_HBM)
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetUclkFastSwitch, 1, NULL);
+
+ return ret;
+}
+
+int smu_v15_0_get_current_power_limit(struct smu_context *smu,
+ uint32_t *power_limit)
+{
+ int power_src;
+ int ret = 0;
+
+ if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT))
+ return -EINVAL;
+
+ power_src = smu_cmn_to_asic_specific_index(smu,
+ CMN2ASIC_MAPPING_PWR,
+ smu->adev->pm.ac_power ?
+ SMU_POWER_SOURCE_AC :
+ SMU_POWER_SOURCE_DC);
+ if (power_src < 0)
+ return -EINVAL;
+
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_GetPptLimit,
+ power_src << 16,
+ power_limit);
+ if (ret)
+ dev_err(smu->adev->dev, "[%s] get PPT limit failed!", __func__);
+
+ return ret;
+}
+
+int smu_v15_0_set_power_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t limit)
+{
+ int ret = 0;
+
+ if (limit_type != SMU_DEFAULT_PPT_LIMIT)
+ return -EINVAL;
+
+ if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) {
+ dev_err(smu->adev->dev, "Setting new power limit is not supported!\n");
+ return -EOPNOTSUPP;
+ }
+
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetPptLimit, limit, NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Set power limit Failed!\n", __func__);
+ return ret;
+ }
+
+ smu->current_power_limit = limit;
+
+ return 0;
+}
+
+static int smu_v15_0_set_irq_state(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ unsigned tyep,
+ enum amdgpu_interrupt_state state)
+{
+ struct smu_context *smu = adev->powerplay.pp_handle;
+ uint32_t val = 0;
+
+ switch (state) {
+ case AMDGPU_IRQ_STATE_DISABLE:
+
+ /* For MP1 SW irqs */
+ if (smu->is_apu) {
+ val = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL_mp1_15_0_0);
+ val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT_CTRL, INT_MASK, 1);
+ WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL_mp1_15_0_0, val);
+ } else {
+ val = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL);
+ val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT_CTRL, INT_MASK, 1);
+ WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL, val);
+ }
+
+ break;
+ case AMDGPU_IRQ_STATE_ENABLE:
+ /* For MP1 SW irqs */
+ if (smu->is_apu) {
+ val = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_mp1_15_0_0);
+ val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT, ID, 0xFE);
+ val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT, VALID, 0);
+ WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_mp1_15_0_0, val);
+
+ val = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL_mp1_15_0_0);
+ val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT_CTRL, INT_MASK, 0);
+ WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL_mp1_15_0_0, val);
+ } else {
+ val = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT);
+ val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT, ID, 0xFE);
+ val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT, VALID, 0);
+ WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT, val);
+
+ val = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL);
+ val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT_CTRL, INT_MASK, 0);
+ WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL, val);
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+#define THM_11_0__SRCID__THM_DIG_THERM_L2H 0 /* ASIC_TEMP > CG_THERMAL_INT.DIG_THERM_INTH */
+#define THM_11_0__SRCID__THM_DIG_THERM_H2L 1 /* ASIC_TEMP < CG_THERMAL_INT.DIG_THERM_INTL */
+
+static int smu_v15_0_irq_process(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ struct amdgpu_iv_entry *entry)
+{
+ struct smu_context *smu = adev->powerplay.pp_handle;
+ uint32_t client_id = entry->client_id;
+ uint32_t src_id = entry->src_id;
+
+ if (client_id == SOC15_IH_CLIENTID_THM) {
+ switch (src_id) {
+ case THM_11_0__SRCID__THM_DIG_THERM_L2H:
+ schedule_delayed_work(&smu->swctf_delayed_work,
+ msecs_to_jiffies(AMDGPU_SWCTF_EXTRA_DELAY));
+ break;
+ case THM_11_0__SRCID__THM_DIG_THERM_H2L:
+ dev_emerg(adev->dev, "ERROR: GPU under temperature range detected\n");
+ break;
+ default:
+ dev_emerg(adev->dev, "ERROR: GPU under temperature range unknown src id (%d)\n",
+ src_id);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static const struct amdgpu_irq_src_funcs smu_v15_0_irq_funcs = {
+ .set = smu_v15_0_set_irq_state,
+ .process = smu_v15_0_irq_process,
+};
+
+int smu_v15_0_register_irq_handler(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+ struct amdgpu_irq_src *irq_src = &smu->irq_source;
+ int ret = 0;
+
+ if (amdgpu_sriov_vf(adev))
+ return 0;
+
+ irq_src->num_types = 1;
+ irq_src->funcs = &smu_v15_0_irq_funcs;
+
+ ret = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_THM,
+ THM_11_0__SRCID__THM_DIG_THERM_L2H,
+ irq_src);
+ if (ret)
+ return ret;
+
+ ret = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_THM,
+ THM_11_0__SRCID__THM_DIG_THERM_H2L,
+ irq_src);
+ if (ret)
+ return ret;
+
+ ret = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_MP1,
+ SMU_IH_INTERRUPT_ID_TO_DRIVER,
+ irq_src);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+static int smu_v15_0_wait_for_reset_complete(struct smu_context *smu,
+ uint64_t event_arg)
+{
+ int ret = 0;
+
+ dev_dbg(smu->adev->dev, "waiting for smu reset complete\n");
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GfxDriverResetRecovery, NULL);
+
+ return ret;
+}
+
+int smu_v15_0_wait_for_event(struct smu_context *smu,
+ enum smu_event_type event,
+ uint64_t event_arg)
+{
+ int ret = -EINVAL;
+
+ switch (event) {
+ case SMU_EVENT_RESET_COMPLETE:
+ ret = smu_v15_0_wait_for_reset_complete(smu, event_arg);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+int smu_v15_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type clk_type,
+ uint32_t *min, uint32_t *max)
+{
+ int ret = 0, clk_id = 0;
+ uint32_t param = 0;
+ uint32_t clock_limit;
+
+ if (!smu_cmn_clk_dpm_is_enabled(smu, clk_type)) {
+ switch (clk_type) {
+ case SMU_MCLK:
+ case SMU_UCLK:
+ clock_limit = smu->smu_table.boot_values.uclk;
+ break;
+ case SMU_GFXCLK:
+ case SMU_SCLK:
+ clock_limit = smu->smu_table.boot_values.gfxclk;
+ break;
+ case SMU_SOCCLK:
+ clock_limit = smu->smu_table.boot_values.socclk;
+ break;
+ default:
+ clock_limit = 0;
+ break;
+ }
+
+ /* clock in Mhz unit */
+ if (min)
+ *min = clock_limit / 100;
+ if (max)
+ *max = clock_limit / 100;
+
+ return 0;
+ }
+
+ clk_id = smu_cmn_to_asic_specific_index(smu,
+ CMN2ASIC_MAPPING_CLK,
+ clk_type);
+ if (clk_id < 0) {
+ ret = -EINVAL;
+ goto failed;
+ }
+ param = (clk_id & 0xffff) << 16;
+
+ if (max) {
+ if (smu->adev->pm.ac_power)
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_GetMaxDpmFreq,
+ param,
+ max);
+ else
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_GetDcModeMaxDpmFreq,
+ param,
+ max);
+ if (ret)
+ goto failed;
+ }
+
+ if (min) {
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GetMinDpmFreq, param, min);
+ if (ret)
+ goto failed;
+ }
+
+failed:
+ return ret;
+}
+
+int smu_v15_0_set_soft_freq_limited_range(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t min,
+ uint32_t max,
+ bool automatic)
+{
+ int ret = 0, clk_id = 0;
+ uint32_t param;
+
+ if (!smu_cmn_clk_dpm_is_enabled(smu, clk_type))
+ return 0;
+
+ clk_id = smu_cmn_to_asic_specific_index(smu,
+ CMN2ASIC_MAPPING_CLK,
+ clk_type);
+ if (clk_id < 0)
+ return clk_id;
+
+ if (max > 0) {
+ if (automatic)
+ param = (uint32_t)((clk_id << 16) | 0xffff);
+ else
+ param = (uint32_t)((clk_id << 16) | (max & 0xffff));
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxByFreq,
+ param, NULL);
+ if (ret)
+ goto out;
+ }
+
+ if (min > 0) {
+ if (automatic)
+ param = (uint32_t)((clk_id << 16) | 0);
+ else
+ param = (uint32_t)((clk_id << 16) | (min & 0xffff));
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMinByFreq,
+ param, NULL);
+ if (ret)
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+int smu_v15_0_set_hard_freq_limited_range(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t min,
+ uint32_t max)
+{
+ int ret = 0, clk_id = 0;
+ uint32_t param;
+
+ if (min <= 0 && max <= 0)
+ return -EINVAL;
+
+ if (!smu_cmn_clk_dpm_is_enabled(smu, clk_type))
+ return 0;
+
+ clk_id = smu_cmn_to_asic_specific_index(smu,
+ CMN2ASIC_MAPPING_CLK,
+ clk_type);
+ if (clk_id < 0)
+ return clk_id;
+
+ if (max > 0) {
+ param = (uint32_t)((clk_id << 16) | (max & 0xffff));
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMaxByFreq,
+ param, NULL);
+ if (ret)
+ return ret;
+ }
+
+ if (min > 0) {
+ param = (uint32_t)((clk_id << 16) | (min & 0xffff));
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinByFreq,
+ param, NULL);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+int smu_v15_0_set_performance_level(struct smu_context *smu,
+ enum amd_dpm_forced_level level)
+{
+ struct smu_15_0_dpm_context *dpm_context =
+ smu->smu_dpm.dpm_context;
+ struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table;
+ struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table;
+ struct smu_dpm_table *soc_table = &dpm_context->dpm_tables.soc_table;
+ struct smu_dpm_table *vclk_table = &dpm_context->dpm_tables.vclk_table;
+ struct smu_dpm_table *dclk_table = &dpm_context->dpm_tables.dclk_table;
+ struct smu_dpm_table *fclk_table = &dpm_context->dpm_tables.fclk_table;
+ struct smu_umd_pstate_table *pstate_table =
+ &smu->pstate_table;
+ struct amdgpu_device *adev = smu->adev;
+ uint32_t sclk_min = 0, sclk_max = 0;
+ uint32_t mclk_min = 0, mclk_max = 0;
+ uint32_t socclk_min = 0, socclk_max = 0;
+ uint32_t vclk_min = 0, vclk_max = 0;
+ uint32_t dclk_min = 0, dclk_max = 0;
+ uint32_t fclk_min = 0, fclk_max = 0;
+ int ret = 0, i;
+ bool auto_level = false;
+
+ switch (level) {
+ case AMD_DPM_FORCED_LEVEL_HIGH:
+ sclk_min = sclk_max = SMU_DPM_TABLE_MAX(gfx_table);
+ mclk_min = mclk_max = SMU_DPM_TABLE_MAX(mem_table);
+ socclk_min = socclk_max = SMU_DPM_TABLE_MAX(soc_table);
+ vclk_min = vclk_max = SMU_DPM_TABLE_MAX(vclk_table);
+ dclk_min = dclk_max = SMU_DPM_TABLE_MAX(dclk_table);
+ fclk_min = fclk_max = SMU_DPM_TABLE_MAX(fclk_table);
+ break;
+ case AMD_DPM_FORCED_LEVEL_LOW:
+ sclk_min = sclk_max = SMU_DPM_TABLE_MIN(gfx_table);
+ mclk_min = mclk_max = SMU_DPM_TABLE_MIN(mem_table);
+ socclk_min = socclk_max = SMU_DPM_TABLE_MIN(soc_table);
+ vclk_min = vclk_max = SMU_DPM_TABLE_MIN(vclk_table);
+ dclk_min = dclk_max = SMU_DPM_TABLE_MIN(dclk_table);
+ fclk_min = fclk_max = SMU_DPM_TABLE_MIN(fclk_table);
+ break;
+ case AMD_DPM_FORCED_LEVEL_AUTO:
+ sclk_min = SMU_DPM_TABLE_MIN(gfx_table);
+ sclk_max = SMU_DPM_TABLE_MAX(gfx_table);
+ mclk_min = SMU_DPM_TABLE_MIN(mem_table);
+ mclk_max = SMU_DPM_TABLE_MAX(mem_table);
+ socclk_min = SMU_DPM_TABLE_MIN(soc_table);
+ socclk_max = SMU_DPM_TABLE_MAX(soc_table);
+ vclk_min = SMU_DPM_TABLE_MIN(vclk_table);
+ vclk_max = SMU_DPM_TABLE_MAX(vclk_table);
+ dclk_min = SMU_DPM_TABLE_MIN(dclk_table);
+ dclk_max = SMU_DPM_TABLE_MAX(dclk_table);
+ fclk_min = SMU_DPM_TABLE_MIN(fclk_table);
+ fclk_max = SMU_DPM_TABLE_MAX(fclk_table);
+ auto_level = true;
+ break;
+ case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
+ sclk_min = sclk_max = pstate_table->gfxclk_pstate.standard;
+ mclk_min = mclk_max = pstate_table->uclk_pstate.standard;
+ socclk_min = socclk_max = pstate_table->socclk_pstate.standard;
+ vclk_min = vclk_max = pstate_table->vclk_pstate.standard;
+ dclk_min = dclk_max = pstate_table->dclk_pstate.standard;
+ fclk_min = fclk_max = pstate_table->fclk_pstate.standard;
+ break;
+ case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
+ sclk_min = sclk_max = pstate_table->gfxclk_pstate.min;
+ break;
+ case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
+ mclk_min = mclk_max = pstate_table->uclk_pstate.min;
+ break;
+ case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
+ sclk_min = sclk_max = pstate_table->gfxclk_pstate.peak;
+ mclk_min = mclk_max = pstate_table->uclk_pstate.peak;
+ socclk_min = socclk_max = pstate_table->socclk_pstate.peak;
+ vclk_min = vclk_max = pstate_table->vclk_pstate.peak;
+ dclk_min = dclk_max = pstate_table->dclk_pstate.peak;
+ fclk_min = fclk_max = pstate_table->fclk_pstate.peak;
+ break;
+ case AMD_DPM_FORCED_LEVEL_MANUAL:
+ case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
+ return 0;
+ default:
+ dev_err(adev->dev, "Invalid performance level %d\n", level);
+ return -EINVAL;
+ }
+
+ if (sclk_min && sclk_max) {
+ ret = smu_v15_0_set_soft_freq_limited_range(smu,
+ SMU_GFXCLK,
+ sclk_min,
+ sclk_max,
+ auto_level);
+ if (ret)
+ return ret;
+
+ pstate_table->gfxclk_pstate.curr.min = sclk_min;
+ pstate_table->gfxclk_pstate.curr.max = sclk_max;
+ }
+
+ if (mclk_min && mclk_max) {
+ ret = smu_v15_0_set_soft_freq_limited_range(smu,
+ SMU_MCLK,
+ mclk_min,
+ mclk_max,
+ auto_level);
+ if (ret)
+ return ret;
+
+ pstate_table->uclk_pstate.curr.min = mclk_min;
+ pstate_table->uclk_pstate.curr.max = mclk_max;
+ }
+
+ if (socclk_min && socclk_max) {
+ ret = smu_v15_0_set_soft_freq_limited_range(smu,
+ SMU_SOCCLK,
+ socclk_min,
+ socclk_max,
+ auto_level);
+ if (ret)
+ return ret;
+
+ pstate_table->socclk_pstate.curr.min = socclk_min;
+ pstate_table->socclk_pstate.curr.max = socclk_max;
+ }
+
+ if (vclk_min && vclk_max) {
+ for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
+ if (adev->vcn.harvest_config & (1 << i))
+ continue;
+ ret = smu_v15_0_set_soft_freq_limited_range(smu,
+ i ? SMU_VCLK1 : SMU_VCLK,
+ vclk_min,
+ vclk_max,
+ auto_level);
+ if (ret)
+ return ret;
+ }
+ pstate_table->vclk_pstate.curr.min = vclk_min;
+ pstate_table->vclk_pstate.curr.max = vclk_max;
+ }
+
+ if (dclk_min && dclk_max) {
+ for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
+ if (adev->vcn.harvest_config & (1 << i))
+ continue;
+ ret = smu_v15_0_set_soft_freq_limited_range(smu,
+ i ? SMU_DCLK1 : SMU_DCLK,
+ dclk_min,
+ dclk_max,
+ auto_level);
+ if (ret)
+ return ret;
+ }
+ pstate_table->dclk_pstate.curr.min = dclk_min;
+ pstate_table->dclk_pstate.curr.max = dclk_max;
+ }
+
+ if (fclk_min && fclk_max) {
+ ret = smu_v15_0_set_soft_freq_limited_range(smu,
+ SMU_FCLK,
+ fclk_min,
+ fclk_max,
+ auto_level);
+ if (ret)
+ return ret;
+
+ pstate_table->fclk_pstate.curr.min = fclk_min;
+ pstate_table->fclk_pstate.curr.max = fclk_max;
+ }
+
+ return ret;
+}
+
+int smu_v15_0_set_power_source(struct smu_context *smu,
+ enum smu_power_src_type power_src)
+{
+ int pwr_source;
+
+ pwr_source = smu_cmn_to_asic_specific_index(smu,
+ CMN2ASIC_MAPPING_PWR,
+ (uint32_t)power_src);
+ if (pwr_source < 0)
+ return -EINVAL;
+
+ return smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_NotifyPowerSource,
+ pwr_source,
+ NULL);
+}
+
+static int smu_v15_0_get_dpm_freq_by_index(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint16_t level,
+ uint32_t *value)
+{
+ int ret = 0, clk_id = 0;
+ uint32_t param;
+
+ if (!value)
+ return -EINVAL;
+
+ if (!smu_cmn_clk_dpm_is_enabled(smu, clk_type))
+ return 0;
+
+ clk_id = smu_cmn_to_asic_specific_index(smu,
+ CMN2ASIC_MAPPING_CLK,
+ clk_type);
+ if (clk_id < 0)
+ return clk_id;
+
+ param = (uint32_t)(((clk_id & 0xffff) << 16) | (level & 0xffff));
+
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_GetDpmFreqByIndex,
+ param,
+ value);
+ if (ret)
+ return ret;
+
+ *value = *value & 0x7fffffff;
+
+ return ret;
+}
+
+static int smu_v15_0_get_dpm_level_count(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t *value)
+{
+ int ret;
+
+ ret = smu_v15_0_get_dpm_freq_by_index(smu, clk_type, 0xff, value);
+
+ return ret;
+}
+
+static int smu_v15_0_get_fine_grained_status(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ bool *is_fine_grained_dpm)
+{
+ int ret = 0, clk_id = 0;
+ uint32_t param;
+ uint32_t value;
+
+ if (!is_fine_grained_dpm)
+ return -EINVAL;
+
+ if (!smu_cmn_clk_dpm_is_enabled(smu, clk_type))
+ return 0;
+
+ clk_id = smu_cmn_to_asic_specific_index(smu,
+ CMN2ASIC_MAPPING_CLK,
+ clk_type);
+ if (clk_id < 0)
+ return clk_id;
+
+ param = (uint32_t)(((clk_id & 0xffff) << 16) | 0xff);
+
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_GetDpmFreqByIndex,
+ param,
+ &value);
+ if (ret)
+ return ret;
+
+ /*
+ * BIT31: 1 - Fine grained DPM, 0 - Dicrete DPM
+ * now, we un-support it
+ */
+ *is_fine_grained_dpm = value & 0x80000000;
+
+ return 0;
+}
+
+int smu_v15_0_set_single_dpm_table(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ struct smu_dpm_table *single_dpm_table)
+{
+ int ret = 0;
+ uint32_t clk;
+ bool is_fine_grained;
+ int i;
+
+ ret = smu_v15_0_get_dpm_level_count(smu,
+ clk_type,
+ &single_dpm_table->count);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] failed to get dpm levels!\n", __func__);
+ return ret;
+ }
+
+ ret = smu_v15_0_get_fine_grained_status(smu,
+ clk_type,
+ &is_fine_grained);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] failed to get fine grained status!\n", __func__);
+ return ret;
+ }
+
+ if (is_fine_grained)
+ single_dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED;
+
+ for (i = 0; i < single_dpm_table->count; i++) {
+ ret = smu_v15_0_get_dpm_freq_by_index(smu,
+ clk_type,
+ i,
+ &clk);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] failed to get dpm freq by index!\n", __func__);
+ return ret;
+ }
+
+ single_dpm_table->dpm_levels[i].value = clk;
+ single_dpm_table->dpm_levels[i].enabled = true;
+ }
+
+ return 0;
+}
+
+int smu_v15_0_set_vcn_enable(struct smu_context *smu,
+ bool enable,
+ int inst)
+{
+ struct amdgpu_device *adev = smu->adev;
+ int ret = 0;
+
+ if (adev->vcn.harvest_config & (1 << inst))
+ return ret;
+
+ if (smu->is_apu) {
+ ret = smu_cmn_send_smc_msg_with_param(smu, enable ?
+ SMU_MSG_PowerUpVcn : SMU_MSG_PowerDownVcn,
+ inst << 16U, NULL);
+ }
+
+ return ret;
+}
+
+int smu_v15_0_set_jpeg_enable(struct smu_context *smu,
+ bool enable)
+{
+ struct amdgpu_device *adev = smu->adev;
+ int i, ret = 0;
+
+ for (i = 0; i < adev->jpeg.num_jpeg_inst; i++) {
+ if (adev->jpeg.harvest_config & (1 << i))
+ continue;
+
+ if (smu->is_apu) {
+ ret = smu_cmn_send_smc_msg_with_param(smu, enable ?
+ SMU_MSG_PowerUpJpeg : SMU_MSG_PowerDownJpeg,
+ i << 16U, NULL);
+ }
+
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+int smu_v15_0_run_btc(struct smu_context *smu)
+{
+ int res;
+
+ res = smu_cmn_send_smc_msg(smu, SMU_MSG_RunDcBtc, NULL);
+ if (res)
+ dev_err(smu->adev->dev, "RunDcBtc failed!\n");
+
+ return res;
+}
+
+int smu_v15_0_gpo_control(struct smu_context *smu,
+ bool enablement)
+{
+ int res;
+
+ res = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_AllowGpo,
+ enablement ? 1 : 0,
+ NULL);
+ if (res)
+ dev_err(smu->adev->dev, "SetGpoAllow %d failed!\n", enablement);
+
+ return res;
+}
+
+int smu_v15_0_deep_sleep_control(struct smu_context *smu,
+ bool enablement)
+{
+ struct amdgpu_device *adev = smu->adev;
+ int ret = 0;
+
+ if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_GFXCLK_BIT)) {
+ ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_DS_GFXCLK_BIT, enablement);
+ if (ret) {
+ dev_err(adev->dev, "Failed to %s GFXCLK DS!\n", enablement ? "enable" : "disable");
+ return ret;
+ }
+ }
+
+ if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_UCLK_BIT)) {
+ ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_DS_UCLK_BIT, enablement);
+ if (ret) {
+ dev_err(adev->dev, "Failed to %s UCLK DS!\n", enablement ? "enable" : "disable");
+ return ret;
+ }
+ }
+
+ if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_FCLK_BIT)) {
+ ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_DS_FCLK_BIT, enablement);
+ if (ret) {
+ dev_err(adev->dev, "Failed to %s FCLK DS!\n", enablement ? "enable" : "disable");
+ return ret;
+ }
+ }
+
+ if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_SOCCLK_BIT)) {
+ ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_DS_SOCCLK_BIT, enablement);
+ if (ret) {
+ dev_err(adev->dev, "Failed to %s SOCCLK DS!\n", enablement ? "enable" : "disable");
+ return ret;
+ }
+ }
+
+ if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_LCLK_BIT)) {
+ ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_DS_LCLK_BIT, enablement);
+ if (ret) {
+ dev_err(adev->dev, "Failed to %s LCLK DS!\n", enablement ? "enable" : "disable");
+ return ret;
+ }
+ }
+
+ if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_VCN_BIT)) {
+ ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_DS_VCN_BIT, enablement);
+ if (ret) {
+ dev_err(adev->dev, "Failed to %s VCN DS!\n", enablement ? "enable" : "disable");
+ return ret;
+ }
+ }
+
+ if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_MP0CLK_BIT)) {
+ ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_DS_MP0CLK_BIT, enablement);
+ if (ret) {
+ dev_err(adev->dev, "Failed to %s MP0/MPIOCLK DS!\n", enablement ? "enable" : "disable");
+ return ret;
+ }
+ }
+
+ if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_MP1CLK_BIT)) {
+ ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_DS_MP1CLK_BIT, enablement);
+ if (ret) {
+ dev_err(adev->dev, "Failed to %s MP1CLK DS!\n", enablement ? "enable" : "disable");
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+int smu_v15_0_gfx_ulv_control(struct smu_context *smu,
+ bool enablement)
+{
+ int ret = 0;
+
+ if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_GFX_ULV_BIT))
+ ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_GFX_ULV_BIT, enablement);
+
+ return ret;
+}
+
+int smu_v15_0_baco_set_armd3_sequence(struct smu_context *smu,
+ enum smu_baco_seq baco_seq)
+{
+ struct smu_baco_context *smu_baco = &smu->smu_baco;
+ int ret;
+
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_ArmD3,
+ baco_seq,
+ NULL);
+ if (ret)
+ return ret;
+
+ if (baco_seq == BACO_SEQ_BAMACO ||
+ baco_seq == BACO_SEQ_BACO)
+ smu_baco->state = SMU_BACO_STATE_ENTER;
+ else
+ smu_baco->state = SMU_BACO_STATE_EXIT;
+
+ return 0;
+}
+
+int smu_v15_0_get_bamaco_support(struct smu_context *smu)
+{
+ struct smu_baco_context *smu_baco = &smu->smu_baco;
+ int bamaco_support = 0;
+
+ if (amdgpu_sriov_vf(smu->adev) ||
+ !smu_baco->platform_support)
+ return 0;
+
+ if (smu_baco->maco_support)
+ bamaco_support |= MACO_SUPPORT;
+
+ /* return true if ASIC is in BACO state already */
+ if (smu_v15_0_baco_get_state(smu) == SMU_BACO_STATE_ENTER)
+ return (bamaco_support |= BACO_SUPPORT);
+
+ if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_BACO_BIT) &&
+ !smu_cmn_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT))
+ return 0;
+
+ return (bamaco_support |= BACO_SUPPORT);
+}
+
+enum smu_baco_state smu_v15_0_baco_get_state(struct smu_context *smu)
+{
+ struct smu_baco_context *smu_baco = &smu->smu_baco;
+
+ return smu_baco->state;
+}
+
+int smu_v15_0_baco_set_state(struct smu_context *smu,
+ enum smu_baco_state state)
+{
+ struct smu_baco_context *smu_baco = &smu->smu_baco;
+ struct amdgpu_device *adev = smu->adev;
+ int ret = 0;
+
+ if (smu_v15_0_baco_get_state(smu) == state)
+ return 0;
+
+ if (state == SMU_BACO_STATE_ENTER) {
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_EnterBaco,
+ (adev->pm.rpm_mode == AMDGPU_RUNPM_BAMACO) ?
+ BACO_SEQ_BAMACO : BACO_SEQ_BACO,
+ NULL);
+ } else {
+ ret = smu_cmn_send_smc_msg(smu,
+ SMU_MSG_ExitBaco,
+ NULL);
+ if (ret)
+ return ret;
+
+ /* clear vbios scratch 6 and 7 for coming asic reinit */
+ WREG32(adev->bios_scratch_reg_offset + 6, 0);
+ WREG32(adev->bios_scratch_reg_offset + 7, 0);
+ }
+
+ if (!ret)
+ smu_baco->state = state;
+
+ return ret;
+}
+
+int smu_v15_0_baco_enter(struct smu_context *smu)
+{
+ int ret = 0;
+
+ ret = smu_v15_0_baco_set_state(smu,
+ SMU_BACO_STATE_ENTER);
+ if (ret)
+ return ret;
+
+ msleep(10);
+
+ return ret;
+}
+
+int smu_v15_0_baco_exit(struct smu_context *smu)
+{
+ return smu_v15_0_baco_set_state(smu,
+ SMU_BACO_STATE_EXIT);
+}
+
+int smu_v15_0_set_gfx_power_up_by_imu(struct smu_context *smu)
+{
+ struct smu_msg_ctl *ctl = &smu->msg_ctl;
+ struct amdgpu_device *adev = smu->adev;
+ int ret;
+
+ if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
+ return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_EnableGfxImu,
+ ENABLE_IMU_ARG_GFXOFF_ENABLE, NULL);
+ }
+
+ mutex_lock(&ctl->lock);
+ ret = smu_msg_send_async_locked(ctl, SMU_MSG_EnableGfxImu,
+ ENABLE_IMU_ARG_GFXOFF_ENABLE);
+ mutex_unlock(&ctl->lock);
+
+ return ret;
+}
+
+int smu_v15_0_od_edit_dpm_table(struct smu_context *smu,
+ enum PP_OD_DPM_TABLE_COMMAND type,
+ long input[], uint32_t size)
+{
+ struct smu_dpm_context *smu_dpm = &(smu->smu_dpm);
+ int ret = 0;
+
+ /* Only allowed in manual mode */
+ if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
+ return -EINVAL;
+
+ switch (type) {
+ case PP_OD_EDIT_SCLK_VDDC_TABLE:
+ if (size != 2) {
+ dev_err(smu->adev->dev, "Input parameter number not correct\n");
+ return -EINVAL;
+ }
+
+ if (input[0] == 0) {
+ if (input[1] < smu->gfx_default_hard_min_freq) {
+ dev_warn(smu->adev->dev,
+ "Fine grain setting minimum sclk (%ld) MHz is less than the minimum allowed (%d) MHz\n",
+ input[1], smu->gfx_default_hard_min_freq);
+ return -EINVAL;
+ }
+ smu->gfx_actual_hard_min_freq = input[1];
+ } else if (input[0] == 1) {
+ if (input[1] > smu->gfx_default_soft_max_freq) {
+ dev_warn(smu->adev->dev,
+ "Fine grain setting maximum sclk (%ld) MHz is greater than the maximum allowed (%d) MHz\n",
+ input[1], smu->gfx_default_soft_max_freq);
+ return -EINVAL;
+ }
+ smu->gfx_actual_soft_max_freq = input[1];
+ } else {
+ return -EINVAL;
+ }
+ break;
+ case PP_OD_RESTORE_DEFAULT_TABLE:
+ if (size != 0) {
+ dev_err(smu->adev->dev, "Input parameter number not correct\n");
+ return -EINVAL;
+ }
+ smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
+ smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
+ break;
+ case PP_OD_COMMIT_DPM_TABLE:
+ if (size != 0) {
+ dev_err(smu->adev->dev, "Input parameter number not correct\n");
+ return -EINVAL;
+ }
+ if (smu->gfx_actual_hard_min_freq > smu->gfx_actual_soft_max_freq) {
+ dev_err(smu->adev->dev,
+ "The setting minimum sclk (%d) MHz is greater than the setting maximum sclk (%d) MHz\n",
+ smu->gfx_actual_hard_min_freq,
+ smu->gfx_actual_soft_max_freq);
+ return -EINVAL;
+ }
+
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk,
+ smu->gfx_actual_hard_min_freq,
+ NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Set hard min sclk failed!");
+ return ret;
+ }
+
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk,
+ smu->gfx_actual_soft_max_freq,
+ NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Set soft max sclk failed!");
+ return ret;
+ }
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return ret;
+}
+
+static int smu_v15_0_allow_ih_interrupt(struct smu_context *smu)
+{
+ return smu_cmn_send_smc_msg(smu,
+ SMU_MSG_AllowIHHostInterrupt,
+ NULL);
+}
+
+int smu_v15_0_enable_thermal_alert(struct smu_context *smu)
+{
+ int ret = 0;
+
+ if (!smu->irq_source.num_types)
+ return 0;
+
+ ret = amdgpu_irq_get(smu->adev, &smu->irq_source, 0);
+ if (ret)
+ return ret;
+
+ return smu_v15_0_allow_ih_interrupt(smu);
+}
+
+int smu_v15_0_disable_thermal_alert(struct smu_context *smu)
+{
+ if (!smu->irq_source.num_types)
+ return 0;
+
+ return amdgpu_irq_put(smu->adev, &smu->irq_source, 0);
+}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c
new file mode 100644
index 000000000000..bb8d09e73c7d
--- /dev/null
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c
@@ -0,0 +1,1472 @@
+/*
+ * Copyright 2025 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "smu_types.h"
+#define SWSMU_CODE_LAYER_L2
+
+#include "amdgpu.h"
+#include "amdgpu_smu.h"
+#include "smu_v15_0.h"
+#include "smu15_driver_if_v15_0_0.h"
+#include "smu_v15_0_0_ppt.h"
+#include "smu_v15_0_0_ppsmc.h"
+#include "smu_v15_0_0_pmfw.h"
+#include "smu_cmn.h"
+
+/*
+ * DO NOT use these for err/warn/info/debug messages.
+ * Use dev_err, dev_warn, dev_info and dev_dbg instead.
+ * They are more MGPU friendly.
+ */
+#undef pr_err
+#undef pr_warn
+#undef pr_info
+#undef pr_debug
+
+#define mmMP1_SMN_C2PMSG_30 0x005e
+#define mmMP1_SMN_C2PMSG_30_BASE_IDX 1
+
+#define mmMP1_SMN_C2PMSG_31 0x005f
+#define mmMP1_SMN_C2PMSG_31_BASE_IDX 1
+
+#define mmMP1_SMN_C2PMSG_32 0x0060
+#define mmMP1_SMN_C2PMSG_32_BASE_IDX 1
+
+#define mmMP1_SMN_C2PMSG_33 0x0061
+#define mmMP1_SMN_C2PMSG_33_BASE_IDX 1
+
+#define mmMP1_SMN_C2PMSG_34 0x0062
+#define mmMP1_SMN_C2PMSG_34_BASE_IDX 1
+
+#define SMU_15_0_UMD_PSTATE_GFXCLK 700
+#define SMU_15_0_UMD_PSTATE_SOCCLK 678
+#define SMU_15_0_UMD_PSTATE_FCLK 1800
+
+
+static const struct smu_feature_bits smu_v15_0_0_dpm_features = {
+ .bits = {
+ SMU_FEATURE_BIT_INIT(FEATURE_CCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_VCN_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_FCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_SOCCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_LCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_SHUBCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_DCFCLK_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_ISP_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_NPU_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_GFX_DPM_BIT),
+ SMU_FEATURE_BIT_INIT(FEATURE_VPE_DPM_BIT)
+ }
+};
+
+enum smu_mall_pg_config {
+ SMU_MALL_PG_CONFIG_PMFW_CONTROL = 0,
+ SMU_MALL_PG_CONFIG_DRIVER_CONTROL_ALWAYS_ON = 1,
+ SMU_MALL_PG_CONFIG_DRIVER_CONTROL_ALWAYS_OFF = 2,
+};
+
+static struct cmn2asic_msg_mapping smu_v15_0_0_message_map[SMU_MSG_MAX_COUNT] = {
+ MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1),
+ MSG_MAP(GetSmuVersion, PPSMC_MSG_GetPmfwVersion, 1),
+ MSG_MAP(GetDriverIfVersion, PPSMC_MSG_GetDriverIfVersion, 1),
+ MSG_MAP(PowerDownVcn, PPSMC_MSG_PowerDownVcn, 1),
+ MSG_MAP(PowerUpVcn, PPSMC_MSG_PowerUpVcn, 1),
+ MSG_MAP(SetSoftMinGfxclk, PPSMC_MSG_SetSoftMinGfxclk, 1),
+ MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload, 1),
+ MSG_MAP(TransferTableSmu2Dram, PPSMC_MSG_TransferTableSmu2Dram, 1),
+ MSG_MAP(TransferTableDram2Smu, PPSMC_MSG_TransferTableDram2Smu, 1),
+ MSG_MAP(GfxDeviceDriverReset, PPSMC_MSG_GfxDeviceDriverReset, 1),
+ MSG_MAP(GetEnabledSmuFeatures, PPSMC_MSG_GetEnabledSmuFeatures, 1),
+ MSG_MAP(SetSoftMinFclk, PPSMC_MSG_SetSoftMinFclk, 1),
+ MSG_MAP(SetSoftMinVcn, PPSMC_MSG_SetSoftMinVcn, 1),
+ MSG_MAP(EnableGfxImu, PPSMC_MSG_EnableGfxImu, 1),
+ MSG_MAP(AllowGfxOff, PPSMC_MSG_AllowGfxOff, 1),
+ MSG_MAP(DisallowGfxOff, PPSMC_MSG_DisallowGfxOff, 1),
+ MSG_MAP(SetSoftMaxGfxClk, PPSMC_MSG_SetSoftMaxGfxClk, 1),
+ MSG_MAP(SetSoftMaxSocclkByFreq, PPSMC_MSG_SetSoftMaxSocclkByFreq, 1),
+ MSG_MAP(SetSoftMaxFclkByFreq, PPSMC_MSG_SetSoftMaxFclkByFreq, 1),
+ MSG_MAP(SetSoftMaxVcn, PPSMC_MSG_SetSoftMaxVcn, 1),
+ MSG_MAP(PowerDownJpeg, PPSMC_MSG_PowerDownJpeg, 1),
+ MSG_MAP(PowerUpJpeg, PPSMC_MSG_PowerUpJpeg, 1),
+ MSG_MAP(SetSoftMinSocclkByFreq, PPSMC_MSG_SetSoftMinSocclkByFreq, 1),
+ MSG_MAP(AllowZstates, PPSMC_MSG_AllowZstates, 1),
+ MSG_MAP(GetSmartShiftStatus, PPSMC_MSG_GetSmartShiftStatus, 1),
+ MSG_MAP(PowerUpUmsch, PPSMC_MSG_PowerUpUmsch, 1),
+ MSG_MAP(PowerDownUmsch, PPSMC_MSG_PowerDownUmsch, 1),
+ MSG_MAP(PowerUpVpe, PPSMC_MSG_PowerUpVpe, 1),
+ MSG_MAP(PowerDownVpe, PPSMC_MSG_PowerDownVpe, 1),
+ MSG_MAP(EnableLSdma, PPSMC_MSG_EnableLSdma, 1),
+ MSG_MAP(DisableLSdma, PPSMC_MSG_DisableLSdma, 1),
+ MSG_MAP(SetSoftMaxVpe, PPSMC_MSG_SetSoftMaxVpe, 1),
+ MSG_MAP(SetSoftMinVpe, PPSMC_MSG_SetSoftMinVpe, 1),
+};
+
+static struct cmn2asic_mapping smu_v15_0_0_feature_mask_map[SMU_FEATURE_COUNT] = {
+ FEA_MAP(CCLK_DPM),
+ FEA_MAP(FAN_CONTROLLER),
+ FEA_MAP(PPT),
+ FEA_MAP(TDC),
+ FEA_MAP(THERMAL),
+ FEA_MAP(VCN_DPM),
+ FEA_MAP_REVERSE(FCLK),
+ FEA_MAP_REVERSE(SOCCLK),
+ FEA_MAP(LCLK_DPM),
+ FEA_MAP(SHUBCLK_DPM),
+ FEA_MAP(DCFCLK_DPM),
+ FEA_MAP_HALF_REVERSE(GFX),
+ FEA_MAP(DS_GFXCLK),
+ FEA_MAP(DS_SOCCLK),
+ FEA_MAP(DS_LCLK),
+ FEA_MAP(LOW_POWER_DCNCLKS),
+ FEA_MAP(DS_FCLK),
+ FEA_MAP(DS_MP1CLK),
+ FEA_MAP(PSI),
+ FEA_MAP(PROCHOT),
+ FEA_MAP(CPUOFF),
+ FEA_MAP(STAPM),
+ FEA_MAP(S0I3),
+ FEA_MAP(PERF_LIMIT),
+ FEA_MAP(CORE_DLDO),
+ FEA_MAP(DS_VCN),
+ FEA_MAP(CPPC),
+ FEA_MAP(DF_CSTATES),
+ FEA_MAP(ATHUB_PG),
+};
+
+static struct cmn2asic_mapping smu_v15_0_0_table_map[SMU_TABLE_COUNT] = {
+ TAB_MAP_VALID(WATERMARKS),
+ TAB_MAP_VALID(SMU_METRICS),
+ TAB_MAP_VALID(CUSTOM_DPM),
+ TAB_MAP_VALID(DPMCLOCKS),
+};
+
+static int smu_v15_0_0_init_smc_tables(struct smu_context *smu)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_table *tables = smu_table->tables;
+ int ret;
+
+ SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
+ PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
+ SMU_TABLE_INIT(tables, SMU_TABLE_DPMCLOCKS, sizeof(DpmClocks_t),
+ PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
+ SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
+ PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
+
+ smu_table->metrics_table = kzalloc_obj(SmuMetrics_t);
+ if (!smu_table->metrics_table)
+ goto err0_out;
+ smu_table->metrics_time = 0;
+
+ smu_table->clocks_table = kzalloc_obj(DpmClocks_t);
+ if (!smu_table->clocks_table)
+ goto err1_out;
+
+ smu_table->watermarks_table = kzalloc_obj(Watermarks_t);
+ if (!smu_table->watermarks_table)
+ goto err2_out;
+
+ ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS,
+ sizeof(struct gpu_metrics_v3_0),
+ SMU_GPU_METRICS_CACHE_INTERVAL);
+ if (ret)
+ goto err3_out;
+
+ return 0;
+
+err3_out:
+ kfree(smu_table->watermarks_table);
+err2_out:
+ kfree(smu_table->clocks_table);
+err1_out:
+ kfree(smu_table->metrics_table);
+err0_out:
+ return -ENOMEM;
+}
+
+static int smu_v15_0_0_fini_smc_tables(struct smu_context *smu)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+
+ kfree(smu_table->clocks_table);
+ smu_table->clocks_table = NULL;
+
+ kfree(smu_table->metrics_table);
+ smu_table->metrics_table = NULL;
+
+ kfree(smu_table->watermarks_table);
+ smu_table->watermarks_table = NULL;
+
+ smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
+ return 0;
+}
+
+static int smu_v15_0_0_system_features_control(struct smu_context *smu, bool en)
+{
+ struct amdgpu_device *adev = smu->adev;
+ int ret = 0;
+
+ if (!en && !adev->in_s0ix) {
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PrepareMp1ForUnload, NULL);
+
+ /* SMU resets BIF_FB_EN to zero, re-enable MC access on APUs with SMU V15 */
+ if (!ret && adev->nbio.funcs && adev->nbio.funcs->mc_access_enable)
+ adev->nbio.funcs->mc_access_enable(adev, true);
+ }
+
+ return ret;
+}
+
+static int smu_v15_0_0_update_table(struct smu_context *smu,
+ enum smu_table_id table_index,
+ int argument,
+ void *table_data,
+ bool drv2smu)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct amdgpu_device *adev = smu->adev;
+ struct smu_table *table = &smu_table->driver_table;
+ int table_id = smu_cmn_to_asic_specific_index(smu,
+ CMN2ASIC_MAPPING_TABLE,
+ table_index);
+ uint64_t address;
+ uint32_t table_size;
+ int ret;
+ uint32_t params[3];
+
+ if (!table_data || table_index >= SMU_TABLE_COUNT || table_id < 0)
+ return -EINVAL;
+
+ table_size = smu_table->tables[table_index].size;
+
+ if (drv2smu) {
+ memcpy(table->cpu_addr, table_data, table_size);
+ /*
+ * Flush hdp cache: to guard the content seen by
+ * GPU is consitent with CPU.
+ */
+ amdgpu_hdp_flush(adev, NULL);
+ }
+
+ address = table->mc_address;
+ params[0] = table_id;
+ params[1] = (uint32_t)lower_32_bits(address);
+ params[2] = (uint32_t)upper_32_bits(address);
+
+ ret = smu_cmn_send_smc_msg_with_params(smu,
+ drv2smu ? SMU_MSG_TransferTableDram2Smu :
+ SMU_MSG_TransferTableSmu2Dram,
+ params, ARRAY_SIZE(params),
+ NULL, 0);
+
+ if (ret)
+ return ret;
+
+ if (!drv2smu) {
+ amdgpu_hdp_invalidate(adev, NULL);
+ memcpy(table_data, table->cpu_addr, table_size);
+ }
+
+ return 0;
+}
+
+static int smu_v15_0_0_set_default_dpm_tables(struct smu_context *smu)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+
+ return smu_v15_0_0_update_table(smu, SMU_TABLE_DPMCLOCKS, 0,
+ smu_table->clocks_table, false);
+}
+
+static int smu_v15_0_0_get_metrics_table(struct smu_context *smu,
+ void *metrics_table,
+ bool bypass_cache)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ uint32_t table_size =
+ smu_table->tables[SMU_TABLE_SMU_METRICS].size;
+ int ret;
+
+ if (bypass_cache ||
+ !smu_table->metrics_time ||
+ time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(1))) {
+ ret = smu_v15_0_0_update_table(smu,
+ SMU_TABLE_SMU_METRICS,
+ 0,
+ smu_table->metrics_table,
+ false);
+ if (ret) {
+ dev_info(smu->adev->dev, "Failed to export SMU15_0_0 metrics table!\n");
+ return ret;
+ }
+ smu_table->metrics_time = jiffies;
+ }
+
+ if (metrics_table)
+ memcpy(metrics_table, smu_table->metrics_table, table_size);
+
+ return 0;
+}
+
+static int smu_v15_0_0_get_smu_metrics_data(struct smu_context *smu,
+ MetricsMember_t member,
+ uint32_t *value)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+
+ SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table;
+ int ret = 0;
+
+ ret = smu_v15_0_0_get_metrics_table(smu, NULL, false);
+ if (ret)
+ return ret;
+
+ switch (member) {
+ case METRICS_AVERAGE_GFXCLK:
+ *value = metrics->GfxclkFrequency;
+ break;
+ case METRICS_AVERAGE_SOCCLK:
+ *value = metrics->SocclkFrequency;
+ break;
+ case METRICS_AVERAGE_VCLK:
+ *value = metrics->VclkFrequency;
+ break;
+ case METRICS_AVERAGE_DCLK:
+ *value = 0;
+ break;
+ case METRICS_AVERAGE_UCLK:
+ *value = metrics->MemclkFrequency;
+ break;
+ case METRICS_AVERAGE_FCLK:
+ *value = metrics->FclkFrequency;
+ break;
+ case METRICS_AVERAGE_VPECLK:
+ *value = metrics->VpeclkFrequency;
+ break;
+ case METRICS_AVERAGE_NPUCLK:
+ *value = metrics->NpuclkFrequency;
+ break;
+ case METRICS_AVERAGE_GFXACTIVITY:
+ if ((smu->smc_fw_version > 0x5d4600))
+ *value = metrics->GfxActivity;
+ else
+ *value = metrics->GfxActivity / 100;
+ break;
+ case METRICS_AVERAGE_VCNACTIVITY:
+ *value = metrics->VcnActivity / 100;
+ break;
+ case METRICS_AVERAGE_SOCKETPOWER:
+ case METRICS_CURR_SOCKETPOWER:
+ *value = (metrics->SocketPower / 1000 << 8) +
+ (metrics->SocketPower % 1000 / 10);
+ break;
+ case METRICS_TEMPERATURE_EDGE:
+ *value = metrics->GfxTemperature / 100 *
+ SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+ break;
+ case METRICS_TEMPERATURE_HOTSPOT:
+ *value = metrics->SocTemperature / 100 *
+ SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+ break;
+ case METRICS_THROTTLER_RESIDENCY_PROCHOT:
+ *value = metrics->ThrottleResidency_PROCHOT;
+ break;
+ case METRICS_THROTTLER_RESIDENCY_SPL:
+ *value = metrics->ThrottleResidency_SPL;
+ break;
+ case METRICS_THROTTLER_RESIDENCY_FPPT:
+ *value = metrics->ThrottleResidency_FPPT;
+ break;
+ case METRICS_THROTTLER_RESIDENCY_SPPT:
+ *value = metrics->ThrottleResidency_SPPT;
+ break;
+ case METRICS_THROTTLER_RESIDENCY_THM_SOC:
+ *value = metrics->ThrottleResidency_THM_SOC;
+ break;
+ case METRICS_VOLTAGE_VDDGFX:
+ *value = 0;
+ break;
+ case METRICS_VOLTAGE_VDDSOC:
+ *value = 0;
+ break;
+ case METRICS_SS_APU_SHARE:
+ /* return the percentage of APU power with respect to APU's power limit.
+ * percentage is reported, this isn't boost value. Smartshift power
+ * boost/shift is only when the percentage is more than 100.
+ */
+ if (metrics->StapmOpnLimit > 0)
+ *value = (metrics->ApuPower * 100) / metrics->StapmOpnLimit;
+ else
+ *value = 0;
+ break;
+ case METRICS_SS_DGPU_SHARE:
+ /* return the percentage of dGPU power with respect to dGPU's power limit.
+ * percentage is reported, this isn't boost value. Smartshift power
+ * boost/shift is only when the percentage is more than 100.
+ */
+ if ((metrics->dGpuPower > 0) &&
+ (metrics->StapmCurrentLimit > metrics->StapmOpnLimit))
+ *value = (metrics->dGpuPower * 100) /
+ (metrics->StapmCurrentLimit - metrics->StapmOpnLimit);
+ else
+ *value = 0;
+ break;
+ default:
+ *value = UINT_MAX;
+ break;
+ }
+
+ return ret;
+}
+
+static int smu_v15_0_0_read_sensor(struct smu_context *smu,
+ enum amd_pp_sensors sensor,
+ void *data, uint32_t *size)
+{
+ int ret = 0;
+
+ if (!data || !size)
+ return -EINVAL;
+
+ switch (sensor) {
+ case AMDGPU_PP_SENSOR_GPU_LOAD:
+ ret = smu_v15_0_0_get_smu_metrics_data(smu,
+ METRICS_AVERAGE_GFXACTIVITY,
+ (uint32_t *)data);
+ *size = 4;
+ break;
+ case AMDGPU_PP_SENSOR_VCN_LOAD:
+ ret = smu_v15_0_0_get_smu_metrics_data(smu,
+ METRICS_AVERAGE_VCNACTIVITY,
+ (uint32_t *)data);
+ *size = 4;
+ break;
+ case AMDGPU_PP_SENSOR_GPU_AVG_POWER:
+ ret = smu_v15_0_0_get_smu_metrics_data(smu,
+ METRICS_AVERAGE_SOCKETPOWER,
+ (uint32_t *)data);
+ *size = 4;
+ break;
+ case AMDGPU_PP_SENSOR_GPU_INPUT_POWER:
+ ret = smu_v15_0_0_get_smu_metrics_data(smu,
+ METRICS_CURR_SOCKETPOWER,
+ (uint32_t *)data);
+ *size = 4;
+ break;
+ case AMDGPU_PP_SENSOR_EDGE_TEMP:
+ ret = smu_v15_0_0_get_smu_metrics_data(smu,
+ METRICS_TEMPERATURE_EDGE,
+ (uint32_t *)data);
+ *size = 4;
+ break;
+ case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
+ ret = smu_v15_0_0_get_smu_metrics_data(smu,
+ METRICS_TEMPERATURE_HOTSPOT,
+ (uint32_t *)data);
+ *size = 4;
+ break;
+ case AMDGPU_PP_SENSOR_GFX_MCLK:
+ ret = smu_v15_0_0_get_smu_metrics_data(smu,
+ METRICS_AVERAGE_UCLK,
+ (uint32_t *)data);
+ *(uint32_t *)data *= 100;
+ *size = 4;
+ break;
+ case AMDGPU_PP_SENSOR_GFX_SCLK:
+ ret = smu_v15_0_0_get_smu_metrics_data(smu,
+ METRICS_AVERAGE_GFXCLK,
+ (uint32_t *)data);
+ *(uint32_t *)data *= 100;
+ *size = 4;
+ break;
+ case AMDGPU_PP_SENSOR_VDDGFX:
+ ret = smu_v15_0_0_get_smu_metrics_data(smu,
+ METRICS_VOLTAGE_VDDGFX,
+ (uint32_t *)data);
+ *size = 4;
+ break;
+ case AMDGPU_PP_SENSOR_VDDNB:
+ ret = smu_v15_0_0_get_smu_metrics_data(smu,
+ METRICS_VOLTAGE_VDDSOC,
+ (uint32_t *)data);
+ *size = 4;
+ break;
+ case AMDGPU_PP_SENSOR_SS_APU_SHARE:
+ ret = smu_v15_0_0_get_smu_metrics_data(smu,
+ METRICS_SS_APU_SHARE,
+ (uint32_t *)data);
+ *size = 4;
+ break;
+ case AMDGPU_PP_SENSOR_SS_DGPU_SHARE:
+ ret = smu_v15_0_0_get_smu_metrics_data(smu,
+ METRICS_SS_DGPU_SHARE,
+ (uint32_t *)data);
+ *size = 4;
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+static int smu_v15_0_0_get_enabled_mask(struct smu_context *smu,
+ struct smu_feature_bits *feature_mask)
+{
+ uint32_t out[2];
+ int ret;
+
+ if (!feature_mask)
+ return -EINVAL;
+
+ ret = smu_cmn_send_smc_msg_with_params(smu,
+ SMU_MSG_GetEnabledSmuFeatures,
+ NULL, 0, out,
+ ARRAY_SIZE(out));
+
+ if (!ret)
+ smu_feature_bits_from_arr32(feature_mask, out,
+ SMU_FEATURE_NUM_DEFAULT);
+
+ return ret;
+}
+
+static bool smu_v15_0_0_is_dpm_running(struct smu_context *smu)
+{
+ int ret = 0;
+ struct smu_feature_bits feature_enabled;
+
+ ret = smu_v15_0_0_get_enabled_mask(smu, &feature_enabled);
+
+ if (ret)
+ return false;
+
+ return smu_feature_bits_test_mask(&feature_enabled,
+ smu_v15_0_0_dpm_features.bits);
+}
+
+static int smu_v15_0_0_set_watermarks_table(struct smu_context *smu,
+ struct pp_smu_wm_range_sets *clock_ranges)
+{
+ int i;
+ int ret = 0;
+ Watermarks_t *table = smu->smu_table.watermarks_table;
+
+ if (!table || !clock_ranges)
+ return -EINVAL;
+
+ if (clock_ranges->num_reader_wm_sets > NUM_WM_RANGES ||
+ clock_ranges->num_writer_wm_sets > NUM_WM_RANGES)
+ return -EINVAL;
+
+ for (i = 0; i < clock_ranges->num_reader_wm_sets; i++) {
+ table->WatermarkRow[WM_DCFCLK][i].MinClock =
+ clock_ranges->reader_wm_sets[i].min_drain_clk_mhz;
+ table->WatermarkRow[WM_DCFCLK][i].MaxClock =
+ clock_ranges->reader_wm_sets[i].max_drain_clk_mhz;
+ table->WatermarkRow[WM_DCFCLK][i].MinMclk =
+ clock_ranges->reader_wm_sets[i].min_fill_clk_mhz;
+ table->WatermarkRow[WM_DCFCLK][i].MaxMclk =
+ clock_ranges->reader_wm_sets[i].max_fill_clk_mhz;
+
+ table->WatermarkRow[WM_DCFCLK][i].WmSetting =
+ clock_ranges->reader_wm_sets[i].wm_inst;
+ }
+
+ for (i = 0; i < clock_ranges->num_writer_wm_sets; i++) {
+ table->WatermarkRow[WM_SOCCLK][i].MinClock =
+ clock_ranges->writer_wm_sets[i].min_fill_clk_mhz;
+ table->WatermarkRow[WM_SOCCLK][i].MaxClock =
+ clock_ranges->writer_wm_sets[i].max_fill_clk_mhz;
+ table->WatermarkRow[WM_SOCCLK][i].MinMclk =
+ clock_ranges->writer_wm_sets[i].min_drain_clk_mhz;
+ table->WatermarkRow[WM_SOCCLK][i].MaxMclk =
+ clock_ranges->writer_wm_sets[i].max_drain_clk_mhz;
+
+ table->WatermarkRow[WM_SOCCLK][i].WmSetting =
+ clock_ranges->writer_wm_sets[i].wm_inst;
+ }
+
+ smu->watermarks_bitmap |= WATERMARKS_EXIST;
+
+ /* pass data to smu controller */
+ if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
+ !(smu->watermarks_bitmap & WATERMARKS_LOADED)) {
+ ret = smu_cmn_write_watermarks_table(smu);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to update WMTABLE!");
+ return ret;
+ }
+ smu->watermarks_bitmap |= WATERMARKS_LOADED;
+ }
+
+ return 0;
+}
+
+static ssize_t smu_v15_0_0_get_gpu_metrics(struct smu_context *smu,
+ void **table)
+{
+ struct gpu_metrics_v3_0 *gpu_metrics =
+ (struct gpu_metrics_v3_0 *)smu_driver_table_ptr(
+ smu, SMU_DRIVER_TABLE_GPU_METRICS);
+ SmuMetrics_t metrics;
+ int ret = 0;
+
+ ret = smu_v15_0_0_get_metrics_table(smu, &metrics, false);
+ if (ret)
+ return ret;
+
+ smu_cmn_init_soft_gpu_metrics(gpu_metrics, 3, 0);
+
+ gpu_metrics->temperature_gfx = metrics.GfxTemperature;
+ gpu_metrics->temperature_soc = metrics.SocTemperature;
+ memcpy(&gpu_metrics->temperature_core[0],
+ &metrics.CoreTemperature[0],
+ sizeof(uint16_t) * 16);
+ gpu_metrics->temperature_skin = metrics.SkinTemp;
+
+ gpu_metrics->average_gfx_activity = metrics.GfxActivity;
+ gpu_metrics->average_vcn_activity = metrics.VcnActivity;
+
+ memcpy(&gpu_metrics->average_core_c0_activity[0],
+ &metrics.CoreC0Residency[0],
+ sizeof(uint16_t) * 16);
+ gpu_metrics->average_dram_reads = metrics.DRAMReads;
+ gpu_metrics->average_dram_writes = metrics.DRAMWrites;
+
+ gpu_metrics->average_socket_power = metrics.SocketPower;
+ gpu_metrics->average_apu_power = metrics.ApuPower;
+ gpu_metrics->average_gfx_power = metrics.GfxPower;
+ gpu_metrics->average_dgpu_power = metrics.dGpuPower;
+ gpu_metrics->average_all_core_power = metrics.AllCorePower;
+ gpu_metrics->average_sys_power = metrics.Psys;
+ memcpy(&gpu_metrics->average_core_power[0],
+ &metrics.CorePower[0],
+ sizeof(uint16_t) * 16);
+
+ gpu_metrics->average_gfxclk_frequency = metrics.GfxclkFrequency;
+ gpu_metrics->average_socclk_frequency = metrics.SocclkFrequency;
+ gpu_metrics->average_vpeclk_frequency = metrics.VpeclkFrequency;
+ gpu_metrics->average_fclk_frequency = metrics.FclkFrequency;
+ gpu_metrics->average_vclk_frequency = metrics.VclkFrequency;
+ gpu_metrics->average_uclk_frequency = metrics.MemclkFrequency;
+
+ memcpy(&gpu_metrics->current_coreclk[0],
+ &metrics.CoreFrequency[0],
+ sizeof(uint16_t) * 16);
+ gpu_metrics->current_core_maxfreq = metrics.InfrastructureCpuMaxFreq;
+ gpu_metrics->current_gfx_maxfreq = metrics.InfrastructureGfxMaxFreq;
+
+ gpu_metrics->throttle_residency_prochot = metrics.ThrottleResidency_PROCHOT;
+ gpu_metrics->throttle_residency_spl = metrics.ThrottleResidency_SPL;
+ gpu_metrics->throttle_residency_fppt = metrics.ThrottleResidency_FPPT;
+ gpu_metrics->throttle_residency_sppt = metrics.ThrottleResidency_SPPT;
+ gpu_metrics->throttle_residency_thm_soc = metrics.ThrottleResidency_THM_SOC;
+
+ gpu_metrics->time_filter_alphavalue = metrics.FilterAlphaValue;
+ gpu_metrics->system_clock_counter = ktime_get_boottime_ns();
+
+ *table = (void *)gpu_metrics;
+
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
+ return sizeof(struct gpu_metrics_v3_0);
+}
+
+static int smu_v15_0_0_mode2_reset(struct smu_context *smu)
+{
+ int ret;
+
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GfxDeviceDriverReset,
+ SMU_RESET_MODE_2, NULL);
+
+ if (ret)
+ dev_err(smu->adev->dev, "Failed to mode2 reset!\n");
+
+ return ret;
+}
+
+static int smu_v15_0_0_get_dpm_freq_by_index(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t dpm_level,
+ uint32_t *freq)
+{
+ DpmClocks_t *clk_table = smu->smu_table.clocks_table;
+
+ if (!clk_table || clk_type >= SMU_CLK_COUNT)
+ return -EINVAL;
+
+ switch (clk_type) {
+ case SMU_SOCCLK:
+ if (dpm_level >= clk_table->NumSocClkLevelsEnabled)
+ return -EINVAL;
+ *freq = clk_table->SocClocks[dpm_level];
+ break;
+ case SMU_VCLK:
+ if (dpm_level >= clk_table->VcnClkLevelsEnabled)
+ return -EINVAL;
+ *freq = clk_table->VClocks[dpm_level];
+ break;
+ case SMU_DCLK:
+ if (dpm_level >= clk_table->VcnClkLevelsEnabled)
+ return -EINVAL;
+ *freq = clk_table->DClocks[dpm_level];
+ break;
+ case SMU_UCLK:
+ case SMU_MCLK:
+ if (dpm_level >= clk_table->NumMemPstatesEnabled)
+ return -EINVAL;
+ *freq = clk_table->MemPstateTable[dpm_level].MemClk;
+ break;
+ case SMU_FCLK:
+ if (dpm_level >= clk_table->NumFclkLevelsEnabled)
+ return -EINVAL;
+ *freq = clk_table->FclkClocks_Freq[dpm_level];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int smu_v15_0_common_get_dpm_freq_by_index(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t dpm_level,
+ uint32_t *freq)
+{
+ smu_v15_0_0_get_dpm_freq_by_index(smu, clk_type, dpm_level, freq);
+
+ return 0;
+}
+
+static bool smu_v15_0_0_clk_dpm_is_enabled(struct smu_context *smu,
+ enum smu_clk_type clk_type)
+{
+ enum smu_feature_mask feature_id = 0;
+
+ switch (clk_type) {
+ case SMU_MCLK:
+ case SMU_UCLK:
+ case SMU_FCLK:
+ feature_id = SMU_FEATURE_DPM_FCLK_BIT;
+ break;
+ case SMU_GFXCLK:
+ case SMU_SCLK:
+ feature_id = SMU_FEATURE_DPM_GFXCLK_BIT;
+ break;
+ case SMU_SOCCLK:
+ feature_id = SMU_FEATURE_DPM_SOCCLK_BIT;
+ break;
+ case SMU_VCLK:
+ case SMU_DCLK:
+ case SMU_VCLK1:
+ case SMU_DCLK1:
+ feature_id = SMU_FEATURE_VCN_DPM_BIT;
+ break;
+ default:
+ return true;
+ }
+
+ return smu_cmn_feature_is_enabled(smu, feature_id);
+}
+
+static int smu_v15_0_0_get_dpm_ultimate_freq(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t *min,
+ uint32_t *max)
+{
+ DpmClocks_t *clk_table = smu->smu_table.clocks_table;
+ uint32_t clock_limit;
+ uint32_t max_dpm_level, min_dpm_level;
+ int ret = 0;
+
+ if (!smu_v15_0_0_clk_dpm_is_enabled(smu, clk_type)) {
+ switch (clk_type) {
+ case SMU_MCLK:
+ case SMU_UCLK:
+ clock_limit = smu->smu_table.boot_values.uclk;
+ break;
+ case SMU_FCLK:
+ clock_limit = smu->smu_table.boot_values.fclk;
+ break;
+ case SMU_GFXCLK:
+ case SMU_SCLK:
+ clock_limit = smu->smu_table.boot_values.gfxclk;
+ break;
+ case SMU_SOCCLK:
+ clock_limit = smu->smu_table.boot_values.socclk;
+ break;
+ case SMU_VCLK:
+ clock_limit = smu->smu_table.boot_values.vclk;
+ break;
+ case SMU_DCLK:
+ clock_limit = smu->smu_table.boot_values.dclk;
+ break;
+ default:
+ clock_limit = 0;
+ break;
+ }
+
+ /* clock in Mhz unit */
+ if (min)
+ *min = clock_limit / 100;
+ if (max)
+ *max = clock_limit / 100;
+
+ return 0;
+ }
+
+ if (max) {
+ switch (clk_type) {
+ case SMU_GFXCLK:
+ case SMU_SCLK:
+ *max = clk_table->MaxGfxClk;
+ break;
+ case SMU_MCLK:
+ case SMU_UCLK:
+ max_dpm_level = 0;
+ break;
+ case SMU_FCLK:
+ max_dpm_level = clk_table->NumFclkLevelsEnabled - 1;
+ break;
+ case SMU_SOCCLK:
+ max_dpm_level = clk_table->NumSocClkLevelsEnabled - 1;
+ break;
+ case SMU_VCLK:
+ case SMU_DCLK:
+ max_dpm_level = clk_table->VcnClkLevelsEnabled - 1;
+ break;
+ default:
+ ret = -EINVAL;
+ goto failed;
+ }
+
+ if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) {
+ ret = smu_v15_0_common_get_dpm_freq_by_index(smu, clk_type, max_dpm_level, max);
+ if (ret)
+ goto failed;
+ }
+ }
+
+ if (min) {
+ switch (clk_type) {
+ case SMU_GFXCLK:
+ case SMU_SCLK:
+ *min = clk_table->MinGfxClk;
+ break;
+ case SMU_MCLK:
+ case SMU_UCLK:
+ min_dpm_level = clk_table->NumMemPstatesEnabled - 1;
+ break;
+ case SMU_FCLK:
+ min_dpm_level = 0;
+ break;
+ case SMU_SOCCLK:
+ min_dpm_level = 0;
+ break;
+ case SMU_VCLK:
+ case SMU_DCLK:
+ min_dpm_level = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ goto failed;
+ }
+
+ if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) {
+ ret = smu_v15_0_common_get_dpm_freq_by_index(smu, clk_type, min_dpm_level, min);
+ if (ret)
+ goto failed;
+ }
+ }
+
+failed:
+ return ret;
+}
+
+static int smu_v15_0_common_get_dpm_ultimate_freq(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t *min,
+ uint32_t *max)
+{
+ if (clk_type != SMU_VCLK1 && clk_type != SMU_DCLK1)
+ smu_v15_0_0_get_dpm_ultimate_freq(smu, clk_type, min, max);
+
+ return 0;
+}
+
+static int smu_v15_0_0_get_current_clk_freq(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t *value)
+{
+ MetricsMember_t member_type;
+
+ switch (clk_type) {
+ case SMU_SOCCLK:
+ member_type = METRICS_AVERAGE_SOCCLK;
+ break;
+ case SMU_VCLK:
+ member_type = METRICS_AVERAGE_VCLK;
+ break;
+ case SMU_VCLK1:
+ member_type = METRICS_AVERAGE_VCLK1;
+ break;
+ case SMU_DCLK:
+ member_type = METRICS_AVERAGE_DCLK;
+ break;
+ case SMU_DCLK1:
+ member_type = METRICS_AVERAGE_DCLK1;
+ break;
+ case SMU_MCLK:
+ member_type = METRICS_AVERAGE_UCLK;
+ break;
+ case SMU_FCLK:
+ member_type = METRICS_AVERAGE_FCLK;
+ break;
+ case SMU_GFXCLK:
+ case SMU_SCLK:
+ member_type = METRICS_AVERAGE_GFXCLK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return smu_v15_0_0_get_smu_metrics_data(smu, member_type, value);
+}
+
+static int smu_v15_0_0_get_dpm_level_count(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t *count)
+{
+ DpmClocks_t *clk_table = smu->smu_table.clocks_table;
+
+ switch (clk_type) {
+ case SMU_SOCCLK:
+ *count = clk_table->NumSocClkLevelsEnabled;
+ break;
+ case SMU_VCLK:
+ *count = clk_table->VcnClkLevelsEnabled;
+ break;
+ case SMU_DCLK:
+ *count = clk_table->VcnClkLevelsEnabled;
+ break;
+ case SMU_MCLK:
+ *count = clk_table->NumMemPstatesEnabled;
+ break;
+ case SMU_FCLK:
+ *count = clk_table->NumFclkLevelsEnabled;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int smu_v15_0_common_get_dpm_level_count(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t *count)
+{
+ if (clk_type != SMU_VCLK1 && clk_type != SMU_DCLK1)
+ smu_v15_0_0_get_dpm_level_count(smu, clk_type, count);
+
+ return 0;
+}
+
+static int smu_v15_0_0_emit_clk_levels(struct smu_context *smu,
+ enum smu_clk_type clk_type, char *buf,
+ int *offset)
+{
+ int i, idx, ret = 0, size = *offset;
+ uint32_t cur_value = 0, value = 0, count = 0;
+ uint32_t min, max;
+
+ switch (clk_type) {
+ case SMU_OD_SCLK:
+ size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK");
+ size += sysfs_emit_at(buf, size, "0: %10uMhz\n",
+ (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq);
+ size += sysfs_emit_at(buf, size, "1: %10uMhz\n",
+ (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq);
+ break;
+ case SMU_OD_RANGE:
+ size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");
+ size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n",
+ smu->gfx_default_hard_min_freq,
+ smu->gfx_default_soft_max_freq);
+ break;
+ case SMU_SOCCLK:
+ case SMU_VCLK:
+ case SMU_DCLK:
+ case SMU_VCLK1:
+ case SMU_DCLK1:
+ case SMU_MCLK:
+ case SMU_FCLK:
+ ret = smu_v15_0_0_get_current_clk_freq(smu, clk_type, &cur_value);
+ if (ret)
+ return ret;
+
+ ret = smu_v15_0_common_get_dpm_level_count(smu, clk_type, &count);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < count; i++) {
+ idx = (clk_type == SMU_MCLK) ? (count - i - 1) : i;
+ ret = smu_v15_0_common_get_dpm_freq_by_index(smu, clk_type, idx, &value);
+ if (ret)
+ return ret;
+
+ size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i,
+ value,
+ cur_value == value ? "*" : "");
+ }
+ break;
+ case SMU_GFXCLK:
+ case SMU_SCLK:
+ ret = smu_v15_0_0_get_current_clk_freq(smu, clk_type, &cur_value);
+ if (ret)
+ return ret;
+ min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq;
+ max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq;
+ if (cur_value == max)
+ i = 2;
+ else if (cur_value == min)
+ i = 0;
+ else
+ i = 1;
+ size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", min,
+ i == 0 ? "*" : "");
+ size += sysfs_emit_at(
+ buf, size, "1: %uMhz %s\n",
+ i == 1 ? cur_value : 1100, /* UMD PSTATE GFXCLK 1100 */
+ i == 1 ? "*" : "");
+ size += sysfs_emit_at(buf, size, "2: %uMhz %s\n", max,
+ i == 2 ? "*" : "");
+ break;
+ default:
+ break;
+ }
+
+ *offset = size;
+
+ return 0;
+}
+
+static int smu_v15_0_0_set_soft_freq_limited_range(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t min,
+ uint32_t max)
+{
+ enum smu_message_type msg_set_min, msg_set_max;
+ int ret = 0;
+
+ if (!smu_v15_0_0_clk_dpm_is_enabled(smu, clk_type))
+ return -EINVAL;
+
+ switch (clk_type) {
+ case SMU_GFXCLK:
+ case SMU_SCLK:
+ msg_set_min = SMU_MSG_SetSoftMinGfxclk;
+ msg_set_max = SMU_MSG_SetSoftMaxGfxClk;
+ break;
+ case SMU_FCLK:
+ msg_set_min = SMU_MSG_SetSoftMinFclk;
+ msg_set_max = SMU_MSG_SetSoftMaxFclkByFreq;
+ break;
+ case SMU_SOCCLK:
+ msg_set_min = SMU_MSG_SetSoftMinSocclkByFreq;
+ msg_set_max = SMU_MSG_SetSoftMaxSocclkByFreq;
+ break;
+ case SMU_VCLK:
+ case SMU_DCLK:
+ msg_set_min = SMU_MSG_SetSoftMinVcn;
+ msg_set_max = SMU_MSG_SetSoftMaxVcn;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_min, min, NULL);
+ if (ret)
+ return ret;
+
+ return smu_cmn_send_smc_msg_with_param(smu, msg_set_max,
+ max, NULL);
+}
+
+static int smu_v15_0_0_force_clk_levels(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t mask)
+{
+ uint32_t soft_min_level = 0, soft_max_level = 0;
+ uint32_t min_freq = 0, max_freq = 0;
+ int ret = 0;
+
+ soft_min_level = mask ? (ffs(mask) - 1) : 0;
+ soft_max_level = mask ? (fls(mask) - 1) : 0;
+
+ switch (clk_type) {
+ case SMU_SOCCLK:
+ case SMU_FCLK:
+ case SMU_VCLK:
+ case SMU_DCLK:
+ case SMU_VCLK1:
+ case SMU_DCLK1:
+ ret = smu_v15_0_common_get_dpm_freq_by_index(smu, clk_type, soft_min_level, &min_freq);
+ if (ret)
+ break;
+
+ ret = smu_v15_0_common_get_dpm_freq_by_index(smu, clk_type, soft_max_level, &max_freq);
+ if (ret)
+ break;
+
+ ret = smu_v15_0_0_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int smu_v15_0_common_get_dpm_profile_freq(struct smu_context *smu,
+ enum amd_dpm_forced_level level,
+ enum smu_clk_type clk_type,
+ uint32_t *min_clk,
+ uint32_t *max_clk)
+{
+ uint32_t clk_limit = 0;
+ int ret = 0;
+
+ switch (clk_type) {
+ case SMU_GFXCLK:
+ case SMU_SCLK:
+ clk_limit = SMU_15_0_UMD_PSTATE_GFXCLK;
+ if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &clk_limit);
+ else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK)
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_SCLK, &clk_limit, NULL);
+ break;
+ case SMU_SOCCLK:
+ clk_limit = SMU_15_0_UMD_PSTATE_SOCCLK;
+ if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_SOCCLK, NULL, &clk_limit);
+ break;
+ case SMU_FCLK:
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(15, 0, 0) ||
+ amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(15, 0, 9))
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &clk_limit);
+ else
+ clk_limit = SMU_15_0_UMD_PSTATE_FCLK;
+ if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &clk_limit);
+ else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK)
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_FCLK, &clk_limit, NULL);
+ break;
+ case SMU_VCLK:
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_VCLK, NULL, &clk_limit);
+ break;
+ case SMU_VCLK1:
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_VCLK1, NULL, &clk_limit);
+ break;
+ case SMU_DCLK:
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_DCLK, NULL, &clk_limit);
+ break;
+ case SMU_DCLK1:
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_DCLK1, NULL, &clk_limit);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ *min_clk = *max_clk = clk_limit;
+ return ret;
+}
+
+static int smu_v15_0_common_set_performance_level(struct smu_context *smu,
+ enum amd_dpm_forced_level level)
+{
+ struct amdgpu_device *adev = smu->adev;
+ uint32_t sclk_min = 0, sclk_max = 0;
+ uint32_t fclk_min = 0, fclk_max = 0;
+ uint32_t socclk_min = 0, socclk_max = 0;
+ uint32_t vclk_min = 0, vclk_max = 0;
+ uint32_t dclk_min = 0, dclk_max = 0;
+ uint32_t vclk1_min = 0, vclk1_max = 0;
+ uint32_t dclk1_min = 0, dclk1_max = 0;
+ int ret = 0;
+
+ switch (level) {
+ case AMD_DPM_FORCED_LEVEL_HIGH:
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &sclk_max);
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &fclk_max);
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_SOCCLK, NULL, &socclk_max);
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_VCLK, NULL, &vclk_max);
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_DCLK, NULL, &dclk_max);
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_VCLK1, NULL, &vclk1_max);
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_DCLK1, NULL, &dclk1_max);
+ sclk_min = sclk_max;
+ fclk_min = fclk_max;
+ socclk_min = socclk_max;
+ vclk_min = vclk_max;
+ dclk_min = dclk_max;
+ vclk1_min = vclk1_max;
+ dclk1_min = dclk1_max;
+ break;
+ case AMD_DPM_FORCED_LEVEL_LOW:
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, NULL);
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_FCLK, &fclk_min, NULL);
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_SOCCLK, &socclk_min, NULL);
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_VCLK, &vclk_min, NULL);
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_DCLK, &dclk_min, NULL);
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_VCLK1, &vclk1_min, NULL);
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_DCLK1, &dclk1_min, NULL);
+ sclk_max = sclk_min;
+ fclk_max = fclk_min;
+ socclk_max = socclk_min;
+ vclk_max = vclk_min;
+ dclk_max = dclk_min;
+ vclk1_max = vclk1_min;
+ dclk1_max = dclk1_min;
+ break;
+ case AMD_DPM_FORCED_LEVEL_AUTO:
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, &sclk_max);
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_FCLK, &fclk_min, &fclk_max);
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_SOCCLK, &socclk_min, &socclk_max);
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_VCLK, &vclk_min, &vclk_max);
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_DCLK, &dclk_min, &dclk_max);
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_VCLK1, &vclk1_min, &vclk1_max);
+ smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_DCLK1, &dclk1_min, &dclk1_max);
+ 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:
+ smu_v15_0_common_get_dpm_profile_freq(smu, level, SMU_SCLK, &sclk_min, &sclk_max);
+ smu_v15_0_common_get_dpm_profile_freq(smu, level, SMU_FCLK, &fclk_min, &fclk_max);
+ smu_v15_0_common_get_dpm_profile_freq(smu, level, SMU_SOCCLK, &socclk_min, &socclk_max);
+ smu_v15_0_common_get_dpm_profile_freq(smu, level, SMU_VCLK, &vclk_min, &vclk_max);
+ smu_v15_0_common_get_dpm_profile_freq(smu, level, SMU_DCLK, &dclk_min, &dclk_max);
+ smu_v15_0_common_get_dpm_profile_freq(smu, level, SMU_VCLK1, &vclk1_min, &vclk1_max);
+ smu_v15_0_common_get_dpm_profile_freq(smu, level, SMU_DCLK1, &dclk1_min, &dclk1_max);
+ break;
+ case AMD_DPM_FORCED_LEVEL_MANUAL:
+ case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
+ return 0;
+ default:
+ dev_err(adev->dev, "Invalid performance level %d\n", level);
+ return -EINVAL;
+ }
+
+ if (sclk_min && sclk_max) {
+ ret = smu_v15_0_0_set_soft_freq_limited_range(smu,
+ SMU_SCLK,
+ sclk_min,
+ sclk_max);
+ if (ret)
+ return ret;
+
+ smu->gfx_actual_hard_min_freq = sclk_min;
+ smu->gfx_actual_soft_max_freq = sclk_max;
+ }
+
+ if (fclk_min && fclk_max) {
+ ret = smu_v15_0_0_set_soft_freq_limited_range(smu,
+ SMU_FCLK,
+ fclk_min,
+ fclk_max);
+ if (ret)
+ return ret;
+ }
+
+ if (socclk_min && socclk_max) {
+ ret = smu_v15_0_0_set_soft_freq_limited_range(smu,
+ SMU_SOCCLK,
+ socclk_min,
+ socclk_max);
+ if (ret)
+ return ret;
+ }
+
+ if (vclk_min && vclk_max) {
+ ret = smu_v15_0_0_set_soft_freq_limited_range(smu,
+ SMU_VCLK,
+ vclk_min,
+ vclk_max);
+ if (ret)
+ return ret;
+ }
+
+ if (vclk1_min && vclk1_max) {
+ ret = smu_v15_0_0_set_soft_freq_limited_range(smu,
+ SMU_VCLK1,
+ vclk1_min,
+ vclk1_max);
+ if (ret)
+ return ret;
+ }
+
+ if (dclk_min && dclk_max) {
+ ret = smu_v15_0_0_set_soft_freq_limited_range(smu,
+ SMU_DCLK,
+ dclk_min,
+ dclk_max);
+ if (ret)
+ return ret;
+ }
+
+ if (dclk1_min && dclk1_max) {
+ ret = smu_v15_0_0_set_soft_freq_limited_range(smu,
+ SMU_DCLK1,
+ dclk1_min,
+ dclk1_max);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+static int smu_v15_0_0_set_fine_grain_gfx_freq_parameters(struct smu_context *smu)
+{
+ DpmClocks_t *clk_table = smu->smu_table.clocks_table;
+
+ smu->gfx_default_hard_min_freq = clk_table->MinGfxClk;
+ smu->gfx_default_soft_max_freq = clk_table->MaxGfxClk;
+ smu->gfx_actual_hard_min_freq = 0;
+ smu->gfx_actual_soft_max_freq = 0;
+
+ return 0;
+}
+
+static int smu_v15_0_common_set_fine_grain_gfx_freq_parameters(struct smu_context *smu)
+{
+ smu_v15_0_0_set_fine_grain_gfx_freq_parameters(smu);
+
+ return 0;
+}
+
+static int smu_v15_0_0_set_vpe_enable(struct smu_context *smu,
+ bool enable)
+{
+ return smu_cmn_send_smc_msg_with_param(smu, enable ?
+ SMU_MSG_PowerUpVpe : SMU_MSG_PowerDownVpe,
+ 0, NULL);
+}
+
+static int smu_v15_0_0_set_umsch_mm_enable(struct smu_context *smu,
+ bool enable)
+{
+ return smu_cmn_send_smc_msg_with_param(smu, enable ?
+ SMU_MSG_PowerUpUmsch : SMU_MSG_PowerDownUmsch,
+ 0, NULL);
+}
+
+static int smu_v15_0_0_get_dpm_table(struct smu_context *smu, struct dpm_clocks *clock_table)
+{
+ DpmClocks_t *clk_table = smu->smu_table.clocks_table;
+ uint8_t idx;
+
+ /* Only the Clock information of SOC and VPE is copied to provide VPE DPM settings for use. */
+ for (idx = 0; idx < NUM_SOCCLK_DPM_LEVELS; idx++) {
+ clock_table->SocClocks[idx].Freq = (idx < clk_table->NumSocClkLevelsEnabled) ? clk_table->SocClocks[idx]:0;
+ clock_table->SocClocks[idx].Vol = 0;
+ }
+
+ for (idx = 0; idx < NUM_VPE_DPM_LEVELS; idx++) {
+ clock_table->VPEClocks[idx].Freq = (idx < clk_table->VpeClkLevelsEnabled) ? clk_table->VPEClocks[idx]:0;
+ clock_table->VPEClocks[idx].Vol = 0;
+ }
+
+ return 0;
+}
+
+static int smu_v15_0_common_get_dpm_table(struct smu_context *smu, struct dpm_clocks *clock_table)
+{
+ smu_v15_0_0_get_dpm_table(smu, clock_table);
+
+ return 0;
+}
+
+static const struct pptable_funcs smu_v15_0_0_ppt_funcs = {
+ .check_fw_status = smu_v15_0_check_fw_status,
+ .check_fw_version = smu_cmn_check_fw_version,
+ .init_smc_tables = smu_v15_0_0_init_smc_tables,
+ .fini_smc_tables = smu_v15_0_0_fini_smc_tables,
+ .get_vbios_bootup_values = smu_v15_0_get_vbios_bootup_values,
+ .system_features_control = smu_v15_0_0_system_features_control,
+ .dpm_set_vcn_enable = smu_v15_0_set_vcn_enable,
+ .dpm_set_jpeg_enable = smu_v15_0_set_jpeg_enable,
+ .set_default_dpm_table = smu_v15_0_0_set_default_dpm_tables,
+ .read_sensor = smu_v15_0_0_read_sensor,
+ .is_dpm_running = smu_v15_0_0_is_dpm_running,
+ .set_watermarks_table = smu_v15_0_0_set_watermarks_table,
+ .get_gpu_metrics = smu_v15_0_0_get_gpu_metrics,
+ .get_enabled_mask = smu_v15_0_0_get_enabled_mask,
+ .get_pp_feature_mask = smu_cmn_get_pp_feature_mask,
+ .gfx_off_control = smu_v15_0_gfx_off_control,
+ .mode2_reset = smu_v15_0_0_mode2_reset,
+ .get_dpm_ultimate_freq = smu_v15_0_common_get_dpm_ultimate_freq,
+ .od_edit_dpm_table = smu_v15_0_od_edit_dpm_table,
+ .emit_clk_levels = smu_v15_0_0_emit_clk_levels,
+ .force_clk_levels = smu_v15_0_0_force_clk_levels,
+ .set_performance_level = smu_v15_0_common_set_performance_level,
+ .set_fine_grain_gfx_freq_parameters = smu_v15_0_common_set_fine_grain_gfx_freq_parameters,
+ .set_gfx_power_up_by_imu = smu_v15_0_set_gfx_power_up_by_imu,
+ .dpm_set_vpe_enable = smu_v15_0_0_set_vpe_enable,
+ .dpm_set_umsch_mm_enable = smu_v15_0_0_set_umsch_mm_enable,
+ .get_dpm_clock_table = smu_v15_0_common_get_dpm_table,
+};
+
+static void smu_v15_0_0_init_msg_ctl(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+ struct smu_msg_ctl *ctl = &smu->msg_ctl;
+
+ ctl->smu = smu;
+ mutex_init(&ctl->lock);
+ ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_30);
+ ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_31);
+ ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_32);
+ ctl->config.arg_regs[1] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_33);
+ ctl->config.arg_regs[2] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_34);
+ ctl->config.num_arg_regs = 3;
+ ctl->ops = &smu_msg_v1_ops;
+ ctl->default_timeout = adev->usec_timeout * 20;
+ ctl->message_map = smu_v15_0_0_message_map;
+}
+
+void smu_v15_0_0_set_ppt_funcs(struct smu_context *smu)
+{
+ smu->ppt_funcs = &smu_v15_0_0_ppt_funcs;
+ smu->feature_map = smu_v15_0_0_feature_mask_map;
+ smu->table_map = smu_v15_0_0_table_map;
+ smu->is_apu = true;
+ smu->smc_driver_if_version = SMU15_DRIVER_IF_VERSION_SMU_V15_0;
+
+ smu_v15_0_0_init_msg_ctl(smu);
+}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.h
new file mode 100644
index 000000000000..8365b9fea77e
--- /dev/null
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2025 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __SMU_V15_0_0_PPT_H__
+#define __SMU_V15_0_0_PPT_H__
+
+extern void smu_v15_0_0_set_ppt_funcs(struct smu_context *smu);
+
+#endif \ No newline at end of file
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c
new file mode 100644
index 000000000000..2105a1d7bb34
--- /dev/null
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c
@@ -0,0 +1,2421 @@
+/*
+ * Copyright 2025 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#define SWSMU_CODE_LAYER_L2
+
+#include <linux/firmware.h>
+#include "amdgpu.h"
+#include "amdgpu_smu.h"
+#include "smu_v15_0_8_pmfw.h"
+#include "smu15_driver_if_v15_0_8.h"
+#include "smu_v15_0_8_ppsmc.h"
+#include "smu_v15_0_8_ppt.h"
+#include <linux/pci.h>
+#include "smu_cmn.h"
+#include "mp/mp_15_0_8_offset.h"
+#include "mp/mp_15_0_8_sh_mask.h"
+#include "smu_v15_0.h"
+#include "amdgpu_fru_eeprom.h"
+
+#undef MP1_Public
+
+/* address block */
+#define MP1_Public 0x03b00000
+#define smnMP1_FIRMWARE_FLAGS_15_0_8 0x3010024
+/*
+ * DO NOT use these for err/warn/info/debug messages.
+ * Use dev_err, dev_warn, dev_info and dev_dbg instead.
+ * They are more MGPU friendly.
+ */
+#undef pr_err
+#undef pr_warn
+#undef pr_info
+#undef pr_debug
+
+#define SMUQ10_TO_UINT(x) ((x) >> 10)
+#define SMUQ10_FRAC(x) ((x) & 0x3ff)
+#define SMUQ10_ROUND(x) ((SMUQ10_TO_UINT(x)) + ((SMUQ10_FRAC(x)) >= 0x200))
+
+#define hbm_stack_mask_valid(umc_mask) \
+ (((umc_mask) & 0xF) == 0xF)
+
+#define for_each_hbm_stack(stack_idx, umc_mask) \
+ for ((stack_idx) = 0; (umc_mask); \
+ (umc_mask) >>= 4, (stack_idx)++) \
+
+#define NUM_JPEG_RINGS_FW 10
+
+#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c))
+
+#define SMU_15_0_8_FEA_MAP(smu_feature, smu_15_0_8_feature) \
+ [smu_feature] = { 1, (smu_15_0_8_feature) }
+
+#define FEATURE_MASK(feature) (1ULL << feature)
+
+static const struct smu_feature_bits smu_v15_0_8_dpm_features = {
+ .bits = { SMU_FEATURE_BIT_INIT(FEATURE_ID_DATA_CALCULATION),
+ SMU_FEATURE_BIT_INIT(FEATURE_ID_DPM_GFXCLK),
+ SMU_FEATURE_BIT_INIT(FEATURE_ID_DPM_UCLK),
+ SMU_FEATURE_BIT_INIT(FEATURE_ID_DPM_FCLK),
+ SMU_FEATURE_BIT_INIT(FEATURE_ID_DPM_GL2CLK) }
+};
+
+static const struct cmn2asic_msg_mapping smu_v15_0_8_message_map[SMU_MSG_MAX_COUNT] = {
+ MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 0),
+ MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1),
+ MSG_MAP(GfxDeviceDriverReset, PPSMC_MSG_GfxDriverReset, SMU_MSG_RAS_PRI | SMU_MSG_NO_PRECHECK),
+ MSG_MAP(GetDriverIfVersion, PPSMC_MSG_GetDriverIfVersion, 1),
+ MSG_MAP(EnableAllSmuFeatures, PPSMC_MSG_EnableAllSmuFeatures, 0),
+ MSG_MAP(GetMetricsVersion, PPSMC_MSG_GetMetricsVersion, 1),
+ MSG_MAP(GetMetricsTable, PPSMC_MSG_GetMetricsTable, 1),
+ MSG_MAP(GetEnabledSmuFeatures, PPSMC_MSG_GetEnabledSmuFeatures, 1),
+ MSG_MAP(SetDriverDramAddr, PPSMC_MSG_SetDriverDramAddr, 1),
+ MSG_MAP(SetToolsDramAddr, PPSMC_MSG_SetToolsDramAddr, 0),
+ MSG_MAP(SetSoftMaxByFreq, PPSMC_MSG_SetSoftMaxByFreq, 1),
+ MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit, 0),
+ MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit, 1),
+ MSG_MAP(DramLogSetDramAddr, PPSMC_MSG_DramLogSetDramAddr, 0),
+ MSG_MAP(HeavySBR, PPSMC_MSG_HeavySBR, 0),
+ MSG_MAP(DFCstateControl, PPSMC_MSG_DFCstateControl, 0),
+ MSG_MAP(GfxDriverResetRecovery, PPSMC_MSG_GfxDriverResetRecovery, 0),
+ MSG_MAP(SetSoftMinGfxclk, PPSMC_MSG_SetSoftMinGfxClk, 1),
+ MSG_MAP(SetSoftMaxGfxClk, PPSMC_MSG_SetSoftMaxGfxClk, 1),
+ MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareForDriverUnload, 0),
+ MSG_MAP(QueryValidMcaCount, PPSMC_MSG_QueryValidMcaCount, SMU_MSG_RAS_PRI),
+ MSG_MAP(McaBankDumpDW, PPSMC_MSG_McaBankDumpDW, SMU_MSG_RAS_PRI),
+ MSG_MAP(ClearMcaOnRead, PPSMC_MSG_ClearMcaOnRead, 0),
+ MSG_MAP(QueryValidMcaCeCount, PPSMC_MSG_QueryValidMcaCeCount, SMU_MSG_RAS_PRI),
+ MSG_MAP(McaBankCeDumpDW, PPSMC_MSG_McaBankCeDumpDW, SMU_MSG_RAS_PRI),
+ MSG_MAP(SelectPLPDMode, PPSMC_MSG_SelectPLPDMode, 0),
+ MSG_MAP(SetThrottlingPolicy, PPSMC_MSG_SetThrottlingPolicy, 0),
+ MSG_MAP(ResetSDMA, PPSMC_MSG_ResetSDMA, 0),
+ MSG_MAP(GetRASTableVersion, PPSMC_MSG_GetRasTableVersion, 0),
+ MSG_MAP(SetTimestamp, PPSMC_MSG_SetTimestamp, 0),
+ MSG_MAP(GetTimestamp, PPSMC_MSG_GetTimestamp, 0),
+ MSG_MAP(GetBadPageIpid, PPSMC_MSG_GetBadPageIpIdLoHi, 0),
+ MSG_MAP(EraseRasTable, PPSMC_MSG_EraseRasTable, 0),
+ MSG_MAP(GetStaticMetricsTable, PPSMC_MSG_GetStaticMetricsTable, 1),
+ MSG_MAP(GetSystemMetricsTable, PPSMC_MSG_GetSystemMetricsTable, 1),
+ MSG_MAP(GetSystemMetricsVersion, PPSMC_MSG_GetSystemMetricsVersion, 0),
+ MSG_MAP(ResetVCN, PPSMC_MSG_ResetVCN, 0),
+ MSG_MAP(SetFastPptLimit, PPSMC_MSG_SetFastPptLimit, 0),
+ MSG_MAP(GetFastPptLimit, PPSMC_MSG_GetFastPptLimit, 0),
+ MSG_MAP(SetSoftMinGl2clk, PPSMC_MSG_SetSoftMinGl2clk, 0),
+ MSG_MAP(SetSoftMaxGl2clk, PPSMC_MSG_SetSoftMaxGl2clk, 0),
+ MSG_MAP(SetSoftMinFclk, PPSMC_MSG_SetSoftMinFclk, 0),
+ MSG_MAP(SetSoftMaxFclk, PPSMC_MSG_SetSoftMaxFclk, 0),
+};
+
+/* TODO: Update the clk map once enum PPCLK is updated in smu15_driver_if_v15_0_8.h */
+static struct cmn2asic_mapping smu_v15_0_8_clk_map[SMU_CLK_COUNT] = {
+ CLK_MAP(UCLK, PPCLK_UCLK),
+};
+
+static const struct cmn2asic_mapping smu_v15_0_8_feature_mask_map[SMU_FEATURE_COUNT] = {
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_DATA_CALCULATIONS_BIT, FEATURE_ID_DATA_CALCULATION),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_DPM_GFXCLK_BIT, FEATURE_ID_DPM_GFXCLK),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_DPM_UCLK_BIT, FEATURE_ID_DPM_UCLK),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_DPM_FCLK_BIT, FEATURE_ID_DPM_FCLK),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_DPM_GL2CLK_BIT, FEATURE_ID_DPM_GL2CLK),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_GFXCLK_BIT, FEATURE_ID_DS_GFXCLK),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_SOCCLK_BIT, FEATURE_ID_DS_SOCCLK),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_LCLK_BIT, FEATURE_ID_DS_LCLK),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_FCLK_BIT, FEATURE_ID_DS_FCLK),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_DMABECLK_BIT, FEATURE_ID_DS_DMABECLK),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_MPIFOECLK_BIT, FEATURE_ID_DS_MPIFOECLK),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_MPRASCLK_BIT, FEATURE_ID_DS_MPRASCLK),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_MPNHTCLK_BIT, FEATURE_ID_DS_MPNHTCLK),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_FIOCLK_BIT, FEATURE_ID_DS_FIOCLK),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_DXIOCLK_BIT, FEATURE_ID_DS_DXIOCLK),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_GL2CLK_BIT, FEATURE_ID_DS_GL2CLK),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_PPT_BIT, FEATURE_ID_PPT),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_TDC_BIT, FEATURE_ID_TDC),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_MP1_CG_BIT, FEATURE_ID_SMU_CG),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_FW_CTF_BIT, FEATURE_ID_FW_CTF),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_THERMAL_BIT, FEATURE_ID_THERMAL),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_SOC_PCC_BIT, FEATURE_ID_SOC_PCC),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_XGMI_PER_LINK_PWR_DWN_BIT, FEATURE_ID_XGMI_PER_LINK_PWR_DOWN),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_VCN_BIT, FEATURE_ID_DS_VCN),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_MP1CLK_BIT, FEATURE_ID_DS_MP1CLK),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_MPIOCLK_BIT, FEATURE_ID_DS_MPIOCLK),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_MP0CLK_BIT, FEATURE_ID_DS_MP0CLK),
+ SMU_15_0_8_FEA_MAP(SMU_FEATURE_PIT_BIT, FEATURE_ID_PIT),
+};
+
+#define TABLE_PMSTATUSLOG 0
+#define TABLE_SMU_METRICS 1
+#define TABLE_I2C_COMMANDS 2
+#define TABLE_COUNT 3
+
+static const struct cmn2asic_mapping smu_v15_0_8_table_map[SMU_TABLE_COUNT] = {
+ TAB_MAP(PMSTATUSLOG),
+ TAB_MAP(SMU_METRICS),
+ TAB_MAP(I2C_COMMANDS),
+};
+
+static const uint8_t smu_v15_0_8_throttler_map[] = {
+ [THROTTLER_PROCHOT_BIT] = (SMU_THROTTLER_PROCHOT_GFX_BIT),
+ [THROTTLER_THERMAL_SOCKET_BIT] = (SMU_THROTTLER_TEMP_GPU_BIT),
+ [THROTTLER_THERMAL_VR_BIT] = (SMU_THROTTLER_TEMP_VR_GFX_BIT),
+ [THROTTLER_THERMAL_HBM_BIT] = (SMU_THROTTLER_TEMP_MEM_BIT),
+};
+
+static size_t smu_v15_0_8_get_system_metrics_size(void)
+{
+ return sizeof(SystemMetricsTable_t);
+}
+
+static int smu_v15_0_8_tables_init(struct smu_context *smu)
+{
+ struct smu_v15_0_8_baseboard_temp_metrics *baseboard_temp_metrics;
+ struct smu_v15_0_8_gpuboard_temp_metrics *gpuboard_temp_metrics;
+ struct smu_table_context *smu_table = &smu->smu_table;
+ int ret, gpu_metrcs_size = sizeof(MetricsTable_t);
+ struct smu_table *tables = smu_table->tables;
+ struct smu_v15_0_8_gpu_metrics *gpu_metrics;
+ void *driver_pptable __free(kfree) = NULL;
+ void *metrics_table __free(kfree) = NULL;
+
+ SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU15_TOOL_SIZE,
+ PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
+
+ SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS,
+ gpu_metrcs_size,
+ PAGE_SIZE,
+ AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT);
+ SMU_TABLE_INIT(tables, SMU_TABLE_PMFW_SYSTEM_METRICS,
+ smu_v15_0_8_get_system_metrics_size(), PAGE_SIZE,
+ AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT);
+
+ metrics_table = kzalloc(gpu_metrcs_size, GFP_KERNEL);
+ if (!metrics_table)
+ return -ENOMEM;
+
+ smu_table->metrics_time = 0;
+
+ driver_pptable = kzalloc(sizeof(PPTable_t), GFP_KERNEL);
+ if (!driver_pptable)
+ return -ENOMEM;
+
+ ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS,
+ sizeof(struct smu_v15_0_8_gpu_metrics),
+ SMU_GPU_METRICS_CACHE_INTERVAL);
+ if (ret)
+ return ret;
+
+ gpu_metrics = (struct smu_v15_0_8_gpu_metrics *)smu_driver_table_ptr(smu,
+ SMU_DRIVER_TABLE_GPU_METRICS);
+ smu_v15_0_8_gpu_metrics_init(gpu_metrics, 1, 9);
+
+ ret = smu_table_cache_init(smu, SMU_TABLE_PMFW_SYSTEM_METRICS,
+ smu_v15_0_8_get_system_metrics_size(), 5);
+
+ if (ret)
+ return ret;
+
+ /* Initialize base board temperature metrics */
+ ret = smu_driver_table_init(smu,
+ SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS,
+ sizeof(*baseboard_temp_metrics), 50);
+ if (ret)
+ return ret;
+ baseboard_temp_metrics = (struct smu_v15_0_8_baseboard_temp_metrics *)
+ smu_driver_table_ptr(smu,
+ SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS);
+ smu_v15_0_8_baseboard_temp_metrics_init(baseboard_temp_metrics, 1, 1);
+ /* Initialize GPU board temperature metrics */
+ ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS,
+ sizeof(*gpuboard_temp_metrics), 50);
+ if (ret) {
+ smu_table_cache_fini(smu, SMU_TABLE_PMFW_SYSTEM_METRICS);
+ smu_driver_table_fini(smu,
+ SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS);
+ return ret;
+ }
+ gpuboard_temp_metrics = (struct smu_v15_0_8_gpuboard_temp_metrics *)
+ smu_driver_table_ptr(smu,
+ SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS);
+ smu_v15_0_8_gpuboard_temp_metrics_init(gpuboard_temp_metrics, 1, 1);
+
+ smu_table->metrics_table = no_free_ptr(metrics_table);
+ smu_table->driver_pptable = no_free_ptr(driver_pptable);
+
+ mutex_init(&smu_table->metrics_lock);
+
+ return 0;
+}
+
+static int smu_v15_0_8_allocate_dpm_context(struct smu_context *smu)
+{
+ struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
+
+ smu_dpm->dpm_context =
+ kzalloc(sizeof(struct smu_15_0_dpm_context), GFP_KERNEL);
+ if (!smu_dpm->dpm_context)
+ return -ENOMEM;
+ smu_dpm->dpm_context_size = sizeof(struct smu_15_0_dpm_context);
+
+ smu_dpm->dpm_policies =
+ kzalloc(sizeof(struct smu_dpm_policy_ctxt), GFP_KERNEL);
+ if (!smu_dpm->dpm_policies) {
+ kfree(smu_dpm->dpm_context);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int smu_v15_0_8_init_smc_tables(struct smu_context *smu)
+{
+ int ret = 0;
+
+ ret = smu_v15_0_8_tables_init(smu);
+ if (ret)
+ return ret;
+
+ ret = smu_v15_0_8_allocate_dpm_context(smu);
+
+ return ret;
+}
+
+static int smu_v15_0_8_tables_fini(struct smu_context *smu)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+
+ smu_driver_table_fini(smu, SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS);
+ smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS);
+ smu_table_cache_fini(smu, SMU_TABLE_PMFW_SYSTEM_METRICS);
+ mutex_destroy(&smu_table->metrics_lock);
+
+ return 0;
+}
+
+static int smu_v15_0_8_fini_smc_tables(struct smu_context *smu)
+{
+ int ret;
+
+ ret = smu_v15_0_8_tables_fini(smu);
+ if (ret)
+ return ret;
+
+ ret = smu_v15_0_fini_smc_tables(smu);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+static int smu_v15_0_8_init_allowed_features(struct smu_context *smu)
+{
+ /* pptable will handle the features to enable */
+ smu_feature_list_set_all(smu, SMU_FEATURE_LIST_ALLOWED);
+
+ return 0;
+}
+
+static int smu_v15_0_8_get_metrics_table_internal(struct smu_context *smu, uint32_t tmo, void *data)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ uint32_t table_size = smu_table->tables[SMU_TABLE_SMU_METRICS].size;
+ struct smu_table *table = &smu_table->driver_table;
+ struct amdgpu_device *adev = smu->adev;
+
+ mutex_lock(&smu_table->metrics_lock);
+
+ if (!tmo || !smu_table->metrics_time ||
+ time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(tmo))) {
+ int ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetMetricsTable, NULL);
+ if (ret) {
+ dev_info(adev->dev,
+ "Failed to export SMU metrics table!\n");
+ mutex_unlock(&smu_table->metrics_lock);
+ return ret;
+ }
+
+ amdgpu_device_invalidate_hdp(smu->adev, NULL);
+ ret = smu_cmn_vram_cpy(smu, smu_table->metrics_table,
+ table->cpu_addr, table_size);
+ if (ret) {
+ mutex_unlock(&smu_table->metrics_lock);
+ return ret;
+ }
+
+ smu_table->metrics_time = jiffies;
+ }
+
+ if (data)
+ memcpy(data, smu_table->metrics_table, table_size);
+ mutex_unlock(&smu_table->metrics_lock);
+ return 0;
+}
+
+static int smu_v15_0_8_get_smu_metrics_data(struct smu_context *smu,
+ MetricsMember_t member, uint32_t *value)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ MetricsTable_t *metrics = (MetricsTable_t *)smu_table->metrics_table;
+ struct amdgpu_device *adev = smu->adev;
+ int ret, xcc_id;
+
+ ret = smu_v15_0_8_get_metrics_table_internal(smu, 10, NULL);
+ if (ret)
+ return ret;
+
+ switch (member) {
+ case METRICS_CURR_GFXCLK:
+ case METRICS_AVERAGE_GFXCLK:
+ xcc_id = GET_INST(GC, 0);
+ *value = SMUQ10_ROUND(metrics->GfxclkFrequency[xcc_id]);
+ break;
+ case METRICS_CURR_SOCCLK:
+ case METRICS_AVERAGE_SOCCLK:
+ *value = SMUQ10_ROUND(metrics->SocclkFrequency[0]);
+ break;
+ case METRICS_CURR_UCLK:
+ case METRICS_AVERAGE_UCLK:
+ *value = SMUQ10_ROUND(metrics->UclkFrequency[0]);
+ break;
+ case METRICS_CURR_VCLK:
+ *value = SMUQ10_ROUND(metrics->VclkFrequency[0]);
+ break;
+ case METRICS_CURR_DCLK:
+ *value = SMUQ10_ROUND(metrics->DclkFrequency[0]);
+ break;
+ case METRICS_CURR_FCLK:
+ *value = SMUQ10_ROUND(metrics->FclkFrequency[0]);
+ break;
+ case METRICS_AVERAGE_GFXACTIVITY:
+ *value = SMUQ10_ROUND(metrics->SocketGfxBusy);
+ break;
+ case METRICS_AVERAGE_MEMACTIVITY:
+ *value = SMUQ10_ROUND(metrics->DramBandwidthUtilization);
+ break;
+ case METRICS_CURR_SOCKETPOWER:
+ *value = SMUQ10_ROUND(metrics->SocketPower) << 8;
+ break;
+ case METRICS_TEMPERATURE_HOTSPOT:
+ *value = SMUQ10_ROUND(metrics->MaxSocketTemperature) *
+ SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+ break;
+ case METRICS_TEMPERATURE_MEM:
+ {
+ struct amdgpu_device *adev = smu->adev;
+ u32 max_hbm_temp = 0;
+
+ /* Find max temperature across all HBM stacks */
+ if (adev->umc.active_mask) {
+ u64 mask = adev->umc.active_mask;
+ int stack_idx;
+
+ for_each_hbm_stack(stack_idx, mask) {
+ u32 temp;
+
+ if (!hbm_stack_mask_valid(mask))
+ continue;
+
+ temp = SMUQ10_ROUND(metrics->HbmTemperature[stack_idx]);
+ if (temp > max_hbm_temp)
+ max_hbm_temp = temp;
+ }
+ }
+ *value = max_hbm_temp * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+ break;
+ }
+ /* This is the max of all VRs and not just SOC VR.
+ */
+ case METRICS_TEMPERATURE_VRSOC:
+ *value = SMUQ10_ROUND(metrics->MaxVrTemperature) *
+ SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+ break;
+ default:
+ *value = UINT_MAX;
+ break;
+ }
+
+ return 0;
+}
+
+static int smu_v15_0_8_get_current_clk_freq_by_table(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t *value)
+{
+ MetricsMember_t member_type;
+
+ if (!value)
+ return -EINVAL;
+
+ switch (clk_type) {
+ case SMU_GFXCLK:
+ case SMU_SCLK:
+ member_type = METRICS_CURR_GFXCLK;
+ break;
+ case SMU_UCLK:
+ case SMU_MCLK:
+ member_type = METRICS_CURR_UCLK;
+ break;
+ case SMU_SOCCLK:
+ member_type = METRICS_CURR_SOCCLK;
+ break;
+ case SMU_VCLK:
+ member_type = METRICS_CURR_VCLK;
+ break;
+ case SMU_DCLK:
+ member_type = METRICS_CURR_DCLK;
+ break;
+ case SMU_FCLK:
+ member_type = METRICS_CURR_FCLK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return smu_v15_0_8_get_smu_metrics_data(smu, member_type, value);
+}
+
+static int smu_v15_0_8_get_current_activity_percent(struct smu_context *smu,
+ enum amd_pp_sensors sensor,
+ uint32_t *value)
+{
+ int ret = 0;
+
+ if (!value)
+ return -EINVAL;
+
+ switch (sensor) {
+ case AMDGPU_PP_SENSOR_GPU_LOAD:
+ ret = smu_v15_0_8_get_smu_metrics_data(smu,
+ METRICS_AVERAGE_GFXACTIVITY, value);
+ break;
+ case AMDGPU_PP_SENSOR_MEM_LOAD:
+ ret = smu_v15_0_8_get_smu_metrics_data(smu,
+ METRICS_AVERAGE_MEMACTIVITY, value);
+ break;
+ default:
+ dev_err(smu->adev->dev,
+ "Invalid sensor for retrieving clock activity\n");
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int smu_v15_0_8_thermal_get_temperature(struct smu_context *smu,
+ enum amd_pp_sensors sensor,
+ uint32_t *value)
+{
+ int ret = 0;
+
+ if (!value)
+ return -EINVAL;
+
+ switch (sensor) {
+ case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
+ ret = smu_v15_0_8_get_smu_metrics_data(smu,
+ METRICS_TEMPERATURE_HOTSPOT, value);
+ break;
+ case AMDGPU_PP_SENSOR_MEM_TEMP:
+ ret = smu_v15_0_8_get_smu_metrics_data(smu,
+ METRICS_TEMPERATURE_MEM, value);
+ break;
+ default:
+ dev_err(smu->adev->dev, "Invalid sensor for retrieving temp\n");
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int smu_v15_0_8_get_system_metrics_table(struct smu_context *smu)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_table *table = &smu_table->driver_table;
+ struct smu_table *tables = smu_table->tables;
+ struct smu_table *sys_table;
+ int ret;
+
+ sys_table = &tables[SMU_TABLE_PMFW_SYSTEM_METRICS];
+ if (smu_table_cache_is_valid(sys_table))
+ return 0;
+
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetSystemMetricsTable, NULL);
+ if (ret) {
+ dev_info(smu->adev->dev,
+ "Failed to export system metrics table!\n");
+ return ret;
+ }
+
+ amdgpu_hdp_invalidate(smu->adev, NULL);
+
+ ret = smu_cmn_vram_cpy(smu, sys_table->cache.buffer,
+ table->cpu_addr,
+ sizeof(SystemMetricsTable_t));
+ if (ret)
+ return ret;
+
+ smu_table_cache_update_time(sys_table, jiffies);
+
+ return 0;
+}
+
+static int smu_v15_0_8_get_npm_data(struct smu_context *smu,
+ enum amd_pp_sensors sensor,
+ uint32_t *value)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_table *tables = smu_table->tables;
+ SystemMetricsTable_t *metrics;
+ struct smu_table *sys_table;
+ int ret;
+
+ if (sensor == AMDGPU_PP_SENSOR_MAXNODEPOWERLIMIT) {
+ /*TBD as of now put 0 */
+ *value = 0;
+ return 0;
+ }
+
+ ret = smu_v15_0_8_get_system_metrics_table(smu);
+ if (ret)
+ return ret;
+
+ sys_table = &tables[SMU_TABLE_PMFW_SYSTEM_METRICS];
+ metrics = (SystemMetricsTable_t *)sys_table->cache.buffer;
+
+ switch (sensor) {
+ case AMDGPU_PP_SENSOR_NODEPOWERLIMIT:
+ *value = SMUQ10_ROUND(metrics->NodePowerLimit);
+ break;
+ case AMDGPU_PP_SENSOR_NODEPOWER:
+ *value = SMUQ10_ROUND(metrics->NodePower);
+ break;
+ case AMDGPU_PP_SENSOR_GPPTRESIDENCY:
+ *value = SMUQ10_ROUND(metrics->GlobalPPTResidencyAcc);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int smu_v15_0_8_read_sensor(struct smu_context *smu,
+ enum amd_pp_sensors sensor, void *data,
+ uint32_t *size)
+{
+ struct smu_15_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
+ int ret = 0;
+
+ if (amdgpu_ras_intr_triggered())
+ return 0;
+
+ if (!data || !size)
+ return -EINVAL;
+
+ switch (sensor) {
+ case AMDGPU_PP_SENSOR_MEM_LOAD:
+ case AMDGPU_PP_SENSOR_GPU_LOAD:
+ ret = smu_v15_0_8_get_current_activity_percent(smu, sensor,
+ (uint32_t *)data);
+ *size = 4;
+ break;
+ case AMDGPU_PP_SENSOR_GPU_INPUT_POWER:
+ ret = smu_v15_0_8_get_smu_metrics_data(smu,
+ METRICS_CURR_SOCKETPOWER,
+ (uint32_t *)data);
+ *size = 4;
+ break;
+ case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
+ case AMDGPU_PP_SENSOR_MEM_TEMP:
+ ret = smu_v15_0_8_thermal_get_temperature(smu, sensor,
+ (uint32_t *)data);
+ *size = 4;
+ break;
+ case AMDGPU_PP_SENSOR_GFX_MCLK:
+ ret = smu_v15_0_8_get_current_clk_freq_by_table(smu,
+ SMU_UCLK, (uint32_t *)data);
+ /* the output clock frequency in 10K unit */
+ *(uint32_t *)data *= 100;
+ *size = 4;
+ break;
+ case AMDGPU_PP_SENSOR_GFX_SCLK:
+ ret = smu_v15_0_8_get_current_clk_freq_by_table(smu,
+ SMU_GFXCLK, (uint32_t *)data);
+ *(uint32_t *)data *= 100;
+ *size = 4;
+ break;
+ case AMDGPU_PP_SENSOR_VDDBOARD:
+ *(uint32_t *)data = dpm_context->board_volt;
+ *size = 4;
+ break;
+ case AMDGPU_PP_SENSOR_NODEPOWERLIMIT:
+ case AMDGPU_PP_SENSOR_NODEPOWER:
+ case AMDGPU_PP_SENSOR_GPPTRESIDENCY:
+ case AMDGPU_PP_SENSOR_MAXNODEPOWERLIMIT:
+ ret = smu_v15_0_8_get_npm_data(smu, sensor, (uint32_t *)data);
+ if (ret)
+ return ret;
+ *size = 4;
+ break;
+ case AMDGPU_PP_SENSOR_GPU_AVG_POWER:
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+static int smu_v15_0_8_emit_clk_levels(struct smu_context *smu,
+ enum smu_clk_type type, char *buf,
+ int *offset)
+{
+ struct smu_umd_pstate_table *pstate_table = &smu->pstate_table;
+ struct smu_15_0_dpm_context *dpm_context;
+ struct smu_dpm_table *single_dpm_table = NULL;
+ struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
+ int ret, now, size = *offset;
+
+ if (amdgpu_ras_intr_triggered()) {
+ sysfs_emit_at(buf, size, "unavailable\n");
+ return -EBUSY;
+ }
+
+ dpm_context = smu_dpm->dpm_context;
+
+ switch (type) {
+ case SMU_OD_SCLK:
+ size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK");
+ size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n",
+ pstate_table->gfxclk_pstate.curr.min,
+ pstate_table->gfxclk_pstate.curr.max);
+ break;
+ case SMU_OD_MCLK:
+ size += sysfs_emit_at(buf, size, "%s:\n", "OD_MCLK");
+ size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n",
+ pstate_table->uclk_pstate.curr.min,
+ pstate_table->uclk_pstate.curr.max);
+ break;
+ case SMU_SCLK:
+ case SMU_GFXCLK:
+ single_dpm_table = &dpm_context->dpm_tables.gfx_table;
+ break;
+ case SMU_MCLK:
+ case SMU_UCLK:
+ single_dpm_table = &dpm_context->dpm_tables.uclk_table;
+ break;
+ case SMU_SOCCLK:
+ single_dpm_table = &dpm_context->dpm_tables.soc_table;
+ break;
+ case SMU_FCLK:
+ single_dpm_table = &dpm_context->dpm_tables.fclk_table;
+ break;
+ case SMU_VCLK:
+ single_dpm_table = &dpm_context->dpm_tables.vclk_table;
+ break;
+ case SMU_DCLK:
+ single_dpm_table = &dpm_context->dpm_tables.dclk_table;
+ break;
+ default:
+ break;
+ }
+
+ if (single_dpm_table) {
+ ret = smu_v15_0_8_get_current_clk_freq_by_table(smu, type, &now);
+ if (ret) {
+ dev_err(smu->adev->dev,
+ "Attempt to get current clk Failed!");
+ return ret;
+ }
+ ret = smu_cmn_print_dpm_clk_levels(smu, single_dpm_table, now,
+ buf, offset);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+ }
+
+ *offset = size;
+
+ return 0;
+}
+
+static int smu_v15_0_8_get_dpm_ultimate_freq(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t *min, uint32_t *max)
+{
+ struct smu_15_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
+ struct smu_table_context *smu_table = &smu->smu_table;
+ PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable;
+ struct smu_dpm_table *dpm_table;
+ uint32_t min_clk = 0, max_clk = 0;
+
+ if (!pptable->init)
+ return -EINVAL;
+
+ /* Try cached DPM tables first */
+ if (dpm_context) {
+ switch (clk_type) {
+ case SMU_MCLK:
+ case SMU_UCLK:
+ dpm_table = &dpm_context->dpm_tables.uclk_table;
+ break;
+ case SMU_GFXCLK:
+ case SMU_SCLK:
+ dpm_table = &dpm_context->dpm_tables.gfx_table;
+ break;
+ case SMU_SOCCLK:
+ dpm_table = &dpm_context->dpm_tables.soc_table;
+ break;
+ case SMU_FCLK:
+ dpm_table = &dpm_context->dpm_tables.fclk_table;
+ break;
+ case SMU_GL2CLK:
+ dpm_table = &dpm_context->dpm_tables.gl2_table;
+ break;
+ case SMU_VCLK:
+ dpm_table = &dpm_context->dpm_tables.vclk_table;
+ break;
+ case SMU_DCLK:
+ dpm_table = &dpm_context->dpm_tables.dclk_table;
+ break;
+ default:
+ dpm_table = NULL;
+ break;
+ }
+
+ if (dpm_table && dpm_table->count > 0) {
+ min_clk = SMU_DPM_TABLE_MIN(dpm_table);
+ max_clk = SMU_DPM_TABLE_MAX(dpm_table);
+
+ if (min_clk && max_clk) {
+ if (min)
+ *min = min_clk;
+ if (max)
+ *max = max_clk;
+ return 0;
+ }
+ }
+ }
+
+ /* Fall back to pptable */
+ switch (clk_type) {
+ case SMU_GFXCLK:
+ case SMU_SCLK:
+ min_clk = pptable->MinGfxclkFrequency;
+ max_clk = pptable->MaxGfxclkFrequency;
+ break;
+ case SMU_FCLK:
+ min_clk = pptable->MinFclkFrequency;
+ max_clk = pptable->MaxFclkFrequency;
+ break;
+ case SMU_GL2CLK:
+ min_clk = pptable->MinGl2clkFrequency;
+ max_clk = pptable->MaxGl2clkFrequency;
+ break;
+ case SMU_MCLK:
+ case SMU_UCLK:
+ min_clk = pptable->UclkFrequencyTable[0];
+ max_clk = pptable->UclkFrequencyTable[ARRAY_SIZE(pptable->UclkFrequencyTable) - 1];
+ break;
+ case SMU_SOCCLK:
+ min_clk = pptable->SocclkFrequency;
+ max_clk = pptable->SocclkFrequency;
+ break;
+ case SMU_VCLK:
+ min_clk = pptable->VclkFrequency;
+ max_clk = pptable->VclkFrequency;
+ break;
+ case SMU_DCLK:
+ min_clk = pptable->DclkFrequency;
+ max_clk = pptable->DclkFrequency;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (min)
+ *min = min_clk;
+ if (max)
+ *max = max_clk;
+
+ return 0;
+}
+
+static int smu_v15_0_8_set_dpm_table(struct smu_context *smu)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_15_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
+ struct smu_dpm_table *dpm_table;
+ PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable;
+ int i, ret;
+ uint32_t gfxclkmin, gfxclkmax;
+
+ /* gfxclk dpm table setup - fine-grained */
+ dpm_table = &dpm_context->dpm_tables.gfx_table;
+ dpm_table->clk_type = SMU_GFXCLK;
+ dpm_table->flags = SMU_DPM_TABLE_FINE_GRAINED;
+ if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) {
+ ret = smu_v15_0_8_get_dpm_ultimate_freq(smu, SMU_GFXCLK,
+ &gfxclkmin, &gfxclkmax);
+ if (ret)
+ return ret;
+
+ dpm_table->count = 2;
+ dpm_table->dpm_levels[0].value = gfxclkmin;
+ dpm_table->dpm_levels[0].enabled = true;
+ dpm_table->dpm_levels[1].value = gfxclkmax;
+ dpm_table->dpm_levels[1].enabled = true;
+ } else {
+ dpm_table->count = 1;
+ dpm_table->dpm_levels[0].value = pptable->MinGfxclkFrequency;
+ dpm_table->dpm_levels[0].enabled = true;
+ }
+
+ /* fclk dpm table setup - fine-grained */
+ dpm_table = &dpm_context->dpm_tables.fclk_table;
+ dpm_table->clk_type = SMU_FCLK;
+ dpm_table->flags = SMU_DPM_TABLE_FINE_GRAINED;
+ if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT)) {
+ dpm_table->count = 2;
+ dpm_table->dpm_levels[0].value = pptable->MinFclkFrequency;
+ dpm_table->dpm_levels[0].enabled = true;
+ dpm_table->dpm_levels[1].value = pptable->MaxFclkFrequency;
+ dpm_table->dpm_levels[1].enabled = true;
+ } else {
+ dpm_table->count = 1;
+ dpm_table->dpm_levels[0].value = pptable->MinFclkFrequency;
+ dpm_table->dpm_levels[0].enabled = true;
+ }
+
+ /* gl2clk dpm table setup - fine-grained */
+ dpm_table = &dpm_context->dpm_tables.gl2_table;
+ dpm_table->flags = SMU_DPM_TABLE_FINE_GRAINED;
+ if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GL2CLK_BIT)) {
+ dpm_table->count = 2;
+ dpm_table->dpm_levels[0].value = pptable->MinGl2clkFrequency;
+ dpm_table->dpm_levels[0].enabled = true;
+ dpm_table->dpm_levels[1].value = pptable->MaxGl2clkFrequency;
+ dpm_table->dpm_levels[1].enabled = true;
+ } else {
+ dpm_table->count = 1;
+ dpm_table->dpm_levels[0].value = pptable->MinGl2clkFrequency;
+ dpm_table->dpm_levels[0].enabled = true;
+ }
+
+ /* uclk dpm table setup - discrete levels */
+ dpm_table = &dpm_context->dpm_tables.uclk_table;
+ dpm_table->clk_type = SMU_UCLK;
+ dpm_table->flags = 0;
+ if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
+ dpm_table->count = ARRAY_SIZE(pptable->UclkFrequencyTable);
+ for (i = 0; i < dpm_table->count; ++i) {
+ dpm_table->dpm_levels[i].value = pptable->UclkFrequencyTable[i];
+ dpm_table->dpm_levels[i].enabled = true;
+ }
+ } else {
+ dpm_table->count = 1;
+ dpm_table->dpm_levels[0].value = pptable->UclkFrequencyTable[0];
+ dpm_table->dpm_levels[0].enabled = true;
+ }
+
+ /* socclk dpm table setup - single boot-time value */
+ dpm_table = &dpm_context->dpm_tables.soc_table;
+ dpm_table->clk_type = SMU_SOCCLK;
+ dpm_table->flags = 0;
+ dpm_table->count = 1;
+ dpm_table->dpm_levels[0].value = pptable->SocclkFrequency;
+ dpm_table->dpm_levels[0].enabled = true;
+
+ /* vclk dpm table setup - single boot-time value */
+ dpm_table = &dpm_context->dpm_tables.vclk_table;
+ dpm_table->clk_type = SMU_VCLK;
+ dpm_table->flags = 0;
+ dpm_table->count = 1;
+ dpm_table->dpm_levels[0].value = pptable->VclkFrequency;
+ dpm_table->dpm_levels[0].enabled = true;
+
+ /* dclk dpm table setup - single boot-time value */
+ dpm_table = &dpm_context->dpm_tables.dclk_table;
+ dpm_table->clk_type = SMU_DCLK;
+ dpm_table->flags = 0;
+ dpm_table->count = 1;
+ dpm_table->dpm_levels[0].value = pptable->DclkFrequency;
+ dpm_table->dpm_levels[0].enabled = true;
+
+ return 0;
+}
+
+static int smu_v15_0_8_setup_pptable(struct smu_context *smu)
+{
+ struct smu_table_context *table_context = &smu->smu_table;
+
+ /* TODO: PPTable is not available.
+ * 1) Find an alternate way to get 'PPTable values' here.
+ * 2) Check if there is SW CTF
+ */
+ table_context->thermal_controller_type = 0;
+
+ return 0;
+}
+
+static int smu_v15_0_8_check_fw_status(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+ uint32_t mp1_fw_flags;
+
+ mp1_fw_flags = RREG32_PCIE(MP1_Public |
+ (smnMP1_FIRMWARE_FLAGS_15_0_8 & 0xffffffff));
+
+ if ((mp1_fw_flags & MP1_CRU1_MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) >>
+ MP1_CRU1_MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED__SHIFT)
+ return 0;
+
+ return -EIO;
+}
+
+static int smu_v15_0_8_get_static_metrics_table(struct smu_context *smu)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ uint32_t table_size = smu_table->tables[SMU_TABLE_SMU_METRICS].size;
+ struct smu_table *table = &smu_table->driver_table;
+ int ret;
+
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetStaticMetricsTable, NULL);
+ if (ret) {
+ dev_err(smu->adev->dev,
+ "Failed to export static metrics table!\n");
+ return ret;
+ }
+
+ amdgpu_hdp_invalidate(smu->adev, NULL);
+
+ return smu_cmn_vram_cpy(smu, smu_table->metrics_table,
+ table->cpu_addr, table_size);
+}
+
+static int smu_v15_0_8_fru_get_product_info(struct smu_context *smu,
+ StaticMetricsTable_t *static_metrics)
+{
+ struct amdgpu_fru_info *fru_info;
+ struct amdgpu_device *adev = smu->adev;
+
+ if (!adev->fru_info) {
+ adev->fru_info = kzalloc(sizeof(*adev->fru_info), GFP_KERNEL);
+ if (!adev->fru_info)
+ return -ENOMEM;
+ }
+
+ fru_info = adev->fru_info;
+ strscpy(fru_info->product_number, static_metrics->ProductInfo.ModelNumber,
+ sizeof(fru_info->product_number));
+ strscpy(fru_info->product_name, static_metrics->ProductInfo.Name,
+ sizeof(fru_info->product_name));
+ strscpy(fru_info->serial, static_metrics->ProductInfo.Serial,
+ sizeof(fru_info->serial));
+ strscpy(fru_info->manufacturer_name, static_metrics->ProductInfo.ManufacturerName,
+ sizeof(fru_info->manufacturer_name));
+ strscpy(fru_info->fru_id, static_metrics->ProductInfo.FruId,
+ sizeof(fru_info->fru_id));
+
+ return 0;
+}
+
+static void smu_v15_0_8_init_xgmi_data(struct smu_context *smu,
+ StaticMetricsTable_t *static_metrics)
+{
+ uint16_t max_speed;
+ uint8_t max_width;
+
+ max_width = (uint8_t)static_metrics->MaxXgmiWidth;
+ max_speed = (uint16_t)static_metrics->MaxXgmiBitrate;
+ amgpu_xgmi_set_max_speed_width(smu->adev, max_speed, max_width);
+}
+
+static int smu_v15_0_8_set_driver_pptable(struct smu_context *smu)
+{
+ struct smu_15_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
+ struct smu_table_context *smu_table = &smu->smu_table;
+ StaticMetricsTable_t *static_metrics = (StaticMetricsTable_t *)smu_table->metrics_table;
+ PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable;
+ int ret, i, n;
+ uint32_t table_version;
+
+ if (!pptable->init) {
+ ret = smu_v15_0_8_get_static_metrics_table(smu);
+ if (ret)
+ return ret;
+
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetMetricsVersion,
+ &table_version);
+ if (ret)
+ return ret;
+ smu_table->tables[SMU_TABLE_SMU_METRICS].version =
+ table_version;
+
+ pptable->MaxSocketPowerLimit = static_metrics->MaxSocketPowerLimit;
+ pptable->MaxGfxclkFrequency = static_metrics->MaxGfxclkFrequency;
+ pptable->MinGfxclkFrequency = static_metrics->MinGfxclkFrequency;
+ pptable->MaxFclkFrequency = static_metrics->MaxFclkFrequency;
+ pptable->MinFclkFrequency = static_metrics->MinFclkFrequency;
+ pptable->MaxGl2clkFrequency = static_metrics->MaxGl2clkFrequency;
+ pptable->MinGl2clkFrequency = static_metrics->MinGl2clkFrequency;
+
+ for (i = 0; i < ARRAY_SIZE(static_metrics->UclkFrequencyTable); ++i)
+ pptable->UclkFrequencyTable[i] = static_metrics->UclkFrequencyTable[i];
+
+ pptable->SocclkFrequency = static_metrics->SocclkFrequency;
+ pptable->LclkFrequency = static_metrics->LclkFrequency;
+ pptable->VclkFrequency = static_metrics->VclkFrequency;
+ pptable->DclkFrequency = static_metrics->DclkFrequency;
+
+ pptable->CTFLimitMID = static_metrics->CTFLimit_MID;
+ pptable->CTFLimitAID = static_metrics->CTFLimit_AID;
+ pptable->CTFLimitXCD = static_metrics->CTFLimit_XCD;
+ pptable->CTFLimitHBM = static_metrics->CTFLimit_HBM;
+ pptable->ThermalLimitMID = static_metrics->ThermalLimit_MID;
+ pptable->ThermalLimitAID = static_metrics->ThermalLimit_AID;
+ pptable->ThermalLimitXCD = static_metrics->ThermalLimit_XCD;
+ pptable->ThermalLimitHBM = static_metrics->ThermalLimit_HBM;
+
+ /* use MID0 serial number by default */
+ pptable->PublicSerialNumberMID =
+ static_metrics->PublicSerialNumber_MID[0];
+
+ amdgpu_device_set_uid(smu->adev->uid_info, AMDGPU_UID_TYPE_SOC,
+ 0, pptable->PublicSerialNumberMID);
+ pptable->PublicSerialNumberAID =
+ static_metrics->PublicSerialNumber_AID[0];
+ pptable->PublicSerialNumberXCD =
+ static_metrics->PublicSerialNumber_XCD[0];
+ n = ARRAY_SIZE(static_metrics->PublicSerialNumber_MID);
+ for (i = 0; i < n; i++) {
+ amdgpu_device_set_uid(smu->adev->uid_info, AMDGPU_UID_TYPE_MID, i,
+ static_metrics->PublicSerialNumber_MID[i]);
+ }
+ n = ARRAY_SIZE(static_metrics->PublicSerialNumber_AID);
+ for (i = 0; i < n; i++) {
+ amdgpu_device_set_uid(smu->adev->uid_info, AMDGPU_UID_TYPE_AID, i,
+ static_metrics->PublicSerialNumber_AID[i]);
+ }
+ n = ARRAY_SIZE(static_metrics->PublicSerialNumber_XCD);
+ for (i = 0; i < n; i++) {
+ amdgpu_device_set_uid(smu->adev->uid_info, AMDGPU_UID_TYPE_XCD, i,
+ static_metrics->PublicSerialNumber_XCD[i]);
+ }
+
+ ret = smu_v15_0_8_fru_get_product_info(smu, static_metrics);
+ if (ret)
+ return ret;
+ pptable->PPT1Max = static_metrics->PPT1Max;
+ pptable->PPT1Min = static_metrics->PPT1Min;
+ pptable->PPT1Default = static_metrics->PPT1Default;
+
+ if (static_metrics->pldmVersion[0] != 0xFFFFFFFF)
+ smu->adev->firmware.pldm_version =
+ static_metrics->pldmVersion[0];
+ dpm_context->board_volt = static_metrics->InputTelemetryVoltageInmV;
+ smu_v15_0_8_init_xgmi_data(smu, static_metrics);
+ pptable->init = true;
+ }
+
+ return 0;
+}
+
+static int smu_v15_0_8_set_default_dpm_table(struct smu_context *smu)
+{
+ int ret;
+
+ ret = smu_v15_0_8_set_driver_pptable(smu);
+ if (ret)
+ return ret;
+
+ ret = smu_v15_0_8_set_dpm_table(smu);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int smu_v15_0_8_irq_process(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ struct amdgpu_iv_entry *entry)
+{
+ struct smu_context *smu = adev->powerplay.pp_handle;
+ struct smu_power_context *smu_power = &smu->smu_power;
+ struct smu_15_0_power_context *power_context = smu_power->power_context;
+ uint32_t client_id = entry->client_id;
+ uint32_t ctxid = entry->src_data[0];
+ uint32_t src_id = entry->src_id;
+ uint32_t data;
+
+ if (client_id == SOC_V1_0_IH_CLIENTID_MP1) {
+ if (src_id == IH_INTERRUPT_ID_TO_DRIVER) {
+ /* ACK SMUToHost interrupt */
+ data = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL);
+ data = REG_SET_FIELD(data, MP1_SMN_IH_SW_INT_CTRL, INT_ACK, 1);
+ WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL, data);
+ /*
+ * ctxid is used to distinguish different events for SMCToHost
+ * interrupt.
+ */
+ switch (ctxid) {
+ case IH_INTERRUPT_CONTEXT_ID_THERMAL_THROTTLING:
+ /*
+ * Increment the throttle interrupt counter
+ */
+ atomic64_inc(&smu->throttle_int_counter);
+
+ if (!atomic_read(&adev->throttling_logging_enabled))
+ return 0;
+
+ /* This uses the new method which fixes the
+ * incorrect throttling status reporting
+ * through metrics table. For older FWs,
+ * it will be ignored.
+ */
+ if (__ratelimit(&adev->throttling_logging_rs)) {
+ atomic_set(
+ &power_context->throttle_status,
+ entry->src_data[1]);
+ schedule_work(&smu->throttling_logging_work);
+ }
+ break;
+ default:
+ dev_dbg(adev->dev, "Unhandled context id %d from client:%d!\n",
+ ctxid, client_id);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int smu_v15_0_8_set_irq_state(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ unsigned type,
+ enum amdgpu_interrupt_state state)
+{
+ uint32_t val = 0;
+
+ switch (state) {
+ case AMDGPU_IRQ_STATE_DISABLE:
+ /* For MP1 SW irqs */
+ val = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL);
+ val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT_CTRL, INT_MASK, 1);
+ WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL, val);
+
+ break;
+ case AMDGPU_IRQ_STATE_ENABLE:
+ /* For MP1 SW irqs */
+ val = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT);
+ val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT, ID, 0xFE);
+ val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT, VALID, 0);
+ WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT, val);
+
+ val = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL);
+ val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT_CTRL, INT_MASK, 0);
+ WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL, val);
+
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static const struct amdgpu_irq_src_funcs smu_v15_0_8_irq_funcs = {
+ .set = smu_v15_0_8_set_irq_state,
+ .process = smu_v15_0_8_irq_process,
+};
+
+static int smu_v15_0_8_register_irq_handler(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+ struct amdgpu_irq_src *irq_src = &smu->irq_source;
+ int ret = 0;
+
+ if (amdgpu_sriov_vf(adev))
+ return 0;
+
+ irq_src->num_types = 1;
+ irq_src->funcs = &smu_v15_0_8_irq_funcs;
+
+ ret = amdgpu_irq_add_id(adev, SOC_V1_0_IH_CLIENTID_MP1,
+ IH_INTERRUPT_ID_TO_DRIVER,
+ irq_src);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+static int smu_v15_0_8_notify_unload(struct smu_context *smu)
+{
+ if (amdgpu_in_reset(smu->adev))
+ return 0;
+
+ dev_dbg(smu->adev->dev, "Notify PMFW about driver unload");
+ /* Ignore return, just intimate FW that driver is not going to be there */
+ smu_cmn_send_smc_msg(smu, SMU_MSG_PrepareMp1ForUnload, NULL);
+
+ return 0;
+}
+
+
+static int smu_v15_0_8_system_features_control(struct smu_context *smu,
+ bool enable)
+{
+ struct amdgpu_device *adev = smu->adev;
+ int ret = 0;
+
+ if (amdgpu_sriov_vf(adev))
+ return 0;
+
+ if (enable)
+ ret = smu_v15_0_system_features_control(smu, enable);
+ else
+ smu_v15_0_8_notify_unload(smu);
+
+ return ret;
+}
+
+/**
+ * smu_v15_0_8_get_enabled_mask - Get enabled SMU features (128-bit)
+ * @smu: SMU context
+ * @feature_mask: feature mask structure
+ *
+ * SMU 15 returns all 128 feature bits in a single message via out_args[0..3].
+ * For backward compatibility, this function returns only the first 64 bits.
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+static int smu_v15_0_8_get_enabled_mask(struct smu_context *smu,
+ struct smu_feature_bits *feature_mask)
+{
+ uint32_t out[2];
+ int ret;
+
+ if (!feature_mask)
+ return -EINVAL;
+
+ ret = smu_cmn_send_smc_msg_with_params(smu,
+ SMU_MSG_GetEnabledSmuFeatures,
+ NULL, 0,
+ out, ARRAY_SIZE(out));
+
+ if (ret)
+ return ret;
+
+ smu_feature_bits_from_arr32(feature_mask, out, SMU_FEATURE_NUM_DEFAULT);
+
+ return 0;
+}
+
+static bool smu_v15_0_8_is_dpm_running(struct smu_context *smu)
+{
+ int ret = 0;
+ struct smu_feature_bits feature_enabled;
+
+ ret = smu_v15_0_8_get_enabled_mask(smu, &feature_enabled);
+ if (ret)
+ return false;
+
+ return smu_feature_bits_test_mask(&feature_enabled,
+ smu_v15_0_8_dpm_features.bits);
+}
+
+static ssize_t smu_v15_0_8_get_pm_metrics(struct smu_context *smu,
+ void *metrics, size_t max_size)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct amdgpu_pm_metrics *pm_metrics = (struct amdgpu_pm_metrics *)metrics;
+ uint32_t table_version = smu_table->tables[SMU_TABLE_SMU_METRICS].version;
+ uint32_t table_size = smu_table->tables[SMU_TABLE_SMU_METRICS].size;
+ uint32_t pmfw_version;
+ int ret;
+
+ if (!pm_metrics || !max_size)
+ return -EINVAL;
+
+ if (max_size < (table_size + sizeof(pm_metrics->common_header)))
+ return -EOVERFLOW;
+
+ /* Don't use cached metrics data */
+ ret = smu_v15_0_8_get_metrics_table_internal(smu, 0, pm_metrics->data);
+ if (ret)
+ return ret;
+
+ smu_cmn_get_smc_version(smu, NULL, &pmfw_version);
+ memset(&pm_metrics->common_header, 0, sizeof(pm_metrics->common_header));
+ pm_metrics->common_header.mp1_ip_discovery_version =
+ amdgpu_ip_version(smu->adev, MP1_HWIP, 0);
+ pm_metrics->common_header.pmfw_version = pmfw_version;
+ pm_metrics->common_header.pmmetrics_version = table_version;
+ pm_metrics->common_header.structure_size =
+ sizeof(pm_metrics->common_header) + table_size;
+
+ return pm_metrics->common_header.structure_size;
+}
+
+static int smu_v15_0_8_mode2_reset(struct smu_context *smu)
+{
+ struct smu_msg_ctl *ctl = &smu->msg_ctl;
+ struct amdgpu_device *adev = smu->adev;
+ int timeout = 10;
+ int ret = 0;
+
+ mutex_lock(&ctl->lock);
+
+ ret = smu_msg_send_async_locked(ctl, SMU_MSG_GfxDeviceDriverReset,
+ SMU_RESET_MODE_2);
+
+ if (ret)
+ goto out;
+
+ /* Reset takes a bit longer, wait for 200ms. */
+ msleep(200);
+
+ dev_dbg(adev->dev, "wait for reset ack\n");
+ do {
+ ret = smu_msg_wait_response(ctl, 0);
+ /* Wait a bit more time for getting ACK */
+ if (ret == -ETIME) {
+ --timeout;
+ usleep_range(500, 1000);
+ continue;
+ }
+
+ if (ret)
+ goto out;
+
+ } while (ret == -ETIME && timeout);
+
+out:
+ mutex_unlock(&ctl->lock);
+
+ if (ret)
+ dev_err(adev->dev, "failed to send mode2 reset, error code %d",
+ ret);
+
+ return ret;
+}
+
+static bool smu_v15_0_8_is_temp_metrics_supported(struct smu_context *smu,
+ enum smu_temp_metric_type type)
+{
+ switch (type) {
+ case SMU_TEMP_METRIC_BASEBOARD:
+ if (smu->adev->gmc.xgmi.physical_node_id == 0)
+ return true;
+ return false;
+ case SMU_TEMP_METRIC_GPUBOARD:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static void smu_v15_0_8_fill_baseboard_temp_metrics(
+ struct smu_v15_0_8_baseboard_temp_metrics *baseboard_temp_metrics,
+ const SystemMetricsTable_t *metrics)
+{
+ baseboard_temp_metrics->accumulation_counter = metrics->AccumulationCounter;
+ baseboard_temp_metrics->label_version = metrics->LabelVersion;
+ baseboard_temp_metrics->node_id = metrics->NodeIdentifier;
+
+ baseboard_temp_metrics->system_temp_ubb_fpga =
+ metrics->SystemTemperatures[SYSTEM_TEMP_UBB_FPGA];
+ baseboard_temp_metrics->system_temp_ubb_front =
+ metrics->SystemTemperatures[SYSTEM_TEMP_UBB_FRONT];
+ baseboard_temp_metrics->system_temp_ubb_back =
+ metrics->SystemTemperatures[SYSTEM_TEMP_UBB_BACK];
+ baseboard_temp_metrics->system_temp_ubb_oam7 =
+ metrics->SystemTemperatures[SYSTEM_TEMP_UBB_OAM7];
+ baseboard_temp_metrics->system_temp_ubb_ibc =
+ metrics->SystemTemperatures[SYSTEM_TEMP_UBB_IBC];
+ baseboard_temp_metrics->system_temp_ubb_ufpga =
+ metrics->SystemTemperatures[SYSTEM_TEMP_UBB_UFPGA];
+ baseboard_temp_metrics->system_temp_ubb_oam1 =
+ metrics->SystemTemperatures[SYSTEM_TEMP_UBB_OAM1];
+ baseboard_temp_metrics->system_temp_oam_0_1_hsc =
+ metrics->SystemTemperatures[SYSTEM_TEMP_OAM_0_1_HSC];
+ baseboard_temp_metrics->system_temp_oam_2_3_hsc =
+ metrics->SystemTemperatures[SYSTEM_TEMP_OAM_2_3_HSC];
+ baseboard_temp_metrics->system_temp_oam_4_5_hsc =
+ metrics->SystemTemperatures[SYSTEM_TEMP_OAM_4_5_HSC];
+ baseboard_temp_metrics->system_temp_oam_6_7_hsc =
+ metrics->SystemTemperatures[SYSTEM_TEMP_OAM_6_7_HSC];
+ baseboard_temp_metrics->system_temp_ubb_fpga_0v72_vr =
+ metrics->SystemTemperatures[SYSTEM_TEMP_UBB_FPGA_0V72_VR];
+ baseboard_temp_metrics->system_temp_ubb_fpga_3v3_vr =
+ metrics->SystemTemperatures[SYSTEM_TEMP_UBB_FPGA_3V3_VR];
+ baseboard_temp_metrics->system_temp_retimer_0_1_2_3_1v2_vr =
+ metrics->SystemTemperatures[SYSTEM_TEMP_RETIMER_0_1_2_3_1V2_VR];
+ baseboard_temp_metrics->system_temp_retimer_4_5_6_7_1v2_vr =
+ metrics->SystemTemperatures[SYSTEM_TEMP_RETIMER_4_5_6_7_1V2_VR];
+ baseboard_temp_metrics->system_temp_retimer_0_1_0v9_vr =
+ metrics->SystemTemperatures[SYSTEM_TEMP_RETIMER_0_1_0V9_VR];
+ baseboard_temp_metrics->system_temp_retimer_4_5_0v9_vr =
+ metrics->SystemTemperatures[SYSTEM_TEMP_RETIMER_4_5_0V9_VR];
+ baseboard_temp_metrics->system_temp_retimer_2_3_0v9_vr =
+ metrics->SystemTemperatures[SYSTEM_TEMP_RETIMER_2_3_0V9_VR];
+ baseboard_temp_metrics->system_temp_retimer_6_7_0v9_vr =
+ metrics->SystemTemperatures[SYSTEM_TEMP_RETIMER_6_7_0V9_VR];
+ baseboard_temp_metrics->system_temp_oam_0_1_2_3_3v3_vr =
+ metrics->SystemTemperatures[SYSTEM_TEMP_OAM_0_1_2_3_3V3_VR];
+ baseboard_temp_metrics->system_temp_oam_4_5_6_7_3v3_vr =
+ metrics->SystemTemperatures[SYSTEM_TEMP_OAM_4_5_6_7_3V3_VR];
+ baseboard_temp_metrics->system_temp_ibc_hsc =
+ metrics->SystemTemperatures[SYSTEM_TEMP_IBC_HSC];
+ baseboard_temp_metrics->system_temp_ibc =
+ metrics->SystemTemperatures[SYSTEM_TEMP_IBC];
+}
+
+static void smu_v15_0_8_fill_gpuboard_temp_metrics(
+ struct smu_v15_0_8_gpuboard_temp_metrics *gpuboard_temp_metrics,
+ const SystemMetricsTable_t *metrics)
+{
+ gpuboard_temp_metrics->accumulation_counter = metrics->AccumulationCounter;
+ gpuboard_temp_metrics->label_version = metrics->LabelVersion;
+ gpuboard_temp_metrics->node_id = metrics->NodeIdentifier;
+
+ gpuboard_temp_metrics->node_temp_retimer =
+ metrics->NodeTemperatures[NODE_TEMP_RETIMER];
+ gpuboard_temp_metrics->node_temp_ibc =
+ metrics->NodeTemperatures[NODE_TEMP_IBC_TEMP];
+ gpuboard_temp_metrics->node_temp_ibc_2 =
+ metrics->NodeTemperatures[NODE_TEMP_IBC_2_TEMP];
+ gpuboard_temp_metrics->node_temp_vdd18_vr =
+ metrics->NodeTemperatures[NODE_TEMP_VDD18_VR_TEMP];
+ gpuboard_temp_metrics->node_temp_04_hbm_b_vr =
+ metrics->NodeTemperatures[NODE_TEMP_04_HBM_B_VR_TEMP];
+ gpuboard_temp_metrics->node_temp_04_hbm_d_vr =
+ metrics->NodeTemperatures[NODE_TEMP_04_HBM_D_VR_TEMP];
+
+ gpuboard_temp_metrics->vr_temp_vddcr_socio_a =
+ metrics->VrTemperatures[SVI_PLANE_VDDCR_SOCIO_A_TEMP];
+ gpuboard_temp_metrics->vr_temp_vddcr_socio_c =
+ metrics->VrTemperatures[SVI_PLANE_VDDCR_SOCIO_C_TEMP];
+ gpuboard_temp_metrics->vr_temp_vddcr_x0 =
+ metrics->VrTemperatures[SVI_PLANE_VDDCR_X0_TEMP];
+ gpuboard_temp_metrics->vr_temp_vddcr_x1 =
+ metrics->VrTemperatures[SVI_PLANE_VDDCR_X1_TEMP];
+ gpuboard_temp_metrics->vr_temp_vddio_hbm_b =
+ metrics->VrTemperatures[SVI_PLANE_VDDIO_HBM_B_TEMP];
+ gpuboard_temp_metrics->vr_temp_vddio_hbm_d =
+ metrics->VrTemperatures[SVI_PLANE_VDDIO_HBM_D_TEMP];
+ gpuboard_temp_metrics->vr_temp_vddio_04_hbm_b =
+ metrics->VrTemperatures[SVI_PLANE_VDDIO_04_HBM_B_TEMP];
+ gpuboard_temp_metrics->vr_temp_vddio_04_hbm_d =
+ metrics->VrTemperatures[SVI_PLANE_VDDIO_04_HBM_D_TEMP];
+ gpuboard_temp_metrics->vr_temp_vddcr_hbm_b =
+ metrics->VrTemperatures[SVI_PLANE_VDDCR_HBM_B_TEMP];
+ gpuboard_temp_metrics->vr_temp_vddcr_hbm_d =
+ metrics->VrTemperatures[SVI_PLANE_VDDCR_HBM_D_TEMP];
+ gpuboard_temp_metrics->vr_temp_vddcr_075_hbm_b =
+ metrics->VrTemperatures[SVI_PLANE_VDDCR_075_HBM_B_TEMP];
+ gpuboard_temp_metrics->vr_temp_vddcr_075_hbm_d =
+ metrics->VrTemperatures[SVI_PLANE_VDDCR_075_HBM_D_TEMP];
+ gpuboard_temp_metrics->vr_temp_vddio_11_gta_a =
+ metrics->VrTemperatures[SVI_PLANE_VDDIO_11_GTA_A_TEMP];
+ gpuboard_temp_metrics->vr_temp_vddio_11_gta_c =
+ metrics->VrTemperatures[SVI_PLANE_VDDIO_11_GTA_C_TEMP];
+ gpuboard_temp_metrics->vr_temp_vddan_075_gta_a =
+ metrics->VrTemperatures[SVI_PLANE_VDDAN_075_GTA_A_TEMP];
+ gpuboard_temp_metrics->vr_temp_vddan_075_gta_c =
+ metrics->VrTemperatures[SVI_PLANE_VDDAN_075_GTA_C_TEMP];
+ gpuboard_temp_metrics->vr_temp_vddcr_075_ucie =
+ metrics->VrTemperatures[SVI_PLANE_VDDCR_075_UCIE_TEMP];
+ gpuboard_temp_metrics->vr_temp_vddio_065_ucieaa =
+ metrics->VrTemperatures[SVI_PLANE_VDDIO_065_UCIEAA_TEMP];
+ gpuboard_temp_metrics->vr_temp_vddio_065_ucieam_a =
+ metrics->VrTemperatures[SVI_PLANE_VDDIO_065_UCIEAM_A_TEMP];
+ gpuboard_temp_metrics->vr_temp_vddio_065_ucieam_c =
+ metrics->VrTemperatures[SVI_PLANE_VDDIO_065_UCIEAM_C_TEMP];
+ gpuboard_temp_metrics->vr_temp_vddan_075 =
+ metrics->VrTemperatures[SVI_PLANE_VDDAN_075_TEMP];
+}
+
+static ssize_t smu_v15_0_8_get_temp_metrics(struct smu_context *smu,
+ enum smu_temp_metric_type type,
+ void *table)
+{
+ struct smu_v15_0_8_baseboard_temp_metrics *baseboard_temp_metrics;
+ struct smu_v15_0_8_gpuboard_temp_metrics *gpuboard_temp_metrics;
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_table *tables = smu_table->tables;
+ SystemMetricsTable_t *metrics;
+ struct smu_table *sys_table;
+ int ret;
+
+ ret = smu_v15_0_8_get_system_metrics_table(smu);
+ if (ret)
+ return ret;
+
+ sys_table = &tables[SMU_TABLE_PMFW_SYSTEM_METRICS];
+ metrics = (SystemMetricsTable_t *)sys_table->cache.buffer;
+
+ switch (type) {
+ case SMU_TEMP_METRIC_GPUBOARD:
+ gpuboard_temp_metrics =
+ (struct smu_v15_0_8_gpuboard_temp_metrics *)
+ smu_driver_table_ptr(smu, SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS);
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS);
+ smu_v15_0_8_fill_gpuboard_temp_metrics(gpuboard_temp_metrics,
+ metrics);
+ memcpy(table, gpuboard_temp_metrics, sizeof(*gpuboard_temp_metrics));
+ return sizeof(*gpuboard_temp_metrics);
+ case SMU_TEMP_METRIC_BASEBOARD:
+ baseboard_temp_metrics =
+ (struct smu_v15_0_8_baseboard_temp_metrics *)
+ smu_driver_table_ptr(smu, SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS);
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS);
+ smu_v15_0_8_fill_baseboard_temp_metrics(baseboard_temp_metrics,
+ metrics);
+ memcpy(table, baseboard_temp_metrics, sizeof(*baseboard_temp_metrics));
+ return sizeof(*baseboard_temp_metrics);
+ default:
+ return -EINVAL;
+ }
+}
+
+static ssize_t smu_v15_0_8_get_xcp_metrics(struct smu_context *smu, int xcp_id,
+ void *table)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ const u8 num_jpeg_rings = NUM_JPEG_RINGS_FW;
+ struct smu_v15_0_8_partition_metrics *xcp_metrics;
+ MetricsTable_t *metrics;
+ struct amdgpu_device *adev = smu->adev;
+ int ret, inst, i, j, k, idx;
+ struct amdgpu_xcp *xcp;
+ u32 inst_mask;
+
+ if (!table)
+ return sizeof(*xcp_metrics);
+
+ for_each_xcp(adev->xcp_mgr, xcp, i) {
+ if (xcp->id == xcp_id)
+ break;
+ }
+ if (i == adev->xcp_mgr->num_xcps)
+ return -EINVAL;
+
+ xcp_metrics = (struct smu_v15_0_8_partition_metrics *)table;
+ smu_v15_0_8_partition_metrics_init(xcp_metrics, 1, 1);
+
+ ret = smu_v15_0_8_get_metrics_table_internal(smu, 1, NULL);
+ if (ret)
+ return ret;
+
+ metrics = (MetricsTable_t *)smu_table->metrics_table;
+
+ amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_VCN, &inst_mask);
+ idx = 0;
+ for_each_inst(k, inst_mask) {
+ /* Both JPEG and VCN has same instances */
+ inst = GET_INST(VCN, k);
+ for (j = 0; j < num_jpeg_rings; ++j) {
+ xcp_metrics->jpeg_busy[(idx * num_jpeg_rings) + j] =
+ SMUQ10_ROUND(metrics->JpegBusy[(inst * num_jpeg_rings) + j]);
+ }
+ xcp_metrics->vcn_busy[idx] =
+ SMUQ10_ROUND(metrics->VcnBusy[inst]);
+
+ xcp_metrics->current_vclk[idx] = SMUQ10_ROUND(metrics->VclkFrequency[inst]);
+ xcp_metrics->current_dclk[idx] = SMUQ10_ROUND(metrics->DclkFrequency[inst]);
+
+ idx++;
+ }
+
+ amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_GFX, &inst_mask);
+ idx = 0;
+ for_each_inst(k, inst_mask) {
+ inst = GET_INST(GC, k);
+ xcp_metrics->current_gfxclk[idx] =
+ SMUQ10_ROUND(metrics->GfxclkFrequency[inst]);
+
+ xcp_metrics->gfx_busy_inst[idx] = SMUQ10_ROUND(metrics->GfxBusy[inst]);
+ xcp_metrics->gfx_busy_acc[idx] = SMUQ10_ROUND(metrics->GfxBusyAcc[inst]);
+ xcp_metrics->gfx_below_host_limit_ppt_acc[idx] =
+ SMUQ10_ROUND(metrics->GfxclkBelowHostLimitPptAcc[inst]);
+ xcp_metrics->gfx_below_host_limit_thm_acc[idx] =
+ SMUQ10_ROUND(metrics->GfxclkBelowHostLimitThmAcc[inst]);
+ xcp_metrics->gfx_low_utilization_acc[idx] =
+ SMUQ10_ROUND(metrics->GfxclkLowUtilizationAcc[inst]);
+ xcp_metrics->gfx_below_host_limit_total_acc[idx] =
+ SMUQ10_ROUND(metrics->GfxclkBelowHostLimitTotalAcc[inst]);
+ idx++;
+ }
+
+ xcp_metrics->accumulation_counter = metrics->AccumulationCounter;
+ xcp_metrics->firmware_timestamp = metrics->Timestamp;
+
+ return sizeof(*xcp_metrics);
+}
+
+static ssize_t smu_v15_0_8_get_gpu_metrics(struct smu_context *smu, void **table)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_v15_0_8_gpu_metrics *gpu_metrics;
+ struct amdgpu_device *adev = smu->adev;
+ int ret = 0, xcc_id, inst, i, j, idx;
+ uint32_t aid_mask = adev->aid_mask;
+ uint32_t mid_mask = adev->aid_mask;
+ MetricsTable_t *metrics;
+
+ ret = smu_v15_0_8_get_metrics_table_internal(smu, 1, NULL);
+ if (ret)
+ return ret;
+
+ metrics = (MetricsTable_t *)smu_table->metrics_table;
+ gpu_metrics = (struct smu_v15_0_8_gpu_metrics *)smu_driver_table_ptr(smu,
+ SMU_DRIVER_TABLE_GPU_METRICS);
+
+ gpu_metrics->system_clock_counter = ktime_get_boottime_ns();
+
+ gpu_metrics->temperature_hotspot = SMUQ10_ROUND(metrics->MaxSocketTemperature);
+
+ /* Per-HBM stack temperatures */
+ if (adev->umc.active_mask) {
+ u64 mask = adev->umc.active_mask;
+ int out_idx = 0;
+ u16 max_hbm_temp = 0;
+ int stack_idx;
+
+ if (unlikely(hweight64(mask) / 4 > SMU_15_0_8_MAX_HBM_STACKS)) {
+ dev_warn(adev->dev, "Invalid umc mask %lld\n", mask);
+ } else {
+ for_each_hbm_stack(stack_idx, mask) {
+ u16 temp;
+
+ if (!hbm_stack_mask_valid(mask))
+ continue;
+ temp = SMUQ10_ROUND(metrics->HbmTemperature[stack_idx]);
+ gpu_metrics->temperature_hbm[out_idx++] = temp;
+ if (temp > max_hbm_temp)
+ max_hbm_temp = temp;
+ }
+ gpu_metrics->temperature_mem = max_hbm_temp;
+ }
+ }
+
+ /* Reports max temperature of all voltage rails */
+ gpu_metrics->temperature_vrsoc = SMUQ10_ROUND(metrics->MaxVrTemperature);
+ /* MID, AID, XCD temperatures */
+ idx = 0;
+ for_each_inst(i, mid_mask) {
+ gpu_metrics->temperature_mid[idx] = SMUQ10_ROUND(metrics->MidTemperature[i]);
+ idx++;
+ }
+
+ idx = 0;
+ for_each_inst(i, aid_mask) {
+ gpu_metrics->temperature_aid[idx] = SMUQ10_ROUND(metrics->AidTemperature[i]);
+ idx++;
+ }
+
+ for (i = 0; i < NUM_XCC(adev->gfx.xcc_mask); ++i) {
+ xcc_id = GET_INST(GC, i);
+ if (xcc_id >= 0)
+ gpu_metrics->temperature_xcd[i] = SMUQ10_ROUND(metrics->XcdTemperature[xcc_id]);
+ }
+ /* Power */
+ gpu_metrics->curr_socket_power = SMUQ10_ROUND(metrics->SocketPower);
+
+ gpu_metrics->average_gfx_activity = SMUQ10_ROUND(metrics->SocketGfxBusy);
+ gpu_metrics->average_umc_activity = SMUQ10_ROUND(metrics->DramBandwidthUtilization);
+ gpu_metrics->mem_max_bandwidth = SMUQ10_ROUND(metrics->MaxDramBandwidth);
+
+ /* Energy counter reported in 15.259uJ (2^-16) units */
+ gpu_metrics->energy_accumulator = metrics->SocketEnergyAcc;
+
+ for (i = 0; i < NUM_XCC(adev->gfx.xcc_mask); ++i) {
+ xcc_id = GET_INST(GC, i);
+ if (xcc_id >= 0) {
+ gpu_metrics->current_gfxclk[i] =
+ SMUQ10_ROUND(metrics->GfxclkFrequency[xcc_id]);
+ }
+ }
+
+ /* Per-MID clocks */
+ idx = 0;
+ for_each_inst(i, mid_mask) {
+ gpu_metrics->current_socclk[idx] = SMUQ10_ROUND(metrics->SocclkFrequency[i]);
+ idx++;
+ }
+
+ /* Per-VCN clocks */
+ for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
+ inst = GET_INST(VCN, i);
+ if (inst >= 0) {
+ gpu_metrics->current_vclk0[i] = SMUQ10_ROUND(metrics->VclkFrequency[inst]);
+ gpu_metrics->current_dclk0[i] = SMUQ10_ROUND(metrics->DclkFrequency[inst]);
+ }
+ }
+
+ /* Per-AID clocks */
+ idx = 0;
+ for_each_inst(i, aid_mask) {
+ gpu_metrics->current_uclk[idx] = SMUQ10_ROUND(metrics->UclkFrequency[i]);
+ idx++;
+ }
+
+ /* Total accumulated cycle counter */
+ gpu_metrics->accumulation_counter = metrics->AccumulationCounter;
+
+ /* Accumulated throttler residencies */
+ gpu_metrics->prochot_residency_acc = metrics->ProchotResidencyAcc;
+ gpu_metrics->ppt_residency_acc = metrics->PptResidencyAcc;
+ gpu_metrics->socket_thm_residency_acc = metrics->SocketThmResidencyAcc;
+ gpu_metrics->vr_thm_residency_acc = metrics->VrThmResidencyAcc;
+ gpu_metrics->hbm_thm_residency_acc = metrics->HbmThmResidencyAcc;
+
+ gpu_metrics->gfx_activity_acc = SMUQ10_ROUND(metrics->SocketGfxBusyAcc);
+ gpu_metrics->mem_activity_acc = SMUQ10_ROUND(metrics->DramBandwidthUtilizationAcc);
+
+ for (i = 0; i < NUM_XGMI_LINKS; i++) {
+ j = amdgpu_xgmi_get_ext_link(adev, i);
+ if (j < 0 || j >= NUM_XGMI_LINKS)
+ continue;
+ ret = amdgpu_get_xgmi_link_status(adev, i);
+ if (ret >= 0)
+ gpu_metrics->xgmi_link_status[j] = ret;
+ }
+
+ gpu_metrics->xgmi_read_data_acc = SMUQ10_ROUND(metrics->XgmiReadBandwidthAcc);
+ gpu_metrics->xgmi_write_data_acc = SMUQ10_ROUND(metrics->XgmiWriteBandwidthAcc);
+
+ for (i = 0; i < NUM_XCC(adev->gfx.xcc_mask); ++i) {
+ inst = GET_INST(GC, i);
+ gpu_metrics->gfx_busy_inst[i] = SMUQ10_ROUND(metrics->GfxBusy[inst]);
+ gpu_metrics->gfx_busy_acc[i] = SMUQ10_ROUND(metrics->GfxBusyAcc[inst]);
+ gpu_metrics->gfx_below_host_limit_ppt_acc[i] =
+ SMUQ10_ROUND(metrics->GfxclkBelowHostLimitPptAcc[inst]);
+ gpu_metrics->gfx_below_host_limit_thm_acc[i] =
+ SMUQ10_ROUND(metrics->GfxclkBelowHostLimitThmAcc[inst]);
+ gpu_metrics->gfx_low_utilization_acc[i] =
+ SMUQ10_ROUND(metrics->GfxclkLowUtilizationAcc[inst]);
+ gpu_metrics->gfx_below_host_limit_total_acc[i] =
+ SMUQ10_ROUND(metrics->GfxclkBelowHostLimitTotalAcc[inst]);
+ }
+
+ gpu_metrics->xgmi_link_width = metrics->XgmiWidth;
+ gpu_metrics->xgmi_link_speed = metrics->XgmiBitrate;
+
+ gpu_metrics->firmware_timestamp = metrics->Timestamp;
+
+ *table = gpu_metrics;
+
+ smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS);
+
+ return sizeof(*gpu_metrics);
+}
+
+static void smu_v15_0_8_get_unique_id(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+ struct smu_table_context *smu_table = &smu->smu_table;
+ PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable;
+
+ adev->unique_id = pptable->PublicSerialNumberMID;
+}
+
+static int smu_v15_0_8_get_power_limit(struct smu_context *smu,
+ uint32_t *current_power_limit,
+ uint32_t *default_power_limit,
+ uint32_t *max_power_limit,
+ uint32_t *min_power_limit)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable;
+ uint32_t power_limit = 0;
+ int ret;
+
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetPptLimit, &power_limit);
+ if (ret) {
+ dev_err(smu->adev->dev, "Couldn't get PPT limit");
+ return -EINVAL;
+ }
+
+ if (current_power_limit)
+ *current_power_limit = power_limit;
+
+ if (default_power_limit)
+ *default_power_limit = pptable->MaxSocketPowerLimit;
+
+ if (max_power_limit)
+ *max_power_limit = pptable->MaxSocketPowerLimit;
+
+ if (min_power_limit)
+ *min_power_limit = 0;
+
+ return 0;
+}
+
+static int smu_v15_0_8_populate_umd_state_clk(struct smu_context *smu)
+{
+ struct smu_15_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
+ struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table;
+ struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table;
+ struct smu_umd_pstate_table *pstate_table = &smu->pstate_table;
+
+ pstate_table->gfxclk_pstate.curr.min = SMU_DPM_TABLE_MIN(gfx_table);
+ pstate_table->gfxclk_pstate.curr.max = SMU_DPM_TABLE_MAX(gfx_table);
+
+ pstate_table->uclk_pstate.curr.min = SMU_DPM_TABLE_MIN(mem_table);
+ pstate_table->uclk_pstate.curr.max = SMU_DPM_TABLE_MAX(mem_table);
+ return 0;
+}
+
+static int smu_v15_0_8_set_gfx_soft_freq_limited_range(struct smu_context *smu,
+ uint32_t min,
+ uint32_t max)
+{
+ int ret;
+
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk,
+ max & 0xffff, NULL);
+ if (ret)
+ return ret;
+
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMinGfxclk,
+ min & 0xffff, NULL);
+
+ return ret;
+}
+
+static int smu_v15_0_8_set_performance_level(struct smu_context *smu,
+ enum amd_dpm_forced_level level)
+{
+ struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
+ struct smu_15_0_dpm_context *dpm_context = smu_dpm->dpm_context;
+ struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table;
+ struct smu_dpm_table *uclk_table = &dpm_context->dpm_tables.uclk_table;
+ struct smu_umd_pstate_table *pstate_table = &smu->pstate_table;
+ int ret;
+
+ switch (level) {
+ case AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM:
+ /* Determinism not supported on SMU v15.0.8 */
+ ret = -EOPNOTSUPP;
+ break;
+
+ case AMD_DPM_FORCED_LEVEL_AUTO:
+ /* Restore GFXCLK to default range */
+ if ((SMU_DPM_TABLE_MIN(gfx_table) !=
+ pstate_table->gfxclk_pstate.curr.min) ||
+ (SMU_DPM_TABLE_MAX(gfx_table) !=
+ pstate_table->gfxclk_pstate.curr.max)) {
+ ret = smu_v15_0_8_set_gfx_soft_freq_limited_range(
+ smu, SMU_DPM_TABLE_MIN(gfx_table),
+ SMU_DPM_TABLE_MAX(gfx_table));
+ if (ret)
+ goto out;
+
+ pstate_table->gfxclk_pstate.curr.min =
+ SMU_DPM_TABLE_MIN(gfx_table);
+ pstate_table->gfxclk_pstate.curr.max =
+ SMU_DPM_TABLE_MAX(gfx_table);
+ }
+
+ /* Restore UCLK to default max */
+ if (SMU_DPM_TABLE_MAX(uclk_table) !=
+ pstate_table->uclk_pstate.curr.max) {
+ /* Min UCLK is not expected to be changed */
+ ret = smu_v15_0_set_soft_freq_limited_range(smu,
+ SMU_UCLK, 0,
+ SMU_DPM_TABLE_MAX(uclk_table),
+ false);
+ if (ret)
+ goto out;
+
+ pstate_table->uclk_pstate.curr.max =
+ SMU_DPM_TABLE_MAX(uclk_table);
+ }
+
+ if (ret)
+ goto out;
+
+ smu_cmn_reset_custom_level(smu);
+
+ break;
+ case AMD_DPM_FORCED_LEVEL_MANUAL:
+ ret = 0;
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+out:
+ return ret;
+}
+
+static int smu_v15_0_8_set_soft_freq_limited_range(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t min, uint32_t max,
+ bool automatic)
+{
+ struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
+ struct smu_umd_pstate_table *pstate_table = &smu->pstate_table;
+ int ret = 0;
+
+ if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK &&
+ clk_type != SMU_UCLK)
+ return -EINVAL;
+
+ if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
+ return -EINVAL;
+
+ if (min >= max) {
+ dev_err(smu->adev->dev,
+ "Minimum clk should be less than the maximum allowed clock\n");
+ return -EINVAL;
+ }
+
+ if (clk_type == SMU_GFXCLK || clk_type == SMU_SCLK) {
+ if ((min == pstate_table->gfxclk_pstate.curr.min) &&
+ (max == pstate_table->gfxclk_pstate.curr.max))
+ return 0;
+
+ ret = smu_v15_0_8_set_gfx_soft_freq_limited_range(smu, min,
+ max);
+ if (!ret) {
+ pstate_table->gfxclk_pstate.curr.min = min;
+ pstate_table->gfxclk_pstate.curr.max = max;
+ }
+ }
+
+ if (clk_type == SMU_UCLK) {
+ if (max == pstate_table->uclk_pstate.curr.max)
+ return 0;
+
+ ret = smu_v15_0_set_soft_freq_limited_range(smu, SMU_UCLK, 0,
+ max, false);
+ if (!ret)
+ pstate_table->uclk_pstate.curr.max = max;
+ }
+
+ return ret;
+}
+
+static int smu_v15_0_8_od_edit_dpm_table(struct smu_context *smu,
+ enum PP_OD_DPM_TABLE_COMMAND type,
+ long input[], uint32_t size)
+{
+ struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
+ struct smu_umd_pstate_table *pstate_table = &smu->pstate_table;
+ struct smu_15_0_dpm_context *dpm_context = smu_dpm->dpm_context;
+ uint32_t min_clk, max_clk;
+ int ret;
+
+ /* Only allowed in manual mode */
+ if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
+ return -EINVAL;
+
+ switch (type) {
+ case PP_OD_EDIT_SCLK_VDDC_TABLE:
+ if (size != 2) {
+ dev_err(smu->adev->dev,
+ "Input parameter number not correct\n");
+ return -EINVAL;
+ }
+ min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.gfx_table);
+ max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.gfx_table);
+ if (input[0] == 0) {
+ if (input[1] < min_clk) {
+ dev_warn(smu->adev->dev,
+ "Minimum GFX clk (%ld) MHz specified is less than the minimum allowed (%d) MHz\n",
+ input[1], min_clk);
+ pstate_table->gfxclk_pstate.custom.min =
+ pstate_table->gfxclk_pstate.curr.min;
+ return -EINVAL;
+ }
+
+ pstate_table->gfxclk_pstate.custom.min = input[1];
+ } else if (input[0] == 1) {
+ if (input[1] > max_clk) {
+ dev_warn(smu->adev->dev,
+ "Maximum GFX clk (%ld) MHz specified is greater than the maximum allowed (%d) MHz\n",
+ input[1], max_clk);
+ pstate_table->gfxclk_pstate.custom.max =
+ pstate_table->gfxclk_pstate.curr.max;
+ return -EINVAL;
+ }
+
+ pstate_table->gfxclk_pstate.custom.max = input[1];
+ } else {
+ return -EINVAL;
+ }
+ break;
+ case PP_OD_EDIT_MCLK_VDDC_TABLE:
+ if (size != 2) {
+ dev_err(smu->adev->dev,
+ "Input parameter number not correct\n");
+ return -EINVAL;
+ }
+
+ if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
+ dev_warn(smu->adev->dev,
+ "UCLK_LIMITS setting not supported!\n");
+ return -EOPNOTSUPP;
+ }
+ max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.uclk_table);
+ if (input[0] == 0) {
+ dev_info(smu->adev->dev,
+ "Setting min UCLK level is not supported");
+ return -EINVAL;
+ } else if (input[0] == 1) {
+ if (input[1] > max_clk) {
+ dev_warn(smu->adev->dev,
+ "Maximum UCLK (%ld) MHz specified is greater than the maximum allowed (%d) MHz\n",
+ input[1], max_clk);
+ pstate_table->uclk_pstate.custom.max =
+ pstate_table->uclk_pstate.curr.max;
+
+ return -EINVAL;
+ }
+
+ pstate_table->uclk_pstate.custom.max = input[1];
+ }
+ break;
+ case PP_OD_RESTORE_DEFAULT_TABLE:
+ if (size != 0) {
+ dev_err(smu->adev->dev,
+ "Input parameter number not correct\n");
+ return -EINVAL;
+ }
+
+ /* Use the default frequencies for manual mode */
+ min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.gfx_table);
+ max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.gfx_table);
+
+ ret = smu_v15_0_8_set_soft_freq_limited_range(smu,
+ SMU_GFXCLK,
+ min_clk, max_clk,
+ false);
+ if (ret)
+ return ret;
+
+ min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.uclk_table);
+ max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.uclk_table);
+ ret = smu_v15_0_8_set_soft_freq_limited_range(smu,
+ SMU_UCLK,
+ min_clk, max_clk,
+ false);
+ if (ret)
+ return ret;
+
+ smu_cmn_reset_custom_level(smu);
+ break;
+ case PP_OD_COMMIT_DPM_TABLE:
+ if (size != 0) {
+ dev_err(smu->adev->dev,
+ "Input parameter number not correct\n");
+ return -EINVAL;
+ }
+
+ if (!pstate_table->gfxclk_pstate.custom.min)
+ pstate_table->gfxclk_pstate.custom.min =
+ pstate_table->gfxclk_pstate.curr.min;
+
+ if (!pstate_table->gfxclk_pstate.custom.max)
+ pstate_table->gfxclk_pstate.custom.max =
+ pstate_table->gfxclk_pstate.curr.max;
+
+ min_clk = pstate_table->gfxclk_pstate.custom.min;
+ max_clk = pstate_table->gfxclk_pstate.custom.max;
+
+ ret = smu_v15_0_8_set_soft_freq_limited_range(smu,
+ SMU_GFXCLK,
+ min_clk, max_clk,
+ false);
+ if (ret)
+ return ret;
+
+ /* Commit UCLK custom range (only max supported) */
+ if (pstate_table->uclk_pstate.custom.max) {
+ min_clk = pstate_table->uclk_pstate.curr.min;
+ max_clk = pstate_table->uclk_pstate.custom.max;
+ ret = smu_v15_0_8_set_soft_freq_limited_range(smu,
+ SMU_UCLK,
+ min_clk, max_clk,
+ false);
+ if (ret)
+ return ret;
+ }
+
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return 0;
+}
+
+static int smu_v15_0_8_get_thermal_temperature_range(struct smu_context *smu,
+ struct smu_temperature_range *range)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable;
+ uint32_t max_ctf, max_thm;
+
+ if (amdgpu_sriov_multi_vf_mode(smu->adev))
+ return 0;
+
+ if (!range)
+ return -EINVAL;
+
+ /* CTF (Critical Temperature Fault) limits */
+ max_ctf = max3(pptable->CTFLimitMID, pptable->CTFLimitXCD,
+ pptable->CTFLimitAID);
+ range->hotspot_emergency_max = max_ctf * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+
+ range->mem_emergency_max = pptable->CTFLimitHBM *
+ SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+
+ /* Thermal throttling limits */
+ max_thm = max3(pptable->ThermalLimitMID, pptable->ThermalLimitXCD,
+ pptable->ThermalLimitAID);
+ range->hotspot_crit_max = max_thm * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+
+ range->mem_crit_max = pptable->ThermalLimitHBM *
+ SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+
+ return 0;
+}
+
+static int smu_v15_0_8_set_power_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t limit)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable;
+ int ret;
+
+ if (limit_type == SMU_FAST_PPT_LIMIT) {
+ if (!pptable->PPT1Max)
+ return -EOPNOTSUPP;
+
+ if (limit > pptable->PPT1Max || limit < pptable->PPT1Min) {
+ dev_err(smu->adev->dev,
+ "New PPT1 limit (%d) should be between min %d and max %d\n",
+ limit, pptable->PPT1Min, pptable->PPT1Max);
+ return -EINVAL;
+ }
+
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetFastPptLimit,
+ limit, NULL);
+ if (ret)
+ dev_err(smu->adev->dev, "Set fast PPT limit failed!\n");
+
+ return ret;
+ }
+
+ return smu_v15_0_set_power_limit(smu, limit_type, limit);
+}
+
+static int smu_v15_0_8_get_ppt_limit(struct smu_context *smu,
+ uint32_t *ppt_limit,
+ enum smu_ppt_limit_type type,
+ enum smu_ppt_limit_level level)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable;
+ int ret = 0;
+
+ if (!ppt_limit)
+ return -EINVAL;
+
+ if (type == SMU_FAST_PPT_LIMIT) {
+ if (!pptable->PPT1Max)
+ return -EOPNOTSUPP;
+
+ switch (level) {
+ case SMU_PPT_LIMIT_MAX:
+ *ppt_limit = pptable->PPT1Max;
+ break;
+ case SMU_PPT_LIMIT_CURRENT:
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetFastPptLimit,
+ ppt_limit);
+ if (ret)
+ dev_err(smu->adev->dev,
+ "Get fast PPT limit failed!\n");
+ break;
+ case SMU_PPT_LIMIT_DEFAULT:
+ *ppt_limit = pptable->PPT1Default;
+ break;
+ case SMU_PPT_LIMIT_MIN:
+ *ppt_limit = pptable->PPT1Min;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return ret;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static uint32_t smu_v15_0_8_get_throttler_status(struct smu_context *smu)
+{
+ struct smu_power_context *smu_power = &smu->smu_power;
+ struct smu_15_0_power_context *power_context = smu_power->power_context;
+ uint32_t throttler_status = 0;
+
+ throttler_status = atomic_read(&power_context->throttle_status);
+ dev_dbg(smu->adev->dev, "SMU Throttler status: %u", throttler_status);
+
+ return throttler_status;
+}
+
+static const char *const throttling_logging_label[] = {
+ [THROTTLER_PROCHOT_BIT] = "Prochot",
+ [THROTTLER_THERMAL_SOCKET_BIT] = "SOC",
+ [THROTTLER_THERMAL_VR_BIT] = "VR",
+ [THROTTLER_THERMAL_HBM_BIT] = "HBM"
+};
+
+static void smu_v15_0_8_log_thermal_throttling_event(struct smu_context *smu)
+{
+ int throttler_idx, throttling_events = 0, buf_idx = 0;
+ struct amdgpu_device *adev = smu->adev;
+ uint32_t throttler_status;
+ char log_buf[256];
+
+ throttler_status = smu_v15_0_8_get_throttler_status(smu);
+ if (!throttler_status)
+ return;
+
+ memset(log_buf, 0, sizeof(log_buf));
+ for (throttler_idx = 0;
+ throttler_idx < ARRAY_SIZE(throttling_logging_label);
+ throttler_idx++) {
+ if (throttler_status & (1U << throttler_idx)) {
+ throttling_events++;
+ buf_idx += snprintf(
+ log_buf + buf_idx, sizeof(log_buf) - buf_idx,
+ "%s%s", throttling_events > 1 ? " and " : "",
+ throttling_logging_label[throttler_idx]);
+ if (buf_idx >= sizeof(log_buf)) {
+ dev_err(adev->dev, "buffer overflow!\n");
+ log_buf[sizeof(log_buf) - 1] = '\0';
+ break;
+ }
+ }
+ }
+
+ dev_warn(adev->dev,
+ "WARN: GPU is throttled, expect performance decrease. %s.\n",
+ log_buf);
+ kgd2kfd_smi_event_throttle(
+ smu->adev->kfd.dev,
+ smu_cmn_get_indep_throttler_status(throttler_status,
+ smu_v15_0_8_throttler_map));
+}
+
+static int smu_v15_0_8_enable_thermal_alert(struct smu_context *smu)
+{
+ if (!smu->irq_source.num_types)
+ return 0;
+
+ return amdgpu_irq_get(smu->adev, &smu->irq_source, 0);
+}
+
+static const struct pptable_funcs smu_v15_0_8_ppt_funcs = {
+ .init_allowed_features = smu_v15_0_8_init_allowed_features,
+ .set_default_dpm_table = smu_v15_0_8_set_default_dpm_table,
+ .is_dpm_running = smu_v15_0_8_is_dpm_running,
+ .init_smc_tables = smu_v15_0_8_init_smc_tables,
+ .fini_smc_tables = smu_v15_0_8_fini_smc_tables,
+ .init_power = smu_v15_0_init_power,
+ .fini_power = smu_v15_0_fini_power,
+ .check_fw_status = smu_v15_0_8_check_fw_status,
+ .check_fw_version = smu_cmn_check_fw_version,
+ .set_driver_table_location = smu_v15_0_set_driver_table_location,
+ .set_tool_table_location = smu_v15_0_set_tool_table_location,
+ .notify_memory_pool_location = smu_v15_0_notify_memory_pool_location,
+ .system_features_control = smu_v15_0_8_system_features_control,
+ .get_enabled_mask = smu_v15_0_8_get_enabled_mask,
+ .feature_is_enabled = smu_cmn_feature_is_enabled,
+ .register_irq_handler = smu_v15_0_8_register_irq_handler,
+ .enable_thermal_alert = smu_v15_0_8_enable_thermal_alert,
+ .disable_thermal_alert = smu_v15_0_disable_thermal_alert,
+ .log_thermal_throttling_event = smu_v15_0_8_log_thermal_throttling_event,
+ .setup_pptable = smu_v15_0_8_setup_pptable,
+ .get_pp_feature_mask = smu_cmn_get_pp_feature_mask,
+ .wait_for_event = smu_v15_0_wait_for_event,
+ .get_pm_metrics = smu_v15_0_8_get_pm_metrics,
+ .get_xcp_metrics = smu_v15_0_8_get_xcp_metrics,
+ .mode2_reset = smu_v15_0_8_mode2_reset,
+ .get_dpm_ultimate_freq = smu_v15_0_8_get_dpm_ultimate_freq,
+ .get_gpu_metrics = smu_v15_0_8_get_gpu_metrics,
+ .get_unique_id = smu_v15_0_8_get_unique_id,
+ .get_power_limit = smu_v15_0_8_get_power_limit,
+ .set_power_limit = smu_v15_0_8_set_power_limit,
+ .get_ppt_limit = smu_v15_0_8_get_ppt_limit,
+ .emit_clk_levels = smu_v15_0_8_emit_clk_levels,
+ .read_sensor = smu_v15_0_8_read_sensor,
+ .populate_umd_state_clk = smu_v15_0_8_populate_umd_state_clk,
+ .set_performance_level = smu_v15_0_8_set_performance_level,
+ .od_edit_dpm_table = smu_v15_0_8_od_edit_dpm_table,
+ .get_thermal_temperature_range = smu_v15_0_8_get_thermal_temperature_range,
+};
+
+static void smu_v15_0_8_init_msg_ctl(struct smu_context *smu,
+ const struct cmn2asic_msg_mapping *message_map)
+{
+ struct amdgpu_device *adev = smu->adev;
+ struct smu_msg_ctl *ctl = &smu->msg_ctl;
+
+ ctl->smu = smu;
+ mutex_init(&ctl->lock);
+ ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_40);
+ ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_41);
+ ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_42);
+ ctl->config.arg_regs[1] = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_43);
+ ctl->config.arg_regs[2] = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_44);
+ ctl->config.arg_regs[3] = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_45);
+ ctl->config.num_arg_regs = 4;
+ ctl->ops = &smu_msg_v1_ops;
+ ctl->default_timeout = adev->usec_timeout * 20;
+ ctl->message_map = message_map;
+}
+
+static const struct smu_temp_funcs smu_v15_0_8_temp_funcs = {
+ .temp_metrics_is_supported = smu_v15_0_8_is_temp_metrics_supported,
+ .get_temp_metrics = smu_v15_0_8_get_temp_metrics,
+};
+
+void smu_v15_0_8_set_ppt_funcs(struct smu_context *smu)
+{
+ smu->ppt_funcs = &smu_v15_0_8_ppt_funcs;
+ smu->clock_map = smu_v15_0_8_clk_map;
+ smu->feature_map = smu_v15_0_8_feature_mask_map;
+ smu->table_map = smu_v15_0_8_table_map;
+ smu_v15_0_8_init_msg_ctl(smu, smu_v15_0_8_message_map);
+ smu->smu_temp.temp_funcs = &smu_v15_0_8_temp_funcs;
+ smu->smc_driver_if_version = SMU15_DRIVER_IF_VERSION_SMU_V15_0_8;
+}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.h
new file mode 100644
index 000000000000..4dfc40aaffcb
--- /dev/null
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.h
@@ -0,0 +1,347 @@
+/*
+ * Copyright 2025 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __SMU_15_0_8_PPT_H__
+#define __SMU_15_0_8_PPT_H__
+
+#define SMU_15_0_8_NUM_XGMI_LINKS 8
+#define SMU_15_0_8_MAX_GFX_CLKS 8
+#define SMU_15_0_8_MAX_CLKS 4
+#define SMU_15_0_8_MAX_XCC 8
+#define SMU_15_0_8_MAX_VCN 4
+#define SMU_15_0_8_MAX_JPEG 40
+#define SMU_15_0_8_MAX_AID 2
+#define SMU_15_0_8_MAX_MID 2
+#define SMU_15_0_8_MAX_HBM_STACKS 12
+extern void smu_v15_0_8_set_ppt_funcs(struct smu_context *smu);
+
+typedef struct {
+ uint32_t MaxSocketPowerLimit;
+ uint32_t MaxGfxclkFrequency;
+ uint32_t MinGfxclkFrequency;
+ uint32_t MaxFclkFrequency;
+ uint32_t MinFclkFrequency;
+ uint32_t MaxGl2clkFrequency;
+ uint32_t MinGl2clkFrequency;
+ uint32_t UclkFrequencyTable[4];
+ uint32_t SocclkFrequency;
+ uint32_t LclkFrequency;
+ uint32_t VclkFrequency;
+ uint32_t DclkFrequency;
+ uint32_t CTFLimitMID;
+ uint32_t CTFLimitAID;
+ uint32_t CTFLimitXCD;
+ uint32_t CTFLimitHBM;
+ uint32_t ThermalLimitMID;
+ uint32_t ThermalLimitAID;
+ uint32_t ThermalLimitXCD;
+ uint32_t ThermalLimitHBM;
+ uint64_t PublicSerialNumberMID;
+ uint64_t PublicSerialNumberAID;
+ uint64_t PublicSerialNumberXCD;
+ uint32_t PPT1Max;
+ uint32_t PPT1Min;
+ uint32_t PPT1Default;
+ bool init;
+} PPTable_t;
+
+#if defined(SWSMU_CODE_LAYER_L2)
+#include "smu_cmn.h"
+
+/* SMUv 15.0.8 GPU metrics*/
+#define SMU_15_0_8_METRICS_FIELDS(SMU_SCALAR, SMU_ARRAY) \
+ SMU_SCALAR(SMU_MATTR(TEMPERATURE_HOTSPOT), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(U16), temperature_hotspot); \
+ SMU_SCALAR(SMU_MATTR(TEMPERATURE_MEM), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(U16), temperature_mem); \
+ SMU_SCALAR(SMU_MATTR(TEMPERATURE_VRSOC), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(U16), temperature_vrsoc); \
+ SMU_ARRAY(SMU_MATTR(TEMPERATURE_HBM), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(U16), temperature_hbm, \
+ SMU_15_0_8_MAX_HBM_STACKS); \
+ SMU_ARRAY(SMU_MATTR(TEMPERATURE_MID), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(U16), temperature_mid, SMU_15_0_8_MAX_MID); \
+ SMU_ARRAY(SMU_MATTR(TEMPERATURE_AID), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(U16), temperature_aid, SMU_15_0_8_MAX_AID); \
+ SMU_ARRAY(SMU_MATTR(TEMPERATURE_XCD), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(U16), temperature_xcd, SMU_15_0_8_MAX_XCC); \
+ SMU_SCALAR(SMU_MATTR(CURR_SOCKET_POWER), SMU_MUNIT(POWER_1), \
+ SMU_MTYPE(U16), curr_socket_power); \
+ SMU_SCALAR(SMU_MATTR(AVERAGE_GFX_ACTIVITY), SMU_MUNIT(PERCENT), \
+ SMU_MTYPE(U16), average_gfx_activity); \
+ SMU_SCALAR(SMU_MATTR(AVERAGE_UMC_ACTIVITY), SMU_MUNIT(PERCENT), \
+ SMU_MTYPE(U16), average_umc_activity); \
+ SMU_SCALAR(SMU_MATTR(MEM_MAX_BANDWIDTH), SMU_MUNIT(BW_1), \
+ SMU_MTYPE(U64), mem_max_bandwidth); \
+ SMU_SCALAR(SMU_MATTR(ENERGY_ACCUMULATOR), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), energy_accumulator); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_CLOCK_COUNTER), SMU_MUNIT(TIME_1), \
+ SMU_MTYPE(U64), system_clock_counter); \
+ SMU_SCALAR(SMU_MATTR(ACCUMULATION_COUNTER), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), accumulation_counter); \
+ SMU_SCALAR(SMU_MATTR(PROCHOT_RESIDENCY_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), prochot_residency_acc); \
+ SMU_SCALAR(SMU_MATTR(PPT_RESIDENCY_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), ppt_residency_acc); \
+ SMU_SCALAR(SMU_MATTR(SOCKET_THM_RESIDENCY_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), socket_thm_residency_acc); \
+ SMU_SCALAR(SMU_MATTR(VR_THM_RESIDENCY_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), vr_thm_residency_acc); \
+ SMU_SCALAR(SMU_MATTR(HBM_THM_RESIDENCY_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), hbm_thm_residency_acc); \
+ SMU_SCALAR(SMU_MATTR(GFXCLK_LOCK_STATUS), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U32), gfxclk_lock_status); \
+ SMU_SCALAR(SMU_MATTR(PCIE_LINK_WIDTH), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U16), pcie_link_width); \
+ SMU_SCALAR(SMU_MATTR(PCIE_LINK_SPEED), SMU_MUNIT(SPEED_2), \
+ SMU_MTYPE(U16), pcie_link_speed); \
+ SMU_SCALAR(SMU_MATTR(XGMI_LINK_WIDTH), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U16), xgmi_link_width); \
+ SMU_SCALAR(SMU_MATTR(XGMI_LINK_SPEED), SMU_MUNIT(SPEED_1), \
+ SMU_MTYPE(U16), xgmi_link_speed); \
+ SMU_SCALAR(SMU_MATTR(GFX_ACTIVITY_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), gfx_activity_acc); \
+ SMU_SCALAR(SMU_MATTR(MEM_ACTIVITY_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), mem_activity_acc); \
+ SMU_ARRAY(SMU_MATTR(PCIE_BANDWIDTH_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), pcie_bandwidth_acc, SMU_15_0_8_MAX_MID); \
+ SMU_ARRAY(SMU_MATTR(PCIE_BANDWIDTH_INST), SMU_MUNIT(BW_1), \
+ SMU_MTYPE(U32), pcie_bandwidth_inst, SMU_15_0_8_MAX_MID); \
+ SMU_SCALAR(SMU_MATTR(PCIE_L0_TO_RECOV_COUNT_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), pcie_l0_to_recov_count_acc); \
+ SMU_SCALAR(SMU_MATTR(PCIE_REPLAY_COUNT_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), pcie_replay_count_acc); \
+ SMU_SCALAR(SMU_MATTR(PCIE_REPLAY_ROVER_COUNT_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), pcie_replay_rover_count_acc); \
+ SMU_SCALAR(SMU_MATTR(PCIE_NAK_SENT_COUNT_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), pcie_nak_sent_count_acc); \
+ SMU_SCALAR(SMU_MATTR(PCIE_NAK_RCVD_COUNT_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), pcie_nak_rcvd_count_acc); \
+ SMU_ARRAY(SMU_MATTR(XGMI_LINK_STATUS), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U16), xgmi_link_status, \
+ SMU_15_0_8_NUM_XGMI_LINKS); \
+ SMU_SCALAR(SMU_MATTR(XGMI_READ_DATA_ACC), SMU_MUNIT(DATA_1), \
+ SMU_MTYPE(U64), xgmi_read_data_acc); \
+ SMU_SCALAR(SMU_MATTR(XGMI_WRITE_DATA_ACC), SMU_MUNIT(DATA_1), \
+ SMU_MTYPE(U64), xgmi_write_data_acc); \
+ SMU_SCALAR(SMU_MATTR(FIRMWARE_TIMESTAMP), SMU_MUNIT(TIME_2), \
+ SMU_MTYPE(U64), firmware_timestamp); \
+ SMU_ARRAY(SMU_MATTR(CURRENT_GFXCLK), SMU_MUNIT(CLOCK_1), \
+ SMU_MTYPE(U16), current_gfxclk, SMU_15_0_8_MAX_GFX_CLKS); \
+ SMU_ARRAY(SMU_MATTR(CURRENT_SOCCLK), SMU_MUNIT(CLOCK_1), \
+ SMU_MTYPE(U16), current_socclk, SMU_15_0_8_MAX_MID); \
+ SMU_ARRAY(SMU_MATTR(CURRENT_VCLK0), SMU_MUNIT(CLOCK_1), \
+ SMU_MTYPE(U16), current_vclk0, SMU_15_0_8_MAX_VCN); \
+ SMU_ARRAY(SMU_MATTR(CURRENT_DCLK0), SMU_MUNIT(CLOCK_1), \
+ SMU_MTYPE(U16), current_dclk0, SMU_15_0_8_MAX_VCN); \
+ SMU_ARRAY(SMU_MATTR(CURRENT_UCLK), SMU_MUNIT(CLOCK_1), \
+ SMU_MTYPE(U16), current_uclk, SMU_15_0_8_MAX_AID); \
+ SMU_SCALAR(SMU_MATTR(PCIE_LC_PERF_OTHER_END_RECOVERY), \
+ SMU_MUNIT(NONE), SMU_MTYPE(U64), \
+ pcie_lc_perf_other_end_recovery); \
+ SMU_ARRAY(SMU_MATTR(GFX_BUSY_INST), SMU_MUNIT(PERCENT), \
+ SMU_MTYPE(U32), gfx_busy_inst, SMU_15_0_8_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(JPEG_BUSY), SMU_MUNIT(PERCENT), SMU_MTYPE(U16), \
+ jpeg_busy, SMU_15_0_8_MAX_JPEG); \
+ SMU_ARRAY(SMU_MATTR(VCN_BUSY), SMU_MUNIT(PERCENT), SMU_MTYPE(U16), \
+ vcn_busy, SMU_15_0_8_MAX_VCN); \
+ SMU_ARRAY(SMU_MATTR(GFX_BUSY_ACC), SMU_MUNIT(NONE), SMU_MTYPE(U64), \
+ gfx_busy_acc, SMU_15_0_8_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_PPT_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), gfx_below_host_limit_ppt_acc, \
+ SMU_15_0_8_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_THM_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), gfx_below_host_limit_thm_acc, \
+ SMU_15_0_8_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(GFX_LOW_UTILIZATION_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), gfx_low_utilization_acc, \
+ SMU_15_0_8_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_TOTAL_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), gfx_below_host_limit_total_acc, \
+ SMU_15_0_8_MAX_XCC);
+
+DECLARE_SMU_METRICS_CLASS(smu_v15_0_8_gpu_metrics, SMU_15_0_8_METRICS_FIELDS);
+
+/* Maximum temperature sensor counts for system metrics */
+#define SMU_15_0_8_MAX_SYSTEM_TEMP_ENTRIES 32
+#define SMU_15_0_8_MAX_NODE_TEMP_ENTRIES 12
+#define SMU_15_0_8_MAX_VR_TEMP_ENTRIES 22
+
+/* SMUv 15.0.8 GPU board temperature metrics */
+#define SMU_15_0_8_GPUBOARD_TEMP_METRICS_FIELDS(SMU_SCALAR, SMU_ARRAY) \
+ SMU_SCALAR(SMU_MATTR(ACCUMULATION_COUNTER), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), accumulation_counter); \
+ SMU_SCALAR(SMU_MATTR(LABEL_VERSION), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U16), label_version); \
+ SMU_SCALAR(SMU_MATTR(NODE_ID), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U16), node_id); \
+ SMU_SCALAR(SMU_MATTR(NODE_TEMP_RETIMER), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), node_temp_retimer); \
+ SMU_SCALAR(SMU_MATTR(NODE_TEMP_IBC), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), node_temp_ibc); \
+ SMU_SCALAR(SMU_MATTR(NODE_TEMP_IBC_2), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), node_temp_ibc_2); \
+ SMU_SCALAR(SMU_MATTR(NODE_TEMP_VDD18_VR), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), node_temp_vdd18_vr); \
+ SMU_SCALAR(SMU_MATTR(NODE_TEMP_04_HBM_B_VR), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), node_temp_04_hbm_b_vr); \
+ SMU_SCALAR(SMU_MATTR(NODE_TEMP_04_HBM_D_VR), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), node_temp_04_hbm_d_vr); \
+ SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_SOCIO_A), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), vr_temp_vddcr_socio_a); \
+ SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_SOCIO_C), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), vr_temp_vddcr_socio_c); \
+ SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_X0), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), vr_temp_vddcr_x0); \
+ SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_X1), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), vr_temp_vddcr_x1); \
+ SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_HBM_B), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), vr_temp_vddio_hbm_b); \
+ SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_HBM_D), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), vr_temp_vddio_hbm_d); \
+ SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_04_HBM_B), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), vr_temp_vddio_04_hbm_b); \
+ SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_04_HBM_D), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), vr_temp_vddio_04_hbm_d); \
+ SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_HBM_B), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), vr_temp_vddcr_hbm_b); \
+ SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_HBM_D), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), vr_temp_vddcr_hbm_d); \
+ SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_075_HBM_B), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), vr_temp_vddcr_075_hbm_b); \
+ SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_075_HBM_D), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), vr_temp_vddcr_075_hbm_d); \
+ SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_11_GTA_A), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), vr_temp_vddio_11_gta_a); \
+ SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_11_GTA_C), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), vr_temp_vddio_11_gta_c); \
+ SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDAN_075_GTA_A), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), vr_temp_vddan_075_gta_a); \
+ SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDAN_075_GTA_C), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), vr_temp_vddan_075_gta_c); \
+ SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_075_UCIE), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), vr_temp_vddcr_075_ucie); \
+ SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_065_UCIEAA), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), vr_temp_vddio_065_ucieaa); \
+ SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_065_UCIEAM_A), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), vr_temp_vddio_065_ucieam_a); \
+ SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_065_UCIEAM_C), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), vr_temp_vddio_065_ucieam_c); \
+ SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDAN_075), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), vr_temp_vddan_075);
+
+DECLARE_SMU_METRICS_CLASS(smu_v15_0_8_gpuboard_temp_metrics,
+ SMU_15_0_8_GPUBOARD_TEMP_METRICS_FIELDS);
+
+/* SMUv 15.0.8 Baseboard temperature metrics - ID-based approach */
+#define SMU_15_0_8_BASEBOARD_TEMP_METRICS_FIELDS(SMU_SCALAR, SMU_ARRAY) \
+ SMU_SCALAR(SMU_MATTR(ACCUMULATION_COUNTER), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), accumulation_counter); \
+ SMU_SCALAR(SMU_MATTR(LABEL_VERSION), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U16), label_version); \
+ SMU_SCALAR(SMU_MATTR(NODE_ID), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U16), node_id); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_FPGA), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_ubb_fpga); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_FRONT), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_ubb_front); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_BACK), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_ubb_back); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_OAM7), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_ubb_oam7); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_IBC), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_ubb_ibc); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_UFPGA), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_ubb_ufpga); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_OAM1), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_ubb_oam1); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_OAM_0_1_HSC), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_oam_0_1_hsc); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_OAM_2_3_HSC), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_oam_2_3_hsc); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_OAM_4_5_HSC), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_oam_4_5_hsc); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_OAM_6_7_HSC), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_oam_6_7_hsc); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_FPGA_0V72_VR), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_ubb_fpga_0v72_vr); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_FPGA_3V3_VR), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_ubb_fpga_3v3_vr); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_RETIMER_0_1_2_3_1V2_VR), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_retimer_0_1_2_3_1v2_vr); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_RETIMER_4_5_6_7_1V2_VR), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_retimer_4_5_6_7_1v2_vr); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_RETIMER_0_1_0V9_VR), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_retimer_0_1_0v9_vr); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_RETIMER_4_5_0V9_VR), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_retimer_4_5_0v9_vr); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_RETIMER_2_3_0V9_VR), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_retimer_2_3_0v9_vr); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_RETIMER_6_7_0V9_VR), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_retimer_6_7_0v9_vr); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_OAM_0_1_2_3_3V3_VR), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_oam_0_1_2_3_3v3_vr); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_OAM_4_5_6_7_3V3_VR), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_oam_4_5_6_7_3v3_vr); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_IBC_HSC), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_ibc_hsc); \
+ SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_IBC), SMU_MUNIT(TEMP_1), \
+ SMU_MTYPE(S16), system_temp_ibc);
+
+DECLARE_SMU_METRICS_CLASS(smu_v15_0_8_baseboard_temp_metrics,
+ SMU_15_0_8_BASEBOARD_TEMP_METRICS_FIELDS);
+#define SMU_15_0_8_PARTITION_METRICS_FIELDS(SMU_SCALAR, SMU_ARRAY) \
+ SMU_ARRAY(SMU_MATTR(CURRENT_GFXCLK), SMU_MUNIT(CLOCK_1), \
+ SMU_MTYPE(U16), current_gfxclk, SMU_15_0_8_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(CURRENT_VCLK0), SMU_MUNIT(CLOCK_1), \
+ SMU_MTYPE(U16), current_vclk, SMU_15_0_8_MAX_VCN); \
+ SMU_ARRAY(SMU_MATTR(CURRENT_DCLK0), SMU_MUNIT(CLOCK_1), \
+ SMU_MTYPE(U16), current_dclk, SMU_15_0_8_MAX_VCN); \
+ SMU_ARRAY(SMU_MATTR(GFX_BUSY_INST), SMU_MUNIT(PERCENT), \
+ SMU_MTYPE(U8), gfx_busy_inst, SMU_15_0_8_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(JPEG_BUSY), SMU_MUNIT(PERCENT), SMU_MTYPE(U8), \
+ jpeg_busy, SMU_15_0_8_MAX_JPEG); \
+ SMU_ARRAY(SMU_MATTR(VCN_BUSY), SMU_MUNIT(PERCENT), SMU_MTYPE(U8), \
+ vcn_busy, SMU_15_0_8_MAX_VCN); \
+ SMU_ARRAY(SMU_MATTR(GFX_BUSY_ACC), SMU_MUNIT(NONE), SMU_MTYPE(U64), \
+ gfx_busy_acc, SMU_15_0_8_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_PPT_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), gfx_below_host_limit_ppt_acc, \
+ SMU_15_0_8_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_THM_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), gfx_below_host_limit_thm_acc, \
+ SMU_15_0_8_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(GFX_LOW_UTILIZATION_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), gfx_low_utilization_acc, \
+ SMU_15_0_8_MAX_XCC); \
+ SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_TOTAL_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), gfx_below_host_limit_total_acc, \
+ SMU_15_0_8_MAX_XCC); \
+ SMU_SCALAR(SMU_MATTR(ACCUMULATION_COUNTER), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), accumulation_counter); \
+ SMU_SCALAR(SMU_MATTR(FIRMWARE_TIMESTAMP), SMU_MUNIT(TIME_2), \
+ SMU_MTYPE(U64), firmware_timestamp);
+
+DECLARE_SMU_METRICS_CLASS(smu_v15_0_8_partition_metrics,
+ SMU_15_0_8_PARTITION_METRICS_FIELDS);
+#endif
+#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
index 9f55207ea9bc..d365f06ac1ac 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
@@ -53,6 +53,9 @@ static const char * const __smu_message_names[] = {
-ENOTSUPP) : \
-EINVAL)
+#define SMU_MSG_V1_DEFAULT_RATELIMIT_INTERVAL (5 * HZ)
+#define SMU_MSG_V1_DEFAULT_RATELIMIT_BURST 10
+
static const char *smu_get_message_name(struct smu_context *smu,
enum smu_message_type type)
{
@@ -62,14 +65,6 @@ static const char *smu_get_message_name(struct smu_context *smu,
return __smu_message_names[type];
}
-static void smu_cmn_read_arg(struct smu_context *smu,
- uint32_t *arg)
-{
- struct amdgpu_device *adev = smu->adev;
-
- *arg = RREG32(smu->param_reg);
-}
-
/* Redefine the SMU error codes here.
*
* Note that these definitions are redundant and should be removed
@@ -86,104 +81,176 @@ static void smu_cmn_read_arg(struct smu_context *smu,
#define SMU_RESP_BUSY_OTHER 0xFC
#define SMU_RESP_DEBUG_END 0xFB
+#define SMU_RESP_UNEXP (~0U)
+
+static int smu_msg_v1_send_debug_msg(struct smu_msg_ctl *ctl, u32 msg, u32 param)
+{
+ struct amdgpu_device *adev = ctl->smu->adev;
+ struct smu_msg_config *cfg = &ctl->config;
+
+ if (!(ctl->flags & SMU_MSG_CTL_DEBUG_MAILBOX))
+ return -EOPNOTSUPP;
+
+ mutex_lock(&ctl->lock);
+
+ WREG32(cfg->debug_param_reg, param);
+ WREG32(cfg->debug_msg_reg, msg);
+ WREG32(cfg->debug_resp_reg, 0);
+
+ mutex_unlock(&ctl->lock);
+
+ return 0;
+}
+
+static int __smu_cmn_send_debug_msg(struct smu_msg_ctl *ctl,
+ u32 msg,
+ u32 param)
+{
+ if (!ctl->ops || !ctl->ops->send_debug_msg)
+ return -EOPNOTSUPP;
+
+ return ctl->ops->send_debug_msg(ctl, msg, param);
+}
+
+/**
+ * smu_cmn_wait_for_response -- wait for response from the SMU
+ * @smu: pointer to an SMU context
+ *
+ * Wait for status from the SMU.
+ *
+ * Return 0 on success, -errno on error, indicating the execution
+ * status and result of the message being waited for. See
+ * smu_msg_v1_decode_response() for details of the -errno.
+ */
+int smu_cmn_wait_for_response(struct smu_context *smu)
+{
+ return smu_msg_wait_response(&smu->msg_ctl, 0);
+}
+
/**
- * __smu_cmn_poll_stat -- poll for a status from the SMU
- * @smu: a pointer to SMU context
+ * smu_cmn_send_smc_msg_with_params_ext - send an SMU message with 0..N args
+ * @smu: pointer to an SMU context
+ * @msg: message to send
+ * @params: optional input argument array
+ * @num_params: number of input arguments in @params
+ * @read_args: optional output argument array
+ * @num_read_args: number of output arguments to read back
+ * @flags: message flags (SMU_MSG_FLAG_*)
+ * @timeout: per-message timeout in us (0 = use default)
*
- * Returns the status of the SMU, which could be,
- * 0, the SMU is busy with your command;
- * 1, execution status: success, execution result: success;
- * 0xFF, execution status: success, execution result: failure;
- * 0xFE, unknown command;
- * 0xFD, valid command, but bad (command) prerequisites;
- * 0xFC, the command was rejected as the SMU is busy;
- * 0xFB, "SMC_Result_DebugDataDumpEnd".
+ * This helper keeps the raw protocol semantics of struct smu_msg_args while
+ * hiding the per-call boilerplate. It is intended for true multi-parameter
+ * messages. Legacy wrappers such as smu_cmn_send_smc_msg() retain their
+ * existing single-zero-parameter behavior for compatibility.
*
- * The values here are not defined by macros, because I'd rather we
- * include a single header file which defines them, which is
- * maintained by the SMU FW team, so that we're impervious to firmware
- * changes. At the moment those values are defined in various header
- * files, one for each ASIC, yet here we're a single ASIC-agnostic
- * interface. Such a change can be followed-up by a subsequent patch.
+ * Return: 0 on success, -errno on failure.
*/
-static u32 __smu_cmn_poll_stat(struct smu_context *smu)
+int smu_cmn_send_smc_msg_with_params_ext(struct smu_context *smu,
+ enum smu_message_type msg,
+ const uint32_t *params,
+ size_t num_params,
+ uint32_t *read_args,
+ size_t num_read_args,
+ uint32_t flags,
+ uint32_t timeout)
{
- struct amdgpu_device *adev = smu->adev;
- int timeout = adev->usec_timeout * 20;
- u32 reg;
+ struct smu_msg_ctl *ctl = &smu->msg_ctl;
+ struct smu_msg_args args = {
+ .msg = msg,
+ .num_args = num_params,
+ .num_out_args = num_read_args,
+ .flags = flags,
+ .timeout = timeout,
+ };
+ int ret;
- for ( ; timeout > 0; timeout--) {
- reg = RREG32(smu->resp_reg);
- if ((reg & MP1_C2PMSG_90__CONTENT_MASK) != 0)
- break;
+ if ((num_params && !params) || (num_read_args && !read_args))
+ return -EINVAL;
- udelay(1);
- }
+ if (num_params > SMU_MSG_MAX_ARGS || num_read_args > SMU_MSG_MAX_ARGS)
+ return -EINVAL;
- return reg;
+ if (num_params)
+ memcpy(args.args, params, num_params * sizeof(*params));
+
+ ret = ctl->ops->send_msg(ctl, &args);
+
+ if (num_read_args)
+ memcpy(read_args, args.out_args,
+ num_read_args * sizeof(*read_args));
+
+ return ret;
}
-static void __smu_cmn_reg_print_error(struct smu_context *smu,
- u32 reg_c2pmsg_90,
- int msg_index,
- u32 param,
- enum smu_message_type msg)
+/**
+ * smu_cmn_send_smc_msg_with_param -- send a message with parameter
+ * @smu: pointer to an SMU context
+ * @msg: message to send
+ * @param: parameter to send to the SMU
+ * @read_arg: pointer to u32 to return a value from the SMU back
+ * to the caller
+ *
+ * Send the message @msg with parameter @param to the SMU, wait for
+ * completion of the command, and return back a value from the SMU in
+ * @read_arg pointer.
+ *
+ * Return 0 on success, -errno when a problem is encountered sending
+ * message or receiving reply. If there is a PCI bus recovery or
+ * the destination is a virtual GPU which does not allow this message
+ * type, the message is simply dropped and success is also returned.
+ * See smu_msg_v1_decode_response() for details of the -errno.
+ *
+ * If we weren't able to send the message to the SMU, we also print
+ * the error to the standard log.
+ *
+ * Command completion status is printed only if the -errno is
+ * -EREMOTEIO, indicating that the SMU returned back an
+ * undefined/unknown/unspecified result. All other cases are
+ * well-defined, not printed, but instead given back to the client to
+ * decide what further to do.
+ *
+ * The return value, @read_arg is read back regardless, to give back
+ * more information to the client, which on error would most likely be
+ * @param, but we can't assume that. This also eliminates more
+ * conditionals.
+ */
+int smu_cmn_send_smc_msg_with_param(struct smu_context *smu,
+ enum smu_message_type msg,
+ uint32_t param,
+ uint32_t *read_arg)
{
- struct amdgpu_device *adev = smu->adev;
- const char *message = smu_get_message_name(smu, msg);
- u32 msg_idx, prm;
-
- switch (reg_c2pmsg_90) {
- case SMU_RESP_NONE: {
- msg_idx = RREG32(smu->msg_reg);
- prm = RREG32(smu->param_reg);
- dev_err_ratelimited(adev->dev,
- "SMU: I'm not done with your previous command: SMN_C2PMSG_66:0x%08X SMN_C2PMSG_82:0x%08X",
- msg_idx, prm);
- }
- break;
- case SMU_RESP_OK:
- /* The SMU executed the command. It completed with a
- * successful result.
- */
- break;
- case SMU_RESP_CMD_FAIL:
- /* The SMU executed the command. It completed with an
- * unsuccessful result.
- */
- break;
- case SMU_RESP_CMD_UNKNOWN:
- dev_err_ratelimited(adev->dev,
- "SMU: unknown command: index:%d param:0x%08X message:%s",
- msg_index, param, message);
- break;
- case SMU_RESP_CMD_BAD_PREREQ:
- dev_err_ratelimited(adev->dev,
- "SMU: valid command, bad prerequisites: index:%d param:0x%08X message:%s",
- msg_index, param, message);
- break;
- case SMU_RESP_BUSY_OTHER:
- dev_err_ratelimited(adev->dev,
- "SMU: I'm very busy for your command: index:%d param:0x%08X message:%s",
- msg_index, param, message);
- break;
- case SMU_RESP_DEBUG_END:
- dev_err_ratelimited(adev->dev,
- "SMU: I'm debugging!");
- break;
- default:
- dev_err_ratelimited(adev->dev,
- "SMU: response:0x%08X for index:%d param:0x%08X message:%s?",
- reg_c2pmsg_90, msg_index, param, message);
- break;
- }
+ return smu_cmn_send_smc_msg_with_params(smu, msg,
+ &param, 1,
+ read_arg, read_arg ? 1 : 0);
+}
+
+int smu_cmn_send_smc_msg(struct smu_context *smu,
+ enum smu_message_type msg,
+ uint32_t *read_arg)
+{
+ return smu_cmn_send_smc_msg_with_param(smu,
+ msg,
+ 0,
+ read_arg);
+}
+
+int smu_cmn_send_debug_smc_msg(struct smu_context *smu,
+ uint32_t msg)
+{
+ return __smu_cmn_send_debug_msg(&smu->msg_ctl, msg, 0);
}
-static int __smu_cmn_reg2errno(struct smu_context *smu, u32 reg_c2pmsg_90)
+int smu_cmn_send_debug_smc_msg_with_param(struct smu_context *smu,
+ uint32_t msg, uint32_t param)
+{
+ return __smu_cmn_send_debug_msg(&smu->msg_ctl, msg, param);
+}
+
+static int smu_msg_v1_decode_response(u32 resp)
{
int res;
- switch (reg_c2pmsg_90) {
+ switch (resp) {
case SMU_RESP_NONE:
/* The SMU is busy--still executing your command.
*/
@@ -224,278 +291,350 @@ static int __smu_cmn_reg2errno(struct smu_context *smu, u32 reg_c2pmsg_90)
return res;
}
-static void __smu_cmn_send_msg(struct smu_context *smu,
- u16 msg,
- u32 param)
+static u32 __smu_msg_v1_poll_stat(struct smu_msg_ctl *ctl, u32 timeout_us)
{
- struct amdgpu_device *adev = smu->adev;
+ struct amdgpu_device *adev = ctl->smu->adev;
+ struct smu_msg_config *cfg = &ctl->config;
+ u32 timeout = timeout_us ? timeout_us : ctl->default_timeout;
+ u32 reg;
- WREG32(smu->resp_reg, 0);
- WREG32(smu->param_reg, param);
- WREG32(smu->msg_reg, msg);
+ for (; timeout > 0; timeout--) {
+ reg = RREG32(cfg->resp_reg);
+ if ((reg & MP1_C2PMSG_90__CONTENT_MASK) != 0)
+ break;
+ udelay(1);
+ }
+
+ return reg;
}
-static inline uint32_t __smu_cmn_get_msg_flags(struct smu_context *smu,
- enum smu_message_type msg)
+static void __smu_msg_v1_send(struct smu_msg_ctl *ctl, u16 index,
+ struct smu_msg_args *args)
{
- return smu->message_map[msg].flags;
+ struct amdgpu_device *adev = ctl->smu->adev;
+ struct smu_msg_config *cfg = &ctl->config;
+ u32 arg;
+ int i;
+
+ WREG32(cfg->resp_reg, 0);
+ for (i = 0; i < cfg->num_arg_regs; i++) {
+ /* NOTE: Clear unused argument registers to avoid stale values. */
+ arg = i < args->num_args ? args->args[i] : 0;
+ WREG32(cfg->arg_regs[i], arg);
+ }
+ WREG32(cfg->msg_reg, index);
}
-static int __smu_cmn_ras_filter_msg(struct smu_context *smu,
- enum smu_message_type msg, bool *poll)
+static void __smu_msg_v1_read_out_args(struct smu_msg_ctl *ctl,
+ struct smu_msg_args *args)
{
- struct amdgpu_device *adev = smu->adev;
- uint32_t flags, resp;
- bool fed_status;
+ struct amdgpu_device *adev = ctl->smu->adev;
+ int i;
- flags = __smu_cmn_get_msg_flags(smu, msg);
- *poll = true;
+ for (i = 0; i < args->num_out_args; i++)
+ args->out_args[i] = RREG32(ctl->config.arg_regs[i]);
+}
- /* When there is RAS fatal error, FW won't process non-RAS priority
- * messages. Don't allow any messages other than RAS priority messages.
- */
- fed_status = amdgpu_ras_get_fed_status(adev);
- if (fed_status) {
- if (!(flags & SMU_MSG_RAS_PRI)) {
- dev_dbg(adev->dev,
- "RAS error detected, skip sending %s",
- smu_get_message_name(smu, msg));
- return -EACCES;
- }
+static void __smu_msg_v1_print_err_limited(struct smu_msg_ctl *ctl,
+ struct smu_msg_args *args,
+ char *err_msg)
+{
+ static DEFINE_RATELIMIT_STATE(_rs,
+ SMU_MSG_V1_DEFAULT_RATELIMIT_INTERVAL,
+ SMU_MSG_V1_DEFAULT_RATELIMIT_BURST);
+ struct smu_context *smu = ctl->smu;
+ struct amdgpu_device *adev = smu->adev;
- /* FW will ignore non-priority messages when a RAS fatal error
- * is detected. Hence it is possible that a previous message
- * wouldn't have got response. Allow to continue without polling
- * for response status for priority messages.
- */
- resp = RREG32(smu->resp_reg);
- dev_dbg(adev->dev,
- "Sending RAS priority message %s response status: %x",
- smu_get_message_name(smu, msg), resp);
- if (resp == 0)
- *poll = false;
+ if (__ratelimit(&_rs)) {
+ u32 in[SMU_MSG_MAX_ARGS];
+ int i;
+
+ dev_err(adev->dev, "%s msg_reg: %x resp_reg: %x", err_msg,
+ RREG32(ctl->config.msg_reg),
+ RREG32(ctl->config.resp_reg));
+ if (args->num_args > 0) {
+ for (i = 0; i < args->num_args; i++)
+ in[i] = RREG32(ctl->config.arg_regs[i]);
+ print_hex_dump(KERN_ERR, "in params:", DUMP_PREFIX_NONE,
+ 16, 4, in, args->num_args * sizeof(u32),
+ false);
+ }
}
-
- return 0;
}
-static int __smu_cmn_send_debug_msg(struct smu_context *smu,
- u32 msg,
- u32 param)
+static void __smu_msg_v1_print_error(struct smu_msg_ctl *ctl,
+ u32 resp,
+ struct smu_msg_args *args)
{
+ struct smu_context *smu = ctl->smu;
struct amdgpu_device *adev = smu->adev;
+ int index = ctl->message_map[args->msg].map_to;
- WREG32(smu->debug_param_reg, param);
- WREG32(smu->debug_msg_reg, msg);
- WREG32(smu->debug_resp_reg, 0);
-
- return 0;
+ switch (resp) {
+ case SMU_RESP_NONE:
+ __smu_msg_v1_print_err_limited(ctl, args, "SMU: No response");
+ break;
+ case SMU_RESP_OK:
+ break;
+ case SMU_RESP_CMD_FAIL:
+ break;
+ case SMU_RESP_CMD_UNKNOWN:
+ __smu_msg_v1_print_err_limited(ctl, args,
+ "SMU: unknown command");
+ break;
+ case SMU_RESP_CMD_BAD_PREREQ:
+ __smu_msg_v1_print_err_limited(
+ ctl, args, "SMU: valid command, bad prerequisites");
+ break;
+ case SMU_RESP_BUSY_OTHER:
+ if (args->msg != SMU_MSG_GetBadPageCount)
+ __smu_msg_v1_print_err_limited(ctl, args,
+ "SMU: I'm very busy");
+ break;
+ case SMU_RESP_DEBUG_END:
+ __smu_msg_v1_print_err_limited(ctl, args, "SMU: Debug Err");
+ break;
+ case SMU_RESP_UNEXP:
+ if (amdgpu_device_bus_status_check(adev)) {
+ dev_err(adev->dev,
+ "SMU: bus error for message: %s(%d) response:0x%08X ",
+ smu_get_message_name(smu, args->msg), index,
+ resp);
+ if (args->num_args > 0)
+ print_hex_dump(KERN_ERR,
+ "in params:", DUMP_PREFIX_NONE,
+ 16, 4, args->args,
+ args->num_args * sizeof(u32),
+ false);
+ }
+ break;
+ default:
+ __smu_msg_v1_print_err_limited(ctl, args,
+ "SMU: unknown response");
+ break;
+ }
}
-/**
- * smu_cmn_send_msg_without_waiting -- send the message; don't wait for status
- * @smu: pointer to an SMU context
- * @msg_index: message index
- * @param: message parameter to send to the SMU
- *
- * Send a message to the SMU with the parameter passed. Do not wait
- * for status/result of the message, thus the "without_waiting".
- *
- * Return 0 on success, -errno on error if we weren't able to _send_
- * the message for some reason. See __smu_cmn_reg2errno() for details
- * of the -errno.
- */
-int smu_cmn_send_msg_without_waiting(struct smu_context *smu,
- uint16_t msg_index,
- uint32_t param)
+
+static int __smu_msg_v1_ras_filter(struct smu_msg_ctl *ctl,
+ enum smu_message_type msg, u32 msg_flags,
+ bool *skip_pre_poll)
{
+ struct smu_context *smu = ctl->smu;
struct amdgpu_device *adev = smu->adev;
+ bool fed_status;
u32 reg;
- int res;
- if (adev->no_hw_access)
+ if (!(smu->smc_fw_caps & SMU_FW_CAP_RAS_PRI))
return 0;
- if (smu->smc_fw_state == SMU_FW_HANG) {
- dev_err(adev->dev, "SMU is in hanged state, failed to send smu message!\n");
- res = -EREMOTEIO;
- goto Out;
- }
+ fed_status = amdgpu_ras_get_fed_status(adev);
- if (smu->smc_fw_state == SMU_FW_INIT) {
- smu->smc_fw_state = SMU_FW_RUNTIME;
- } else {
- reg = __smu_cmn_poll_stat(smu);
- res = __smu_cmn_reg2errno(smu, reg);
- if (reg == SMU_RESP_NONE || res == -EREMOTEIO)
- goto Out;
+ /* Block non-RAS-priority messages during RAS error */
+ if (fed_status && !(msg_flags & SMU_MSG_RAS_PRI)) {
+ dev_dbg(adev->dev, "RAS error detected, skip sending %s",
+ smu_get_message_name(smu, msg));
+ return -EACCES;
}
- __smu_cmn_send_msg(smu, msg_index, param);
- res = 0;
-Out:
- if (unlikely(adev->pm.smu_debug_mask & SMU_DEBUG_HALT_ON_ERROR) &&
- res && (res != -ETIME)) {
- amdgpu_device_halt(adev);
- WARN_ON(1);
+ /* Skip pre-poll for priority messages or during RAS error */
+ if ((msg_flags & SMU_MSG_NO_PRECHECK) || fed_status) {
+ reg = RREG32(ctl->config.resp_reg);
+ dev_dbg(adev->dev,
+ "Sending priority message %s response status: %x",
+ smu_get_message_name(smu, msg), reg);
+ if (reg == 0)
+ *skip_pre_poll = true;
}
- return res;
+ return 0;
}
/**
- * smu_cmn_wait_for_response -- wait for response from the SMU
- * @smu: pointer to an SMU context
+ * smu_msg_v1_send_msg - Complete V1 protocol with all filtering
+ * @ctl: Message control block
+ * @args: Message arguments
*
- * Wait for status from the SMU.
- *
- * Return 0 on success, -errno on error, indicating the execution
- * status and result of the message being waited for. See
- * __smu_cmn_reg2errno() for details of the -errno.
+ * Return: 0 on success, negative errno on failure
*/
-int smu_cmn_wait_for_response(struct smu_context *smu)
+static int smu_msg_v1_send_msg(struct smu_msg_ctl *ctl,
+ struct smu_msg_args *args)
{
- u32 reg;
- int res;
+ struct smu_context *smu = ctl->smu;
+ struct amdgpu_device *adev = smu->adev;
+ const struct cmn2asic_msg_mapping *mapping;
+ u32 reg, msg_flags;
+ int ret, index;
+ bool skip_pre_poll = false;
+ bool lock_held = args->flags & SMU_MSG_FLAG_LOCK_HELD;
- reg = __smu_cmn_poll_stat(smu);
- res = __smu_cmn_reg2errno(smu, reg);
+ /* Early exit if no HW access */
+ if (adev->no_hw_access)
+ return 0;
- if (res == -EREMOTEIO)
- smu->smc_fw_state = SMU_FW_HANG;
+ /* Message index translation */
+ if (args->msg >= SMU_MSG_MAX_COUNT || !ctl->message_map)
+ return -EINVAL;
- if (unlikely(smu->adev->pm.smu_debug_mask & SMU_DEBUG_HALT_ON_ERROR) &&
- res && (res != -ETIME)) {
- amdgpu_device_halt(smu->adev);
- WARN_ON(1);
- }
+ if (args->num_args > ctl->config.num_arg_regs ||
+ args->num_out_args > ctl->config.num_arg_regs)
+ return -EINVAL;
- return res;
-}
+ mapping = &ctl->message_map[args->msg];
+ if (!mapping->valid_mapping)
+ return -EINVAL;
-/**
- * smu_cmn_send_smc_msg_with_param -- send a message with parameter
- * @smu: pointer to an SMU context
- * @msg: message to send
- * @param: parameter to send to the SMU
- * @read_arg: pointer to u32 to return a value from the SMU back
- * to the caller
- *
- * Send the message @msg with parameter @param to the SMU, wait for
- * completion of the command, and return back a value from the SMU in
- * @read_arg pointer.
- *
- * Return 0 on success, -errno when a problem is encountered sending
- * message or receiving reply. If there is a PCI bus recovery or
- * the destination is a virtual GPU which does not allow this message
- * type, the message is simply dropped and success is also returned.
- * See __smu_cmn_reg2errno() for details of the -errno.
- *
- * If we weren't able to send the message to the SMU, we also print
- * the error to the standard log.
- *
- * Command completion status is printed only if the -errno is
- * -EREMOTEIO, indicating that the SMU returned back an
- * undefined/unknown/unspecified result. All other cases are
- * well-defined, not printed, but instead given back to the client to
- * decide what further to do.
- *
- * The return value, @read_arg is read back regardless, to give back
- * more information to the client, which on error would most likely be
- * @param, but we can't assume that. This also eliminates more
- * conditionals.
- */
-int smu_cmn_send_smc_msg_with_param(struct smu_context *smu,
- enum smu_message_type msg,
- uint32_t param,
- uint32_t *read_arg)
-{
- struct amdgpu_device *adev = smu->adev;
- int res, index;
- bool poll = true;
- u32 reg;
+ msg_flags = mapping->flags;
+ index = mapping->map_to;
- if (adev->no_hw_access)
+ /* VF filter - skip messages not valid for VF */
+ if (amdgpu_sriov_vf(adev) && !(msg_flags & SMU_MSG_VF_FLAG))
return 0;
- index = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_MSG,
- msg);
- if (index < 0)
- return index == -EACCES ? 0 : index;
-
- mutex_lock(&smu->message_lock);
+ if (!lock_held)
+ mutex_lock(&ctl->lock);
- if (smu->smc_fw_caps & SMU_FW_CAP_RAS_PRI) {
- res = __smu_cmn_ras_filter_msg(smu, msg, &poll);
- if (res)
- goto Out;
- }
+ /* RAS priority filter */
+ ret = __smu_msg_v1_ras_filter(ctl, args->msg, msg_flags,
+ &skip_pre_poll);
+ if (ret)
+ goto out;
+ /* FW state checks */
if (smu->smc_fw_state == SMU_FW_HANG) {
- dev_err(adev->dev, "SMU is in hanged state, failed to send smu message!\n");
- res = -EREMOTEIO;
- goto Out;
+ dev_err(adev->dev,
+ "SMU is in hanged state, failed to send smu message!\n");
+ ret = -EREMOTEIO;
+ goto out;
} else if (smu->smc_fw_state == SMU_FW_INIT) {
- /* Ignore initial smu response register value */
- poll = false;
+ skip_pre_poll = true;
smu->smc_fw_state = SMU_FW_RUNTIME;
}
- if (poll) {
- reg = __smu_cmn_poll_stat(smu);
- res = __smu_cmn_reg2errno(smu, reg);
- if (reg == SMU_RESP_NONE || res == -EREMOTEIO) {
- __smu_cmn_reg_print_error(smu, reg, index, param, msg);
- goto Out;
+ /* Pre-poll: ensure previous message completed */
+ if (!skip_pre_poll) {
+ reg = __smu_msg_v1_poll_stat(ctl, args->timeout);
+ ret = smu_msg_v1_decode_response(reg);
+ if (reg == SMU_RESP_NONE || ret == -EREMOTEIO) {
+ __smu_msg_v1_print_error(ctl, reg, args);
+ goto out;
}
}
- __smu_cmn_send_msg(smu, (uint16_t) index, param);
- reg = __smu_cmn_poll_stat(smu);
- res = __smu_cmn_reg2errno(smu, reg);
- if (res != 0) {
- if (res == -EREMOTEIO)
- smu->smc_fw_state = SMU_FW_HANG;
- __smu_cmn_reg_print_error(smu, reg, index, param, msg);
+
+ /* Send message */
+ __smu_msg_v1_send(ctl, (u16)index, args);
+
+ /* Post-poll (skip if ASYNC) */
+ if (args->flags & SMU_MSG_FLAG_ASYNC) {
+ ret = 0;
+ goto out;
+ }
+
+ reg = __smu_msg_v1_poll_stat(ctl, args->timeout);
+ ret = smu_msg_v1_decode_response(reg);
+
+ /* FW state update on fatal error */
+ if (ret == -EREMOTEIO) {
+ smu->smc_fw_state = SMU_FW_HANG;
+ __smu_msg_v1_print_error(ctl, reg, args);
+ } else if (ret != 0) {
+ __smu_msg_v1_print_error(ctl, reg, args);
}
- if (read_arg) {
- smu_cmn_read_arg(smu, read_arg);
- dev_dbg(adev->dev, "smu send message: %s(%d) param: 0x%08x, resp: 0x%08x,\
- readval: 0x%08x\n",
- smu_get_message_name(smu, msg), index, param, reg, *read_arg);
+
+ /* Read output args */
+ if ((ret == 0 || (args->flags & SMU_MSG_FLAG_FORCE_READ_ARG)) &&
+ args->num_out_args > 0) {
+ __smu_msg_v1_read_out_args(ctl, args);
+ dev_dbg(adev->dev, "smu send message: %s(%d) resp : 0x%08x",
+ smu_get_message_name(smu, args->msg), index, reg);
+ if (args->num_args > 0)
+ print_hex_dump_debug("in params:", DUMP_PREFIX_NONE, 16,
+ 4, args->args,
+ args->num_args * sizeof(u32),
+ false);
+ print_hex_dump_debug("out params:", DUMP_PREFIX_NONE, 16, 4,
+ args->out_args,
+ args->num_out_args * sizeof(u32), false);
} else {
- dev_dbg(adev->dev, "smu send message: %s(%d) param: 0x%08x, resp: 0x%08x\n",
- smu_get_message_name(smu, msg), index, param, reg);
+ dev_dbg(adev->dev, "smu send message: %s(%d), resp: 0x%08x\n",
+ smu_get_message_name(smu, args->msg), index, reg);
+ if (args->num_args > 0)
+ print_hex_dump_debug("in params:", DUMP_PREFIX_NONE, 16,
+ 4, args->args,
+ args->num_args * sizeof(u32),
+ false);
}
-Out:
- if (unlikely(adev->pm.smu_debug_mask & SMU_DEBUG_HALT_ON_ERROR) && res) {
+
+out:
+ /* Debug halt on error */
+ if (unlikely(adev->pm.smu_debug_mask & SMU_DEBUG_HALT_ON_ERROR) &&
+ ret) {
amdgpu_device_halt(adev);
WARN_ON(1);
}
- mutex_unlock(&smu->message_lock);
- return res;
+ if (!lock_held)
+ mutex_unlock(&ctl->lock);
+ return ret;
}
-int smu_cmn_send_smc_msg(struct smu_context *smu,
- enum smu_message_type msg,
- uint32_t *read_arg)
+static int smu_msg_v1_wait_response(struct smu_msg_ctl *ctl, u32 timeout_us)
{
- return smu_cmn_send_smc_msg_with_param(smu,
- msg,
- 0,
- read_arg);
+ struct smu_context *smu = ctl->smu;
+ struct amdgpu_device *adev = smu->adev;
+ u32 reg;
+ int ret;
+
+ reg = __smu_msg_v1_poll_stat(ctl, timeout_us);
+ ret = smu_msg_v1_decode_response(reg);
+
+ if (ret == -EREMOTEIO)
+ smu->smc_fw_state = SMU_FW_HANG;
+
+ if (unlikely(adev->pm.smu_debug_mask & SMU_DEBUG_HALT_ON_ERROR) &&
+ ret && (ret != -ETIME)) {
+ amdgpu_device_halt(adev);
+ WARN_ON(1);
+ }
+
+ return ret;
}
-int smu_cmn_send_debug_smc_msg(struct smu_context *smu,
- uint32_t msg)
+const struct smu_msg_ops smu_msg_v1_ops = {
+ .send_msg = smu_msg_v1_send_msg,
+ .wait_response = smu_msg_v1_wait_response,
+ .decode_response = smu_msg_v1_decode_response,
+ .send_debug_msg = smu_msg_v1_send_debug_msg,
+};
+
+int smu_msg_wait_response(struct smu_msg_ctl *ctl, u32 timeout_us)
{
- return __smu_cmn_send_debug_msg(smu, msg, 0);
+ return ctl->ops->wait_response(ctl, timeout_us);
}
-int smu_cmn_send_debug_smc_msg_with_param(struct smu_context *smu,
- uint32_t msg, uint32_t param)
+/**
+ * smu_msg_send_async_locked - Send message asynchronously, caller holds lock
+ * @ctl: Message control block
+ * @msg: Message type
+ * @param: Message parameter
+ *
+ * Send an SMU message without waiting for response. Caller must hold ctl->lock
+ * and call smu_msg_wait_response() later to get the result.
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+int smu_msg_send_async_locked(struct smu_msg_ctl *ctl,
+ enum smu_message_type msg, u32 param)
{
- return __smu_cmn_send_debug_msg(smu, msg, param);
+ struct smu_msg_args args = {
+ .msg = msg,
+ .args[0] = param,
+ .num_args = 1,
+ .num_out_args = 0,
+ .flags = SMU_MSG_FLAG_ASYNC | SMU_MSG_FLAG_LOCK_HELD,
+ .timeout = 0,
+ };
+
+ return ctl->ops->send_msg(ctl, &args);
}
int smu_cmn_to_asic_specific_index(struct smu_context *smu,
@@ -508,10 +647,10 @@ int smu_cmn_to_asic_specific_index(struct smu_context *smu,
switch (type) {
case CMN2ASIC_MAPPING_MSG:
if (index >= SMU_MSG_MAX_COUNT ||
- !smu->message_map)
+ !smu->msg_ctl.message_map)
return -EINVAL;
- msg_mapping = smu->message_map[index];
+ msg_mapping = smu->msg_ctl.message_map[index];
if (!msg_mapping.valid_mapping)
return -EINVAL;
@@ -584,7 +723,6 @@ int smu_cmn_to_asic_specific_index(struct smu_context *smu,
int smu_cmn_feature_is_supported(struct smu_context *smu,
enum smu_feature_mask mask)
{
- struct smu_feature *feature = &smu->smu_feature;
int feature_id;
feature_id = smu_cmn_to_asic_specific_index(smu,
@@ -593,13 +731,12 @@ int smu_cmn_feature_is_supported(struct smu_context *smu,
if (feature_id < 0)
return 0;
- WARN_ON(feature_id > feature->feature_num);
-
- return test_bit(feature_id, feature->supported);
+ return smu_feature_list_is_set(smu, SMU_FEATURE_LIST_SUPPORTED,
+ feature_id);
}
static int __smu_get_enabled_features(struct smu_context *smu,
- uint64_t *enabled_features)
+ struct smu_feature_bits *enabled_features)
{
return smu_cmn_call_asic_func(get_enabled_mask, smu, enabled_features);
}
@@ -608,7 +745,7 @@ int smu_cmn_feature_is_enabled(struct smu_context *smu,
enum smu_feature_mask mask)
{
struct amdgpu_device *adev = smu->adev;
- uint64_t enabled_features;
+ struct smu_feature_bits enabled_features;
int feature_id;
if (__smu_get_enabled_features(smu, &enabled_features)) {
@@ -621,7 +758,8 @@ int smu_cmn_feature_is_enabled(struct smu_context *smu,
* enabled. Also considering they have no feature_map available, the
* check here can avoid unwanted feature_map check below.
*/
- if (enabled_features == ULLONG_MAX)
+ if (smu_feature_bits_full(&enabled_features,
+ smu->smu_feature.feature_num))
return 1;
feature_id = smu_cmn_to_asic_specific_index(smu,
@@ -630,7 +768,7 @@ int smu_cmn_feature_is_enabled(struct smu_context *smu,
if (feature_id < 0)
return 0;
- return test_bit(feature_id, (unsigned long *)&enabled_features);
+ return smu_feature_bits_is_set(&enabled_features, feature_id);
}
bool smu_cmn_clk_dpm_is_enabled(struct smu_context *smu,
@@ -672,45 +810,39 @@ bool smu_cmn_clk_dpm_is_enabled(struct smu_context *smu,
}
int smu_cmn_get_enabled_mask(struct smu_context *smu,
- uint64_t *feature_mask)
+ struct smu_feature_bits *feature_mask)
{
- uint32_t *feature_mask_high;
- uint32_t *feature_mask_low;
+ uint32_t features[2];
int ret = 0, index = 0;
if (!feature_mask)
return -EINVAL;
- feature_mask_low = &((uint32_t *)feature_mask)[0];
- feature_mask_high = &((uint32_t *)feature_mask)[1];
-
index = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_MSG,
SMU_MSG_GetEnabledSmuFeatures);
if (index > 0) {
- ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_GetEnabledSmuFeatures,
- 0,
- feature_mask_low);
+ ret = smu_cmn_send_smc_msg_with_param(
+ smu, SMU_MSG_GetEnabledSmuFeatures, 0, &features[0]);
if (ret)
return ret;
- ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_GetEnabledSmuFeatures,
- 1,
- feature_mask_high);
+ ret = smu_cmn_send_smc_msg_with_param(
+ smu, SMU_MSG_GetEnabledSmuFeatures, 1, &features[1]);
} else {
- ret = smu_cmn_send_smc_msg(smu,
- SMU_MSG_GetEnabledSmuFeaturesHigh,
- feature_mask_high);
+ ret = smu_cmn_send_smc_msg(
+ smu, SMU_MSG_GetEnabledSmuFeaturesHigh, &features[1]);
if (ret)
return ret;
- ret = smu_cmn_send_smc_msg(smu,
- SMU_MSG_GetEnabledSmuFeaturesLow,
- feature_mask_low);
+ ret = smu_cmn_send_smc_msg(
+ smu, SMU_MSG_GetEnabledSmuFeaturesLow, &features[0]);
}
+ if (!ret)
+ smu_feature_bits_from_arr32(feature_mask, features,
+ SMU_FEATURE_NUM_DEFAULT);
+
return ret;
}
@@ -794,8 +926,9 @@ static const char *smu_get_feature_name(struct smu_context *smu,
size_t smu_cmn_get_pp_feature_mask(struct smu_context *smu,
char *buf)
{
- int8_t sort_feature[MAX(SMU_FEATURE_COUNT, SMU_FEATURE_MAX)];
- uint64_t feature_mask;
+ int16_t sort_feature[MAX(SMU_FEATURE_COUNT, SMU_FEATURE_MAX)];
+ struct smu_feature_bits feature_mask;
+ uint32_t features[2];
int i, feature_index;
uint32_t count = 0;
size_t size = 0;
@@ -803,8 +936,10 @@ size_t smu_cmn_get_pp_feature_mask(struct smu_context *smu,
if (__smu_get_enabled_features(smu, &feature_mask))
return 0;
- size = sysfs_emit_at(buf, size, "features high: 0x%08x low: 0x%08x\n",
- upper_32_bits(feature_mask), lower_32_bits(feature_mask));
+ /* TBD: Need to handle for > 64 bits */
+ smu_feature_bits_to_arr32(&feature_mask, features, 64);
+ size = sysfs_emit_at(buf, size, "features high: 0x%08x low: 0x%08x\n",
+ features[1], features[0]);
memset(sort_feature, -1, sizeof(sort_feature));
@@ -821,16 +956,18 @@ size_t smu_cmn_get_pp_feature_mask(struct smu_context *smu,
size += sysfs_emit_at(buf, size, "%-2s. %-20s %-3s : %-s\n",
"No", "Feature", "Bit", "State");
- for (feature_index = 0; feature_index < SMU_FEATURE_MAX; feature_index++) {
+ for (feature_index = 0; feature_index < smu->smu_feature.feature_num;
+ feature_index++) {
if (sort_feature[feature_index] < 0)
continue;
- size += sysfs_emit_at(buf, size, "%02d. %-20s (%2d) : %s\n",
- count++,
- smu_get_feature_name(smu, sort_feature[feature_index]),
- feature_index,
- !!test_bit(feature_index, (unsigned long *)&feature_mask) ?
- "enabled" : "disabled");
+ size += sysfs_emit_at(
+ buf, size, "%02d. %-20s (%2d) : %s\n", count++,
+ smu_get_feature_name(smu, sort_feature[feature_index]),
+ feature_index,
+ smu_feature_bits_is_set(&feature_mask, feature_index) ?
+ "enabled" :
+ "disabled");
}
return size;
@@ -840,7 +977,8 @@ int smu_cmn_set_pp_feature_mask(struct smu_context *smu,
uint64_t new_mask)
{
int ret = 0;
- uint64_t feature_mask;
+ struct smu_feature_bits feature_mask;
+ uint64_t feature_mask_u64;
uint64_t feature_2_enabled = 0;
uint64_t feature_2_disabled = 0;
@@ -848,8 +986,9 @@ int smu_cmn_set_pp_feature_mask(struct smu_context *smu,
if (ret)
return ret;
- feature_2_enabled = ~feature_mask & new_mask;
- feature_2_disabled = feature_mask & ~new_mask;
+ feature_mask_u64 = *(uint64_t *)feature_mask.bits;
+ feature_2_enabled = ~feature_mask_u64 & new_mask;
+ feature_2_disabled = feature_mask_u64 & ~new_mask;
if (feature_2_enabled) {
ret = smu_cmn_feature_update_enable_state(smu,
@@ -942,21 +1081,49 @@ int smu_cmn_get_smc_version(struct smu_context *smu,
return ret;
}
-int smu_cmn_update_table(struct smu_context *smu,
- enum smu_table_id table_index,
- int argument,
- void *table_data,
- bool drv2smu)
+int smu_cmn_check_fw_version(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+ uint32_t if_version = 0xff, smu_version = 0xff;
+ uint8_t smu_program, smu_major, smu_minor, smu_debug;
+ int ret;
+
+ ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version);
+ if (ret)
+ return ret;
+
+ smu_program = (smu_version >> 24) & 0xff;
+ smu_major = (smu_version >> 16) & 0xff;
+ smu_minor = (smu_version >> 8) & 0xff;
+ smu_debug = (smu_version >> 0) & 0xff;
+ adev->pm.fw_version = smu_version;
+
+ dev_info_once(adev->dev, "smu driver if version = 0x%08x, smu fw if version = 0x%08x, "
+ "smu fw program = %d, smu fw version = 0x%08x (%d.%d.%d)\n",
+ smu->smc_driver_if_version, if_version,
+ smu_program, smu_version, smu_major, smu_minor, smu_debug);
+
+ return 0;
+}
+
+int smu_cmn_update_table_read_arg(struct smu_context *smu,
+ enum smu_table_id table_index,
+ int argument,
+ void *table_data,
+ uint32_t *read_arg,
+ bool drv2smu)
{
- struct smu_table_context *smu_table = &smu->smu_table;
struct amdgpu_device *adev = smu->adev;
+ struct smu_table_context *smu_table = &smu->smu_table;
struct smu_table *table = &smu_table->driver_table;
int table_id = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_TABLE,
table_index);
uint32_t table_size;
int ret = 0;
- if (!table_data || table_id >= SMU_TABLE_COUNT || table_id < 0)
+ uint32_t param;
+
+ if (!table_data || table_index >= SMU_TABLE_COUNT || table_id < 0)
return -EINVAL;
table_size = smu_table->tables[table_index].size;
@@ -967,25 +1134,41 @@ int smu_cmn_update_table(struct smu_context *smu,
* Flush hdp cache: to guard the content seen by
* GPU is consitent with CPU.
*/
- amdgpu_asic_flush_hdp(adev, NULL);
+ amdgpu_hdp_flush(adev, NULL);
}
- ret = smu_cmn_send_smc_msg_with_param(smu, drv2smu ?
- SMU_MSG_TransferTableDram2Smu :
- SMU_MSG_TransferTableSmu2Dram,
- table_id | ((argument & 0xFFFF) << 16),
- NULL);
+ param = ((argument & 0xFFFF) << 16) | (table_id & 0xffff);
+
+ ret = smu_cmn_send_smc_msg_with_params_ext(
+ smu,
+ drv2smu ? SMU_MSG_TransferTableDram2Smu :
+ SMU_MSG_TransferTableSmu2Dram,
+ &param, 1, read_arg, read_arg ? 1 : 0,
+ read_arg ? SMU_MSG_FLAG_FORCE_READ_ARG : 0, 0);
+
if (ret)
return ret;
if (!drv2smu) {
- amdgpu_asic_invalidate_hdp(adev, NULL);
+ amdgpu_hdp_invalidate(adev, NULL);
memcpy(table_data, table->cpu_addr, table_size);
}
return 0;
}
+int smu_cmn_vram_cpy(struct smu_context *smu, void *dst, const void *src,
+ size_t len)
+{
+ memcpy(dst, src, len);
+
+ /* Don't trust the copy operation if RAS fatal error happened. */
+ if (amdgpu_ras_get_fed_status(smu->adev))
+ return -EHWPOISON;
+
+ return 0;
+}
+
int smu_cmn_write_watermarks_table(struct smu_context *smu)
{
void *watermarks_table = smu->smu_table.watermarks_table;
@@ -1052,70 +1235,6 @@ int smu_cmn_get_combo_pptable(struct smu_context *smu)
false);
}
-void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev)
-{
- struct metrics_table_header *header = (struct metrics_table_header *)table;
- uint16_t structure_size;
-
-#define METRICS_VERSION(a, b) ((a << 16) | b)
-
- switch (METRICS_VERSION(frev, crev)) {
- case METRICS_VERSION(1, 0):
- structure_size = sizeof(struct gpu_metrics_v1_0);
- break;
- case METRICS_VERSION(1, 1):
- structure_size = sizeof(struct gpu_metrics_v1_1);
- break;
- case METRICS_VERSION(1, 2):
- structure_size = sizeof(struct gpu_metrics_v1_2);
- break;
- case METRICS_VERSION(1, 3):
- structure_size = sizeof(struct gpu_metrics_v1_3);
- break;
- case METRICS_VERSION(1, 4):
- structure_size = sizeof(struct gpu_metrics_v1_4);
- break;
- case METRICS_VERSION(1, 5):
- structure_size = sizeof(struct gpu_metrics_v1_5);
- break;
- case METRICS_VERSION(1, 6):
- structure_size = sizeof(struct gpu_metrics_v1_6);
- break;
- case METRICS_VERSION(1, 7):
- structure_size = sizeof(struct gpu_metrics_v1_7);
- break;
- case METRICS_VERSION(2, 0):
- structure_size = sizeof(struct gpu_metrics_v2_0);
- break;
- case METRICS_VERSION(2, 1):
- structure_size = sizeof(struct gpu_metrics_v2_1);
- break;
- case METRICS_VERSION(2, 2):
- structure_size = sizeof(struct gpu_metrics_v2_2);
- break;
- case METRICS_VERSION(2, 3):
- structure_size = sizeof(struct gpu_metrics_v2_3);
- break;
- case METRICS_VERSION(2, 4):
- structure_size = sizeof(struct gpu_metrics_v2_4);
- break;
- case METRICS_VERSION(3, 0):
- structure_size = sizeof(struct gpu_metrics_v3_0);
- break;
- default:
- return;
- }
-
-#undef METRICS_VERSION
-
- memset(header, 0xFF, structure_size);
-
- header->format_revision = frev;
- header->content_revision = crev;
- header->structure_size = structure_size;
-
-}
-
int smu_cmn_set_mp1_state(struct smu_context *smu,
enum pp_mp1_state mp1_state)
{
@@ -1246,3 +1365,182 @@ void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
*backend_workload_mask |= 1 << workload_type;
}
}
+
+void smu_cmn_reset_custom_level(struct smu_context *smu)
+{
+ struct smu_umd_pstate_table *pstate_table = &smu->pstate_table;
+
+ pstate_table->gfxclk_pstate.custom.min = 0;
+ pstate_table->gfxclk_pstate.custom.max = 0;
+ pstate_table->uclk_pstate.custom.min = 0;
+ pstate_table->uclk_pstate.custom.max = 0;
+}
+
+static inline bool smu_cmn_freqs_match(uint32_t freq1, uint32_t freq2)
+{
+ /* Frequencies within 25 MHz are considered equal */
+ return (abs((int)freq1 - (int)freq2) <= 25);
+}
+
+int smu_cmn_print_dpm_clk_levels(struct smu_context *smu,
+ struct smu_dpm_table *dpm_table,
+ uint32_t cur_clk, char *buf, int *offset)
+{
+ uint32_t min_clk, max_clk, level_index, count;
+ uint32_t freq_values[3];
+ int size, lvl, i;
+ bool is_fine_grained;
+ bool is_deep_sleep;
+ bool freq_match;
+
+ if (!dpm_table || !buf)
+ return -EINVAL;
+
+ level_index = 0;
+ size = *offset;
+ count = dpm_table->count;
+ is_fine_grained = dpm_table->flags & SMU_DPM_TABLE_FINE_GRAINED;
+ 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;
+ if (is_deep_sleep) {
+ size += sysfs_emit_at(buf, size, "S: %uMhz *\n", cur_clk);
+ level_index = 1;
+ }
+
+ if (!is_fine_grained || count == 1) {
+ 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 ? "*" : "");
+ }
+ } else {
+ count = 2;
+ freq_values[0] = min_clk;
+ freq_values[1] = max_clk;
+
+ if (!is_deep_sleep) {
+ if (smu_cmn_freqs_match(cur_clk, min_clk)) {
+ lvl = 0;
+ } else if (smu_cmn_freqs_match(cur_clk, max_clk)) {
+ lvl = 1;
+ } else {
+ /* NOTE: use index '1' to show current clock value */
+ lvl = 1;
+ count = 3;
+ freq_values[1] = cur_clk;
+ freq_values[2] = max_clk;
+ }
+ }
+
+ for (i = 0; i < count; i++) {
+ size += sysfs_emit_at(
+ buf, size, "%d: %uMhz %s\n", level_index + i,
+ freq_values[i],
+ (!is_deep_sleep && i == lvl) ? "*" : "");
+ }
+ }
+
+ *offset = size;
+
+ return 0;
+}
+
+int smu_cmn_print_pcie_levels(struct smu_context *smu,
+ struct smu_pcie_table *pcie_table,
+ uint32_t cur_gen, uint32_t cur_lane, char *buf,
+ int *offset)
+{
+ int size, i;
+
+ if (!pcie_table || !buf)
+ return -EINVAL;
+
+ size = *offset;
+
+ for (i = 0; i < pcie_table->lclk_levels; i++) {
+ size += sysfs_emit_at(
+ buf, size, "%d: %s %s %dMhz %s\n", i,
+ (pcie_table->pcie_gen[i] == 0) ? "2.5GT/s," :
+ (pcie_table->pcie_gen[i] == 1) ? "5.0GT/s," :
+ (pcie_table->pcie_gen[i] == 2) ? "8.0GT/s," :
+ (pcie_table->pcie_gen[i] == 3) ? "16.0GT/s," :
+ (pcie_table->pcie_gen[i] == 4) ? "32.0GT/s," :
+ (pcie_table->pcie_gen[i] == 5) ? "64.0GT/s," :
+ "",
+ (pcie_table->pcie_lane[i] == 1) ? "x1" :
+ (pcie_table->pcie_lane[i] == 2) ? "x2" :
+ (pcie_table->pcie_lane[i] == 3) ? "x4" :
+ (pcie_table->pcie_lane[i] == 4) ? "x8" :
+ (pcie_table->pcie_lane[i] == 5) ? "x12" :
+ (pcie_table->pcie_lane[i] == 6) ? "x16" :
+ (pcie_table->pcie_lane[i] == 7) ? "x32" :
+ "",
+ pcie_table->lclk_freq[i],
+ (cur_gen == pcie_table->pcie_gen[i]) &&
+ (cur_lane == pcie_table->pcie_lane[i]) ?
+ "*" :
+ "");
+ }
+
+ *offset = size;
+
+ return 0;
+}
+
+int smu_cmn_dpm_pcie_gen_idx(int gen)
+{
+ int ret;
+
+ switch (gen) {
+ case 1 ... 5:
+ ret = gen - 1;
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
+
+int smu_cmn_dpm_pcie_width_idx(int width)
+{
+ int ret;
+
+ switch (width) {
+ case 1:
+ ret = 1;
+ break;
+ case 2:
+ ret = 2;
+ break;
+ case 4:
+ ret = 3;
+ break;
+ case 8:
+ ret = 4;
+ break;
+ case 12:
+ ret = 5;
+ break;
+ case 16:
+ ret = 6;
+ break;
+ case 32:
+ ret = 7;
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
index a020277dec3e..0e119965ce13 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
@@ -25,6 +25,12 @@
#include "amdgpu_smu.h"
+extern const struct smu_msg_ops smu_msg_v1_ops;
+
+int smu_msg_wait_response(struct smu_msg_ctl *ctl, u32 timeout_us);
+int smu_msg_send_async_locked(struct smu_msg_ctl *ctl,
+ enum smu_message_type msg, u32 param);
+
#if defined(SWSMU_CODE_LAYER_L2) || defined(SWSMU_CODE_LAYER_L3) || defined(SWSMU_CODE_LAYER_L4)
#define FDO_PWM_MODE_STATIC 1
@@ -40,6 +46,65 @@
#define SMU_IH_INTERRUPT_CONTEXT_ID_FAN_ABNORMAL 0x8
#define SMU_IH_INTERRUPT_CONTEXT_ID_FAN_RECOVERY 0x9
+#define SMU_IGNORE_IF_VERSION 0xFFFFFFFF
+
+#define smu_cmn_init_soft_gpu_metrics(ptr, frev, crev) \
+ do { \
+ typecheck(struct gpu_metrics_v##frev##_##crev *, (ptr)); \
+ struct gpu_metrics_v##frev##_##crev *tmp = (ptr); \
+ struct metrics_table_header *header = \
+ (struct metrics_table_header *)tmp; \
+ memset(header, 0xFF, sizeof(*tmp)); \
+ header->format_revision = frev; \
+ header->content_revision = crev; \
+ header->structure_size = sizeof(*tmp); \
+ } while (0)
+
+#define smu_cmn_init_partition_metrics(ptr, fr, cr) \
+ do { \
+ typecheck(struct amdgpu_partition_metrics_v##fr##_##cr *, \
+ (ptr)); \
+ struct amdgpu_partition_metrics_v##fr##_##cr *tmp = (ptr); \
+ struct metrics_table_header *header = \
+ (struct metrics_table_header *)tmp; \
+ memset(header, 0xFF, sizeof(*tmp)); \
+ header->format_revision = fr; \
+ header->content_revision = cr; \
+ header->structure_size = sizeof(*tmp); \
+ } while (0)
+
+#define smu_cmn_init_baseboard_temp_metrics(ptr, fr, cr) \
+ do { \
+ typecheck(struct amdgpu_baseboard_temp_metrics_v##fr##_##cr *, \
+ (ptr)); \
+ struct amdgpu_baseboard_temp_metrics_v##fr##_##cr *tmp = (ptr); \
+ struct metrics_table_header *header = \
+ (struct metrics_table_header *)tmp; \
+ memset(header, 0xFF, sizeof(*tmp)); \
+ header->format_revision = fr; \
+ header->content_revision = cr; \
+ header->structure_size = sizeof(*tmp); \
+ } while (0)
+
+#define smu_cmn_init_gpuboard_temp_metrics(ptr, fr, cr) \
+ do { \
+ typecheck(struct amdgpu_gpuboard_temp_metrics_v##fr##_##cr *, \
+ (ptr)); \
+ struct amdgpu_gpuboard_temp_metrics_v##fr##_##cr *tmp = (ptr); \
+ struct metrics_table_header *header = \
+ (struct metrics_table_header *)tmp; \
+ memset(header, 0xFF, sizeof(*tmp)); \
+ header->format_revision = fr; \
+ header->content_revision = cr; \
+ header->structure_size = sizeof(*tmp); \
+ } while (0)
+
+#define SMU_DPM_PCIE_GEN_IDX(gen) smu_cmn_dpm_pcie_gen_idx((gen))
+#define SMU_DPM_PCIE_WIDTH_IDX(width) smu_cmn_dpm_pcie_width_idx((width))
+
+#define smu_cmn_update_table(smu, table_index, argument, table_data, drv2smu) \
+ smu_cmn_update_table_read_arg((smu), (table_index), (argument), (table_data), NULL, (drv2smu))
+
extern const int link_speed[];
/* Helper to Convert from PCIE Gen 1/2/3/4/5/6 to 0.1 GT/s speed units */
@@ -48,14 +113,33 @@ static inline int pcie_gen_to_speed(uint32_t gen)
return ((gen == 0) ? link_speed[0] : link_speed[gen - 1]);
}
-int smu_cmn_send_msg_without_waiting(struct smu_context *smu,
- uint16_t msg_index,
- uint32_t param);
int smu_cmn_send_smc_msg_with_param(struct smu_context *smu,
enum smu_message_type msg,
uint32_t param,
uint32_t *read_arg);
+int smu_cmn_send_smc_msg_with_params_ext(struct smu_context *smu,
+ enum smu_message_type msg,
+ const uint32_t *params,
+ size_t num_params,
+ uint32_t *read_args,
+ size_t num_read_args,
+ uint32_t flags,
+ uint32_t timeout);
+
+static inline int smu_cmn_send_smc_msg_with_params(struct smu_context *smu,
+ enum smu_message_type msg,
+ const uint32_t *params,
+ size_t num_params,
+ uint32_t *read_args,
+ size_t num_read_args)
+{
+ return smu_cmn_send_smc_msg_with_params_ext(smu, msg,
+ params, num_params,
+ read_args, num_read_args,
+ 0, 0);
+}
+
int smu_cmn_send_smc_msg(struct smu_context *smu,
enum smu_message_type msg,
uint32_t *read_arg);
@@ -82,7 +166,7 @@ bool smu_cmn_clk_dpm_is_enabled(struct smu_context *smu,
enum smu_clk_type clk_type);
int smu_cmn_get_enabled_mask(struct smu_context *smu,
- uint64_t *feature_mask);
+ struct smu_feature_bits *feature_mask);
uint64_t smu_cmn_get_indep_throttler_status(
const unsigned long dep_status,
@@ -109,11 +193,15 @@ int smu_cmn_get_smc_version(struct smu_context *smu,
uint32_t *if_version,
uint32_t *smu_version);
-int smu_cmn_update_table(struct smu_context *smu,
- enum smu_table_id table_index,
- int argument,
- void *table_data,
- bool drv2smu);
+int smu_cmn_update_table_read_arg(struct smu_context *smu,
+ enum smu_table_id table_index,
+ int argument,
+ void *table_data,
+ uint32_t *read_arg,
+ bool drv2smu);
+
+int smu_cmn_vram_cpy(struct smu_context *smu, void *dst,
+ const void *src, size_t len);
int smu_cmn_write_watermarks_table(struct smu_context *smu);
@@ -125,24 +213,9 @@ int smu_cmn_get_metrics_table(struct smu_context *smu,
int smu_cmn_get_combo_pptable(struct smu_context *smu);
-void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev);
-
int smu_cmn_set_mp1_state(struct smu_context *smu,
enum pp_mp1_state mp1_state);
-/*
- * Helper function to make sysfs_emit_at() happy. Align buf to
- * the current page boundary and record the offset.
- */
-static inline void smu_cmn_get_sysfs_buf(char **buf, int *offset)
-{
- if (!*buf || !offset)
- return;
-
- *offset = offset_in_page(*buf);
- *buf -= *offset;
-}
-
bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev);
void smu_cmn_generic_soc_policy_desc(struct smu_dpm_policy *policy);
void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy);
@@ -151,5 +224,87 @@ void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
u32 workload_mask,
u32 *backend_workload_mask);
+int smu_cmn_print_dpm_clk_levels(struct smu_context *smu,
+ struct smu_dpm_table *dpm_table,
+ uint32_t cur_clk,
+ char *buf, int *offset);
+
+int smu_cmn_print_pcie_levels(struct smu_context *smu,
+ struct smu_pcie_table *pcie_table,
+ uint32_t cur_gen, uint32_t cur_lane,
+ char *buf, int *offset);
+void smu_cmn_reset_custom_level(struct smu_context *smu);
+
+int smu_cmn_dpm_pcie_gen_idx(int gen);
+int smu_cmn_dpm_pcie_width_idx(int width);
+int smu_cmn_check_fw_version(struct smu_context *smu);
+
+/*SMU gpu metrics */
+
+/* Attribute ID mapping */
+#define SMU_MATTR(X) AMDGPU_METRICS_ATTR_ID_##X
+/* Type ID mapping */
+#define SMU_MTYPE(X) AMDGPU_METRICS_TYPE_##X
+/* Unit ID mapping */
+#define SMU_MUNIT(X) AMDGPU_METRICS_UNIT_##X
+
+/* Map TYPEID to C type */
+#define SMU_CTYPE(TYPEID) SMU_CTYPE_##TYPEID
+
+#define SMU_CTYPE_AMDGPU_METRICS_TYPE_U8 u8
+#define SMU_CTYPE_AMDGPU_METRICS_TYPE_S8 s8
+#define SMU_CTYPE_AMDGPU_METRICS_TYPE_U16 u16
+#define SMU_CTYPE_AMDGPU_METRICS_TYPE_S16 s16
+#define SMU_CTYPE_AMDGPU_METRICS_TYPE_U32 u32
+#define SMU_CTYPE_AMDGPU_METRICS_TYPE_S32 s32
+#define SMU_CTYPE_AMDGPU_METRICS_TYPE_U64 u64
+#define SMU_CTYPE_AMDGPU_METRICS_TYPE_S64 s64
+
+/* struct members */
+#define SMU_METRICS_SCALAR(ID, UNIT, TYPEID, NAME) \
+ u64 NAME##_ftype; \
+ SMU_CTYPE(TYPEID) NAME
+
+#define SMU_METRICS_ARRAY(ID, UNIT, TYPEID, NAME, SIZE) \
+ u64 NAME##_ftype; \
+ SMU_CTYPE(TYPEID) NAME[SIZE]
+
+/* Init functions for scalar/array fields - init to 0xFFs */
+#define SMU_METRICS_INIT_SCALAR(ID, UNIT, TYPEID, NAME) \
+ do { \
+ obj->NAME##_ftype = \
+ AMDGPU_METRICS_ENC_ATTR(UNIT, TYPEID, ID, 1); \
+ obj->NAME = (SMU_CTYPE(TYPEID)) ~0; \
+ count++; \
+ } while (0)
+
+#define SMU_METRICS_INIT_ARRAY(ID, UNIT, TYPEID, NAME, SIZE) \
+ do { \
+ obj->NAME##_ftype = \
+ AMDGPU_METRICS_ENC_ATTR(UNIT, TYPEID, ID, SIZE); \
+ memset(obj->NAME, 0xFF, sizeof(obj->NAME)); \
+ count++; \
+ } while (0)
+
+/* Declare Metrics Class and Template object */
+#define DECLARE_SMU_METRICS_CLASS(CLASSNAME, SMU_METRICS_FIELD_LIST) \
+ struct __packed CLASSNAME { \
+ struct metrics_table_header header; \
+ int attr_count; \
+ SMU_METRICS_FIELD_LIST(SMU_METRICS_SCALAR, SMU_METRICS_ARRAY); \
+ }; \
+ static inline void CLASSNAME##_init(struct CLASSNAME *obj, \
+ uint8_t frev, uint8_t crev) \
+ { \
+ int count = 0; \
+ memset(obj, 0xFF, sizeof(*obj)); \
+ obj->header.format_revision = frev; \
+ obj->header.content_revision = crev; \
+ obj->header.structure_size = sizeof(*obj); \
+ SMU_METRICS_FIELD_LIST(SMU_METRICS_INIT_SCALAR, \
+ SMU_METRICS_INIT_ARRAY) \
+ obj->attr_count = count; \
+ }
+
#endif
#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h
index c09ecf1a68a0..24848da90234 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h
@@ -54,8 +54,6 @@
#define smu_system_features_control(smu, en) smu_ppt_funcs(system_features_control, 0, smu, en)
#define smu_init_max_sustainable_clocks(smu) smu_ppt_funcs(init_max_sustainable_clocks, 0, smu)
#define smu_set_default_od_settings(smu) smu_ppt_funcs(set_default_od_settings, 0, smu)
-#define smu_send_smc_msg_with_param(smu, msg, param, read_arg) smu_ppt_funcs(send_smc_msg_with_param, 0, smu, msg, param, read_arg)
-#define smu_send_smc_msg(smu, msg, read_arg) smu_ppt_funcs(send_smc_msg, 0, smu, msg, read_arg)
#define smu_init_display_count(smu, count) smu_ppt_funcs(init_display_count, 0, smu, count)
#define smu_feature_set_allowed_mask(smu) smu_ppt_funcs(set_allowed_mask, 0, smu)
#define smu_feature_get_enabled_mask(smu, mask) smu_ppt_funcs(get_enabled_mask, -EOPNOTSUPP, smu, mask)
@@ -72,7 +70,7 @@
#define smu_apply_clocks_adjust_rules(smu) smu_ppt_funcs(apply_clocks_adjust_rules, 0, smu)
#define smu_notify_smc_display_config(smu) smu_ppt_funcs(notify_smc_display_config, 0, smu)
#define smu_run_btc(smu) smu_ppt_funcs(run_btc, 0, smu)
-#define smu_get_allowed_feature_mask(smu, feature_mask, num) smu_ppt_funcs(get_allowed_feature_mask, 0, smu, feature_mask, num)
+#define smu_init_allowed_features(smu) smu_ppt_funcs(init_allowed_features, 0, smu)
#define smu_set_watermarks_table(smu, clock_ranges) smu_ppt_funcs(set_watermarks_table, 0, smu, clock_ranges)
#define smu_thermal_temperature_range_update(smu, range, rw) smu_ppt_funcs(thermal_temperature_range_update, 0, smu, range, rw)
#define smu_register_irq_handler(smu) smu_ppt_funcs(register_irq_handler, 0, smu)
@@ -100,6 +98,7 @@
#define smu_is_asic_wbrf_supported(smu) smu_ppt_funcs(is_asic_wbrf_supported, false, smu)
#define smu_enable_uclk_shadow(smu, enable) smu_ppt_funcs(enable_uclk_shadow, 0, smu, enable)
#define smu_set_wbrf_exclusion_ranges(smu, freq_band_range) smu_ppt_funcs(set_wbrf_exclusion_ranges, -EOPNOTSUPP, smu, freq_band_range)
+#define smu_get_ras_smu_drv(smu, ras_smu_drv) smu_ppt_funcs(get_ras_smu_drv, -EOPNOTSUPP, smu, ras_smu_drv)
#endif
#endif