<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style type="text/css" style="display:none;"> P {margin-top:0;margin-bottom:0;} </style>
</head>
<body dir="ltr">
<p style="font-family:Arial;font-size:10pt;color:#0078D7;margin:15pt;" align="Left">
[AMD Official Use Only - Internal Distribution Only]<br>
</p>
<br>
<div>
<div id="appendonsend"></div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
comment inline.</div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
<br>
</div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
after fixed, the patch is </div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
Reviewed-by: Kevin Wang <kevin1.wang@amd.com></div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
<br>
</div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
Best Regards,<br>
Kevin</div>
<hr tabindex="-1" style="display:inline-block; width:98%">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" color="#000000" style="font-size:11pt"><b>From:</b> Du, Xiaojian <Xiaojian.Du@amd.com><br>
<b>Sent:</b> Monday, September 28, 2020 3:15 PM<br>
<b>To:</b> amd-gfx@lists.freedesktop.org <amd-gfx@lists.freedesktop.org><br>
<b>Cc:</b> Huang, Ray <Ray.Huang@amd.com>; Wang, Kevin(Yang) <Kevin1.Wang@amd.com>; Deucher, Alexander <Alexander.Deucher@amd.com>; Quan, Evan <Evan.Quan@amd.com>; Huang, Shimmer <Xinmei.Huang@amd.com>; Du, Xiaojian <Xiaojian.Du@amd.com>; Du, Xiaojian <Xiaojian.Du@amd.com><br>
<b>Subject:</b> [PATCH] drm/amd/powerplay: add one sysfs file -- "pp_od_clk_voltage" to support the feature to modify gfx engine clock(Mhz units) on Raven/Raven2/Picasso APU.</font>
<div> </div>
</div>
<div class="BodyFragment"><font size="2"><span style="font-size:11pt">
<div class="PlainText">From: Xiaojian Du <xiaojian.du@amd.com><br>
<br>
From: Xiaojian Du <Xiaojian.Du@amd.com></div>
<div class="PlainText"><br>
</div>
<div class="PlainText">[Kevin]: the patch title is too long, please simplify it. <br>
<br>
This patch is to add one sysfs file -- "pp_od_clk_voltage" for<br>
Raven/Raven2/Picasso APU, which is only used by dGPU like VEGA10.<br>
This sysfs file supports the feature to modify gfx engine clock(Mhz units), it can<br>
be used to configure the min value and the max value for gfx clock limited in the<br>
safe range.<br>
<br>
Command guide:<br>
echo "s level clock" > pp_od_clk_voltage<br>
        s - adjust teh sclk level<br>
        level - 0 or 1, "0" represents the min value, "1" represents the max value<br>
        clock - the clock value(Mhz units), like 400, 800 or 1200, the value must be within the<br>
                OD_RANGE limits.<br>
Example:<br>
$ cat pp_od_clk_voltage<br>
OD_SCLK:<br>
0:        200Mhz<br>
1:       1400Mhz<br>
OD_RANGE:<br>
SCLK:     200MHz       1400MHz<br>
<br>
$ echo "s 0 600" > pp_od_clk_voltage<br>
$ echo "s 1 1000" > pp_od_clk_voltage<br>
$ cat pp_od_clk_voltage<br>
OD_SCLK:<br>
0:        600Mhz<br>
1:       1000Mhz<br>
OD_RANGE:<br>
SCLK:     200MHz       1400MHz<br>
<br>
Signed-off-by: Xiaojian Du <Xiaojian.Du@amd.com><br>
---<br>
 .../gpu/drm/amd/include/kgd_pp_interface.h    |  1 +<br>
 drivers/gpu/drm/amd/pm/amdgpu_pm.c            | 12 +++<br>
 drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h       |  4 +<br>
 drivers/gpu/drm/amd/pm/inc/hwmgr.h            |  5 ++<br>
 .../gpu/drm/amd/pm/powerplay/amd_powerplay.c  | 17 +++-<br>
 .../drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c  | 79 +++++++++++++++++++<br>
 6 files changed, 117 insertions(+), 1 deletion(-)<br>
<br>
diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h<br>
index 0aec28fda058..94132c70d7af 100644<br>
--- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h<br>
+++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h<br>
@@ -281,6 +281,7 @@ struct amd_pm_funcs {<br>
         int (*get_power_limit)(void *handle, uint32_t *limit, bool default_limit);<br>
         int (*get_power_profile_mode)(void *handle, char *buf);<br>
         int (*set_power_profile_mode)(void *handle, long *input, uint32_t size);<br>
+       int (*set_fine_grain_clk_vol)(void *handle, uint32_t type, long *input, uint32_t size);<br>
         int (*odn_edit_dpm_table)(void *handle, uint32_t type, long *input, uint32_t size);<br>
         int (*set_mp1_state)(void *handle, enum pp_mp1_state mp1_state);<br>
         int (*smu_i2c_bus_access)(void *handle, bool acquire);<br>
diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c<br>
index b5d2f30043ad..fe0de00f56e2 100644<br>
--- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c<br>
+++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c<br>
@@ -827,6 +827,18 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev,<br>
                         return -EINVAL;<br>
                 }<br>
         } else {<br>
+<br>
+               if (adev->powerplay.pp_funcs->set_fine_grain_clk_vol) {<br>
+                       ret = amdgpu_dpm_set_fine_grain_clk_vol(adev, type,<br>
+                                                               parameter,<br>
+                                                               parameter_size);<br>
+                       if (ret) {<br>
+                               pm_runtime_mark_last_busy(ddev->dev);<br>
+                               pm_runtime_put_autosuspend(ddev->dev);<br>
+                               return -EINVAL;<br>
+                       }<br>
+               }<br>
+<br>
                 if (adev->powerplay.pp_funcs->odn_edit_dpm_table) {<br>
                         ret = amdgpu_dpm_odn_edit_dpm_table(adev, type,<br>
                                                 parameter, parameter_size);<br>
diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h<br>
index dff4a5f99bb0..f6e0e7d8a007 100644<br>
--- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h<br>
+++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h<br>
@@ -349,6 +349,10 @@ enum amdgpu_pcie_gen {<br>
                 ((adev)->powerplay.pp_funcs->set_power_profile_mode(\<br>
                         (adev)->powerplay.pp_handle, parameter, size))<br>
 <br>
+#define amdgpu_dpm_set_fine_grain_clk_vol(adev, type, parameter, size) \<br>
+               ((adev)->powerplay.pp_funcs->set_fine_grain_clk_vol(\<br>
+                       (adev)->powerplay.pp_handle, type, parameter, size))<br>
+<br>
 #define amdgpu_dpm_odn_edit_dpm_table(adev, type, parameter, size) \<br>
                 ((adev)->powerplay.pp_funcs->odn_edit_dpm_table(\<br>
                         (adev)->powerplay.pp_handle, type, parameter, size))<br>
diff --git a/drivers/gpu/drm/amd/pm/inc/hwmgr.h b/drivers/gpu/drm/amd/pm/inc/hwmgr.h<br>
index 1b3529efc91e..3898a95ec28b 100644<br>
--- a/drivers/gpu/drm/amd/pm/inc/hwmgr.h<br>
+++ b/drivers/gpu/drm/amd/pm/inc/hwmgr.h<br>
@@ -340,6 +340,9 @@ struct pp_hwmgr_func {<br>
         int (*odn_edit_dpm_table)(struct pp_hwmgr *hwmgr,<br>
                                         enum PP_OD_DPM_TABLE_COMMAND type,<br>
                                         long *input, uint32_t size);<br>
+       int (*set_fine_grain_clk_vol)(struct pp_hwmgr *hwmgr,<br>
+                                     enum PP_OD_DPM_TABLE_COMMAND type,<br>
+                                     long *input, uint32_t size);<br>
         int (*set_power_limit)(struct pp_hwmgr *hwmgr, uint32_t n);<br>
         int (*powergate_mmhub)(struct pp_hwmgr *hwmgr);<br>
         int (*smus_notify_pwe)(struct pp_hwmgr *hwmgr);<br>
@@ -347,6 +350,8 @@ struct pp_hwmgr_func {<br>
         int (*enable_mgpu_fan_boost)(struct pp_hwmgr *hwmgr);<br>
         int (*set_hard_min_dcefclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock);<br>
         int (*set_hard_min_fclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock);<br>
+       int (*set_hard_min_gfxclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock);<br>
+       int (*set_soft_max_gfxclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock);<br>
         int (*get_asic_baco_capability)(struct pp_hwmgr *hwmgr, bool *cap);<br>
         int (*get_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE *state);<br>
         int (*set_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE state);<br>
diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c<br>
index a6321f2063c1..bb8d077d3f05 100644<br>
--- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c<br>
+++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c<br>
@@ -911,6 +911,20 @@ static int pp_set_power_profile_mode(void *handle, long *input, uint32_t size)<br>
         return ret;<br>
 }<br>
 <br>
+static int pp_set_fine_grain_clk_vol(void *handle, uint32_t type, long *input, uint32_t size)<br>
+{<br>
+       struct pp_hwmgr *hwmgr = handle;<br>
+<br>
+       if (!hwmgr || !hwmgr->pm_en)<br>
+               return -EINVAL;<br>
+<br>
+       if (hwmgr->hwmgr_func->set_fine_grain_clk_vol == NULL) {<br>
+               return 0;<br>
+       }</div>
<div class="PlainText"><br>
</div>
<div class="PlainText">[Kevin]: don't need '{}' if the code only have 1 line.</div>
<div class="PlainText">+<br>
+       return hwmgr->hwmgr_func->set_fine_grain_clk_vol(hwmgr, type, input, size);<br>
+}<br>
+<br>
 static int pp_odn_edit_dpm_table(void *handle, uint32_t type, long *input, uint32_t size)<br>
 {<br>
         struct pp_hwmgr *hwmgr = handle;<br>
@@ -920,7 +934,7 @@ static int pp_odn_edit_dpm_table(void *handle, uint32_t type, long *input, uint3<br>
 <br>
         if (hwmgr->hwmgr_func->odn_edit_dpm_table == NULL) {<br>
                 pr_info_ratelimited("%s was not implemented.\n", __func__);<br>
-               return -EINVAL;<br>
+               return 0;<br>
         }<br>
 <br>
         return hwmgr->hwmgr_func->odn_edit_dpm_table(hwmgr, type, input, size);<br>
@@ -1645,6 +1659,7 @@ static const struct amd_pm_funcs pp_dpm_funcs = {<br>
         .set_powergating_by_smu = pp_set_powergating_by_smu,<br>
         .get_power_profile_mode = pp_get_power_profile_mode,<br>
         .set_power_profile_mode = pp_set_power_profile_mode,<br>
+       .set_fine_grain_clk_vol = pp_set_fine_grain_clk_vol,<br>
         .odn_edit_dpm_table = pp_odn_edit_dpm_table,<br>
         .set_mp1_state = pp_dpm_set_mp1_state,<br>
         .set_power_limit = pp_set_power_limit,<br>
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c<br>
index 9ee8cf8267c8..791db107d51a 100644<br>
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c<br>
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c<br>
@@ -242,6 +242,34 @@ static int smu10_set_hard_min_fclk_by_freq(struct pp_hwmgr *hwmgr, uint32_t cloc<br>
         return 0;<br>
 }<br>
 <br>
+static int smu10_set_hard_min_gfxclk_by_freq(struct pp_hwmgr *hwmgr, uint32_t clock)<br>
+{<br>
+       struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);<br>
+<br>
+       if (clock && smu10_data->gfx_actual_soft_min_freq != clock) {<br>
+               smu10_data->gfx_actual_soft_min_freq = clock;<br>
+               smum_send_msg_to_smc_with_parameter(hwmgr,<br>
+                                       PPSMC_MSG_SetHardMinGfxClk,<br>
+                                       smu10_data->gfx_actual_soft_min_freq,<br>
+                                       NULL);<br>
+       }<br>
+       return 0;<br>
+}<br>
+<br>
+static int smu10_set_soft_max_gfxclk_by_freq(struct pp_hwmgr *hwmgr, uint32_t clock)<br>
+{<br>
+       struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);<br>
+<br>
+       if (clock && smu10_data->gfx_max_freq_limit != (clock * 100))  {<br>
+               smu10_data->gfx_max_freq_limit = clock * 100;<br>
+               smum_send_msg_to_smc_with_parameter(hwmgr,<br>
+                                       PPSMC_MSG_SetSoftMaxGfxClk,<br>
+                                       clock,<br>
+                                       NULL);<br>
+       }<br>
+       return 0;<br>
+}</div>
<div class="PlainText"><br>
</div>
<div class="PlainText">the  unit of varible '<span style="color: rgb(0, 0, 0); font-family: "Segoe UI", "Segoe UI Web (West European)", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif; background-color: rgb(255, 255, 255); display: inline !important">gfx_max_freq_limit'<span> and
 '<span style="font-family: "Segoe UI", "Segoe UI Web (West European)", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif; background-color: rgb(255, 255, 255); display: inline !important">gfx_max_freq_limit' is different,
 one is Mhz and another is 10Khz.</span></span></span></div>
<div class="PlainText">we'd better unify it.</div>
<div class="PlainText">+<br>
 static int smu10_set_active_display_count(struct pp_hwmgr *hwmgr, uint32_t count)<br>
 {<br>
         struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);<br>
@@ -527,6 +555,8 @@ static int smu10_hwmgr_backend_init(struct pp_hwmgr *hwmgr)<br>
         hwmgr->pstate_sclk = SMU10_UMD_PSTATE_GFXCLK * 100;<br>
         hwmgr->pstate_mclk = SMU10_UMD_PSTATE_FCLK * 100;<br>
 <br>
+       hwmgr->od_enabled = 1; /*enable the pp_od_clk_voltage sysfs file*/</div>
<div class="PlainText">[Kevin]: please move this comment to a new line.<br>
+<br>
         return result;<br>
 }<br>
 <br>
@@ -947,6 +977,26 @@ static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr,<br>
                                         ((mclk_table->entries[i].clk / 100)<br>
                                          == now) ? "*" : "");<br>
                 break;<br>
+       case OD_SCLK:<br>
+               if (hwmgr->od_enabled) {<br>
+                       size = sprintf(buf, "%s:\n", "OD_SCLK");<br>
+<br>
+                       size += sprintf(buf + size, "0: %10uMhz\n",<br>
+                       (data->gfx_actual_soft_min_freq > 0) ? data->gfx_actual_soft_min_freq : data->gfx_min_freq_limit/100);<br>
+                       size += sprintf(buf + size, "1: %10uMhz\n", data->gfx_max_freq_limit/100);<br>
+               }<br>
+               break;<br>
+       case OD_RANGE:<br>
+               if (hwmgr->od_enabled) {<br>
+                       uint32_t min_freq, max_freq = 0;<br>
+                       smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency, &min_freq);<br>
+                       smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency, &max_freq);<br>
+<br>
+                       size = sprintf(buf, "%s:\n", "OD_RANGE");<br>
+                       size += sprintf(buf + size, "SCLK: %7uMHz %10uMHz\n",<br>
+                               min_freq, max_freq);<br>
+               }<br>
+               break;<br>
         default:<br>
                 break;<br>
         }<br>
@@ -1348,6 +1398,32 @@ static int smu10_asic_reset(struct pp_hwmgr *hwmgr, enum SMU_ASIC_RESET_MODE mod<br>
                                                    NULL);<br>
 }<br>
 <br>
+static int smu10_set_fine_grain_clk_vol(struct pp_hwmgr *hwmgr,<br>
+                                       enum PP_OD_DPM_TABLE_COMMAND type,<br>
+                                       long *input, uint32_t size)<br>
+{<br>
+       if (!hwmgr->od_enabled) {<br>
+               pr_err("Fine grain not support\n");<br>
+               return -EINVAL;<br>
+       }<br>
+<br>
+       if (size != 2) {<br>
+               pr_err("Input parameter number not correct\n");<br>
+               return -EINVAL;<br>
+       }<br>
+<br>
+       if (type == PP_OD_EDIT_SCLK_VDDC_TABLE) {<br>
+               if (input[0] == 0)<br>
+                       smu10_set_hard_min_gfxclk_by_freq(hwmgr, input[1]);<br>
+               else if (input[0] == 1)<br>
+                       smu10_set_soft_max_gfxclk_by_freq(hwmgr, input[1]);<br>
+               else<br>
+                       return -EINVAL;<br>
+       }<br>
+<br>
+       return 0;<br>
+}<br>
+<br>
 static const struct pp_hwmgr_func smu10_hwmgr_funcs = {<br>
         .backend_init = smu10_hwmgr_backend_init,<br>
         .backend_fini = smu10_hwmgr_backend_fini,<br>
@@ -1388,9 +1464,12 @@ static const struct pp_hwmgr_func smu10_hwmgr_funcs = {<br>
         .powergate_sdma = smu10_powergate_sdma,<br>
         .set_hard_min_dcefclk_by_freq = smu10_set_hard_min_dcefclk_by_freq,<br>
         .set_hard_min_fclk_by_freq = smu10_set_hard_min_fclk_by_freq,<br>
+       .set_hard_min_gfxclk_by_freq = smu10_set_hard_min_gfxclk_by_freq,<br>
+       .set_soft_max_gfxclk_by_freq = smu10_set_soft_max_gfxclk_by_freq,<br>
         .get_power_profile_mode = smu10_get_power_profile_mode,<br>
         .set_power_profile_mode = smu10_set_power_profile_mode,<br>
         .asic_reset = smu10_asic_reset,<br>
+       .set_fine_grain_clk_vol = smu10_set_fine_grain_clk_vol,<br>
 };<br>
 <br>
 int smu10_init_function_pointers(struct pp_hwmgr *hwmgr)<br>
-- <br>
2.17.1<br>
<br>
</div>
</span></font></div>
</div>
</body>
</html>