drm/amd/powerplay: add function to set default overdrive settings

Add function of vega20_set_default_od8_setttings for vega20 with smu11
arch to setup default overdrive value.

Signed-off-by: Likun Gao <Likun.Gao@amd.com>
Reviewed-by: Kevin Wang <kevin1.wang@amd.com>
Reviewed-by: Evan Quan <evan.quan@amd.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Likun Gao 2019-01-09 19:11:58 +08:00 committed by Alex Deucher
parent b55ca3bdaf
commit 2c80abe381
5 changed files with 309 additions and 51 deletions

View File

@ -533,6 +533,10 @@ static int smu_smc_table_hw_init(struct smu_context *smu)
if (ret)
return ret;
ret = smu_set_od8_default_settings(smu);
if (ret)
return ret;
ret = smu_populate_umd_state_clk(smu);
if (ret)
return ret;
@ -704,6 +708,16 @@ static int smu_hw_fini(void *handle)
table_context->od_settings_min = NULL;
}
if (table_context->overdrive_table) {
kfree(table_context->overdrive_table);
table_context->overdrive_table = NULL;
}
if (table_context->od8_settings) {
kfree(table_context->od8_settings);
table_context->od8_settings = NULL;
}
ret = smu_fini_fb_allocations(smu);
if (ret)
return ret;

View File

@ -196,6 +196,8 @@ struct smu_table_context
uint8_t *od_feature_capabilities;
uint32_t *od_settings_max;
uint32_t *od_settings_min;
void *overdrive_table;
void *od8_settings;
};
struct smu_dpm_context {
@ -258,6 +260,7 @@ struct pptable_funcs {
int (*populate_umd_state_clk)(struct smu_context *smu);
int (*print_clk_levels)(struct smu_context *smu, enum pp_clock_type type, char *buf);
int (*force_clk_levels)(struct smu_context *smu, enum pp_clock_type type, uint32_t mask);
int (*set_default_od8_settings)(struct smu_context *smu);
int (*get_clock_by_type_with_latency)(struct smu_context *smu,
enum amd_pp_clock_type type,
struct
@ -331,6 +334,7 @@ struct smu_funcs
int (*notify_smu_enable_pwe)(struct smu_context *smu);
int (*set_watermarks_for_clock_ranges)(struct smu_context *smu,
struct dm_pp_wm_sets_with_clock_ranges_soc15 *clock_ranges);
int (*set_od8_default_settings)(struct smu_context *smu);
};
#define smu_init_microcode(smu) \
@ -377,6 +381,8 @@ struct smu_funcs
((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_set_od8_default_settings(smu) \
((smu)->funcs->set_od8_default_settings ? (smu)->funcs->set_od8_default_settings((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) \
@ -407,6 +413,8 @@ struct smu_funcs
((smu)->ppt_funcs->set_default_dpm_table ? (smu)->ppt_funcs->set_default_dpm_table((smu)) : 0)
#define smu_populate_umd_state_clk(smu) \
((smu)->ppt_funcs->populate_umd_state_clk ? (smu)->ppt_funcs->populate_umd_state_clk((smu)) : 0)
#define smu_set_default_od8_settings(smu) \
((smu)->ppt_funcs->set_default_od8_settings ? (smu)->ppt_funcs->set_default_od8_settings((smu)) : 0)
#define smu_get_power_limit(smu) \
((smu)->funcs->get_power_limit? (smu)->funcs->get_power_limit((smu)) : 0)
#define smu_get_current_clk_freq(smu, clk_id, value) \

View File

@ -542,61 +542,12 @@ static int smu_v11_0_populate_smc_pptable(struct smu_context *smu)
return ret;
}
static int smu_v11_0_copy_table_to_smc(struct smu_context *smu,
uint32_t table_id)
{
struct smu_table_context *table_context = &smu->smu_table;
struct smu_table *driver_pptable = &smu->smu_table.tables[table_id];
int ret = 0;
if (table_id >= TABLE_COUNT) {
pr_err("Invalid SMU Table ID for smu11!");
return -EINVAL;
}
if (!driver_pptable->cpu_addr) {
pr_err("Invalid virtual address for smu11!");
return -EINVAL;
}
if (!driver_pptable->mc_address) {
pr_err("Invalid MC address for smu11!");
return -EINVAL;
}
if (!driver_pptable->size) {
pr_err("Invalid SMU Table size for smu11!");
return -EINVAL;
}
memcpy(driver_pptable->cpu_addr, table_context->driver_pptable,
driver_pptable->size);
ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetDriverDramAddrHigh,
upper_32_bits(driver_pptable->mc_address));
if (ret) {
pr_err("[CopyTableToSMC] Attempt to Set Dram Addr High Failed!");
return ret;
}
ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetDriverDramAddrLow,
lower_32_bits(driver_pptable->mc_address));
if (ret) {
pr_err("[CopyTableToSMC] Attempt to Set Dram Addr Low Failed!");
return ret;
}
ret = smu_send_smc_msg_with_param(smu, SMU_MSG_TransferTableDram2Smu,
table_id);
if (ret) {
pr_err("[CopyTableToSMC] Attempt to Transfer Table To SMU Failed!");
return ret;
}
return 0;
}
static int smu_v11_0_write_pptable(struct smu_context *smu)
{
struct smu_table_context *table_context = &smu->smu_table;
int ret = 0;
ret = smu_v11_0_copy_table_to_smc(smu, TABLE_PPTABLE);
ret = smu_update_table(smu, TABLE_PPTABLE, table_context->driver_pptable, true);
return ret;
}
@ -1246,6 +1197,36 @@ smu_v11_0_set_watermarks_for_clock_ranges(struct smu_context *smu, struct
return ret;
}
static int smu_v11_0_set_od8_default_settings(struct smu_context *smu)
{
struct smu_table_context *table_context = &smu->smu_table;
int ret;
if (table_context->overdrive_table)
return -EINVAL;
table_context->overdrive_table = kzalloc(sizeof(OverDriveTable_t), GFP_KERNEL);
if (!table_context->overdrive_table)
return -ENOMEM;
ret = smu_update_table(smu, TABLE_OVERDRIVE, table_context->overdrive_table, false);
if (ret) {
pr_err("Failed to export over drive table!\n");
return ret;
}
smu_set_default_od8_settings(smu);
ret = smu_update_table(smu, TABLE_OVERDRIVE, table_context->overdrive_table, true);
if (ret) {
pr_err("Failed to import over drive table!\n");
return ret;
}
return 0;
}
static const struct smu_funcs smu_v11_0_funcs = {
.init_microcode = smu_v11_0_init_microcode,
.load_microcode = smu_v11_0_load_microcode,
@ -1282,6 +1263,7 @@ static const struct smu_funcs smu_v11_0_funcs = {
.set_deep_sleep_dcefclk = smu_v11_0_set_deep_sleep_dcefclk,
.display_clock_voltage_request = smu_v11_0_display_clock_voltage_request,
.set_watermarks_for_clock_ranges = smu_v11_0_set_watermarks_for_clock_ranges,
.set_od8_default_settings = smu_v11_0_set_od8_default_settings,
};
void smu_v11_0_set_smu_funcs(struct smu_context *smu)

View File

@ -904,6 +904,208 @@ static int vega20_get_clock_by_type_with_latency(struct smu_context *smu,
return ret;
}
static int vega20_overdrive_get_gfx_clk_base_voltage(struct smu_context *smu,
uint32_t *voltage,
uint32_t freq)
{
int ret;
ret = smu_send_smc_msg_with_param(smu,
SMU_MSG_GetAVFSVoltageByDpm,
((AVFS_CURVE << 24) | (OD8_HOTCURVE_TEMPERATURE << 16) | freq));
if (ret) {
pr_err("[GetBaseVoltage] failed to get GFXCLK AVFS voltage from SMU!");
return ret;
}
smu_read_smc_arg(smu, voltage);
*voltage = *voltage / VOLTAGE_SCALE;
return 0;
}
static int vega20_set_default_od8_setttings(struct smu_context *smu)
{
struct smu_table_context *table_context = &smu->smu_table;
OverDriveTable_t *od_table = (OverDriveTable_t *)(table_context->overdrive_table);
struct vega20_od8_settings *od8_settings = NULL;
PPTable_t *smc_pptable = table_context->driver_pptable;
int i, ret;
if (table_context->od8_settings)
return -EINVAL;
table_context->od8_settings = kzalloc(sizeof(struct vega20_od8_settings), GFP_KERNEL);
if (!table_context->od8_settings)
return -ENOMEM;
memset(table_context->od8_settings, 0, sizeof(struct vega20_od8_settings));
od8_settings = (struct vega20_od8_settings *)table_context->od8_settings;
if (smu_feature_is_enabled(smu, FEATURE_DPM_SOCCLK_BIT)) {
if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_GFXCLK_LIMITS] &&
table_context->od_settings_max[OD8_SETTING_GFXCLK_FMAX] > 0 &&
table_context->od_settings_min[OD8_SETTING_GFXCLK_FMIN] > 0 &&
(table_context->od_settings_max[OD8_SETTING_GFXCLK_FMAX] >=
table_context->od_settings_min[OD8_SETTING_GFXCLK_FMIN])) {
od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id =
OD8_GFXCLK_LIMITS;
od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id =
OD8_GFXCLK_LIMITS;
od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].default_value =
od_table->GfxclkFmin;
od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].default_value =
od_table->GfxclkFmax;
}
if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_GFXCLK_CURVE] &&
(table_context->od_settings_min[OD8_SETTING_GFXCLK_VOLTAGE1] >=
smc_pptable->MinVoltageGfx / VOLTAGE_SCALE) &&
(table_context->od_settings_max[OD8_SETTING_GFXCLK_VOLTAGE3] <=
smc_pptable->MaxVoltageGfx / VOLTAGE_SCALE) &&
(table_context->od_settings_min[OD8_SETTING_GFXCLK_VOLTAGE1] <=
table_context->od_settings_max[OD8_SETTING_GFXCLK_VOLTAGE3])) {
od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id =
OD8_GFXCLK_CURVE;
od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id =
OD8_GFXCLK_CURVE;
od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id =
OD8_GFXCLK_CURVE;
od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id =
OD8_GFXCLK_CURVE;
od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id =
OD8_GFXCLK_CURVE;
od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id =
OD8_GFXCLK_CURVE;
od_table->GfxclkFreq1 = od_table->GfxclkFmin;
od_table->GfxclkFreq2 = (od_table->GfxclkFmin + od_table->GfxclkFmax) / 2;
od_table->GfxclkFreq3 = od_table->GfxclkFmax;
od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].default_value =
od_table->GfxclkFreq1;
od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].default_value =
od_table->GfxclkFreq2;
od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].default_value =
od_table->GfxclkFreq3;
ret = vega20_overdrive_get_gfx_clk_base_voltage(smu,
&od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value,
od_table->GfxclkFreq1);
if (ret)
od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value = 0;
od_table->GfxclkVolt1 =
od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value
* VOLTAGE_SCALE;
ret = vega20_overdrive_get_gfx_clk_base_voltage(smu,
&od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value,
od_table->GfxclkFreq2);
if (ret)
od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value = 0;
od_table->GfxclkVolt2 =
od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value
* VOLTAGE_SCALE;
ret = vega20_overdrive_get_gfx_clk_base_voltage(smu,
&od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value,
od_table->GfxclkFreq3);
if (ret)
od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value = 0;
od_table->GfxclkVolt3 =
od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value
* VOLTAGE_SCALE;
}
}
if (smu_feature_is_enabled(smu, FEATURE_DPM_UCLK_BIT)) {
if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_UCLK_MAX] &&
table_context->od_settings_min[OD8_SETTING_UCLK_FMAX] > 0 &&
table_context->od_settings_max[OD8_SETTING_UCLK_FMAX] > 0 &&
(table_context->od_settings_max[OD8_SETTING_UCLK_FMAX] >=
table_context->od_settings_min[OD8_SETTING_UCLK_FMAX])) {
od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id =
OD8_UCLK_MAX;
od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].default_value =
od_table->UclkFmax;
}
}
if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_POWER_LIMIT] &&
table_context->od_settings_min[OD8_SETTING_POWER_PERCENTAGE] > 0 &&
table_context->od_settings_min[OD8_SETTING_POWER_PERCENTAGE] <= 100 &&
table_context->od_settings_max[OD8_SETTING_POWER_PERCENTAGE] > 0 &&
table_context->od_settings_max[OD8_SETTING_POWER_PERCENTAGE] <= 100) {
od8_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].feature_id =
OD8_POWER_LIMIT;
od8_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].default_value =
od_table->OverDrivePct;
}
if (smu_feature_is_enabled(smu, FEATURE_FAN_CONTROL_BIT)) {
if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_ACOUSTIC_LIMIT] &&
table_context->od_settings_min[OD8_SETTING_FAN_ACOUSTIC_LIMIT] > 0 &&
table_context->od_settings_max[OD8_SETTING_FAN_ACOUSTIC_LIMIT] > 0 &&
(table_context->od_settings_max[OD8_SETTING_FAN_ACOUSTIC_LIMIT] >=
table_context->od_settings_min[OD8_SETTING_FAN_ACOUSTIC_LIMIT])) {
od8_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].feature_id =
OD8_ACOUSTIC_LIMIT_SCLK;
od8_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].default_value =
od_table->FanMaximumRpm;
}
if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_SPEED_MIN] &&
table_context->od_settings_min[OD8_SETTING_FAN_MIN_SPEED] > 0 &&
table_context->od_settings_max[OD8_SETTING_FAN_MIN_SPEED] > 0 &&
(table_context->od_settings_max[OD8_SETTING_FAN_MIN_SPEED] >=
table_context->od_settings_min[OD8_SETTING_FAN_MIN_SPEED])) {
od8_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].feature_id =
OD8_FAN_SPEED_MIN;
od8_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].default_value =
od_table->FanMinimumPwm * smc_pptable->FanMaximumRpm / 100;
}
}
if (smu_feature_is_enabled(smu, FEATURE_THERMAL_BIT)) {
if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_TEMPERATURE_FAN] &&
table_context->od_settings_min[OD8_SETTING_FAN_TARGET_TEMP] > 0 &&
table_context->od_settings_max[OD8_SETTING_FAN_TARGET_TEMP] > 0 &&
(table_context->od_settings_max[OD8_SETTING_FAN_TARGET_TEMP] >=
table_context->od_settings_min[OD8_SETTING_FAN_TARGET_TEMP])) {
od8_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].feature_id =
OD8_TEMPERATURE_FAN;
od8_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].default_value =
od_table->FanTargetTemperature;
}
if (table_context->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_TEMPERATURE_SYSTEM] &&
table_context->od_settings_min[OD8_SETTING_OPERATING_TEMP_MAX] > 0 &&
table_context->od_settings_max[OD8_SETTING_OPERATING_TEMP_MAX] > 0 &&
(table_context->od_settings_max[OD8_SETTING_OPERATING_TEMP_MAX] >=
table_context->od_settings_min[OD8_SETTING_OPERATING_TEMP_MAX])) {
od8_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].feature_id =
OD8_TEMPERATURE_SYSTEM;
od8_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].default_value =
od_table->MaxOpTemp;
}
}
for (i = 0; i < OD8_SETTING_COUNT; i++) {
if (od8_settings->od8_settings_array[i].feature_id) {
od8_settings->od8_settings_array[i].min_value =
table_context->od_settings_min[i];
od8_settings->od8_settings_array[i].max_value =
table_context->od_settings_max[i];
od8_settings->od8_settings_array[i].current_value =
od8_settings->od8_settings_array[i].default_value;
} else {
od8_settings->od8_settings_array[i].min_value = 0;
od8_settings->od8_settings_array[i].max_value = 0;
od8_settings->od8_settings_array[i].current_value = 0;
}
}
return 0;
}
static const struct pptable_funcs vega20_ppt_funcs = {
.alloc_dpm_context = vega20_allocate_dpm_context,
.store_powerplay_table = vega20_store_powerplay_table,
@ -917,6 +1119,7 @@ static const struct pptable_funcs vega20_ppt_funcs = {
.print_clk_levels = vega20_print_clk_levels,
.force_clk_levels = vega20_force_clk_levels,
.get_clock_by_type_with_latency = vega20_get_clock_by_type_with_latency,
.set_default_od8_settings = vega20_set_default_od8_setttings,
};
void vega20_set_ppt_funcs(struct smu_context *smu)

View File

@ -29,6 +29,10 @@
#define MAX_REGULAR_DPM_NUMBER 16
#define MAX_PCIE_CONF 2
#define VOLTAGE_SCALE 4
#define AVFS_CURVE 0
#define OD8_HOTCURVE_TEMPERATURE 85
struct vega20_dpm_level {
bool enabled;
uint32_t value;
@ -70,6 +74,53 @@ struct vega20_dpm_table {
struct vega20_pcie_table pcie_table;
};
enum OD8_FEATURE_ID
{
OD8_GFXCLK_LIMITS = 1 << 0,
OD8_GFXCLK_CURVE = 1 << 1,
OD8_UCLK_MAX = 1 << 2,
OD8_POWER_LIMIT = 1 << 3,
OD8_ACOUSTIC_LIMIT_SCLK = 1 << 4, //FanMaximumRpm
OD8_FAN_SPEED_MIN = 1 << 5, //FanMinimumPwm
OD8_TEMPERATURE_FAN = 1 << 6, //FanTargetTemperature
OD8_TEMPERATURE_SYSTEM = 1 << 7, //MaxOpTemp
OD8_MEMORY_TIMING_TUNE = 1 << 8,
OD8_FAN_ZERO_RPM_CONTROL = 1 << 9
};
enum OD8_SETTING_ID
{
OD8_SETTING_GFXCLK_FMIN = 0,
OD8_SETTING_GFXCLK_FMAX,
OD8_SETTING_GFXCLK_FREQ1,
OD8_SETTING_GFXCLK_VOLTAGE1,
OD8_SETTING_GFXCLK_FREQ2,
OD8_SETTING_GFXCLK_VOLTAGE2,
OD8_SETTING_GFXCLK_FREQ3,
OD8_SETTING_GFXCLK_VOLTAGE3,
OD8_SETTING_UCLK_FMAX,
OD8_SETTING_POWER_PERCENTAGE,
OD8_SETTING_FAN_ACOUSTIC_LIMIT,
OD8_SETTING_FAN_MIN_SPEED,
OD8_SETTING_FAN_TARGET_TEMP,
OD8_SETTING_OPERATING_TEMP_MAX,
OD8_SETTING_AC_TIMING,
OD8_SETTING_FAN_ZERO_RPM_CONTROL,
OD8_SETTING_COUNT
};
struct vega20_od8_single_setting {
uint32_t feature_id;
int32_t min_value;
int32_t max_value;
int32_t current_value;
int32_t default_value;
};
struct vega20_od8_settings {
struct vega20_od8_single_setting od8_settings_array[OD8_SETTING_COUNT];
};
extern void vega20_set_ppt_funcs(struct smu_context *smu);
#endif