Commit 2c80abe3 authored by Likun Gao's avatar Likun Gao Committed by Alex Deucher
Browse files

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: default avatarLikun Gao <Likun.Gao@amd.com>
Reviewed-by: default avatarKevin Wang <kevin1.wang@amd.com>
Reviewed-by: default avatarEvan Quan <evan.quan@amd.com>
Acked-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent b55ca3bd
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -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;
+8 −0
Original line number Diff line number Diff line
@@ -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) \
+33 −51
Original line number Diff line number Diff line
@@ -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)
+203 −0
Original line number Diff line number Diff line
@@ -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)
+51 −0
Original line number Diff line number Diff line
@@ -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