drm/amd/powerplay: new interfaces for overdrive vega20 sclk and mclk
authorEvan Quan <evan.quan@amd.com>
Mon, 21 May 2018 02:19:06 +0000 (10:19 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 27 Aug 2018 16:10:31 +0000 (11:10 -0500)
Add support for the new SMU firmware interface for clock adjustment.

Signed-off-by: Evan Quan <evan.quan@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c

index 51bc05dea8e16ac8613a2c4c910b041b69b0e46c..1e9426fb1bf9a2dbb5f2c0fbc3b9e77ba6209960 100644 (file)
@@ -1101,6 +1101,166 @@ static int vega20_od8_initialize_default_settings(
        return 0;
 }
 
+static int vega20_od8_set_settings(
+               struct pp_hwmgr *hwmgr,
+               uint32_t index,
+               uint32_t value)
+{
+       OverDriveTable_t od_table;
+       int ret = 0;
+
+       ret = vega20_copy_table_from_smc(hwmgr, (uint8_t *)(&od_table), TABLE_OVERDRIVE);
+       PP_ASSERT_WITH_CODE(!ret,
+                       "Failed to export over drive table!",
+                       return ret);
+
+       switch(index) {
+       case OD8_SETTING_GFXCLK_FMIN:
+               od_table.GfxclkFmin = (uint16_t)value;
+               break;
+       case OD8_SETTING_GFXCLK_FMAX:
+               od_table.GfxclkFmax = (uint16_t)value;
+               break;
+       case OD8_SETTING_GFXCLK_FREQ1:
+               od_table.GfxclkFreq1 = (uint16_t)value;
+               break;
+       case OD8_SETTING_GFXCLK_VOLTAGE1:
+               od_table.GfxclkOffsetVolt1 = (uint16_t)value;
+               break;
+       case OD8_SETTING_GFXCLK_FREQ2:
+               od_table.GfxclkFreq2 = (uint16_t)value;
+               break;
+       case OD8_SETTING_GFXCLK_VOLTAGE2:
+               od_table.GfxclkOffsetVolt2 = (uint16_t)value;
+               break;
+       case OD8_SETTING_GFXCLK_FREQ3:
+               od_table.GfxclkFreq3 = (uint16_t)value;
+               break;
+       case OD8_SETTING_GFXCLK_VOLTAGE3:
+               od_table.GfxclkOffsetVolt3 = (uint16_t)value;
+               break;
+       case OD8_SETTING_UCLK_FMAX:
+               od_table.UclkFmax = (uint16_t)value;
+               break;
+       case OD8_SETTING_POWER_PERCENTAGE:
+               od_table.OverDrivePct = (int16_t)value;
+               break;
+       case OD8_SETTING_FAN_ACOUSTIC_LIMIT:
+               od_table.FanMaximumRpm = (uint16_t)value;
+               break;
+       case OD8_SETTING_FAN_MIN_SPEED:
+               od_table.FanMinimumPwm = (uint16_t)value;
+               break;
+       case OD8_SETTING_FAN_TARGET_TEMP:
+               od_table.FanTargetTemperature = (uint16_t)value;
+               break;
+       case OD8_SETTING_OPERATING_TEMP_MAX:
+               od_table.MaxOpTemp = (uint16_t)value;
+               break;
+       }
+
+       ret = vega20_copy_table_to_smc(hwmgr, (uint8_t *)(&od_table), TABLE_OVERDRIVE);
+       PP_ASSERT_WITH_CODE(!ret,
+                       "Failed to import over drive table!",
+                       return ret);
+
+       return 0;
+}
+
+static int vega20_get_sclk_od(
+               struct pp_hwmgr *hwmgr)
+{
+       struct vega20_hwmgr *data = hwmgr->backend;
+       struct vega20_single_dpm_table *sclk_table =
+                       &(data->dpm_table.gfx_table);
+       struct vega20_single_dpm_table *golden_sclk_table =
+                       &(data->golden_dpm_table.gfx_table);
+       int value;
+
+       /* od percentage */
+       value = DIV_ROUND_UP((sclk_table->dpm_levels[sclk_table->count - 1].value -
+               golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value) * 100,
+               golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value);
+
+       return value;
+}
+
+static int vega20_set_sclk_od(
+               struct pp_hwmgr *hwmgr, uint32_t value)
+{
+       struct vega20_hwmgr *data = hwmgr->backend;
+       struct vega20_single_dpm_table *sclk_table =
+                       &(data->dpm_table.gfx_table);
+       struct vega20_single_dpm_table *golden_sclk_table =
+                       &(data->golden_dpm_table.gfx_table);
+       uint32_t od_sclk;
+       int ret = 0;
+
+       od_sclk = golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value * value;
+       do_div(od_sclk, 100);
+       od_sclk += golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
+
+       ret = vega20_od8_set_settings(hwmgr, OD8_SETTING_GFXCLK_FMAX, od_sclk);
+       PP_ASSERT_WITH_CODE(!ret,
+                       "[SetSclkOD] failed to set od gfxclk!",
+                       return ret);
+
+       /* refresh gfxclk table */
+       ret = vega20_setup_single_dpm_table(hwmgr, sclk_table, PPCLK_GFXCLK);
+       PP_ASSERT_WITH_CODE(!ret,
+                       "[SetSclkOD] failed to refresh gfxclk table!",
+                       return ret);
+
+       return 0;
+}
+
+static int vega20_get_mclk_od(
+               struct pp_hwmgr *hwmgr)
+{
+       struct vega20_hwmgr *data = hwmgr->backend;
+       struct vega20_single_dpm_table *mclk_table =
+                       &(data->dpm_table.mem_table);
+       struct vega20_single_dpm_table *golden_mclk_table =
+                       &(data->golden_dpm_table.mem_table);
+       int value;
+
+       /* od percentage */
+       value = DIV_ROUND_UP((mclk_table->dpm_levels[mclk_table->count - 1].value -
+               golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value) * 100,
+               golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value);
+
+       return value;
+}
+
+static int vega20_set_mclk_od(
+               struct pp_hwmgr *hwmgr, uint32_t value)
+{
+       struct vega20_hwmgr *data = hwmgr->backend;
+       struct vega20_single_dpm_table *mclk_table =
+                       &(data->dpm_table.mem_table);
+       struct vega20_single_dpm_table *golden_mclk_table =
+                       &(data->golden_dpm_table.mem_table);
+       uint32_t od_mclk;
+       int ret = 0;
+
+       od_mclk = golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value * value;
+       do_div(od_mclk, 100);
+       od_mclk += golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
+
+       ret = vega20_od8_set_settings(hwmgr, OD8_SETTING_UCLK_FMAX, od_mclk);
+       PP_ASSERT_WITH_CODE(!ret,
+                       "[SetMclkOD] failed to set od memclk!",
+                       return ret);
+
+       /* refresh memclk table */
+       ret = vega20_setup_single_dpm_table(hwmgr, mclk_table, PPCLK_UCLK);
+       PP_ASSERT_WITH_CODE(!ret,
+                       "[SetMclkOD] failed to refresh memclk table!",
+                       return ret);
+
+       return 0;
+}
+
 static int vega20_populate_umdpstate_clocks(
                struct pp_hwmgr *hwmgr)
 {
@@ -2604,8 +2764,17 @@ static const struct pp_hwmgr_func vega20_hwmgr_funcs = {
                vega20_get_power_profile_mode,
        .set_power_profile_mode =
                vega20_set_power_profile_mode,
+       /* od related */
        .set_power_limit =
                vega20_set_power_limit,
+       .get_sclk_od =
+               vega20_get_sclk_od,
+       .set_sclk_od =
+               vega20_set_sclk_od,
+       .get_mclk_od =
+               vega20_get_mclk_od,
+       .set_mclk_od =
+               vega20_set_mclk_od,
        /* for sysfs to retrive/set gfxclk/memclk */
        .force_clock_level =
                vega20_force_clock_level,