Commit eb3b4251 authored by Arunpravin's avatar Arunpravin Committed by Alex Deucher
Browse files

drm/amd/pm: store and reinstate swsmu user power configurations



store swsmu user power configurations which include
power limit, clock frequencies, fan speed and fan mode
on suspend and reinstate on resume.

V2: Addressed Lijo's review comments
     added a function to set clock interdependencies
     add check on fan control mode to reapply fan speed

V3: Addressed review comments from Alex
     moved store logic and reinstate function call into swSMU

V4: added a logic to keep off storing configurations in suspend

V5: Addressed review comments from Lijo
     add a restore flag
     give restore priority to mclk comparing fclk and socclk

Signed-off-by: default avatarArunpravin <Arunpravin.PaneerSelvam@amd.com>
Acked-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Reviewed-by: default avatarLijo Lazar <lijo.lazar@amd.com>
Reviewed-by: default avatarKevin Wang <kevin1.wang@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 64dcf2f0
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@
#define SMU_TEMPERATURE_UNITS_PER_CENTIGRADES	1000
#define SMU_FW_NAME_LEN			0x24

#define SMU_DPM_USER_PROFILE_RESTORE (1 << 0)

struct smu_hw_power_state {
	unsigned int magic;
};
@@ -168,6 +170,17 @@ enum smu_memory_pool_size
    SMU_MEMORY_POOL_SIZE_2_GB   = 0x80000000,
};

struct smu_user_dpm_profile {
	uint32_t fan_mode;
	uint32_t power_limit;
	uint32_t fan_speed_rpm;
	uint32_t flags;

	/* user clock state information */
	uint32_t clk_mask[SMU_CLK_COUNT];
	uint32_t clk_dependency;
};

#define SMU_TABLE_INIT(tables, table_id, s, a, d)	\
	do {						\
		tables[table_id].size = s;		\
@@ -473,6 +486,8 @@ struct smu_context
	uint32_t cpu_actual_soft_max_freq;
	uint32_t cpu_core_id_select;
	uint16_t cpu_core_num;

	struct smu_user_dpm_profile user_dpm_profile;
};

struct i2c_adapter;
+144 −4
Original line number Diff line number Diff line
@@ -266,6 +266,119 @@ int smu_dpm_set_power_gate(struct smu_context *smu, uint32_t block_type,
	return ret;
}

/**
 * smu_set_user_clk_dependencies - set user profile clock dependencies
 *
 * @smu:	smu_context pointer
 * @clk:	enum smu_clk_type type
 *
 * Enable/Disable the clock dependency for the @clk type.
 */
static void smu_set_user_clk_dependencies(struct smu_context *smu, enum smu_clk_type clk)
{
	if (smu->adev->in_suspend)
		return;

	/*
	 * mclk, fclk and socclk are interdependent
	 * on each other
	 */
	if (clk == SMU_MCLK) {
		/* reset clock dependency */
		smu->user_dpm_profile.clk_dependency = 0;
		/* set mclk dependent clocks(fclk and socclk) */
		smu->user_dpm_profile.clk_dependency = BIT(SMU_FCLK) | BIT(SMU_SOCCLK);
	} else if (clk == SMU_FCLK) {
		/* give priority to mclk, if mclk dependent clocks are set */
		if (smu->user_dpm_profile.clk_dependency == (BIT(SMU_FCLK) | BIT(SMU_SOCCLK)))
			return;

		/* reset clock dependency */
		smu->user_dpm_profile.clk_dependency = 0;
		/* set fclk dependent clocks(mclk and socclk) */
		smu->user_dpm_profile.clk_dependency = BIT(SMU_MCLK) | BIT(SMU_SOCCLK);
	} else if (clk == SMU_SOCCLK) {
		/* give priority to mclk, if mclk dependent clocks are set */
		if (smu->user_dpm_profile.clk_dependency == (BIT(SMU_FCLK) | BIT(SMU_SOCCLK)))
			return;

		/* reset clock dependency */
		smu->user_dpm_profile.clk_dependency = 0;
		/* set socclk dependent clocks(mclk and fclk) */
		smu->user_dpm_profile.clk_dependency = BIT(SMU_MCLK) | BIT(SMU_FCLK);
	} else
		/* add clk dependencies here, if any */
		return;
}

/**
 * smu_restore_dpm_user_profile - reinstate user dpm profile
 *
 * @smu:	smu_context pointer
 *
 * Restore the saved user power configurations include power limit,
 * clock frequencies, fan control mode and fan speed.
 */
static void smu_restore_dpm_user_profile(struct smu_context *smu)
{
	struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
	int ret = 0;

	if (!smu->adev->in_suspend)
		return;

	if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
		return;

	/* Enable restore flag */
	smu->user_dpm_profile.flags = SMU_DPM_USER_PROFILE_RESTORE;

	/* set the user dpm power limit */
	if (smu->user_dpm_profile.power_limit) {
		ret = smu_set_power_limit(smu, smu->user_dpm_profile.power_limit);
		if (ret)
			dev_err(smu->adev->dev, "Failed to set power limit value\n");
	}

	/* set the user dpm clock configurations */
	if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) {
		enum smu_clk_type clk_type;

		for (clk_type = 0; clk_type < SMU_CLK_COUNT; clk_type++) {
			/*
			 * Iterate over smu clk type and force the saved user clk
			 * configs, skip if clock dependency is enabled
			 */
			if (!(smu->user_dpm_profile.clk_dependency & BIT(clk_type)) &&
					smu->user_dpm_profile.clk_mask[clk_type]) {
				ret = smu_force_clk_levels(smu, clk_type,
						smu->user_dpm_profile.clk_mask[clk_type]);
				if (ret)
					dev_err(smu->adev->dev, "Failed to set clock type = %d\n",
							clk_type);
			}
		}
	}

	/* set the user dpm fan configurations */
	if (smu->user_dpm_profile.fan_mode == AMD_FAN_CTRL_MANUAL) {
		ret = smu_set_fan_control_mode(smu, smu->user_dpm_profile.fan_mode);
		if (ret) {
			dev_err(smu->adev->dev, "Failed to set manual fan control mode\n");
			return;
		}

		if (!ret && smu->user_dpm_profile.fan_speed_rpm) {
			ret = smu_set_fan_speed_rpm(smu, smu->user_dpm_profile.fan_speed_rpm);
			if (ret)
				dev_err(smu->adev->dev, "Failed to set manual fan speed\n");
		}
	}

	/* Disable restore flag */
	smu->user_dpm_profile.flags &= ~SMU_DPM_USER_PROFILE_RESTORE;
}

int smu_get_power_num_states(struct smu_context *smu,
			     struct pp_states_info *state_info)
{
@@ -529,6 +642,8 @@ static int smu_late_init(void *handle)
			AMD_PP_TASK_COMPLETE_INIT,
			false);

	smu_restore_dpm_user_profile(smu);

	return 0;
}

@@ -1622,6 +1737,12 @@ int smu_force_performance_level(struct smu_context *smu, enum amd_dpm_forced_lev

	mutex_unlock(&smu->mutex);

	/* reset user dpm clock state */
	if (!ret && smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) {
		memset(smu->user_dpm_profile.clk_mask, 0, sizeof(smu->user_dpm_profile.clk_mask));
		smu->user_dpm_profile.clk_dependency = 0;
	}

	return ret;
}

@@ -1656,8 +1777,13 @@ int smu_force_clk_levels(struct smu_context *smu,

	mutex_lock(&smu->mutex);

	if (smu->ppt_funcs && smu->ppt_funcs->force_clk_levels)
	if (smu->ppt_funcs && smu->ppt_funcs->force_clk_levels) {
		ret = smu->ppt_funcs->force_clk_levels(smu, clk_type, mask);
		if (!ret && smu->user_dpm_profile.flags != SMU_DPM_USER_PROFILE_RESTORE) {
			smu->user_dpm_profile.clk_mask[clk_type] = mask;
			smu_set_user_clk_dependencies(smu, clk_type);
		}
	}

	mutex_unlock(&smu->mutex);

@@ -1906,8 +2032,11 @@ int smu_set_fan_speed_rpm(struct smu_context *smu, uint32_t speed)

	mutex_lock(&smu->mutex);

	if (smu->ppt_funcs->set_fan_speed_rpm)
	if (smu->ppt_funcs->set_fan_speed_rpm) {
		ret = smu->ppt_funcs->set_fan_speed_rpm(smu, speed);
		if (!ret && smu->user_dpm_profile.flags != SMU_DPM_USER_PROFILE_RESTORE)
			smu->user_dpm_profile.fan_speed_rpm = speed;
	}

	mutex_unlock(&smu->mutex);

@@ -1949,8 +2078,11 @@ int smu_set_power_limit(struct smu_context *smu, uint32_t limit)
	if (!limit)
		limit = smu->current_power_limit;

	if (smu->ppt_funcs->set_power_limit)
	if (smu->ppt_funcs->set_power_limit) {
		ret = smu->ppt_funcs->set_power_limit(smu, limit);
		if (!ret && smu->user_dpm_profile.flags != SMU_DPM_USER_PROFILE_RESTORE)
			smu->user_dpm_profile.power_limit = limit;
	}

out:
	mutex_unlock(&smu->mutex);
@@ -2127,11 +2259,19 @@ int smu_set_fan_control_mode(struct smu_context *smu, int value)

	mutex_lock(&smu->mutex);

	if (smu->ppt_funcs->set_fan_control_mode)
	if (smu->ppt_funcs->set_fan_control_mode) {
		ret = smu->ppt_funcs->set_fan_control_mode(smu, value);
		if (!ret && smu->user_dpm_profile.flags != SMU_DPM_USER_PROFILE_RESTORE)
			smu->user_dpm_profile.fan_mode = value;
	}

	mutex_unlock(&smu->mutex);

	/* reset user dpm fan speed */
	if (!ret && value != AMD_FAN_CTRL_MANUAL &&
			smu->user_dpm_profile.flags != SMU_DPM_USER_PROFILE_RESTORE)
		smu->user_dpm_profile.fan_speed_rpm = 0;

	return ret;
}