diff options
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.14.71/5245-drm-amd-powerplay-added-vega20-overdrive-support-V3.patch')
-rw-r--r-- | common/recipes-kernel/linux/linux-yocto-4.14.71/5245-drm-amd-powerplay-added-vega20-overdrive-support-V3.patch | 452 |
1 files changed, 452 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.14.71/5245-drm-amd-powerplay-added-vega20-overdrive-support-V3.patch b/common/recipes-kernel/linux/linux-yocto-4.14.71/5245-drm-amd-powerplay-added-vega20-overdrive-support-V3.patch new file mode 100644 index 00000000..075a05ca --- /dev/null +++ b/common/recipes-kernel/linux/linux-yocto-4.14.71/5245-drm-amd-powerplay-added-vega20-overdrive-support-V3.patch @@ -0,0 +1,452 @@ +From 74b0a922b04d1b411801ff7e08fc8c0d8798e89b Mon Sep 17 00:00:00 2001 +From: Evan Quan <evan.quan@amd.com> +Date: Wed, 29 Aug 2018 14:38:50 +0800 +Subject: [PATCH 5245/5725] drm/amd/powerplay: added vega20 overdrive support + V3 + +Added vega20 overdrive support based on existing OD sysfs +APIs. However, the OD logics are simplified on vega20. So, +the behavior will be a little different and works only on +some limited levels. + +V2: fix typo + fix commit description + revise error logs + add support for clock OD + +V3: separate clock from voltage OD settings + +Change-Id: I403cb38a95863db664cf06d030ac42a19bff6b33 +Signed-off-by: Evan Quan <evan.quan@amd.com> +Reviewed-by: Alex Deucher <alexander.deucher@amd.com> +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 45 ++++ + drivers/gpu/drm/amd/include/kgd_pp_interface.h | 2 + + drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c | 289 ++++++++++++++++++++- + 3 files changed, 335 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +index f5404f2..e63b0c2 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +@@ -474,6 +474,8 @@ static ssize_t amdgpu_set_pp_table(struct device *dev, + * in each power level within a power state. The pp_od_clk_voltage is used for + * this. + * ++ * < For Vega10 and previous ASICs > ++ * + * Reading the file will display: + * + * - a list of engine clock levels and voltages labeled OD_SCLK +@@ -491,6 +493,44 @@ static ssize_t amdgpu_set_pp_table(struct device *dev, + * "c" (commit) to the file to commit your changes. If you want to reset to the + * default power levels, write "r" (reset) to the file to reset them. + * ++ * ++ * < For Vega20 > ++ * ++ * Reading the file will display: ++ * ++ * - minimum and maximum engine clock labeled OD_SCLK ++ * ++ * - maximum memory clock labeled OD_MCLK ++ * ++ * - three <frequency, voltage offset> points labeled OD_VDDC_CURVE. ++ * They can be used to calibrate the sclk voltage curve. ++ * ++ * - a list of valid ranges for sclk, mclk, and voltage curve points ++ * labeled OD_RANGE ++ * ++ * To manually adjust these settings: ++ * ++ * - First select manual using power_dpm_force_performance_level ++ * ++ * - For clock frequency setting, enter a new value by writing a ++ * string that contains "s/m index clock" to the file. The index ++ * should be 0 if to set minimum clock. And 1 if to set maximum ++ * clock. E.g., "s 0 500" will update minimum sclk to be 500 MHz. ++ * "m 1 800" will update maximum mclk to be 800Mhz. ++ * ++ * For sclk voltage curve, enter the new values by writing a ++ * string that contains "vc point clock voff" to the file. The ++ * points are indexed by 0, 1 and 2. E.g., "vc 0 300 10" will ++ * update point1 with clock set as 300Mhz and voltage increased ++ * by 10mV. "vc 2 1000 -10" will update point3 with clock set ++ * as 1000Mhz and voltage drop by 10mV. ++ * ++ * - When you have edited all of the states as needed, write "c" (commit) ++ * to the file to commit your changes ++ * ++ * - If you want to reset to the default power levels, write "r" (reset) ++ * to the file to reset them ++ * + */ + + static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev, +@@ -520,6 +560,8 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev, + type = PP_OD_RESTORE_DEFAULT_TABLE; + else if (*buf == 'c') + type = PP_OD_COMMIT_DPM_TABLE; ++ else if (!strncmp(buf, "vc", 2)) ++ type = PP_OD_EDIT_VDDC_CURVE; + else + return -EINVAL; + +@@ -527,6 +569,8 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev, + + tmp_str = buf_cpy; + ++ if (type == PP_OD_EDIT_VDDC_CURVE) ++ tmp_str++; + while (isspace(*++tmp_str)); + + while (tmp_str[0]) { +@@ -570,6 +614,7 @@ static ssize_t amdgpu_get_pp_od_clk_voltage(struct device *dev, + if (adev->powerplay.pp_funcs->print_clock_levels) { + size = amdgpu_dpm_print_clock_levels(adev, OD_SCLK, buf); + size += amdgpu_dpm_print_clock_levels(adev, OD_MCLK, buf+size); ++ size += amdgpu_dpm_print_clock_levels(adev, OD_VDDC_CURVE, buf+size); + size += amdgpu_dpm_print_clock_levels(adev, OD_RANGE, buf+size); + return size; + } else { +diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h +index 6a41b81..448dee4 100644 +--- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h ++++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h +@@ -94,6 +94,7 @@ enum pp_clock_type { + PP_PCIE, + OD_SCLK, + OD_MCLK, ++ OD_VDDC_CURVE, + OD_RANGE, + }; + +@@ -141,6 +142,7 @@ enum { + enum PP_OD_DPM_TABLE_COMMAND { + PP_OD_EDIT_SCLK_VDDC_TABLE, + PP_OD_EDIT_MCLK_VDDC_TABLE, ++ PP_OD_EDIT_VDDC_CURVE, + PP_OD_RESTORE_DEFAULT_TABLE, + PP_OD_COMMIT_DPM_TABLE + }; +diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c +index fb32b28..3efd59e 100644 +--- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c ++++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c +@@ -2325,11 +2325,207 @@ static int vega20_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, + return 0; + } + ++static int vega20_odn_edit_dpm_table(struct pp_hwmgr *hwmgr, ++ enum PP_OD_DPM_TABLE_COMMAND type, ++ long *input, uint32_t size) ++{ ++ struct vega20_hwmgr *data = ++ (struct vega20_hwmgr *)(hwmgr->backend); ++ struct vega20_od8_single_setting *od8_settings = ++ data->od8_settings.od8_settings_array; ++ OverDriveTable_t *od_table = ++ &(data->smc_state_table.overdrive_table); ++ struct pp_clock_levels_with_latency clocks; ++ int32_t input_index, input_clk, input_vol, i; ++ int ret; ++ ++ PP_ASSERT_WITH_CODE(input, "NULL user input for clock and voltage", ++ return -EINVAL); ++ ++ switch (type) { ++ case PP_OD_EDIT_SCLK_VDDC_TABLE: ++ if (!(od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id && ++ od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id)) { ++ pr_info("Sclk min/max frequency overdrive not supported\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ for (i = 0; i < size; i += 2) { ++ if (i + 2 > size) { ++ pr_info("invalid number of input parameters %d\n", ++ size); ++ return -EINVAL; ++ } ++ ++ input_index = input[i]; ++ input_clk = input[i + 1]; ++ ++ if (input_index != 0 && input_index != 1) { ++ pr_info("Invalid index %d\n", input_index); ++ pr_info("Support min/max sclk frequency setting only which index by 0/1\n"); ++ return -EINVAL; ++ } ++ ++ if (input_clk < od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value || ++ input_clk > od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value) { ++ pr_info("clock freq %d is not within allowed range [%d - %d]\n", ++ input_clk, ++ od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value, ++ od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value); ++ return -EINVAL; ++ } ++ ++ if (input_index == 0) ++ od_table->GfxclkFmin = input_clk; ++ else ++ od_table->GfxclkFmax = input_clk; ++ } ++ ++ break; ++ ++ case PP_OD_EDIT_MCLK_VDDC_TABLE: ++ if (!od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) { ++ pr_info("Mclk max frequency overdrive not supported\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ ret = vega20_get_memclocks(hwmgr, &clocks); ++ PP_ASSERT_WITH_CODE(!ret, ++ "Attempt to get memory clk levels failed!", ++ return ret); ++ ++ for (i = 0; i < size; i += 2) { ++ if (i + 2 > size) { ++ pr_info("invalid number of input parameters %d\n", ++ size); ++ return -EINVAL; ++ } ++ ++ input_index = input[i]; ++ input_clk = input[i + 1]; ++ ++ if (input_index != 1) { ++ pr_info("Invalid index %d\n", input_index); ++ pr_info("Support max Mclk frequency setting only which index by 1\n"); ++ return -EINVAL; ++ } ++ ++ if (input_clk < clocks.data[0].clocks_in_khz / 100 || ++ input_clk > od8_settings[OD8_SETTING_UCLK_FMAX].max_value) { ++ pr_info("clock freq %d is not within allowed range [%d - %d]\n", ++ input_clk, ++ clocks.data[0].clocks_in_khz / 100, ++ od8_settings[OD8_SETTING_UCLK_FMAX].max_value); ++ return -EINVAL; ++ } ++ ++ od_table->UclkFmax = input_clk; ++ } ++ ++ break; ++ ++ case PP_OD_EDIT_VDDC_CURVE: ++ if (!(od8_settings[OD8_SETTING_GFXCLK_FREQ1].feature_id && ++ od8_settings[OD8_SETTING_GFXCLK_FREQ2].feature_id && ++ od8_settings[OD8_SETTING_GFXCLK_FREQ3].feature_id && ++ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id && ++ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id && ++ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id)) { ++ pr_info("Voltage curve calibrate not supported\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ for (i = 0; i < size; i += 3) { ++ if (i + 3 > size) { ++ pr_info("invalid number of input parameters %d\n", ++ size); ++ return -EINVAL; ++ } ++ ++ input_index = input[i]; ++ input_clk = input[i + 1]; ++ input_vol = input[i + 2]; ++ ++ if (input_index > 2) { ++ pr_info("Setting for point %d is not supported\n", ++ input_index + 1); ++ pr_info("Three supported points index by 0, 1, 2\n"); ++ return -EINVAL; ++ } ++ ++ if (input_clk < od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value || ++ input_clk > od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value) { ++ pr_info("clock freq %d is not within allowed range [%d - %d]\n", ++ input_clk, ++ od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value, ++ od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value); ++ return -EINVAL; ++ } ++ ++ /* TODO: suppose voltage1/2/3 has the same min/max value */ ++ if (input_vol < od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].min_value || ++ input_vol > od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].max_value) { ++ pr_info("clock voltage offset %d is not within allowed range [%d - %d]\n", ++ input_vol, ++ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].min_value, ++ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].max_value); ++ return -EINVAL; ++ } ++ ++ switch (input_index) { ++ case 0: ++ od_table->GfxclkFreq1 = input_clk; ++ od_table->GfxclkOffsetVolt1 = input_vol; ++ break; ++ case 1: ++ od_table->GfxclkFreq2 = input_clk; ++ od_table->GfxclkOffsetVolt2 = input_vol; ++ break; ++ case 2: ++ od_table->GfxclkFreq3 = input_clk; ++ od_table->GfxclkOffsetVolt3 = input_vol; ++ break; ++ } ++ } ++ break; ++ ++ case PP_OD_RESTORE_DEFAULT_TABLE: ++ ret = vega20_copy_table_from_smc(hwmgr, ++ (uint8_t *)od_table, ++ TABLE_OVERDRIVE); ++ PP_ASSERT_WITH_CODE(!ret, ++ "Failed to export overdrive table!", ++ return ret); ++ break; ++ ++ case PP_OD_COMMIT_DPM_TABLE: ++ ret = vega20_copy_table_to_smc(hwmgr, ++ (uint8_t *)od_table, ++ TABLE_OVERDRIVE); ++ PP_ASSERT_WITH_CODE(!ret, ++ "Failed to import overdrive table!", ++ return ret); ++ ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ + static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, + enum pp_clock_type type, char *buf) + { +- int i, now, size = 0; ++ struct vega20_hwmgr *data = ++ (struct vega20_hwmgr *)(hwmgr->backend); ++ struct vega20_od8_single_setting *od8_settings = ++ data->od8_settings.od8_settings_array; ++ OverDriveTable_t *od_table = ++ &(data->smc_state_table.overdrive_table); + struct pp_clock_levels_with_latency clocks; ++ int i, now, size = 0; + int ret = 0; + + switch (type) { +@@ -2370,6 +2566,95 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, + case PP_PCIE: + break; + ++ case OD_SCLK: ++ if (od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id && ++ od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id) { ++ size = sprintf(buf, "%s:\n", "OD_SCLK"); ++ size += sprintf(buf + size, "0: %10uMhz\n", ++ od_table->GfxclkFmin); ++ size += sprintf(buf + size, "1: %10uMhz\n", ++ od_table->GfxclkFmax); ++ } ++ break; ++ ++ case OD_MCLK: ++ if (od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) { ++ size = sprintf(buf, "%s:\n", "OD_MCLK"); ++ size += sprintf(buf + size, "1: %10uMhz\n", ++ od_table->UclkFmax); ++ } ++ ++ break; ++ ++ case OD_VDDC_CURVE: ++ if (od8_settings[OD8_SETTING_GFXCLK_FREQ1].feature_id && ++ od8_settings[OD8_SETTING_GFXCLK_FREQ2].feature_id && ++ od8_settings[OD8_SETTING_GFXCLK_FREQ3].feature_id && ++ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id && ++ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id && ++ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) { ++ size = sprintf(buf, "%s:\n", "OD_VDDC_CURVE"); ++ size += sprintf(buf + size, "0: %10uMhz %10dmV\n", ++ od_table->GfxclkFreq1, ++ od_table->GfxclkOffsetVolt1); ++ size += sprintf(buf + size, "1: %10uMhz %10dmV\n", ++ od_table->GfxclkFreq2, ++ od_table->GfxclkOffsetVolt2); ++ size += sprintf(buf + size, "2: %10uMhz %10dmV\n", ++ od_table->GfxclkFreq3, ++ od_table->GfxclkOffsetVolt3); ++ } ++ ++ break; ++ ++ case OD_RANGE: ++ size = sprintf(buf, "%s:\n", "OD_RANGE"); ++ ++ if (od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id && ++ od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id) { ++ size += sprintf(buf + size, "SCLK: %7uMhz %10uMhz\n", ++ od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value, ++ od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value); ++ } ++ ++ if (od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) { ++ ret = vega20_get_memclocks(hwmgr, &clocks); ++ PP_ASSERT_WITH_CODE(!ret, ++ "Fail to get memory clk levels!", ++ return ret); ++ ++ size += sprintf(buf + size, "MCLK: %7uMhz %10uMhz\n", ++ clocks.data[0].clocks_in_khz / 100, ++ od8_settings[OD8_SETTING_UCLK_FMAX].max_value); ++ } ++ ++ if (od8_settings[OD8_SETTING_GFXCLK_FREQ1].feature_id && ++ od8_settings[OD8_SETTING_GFXCLK_FREQ2].feature_id && ++ od8_settings[OD8_SETTING_GFXCLK_FREQ3].feature_id && ++ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id && ++ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id && ++ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) { ++ size += sprintf(buf + size, "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n", ++ od8_settings[OD8_SETTING_GFXCLK_FREQ1].min_value, ++ od8_settings[OD8_SETTING_GFXCLK_FREQ1].max_value); ++ size += sprintf(buf + size, "VDDC_CURVE_VOFF[0]: %7dmV %11dmV\n", ++ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].min_value, ++ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].max_value); ++ size += sprintf(buf + size, "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n", ++ od8_settings[OD8_SETTING_GFXCLK_FREQ2].min_value, ++ od8_settings[OD8_SETTING_GFXCLK_FREQ2].max_value); ++ size += sprintf(buf + size, "VDDC_CURVE_VOFF[1]: %7dmV %11dmV\n", ++ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].min_value, ++ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].max_value); ++ size += sprintf(buf + size, "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n", ++ od8_settings[OD8_SETTING_GFXCLK_FREQ3].min_value, ++ od8_settings[OD8_SETTING_GFXCLK_FREQ3].max_value); ++ size += sprintf(buf + size, "VDDC_CURVE_VOFF[2]: %7dmV %11dmV\n", ++ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].min_value, ++ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].max_value); ++ } ++ ++ break; + default: + break; + } +@@ -2977,6 +3262,8 @@ static const struct pp_hwmgr_func vega20_hwmgr_funcs = { + vega20_get_mclk_od, + .set_mclk_od = + vega20_set_mclk_od, ++ .odn_edit_dpm_table = ++ vega20_odn_edit_dpm_table, + /* for sysfs to retrive/set gfxclk/memclk */ + .force_clock_level = + vega20_force_clock_level, +-- +2.7.4 + |