* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include "pp_debug.h"
#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "pp_debug.h"
#include "amdgpu.h"
#include "amdgpu_smu.h"
#include "atomfirmware.h"
#include "amdgpu_atomfirmware.h"
#include "smu_v11_0.h"
-#include "smu_11_0_driver_if.h"
#include "soc15_common.h"
#include "atom.h"
#include "vega20_ppt.h"
#include "navi10_ppt.h"
-#include "pp_thermal.h"
#include "asic_reg/thm/thm_11_0_2_offset.h"
#include "asic_reg/thm/thm_11_0_2_sh_mask.h"
#include "asic_reg/mp/mp_11_0_offset.h"
#include "asic_reg/mp/mp_11_0_sh_mask.h"
#include "asic_reg/nbio/nbio_7_4_offset.h"
+#include "asic_reg/nbio/nbio_7_4_sh_mask.h"
#include "asic_reg/smuio/smuio_11_0_0_offset.h"
#include "asic_reg/smuio/smuio_11_0_0_sh_mask.h"
MODULE_FIRMWARE("amdgpu/vega20_smc.bin");
MODULE_FIRMWARE("amdgpu/navi10_smc.bin");
+MODULE_FIRMWARE("amdgpu/navi14_smc.bin");
-#define SMU11_TOOL_SIZE 0x19000
-#define SMU11_THERMAL_MINIMUM_ALERT_TEMP 0
-#define SMU11_THERMAL_MAXIMUM_ALERT_TEMP 255
-
-#define SMU11_TEMPERATURE_UNITS_PER_CENTIGRADES 1000
#define SMU11_VOLTAGE_SCALE 4
-#define SMC_DPM_FEATURE (FEATURE_DPM_PREFETCHER_MASK | \
- FEATURE_DPM_GFXCLK_MASK | \
- FEATURE_DPM_UCLK_MASK | \
- FEATURE_DPM_SOCCLK_MASK | \
- FEATURE_DPM_UVD_MASK | \
- FEATURE_DPM_VCE_MASK | \
- FEATURE_DPM_MP0CLK_MASK | \
- FEATURE_DPM_LINK_MASK | \
- FEATURE_DPM_DCEFCLK_MASK)
-
static int smu_v11_0_send_msg_without_waiting(struct smu_context *smu,
uint16_t msg)
{
static int smu_v11_0_wait_for_response(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- uint32_t cur_value, i;
+ uint32_t cur_value, i, timeout = adev->usec_timeout * 10;
- for (i = 0; i < adev->usec_timeout; i++) {
+ for (i = 0; i < timeout; i++) {
cur_value = RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90);
if ((cur_value & MP1_C2PMSG_90__CONTENT_MASK) != 0)
break;
}
/* timeout means wrong logic */
- if (i == adev->usec_timeout)
+ if (i == timeout)
return -ETIME;
return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90) == 0x1 ? 0 : -EIO;
return ret;
}
-static void smu_v11_0_init_smu_ext_microcode(struct smu_context *smu)
-{
- struct amdgpu_device *adev = smu->adev;
- const struct smc_firmware_header_v2_0 *v2;
-
- v2 = (const struct smc_firmware_header_v2_0 *) adev->pm.fw->data;
-
- smu->ppt_offset_bytes = le32_to_cpu(v2->ppt_offset_bytes);
- smu->ppt_size_bytes = le32_to_cpu(v2->ppt_size_bytes);
- smu->ppt_start_addr = (uint8_t *)v2 + smu->ppt_offset_bytes;
-}
-
static int smu_v11_0_init_microcode(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
const struct smc_firmware_header_v1_0 *hdr;
const struct common_firmware_header *header;
struct amdgpu_firmware_info *ucode = NULL;
- uint32_t version_major, version_minor;
switch (adev->asic_type) {
case CHIP_VEGA20:
case CHIP_NAVI10:
chip_name = "navi10";
break;
+ case CHIP_NAVI14:
+ chip_name = "navi14";
+ break;
default:
BUG();
}
amdgpu_ucode_print_smc_hdr(&hdr->header);
adev->pm.fw_version = le32_to_cpu(hdr->header.ucode_version);
- version_major = le16_to_cpu(hdr->header.header_version_major);
- version_minor = le16_to_cpu(hdr->header.header_version_minor);
- if (version_major == 2 && version_minor == 0)
- smu_v11_0_init_smu_ext_microcode(smu); /* with soft pptable */
-
if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
ucode = &adev->firmware.ucode[AMDGPU_UCODE_ID_SMC];
ucode->ucode_id = AMDGPU_UCODE_ID_SMC;
smu_minor = (smu_version >> 8) & 0xff;
smu_debug = (smu_version >> 0) & 0xff;
- pr_info("SMU Driver IF Version = 0x%08x, SMU FW Version = 0x%08x (%d.%d.%d)\n",
- if_version, 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 warning message instead
+ * of halt driver loading.
+ */
if (if_version != smu->smc_if_version) {
- pr_err("SMU driver if version not matched\n");
- ret = -EINVAL;
+ pr_info("smu driver if version = 0x%08x, smu fw if version = 0x%08x, "
+ "smu fw version = 0x%08x (%d.%d.%d)\n",
+ smu->smc_if_version, if_version,
+ smu_version, smu_major, smu_minor, smu_debug);
+ pr_warn("SMU driver if version not matched\n");
}
return ret;
}
-static int smu_v11_0_read_pptable_from_vbios(struct smu_context *smu)
+static int smu_v11_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_v11_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_v11_0_setup_pptable(struct smu_context *smu)
{
+ struct amdgpu_device *adev = smu->adev;
+ const struct smc_firmware_header_v1_0 *hdr;
int ret, index;
- uint16_t size;
+ uint32_t size;
uint8_t frev, crev;
void *table;
+ uint16_t version_major, version_minor;
+
+ hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data;
+ version_major = le16_to_cpu(hdr->header.header_version_major);
+ version_minor = le16_to_cpu(hdr->header.header_version_minor);
+ if (version_major == 2 && smu->smu_table.boot_values.pp_table_id > 0) {
+ switch (version_minor) {
+ case 0:
+ ret = smu_v11_0_set_pptable_v2_0(smu, &table, &size);
+ break;
+ case 1:
+ ret = smu_v11_0_set_pptable_v2_1(smu, &table, &size,
+ smu->smu_table.boot_values.pp_table_id);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret)
+ return ret;
- if (smu->smu_table.boot_values.pp_table_id > 0 && smu->ppt_start_addr) {
- /* load soft pptable */
- table = (void *)smu->ppt_start_addr;
- size= smu->ppt_size_bytes;
} else {
index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
powerplayinfo);
- ret = smu_get_atom_data_table(smu, index, &size, &frev, &crev,
+ ret = smu_get_atom_data_table(smu, index, (uint16_t *)&size, &frev, &crev,
(uint8_t **)&table);
if (ret)
return ret;
struct smu_table *tables = NULL;
int ret = 0;
- if (smu_table->tables || smu_table->table_count != 0)
+ if (smu_table->tables || smu_table->table_count == 0)
return -EINVAL;
- tables = kcalloc(TABLE_COUNT, sizeof(struct smu_table), GFP_KERNEL);
+ tables = kcalloc(SMU_TABLE_COUNT, sizeof(struct smu_table),
+ GFP_KERNEL);
if (!tables)
return -ENOMEM;
smu_table->tables = tables;
- smu_table->table_count = TABLE_COUNT;
-
- SMU_TABLE_INIT(tables, TABLE_PPTABLE, sizeof(PPTable_t),
- PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
- SMU_TABLE_INIT(tables, TABLE_WATERMARKS, sizeof(Watermarks_t),
- PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
- SMU_TABLE_INIT(tables, TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
- PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
- SMU_TABLE_INIT(tables, TABLE_OVERDRIVE, sizeof(OverDriveTable_t),
- PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
- SMU_TABLE_INIT(tables, TABLE_PMSTATUSLOG, SMU11_TOOL_SIZE, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM);
- SMU_TABLE_INIT(tables, TABLE_ACTIVITY_MONITOR_COEFF,
- sizeof(DpmActivityMonitorCoeffInt_t),
- PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM);
+
+ ret = smu_tables_init(smu, tables);
+ if (ret)
+ return ret;
ret = smu_v11_0_init_dpm_context(smu);
if (ret)
return -EINVAL;
kfree(smu_table->tables);
+ kfree(smu_table->metrics_table);
smu_table->tables = NULL;
smu_table->table_count = 0;
+ smu_table->metrics_table = NULL;
+ smu_table->metrics_time = 0;
ret = smu_v11_0_fini_dpm_context(smu);
if (ret)
return -ENOMEM;
smu_power->power_context_size = sizeof(struct smu_11_0_dpm_context);
- smu->metrics_time = 0;
- smu->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
- if (!smu->metrics_table) {
- kfree(smu_power->power_context);
- return -ENOMEM;
- }
-
return 0;
}
if (!smu_power->power_context || smu_power->power_context_size == 0)
return -EINVAL;
- kfree(smu->metrics_table);
kfree(smu_power->power_context);
- smu->metrics_table = NULL;
smu_power->power_context = NULL;
smu_power->power_context_size = 0;
int ret;
struct smu_table_context *table_context = &smu->smu_table;
+ struct smu_table *table = &table_context->tables[SMU_TABLE_PPTABLE];
if (table_context->driver_pptable)
return -EINVAL;
- table_context->driver_pptable = kzalloc(sizeof(PPTable_t), GFP_KERNEL);
+ table_context->driver_pptable = kzalloc(table->size, GFP_KERNEL);
if (!table_context->driver_pptable)
return -ENOMEM;
struct smu_table_context *table_context = &smu->smu_table;
int ret = 0;
- ret = smu_update_table(smu, TABLE_PPTABLE, table_context->driver_pptable, true);
+ ret = smu_update_table(smu, SMU_TABLE_PPTABLE, 0,
+ table_context->driver_pptable, true);
return ret;
}
static int smu_v11_0_write_watermarks_table(struct smu_context *smu)
{
- return smu_update_table(smu, TABLE_WATERMARKS,
- smu->smu_table.tables[TABLE_WATERMARKS].cpu_addr, true);
+ int ret = 0;
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct smu_table *table = NULL;
+
+ table = &smu_table->tables[SMU_TABLE_WATERMARKS];
+ if (!table)
+ return -EINVAL;
+
+ if (!table->cpu_addr)
+ return -EINVAL;
+
+ ret = smu_update_table(smu, SMU_TABLE_WATERMARKS, 0, table->cpu_addr,
+ true);
+
+ return ret;
}
static int smu_v11_0_set_deep_sleep_dcefclk(struct smu_context *smu, uint32_t clk)
static int smu_v11_0_set_tool_table_location(struct smu_context *smu)
{
int ret = 0;
- struct smu_table *tool_table = &smu->smu_table.tables[TABLE_PMSTATUSLOG];
+ struct smu_table *tool_table = &smu->smu_table.tables[SMU_TABLE_PMSTATUSLOG];
if (tool_table->mc_address) {
ret = smu_send_smc_msg_with_param(smu,
return ret;
}
-static int smu_v11_0_init_display(struct smu_context *smu)
+static int smu_v11_0_init_display_count(struct smu_context *smu, uint32_t count)
{
int ret = 0;
if (!smu->pm_enabled)
return ret;
- ret = smu_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, 0);
+
+ ret = smu_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, count);
return ret;
}
return ret;
}
-static bool smu_v11_0_is_dpm_running(struct smu_context *smu)
-{
- int ret = 0;
- uint32_t feature_mask[2];
- unsigned long feature_enabled;
- ret = smu_v11_0_get_enabled_mask(smu, feature_mask, 2);
- feature_enabled = (unsigned long)((uint64_t)feature_mask[0] |
- ((uint64_t)feature_mask[1] << 32));
- return !!(feature_enabled & SMC_DPM_FEATURE);
-}
-
static int smu_v11_0_system_features_control(struct smu_context *smu,
bool en)
{
if (!smu->pm_enabled)
return ret;
- if (smu_feature_is_enabled(smu, FEATURE_DPM_UCLK_BIT))
- ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetUclkFastSwitch, 1);
+ if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT) &&
+ smu->adev->gmc.vram_type == AMDGPU_VRAM_TYPE_HBM)
+ ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetUclkFastSwitch, 1);
return ret;
}
static int
smu_v11_0_get_max_sustainable_clock(struct smu_context *smu, uint32_t *clock,
- PPCLK_e clock_select)
+ enum smu_clk_type clock_select)
{
int ret = 0;
if (!smu->pm_enabled)
return ret;
ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetDcModeMaxDpmFreq,
- clock_select << 16);
+ smu_clk_get_index(smu, clock_select) << 16);
if (ret) {
pr_err("[GetMaxSustainableClock] Failed to get max DC clock from SMC!");
return ret;
/* if DC limit is zero, return AC limit */
ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetMaxDpmFreq,
- clock_select << 16);
+ smu_clk_get_index(smu, clock_select) << 16);
if (ret) {
pr_err("[GetMaxSustainableClock] failed to get max AC clock from SMC!");
return ret;
max_sustainable_clocks->phy_clock = 0xFFFFFFFF;
max_sustainable_clocks->pixel_clock = 0xFFFFFFFF;
- if (smu_feature_is_enabled(smu, FEATURE_DPM_UCLK_BIT)) {
+ if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
ret = smu_v11_0_get_max_sustainable_clock(smu,
&(max_sustainable_clocks->uclock),
- PPCLK_UCLK);
+ SMU_UCLK);
if (ret) {
pr_err("[%s] failed to get max UCLK from SMC!",
__func__);
}
}
- if (smu_feature_is_enabled(smu, FEATURE_DPM_SOCCLK_BIT)) {
+ if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
ret = smu_v11_0_get_max_sustainable_clock(smu,
&(max_sustainable_clocks->soc_clock),
- PPCLK_SOCCLK);
+ SMU_SOCCLK);
if (ret) {
pr_err("[%s] failed to get max SOCCLK from SMC!",
__func__);
}
}
- if (smu_feature_is_enabled(smu, FEATURE_DPM_DCEFCLK_BIT)) {
+ if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
ret = smu_v11_0_get_max_sustainable_clock(smu,
&(max_sustainable_clocks->dcef_clock),
- PPCLK_DCEFCLK);
+ SMU_DCEFCLK);
if (ret) {
pr_err("[%s] failed to get max DCEFCLK from SMC!",
__func__);
ret = smu_v11_0_get_max_sustainable_clock(smu,
&(max_sustainable_clocks->display_clock),
- PPCLK_DISPCLK);
+ SMU_DISPCLK);
if (ret) {
pr_err("[%s] failed to get max DISPCLK from SMC!",
__func__);
}
ret = smu_v11_0_get_max_sustainable_clock(smu,
&(max_sustainable_clocks->phy_clock),
- PPCLK_PHYCLK);
+ SMU_PHYCLK);
if (ret) {
pr_err("[%s] failed to get max PHYCLK from SMC!",
__func__);
}
ret = smu_v11_0_get_max_sustainable_clock(smu,
&(max_sustainable_clocks->pixel_clock),
- PPCLK_PIXCLK);
+ SMU_PIXCLK);
if (ret) {
pr_err("[%s] failed to get max PIXCLK from SMC!",
__func__);
mutex_unlock(&smu->mutex);
} else {
ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetPptLimit,
- POWER_SOURCE_AC << 16);
+ smu_power_get_index(smu, SMU_POWER_SOURCE_AC) << 16);
if (ret) {
pr_err("[%s] get PPT limit failed!", __func__);
return ret;
max_power_limit /= 100;
}
- if (smu_feature_is_enabled(smu, FEATURE_PPT_BIT))
+ if (smu_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT))
ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetPptLimit, n);
if (ret) {
pr_err("[%s] Set power limit Failed!", __func__);
return ret;
}
-static int smu_v11_0_get_current_clk_freq(struct smu_context *smu, uint32_t clk_id, uint32_t *value)
+static int smu_v11_0_get_current_clk_freq(struct smu_context *smu,
+ enum smu_clk_type clk_id,
+ uint32_t *value)
{
int ret = 0;
- uint32_t freq;
+ uint32_t freq = 0;
- if (clk_id >= PPCLK_COUNT || !value)
+ if (clk_id >= SMU_CLK_COUNT || !value)
return -EINVAL;
- ret = smu_send_smc_msg_with_param(smu,
- SMU_MSG_GetDpmClockFreq, (clk_id << 16));
- if (ret)
- return ret;
+ /* if don't has GetDpmClockFreq Message, try get current clock by SmuMetrics_t */
+ if (smu_msg_get_index(smu, SMU_MSG_GetDpmClockFreq) == 0)
+ ret = smu_get_current_clk_freq_by_table(smu, clk_id, &freq);
+ else {
+ ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetDpmClockFreq,
+ (smu_clk_get_index(smu, clk_id) << 16));
+ if (ret)
+ return ret;
- ret = smu_read_smc_arg(smu, &freq);
- if (ret)
- return ret;
+ ret = smu_read_smc_arg(smu, &freq);
+ if (ret)
+ return ret;
+ }
freq *= 100;
*value = freq;
return ret;
}
-static int smu_v11_0_get_thermal_range(struct smu_context *smu,
- struct PP_TemperatureRange *range)
-{
- PPTable_t *pptable = smu->smu_table.driver_pptable;
- memcpy(range, &SMU7ThermalWithDelayPolicy[0], sizeof(struct PP_TemperatureRange));
-
- range->max = pptable->TedgeLimit *
- PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
- range->edge_emergency_max = (pptable->TedgeLimit + CTF_OFFSET_EDGE) *
- PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
- range->hotspot_crit_max = pptable->ThotspotLimit *
- PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
- range->hotspot_emergency_max = (pptable->ThotspotLimit + CTF_OFFSET_HOTSPOT) *
- PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
- range->mem_crit_max = pptable->ThbmLimit *
- PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
- range->mem_emergency_max = (pptable->ThbmLimit + CTF_OFFSET_HBM)*
- PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
-
- return 0;
-}
-
static int smu_v11_0_set_thermal_range(struct smu_context *smu,
- struct PP_TemperatureRange *range)
+ struct smu_temperature_range *range)
{
struct amdgpu_device *adev = smu->adev;
- int low = SMU11_THERMAL_MINIMUM_ALERT_TEMP *
- PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
- int high = SMU11_THERMAL_MAXIMUM_ALERT_TEMP *
- PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+ int low = SMU_THERMAL_MINIMUM_ALERT_TEMP *
+ SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+ int high = SMU_THERMAL_MAXIMUM_ALERT_TEMP *
+ SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
uint32_t val;
+ if (!range)
+ return -EINVAL;
+
if (low < range->min)
low = range->min;
if (high > range->max)
val = RREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_CTRL);
val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, MAX_IH_CREDIT, 5);
val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_IH_HW_ENA, 1);
- val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTH, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
- val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTL, (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
+ val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_INTH_MASK, 0);
+ val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_INTL_MASK, 0);
+ val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTH, (high / SMU_TEMPERATURE_UNITS_PER_CENTIGRADES));
+ val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTL, (low / SMU_TEMPERATURE_UNITS_PER_CENTIGRADES));
val = val & (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK);
WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_CTRL, val);
return 0;
}
-static int smu_v11_0_set_thermal_fan_table(struct smu_context *smu)
-{
- int ret;
- struct smu_table_context *table_context = &smu->smu_table;
- PPTable_t *pptable = table_context->driver_pptable;
-
- ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetFanTemperatureTarget,
- (uint32_t)pptable->FanTargetTemperature);
-
- return ret;
-}
-
static int smu_v11_0_start_thermal_control(struct smu_context *smu)
{
int ret = 0;
- struct PP_TemperatureRange range = {
+ struct smu_temperature_range range = {
TEMP_RANGE_MIN,
TEMP_RANGE_MAX,
TEMP_RANGE_MAX,
if (!smu->pm_enabled)
return ret;
- smu_v11_0_get_thermal_range(smu, &range);
+ ret = smu_get_thermal_temperature_range(smu, &range);
if (smu->smu_table.thermal_controller_type) {
ret = smu_v11_0_set_thermal_range(smu, &range);
ret = smu_v11_0_enable_thermal_alert(smu);
if (ret)
return ret;
- ret = smu_v11_0_set_thermal_fan_table(smu);
+
+ ret = smu_set_thermal_fan_table(smu);
if (ret)
return ret;
}
return ret;
}
-static int smu_v11_0_get_metrics_table(struct smu_context *smu,
- SmuMetrics_t *metrics_table)
-{
- int ret = 0;
-
- if (!smu->metrics_time || time_after(jiffies, smu->metrics_time + HZ / 1000)) {
- ret = smu_update_table(smu, TABLE_SMU_METRICS,
- (void *)metrics_table, false);
- if (ret) {
- pr_info("Failed to export SMU metrics table!\n");
- return ret;
- }
- memcpy(smu->metrics_table, metrics_table, sizeof(SmuMetrics_t));
- smu->metrics_time = jiffies;
- } else
- memcpy(metrics_table, smu->metrics_table, sizeof(SmuMetrics_t));
-
- return ret;
-}
-
-static int smu_v11_0_get_current_activity_percent(struct smu_context *smu,
- enum amd_pp_sensors sensor,
- uint32_t *value)
-{
- int ret = 0;
- SmuMetrics_t metrics;
-
- if (!value)
- return -EINVAL;
-
- ret = smu_v11_0_get_metrics_table(smu, &metrics);
- if (ret)
- return ret;
-
- switch (sensor) {
- case AMDGPU_PP_SENSOR_GPU_LOAD:
- *value = metrics.AverageGfxActivity;
- break;
- case AMDGPU_PP_SENSOR_MEM_LOAD:
- *value = metrics.AverageUclkActivity;
- break;
- default:
- pr_err("Invalid sensor for retrieving clock activity\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int smu_v11_0_thermal_get_temperature(struct smu_context *smu,
- enum amd_pp_sensors sensor,
- uint32_t *value)
-{
- struct amdgpu_device *adev = smu->adev;
- SmuMetrics_t metrics;
- uint32_t temp = 0;
- int ret = 0;
-
- if (!value)
- return -EINVAL;
-
- ret = smu_v11_0_get_metrics_table(smu, &metrics);
- if (ret)
- return ret;
-
- switch (sensor) {
- case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
- temp = RREG32_SOC15(THM, 0, mmCG_MULT_THERMAL_STATUS);
- temp = (temp & CG_MULT_THERMAL_STATUS__CTF_TEMP_MASK) >>
- CG_MULT_THERMAL_STATUS__CTF_TEMP__SHIFT;
-
- temp = temp & 0x1ff;
- temp *= SMU11_TEMPERATURE_UNITS_PER_CENTIGRADES;
-
- *value = temp;
- break;
- case AMDGPU_PP_SENSOR_EDGE_TEMP:
- *value = metrics.TemperatureEdge *
- PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
- break;
- case AMDGPU_PP_SENSOR_MEM_TEMP:
- *value = metrics.TemperatureHBM *
- PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
- break;
- default:
- pr_err("Invalid sensor for retrieving temp\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int smu_v11_0_get_gpu_power(struct smu_context *smu, uint32_t *value)
-{
- int ret = 0;
- SmuMetrics_t metrics;
-
- if (!value)
- return -EINVAL;
-
- ret = smu_v11_0_get_metrics_table(smu, &metrics);
- if (ret)
- return ret;
-
- *value = metrics.CurrSocketPower << 8;
-
- return 0;
-}
-
static uint16_t convert_to_vddc(uint8_t vid)
{
return (uint16_t) ((6200 - (vid * 25)) / SMU11_VOLTAGE_SCALE);
enum amd_pp_sensors sensor,
void *data, uint32_t *size)
{
- struct smu_table_context *table_context = &smu->smu_table;
- PPTable_t *pptable = table_context->driver_pptable;
int ret = 0;
switch (sensor) {
- case AMDGPU_PP_SENSOR_GPU_LOAD:
- case AMDGPU_PP_SENSOR_MEM_LOAD:
- ret = smu_v11_0_get_current_activity_percent(smu,
- sensor,
- (uint32_t *)data);
- *size = 4;
- break;
case AMDGPU_PP_SENSOR_GFX_MCLK:
- ret = smu_get_current_clk_freq(smu, PPCLK_UCLK, (uint32_t *)data);
+ ret = smu_get_current_clk_freq(smu, SMU_UCLK, (uint32_t *)data);
*size = 4;
break;
case AMDGPU_PP_SENSOR_GFX_SCLK:
- ret = smu_get_current_clk_freq(smu, PPCLK_GFXCLK, (uint32_t *)data);
- *size = 4;
- break;
- case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
- case AMDGPU_PP_SENSOR_EDGE_TEMP:
- case AMDGPU_PP_SENSOR_MEM_TEMP:
- ret = smu_v11_0_thermal_get_temperature(smu, sensor, (uint32_t *)data);
- *size = 4;
- break;
- case AMDGPU_PP_SENSOR_GPU_POWER:
- ret = smu_v11_0_get_gpu_power(smu, (uint32_t *)data);
+ ret = smu_get_current_clk_freq(smu, SMU_GFXCLK, (uint32_t *)data);
*size = 4;
break;
case AMDGPU_PP_SENSOR_VDDGFX:
ret = smu_v11_0_get_gfx_vdd(smu, (uint32_t *)data);
*size = 4;
break;
- case AMDGPU_PP_SENSOR_UVD_POWER:
- *(uint32_t *)data = smu_feature_is_enabled(smu, FEATURE_DPM_UVD_BIT) ? 1 : 0;
- *size = 4;
- break;
- case AMDGPU_PP_SENSOR_VCE_POWER:
- *(uint32_t *)data = smu_feature_is_enabled(smu, FEATURE_DPM_VCE_BIT) ? 1 : 0;
- *size = 4;
- break;
case AMDGPU_PP_SENSOR_MIN_FAN_RPM:
*(uint32_t *)data = 0;
*size = 4;
break;
- case AMDGPU_PP_SENSOR_MAX_FAN_RPM:
- *(uint32_t *)data = pptable->FanMaximumRpm;
- *size = 4;
- break;
default:
ret = smu_common_read_sensor(smu, sensor, data, size);
break;
}
+ /* try get sensor data by asic */
+ if (ret)
+ ret = smu_asic_read_sensor(smu, sensor, data, size);
+
if (ret)
*size = 0;
{
enum amd_pp_clock_type clk_type = clock_req->clock_type;
int ret = 0;
- PPCLK_e clk_select = 0;
+ enum smu_clk_type clk_select = 0;
uint32_t clk_freq = clock_req->clock_freq_in_khz / 1000;
if (!smu->pm_enabled)
return -EINVAL;
- if (smu_feature_is_enabled(smu, FEATURE_DPM_DCEFCLK_BIT)) {
+
+ if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) ||
+ smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
switch (clk_type) {
case amd_pp_dcef_clock:
- clk_select = PPCLK_DCEFCLK;
+ clk_select = SMU_DCEFCLK;
break;
case amd_pp_disp_clock:
- clk_select = PPCLK_DISPCLK;
+ clk_select = SMU_DISPCLK;
break;
case amd_pp_pixel_clock:
- clk_select = PPCLK_PIXCLK;
+ clk_select = SMU_PIXCLK;
break;
case amd_pp_phy_clock:
- clk_select = PPCLK_PHYCLK;
+ clk_select = SMU_PHYCLK;
+ break;
+ case amd_pp_mem_clock:
+ clk_select = SMU_UCLK;
break;
default:
pr_info("[%s] Invalid Clock Type!", __func__);
if (ret)
goto failed;
+ mutex_lock(&smu->mutex);
ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinByFreq,
- (clk_select << 16) | clk_freq);
+ (smu_clk_get_index(smu, clk_select) << 16) | clk_freq);
+ mutex_unlock(&smu->mutex);
}
failed:
return ret;
}
-static int smu_v11_0_set_watermarks_table(struct smu_context *smu,
- Watermarks_t *table, struct
- dm_pp_wm_sets_with_clock_ranges_soc15
- *clock_ranges)
-{
- int i;
-
- if (!table || !clock_ranges)
- return -EINVAL;
-
- if (clock_ranges->num_wm_dmif_sets > 4 ||
- clock_ranges->num_wm_mcif_sets > 4)
- return -EINVAL;
-
- for (i = 0; i < clock_ranges->num_wm_dmif_sets; i++) {
- table->WatermarkRow[1][i].MinClock =
- cpu_to_le16((uint16_t)
- (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz /
- 1000));
- table->WatermarkRow[1][i].MaxClock =
- cpu_to_le16((uint16_t)
- (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz /
- 1000));
- table->WatermarkRow[1][i].MinUclk =
- cpu_to_le16((uint16_t)
- (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz /
- 1000));
- table->WatermarkRow[1][i].MaxUclk =
- cpu_to_le16((uint16_t)
- (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz /
- 1000));
- table->WatermarkRow[1][i].WmSetting = (uint8_t)
- clock_ranges->wm_dmif_clocks_ranges[i].wm_set_id;
- }
-
- for (i = 0; i < clock_ranges->num_wm_mcif_sets; i++) {
- table->WatermarkRow[0][i].MinClock =
- cpu_to_le16((uint16_t)
- (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz /
- 1000));
- table->WatermarkRow[0][i].MaxClock =
- cpu_to_le16((uint16_t)
- (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz /
- 1000));
- table->WatermarkRow[0][i].MinUclk =
- cpu_to_le16((uint16_t)
- (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz /
- 1000));
- table->WatermarkRow[0][i].MaxUclk =
- cpu_to_le16((uint16_t)
- (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz /
- 1000));
- table->WatermarkRow[0][i].WmSetting = (uint8_t)
- clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id;
- }
-
- return 0;
-}
-
static int
smu_v11_0_set_watermarks_for_clock_ranges(struct smu_context *smu, struct
dm_pp_wm_sets_with_clock_ranges_soc15
*clock_ranges)
{
int ret = 0;
- struct smu_table *watermarks = &smu->smu_table.tables[TABLE_WATERMARKS];
- Watermarks_t *table = watermarks->cpu_addr;
+ struct smu_table *watermarks = &smu->smu_table.tables[SMU_TABLE_WATERMARKS];
+ void *table = watermarks->cpu_addr;
if (!smu->disable_watermark &&
- smu_feature_is_enabled(smu, FEATURE_DPM_DCEFCLK_BIT) &&
- smu_feature_is_enabled(smu, FEATURE_DPM_SOCCLK_BIT)) {
- smu_v11_0_set_watermarks_table(smu, table, clock_ranges);
+ smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) &&
+ smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
+ smu_set_watermarks_table(smu, table, clock_ranges);
smu->watermarks_bitmap |= WATERMARKS_EXIST;
smu->watermarks_bitmap &= ~WATERMARKS_LOADED;
}
return ret;
}
-static int smu_v11_0_get_clock_ranges(struct smu_context *smu,
- uint32_t *clock,
- PPCLK_e clock_select,
- bool max)
+static int smu_v11_0_gfx_off_control(struct smu_context *smu, bool enable)
{
- int ret;
- *clock = 0;
- if (max) {
- ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetMaxDpmFreq,
- (clock_select << 16));
- if (ret) {
- pr_err("[GetClockRanges] Failed to get max clock from SMC!\n");
- return ret;
- }
- smu_read_smc_arg(smu, clock);
- } else {
- ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetMinDpmFreq,
- (clock_select << 16));
- if (ret) {
- pr_err("[GetClockRanges] Failed to get min clock from SMC!\n");
- return ret;
- }
- smu_read_smc_arg(smu, clock);
- }
-
- return 0;
-}
-
-static uint32_t smu_v11_0_dpm_get_sclk(struct smu_context *smu, bool low)
-{
- uint32_t gfx_clk;
- int ret;
-
- if (!smu_feature_is_enabled(smu, FEATURE_DPM_GFXCLK_BIT)) {
- pr_err("[GetSclks]: gfxclk dpm not enabled!\n");
- return -EPERM;
- }
-
- if (low) {
- ret = smu_v11_0_get_clock_ranges(smu, &gfx_clk, PPCLK_GFXCLK, false);
- if (ret) {
- pr_err("[GetSclks]: fail to get min PPCLK_GFXCLK\n");
- return ret;
- }
- } else {
- ret = smu_v11_0_get_clock_ranges(smu, &gfx_clk, PPCLK_GFXCLK, true);
- if (ret) {
- pr_err("[GetSclks]: fail to get max PPCLK_GFXCLK\n");
- return ret;
- }
- }
-
- return (gfx_clk * 100);
-}
-
-static uint32_t smu_v11_0_dpm_get_mclk(struct smu_context *smu, bool low)
-{
- uint32_t mem_clk;
- int ret;
-
- if (!smu_feature_is_enabled(smu, FEATURE_DPM_UCLK_BIT)) {
- pr_err("[GetMclks]: memclk dpm not enabled!\n");
- return -EPERM;
- }
-
- if (low) {
- ret = smu_v11_0_get_clock_ranges(smu, &mem_clk, PPCLK_UCLK, false);
- if (ret) {
- pr_err("[GetMclks]: fail to get min PPCLK_UCLK\n");
- return ret;
- }
- } else {
- ret = smu_v11_0_get_clock_ranges(smu, &mem_clk, PPCLK_GFXCLK, true);
- if (ret) {
- pr_err("[GetMclks]: fail to get max PPCLK_UCLK\n");
- return ret;
- }
- }
-
- return (mem_clk * 100);
-}
-
-static int smu_v11_0_set_od8_default_settings(struct smu_context *smu,
- bool initialize)
-{
- struct smu_table_context *table_context = &smu->smu_table;
- int ret;
-
- if (initialize) {
- if (table_context->overdrive_table)
- return -EINVAL;
-
- table_context->overdrive_table = kzalloc(sizeof(OverDriveTable_t), GFP_KERNEL);
-
- if (!table_context->overdrive_table)
- return -ENOMEM;
-
- ret = smu_update_table(smu, TABLE_OVERDRIVE, table_context->overdrive_table, false);
- if (ret) {
- pr_err("Failed to export over drive table!\n");
- return ret;
- }
-
- smu_set_default_od8_settings(smu);
- }
-
- ret = smu_update_table(smu, TABLE_OVERDRIVE, table_context->overdrive_table, true);
- if (ret) {
- pr_err("Failed to import over drive table!\n");
- return ret;
- }
-
- return 0;
-}
+ int ret = 0;
+ struct amdgpu_device *adev = smu->adev;
-static int smu_v11_0_conv_power_profile_to_pplib_workload(int power_profile)
-{
- int pplib_workload = 0;
-
- switch (power_profile) {
- case PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT:
- pplib_workload = WORKLOAD_DEFAULT_BIT;
- break;
- case PP_SMC_POWER_PROFILE_FULLSCREEN3D:
- pplib_workload = WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT;
- break;
- case PP_SMC_POWER_PROFILE_POWERSAVING:
- pplib_workload = WORKLOAD_PPLIB_POWER_SAVING_BIT;
- break;
- case PP_SMC_POWER_PROFILE_VIDEO:
- pplib_workload = WORKLOAD_PPLIB_VIDEO_BIT;
- break;
- case PP_SMC_POWER_PROFILE_VR:
- pplib_workload = WORKLOAD_PPLIB_VR_BIT;
- break;
- case PP_SMC_POWER_PROFILE_COMPUTE:
- pplib_workload = WORKLOAD_PPLIB_COMPUTE_BIT;
- break;
- case PP_SMC_POWER_PROFILE_CUSTOM:
- pplib_workload = WORKLOAD_PPLIB_CUSTOM_BIT;
+ switch (adev->asic_type) {
+ case CHIP_VEGA20:
+ break;
+ case CHIP_NAVI10:
+ if (!(adev->pm.pp_feature & PP_GFXOFF_MASK))
+ return 0;
+ mutex_lock(&smu->mutex);
+ if (enable)
+ ret = smu_send_smc_msg(smu, SMU_MSG_AllowGfxOff);
+ else
+ ret = smu_send_smc_msg(smu, SMU_MSG_DisallowGfxOff);
+ mutex_unlock(&smu->mutex);
+ break;
+ default:
break;
}
- return pplib_workload;
-}
-
-static int smu_v11_0_get_power_profile_mode(struct smu_context *smu, char *buf)
-{
- DpmActivityMonitorCoeffInt_t activity_monitor;
- uint32_t i, size = 0;
- uint16_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)",
- "FPS",
- "UseRlcBusy",
- "MinActiveFreqType",
- "MinActiveFreq",
- "BoosterFreqType",
- "BoosterFreq",
- "PD_Data_limit_c",
- "PD_Data_error_coeff",
- "PD_Data_error_rate_coeff"};
- int result = 0;
-
- if (!smu->pm_enabled || !buf)
- return -EINVAL;
-
- size += sprintf(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]);
-
- for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) {
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_v11_0_conv_power_profile_to_pplib_workload(i);
- result = smu_update_table_with_arg(smu, TABLE_ACTIVITY_MONITOR_COEFF,
- workload_type, &activity_monitor, false);
- if (result) {
- pr_err("[%s] Failed to get activity monitor!", __func__);
- return result;
- }
-
- size += sprintf(buf + size, "%2d %14s%s:\n",
- i, 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",
- " ",
- 0,
- "GFXCLK",
- activity_monitor.Gfx_FPS,
- activity_monitor.Gfx_UseRlcBusy,
- activity_monitor.Gfx_MinActiveFreqType,
- activity_monitor.Gfx_MinActiveFreq,
- activity_monitor.Gfx_BoosterFreqType,
- activity_monitor.Gfx_BoosterFreq,
- activity_monitor.Gfx_PD_Data_limit_c,
- 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",
- " ",
- 1,
- "SOCCLK",
- activity_monitor.Soc_FPS,
- activity_monitor.Soc_UseRlcBusy,
- activity_monitor.Soc_MinActiveFreqType,
- activity_monitor.Soc_MinActiveFreq,
- activity_monitor.Soc_BoosterFreqType,
- activity_monitor.Soc_BoosterFreq,
- activity_monitor.Soc_PD_Data_limit_c,
- 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",
- " ",
- 2,
- "UCLK",
- activity_monitor.Mem_FPS,
- activity_monitor.Mem_UseRlcBusy,
- activity_monitor.Mem_MinActiveFreqType,
- activity_monitor.Mem_MinActiveFreq,
- activity_monitor.Mem_BoosterFreqType,
- activity_monitor.Mem_BoosterFreq,
- activity_monitor.Mem_PD_Data_limit_c,
- activity_monitor.Mem_PD_Data_error_coeff,
- activity_monitor.Mem_PD_Data_error_rate_coeff);
-
- size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
- " ",
- 3,
- "FCLK",
- activity_monitor.Fclk_FPS,
- activity_monitor.Fclk_UseRlcBusy,
- activity_monitor.Fclk_MinActiveFreqType,
- activity_monitor.Fclk_MinActiveFreq,
- activity_monitor.Fclk_BoosterFreqType,
- activity_monitor.Fclk_BoosterFreq,
- activity_monitor.Fclk_PD_Data_limit_c,
- activity_monitor.Fclk_PD_Data_error_coeff,
- activity_monitor.Fclk_PD_Data_error_rate_coeff);
- }
-
- return size;
-}
-
-static int smu_v11_0_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
-{
- DpmActivityMonitorCoeffInt_t activity_monitor;
- int workload_type = 0, ret = 0;
-
- smu->power_profile_mode = input[size];
-
- if (!smu->pm_enabled)
- return ret;
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- pr_err("Invalid power profile mode %d\n", smu->power_profile_mode);
- return -EINVAL;
- }
-
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
- ret = smu_update_table_with_arg(smu, TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT, &activity_monitor, false);
- if (ret) {
- pr_err("[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
-
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor.Gfx_FPS = input[1];
- activity_monitor.Gfx_UseRlcBusy = 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_UseRlcBusy = 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: /* Uclk */
- activity_monitor.Mem_FPS = input[1];
- activity_monitor.Mem_UseRlcBusy = 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;
- case 3: /* Fclk */
- activity_monitor.Fclk_FPS = input[1];
- activity_monitor.Fclk_UseRlcBusy = input[2];
- activity_monitor.Fclk_MinActiveFreqType = input[3];
- activity_monitor.Fclk_MinActiveFreq = input[4];
- activity_monitor.Fclk_BoosterFreqType = input[5];
- activity_monitor.Fclk_BoosterFreq = input[6];
- activity_monitor.Fclk_PD_Data_limit_c = input[7];
- activity_monitor.Fclk_PD_Data_error_coeff = input[8];
- activity_monitor.Fclk_PD_Data_error_rate_coeff = input[9];
- break;
- }
-
- ret = smu_update_table_with_arg(smu, TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_COMPUTE_BIT, &activity_monitor, true);
- if (ret) {
- pr_err("[%s] Failed to set activity monitor!", __func__);
- return ret;
- }
- }
-
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type =
- smu_v11_0_conv_power_profile_to_pplib_workload(smu->power_profile_mode);
- smu_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
- 1 << workload_type);
-
return ret;
}
-static int smu_v11_0_update_od8_settings(struct smu_context *smu,
- uint32_t index,
- uint32_t value)
-{
- struct smu_table_context *table_context = &smu->smu_table;
- int ret;
-
- ret = smu_update_table(smu, TABLE_OVERDRIVE,
- table_context->overdrive_table, false);
- if (ret) {
- pr_err("Failed to export over drive table!\n");
- return ret;
- }
-
- smu_update_specified_od8_value(smu, index, value);
-
- ret = smu_update_table(smu, TABLE_OVERDRIVE,
- table_context->overdrive_table, true);
- if (ret) {
- pr_err("Failed to import over drive table!\n");
- return ret;
- }
-
- return 0;
-}
-
-static int smu_v11_0_dpm_set_uvd_enable(struct smu_context *smu, bool enable)
-{
- if (!smu_feature_is_supported(smu, FEATURE_DPM_UVD_BIT))
- return 0;
-
- if (enable == smu_feature_is_enabled(smu, FEATURE_DPM_UVD_BIT))
- return 0;
-
- return smu_feature_set_enabled(smu, FEATURE_DPM_UVD_BIT, enable);
-}
-
-static int smu_v11_0_dpm_set_vce_enable(struct smu_context *smu, bool enable)
-{
- if (!smu_feature_is_supported(smu, FEATURE_DPM_VCE_BIT))
- return 0;
-
- if (enable == smu_feature_is_enabled(smu, FEATURE_DPM_VCE_BIT))
- return 0;
-
- return smu_feature_set_enabled(smu, FEATURE_DPM_VCE_BIT, enable);
-}
-
static int smu_v11_0_get_current_rpm(struct smu_context *smu,
uint32_t *current_rpm)
{
static uint32_t
smu_v11_0_get_fan_control_mode(struct smu_context *smu)
{
- if (!smu_feature_is_enabled(smu, FEATURE_FAN_CONTROL_BIT))
+ if (!smu_feature_is_enabled(smu, SMU_FEATURE_FAN_CONTROL_BIT))
return AMD_FAN_CTRL_MANUAL;
else
return AMD_FAN_CTRL_AUTO;
}
-static int
-smu_v11_0_get_fan_speed_percent(struct smu_context *smu,
- uint32_t *speed)
-{
- int ret = 0;
- uint32_t percent = 0;
- uint32_t current_rpm;
- PPTable_t *pptable = smu->smu_table.driver_pptable;
-
- ret = smu_v11_0_get_current_rpm(smu, ¤t_rpm);
- percent = current_rpm * 100 / pptable->FanMaximumRpm;
- *speed = percent > 100 ? 100 : percent;
-
- return ret;
-}
-
static int
smu_v11_0_smc_fan_control(struct smu_context *smu, bool start)
{
int ret = 0;
- if (smu_feature_is_supported(smu, FEATURE_FAN_CONTROL_BIT))
+ if (smu_feature_is_supported(smu, SMU_FEATURE_FAN_CONTROL_BIT))
return 0;
- ret = smu_feature_set_enabled(smu, FEATURE_FAN_CONTROL_BIT, start);
+ ret = smu_feature_set_enabled(smu, SMU_FEATURE_FAN_CONTROL_BIT, start);
if (ret)
pr_err("[%s]%s smc FAN CONTROL feature failed!",
__func__, (start ? "Start" : "Stop"));
return ret;
}
+#define XGMI_STATE_D0 1
+#define XGMI_STATE_D3 0
+
static int smu_v11_0_set_xgmi_pstate(struct smu_context *smu,
uint32_t pstate)
{
return ret;
}
+#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_v11_0_irq_process(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ struct amdgpu_iv_entry *entry)
+{
+ 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:
+ pr_warn("GPU over temperature range detected on PCIe %d:%d.%d!\n",
+ PCI_BUS_NUM(adev->pdev->devfn),
+ PCI_SLOT(adev->pdev->devfn),
+ PCI_FUNC(adev->pdev->devfn));
+ break;
+ case THM_11_0__SRCID__THM_DIG_THERM_H2L:
+ pr_warn("GPU under temperature range detected on PCIe %d:%d.%d!\n",
+ PCI_BUS_NUM(adev->pdev->devfn),
+ PCI_SLOT(adev->pdev->devfn),
+ PCI_FUNC(adev->pdev->devfn));
+ break;
+ default:
+ pr_warn("GPU under temperature range unknown src id (%d), detected on PCIe %d:%d.%d!\n",
+ src_id,
+ PCI_BUS_NUM(adev->pdev->devfn),
+ PCI_SLOT(adev->pdev->devfn),
+ PCI_FUNC(adev->pdev->devfn));
+ break;
+
+ }
+ }
+
+ return 0;
+}
+
+static const struct amdgpu_irq_src_funcs smu_v11_0_irq_funcs =
+{
+ .process = smu_v11_0_irq_process,
+};
+
+static int smu_v11_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;
+
+ /* already register */
+ if (irq_src)
+ return 0;
+
+ irq_src = kzalloc(sizeof(struct amdgpu_irq_src), GFP_KERNEL);
+ if (!irq_src)
+ return -ENOMEM;
+ smu->irq_source = irq_src;
+
+ irq_src->funcs = &smu_v11_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;
+
+ return ret;
+}
+
+static int smu_v11_0_get_max_sustainable_clocks_by_dc(struct smu_context *smu,
+ struct pp_smu_nv_clock_table *max_clocks)
+{
+ struct smu_table_context *table_context = &smu->smu_table;
+ struct smu_11_0_max_sustainable_clocks *sustainable_clocks = NULL;
+
+ if (!max_clocks || !table_context->max_sustainable_clocks)
+ return -EINVAL;
+
+ sustainable_clocks = table_context->max_sustainable_clocks;
+
+ max_clocks->dcfClockInKhz =
+ (unsigned int) sustainable_clocks->dcef_clock * 1000;
+ max_clocks->displayClockInKhz =
+ (unsigned int) sustainable_clocks->display_clock * 1000;
+ max_clocks->phyClockInKhz =
+ (unsigned int) sustainable_clocks->phy_clock * 1000;
+ max_clocks->pixelClockInKhz =
+ (unsigned int) sustainable_clocks->pixel_clock * 1000;
+ max_clocks->uClockInKhz =
+ (unsigned int) sustainable_clocks->uclock * 1000;
+ max_clocks->socClockInKhz =
+ (unsigned int) sustainable_clocks->soc_clock * 1000;
+ max_clocks->dscClockInKhz = 0;
+ max_clocks->dppClockInKhz = 0;
+ max_clocks->fabricClockInKhz = 0;
+
+ return 0;
+}
+
+static int smu_v11_0_set_azalia_d3_pme(struct smu_context *smu)
+{
+ int ret = 0;
+
+ mutex_lock(&smu->mutex);
+ ret = smu_send_smc_msg(smu, SMU_MSG_BacoAudioD3PME);
+ mutex_unlock(&smu->mutex);
+
+ return ret;
+}
+
+static int smu_v11_0_baco_set_armd3_sequence(struct smu_context *smu, enum smu_v11_0_baco_seq baco_seq)
+{
+ return smu_send_smc_msg_with_param(smu, SMU_MSG_ArmD3, baco_seq);
+}
+
+static bool smu_v11_0_baco_is_support(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+ struct smu_baco_context *smu_baco = &smu->smu_baco;
+ uint32_t val;
+ bool baco_support;
+
+ mutex_lock(&smu_baco->mutex);
+ baco_support = smu_baco->platform_support;
+ mutex_unlock(&smu_baco->mutex);
+
+ if (!baco_support)
+ return false;
+
+ if (!smu_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT))
+ return false;
+
+ val = RREG32_SOC15(NBIO, 0, mmRCC_BIF_STRAP0);
+ if (val & RCC_BIF_STRAP0__STRAP_PX_CAPABLE_MASK)
+ return true;
+
+ return false;
+}
+
+static enum smu_baco_state smu_v11_0_baco_get_state(struct smu_context *smu)
+{
+ struct smu_baco_context *smu_baco = &smu->smu_baco;
+ enum smu_baco_state baco_state = SMU_BACO_STATE_EXIT;
+
+ mutex_lock(&smu_baco->mutex);
+ baco_state = smu_baco->state;
+ mutex_unlock(&smu_baco->mutex);
+
+ return baco_state;
+}
+
+static int smu_v11_0_baco_set_state(struct smu_context *smu, enum smu_baco_state state)
+{
+
+ struct smu_baco_context *smu_baco = &smu->smu_baco;
+ int ret = 0;
+
+ if (smu_v11_0_baco_get_state(smu) == state)
+ return 0;
+
+ mutex_lock(&smu_baco->mutex);
+
+ if (state == SMU_BACO_STATE_ENTER)
+ ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnterBaco, BACO_SEQ_BACO);
+ else
+ ret = smu_send_smc_msg(smu, SMU_MSG_ExitBaco);
+ if (ret)
+ goto out;
+
+ smu_baco->state = state;
+out:
+ mutex_unlock(&smu_baco->mutex);
+ return ret;
+}
+
+static int smu_v11_0_baco_reset(struct smu_context *smu)
+{
+ int ret = 0;
+
+ ret = smu_v11_0_baco_set_armd3_sequence(smu, BACO_SEQ_BACO);
+ if (ret)
+ return ret;
+
+ ret = smu_v11_0_baco_set_state(smu, SMU_BACO_STATE_ENTER);
+ if (ret)
+ return ret;
+
+ msleep(10);
+
+ ret = smu_v11_0_baco_set_state(smu, SMU_BACO_STATE_EXIT);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
static const struct smu_funcs smu_v11_0_funcs = {
.init_microcode = smu_v11_0_init_microcode,
.load_microcode = smu_v11_0_load_microcode,
.send_smc_msg = smu_v11_0_send_msg,
.send_smc_msg_with_param = smu_v11_0_send_msg_with_param,
.read_smc_arg = smu_v11_0_read_arg,
- .read_pptable_from_vbios = smu_v11_0_read_pptable_from_vbios,
.setup_pptable = smu_v11_0_setup_pptable,
.init_smc_tables = smu_v11_0_init_smc_tables,
.fini_smc_tables = smu_v11_0_fini_smc_tables,
.write_watermarks_table = smu_v11_0_write_watermarks_table,
.set_min_dcef_deep_sleep = smu_v11_0_set_min_dcef_deep_sleep,
.set_tool_table_location = smu_v11_0_set_tool_table_location,
- .init_display = smu_v11_0_init_display,
+ .init_display_count = smu_v11_0_init_display_count,
.set_allowed_mask = smu_v11_0_set_allowed_mask,
.get_enabled_mask = smu_v11_0_get_enabled_mask,
- .is_dpm_running = smu_v11_0_is_dpm_running,
.system_features_control = smu_v11_0_system_features_control,
.update_feature_enable_state = smu_v11_0_update_feature_enable_state,
.notify_display_change = smu_v11_0_notify_display_change,
.set_deep_sleep_dcefclk = smu_v11_0_set_deep_sleep_dcefclk,
.display_clock_voltage_request = smu_v11_0_display_clock_voltage_request,
.set_watermarks_for_clock_ranges = smu_v11_0_set_watermarks_for_clock_ranges,
- .get_sclk = smu_v11_0_dpm_get_sclk,
- .get_mclk = smu_v11_0_dpm_get_mclk,
- .set_od8_default_settings = smu_v11_0_set_od8_default_settings,
- .conv_power_profile_to_pplib_workload = smu_v11_0_conv_power_profile_to_pplib_workload,
- .get_power_profile_mode = smu_v11_0_get_power_profile_mode,
- .set_power_profile_mode = smu_v11_0_set_power_profile_mode,
- .update_od8_settings = smu_v11_0_update_od8_settings,
- .dpm_set_uvd_enable = smu_v11_0_dpm_set_uvd_enable,
- .dpm_set_vce_enable = smu_v11_0_dpm_set_vce_enable,
.get_current_rpm = smu_v11_0_get_current_rpm,
.get_fan_control_mode = smu_v11_0_get_fan_control_mode,
.set_fan_control_mode = smu_v11_0_set_fan_control_mode,
- .get_fan_speed_percent = smu_v11_0_get_fan_speed_percent,
.set_fan_speed_percent = smu_v11_0_set_fan_speed_percent,
.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,
+ .baco_reset = smu_v11_0_baco_reset,
};
void smu_v11_0_set_smu_funcs(struct smu_context *smu)
vega20_set_ppt_funcs(smu);
break;
case CHIP_NAVI10:
+ case CHIP_NAVI14:
navi10_set_ppt_funcs(smu);
break;
default: