char *buf)
 {
        struct amdgpu_device *adev = dev_get_drvdata(dev);
-       uint32_t limit = 0;
+       int limit_type = to_sensor_dev_attr(attr)->index;
+       uint32_t limit = limit_type << 24;
        ssize_t size;
        int r;
 
                                         char *buf)
 {
        struct amdgpu_device *adev = dev_get_drvdata(dev);
-       uint32_t limit = 0;
+       int limit_type = to_sensor_dev_attr(attr)->index;
+       uint32_t limit = limit_type << 24;
        ssize_t size;
        int r;
 
        return size;
 }
 
+static ssize_t amdgpu_hwmon_show_power_label(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       int limit_type = to_sensor_dev_attr(attr)->index;
+
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+               limit_type == SMU_FAST_PPT_LIMIT ? "fastPPT" : "slowPPT");
+}
 
 static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev,
                struct device_attribute *attr,
                size_t count)
 {
        struct amdgpu_device *adev = dev_get_drvdata(dev);
+       int limit_type = to_sensor_dev_attr(attr)->index;
        int err;
        u32 value;
 
                return err;
 
        value = value / 1000000; /* convert to Watt */
-
+       value |= limit_type << 24;
 
        err = pm_runtime_get_sync(adev_to_drm(adev)->dev);
        if (err < 0) {
 static SENSOR_DEVICE_ATTR(power1_cap_max, S_IRUGO, amdgpu_hwmon_show_power_cap_max, NULL, 0);
 static SENSOR_DEVICE_ATTR(power1_cap_min, S_IRUGO, amdgpu_hwmon_show_power_cap_min, NULL, 0);
 static SENSOR_DEVICE_ATTR(power1_cap, S_IRUGO | S_IWUSR, amdgpu_hwmon_show_power_cap, amdgpu_hwmon_set_power_cap, 0);
+static SENSOR_DEVICE_ATTR(power1_label, S_IRUGO, amdgpu_hwmon_show_power_label, NULL, 0);
+static SENSOR_DEVICE_ATTR(power2_average, S_IRUGO, amdgpu_hwmon_show_power_avg, NULL, 1);
+static SENSOR_DEVICE_ATTR(power2_cap_max, S_IRUGO, amdgpu_hwmon_show_power_cap_max, NULL, 1);
+static SENSOR_DEVICE_ATTR(power2_cap_min, S_IRUGO, amdgpu_hwmon_show_power_cap_min, NULL, 1);
+static SENSOR_DEVICE_ATTR(power2_cap, S_IRUGO | S_IWUSR, amdgpu_hwmon_show_power_cap, amdgpu_hwmon_set_power_cap, 1);
+static SENSOR_DEVICE_ATTR(power2_label, S_IRUGO, amdgpu_hwmon_show_power_label, NULL, 1);
 static SENSOR_DEVICE_ATTR(freq1_input, S_IRUGO, amdgpu_hwmon_show_sclk, NULL, 0);
 static SENSOR_DEVICE_ATTR(freq1_label, S_IRUGO, amdgpu_hwmon_show_sclk_label, NULL, 0);
 static SENSOR_DEVICE_ATTR(freq2_input, S_IRUGO, amdgpu_hwmon_show_mclk, NULL, 0);
        &sensor_dev_attr_power1_cap_max.dev_attr.attr,
        &sensor_dev_attr_power1_cap_min.dev_attr.attr,
        &sensor_dev_attr_power1_cap.dev_attr.attr,
+       &sensor_dev_attr_power1_label.dev_attr.attr,
+       &sensor_dev_attr_power2_average.dev_attr.attr,
+       &sensor_dev_attr_power2_cap_max.dev_attr.attr,
+       &sensor_dev_attr_power2_cap_min.dev_attr.attr,
+       &sensor_dev_attr_power2_cap.dev_attr.attr,
+       &sensor_dev_attr_power2_label.dev_attr.attr,
        &sensor_dev_attr_freq1_input.dev_attr.attr,
        &sensor_dev_attr_freq1_label.dev_attr.attr,
        &sensor_dev_attr_freq2_input.dev_attr.attr,
                        effective_mode &= ~S_IWUSR;
        }
 
-       if (((adev->flags & AMD_IS_APU) ||
-            adev->family == AMDGPU_FAMILY_SI) &&       /* not implemented yet */
+       if (((adev->family == AMDGPU_FAMILY_SI) ||
+                ((adev->flags & AMD_IS_APU) &&
+             (adev->asic_type != CHIP_VANGOGH))) &&    /* not implemented yet */
            (attr == &sensor_dev_attr_power1_cap_max.dev_attr.attr ||
             attr == &sensor_dev_attr_power1_cap_min.dev_attr.attr||
             attr == &sensor_dev_attr_power1_cap.dev_attr.attr))
             attr == &sensor_dev_attr_temp3_label.dev_attr.attr))
                return 0;
 
+       /* only Vangogh has fast PPT limit and power labels */
+       if (!(adev->asic_type == CHIP_VANGOGH) &&
+           (attr == &sensor_dev_attr_power2_average.dev_attr.attr ||
+                attr == &sensor_dev_attr_power2_cap_max.dev_attr.attr ||
+            attr == &sensor_dev_attr_power2_cap_min.dev_attr.attr ||
+                attr == &sensor_dev_attr_power2_cap.dev_attr.attr ||
+                attr == &sensor_dev_attr_power2_label.dev_attr.attr ||
+                attr == &sensor_dev_attr_power1_label.dev_attr.attr))
+               return 0;
+
        return effective_mode;
 }
 
 
        SMU_POWER_SOURCE_COUNT,
 };
 
+enum smu_ppt_limit_type
+{
+       SMU_DEFAULT_PPT_LIMIT = 0,
+       SMU_FAST_PPT_LIMIT,
+};
+
 enum smu_ppt_limit_level
 {
        SMU_PPT_LIMIT_MIN = -1,
         */
        int (*get_power_limit)(struct smu_context *smu);
 
+       /**
+        * @get_ppt_limit: Get the device's ppt limits.
+        */
+       int (*get_ppt_limit)(struct smu_context *smu, uint32_t *ppt_limit,
+                       enum smu_ppt_limit_type limit_type, enum smu_ppt_limit_level limit_level);
+
        /**
         * @set_df_cstate: Set data fabric cstate.
         */
 
        enum smu_11_0_power_state power_state;
 };
 
+struct smu_11_5_power_context {
+       uint32_t        power_source;
+       uint8_t         in_power_limit_boost_mode;
+       enum smu_11_0_power_state power_state;
+
+       uint32_t        current_fast_ppt_limit;
+       uint32_t        max_fast_ppt_limit;
+};
+
 enum smu_v11_0_baco_seq {
        BACO_SEQ_BACO = 0,
        BACO_SEQ_MSR,
 
                        uint32_t *limit,
                        enum smu_ppt_limit_level limit_level)
 {
+       uint32_t limit_type = *limit >> 24;
+       int ret = 0;
+
        if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
                return -EOPNOTSUPP;
 
        mutex_lock(&smu->mutex);
 
-       switch (limit_level) {
-       case SMU_PPT_LIMIT_CURRENT:
-               *limit = smu->current_power_limit;
-               break;
-       case SMU_PPT_LIMIT_MAX:
-               *limit = smu->max_power_limit;
-               break;
-       default:
-               break;
+       if (limit_type != SMU_DEFAULT_PPT_LIMIT) {
+               if (smu->ppt_funcs->get_ppt_limit)
+                       ret = smu->ppt_funcs->get_ppt_limit(smu, limit, limit_type, limit_level);
+       } else {
+               switch (limit_level) {
+               case SMU_PPT_LIMIT_CURRENT:
+                       *limit = smu->current_power_limit;
+                       break;
+               case SMU_PPT_LIMIT_MAX:
+                       *limit = smu->max_power_limit;
+                       break;
+               default:
+                       break;
+               }
        }
 
        mutex_unlock(&smu->mutex);
 
-       return 0;
+       return ret;
 }
 
 int smu_set_power_limit(struct smu_context *smu, uint32_t limit)
 {
+       uint32_t limit_type = limit >> 24;
        int ret = 0;
 
        if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
 
        mutex_lock(&smu->mutex);
 
+       if (limit_type != SMU_DEFAULT_PPT_LIMIT)
+               if (smu->ppt_funcs->set_power_limit) {
+                       ret = smu->ppt_funcs->set_power_limit(smu, limit);
+                       goto out;
+               }
+
        if (limit > smu->max_power_limit) {
                dev_err(smu->adev->dev,
                        "New power limit (%d) is over the max allowed %d\n",
 
 int smu_v11_0_init_power(struct smu_context *smu)
 {
        struct smu_power_context *smu_power = &smu->smu_power;
+       size_t size = smu->adev->asic_type == CHIP_VANGOGH ?
+                       sizeof(struct smu_11_5_power_context) :
+                       sizeof(struct smu_11_0_power_context);
 
-       smu_power->power_context = kzalloc(sizeof(struct smu_11_0_power_context),
-                                          GFP_KERNEL);
+       smu_power->power_context = kzalloc(size, GFP_KERNEL);
        if (!smu_power->power_context)
                return -ENOMEM;
-       smu_power->power_context_size = sizeof(struct smu_11_0_power_context);
+       smu_power->power_context_size = size;
 
        return 0;
 }
 
        MSG_MAP(SetSoftMinCclk,                     PPSMC_MSG_SetSoftMinCclk,                                           0),
        MSG_MAP(SetSoftMaxCclk,                     PPSMC_MSG_SetSoftMaxCclk,                                           0),
        MSG_MAP(RequestActiveWgp,                   PPSMC_MSG_RequestActiveWgp,                     0),
+       MSG_MAP(SetFastPPTLimit,                    PPSMC_MSG_SetFastPPTLimit,                                          0),
+       MSG_MAP(SetSlowPPTLimit,                    PPSMC_MSG_SetSlowPPTLimit,                                          0),
+       MSG_MAP(GetFastPPTLimit,                    PPSMC_MSG_GetFastPPTLimit,                                          0),
+       MSG_MAP(GetSlowPPTLimit,                    PPSMC_MSG_GetSlowPPTLimit,                                          0),
 };
 
 static struct cmn2asic_mapping vangogh_feature_mask_map[SMU_FEATURE_COUNT] = {
        return vangogh_mode_reset(smu, SMU_RESET_MODE_2);
 }
 
+static int vangogh_get_power_limit(struct smu_context *smu)
+{
+       struct smu_11_5_power_context *power_context =
+                                                               smu->smu_power.power_context;
+       uint32_t ppt_limit;
+       int ret = 0;
+
+       if (smu->adev->pm.fw_version < 0x43f1e00)
+               return ret;
+
+       ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetSlowPPTLimit, &ppt_limit);
+       if (ret) {
+               dev_err(smu->adev->dev, "Get slow PPT limit failed!\n");
+               return ret;
+       }
+       /* convert from milliwatt to watt */
+       smu->current_power_limit = ppt_limit / 1000;
+       smu->max_power_limit = 29;
+
+       ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetFastPPTLimit, &ppt_limit);
+       if (ret) {
+               dev_err(smu->adev->dev, "Get fast PPT limit failed!\n");
+               return ret;
+       }
+       /* convert from milliwatt to watt */
+       power_context->current_fast_ppt_limit = ppt_limit / 1000;
+       power_context->max_fast_ppt_limit = 30;
+
+       return ret;
+}
+
+static int vangogh_get_ppt_limit(struct smu_context *smu,
+                                                               uint32_t *ppt_limit,
+                                                               enum smu_ppt_limit_type type,
+                                                               enum smu_ppt_limit_level level)
+{
+       struct smu_11_5_power_context *power_context =
+                                                       smu->smu_power.power_context;
+
+       if (!power_context)
+               return -EOPNOTSUPP;
+
+       if (type == SMU_FAST_PPT_LIMIT) {
+               switch (level) {
+               case SMU_PPT_LIMIT_MAX:
+                       *ppt_limit = power_context->max_fast_ppt_limit;
+                       break;
+               case SMU_PPT_LIMIT_CURRENT:
+                       *ppt_limit = power_context->current_fast_ppt_limit;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int vangogh_set_power_limit(struct smu_context *smu, uint32_t ppt_limit)
+{
+       struct smu_11_5_power_context *power_context =
+                                                       smu->smu_power.power_context;
+       uint32_t limit_type = ppt_limit >> 24;
+       int ret = 0;
+
+       if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) {
+               dev_err(smu->adev->dev, "Setting new power limit is not supported!\n");
+               return -EOPNOTSUPP;
+       }
+
+       switch (limit_type) {
+       case SMU_DEFAULT_PPT_LIMIT:
+               ret = smu_cmn_send_smc_msg_with_param(smu,
+                               SMU_MSG_SetSlowPPTLimit,
+                               ppt_limit * 1000, /* convert from watt to milliwatt */
+                               NULL);
+               if (ret)
+                       return ret;
+
+               smu->current_power_limit = ppt_limit;
+               break;
+       case SMU_FAST_PPT_LIMIT:
+               ppt_limit &= ~(SMU_FAST_PPT_LIMIT << 24);
+               if (ppt_limit > power_context->max_fast_ppt_limit) {
+                       dev_err(smu->adev->dev,
+                               "New power limit (%d) is over the max allowed %d\n",
+                               ppt_limit, power_context->max_fast_ppt_limit);
+                       return ret;
+               }
+
+               ret = smu_cmn_send_smc_msg_with_param(smu,
+                               SMU_MSG_SetFastPPTLimit,
+                               ppt_limit * 1000, /* convert from watt to milliwatt */
+                               NULL);
+               if (ret)
+                       return ret;
+
+               power_context->current_fast_ppt_limit = ppt_limit;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
 static const struct pptable_funcs vangogh_ppt_funcs = {
 
        .check_fw_status = smu_v11_0_check_fw_status,
        .post_init = vangogh_post_smu_init,
        .mode2_reset = vangogh_mode2_reset,
        .gfx_off_control = smu_v11_0_gfx_off_control,
+       .get_ppt_limit = vangogh_get_ppt_limit,
+       .get_power_limit = vangogh_get_power_limit,
+       .set_power_limit = vangogh_set_power_limit,
 };
 
 void vangogh_set_ppt_funcs(struct smu_context *smu)