OSDN Git Service

drm/amd/powerplay: add one sysfs file to support the feature to modify gfx clock...
authorXiaojian Du <Xiaojian.Du@amd.com>
Sun, 27 Sep 2020 09:07:02 +0000 (17:07 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 29 Sep 2020 20:12:16 +0000 (16:12 -0400)
This patch is to add one sysfs file -- "pp_od_clk_voltage" for
Raven/Raven2/Picasso APU, which is only used by dGPU like VEGA10.
This sysfs file supports the feature to modify gfx engine clock(Mhz units), it can
be used to configure the min value and the max value for gfx clock limited in the
safe range.

Command guide:
echo "s level clock" > pp_od_clk_voltage
s - adjust teh sclk level
level - 0 or 1, "0" represents the min value, "1" represents the max value
clock - the clock value(Mhz units), like 400, 800 or 1200, the value must be within the
                OD_RANGE limits.
Example:
$ cat pp_od_clk_voltage
OD_SCLK:
0:        200Mhz
1:       1400Mhz
OD_RANGE:
SCLK:     200MHz       1400MHz

$ echo "s 0 600" > pp_od_clk_voltage
$ echo "s 1 1000" > pp_od_clk_voltage
$ cat pp_od_clk_voltage
OD_SCLK:
0:        600Mhz
1:       1000Mhz
OD_RANGE:
SCLK:     200MHz       1400MHz

Signed-off-by: Xiaojian Du <Xiaojian.Du@amd.com>
Reviewed-by: Kevin Wang <kevin1.wang@amd.com>
Reviewed-by: Huang Rui <ray.huang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/include/kgd_pp_interface.h
drivers/gpu/drm/amd/pm/amdgpu_pm.c
drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
drivers/gpu/drm/amd/pm/inc/hwmgr.h
drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c
drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.h

index 0aec28f..94132c7 100644 (file)
@@ -281,6 +281,7 @@ struct amd_pm_funcs {
        int (*get_power_limit)(void *handle, uint32_t *limit, bool default_limit);
        int (*get_power_profile_mode)(void *handle, char *buf);
        int (*set_power_profile_mode)(void *handle, long *input, uint32_t size);
+       int (*set_fine_grain_clk_vol)(void *handle, uint32_t type, long *input, uint32_t size);
        int (*odn_edit_dpm_table)(void *handle, uint32_t type, long *input, uint32_t size);
        int (*set_mp1_state)(void *handle, enum pp_mp1_state mp1_state);
        int (*smu_i2c_bus_access)(void *handle, bool acquire);
index 2d924e8..5298166 100644 (file)
@@ -827,6 +827,18 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev,
                        return -EINVAL;
                }
        } else {
+
+               if (adev->powerplay.pp_funcs->set_fine_grain_clk_vol) {
+                       ret = amdgpu_dpm_set_fine_grain_clk_vol(adev, type,
+                                                               parameter,
+                                                               parameter_size);
+                       if (ret) {
+                               pm_runtime_mark_last_busy(ddev->dev);
+                               pm_runtime_put_autosuspend(ddev->dev);
+                               return -EINVAL;
+                       }
+               }
+
                if (adev->powerplay.pp_funcs->odn_edit_dpm_table) {
                        ret = amdgpu_dpm_odn_edit_dpm_table(adev, type,
                                                parameter, parameter_size);
index dff4a5f..f6e0e7d 100644 (file)
@@ -349,6 +349,10 @@ enum amdgpu_pcie_gen {
                ((adev)->powerplay.pp_funcs->set_power_profile_mode(\
                        (adev)->powerplay.pp_handle, parameter, size))
 
+#define amdgpu_dpm_set_fine_grain_clk_vol(adev, type, parameter, size) \
+               ((adev)->powerplay.pp_funcs->set_fine_grain_clk_vol(\
+                       (adev)->powerplay.pp_handle, type, parameter, size))
+
 #define amdgpu_dpm_odn_edit_dpm_table(adev, type, parameter, size) \
                ((adev)->powerplay.pp_funcs->odn_edit_dpm_table(\
                        (adev)->powerplay.pp_handle, type, parameter, size))
index 1b3529e..3898a95 100644 (file)
@@ -340,6 +340,9 @@ struct pp_hwmgr_func {
        int (*odn_edit_dpm_table)(struct pp_hwmgr *hwmgr,
                                        enum PP_OD_DPM_TABLE_COMMAND type,
                                        long *input, uint32_t size);
+       int (*set_fine_grain_clk_vol)(struct pp_hwmgr *hwmgr,
+                                     enum PP_OD_DPM_TABLE_COMMAND type,
+                                     long *input, uint32_t size);
        int (*set_power_limit)(struct pp_hwmgr *hwmgr, uint32_t n);
        int (*powergate_mmhub)(struct pp_hwmgr *hwmgr);
        int (*smus_notify_pwe)(struct pp_hwmgr *hwmgr);
@@ -347,6 +350,8 @@ struct pp_hwmgr_func {
        int (*enable_mgpu_fan_boost)(struct pp_hwmgr *hwmgr);
        int (*set_hard_min_dcefclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock);
        int (*set_hard_min_fclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock);
+       int (*set_hard_min_gfxclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock);
+       int (*set_soft_max_gfxclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock);
        int (*get_asic_baco_capability)(struct pp_hwmgr *hwmgr, bool *cap);
        int (*get_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE *state);
        int (*set_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE state);
index a6321f2..eab9768 100644 (file)
@@ -911,6 +911,19 @@ static int pp_set_power_profile_mode(void *handle, long *input, uint32_t size)
        return ret;
 }
 
+static int pp_set_fine_grain_clk_vol(void *handle, uint32_t type, long *input, uint32_t size)
+{
+       struct pp_hwmgr *hwmgr = handle;
+
+       if (!hwmgr || !hwmgr->pm_en)
+               return -EINVAL;
+
+       if (hwmgr->hwmgr_func->set_fine_grain_clk_vol == NULL)
+               return 0;
+
+       return hwmgr->hwmgr_func->set_fine_grain_clk_vol(hwmgr, type, input, size);
+}
+
 static int pp_odn_edit_dpm_table(void *handle, uint32_t type, long *input, uint32_t size)
 {
        struct pp_hwmgr *hwmgr = handle;
@@ -920,7 +933,7 @@ static int pp_odn_edit_dpm_table(void *handle, uint32_t type, long *input, uint3
 
        if (hwmgr->hwmgr_func->odn_edit_dpm_table == NULL) {
                pr_info_ratelimited("%s was not implemented.\n", __func__);
-               return -EINVAL;
+               return 0;
        }
 
        return hwmgr->hwmgr_func->odn_edit_dpm_table(hwmgr, type, input, size);
@@ -1645,6 +1658,7 @@ static const struct amd_pm_funcs pp_dpm_funcs = {
        .set_powergating_by_smu = pp_set_powergating_by_smu,
        .get_power_profile_mode = pp_get_power_profile_mode,
        .set_power_profile_mode = pp_set_power_profile_mode,
+       .set_fine_grain_clk_vol = pp_set_fine_grain_clk_vol,
        .odn_edit_dpm_table = pp_odn_edit_dpm_table,
        .set_mp1_state = pp_dpm_set_mp1_state,
        .set_power_limit = pp_set_power_limit,
index e0ac546..cf60f39 100644 (file)
@@ -242,6 +242,34 @@ static int smu10_set_hard_min_fclk_by_freq(struct pp_hwmgr *hwmgr, uint32_t cloc
        return 0;
 }
 
+static int smu10_set_hard_min_gfxclk_by_freq(struct pp_hwmgr *hwmgr, uint32_t clock)
+{
+       struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
+
+       if (clock && smu10_data->gfx_actual_soft_min_freq != clock) {
+               smu10_data->gfx_actual_soft_min_freq = clock;
+               smum_send_msg_to_smc_with_parameter(hwmgr,
+                                       PPSMC_MSG_SetHardMinGfxClk,
+                                       smu10_data->gfx_actual_soft_min_freq,
+                                       NULL);
+       }
+       return 0;
+}
+
+static int smu10_set_soft_max_gfxclk_by_freq(struct pp_hwmgr *hwmgr, uint32_t clock)
+{
+       struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
+
+       if (clock && smu10_data->gfx_max_freq_limit != (clock * 100))  {
+               smu10_data->gfx_max_freq_limit = clock * 100;
+               smum_send_msg_to_smc_with_parameter(hwmgr,
+                                       PPSMC_MSG_SetSoftMaxGfxClk,
+                                       clock,
+                                       NULL);
+       }
+       return 0;
+}
+
 static int smu10_set_active_display_count(struct pp_hwmgr *hwmgr, uint32_t count)
 {
        struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
@@ -527,6 +555,9 @@ static int smu10_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
        hwmgr->pstate_sclk = SMU10_UMD_PSTATE_GFXCLK * 100;
        hwmgr->pstate_mclk = SMU10_UMD_PSTATE_FCLK * 100;
 
+       /* enable the pp_od_clk_voltage sysfs file */
+       hwmgr->od_enabled = 1;
+
        return result;
 }
 
@@ -949,6 +980,26 @@ static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr,
                                        ((mclk_table->entries[i].clk / 100)
                                         == now) ? "*" : "");
                break;
+       case OD_SCLK:
+               if (hwmgr->od_enabled) {
+                       size = sprintf(buf, "%s:\n", "OD_SCLK");
+
+                       size += sprintf(buf + size, "0: %10uMhz\n",
+                       (data->gfx_actual_soft_min_freq > 0) ? data->gfx_actual_soft_min_freq : data->gfx_min_freq_limit/100);
+                       size += sprintf(buf + size, "1: %10uMhz\n", data->gfx_max_freq_limit/100);
+               }
+               break;
+       case OD_RANGE:
+               if (hwmgr->od_enabled) {
+                       uint32_t min_freq, max_freq = 0;
+                       smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency, &min_freq);
+                       smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency, &max_freq);
+
+                       size = sprintf(buf, "%s:\n", "OD_RANGE");
+                       size += sprintf(buf + size, "SCLK: %7uMHz %10uMHz\n",
+                               min_freq, max_freq);
+               }
+               break;
        default:
                break;
        }
@@ -1361,6 +1412,32 @@ static int smu10_asic_reset(struct pp_hwmgr *hwmgr, enum SMU_ASIC_RESET_MODE mod
                                                   NULL);
 }
 
+static int smu10_set_fine_grain_clk_vol(struct pp_hwmgr *hwmgr,
+                                       enum PP_OD_DPM_TABLE_COMMAND type,
+                                       long *input, uint32_t size)
+{
+       if (!hwmgr->od_enabled) {
+               pr_err("Fine grain not support\n");
+               return -EINVAL;
+       }
+
+       if (size != 2) {
+               pr_err("Input parameter number not correct\n");
+               return -EINVAL;
+       }
+
+       if (type == PP_OD_EDIT_SCLK_VDDC_TABLE) {
+               if (input[0] == 0)
+                       smu10_set_hard_min_gfxclk_by_freq(hwmgr, input[1]);
+               else if (input[0] == 1)
+                       smu10_set_soft_max_gfxclk_by_freq(hwmgr, input[1]);
+               else
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
 static const struct pp_hwmgr_func smu10_hwmgr_funcs = {
        .backend_init = smu10_hwmgr_backend_init,
        .backend_fini = smu10_hwmgr_backend_fini,
@@ -1401,9 +1478,12 @@ static const struct pp_hwmgr_func smu10_hwmgr_funcs = {
        .powergate_sdma = smu10_powergate_sdma,
        .set_hard_min_dcefclk_by_freq = smu10_set_hard_min_dcefclk_by_freq,
        .set_hard_min_fclk_by_freq = smu10_set_hard_min_fclk_by_freq,
+       .set_hard_min_gfxclk_by_freq = smu10_set_hard_min_gfxclk_by_freq,
+       .set_soft_max_gfxclk_by_freq = smu10_set_soft_max_gfxclk_by_freq,
        .get_power_profile_mode = smu10_get_power_profile_mode,
        .set_power_profile_mode = smu10_set_power_profile_mode,
        .asic_reset = smu10_asic_reset,
+       .set_fine_grain_clk_vol = smu10_set_fine_grain_clk_vol,
 };
 
 int smu10_init_function_pointers(struct pp_hwmgr *hwmgr)
index ee0c959..6c9b5f0 100644 (file)
@@ -284,7 +284,7 @@ struct smu10_hwmgr {
        uint32_t                        dclk_soft_min;
        uint32_t                        gfx_actual_soft_min_freq;
        uint32_t                        gfx_min_freq_limit;
-       uint32_t                        gfx_max_freq_limit;
+       uint32_t                        gfx_max_freq_limit; /* in 10Khz*/
 
        bool                           vcn_power_gated;
        bool                           vcn_dpg_mode;