drm/amd/powerplay: add get_max_sustainable_clock function
authorHuang Rui <ray.huang@amd.com>
Tue, 25 Dec 2018 08:34:39 +0000 (16:34 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 19 Mar 2019 20:03:57 +0000 (15:03 -0500)
This patch adds get_max_sustainable_clock function for smu11.

Signed-off-by: Huang Rui <ray.huang@amd.com>
Reviewed-by: Kevin Wang <Kevin1.Wang@amd.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/powerplay/amdgpu_smu.c
drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h
drivers/gpu/drm/amd/powerplay/inc/smu_v11_0.h
drivers/gpu/drm/amd/powerplay/smu_v11_0.c

index b225cf876a9152e0b6c41fda832d0c13ccf2a4dc..cd04369c652bcd9768eb5293f81a57a27543da9a 100644 (file)
@@ -393,6 +393,10 @@ static int smu_smc_table_hw_init(struct smu_context *smu)
        if (ret)
                return ret;
 
+       ret = smu_init_max_sustainable_clocks(smu);
+       if (ret)
+               return ret;
+
        ret = smu_populate_umd_state_clk(smu);
        if (ret)
                return ret;
@@ -539,6 +543,11 @@ static int smu_hw_fini(void *handle)
                return -EINVAL;
        kfree(table_context->driver_pptable);
 
+       if (table_context->max_sustainable_clocks) {
+               kfree(table_context->max_sustainable_clocks);
+               table_context->max_sustainable_clocks = NULL;
+       }
+
        ret = smu_fini_fb_allocations(smu);
        if (ret)
                return ret;
index a3c8b736af840e2cf8f0edd8e4f32792ff189760..a68519ea6dc87d396686c98f0542ff66477c0135 100644 (file)
@@ -158,6 +158,7 @@ struct smu_table_context
        void                            *power_play_table;
        uint32_t                        power_play_table_size;
 
+       void                            *max_sustainable_clocks;
        struct smu_bios_boot_up_values  boot_values;
        void                            *driver_pptable;
        struct smu_table                *tables;
@@ -253,6 +254,7 @@ struct smu_funcs
        int (*notify_display_change)(struct smu_context *smu);
        int (*get_power_limit)(struct smu_context *smu);
        int (*get_current_clk_freq)(struct smu_context *smu, uint32_t clk_id, uint32_t *value);
+       int (*init_max_sustainable_clocks)(struct smu_context *smu);
 };
 
 #define smu_init_microcode(smu) \
@@ -297,6 +299,8 @@ struct smu_funcs
        ((smu)->funcs->set_last_dcef_min_deep_sleep_clk ? (smu)->funcs->set_last_dcef_min_deep_sleep_clk((smu)) : 0)
 #define smu_system_features_control(smu, en) \
        ((smu)->funcs->system_features_control ? (smu)->funcs->system_features_control((smu), (en)) : 0)
+#define smu_init_max_sustainable_clocks(smu) \
+       ((smu)->funcs->init_max_sustainable_clocks ? (smu)->funcs->init_max_sustainable_clocks((smu)) : 0)
 #define smu_send_smc_msg(smu, msg) \
        ((smu)->funcs->send_smc_msg? (smu)->funcs->send_smc_msg((smu), (msg)) : 0)
 #define smu_send_smc_msg_with_param(smu, msg, param) \
index 2853ab717d809507a32a51f50de76716ddc712f0..aa8d81f4111e98ea6bd5279029c9d89cb980241d 100644 (file)
 #define smnMP0_FW_INTF                 0x30101c0
 #define smnMP1_PUB_CTRL                        0x3010b14
 
+struct smu_11_0_max_sustainable_clocks {
+       uint32_t display_clock;
+       uint32_t phy_clock;
+       uint32_t pixel_clock;
+       uint32_t uclock;
+       uint32_t dcef_clock;
+       uint32_t soc_clock;
+};
 
 struct smu_11_0_dpm_table {
        uint32_t    min;        /* MHz */
index def64f5a967df88a52ef897cf7194f70d19f9886..129d2b1c148776e54a288ec6fc9db5f9d7036d42 100644 (file)
@@ -738,6 +738,119 @@ static int smu_v11_0_notify_display_change(struct smu_context *smu)
        return ret;
 }
 
+static int
+smu_v11_0_get_max_sustainable_clock(struct smu_context *smu, uint32_t *clock,
+                                   PPCLK_e clock_select)
+{
+       int ret = 0;
+
+       ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetDcModeMaxDpmFreq,
+                                         clock_select << 16);
+       if (ret) {
+               pr_err("[GetMaxSustainableClock] Failed to get max DC clock from SMC!");
+               return ret;
+       }
+
+       ret = smu_read_smc_arg(smu, clock);
+       if (ret)
+               return ret;
+
+       if (*clock != 0)
+               return 0;
+
+       /* if DC limit is zero, return AC limit */
+       ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetMaxDpmFreq,
+                                         clock_select << 16);
+       if (ret) {
+               pr_err("[GetMaxSustainableClock] failed to get max AC clock from SMC!");
+               return ret;
+       }
+
+       ret = smu_read_smc_arg(smu, clock);
+
+       return ret;
+}
+
+static int smu_v11_0_init_max_sustainable_clocks(struct smu_context *smu)
+{
+       struct smu_11_0_max_sustainable_clocks *max_sustainable_clocks;
+       int ret = 0;
+
+       max_sustainable_clocks = kzalloc(sizeof(struct smu_11_0_max_sustainable_clocks),
+                                        GFP_KERNEL);
+       smu->smu_table.max_sustainable_clocks = (void *)max_sustainable_clocks;
+
+       max_sustainable_clocks->uclock = smu->smu_table.boot_values.uclk / 100;
+       max_sustainable_clocks->soc_clock = smu->smu_table.boot_values.socclk / 100;
+       max_sustainable_clocks->dcef_clock = smu->smu_table.boot_values.dcefclk / 100;
+       max_sustainable_clocks->display_clock = 0xFFFFFFFF;
+       max_sustainable_clocks->phy_clock = 0xFFFFFFFF;
+       max_sustainable_clocks->pixel_clock = 0xFFFFFFFF;
+
+       if (smu_feature_is_enabled(smu, FEATURE_DPM_UCLK_BIT)) {
+               ret = smu_v11_0_get_max_sustainable_clock(smu,
+                                                         &(max_sustainable_clocks->uclock),
+                                                         PPCLK_UCLK);
+               if (ret) {
+                       pr_err("[%s] failed to get max UCLK from SMC!",
+                              __func__);
+                       return ret;
+               }
+       }
+
+       if (smu_feature_is_enabled(smu, FEATURE_DPM_SOCCLK_BIT)) {
+               ret = smu_v11_0_get_max_sustainable_clock(smu,
+                                                         &(max_sustainable_clocks->soc_clock),
+                                                         PPCLK_SOCCLK);
+               if (ret) {
+                       pr_err("[%s] failed to get max SOCCLK from SMC!",
+                              __func__);
+                       return ret;
+               }
+       }
+
+       if (smu_feature_is_enabled(smu, FEATURE_DPM_DCEFCLK_BIT)) {
+               ret = smu_v11_0_get_max_sustainable_clock(smu,
+                                                         &(max_sustainable_clocks->dcef_clock),
+                                                         PPCLK_DCEFCLK);
+               if (ret) {
+                       pr_err("[%s] failed to get max DCEFCLK from SMC!",
+                              __func__);
+                       return ret;
+               }
+
+               ret = smu_v11_0_get_max_sustainable_clock(smu,
+                                                         &(max_sustainable_clocks->display_clock),
+                                                         PPCLK_DISPCLK);
+               if (ret) {
+                       pr_err("[%s] failed to get max DISPCLK from SMC!",
+                              __func__);
+                       return ret;
+               }
+               ret = smu_v11_0_get_max_sustainable_clock(smu,
+                                                         &(max_sustainable_clocks->phy_clock),
+                                                         PPCLK_PHYCLK);
+               if (ret) {
+                       pr_err("[%s] failed to get max PHYCLK from SMC!",
+                              __func__);
+                       return ret;
+               }
+               ret = smu_v11_0_get_max_sustainable_clock(smu,
+                                                         &(max_sustainable_clocks->pixel_clock),
+                                                         PPCLK_PIXCLK);
+               if (ret) {
+                       pr_err("[%s] failed to get max PIXCLK from SMC!",
+                              __func__);
+                       return ret;
+               }
+       }
+
+       if (max_sustainable_clocks->soc_clock < max_sustainable_clocks->uclock)
+               max_sustainable_clocks->uclock = max_sustainable_clocks->soc_clock;
+
+       return 0;
+}
+
 static int smu_v11_0_get_power_limit(struct smu_context *smu)
 {
        int ret;
@@ -810,6 +923,7 @@ static const struct smu_funcs smu_v11_0_funcs = {
        .notify_display_change = smu_v11_0_notify_display_change,
        .get_power_limit = smu_v11_0_get_power_limit,
        .get_current_clk_freq = smu_v11_0_get_current_clk_freq,
+       .init_max_sustainable_clocks = smu_v11_0_init_max_sustainable_clocks,
 };
 
 void smu_v11_0_set_smu_funcs(struct smu_context *smu)