]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/gpu/drm/amd/powerplay/smu_v11_0.c
drm/amdgpu/smu11: add support for navi14
[linux.git] / drivers / gpu / drm / amd / powerplay / smu_v11_0.c
index 297cd1bce4fe9d93ad8a0ecf36ce818411f30b19..0e9eead6ad29b6e9b4a7595bf6672c6df7ba373d 100644 (file)
  * 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 "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_THERMAL_MINIMUM_ALERT_TEMP      0
-#define SMU11_THERMAL_MAXIMUM_ALERT_TEMP      255
-
-#define SMU11_TEMPERATURE_UNITS_PER_CENTIGRADES 1000
 #define SMU11_VOLTAGE_SCALE 4
 
 static int smu_v11_0_send_msg_without_waiting(struct smu_context *smu,
@@ -69,9 +69,9 @@ static int smu_v11_0_read_arg(struct smu_context *smu, uint32_t *arg)
 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;
@@ -79,7 +79,7 @@ static int smu_v11_0_wait_for_response(struct smu_context *smu)
        }
 
        /* 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;
@@ -158,6 +158,9 @@ static int smu_v11_0_init_microcode(struct smu_context *smu)
        case CHIP_NAVI10:
                chip_name = "navi10";
                break;
+       case CHIP_NAVI14:
+               chip_name = "navi14";
+               break;
        default:
                BUG();
        }
@@ -262,12 +265,20 @@ static int smu_v11_0_check_fw_version(struct smu_context *smu)
        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;
@@ -407,7 +418,9 @@ static int smu_v11_0_init_smc_tables(struct smu_context *smu)
 
        smu_table->tables = tables;
 
-       smu_tables_init(smu, tables);
+       ret = smu_tables_init(smu, tables);
+       if (ret)
+               return ret;
 
        ret = smu_v11_0_init_dpm_context(smu);
        if (ret)
@@ -425,8 +438,11 @@ static int smu_v11_0_fini_smc_tables(struct smu_context *smu)
                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)
@@ -449,13 +465,6 @@ static int smu_v11_0_init_power(struct smu_context *smu)
                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;
 }
 
@@ -468,9 +477,7 @@ static int smu_v11_0_fini_power(struct smu_context *smu)
        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;
 
@@ -706,7 +713,7 @@ static int smu_v11_0_write_pptable(struct smu_context *smu)
        struct smu_table_context *table_context = &smu->smu_table;
        int ret = 0;
 
-       ret = smu_update_table(smu, SMU_TABLE_PPTABLE,
+       ret = smu_update_table(smu, SMU_TABLE_PPTABLE, 0,
                               table_context->driver_pptable, true);
 
        return ret;
@@ -725,7 +732,7 @@ static int smu_v11_0_write_watermarks_table(struct smu_context *smu)
        if (!table->cpu_addr)
                return -EINVAL;
 
-       ret = smu_update_table(smu, SMU_TABLE_WATERMARKS, table->cpu_addr,
+       ret = smu_update_table(smu, SMU_TABLE_WATERMARKS, 0, table->cpu_addr,
                                true);
 
        return ret;
@@ -774,13 +781,14 @@ static int smu_v11_0_set_tool_table_location(struct smu_context *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;
 }
 
@@ -1091,7 +1099,7 @@ static int smu_v11_0_get_current_clk_freq(struct smu_context *smu,
                                          uint32_t *value)
 {
        int ret = 0;
-       uint32_t freq;
+       uint32_t freq = 0;
 
        if (clk_id >= SMU_CLK_COUNT || !value)
                return -EINVAL;
@@ -1116,38 +1124,19 @@ static int smu_v11_0_get_current_clk_freq(struct smu_context *smu,
        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)
@@ -1159,8 +1148,10 @@ static int smu_v11_0_set_thermal_range(struct smu_context *smu,
        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);
@@ -1185,7 +1176,7 @@ static int smu_v11_0_enable_thermal_alert(struct smu_context *smu)
 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,
@@ -1199,7 +1190,7 @@ static int smu_v11_0_start_thermal_control(struct smu_context *smu)
 
        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);
@@ -1209,6 +1200,7 @@ static int smu_v11_0_start_thermal_control(struct smu_context *smu)
                ret = smu_v11_0_enable_thermal_alert(smu);
                if (ret)
                        return ret;
+
                ret = smu_set_thermal_fan_table(smu);
                if (ret)
                        return ret;
@@ -1227,69 +1219,6 @@ static int smu_v11_0_start_thermal_control(struct smu_context *smu)
        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, 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_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 uint16_t convert_to_vddc(uint8_t vid)
 {
        return (uint16_t) ((6200 - (vid * 25)) / SMU11_VOLTAGE_SCALE);
@@ -1328,12 +1257,6 @@ static int smu_v11_0_read_sensor(struct smu_context *smu,
                ret = smu_get_current_clk_freq(smu, SMU_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_VDDGFX:
                ret = smu_v11_0_get_gfx_vdd(smu, (uint32_t *)data);
                *size = 4;
@@ -1369,7 +1292,9 @@ smu_v11_0_display_clock_voltage_request(struct smu_context *smu,
 
        if (!smu->pm_enabled)
                return -EINVAL;
-       if (smu_feature_is_enabled(smu, 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 = SMU_DCEFCLK;
@@ -1383,6 +1308,9 @@ smu_v11_0_display_clock_voltage_request(struct smu_context *smu,
                case amd_pp_phy_clock:
                        clk_select = SMU_PHYCLK;
                        break;
+               case amd_pp_mem_clock:
+                       clk_select = SMU_UCLK;
+                       break;
                default:
                        pr_info("[%s] Invalid Clock Type!", __func__);
                        ret = -EINVAL;
@@ -1392,8 +1320,10 @@ smu_v11_0_display_clock_voltage_request(struct smu_context *smu,
                if (ret)
                        goto failed;
 
+               mutex_lock(&smu->mutex);
                ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinByFreq,
                        (smu_clk_get_index(smu, clk_select) << 16) | clk_freq);
+               mutex_unlock(&smu->mutex);
        }
 
 failed:
@@ -1445,158 +1375,6 @@ static int smu_v11_0_gfx_off_control(struct smu_context *smu, bool enable)
        return ret;
 }
 
-
-static int smu_v11_0_get_clock_ranges(struct smu_context *smu,
-                                     uint32_t *clock,
-                                     enum smu_clk_type clock_select,
-                                     bool max)
-{
-       int ret;
-       *clock = 0;
-       if (max) {
-               ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetMaxDpmFreq,
-                               smu_clk_get_index(smu, 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,
-                               smu_clk_get_index(smu, 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, 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, SMU_GFXCLK, false);
-               if (ret) {
-                       pr_err("[GetSclks]: fail to get min SMU_GFXCLK\n");
-                       return ret;
-               }
-       } else {
-               ret = smu_v11_0_get_clock_ranges(smu, &gfx_clk, SMU_GFXCLK, true);
-               if (ret) {
-                       pr_err("[GetSclks]: fail to get max SMU_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, 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, SMU_UCLK, false);
-               if (ret) {
-                       pr_err("[GetMclks]: fail to get min SMU_UCLK\n");
-                       return ret;
-               }
-       } else {
-               ret = smu_v11_0_get_clock_ranges(smu, &mem_clk, SMU_GFXCLK, true);
-               if (ret) {
-                       pr_err("[GetMclks]: fail to get max SMU_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;
-       struct smu_table *table = &table_context->tables[SMU_TABLE_OVERDRIVE];
-       int ret;
-
-       /**
-        * TODO: Enable overdrive for navi10, that replies on smc/pptable
-        * support.
-        */
-       if (smu->adev->asic_type == CHIP_NAVI10)
-               return 0;
-
-       if (initialize) {
-               if (table_context->overdrive_table)
-                       return -EINVAL;
-
-               table_context->overdrive_table = kzalloc(table->size, GFP_KERNEL);
-
-               if (!table_context->overdrive_table)
-                       return -ENOMEM;
-
-               ret = smu_update_table(smu, 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, 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_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, 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, 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_get_current_rpm(struct smu_context *smu,
                                     uint32_t *current_rpm)
 {
@@ -1759,6 +1537,208 @@ static int smu_v11_0_set_xgmi_pstate(struct smu_context *smu,
        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,
@@ -1782,7 +1762,7 @@ static const struct smu_funcs smu_v11_0_funcs = {
        .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,
        .system_features_control = smu_v11_0_system_features_control,
@@ -1797,10 +1777,6 @@ static const struct smu_funcs smu_v11_0_funcs = {
        .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,
-       .update_od8_settings = smu_v11_0_update_od8_settings,
        .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,
@@ -1808,6 +1784,13 @@ static const struct smu_funcs smu_v11_0_funcs = {
        .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)
@@ -1820,6 +1803,7 @@ 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: