summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c')
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c1204
1 files changed, 826 insertions, 378 deletions
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 1ba42b69ce74..7c9f77124ab2 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
@@ -27,6 +27,7 @@
#include <linux/pci.h>
#include <linux/i2c.h>
#include "amdgpu.h"
+#include "amdgpu_dpm.h"
#include "amdgpu_smu.h"
#include "atomfirmware.h"
#include "amdgpu_atomfirmware.h"
@@ -57,8 +58,6 @@
#undef pr_info
#undef pr_debug
-#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_PREFETCHER_BIT) | \
@@ -86,21 +85,21 @@ static struct cmn2asic_msg_mapping navi10_message_map[SMU_MSG_MAX_COUNT] = {
MSG_MAP(DisableSmuFeaturesHigh, PPSMC_MSG_DisableSmuFeaturesHigh, 0),
MSG_MAP(GetEnabledSmuFeaturesLow, PPSMC_MSG_GetEnabledSmuFeaturesLow, 1),
MSG_MAP(GetEnabledSmuFeaturesHigh, PPSMC_MSG_GetEnabledSmuFeaturesHigh, 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, 0),
- MSG_MAP(SetDriverDramAddrLow, PPSMC_MSG_SetDriverDramAddrLow, 0),
+ 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(TransferTableSmu2Dram, PPSMC_MSG_TransferTableSmu2Dram, 0),
+ MSG_MAP(TransferTableSmu2Dram, PPSMC_MSG_TransferTableSmu2Dram, 1),
MSG_MAP(TransferTableDram2Smu, PPSMC_MSG_TransferTableDram2Smu, 0),
MSG_MAP(UseDefaultPPTable, PPSMC_MSG_UseDefaultPPTable, 0),
MSG_MAP(UseBackupPPTable, PPSMC_MSG_UseBackupPPTable, 0),
MSG_MAP(RunBtc, PPSMC_MSG_RunBtc, 0),
MSG_MAP(EnterBaco, PPSMC_MSG_EnterBaco, 0),
- MSG_MAP(SetSoftMinByFreq, PPSMC_MSG_SetSoftMinByFreq, 0),
- MSG_MAP(SetSoftMaxByFreq, PPSMC_MSG_SetSoftMaxByFreq, 0),
- MSG_MAP(SetHardMinByFreq, PPSMC_MSG_SetHardMinByFreq, 1),
+ MSG_MAP(SetSoftMinByFreq, PPSMC_MSG_SetSoftMinByFreq, 1),
+ MSG_MAP(SetSoftMaxByFreq, PPSMC_MSG_SetSoftMaxByFreq, 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),
@@ -137,7 +136,7 @@ static struct cmn2asic_msg_mapping navi10_message_map[SMU_MSG_MAX_COUNT] = {
MSG_MAP(PowerDownJpeg, PPSMC_MSG_PowerDownJpeg, 0),
MSG_MAP(BacoAudioD3PME, PPSMC_MSG_BacoAudioD3PME, 0),
MSG_MAP(ArmD3, PPSMC_MSG_ArmD3, 0),
- MSG_MAP(DAL_DISABLE_DUMMY_PSTATE_CHANGE,PPSMC_MSG_DALDisableDummyPstateChange, 0),
+ MSG_MAP(DAL_DISABLE_DUMMY_PSTATE_CHANGE, PPSMC_MSG_DALDisableDummyPstateChange, 0),
MSG_MAP(DAL_ENABLE_DUMMY_PSTATE_CHANGE, PPSMC_MSG_DALEnableDummyPstateChange, 0),
MSG_MAP(GetVoltageByDpm, PPSMC_MSG_GetVoltageByDpm, 0),
MSG_MAP(GetVoltageByDpmOverdrive, PPSMC_MSG_GetVoltageByDpmOverdrive, 0),
@@ -305,7 +304,8 @@ navi10_get_allowed_feature_mask(struct smu_context *smu,
| 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_OUT_OF_BAND_MONITOR_BIT)
+ | FEATURE_MASK(FEATURE_TEMP_DEPENDENT_VMIN_BIT);
if (adev->pm.pp_feature & PP_SCLK_DPM_MASK)
*(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT);
@@ -345,8 +345,8 @@ navi10_get_allowed_feature_mask(struct smu_context *smu,
/* DPM UCLK enablement should be skipped for navi10 A0 secure board */
if (!(is_asic_secure(smu) &&
- (adev->asic_type == CHIP_NAVI10) &&
- (adev->rev_id == 0)) &&
+ (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)
@@ -354,7 +354,7 @@ navi10_get_allowed_feature_mask(struct smu_context *smu,
/* DS SOCCLK enablement should be skipped for navi10 A0 secure board */
if (is_asic_secure(smu) &&
- (adev->asic_type == CHIP_NAVI10) &&
+ (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);
@@ -431,16 +431,16 @@ static int navi10_append_powerplay_table(struct smu_context *smu)
switch (smc_dpm_table->table_header.content_revision) {
case 5: /* nv10 and nv14 */
- memcpy(smc_pptable->I2cControllers, smc_dpm_table->I2cControllers,
- sizeof(*smc_dpm_table) - sizeof(smc_dpm_table->table_header));
+ smu_memcpy_trailing(smc_pptable, I2cControllers, BoardReserved,
+ smc_dpm_table, I2cControllers);
break;
case 7: /* nv12 */
ret = amdgpu_atombios_get_data_table(adev, index, NULL, NULL, NULL,
(uint8_t **)&smc_dpm_table_v4_7);
if (ret)
return ret;
- memcpy(smc_pptable->I2cControllers, smc_dpm_table_v4_7->I2cControllers,
- sizeof(*smc_dpm_table_v4_7) - sizeof(smc_dpm_table_v4_7->table_header));
+ smu_memcpy_trailing(smc_pptable, I2cControllers, BoardReserved,
+ smc_dpm_table_v4_7, I2cControllers);
break;
default:
dev_err(smu->adev->dev, "smc_dpm_info with unsupported content revision %d!\n",
@@ -495,6 +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;
SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
@@ -511,6 +513,12 @@ static int navi10_tables_init(struct smu_context *smu)
SMU_TABLE_INIT(tables, SMU_TABLE_ACTIVITY_MONITOR_COEFF,
sizeof(DpmActivityMonitorCoeffInt_t), PAGE_SIZE,
AMDGPU_GEM_DOMAIN_VRAM);
+ SMU_TABLE_INIT(tables, SMU_TABLE_DRIVER_SMU_CONFIG, sizeof(DriverSmuConfig_t),
+ PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
+
+ dummy_read_1_table->size = 0x40000;
+ 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);
@@ -527,8 +535,15 @@ static int navi10_tables_init(struct smu_context *smu)
if (!smu_table->watermarks_table)
goto err2_out;
+ smu_table->driver_smu_config_table =
+ kzalloc(tables[SMU_TABLE_DRIVER_SMU_CONFIG].size, GFP_KERNEL);
+ if (!smu_table->driver_smu_config_table)
+ goto err3_out;
+
return 0;
+err3_out:
+ kfree(smu_table->watermarks_table);
err2_out:
kfree(smu_table->gpu_metrics_table);
err1_out:
@@ -541,20 +556,16 @@ static int navi10_get_legacy_smu_metrics_data(struct smu_context *smu,
MetricsMember_t member,
uint32_t *value)
{
- struct smu_table_context *smu_table= &smu->smu_table;
+ struct smu_table_context *smu_table = &smu->smu_table;
SmuMetrics_legacy_t *metrics =
(SmuMetrics_legacy_t *)smu_table->metrics_table;
int ret = 0;
- mutex_lock(&smu->metrics_lock);
-
- ret = smu_cmn_get_metrics_table_locked(smu,
- NULL,
- false);
- if (ret) {
- mutex_unlock(&smu->metrics_lock);
+ ret = smu_cmn_get_metrics_table(smu,
+ NULL,
+ false);
+ if (ret)
return ret;
- }
switch (member) {
case METRICS_CURR_GFXCLK:
@@ -624,8 +635,6 @@ static int navi10_get_legacy_smu_metrics_data(struct smu_context *smu,
break;
}
- mutex_unlock(&smu->metrics_lock);
-
return ret;
}
@@ -633,20 +642,16 @@ static int navi10_get_smu_metrics_data(struct smu_context *smu,
MetricsMember_t member,
uint32_t *value)
{
- struct smu_table_context *smu_table= &smu->smu_table;
+ struct smu_table_context *smu_table = &smu->smu_table;
SmuMetrics_t *metrics =
(SmuMetrics_t *)smu_table->metrics_table;
int ret = 0;
- mutex_lock(&smu->metrics_lock);
-
- ret = smu_cmn_get_metrics_table_locked(smu,
- NULL,
- false);
- if (ret) {
- mutex_unlock(&smu->metrics_lock);
+ ret = smu_cmn_get_metrics_table(smu,
+ NULL,
+ false);
+ if (ret)
return ret;
- }
switch (member) {
case METRICS_CURR_GFXCLK:
@@ -719,8 +724,6 @@ static int navi10_get_smu_metrics_data(struct smu_context *smu,
break;
}
- mutex_unlock(&smu->metrics_lock);
-
return ret;
}
@@ -728,20 +731,16 @@ static int navi12_get_legacy_smu_metrics_data(struct smu_context *smu,
MetricsMember_t member,
uint32_t *value)
{
- struct smu_table_context *smu_table= &smu->smu_table;
+ struct smu_table_context *smu_table = &smu->smu_table;
SmuMetrics_NV12_legacy_t *metrics =
(SmuMetrics_NV12_legacy_t *)smu_table->metrics_table;
int ret = 0;
- mutex_lock(&smu->metrics_lock);
-
- ret = smu_cmn_get_metrics_table_locked(smu,
- NULL,
- false);
- if (ret) {
- mutex_unlock(&smu->metrics_lock);
+ ret = smu_cmn_get_metrics_table(smu,
+ NULL,
+ false);
+ if (ret)
return ret;
- }
switch (member) {
case METRICS_CURR_GFXCLK:
@@ -811,8 +810,6 @@ static int navi12_get_legacy_smu_metrics_data(struct smu_context *smu,
break;
}
- mutex_unlock(&smu->metrics_lock);
-
return ret;
}
@@ -820,20 +817,16 @@ static int navi12_get_smu_metrics_data(struct smu_context *smu,
MetricsMember_t member,
uint32_t *value)
{
- struct smu_table_context *smu_table= &smu->smu_table;
+ struct smu_table_context *smu_table = &smu->smu_table;
SmuMetrics_NV12_t *metrics =
(SmuMetrics_NV12_t *)smu_table->metrics_table;
int ret = 0;
- mutex_lock(&smu->metrics_lock);
-
- ret = smu_cmn_get_metrics_table_locked(smu,
- NULL,
- false);
- if (ret) {
- mutex_unlock(&smu->metrics_lock);
+ ret = smu_cmn_get_metrics_table(smu,
+ NULL,
+ false);
+ if (ret)
return ret;
- }
switch (member) {
case METRICS_CURR_GFXCLK:
@@ -906,8 +899,6 @@ static int navi12_get_smu_metrics_data(struct smu_context *smu,
break;
}
- mutex_unlock(&smu->metrics_lock);
-
return ret;
}
@@ -916,27 +907,24 @@ static int navi1x_get_smu_metrics_data(struct smu_context *smu,
uint32_t *value)
{
struct amdgpu_device *adev = smu->adev;
- uint32_t smu_version;
int ret = 0;
- ret = smu_cmn_get_smc_version(smu, NULL, &smu_version);
- if (ret) {
- dev_err(adev->dev, "Failed to get smu version!\n");
- return ret;
- }
-
- switch (adev->asic_type) {
- case CHIP_NAVI12:
- if (smu_version > 0x00341C00)
+ switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
+ case IP_VERSION(11, 0, 9):
+ if (smu->smc_fw_version > 0x00341C00)
ret = navi12_get_smu_metrics_data(smu, member, value);
else
ret = navi12_get_legacy_smu_metrics_data(smu, member, value);
break;
- case CHIP_NAVI10:
- case CHIP_NAVI14:
+ case IP_VERSION(11, 0, 0):
+ case IP_VERSION(11, 0, 5):
default:
- if (((adev->asic_type == CHIP_NAVI14) && smu_version > 0x00351F00) ||
- ((adev->asic_type == CHIP_NAVI10) && smu_version > 0x002A3B00))
+ if (((amdgpu_ip_version(adev, MP1_HWIP, 0) ==
+ IP_VERSION(11, 0, 5)) &&
+ smu->smc_fw_version > 0x00351F00) ||
+ ((amdgpu_ip_version(adev, MP1_HWIP, 0) ==
+ IP_VERSION(11, 0, 0)) &&
+ smu->smc_fw_version > 0x002A3B00))
ret = navi10_get_smu_metrics_data(smu, member, value);
else
ret = navi10_get_legacy_smu_metrics_data(smu, member, value);
@@ -1147,7 +1135,9 @@ static int navi10_set_default_dpm_table(struct smu_context *smu)
return 0;
}
-static int navi10_dpm_set_vcn_enable(struct smu_context *smu, bool enable)
+static int navi10_dpm_set_vcn_enable(struct smu_context *smu,
+ bool enable,
+ int inst)
{
int ret = 0;
@@ -1231,19 +1221,22 @@ static int navi10_get_current_clk_freq_by_table(struct smu_context *smu,
value);
}
-static bool navi10_is_support_fine_grained_dpm(struct smu_context *smu, enum smu_clk_type clk_type)
+static int navi10_is_support_fine_grained_dpm(struct smu_context *smu, enum smu_clk_type clk_type)
{
PPTable_t *pptable = smu->smu_table.driver_pptable;
DpmDescriptor_t *dpm_desc = NULL;
- uint32_t clk_index = 0;
+ int clk_index = 0;
clk_index = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_CLK,
clk_type);
+ if (clk_index < 0)
+ return clk_index;
+
dpm_desc = &pptable->DpmDescriptor[clk_index];
/* 0 - Fine grained DPM, 1 - Discrete DPM */
- return dpm_desc->SnapToDiscrete == 0;
+ return dpm_desc->SnapToDiscrete == 0 ? 1 : 0;
}
static inline bool navi10_od_feature_is_supported(struct smu_11_0_overdrive_table *od_table, enum SMU_11_0_ODFEATURE_CAP cap)
@@ -1261,11 +1254,222 @@ static void navi10_od_setting_get_range(struct smu_11_0_overdrive_table *od_tabl
*max = od_table->max[setting];
}
+static int navi10_emit_clk_levels(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ char *buf,
+ int *offset)
+{
+ 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;
+ 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;
+
+ 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 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 ? "*" : "");
+ }
+ }
+ 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;
+ case SMU_OD_SCLK:
+ if (!smu->od_enabled || !od_table || !od_settings)
+ return -EOPNOTSUPP;
+ if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_LIMITS))
+ break;
+ *offset += sysfs_emit_at(buf, *offset, "OD_SCLK:\n0: %uMhz\n1: %uMhz\n",
+ od_table->GfxclkFmin, od_table->GfxclkFmax);
+ break;
+ case SMU_OD_MCLK:
+ if (!smu->od_enabled || !od_table || !od_settings)
+ return -EOPNOTSUPP;
+ if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_UCLK_MAX))
+ break;
+ *offset += sysfs_emit_at(buf, *offset, "OD_MCLK:\n1: %uMHz\n", od_table->UclkFmax);
+ break;
+ case SMU_OD_VDDC_CURVE:
+ if (!smu->od_enabled || !od_table || !od_settings)
+ return -EOPNOTSUPP;
+ if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_CURVE))
+ break;
+ *offset += sysfs_emit_at(buf, *offset, "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;
+ }
+ *offset += sysfs_emit_at(buf, *offset, "%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)
+ return -EOPNOTSUPP;
+ *offset += sysfs_emit_at(buf, *offset, "%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);
+ *offset += sysfs_emit_at(buf, *offset, "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);
+ *offset += sysfs_emit_at(buf, *offset, "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);
+ *offset += sysfs_emit_at(buf, *offset,
+ "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);
+ *offset += sysfs_emit_at(buf, *offset,
+ "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);
+ *offset += sysfs_emit_at(buf, *offset,
+ "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);
+ *offset += sysfs_emit_at(buf, *offset,
+ "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);
+ *offset += sysfs_emit_at(buf, *offset,
+ "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);
+ *offset += sysfs_emit_at(buf, *offset,
+ "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n",
+ min_value, max_value);
+ }
+
+ break;
+ default:
+ 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, size = 0, ret = 0;
+ int i, levels, size = 0, ret = 0, start_offset = 0;
uint32_t cur_value = 0, value = 0, count = 0;
uint32_t freq_values[3] = {0};
uint32_t mark_index = 0;
@@ -1279,6 +1483,9 @@ static int navi10_print_clk_levels(struct smu_context *smu,
struct smu_11_0_overdrive_table *od_settings = smu->od_settings;
uint32_t min_value, max_value;
+ smu_cmn_get_sysfs_buf(&buf, &size);
+ start_offset = size;
+
switch (clk_type) {
case SMU_GFXCLK:
case SMU_SCLK:
@@ -1291,47 +1498,54 @@ static int navi10_print_clk_levels(struct smu_context *smu,
case SMU_DCEFCLK:
ret = navi10_get_current_clk_freq_by_table(smu, clk_type, &cur_value);
if (ret)
- return size;
+ return size - start_offset;
ret = smu_v11_0_get_dpm_level_count(smu, clk_type, &count);
if (ret)
- return size;
+ return size - start_offset;
- if (!navi10_is_support_fine_grained_dpm(smu, clk_type)) {
+ 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;
+ return size - start_offset;
- size += sprintf(buf + size, "%d: %uMhz %s\n", i, value,
+ 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;
+ return size - start_offset;
ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, count - 1, &freq_values[2]);
if (ret)
- return size;
+ return size - start_offset;
freq_values[1] = cur_value;
mark_index = cur_value == freq_values[0] ? 0 :
cur_value == freq_values[2] ? 2 : 1;
- if (mark_index != 1)
- freq_values[1] = (freq_values[0] + freq_values[2]) / 2;
- for (i = 0; i < 3; i++) {
- size += sprintf(buf + size, "%d: %uMhz %s\n", i, freq_values[i],
- i == mark_index ? "*" : "");
+ 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 += sprintf(buf + size, "%d: %s %s %dMhz %s\n", 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," :
@@ -1352,23 +1566,24 @@ static int navi10_print_clk_levels(struct smu_context *smu,
break;
if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_LIMITS))
break;
- size += sprintf(buf + size, "OD_SCLK:\n");
- size += sprintf(buf + size, "0: %uMhz\n1: %uMhz\n", od_table->GfxclkFmin, od_table->GfxclkFmax);
+ 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 += sprintf(buf + size, "OD_MCLK:\n");
- size += sprintf(buf + size, "1: %uMHz\n", od_table->UclkFmax);
+ 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 += sprintf(buf + size, "OD_VDDC_CURVE:\n");
+ size += sysfs_emit_at(buf, size, "OD_VDDC_CURVE:\n");
for (i = 0; i < 3; i++) {
switch (i) {
case 0:
@@ -1380,58 +1595,58 @@ static int navi10_print_clk_levels(struct smu_context *smu,
case 2:
curve_settings = &od_table->GfxclkFreq3;
break;
- default:
- break;
}
- size += sprintf(buf + size, "%d: %uMHz %umV\n", i, curve_settings[0], curve_settings[1] / NAVI10_VOLTAGE_SCALE);
+ 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 = sprintf(buf, "%s:\n", "OD_RANGE");
+ 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 += sprintf(buf + size, "SCLK: %7uMhz %10uMhz\n",
+ 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 += sprintf(buf + size, "MCLK: %7uMhz %10uMhz\n",
+ 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 += sprintf(buf + size, "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n",
- 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 += sprintf(buf + size, "VDDC_CURVE_VOLT[0]: %7dmV %11dmV\n",
- 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 += sprintf(buf + size, "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n",
- 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 += sprintf(buf + size, "VDDC_CURVE_VOLT[1]: %7dmV %11dmV\n",
- 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 += sprintf(buf + size, "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n",
- 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 += sprintf(buf + size, "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n",
- min_value, max_value);
+ size += sysfs_emit_at(buf, size, "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n",
+ min_value, max_value);
}
break;
@@ -1439,14 +1654,14 @@ static int navi10_print_clk_levels(struct smu_context *smu,
break;
}
- return size;
+ return size - start_offset;
}
static int navi10_force_clk_levels(struct smu_context *smu,
enum smu_clk_type clk_type, uint32_t mask)
{
- int ret = 0, size = 0;
+ int ret = 0;
uint32_t soft_min_level = 0, soft_max_level = 0, min_freq = 0, max_freq = 0;
soft_min_level = mask ? (ffs(mask) - 1) : 0;
@@ -1460,32 +1675,36 @@ static int navi10_force_clk_levels(struct smu_context *smu,
case SMU_UCLK:
case SMU_FCLK:
/* There is only 2 levels for fine grained DPM */
- if (navi10_is_support_fine_grained_dpm(smu, clk_type)) {
+ ret = navi10_is_support_fine_grained_dpm(smu, clk_type);
+ if (ret < 0)
+ return ret;
+
+ if (ret) {
soft_max_level = (soft_max_level >= 1 ? 1 : 0);
soft_min_level = (soft_min_level >= 1 ? 1 : 0);
}
ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, soft_min_level, &min_freq);
if (ret)
- return size;
+ return 0;
ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, soft_max_level, &max_freq);
if (ret)
- return size;
+ return 0;
- ret = smu_v11_0_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq);
+ ret = smu_v11_0_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq, false);
if (ret)
- return size;
+ return 0;
break;
case SMU_DCEFCLK:
- dev_info(smu->adev->dev,"Setting DCEFCLK min/max dpm level is not supported!\n");
+ dev_info(smu->adev->dev, "Setting DCEFCLK min/max dpm level is not supported!\n");
break;
default:
break;
}
- return size;
+ return 0;
}
static int navi10_populate_umd_state_clk(struct smu_context *smu)
@@ -1504,8 +1723,8 @@ static int navi10_populate_umd_state_clk(struct smu_context *smu)
uint32_t sclk_freq;
pstate_table->gfxclk_pstate.min = gfx_table->min;
- switch (adev->asic_type) {
- case CHIP_NAVI10:
+ switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
+ case IP_VERSION(11, 0, 0):
switch (adev->pdev->revision) {
case 0xf0: /* XTX */
case 0xc0:
@@ -1520,7 +1739,7 @@ static int navi10_populate_umd_state_clk(struct smu_context *smu)
break;
}
break;
- case CHIP_NAVI14:
+ case IP_VERSION(11, 0, 5):
switch (adev->pdev->revision) {
case 0xc7: /* XT */
case 0xf4:
@@ -1543,7 +1762,7 @@ static int navi10_populate_umd_state_clk(struct smu_context *smu)
break;
}
break;
- case CHIP_NAVI12:
+ case IP_VERSION(11, 0, 9):
sclk_freq = NAVI12_UMD_PSTATE_PEAK_GFXCLK;
break;
default:
@@ -1641,8 +1860,8 @@ static int navi10_display_config_changed(struct smu_context *smu)
int ret = 0;
if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
- smu_cmn_feature_is_supported(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) &&
- smu_cmn_feature_is_supported(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
+ smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) &&
+ smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays,
smu->display_config->num_display,
NULL);
@@ -1656,39 +1875,36 @@ static int navi10_display_config_changed(struct smu_context *smu)
static bool navi10_is_dpm_running(struct smu_context *smu)
{
int ret = 0;
- uint32_t feature_mask[2];
uint64_t feature_enabled;
- ret = smu_cmn_get_enabled_mask(smu, feature_mask, 2);
+ ret = smu_cmn_get_enabled_mask(smu, &feature_enabled);
if (ret)
return false;
- feature_enabled = (uint64_t)feature_mask[1] << 32 | feature_mask[0];
-
return !!(feature_enabled & SMC_DPM_FEATURE);
}
-static int navi10_get_fan_speed_percent(struct smu_context *smu,
- uint32_t *speed)
+static int navi10_get_fan_speed_rpm(struct smu_context *smu,
+ uint32_t *speed)
{
- int ret;
- u32 rpm;
+ int ret = 0;
if (!speed)
return -EINVAL;
switch (smu_v11_0_get_fan_control_mode(smu)) {
case AMD_FAN_CTRL_AUTO:
- ret = navi1x_get_smu_metrics_data(smu,
+ ret = navi10_get_smu_metrics_data(smu,
METRICS_CURR_FANSPEED,
- &rpm);
- if (!ret && smu->fan_max_rpm)
- *speed = rpm * 100 / smu->fan_max_rpm;
- return ret;
+ speed);
+ break;
default:
- *speed = smu->user_dpm_profile.fan_speed_percent;
- return 0;
+ ret = smu_v11_0_get_fan_speed_rpm(smu,
+ speed);
+ break;
}
+
+ return ret;
}
static int navi10_get_fan_parameters(struct smu_context *smu)
@@ -1705,14 +1921,6 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
DpmActivityMonitorCoeffInt_t activity_monitor;
uint32_t i, size = 0;
int16_t workload_type = 0;
- static const char *profile_name[] = {
- "BOOTUP_DEFAULT",
- "3D_FULL_SCREEN",
- "POWER_SAVING",
- "VIDEO",
- "VR",
- "COMPUTE",
- "CUSTOM"};
static const char *title[] = {
"PROFILE_INDEX(NAME)",
"CLOCK_TYPE(NAME)",
@@ -1730,7 +1938,7 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
if (!buf)
return -EINVAL;
- size += sprintf(buf + size, "%16s %s %s %s %s %s %s %s %s %s %s\n",
+ size += sysfs_emit_at(buf, size, "%16s %s %s %s %s %s %s %s %s %s %s\n",
title[0], title[1], title[2], title[3], title[4], title[5],
title[6], title[7], title[8], title[9], title[10]);
@@ -1750,10 +1958,10 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
return result;
}
- size += sprintf(buf + size, "%2d %14s%s:\n",
- i, profile_name[i], (i == smu->power_profile_mode) ? "*" : " ");
+ size += sysfs_emit_at(buf, size, "%2d %14s%s:\n",
+ i, amdgpu_pp_profile_name[i], (i == smu->power_profile_mode) ? "*" : " ");
- size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
+ size += sysfs_emit_at(buf, size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
" ",
0,
"GFXCLK",
@@ -1767,7 +1975,7 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
activity_monitor.Gfx_PD_Data_error_coeff,
activity_monitor.Gfx_PD_Data_error_rate_coeff);
- size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
+ size += sysfs_emit_at(buf, size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
" ",
1,
"SOCCLK",
@@ -1781,10 +1989,10 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
activity_monitor.Soc_PD_Data_error_coeff,
activity_monitor.Soc_PD_Data_error_rate_coeff);
- size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
+ size += sysfs_emit_at(buf, size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
" ",
2,
- "MEMLK",
+ "MEMCLK",
activity_monitor.Mem_FPS,
activity_monitor.Mem_MinFreqStep,
activity_monitor.Mem_MinActiveFreqType,
@@ -1799,81 +2007,122 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
return size;
}
-static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+#define NAVI10_CUSTOM_PARAMS_COUNT 10
+#define NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT 3
+#define NAVI10_CUSTOM_PARAMS_SIZE (NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT * NAVI10_CUSTOM_PARAMS_COUNT * sizeof(long))
+
+static int navi10_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input)
{
DpmActivityMonitorCoeffInt_t activity_monitor;
- int workload_type, ret = 0;
+ int ret, idx;
- smu->power_profile_mode = input[size];
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor), false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
+ }
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
- return -EINVAL;
+ idx = 0 * NAVI10_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Gfxclk */
+ activity_monitor.Gfx_FPS = input[idx + 1];
+ activity_monitor.Gfx_MinFreqStep = input[idx + 2];
+ activity_monitor.Gfx_MinActiveFreqType = input[idx + 3];
+ activity_monitor.Gfx_MinActiveFreq = input[idx + 4];
+ activity_monitor.Gfx_BoosterFreqType = input[idx + 5];
+ activity_monitor.Gfx_BoosterFreq = input[idx + 6];
+ activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7];
+ activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8];
+ activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9];
+ }
+ idx = 1 * NAVI10_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Socclk */
+ activity_monitor.Soc_FPS = input[idx + 1];
+ activity_monitor.Soc_MinFreqStep = input[idx + 2];
+ activity_monitor.Soc_MinActiveFreqType = input[idx + 3];
+ activity_monitor.Soc_MinActiveFreq = input[idx + 4];
+ activity_monitor.Soc_BoosterFreqType = input[idx + 5];
+ activity_monitor.Soc_BoosterFreq = input[idx + 6];
+ activity_monitor.Soc_PD_Data_limit_c = input[idx + 7];
+ activity_monitor.Soc_PD_Data_error_coeff = input[idx + 8];
+ activity_monitor.Soc_PD_Data_error_rate_coeff = input[idx + 9];
+ }
+ idx = 2 * NAVI10_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Memclk */
+ activity_monitor.Mem_FPS = input[idx + 1];
+ activity_monitor.Mem_MinFreqStep = input[idx + 2];
+ activity_monitor.Mem_MinActiveFreqType = input[idx + 3];
+ activity_monitor.Mem_MinActiveFreq = input[idx + 4];
+ activity_monitor.Mem_BoosterFreqType = input[idx + 5];
+ activity_monitor.Mem_BoosterFreq = input[idx + 6];
+ activity_monitor.Mem_PD_Data_limit_c = input[idx + 7];
+ activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8];
+ activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9];
+ }
+
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor), true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
+ return ret;
+}
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor), false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+static int navi10_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask,
+ long *custom_params,
+ u32 custom_params_max_idx)
+{
+ u32 backend_workload_mask = 0;
+ int ret, idx = -1, i;
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor.Gfx_FPS = input[1];
- activity_monitor.Gfx_MinFreqStep = input[2];
- activity_monitor.Gfx_MinActiveFreqType = input[3];
- activity_monitor.Gfx_MinActiveFreq = input[4];
- activity_monitor.Gfx_BoosterFreqType = input[5];
- activity_monitor.Gfx_BoosterFreq = input[6];
- activity_monitor.Gfx_PD_Data_limit_c = input[7];
- activity_monitor.Gfx_PD_Data_error_coeff = input[8];
- activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
- break;
- case 1: /* Socclk */
- activity_monitor.Soc_FPS = input[1];
- activity_monitor.Soc_MinFreqStep = input[2];
- activity_monitor.Soc_MinActiveFreqType = input[3];
- activity_monitor.Soc_MinActiveFreq = input[4];
- activity_monitor.Soc_BoosterFreqType = input[5];
- activity_monitor.Soc_BoosterFreq = input[6];
- activity_monitor.Soc_PD_Data_limit_c = input[7];
- activity_monitor.Soc_PD_Data_error_coeff = input[8];
- activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
- break;
- case 2: /* Memlk */
- activity_monitor.Mem_FPS = input[1];
- activity_monitor.Mem_MinFreqStep = input[2];
- activity_monitor.Mem_MinActiveFreqType = input[3];
- activity_monitor.Mem_MinActiveFreq = input[4];
- activity_monitor.Mem_BoosterFreqType = input[5];
- activity_monitor.Mem_BoosterFreq = input[6];
- activity_monitor.Mem_PD_Data_limit_c = input[7];
- activity_monitor.Mem_PD_Data_error_coeff = input[8];
- activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
- break;
- }
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask);
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor), true);
+ if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
+ if (!smu->custom_profile_params) {
+ smu->custom_profile_params = kzalloc(NAVI10_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
+ if (!smu->custom_profile_params)
+ return -ENOMEM;
+ }
+ if (custom_params && custom_params_max_idx) {
+ if (custom_params_max_idx != NAVI10_CUSTOM_PARAMS_COUNT)
+ return -EINVAL;
+ if (custom_params[0] >= NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT)
+ return -EINVAL;
+ idx = custom_params[0] * NAVI10_CUSTOM_PARAMS_COUNT;
+ smu->custom_profile_params[idx] = 1;
+ for (i = 1; i < custom_params_max_idx; i++)
+ smu->custom_profile_params[idx + i] = custom_params[i];
+ }
+ ret = navi10_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_params);
if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ if (idx != -1)
+ smu->custom_profile_params[idx] = 0;
return ret;
}
+ } else if (smu->custom_profile_params) {
+ memset(smu->custom_profile_params, 0, NAVI10_CUSTOM_PARAMS_SIZE);
}
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
- if (workload_type < 0)
- return -EINVAL;
- smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
- 1 << workload_type, NULL);
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
+ backend_workload_mask, NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
+ if (idx != -1)
+ smu->custom_profile_params[idx] = 0;
+ return ret;
+ }
return ret;
}
@@ -1888,13 +2137,13 @@ static int navi10_notify_smc_display_config(struct smu_context *smu)
min_clocks.dcef_clock_in_sr = smu->display_config->min_dcef_deep_sleep_set_clk;
min_clocks.memory_clock = smu->display_config->min_mem_set_clock;
- if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
+ if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
clock_req.clock_type = amd_pp_dcef_clock;
clock_req.clock_freq_in_khz = min_clocks.dcef_clock * 10;
ret = smu_v11_0_display_clock_voltage_request(smu, &clock_req);
if (!ret) {
- if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_DCEFCLK_BIT)) {
+ if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DS_DCEFCLK_BIT)) {
ret = smu_cmn_send_smc_msg_with_param(smu,
SMU_MSG_SetMinDeepSleepDcefclk,
min_clocks.dcef_clock_in_sr/100,
@@ -1985,10 +2234,9 @@ static int navi10_read_sensor(struct smu_context *smu,
struct smu_table_context *table_context = &smu->smu_table;
PPTable_t *pptable = table_context->driver_pptable;
- if(!data || !size)
+ if (!data || !size)
return -EINVAL;
- mutex_lock(&smu->sensor_lock);
switch (sensor) {
case AMDGPU_PP_SENSOR_MAX_FAN_RPM:
*(uint32_t *)data = pptable->FanMaximumRpm;
@@ -2006,7 +2254,7 @@ static int navi10_read_sensor(struct smu_context *smu,
(uint32_t *)data);
*size = 4;
break;
- case AMDGPU_PP_SENSOR_GPU_POWER:
+ case AMDGPU_PP_SENSOR_GPU_AVG_POWER:
ret = navi1x_get_smu_metrics_data(smu,
METRICS_AVERAGE_SOCKETPOWER,
(uint32_t *)data);
@@ -2044,11 +2292,11 @@ static int navi10_read_sensor(struct smu_context *smu,
ret = smu_v11_0_get_gfx_vdd(smu, (uint32_t *)data);
*size = 4;
break;
+ case AMDGPU_PP_SENSOR_GPU_INPUT_POWER:
default:
ret = -EOPNOTSUPP;
break;
}
- mutex_unlock(&smu->sensor_lock);
return ret;
}
@@ -2122,30 +2370,31 @@ static int navi10_display_disable_memory_clock_switch(struct smu_context *smu,
uint32_t min_memory_clock = smu->hard_min_uclk_req_from_dal;
uint32_t max_memory_clock = max_sustainable_clocks->uclock;
- if(smu->disable_uclk_switch == disable_memory_clock_switch)
+ if (smu->disable_uclk_switch == disable_memory_clock_switch)
return 0;
- if(disable_memory_clock_switch)
+ if (disable_memory_clock_switch)
ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, max_memory_clock, 0);
else
ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, min_memory_clock, 0);
- if(!ret)
+ if (!ret)
smu->disable_uclk_switch = disable_memory_clock_switch;
return ret;
}
static int navi10_get_power_limit(struct smu_context *smu,
- uint32_t *current_power_limit,
- uint32_t *default_power_limit,
- uint32_t *max_power_limit)
+ uint32_t *current_power_limit,
+ uint32_t *default_power_limit,
+ uint32_t *max_power_limit,
+ uint32_t *min_power_limit)
{
struct smu_11_0_powerplay_table *powerplay_table =
(struct smu_11_0_powerplay_table *)smu->smu_table.power_play_table;
struct smu_11_0_overdrive_table *od_settings = smu->od_settings;
PPTable_t *pptable = smu->smu_table.driver_pptable;
- uint32_t power_limit, od_percent;
+ uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0;
if (smu_v11_0_get_current_power_limit(smu, &power_limit)) {
/* the last hope to figure out the ppt limit */
@@ -2162,31 +2411,42 @@ static int navi10_get_power_limit(struct smu_context *smu,
if (default_power_limit)
*default_power_limit = power_limit;
- if (max_power_limit) {
+ if (powerplay_table) {
if (smu->od_enabled &&
- navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_POWER_LIMIT)) {
- od_percent = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
+ navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_POWER_LIMIT)) {
+ od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
+ od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
+ } else if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_POWER_LIMIT)) {
+ od_percent_upper = 0;
+ od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
+ }
+ }
- dev_dbg(smu->adev->dev, "ODSETTING_POWERPERCENTAGE: %d (default: %d)\n", od_percent, power_limit);
+ 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);
- power_limit *= (100 + od_percent);
- power_limit /= 100;
- }
+ if (max_power_limit) {
+ *max_power_limit = power_limit * (100 + od_percent_upper);
+ *max_power_limit /= 100;
+ }
- *max_power_limit = power_limit;
+ if (min_power_limit) {
+ *min_power_limit = power_limit * (100 - od_percent_lower);
+ *min_power_limit /= 100;
}
return 0;
}
static int navi10_update_pcie_parameters(struct smu_context *smu,
- uint32_t pcie_gen_cap,
- uint32_t pcie_width_cap)
+ uint8_t pcie_gen_cap,
+ uint8_t pcie_width_cap)
{
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++) {
@@ -2195,25 +2455,27 @@ static int navi10_update_pcie_parameters(struct smu_context *smu,
}
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);
- ret = smu_cmn_send_smc_msg_with_param(smu,
- 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;
+ if (pptable->PcieGenSpeed[i] > pcie_gen_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 |= pcie_gen_cap << 8;
+ smu_pcie_arg |= pcie_width_cap;
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_OverridePcieParameters,
+ smu_pcie_arg,
+ NULL);
+ if (ret)
+ break;
+ }
}
- return 0;
+ return ret;
}
static inline void navi10_dump_od_table(struct smu_context *smu,
@@ -2269,7 +2531,27 @@ static int navi10_baco_enter(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- if (adev->in_runpm)
+ /*
+ * This aims the case below:
+ * amdgpu driver loaded -> runpm suspend kicked -> sound driver loaded
+ *
+ * For NAVI10 and later ASICs, we rely on PMFW to handle the runpm. To
+ * make that possible, PMFW needs to acknowledge the dstate transition
+ * process for both gfx(function 0) and audio(function 1) function of
+ * the ASIC.
+ *
+ * The PCI device's initial runpm status is RUNPM_SUSPENDED. So as the
+ * device representing the audio function of the ASIC. And that means
+ * even if the sound driver(snd_hda_intel) was not loaded yet, it's still
+ * possible runpm suspend kicked on the ASIC. However without the dstate
+ * transition notification from audio function, pmfw cannot handle the
+ * BACO in/exit correctly. And that will cause driver hang on runpm
+ * resuming.
+ *
+ * To address this, we revert to legacy message way(driver masters the
+ * timing for BACO in/exit) on sound driver missing.
+ */
+ if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev))
return smu_v11_0_baco_set_armd3_sequence(smu, BACO_SEQ_BACO);
else
return smu_v11_0_baco_enter(smu);
@@ -2279,7 +2561,7 @@ static int navi10_baco_exit(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- if (adev->in_runpm) {
+ if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev)) {
/* Wait for PMFW handling for the Dstate change */
msleep(10);
return smu_v11_0_baco_set_armd3_sequence(smu, BACO_SEQ_ULPS);
@@ -2294,46 +2576,58 @@ static int navi10_set_default_od_settings(struct smu_context *smu)
(OverDriveTable_t *)smu->smu_table.overdrive_table;
OverDriveTable_t *boot_od_table =
(OverDriveTable_t *)smu->smu_table.boot_overdrive_table;
+ OverDriveTable_t *user_od_table =
+ (OverDriveTable_t *)smu->smu_table.user_overdrive_table;
int ret = 0;
- ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE, 0, (void *)od_table, false);
+ /*
+ * For S3/S4/Runpm resume, no need to setup those overdrive tables again as
+ * - either they already have the default OD settings got during cold bootup
+ * - or they have some user customized OD settings which cannot be overwritten
+ */
+ if (smu->adev->in_suspend)
+ return 0;
+
+ ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE, 0, (void *)boot_od_table, false);
if (ret) {
dev_err(smu->adev->dev, "Failed to get overdrive table!\n");
return ret;
}
- if (!od_table->GfxclkVolt1) {
+ if (!boot_od_table->GfxclkVolt1) {
ret = navi10_overdrive_get_gfx_clk_base_voltage(smu,
- &od_table->GfxclkVolt1,
- od_table->GfxclkFreq1);
+ &boot_od_table->GfxclkVolt1,
+ boot_od_table->GfxclkFreq1);
if (ret)
return ret;
}
- if (!od_table->GfxclkVolt2) {
+ if (!boot_od_table->GfxclkVolt2) {
ret = navi10_overdrive_get_gfx_clk_base_voltage(smu,
- &od_table->GfxclkVolt2,
- od_table->GfxclkFreq2);
+ &boot_od_table->GfxclkVolt2,
+ boot_od_table->GfxclkFreq2);
if (ret)
return ret;
}
- if (!od_table->GfxclkVolt3) {
+ if (!boot_od_table->GfxclkVolt3) {
ret = navi10_overdrive_get_gfx_clk_base_voltage(smu,
- &od_table->GfxclkVolt3,
- od_table->GfxclkFreq3);
+ &boot_od_table->GfxclkVolt3,
+ boot_od_table->GfxclkFreq3);
if (ret)
return ret;
}
- memcpy(boot_od_table, od_table, sizeof(OverDriveTable_t));
+ navi10_dump_od_table(smu, boot_od_table);
- navi10_dump_od_table(smu, od_table);
+ memcpy(od_table, boot_od_table, sizeof(OverDriveTable_t));
+ memcpy(user_od_table, boot_od_table, sizeof(OverDriveTable_t));
return 0;
}
-static int navi10_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type, long input[], uint32_t size) {
+static int navi10_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type, long input[], uint32_t size)
+{
int i;
int ret = 0;
struct smu_table_context *table_context = &smu->smu_table;
@@ -2429,11 +2723,20 @@ static int navi10_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABL
memcpy(table_context->overdrive_table, table_context->boot_overdrive_table, sizeof(OverDriveTable_t));
break;
case PP_OD_COMMIT_DPM_TABLE:
- navi10_dump_od_table(smu, od_table);
- ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE, 0, (void *)od_table, true);
- if (ret) {
- dev_err(smu->adev->dev, "Failed to import overdrive table!\n");
- return ret;
+ if (memcmp(od_table, table_context->user_overdrive_table, sizeof(OverDriveTable_t))) {
+ navi10_dump_od_table(smu, od_table);
+ ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE, 0, (void *)od_table, true);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to import overdrive table!\n");
+ return ret;
+ }
+ memcpy(table_context->user_overdrive_table, od_table, sizeof(OverDriveTable_t));
+ smu->user_dpm_profile.user_od = true;
+
+ if (!memcmp(table_context->user_overdrive_table,
+ table_context->boot_overdrive_table,
+ sizeof(OverDriveTable_t)))
+ smu->user_dpm_profile.user_od = false;
}
break;
case PP_OD_EDIT_VDDC_CURVE:
@@ -2517,8 +2820,8 @@ static bool navi10_need_umc_cdr_workaround(struct smu_context *smu)
if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT))
return false;
- if (adev->asic_type == CHIP_NAVI10 ||
- adev->asic_type == CHIP_NAVI14)
+ if (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 0) ||
+ amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 5))
return true;
return false;
@@ -2586,7 +2889,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,
@@ -2606,19 +2909,12 @@ static int navi10_run_umc_cdr_workaround(struct smu_context *smu)
struct amdgpu_device *adev = smu->adev;
uint8_t umc_fw_greater_than_v136 = false;
uint8_t umc_fw_disable_cdr = false;
- uint32_t pmfw_version;
uint32_t param;
int ret = 0;
if (!navi10_need_umc_cdr_workaround(smu))
return 0;
- ret = smu_cmn_get_smc_version(smu, NULL, &pmfw_version);
- if (ret) {
- dev_err(adev->dev, "Failed to get smu version!\n");
- return ret;
- }
-
/*
* The messages below are only supported by Navi10 42.53.0 and later
* PMFWs and Navi14 53.29.0 and later PMFWs.
@@ -2626,8 +2922,10 @@ static int navi10_run_umc_cdr_workaround(struct smu_context *smu)
* - PPSMC_MSG_SetDriverDummyTableDramAddrLow
* - PPSMC_MSG_GetUMCFWWA
*/
- if (((adev->asic_type == CHIP_NAVI10) && (pmfw_version >= 0x2a3500)) ||
- ((adev->asic_type == CHIP_NAVI14) && (pmfw_version >= 0x351D00))) {
+ if (((amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 0)) &&
+ (smu->smc_fw_version >= 0x2a3500)) ||
+ ((amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 5)) &&
+ (smu->smc_fw_version >= 0x351D00))) {
ret = smu_cmn_send_smc_msg_with_param(smu,
SMU_MSG_GET_UMC_FW_WA,
0,
@@ -2646,13 +2944,15 @@ static int navi10_run_umc_cdr_workaround(struct smu_context *smu)
return 0;
if (umc_fw_disable_cdr) {
- if (adev->asic_type == CHIP_NAVI10)
+ if (amdgpu_ip_version(adev, MP1_HWIP, 0) ==
+ IP_VERSION(11, 0, 0))
return navi10_umc_hybrid_cdr_workaround(smu);
} else {
return navi10_set_dummy_pstates_table_location(smu);
}
} else {
- if (adev->asic_type == CHIP_NAVI10)
+ if (amdgpu_ip_version(adev, MP1_HWIP, 0) ==
+ IP_VERSION(11, 0, 0))
return navi10_umc_hybrid_cdr_workaround(smu);
}
@@ -2668,20 +2968,14 @@ static ssize_t navi10_get_legacy_gpu_metrics(struct smu_context *smu,
SmuMetrics_legacy_t metrics;
int ret = 0;
- mutex_lock(&smu->metrics_lock);
-
- ret = smu_cmn_get_metrics_table_locked(smu,
- NULL,
- true);
- if (ret) {
- mutex_unlock(&smu->metrics_lock);
+ ret = smu_cmn_get_metrics_table(smu,
+ NULL,
+ true);
+ if (ret)
return ret;
- }
memcpy(&metrics, smu_table->metrics_table, sizeof(SmuMetrics_legacy_t));
- mutex_unlock(&smu->metrics_lock);
-
smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 3);
gpu_metrics->temperature_edge = metrics.TemperatureEdge;
@@ -2735,6 +3029,144 @@ static ssize_t navi10_get_legacy_gpu_metrics(struct smu_context *smu,
return sizeof(struct gpu_metrics_v1_3);
}
+static int navi10_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msg, int num_msgs)
+{
+ struct amdgpu_smu_i2c_bus *smu_i2c = i2c_get_adapdata(i2c_adap);
+ struct amdgpu_device *adev = smu_i2c->adev;
+ struct smu_context *smu = adev->powerplay.pp_handle;
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_table *table = &smu_table->driver_table;
+ SwI2cRequest_t *req, *res = (SwI2cRequest_t *)table->cpu_addr;
+ int i, j, r, c;
+ u16 dir;
+
+ if (!adev->pm.dpm_enabled)
+ return -EBUSY;
+
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ req->I2CcontrollerPort = smu_i2c->port;
+ req->I2CSpeed = I2C_SPEED_FAST_400K;
+ req->SlaveAddress = msg[0].addr << 1; /* wants an 8-bit address */
+ dir = msg[0].flags & I2C_M_RD;
+
+ for (c = i = 0; i < num_msgs; i++) {
+ for (j = 0; j < msg[i].len; j++, c++) {
+ SwI2cCmd_t *cmd = &req->SwI2cCmds[c];
+
+ if (!(msg[i].flags & I2C_M_RD)) {
+ /* write */
+ cmd->Cmd = I2C_CMD_WRITE;
+ cmd->RegisterAddr = msg[i].buf[j];
+ }
+
+ if ((dir ^ msg[i].flags) & I2C_M_RD) {
+ /* The direction changes.
+ */
+ dir = msg[i].flags & I2C_M_RD;
+ cmd->CmdConfig |= CMDCONFIG_RESTART_MASK;
+ }
+
+ req->NumCmds++;
+
+ /*
+ * Insert STOP if we are at the last byte of either last
+ * message for the transaction or the client explicitly
+ * requires a STOP at this particular message.
+ */
+ if ((j == msg[i].len - 1) &&
+ ((i == num_msgs - 1) || (msg[i].flags & I2C_M_STOP))) {
+ cmd->CmdConfig &= ~CMDCONFIG_RESTART_MASK;
+ cmd->CmdConfig |= CMDCONFIG_STOP_MASK;
+ }
+ }
+ }
+ mutex_lock(&adev->pm.mutex);
+ r = smu_cmn_update_table(smu, SMU_TABLE_I2C_COMMANDS, 0, req, true);
+ if (r)
+ goto fail;
+
+ for (c = i = 0; i < num_msgs; i++) {
+ if (!(msg[i].flags & I2C_M_RD)) {
+ c += msg[i].len;
+ continue;
+ }
+ for (j = 0; j < msg[i].len; j++, c++) {
+ SwI2cCmd_t *cmd = &res->SwI2cCmds[c];
+
+ msg[i].buf[j] = cmd->Data;
+ }
+ }
+ r = num_msgs;
+fail:
+ mutex_unlock(&adev->pm.mutex);
+ kfree(req);
+ return r;
+}
+
+static u32 navi10_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+
+static const struct i2c_algorithm navi10_i2c_algo = {
+ .master_xfer = navi10_i2c_xfer,
+ .functionality = navi10_i2c_func,
+};
+
+static const struct i2c_adapter_quirks navi10_i2c_control_quirks = {
+ .flags = I2C_AQ_COMB | I2C_AQ_COMB_SAME_ADDR | I2C_AQ_NO_ZERO_LEN,
+ .max_read_len = MAX_SW_I2C_COMMANDS,
+ .max_write_len = MAX_SW_I2C_COMMANDS,
+ .max_comb_1st_msg_len = 2,
+ .max_comb_2nd_msg_len = MAX_SW_I2C_COMMANDS - 2,
+};
+
+static int navi10_i2c_control_init(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+ int res, 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;
+
+ smu_i2c->adev = adev;
+ smu_i2c->port = i;
+ mutex_init(&smu_i2c->mutex);
+ control->owner = THIS_MODULE;
+ control->class = I2C_CLASS_HWMON;
+ control->dev.parent = &adev->pdev->dev;
+ control->algo = &navi10_i2c_algo;
+ snprintf(control->name, sizeof(control->name), "AMDGPU SMU %d", i);
+ control->quirks = &navi10_i2c_control_quirks;
+ i2c_set_adapdata(control, smu_i2c);
+
+ res = devm_i2c_add_adapter(adev->dev, control);
+ if (res) {
+ DRM_ERROR("Failed to register hw i2c, err: %d\n", res);
+ return res;
+ }
+ }
+
+ adev->pm.ras_eeprom_i2c_bus = &adev->pm.smu_i2c[0].adapter;
+ adev->pm.fru_eeprom_i2c_bus = &adev->pm.smu_i2c[1].adapter;
+
+ return 0;
+}
+
+static void navi10_i2c_control_fini(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+
+ adev->pm.ras_eeprom_i2c_bus = NULL;
+ adev->pm.fru_eeprom_i2c_bus = NULL;
+}
+
static ssize_t navi10_get_gpu_metrics(struct smu_context *smu,
void **table)
{
@@ -2744,20 +3176,14 @@ static ssize_t navi10_get_gpu_metrics(struct smu_context *smu,
SmuMetrics_t metrics;
int ret = 0;
- mutex_lock(&smu->metrics_lock);
-
- ret = smu_cmn_get_metrics_table_locked(smu,
- NULL,
- true);
- if (ret) {
- mutex_unlock(&smu->metrics_lock);
+ ret = smu_cmn_get_metrics_table(smu,
+ NULL,
+ true);
+ if (ret)
return ret;
- }
memcpy(&metrics, smu_table->metrics_table, sizeof(SmuMetrics_t));
- mutex_unlock(&smu->metrics_lock);
-
smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 3);
gpu_metrics->temperature_edge = metrics.TemperatureEdge;
@@ -2822,20 +3248,14 @@ static ssize_t navi12_get_legacy_gpu_metrics(struct smu_context *smu,
SmuMetrics_NV12_legacy_t metrics;
int ret = 0;
- mutex_lock(&smu->metrics_lock);
-
- ret = smu_cmn_get_metrics_table_locked(smu,
- NULL,
- true);
- if (ret) {
- mutex_unlock(&smu->metrics_lock);
+ ret = smu_cmn_get_metrics_table(smu,
+ NULL,
+ true);
+ if (ret)
return ret;
- }
memcpy(&metrics, smu_table->metrics_table, sizeof(SmuMetrics_NV12_legacy_t));
- mutex_unlock(&smu->metrics_lock);
-
smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 3);
gpu_metrics->temperature_edge = metrics.TemperatureEdge;
@@ -2903,20 +3323,14 @@ static ssize_t navi12_get_gpu_metrics(struct smu_context *smu,
SmuMetrics_NV12_t metrics;
int ret = 0;
- mutex_lock(&smu->metrics_lock);
-
- ret = smu_cmn_get_metrics_table_locked(smu,
- NULL,
- true);
- if (ret) {
- mutex_unlock(&smu->metrics_lock);
+ ret = smu_cmn_get_metrics_table(smu,
+ NULL,
+ true);
+ if (ret)
return ret;
- }
memcpy(&metrics, smu_table->metrics_table, sizeof(SmuMetrics_NV12_t));
- mutex_unlock(&smu->metrics_lock);
-
smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 3);
gpu_metrics->temperature_edge = metrics.TemperatureEdge;
@@ -2981,30 +3395,27 @@ static ssize_t navi1x_get_gpu_metrics(struct smu_context *smu,
void **table)
{
struct amdgpu_device *adev = smu->adev;
- uint32_t smu_version;
int ret = 0;
- ret = smu_cmn_get_smc_version(smu, NULL, &smu_version);
- if (ret) {
- dev_err(adev->dev, "Failed to get smu version!\n");
- return ret;
- }
-
- switch (adev->asic_type) {
- case CHIP_NAVI12:
- if (smu_version > 0x00341C00)
+ switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
+ case IP_VERSION(11, 0, 9):
+ if (smu->smc_fw_version > 0x00341C00)
ret = navi12_get_gpu_metrics(smu, table);
else
ret = navi12_get_legacy_gpu_metrics(smu, table);
break;
- case CHIP_NAVI10:
- case CHIP_NAVI14:
+ case IP_VERSION(11, 0, 0):
+ case IP_VERSION(11, 0, 5):
default:
- if (((adev->asic_type == CHIP_NAVI14) && smu_version > 0x00351F00) ||
- ((adev->asic_type == CHIP_NAVI10) && smu_version > 0x002A3B00))
+ if (((amdgpu_ip_version(adev, MP1_HWIP, 0) ==
+ IP_VERSION(11, 0, 5)) &&
+ smu->smc_fw_version > 0x00351F00) ||
+ ((amdgpu_ip_version(adev, MP1_HWIP, 0) ==
+ IP_VERSION(11, 0, 0)) &&
+ smu->smc_fw_version > 0x002A3B00))
ret = navi10_get_gpu_metrics(smu, table);
else
- ret =navi10_get_legacy_gpu_metrics(smu, table);
+ ret = navi10_get_legacy_gpu_metrics(smu, table);
break;
}
@@ -3019,7 +3430,7 @@ static int navi10_enable_mgpu_fan_boost(struct smu_context *smu)
uint32_t param = 0;
/* Navi12 does not support this */
- if (adev->asic_type == CHIP_NAVI12)
+ if (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 9))
return 0;
/*
@@ -3049,36 +3460,69 @@ static int navi10_post_smu_init(struct smu_context *smu)
return 0;
ret = navi10_run_umc_cdr_workaround(smu);
- if (ret) {
+ if (ret)
dev_err(adev->dev, "Failed to apply umc cdr workaround!\n");
- return ret;
- }
-
- if (!smu->dc_controlled_by_gpio) {
- /*
- * For Navi1X, manually switch it to AC mode as PMFW
- * may boot it with DC mode.
- */
- ret = smu_v11_0_set_power_source(smu,
- adev->pm.ac_power ?
- SMU_POWER_SOURCE_AC :
- SMU_POWER_SOURCE_DC);
- if (ret) {
- dev_err(adev->dev, "Failed to switch to %s mode!\n",
- adev->pm.ac_power ? "AC" : "DC");
- return ret;
- }
- }
return ret;
}
+static int navi10_get_default_config_table_settings(struct smu_context *smu,
+ struct config_table_setting *table)
+{
+ if (!table)
+ return -EINVAL;
+
+ table->gfxclk_average_tau = 10;
+ table->socclk_average_tau = 10;
+ table->uclk_average_tau = 10;
+ table->gfx_activity_average_tau = 10;
+ table->mem_activity_average_tau = 10;
+ table->socket_power_average_tau = 10;
+
+ return 0;
+}
+
+static int navi10_set_config_table(struct smu_context *smu,
+ struct config_table_setting *table)
+{
+ DriverSmuConfig_t driver_smu_config_table;
+
+ if (!table)
+ return -EINVAL;
+
+ memset(&driver_smu_config_table,
+ 0,
+ sizeof(driver_smu_config_table));
+
+ driver_smu_config_table.GfxclkAverageLpfTau =
+ table->gfxclk_average_tau;
+ driver_smu_config_table.SocclkAverageLpfTau =
+ table->socclk_average_tau;
+ driver_smu_config_table.UclkAverageLpfTau =
+ table->uclk_average_tau;
+ driver_smu_config_table.GfxActivityLpfTau =
+ table->gfx_activity_average_tau;
+ driver_smu_config_table.UclkActivityLpfTau =
+ table->mem_activity_average_tau;
+ driver_smu_config_table.SocketPowerLpfTau =
+ table->socket_power_average_tau;
+
+ return smu_cmn_update_table(smu,
+ SMU_TABLE_DRIVER_SMU_CONFIG,
+ 0,
+ (void *)&driver_smu_config_table,
+ true);
+}
+
static const struct pptable_funcs navi10_ppt_funcs = {
.get_allowed_feature_mask = navi10_get_allowed_feature_mask,
.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,
.get_clock_by_type_with_latency = navi10_get_clock_by_type_with_latency,
@@ -3086,7 +3530,8 @@ static const struct pptable_funcs navi10_ppt_funcs = {
.display_config_changed = navi10_display_config_changed,
.notify_smc_display_config = navi10_notify_smc_display_config,
.is_dpm_running = navi10_is_dpm_running,
- .get_fan_speed_percent = navi10_get_fan_speed_percent,
+ .get_fan_speed_pwm = smu_v11_0_get_fan_speed_pwm,
+ .get_fan_speed_rpm = navi10_get_fan_speed_rpm,
.get_power_profile_mode = navi10_get_power_profile_mode,
.set_power_profile_mode = navi10_set_power_profile_mode,
.set_watermarks_table = navi10_set_watermarks_table,
@@ -3129,21 +3574,21 @@ static const struct pptable_funcs navi10_ppt_funcs = {
.display_clock_voltage_request = smu_v11_0_display_clock_voltage_request,
.get_fan_control_mode = smu_v11_0_get_fan_control_mode,
.set_fan_control_mode = smu_v11_0_set_fan_control_mode,
- .set_fan_speed_percent = smu_v11_0_set_fan_speed_percent,
+ .set_fan_speed_pwm = smu_v11_0_set_fan_speed_pwm,
+ .set_fan_speed_rpm = smu_v11_0_set_fan_speed_rpm,
.set_xgmi_pstate = smu_v11_0_set_xgmi_pstate,
.gfx_off_control = smu_v11_0_gfx_off_control,
.register_irq_handler = smu_v11_0_register_irq_handler,
.set_azalia_d3_pme = smu_v11_0_set_azalia_d3_pme,
.get_max_sustainable_clocks_by_dc = smu_v11_0_get_max_sustainable_clocks_by_dc,
- .baco_is_support = smu_v11_0_baco_is_support,
- .baco_get_state = smu_v11_0_baco_get_state,
- .baco_set_state = smu_v11_0_baco_set_state,
+ .get_bamaco_support = smu_v11_0_get_bamaco_support,
.baco_enter = navi10_baco_enter,
.baco_exit = navi10_baco_exit,
.get_dpm_ultimate_freq = smu_v11_0_get_dpm_ultimate_freq,
.set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range,
.set_default_od_settings = navi10_set_default_od_settings,
.od_edit_dpm_table = navi10_od_edit_dpm_table,
+ .restore_user_od_settings = smu_v11_0_restore_user_od_settings,
.run_btc = navi10_run_btc,
.set_power_source = smu_v11_0_set_power_source,
.get_pp_feature_mask = smu_cmn_get_pp_feature_mask,
@@ -3156,6 +3601,8 @@ static const struct pptable_funcs navi10_ppt_funcs = {
.post_init = navi10_post_smu_init,
.interrupt_work = smu_v11_0_interrupt_work,
.set_mp1_state = smu_cmn_set_mp1_state,
+ .get_default_config_table_settings = navi10_get_default_config_table_settings,
+ .set_config_table = navi10_set_config_table,
};
void navi10_set_ppt_funcs(struct smu_context *smu)
@@ -3167,4 +3614,5 @@ void navi10_set_ppt_funcs(struct smu_context *smu)
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);
}