Commit abd0a16a authored by Lang Yu's avatar Lang Yu Committed by Alex Deucher
Browse files

drm/amdgpu: add manual sclk/vddc setting support for cyan skilfish(v3)



Add manual sclk/vddc setting supoort via pp_od_clk_voltage sysfs
to maintain consistency with other asics. As cyan skillfish doesn't
support DPM, there is only a single frequency and voltage to adjust.

v2: maintain consistency and add command guide.
v3: adjust user settings storage and coding style.

Command guide:
echo vc point sclk vddc > pp_od_clk_voltage
	"vc"    - sclk voltage curve
	"point" - must be 0
	"sclk"  - target value of sclk(MHz), should be in safe range
	"vddc"  - target value of vddc(mV), a 6.25(mV) stepping is
		  recommended and should be in safe range (the real
		  vddc is an approximation of target value)
echo c > pp_od_clk_voltage
	"c"	- commit the changes of sclk and vddc, only after
		  the commit command, the target values set by "vc"
		  command will take effect
echo r > pp_od_clk_voltage
	"r" 	- reset sclk and vddc to default value, a subsequent
		  commit command is needed to take effect

Example:
1) Check default sclk and vddc
	$ cat pp_od_clk_voltage
	OD_SCLK:
	0: 1800Mhz *
	OD_VDDC:
	0: 862mV *
	OD_RANGE:
	SCLK:    1000Mhz       2000Mhz
	VDDC:     700mV        1129mV
2) Set sclk to 1500MHz and vddc to 700mV
	$ echo vc 0 1500 700 > pp_od_clk_voltage
	$ echo c > pp_od_clk_voltage
	$ cat pp_od_clk_voltage
	OD_SCLK:
	0: 1500Mhz *
	OD_VDDC:
	0: 693mV *
	OD_RANGE:
	SCLK:    1000Mhz       2000Mhz
	VDDC:     700mV        1129mV
3) Reset sclk and vddc to default
	$ echo r > pp_od_clk_voltage
	$ echo c > pp_od_clk_voltage
	$ cat pp_od_clk_voltage
	OD_SCLK:
	0: 1800Mhz *
	OD_VDDC:
	0: 874mV *
	OD_RANGE:
	SCLK:    1000Mhz       2000Mhz
	VDDC:     700mV        1129mV
NOTE:
We don't specify an explicit safe range, you can set any values
between min and max at your own risk. Enjoy!

Signed-off-by: default avatarLang Yu <lang.yu@amd.com>
Reviewed-by: default avatarLijo Lazar <lijo.lazar@amd.com>
Reviewed-by: default avatarHuang Rui <ray.huang@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 3061fe93
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -226,7 +226,10 @@
	__SMU_DUMMY_MAP(SetUclkDpmMode),		\
	__SMU_DUMMY_MAP(LightSBR),			\
	__SMU_DUMMY_MAP(GfxDriverResetRecovery),	\
	__SMU_DUMMY_MAP(BoardPowerCalibration),
	__SMU_DUMMY_MAP(BoardPowerCalibration),   \
	__SMU_DUMMY_MAP(RequestGfxclk),           \
	__SMU_DUMMY_MAP(ForceGfxVid),             \
	__SMU_DUMMY_MAP(UnforceGfxVid),

#undef __SMU_DUMMY_MAP
#define __SMU_DUMMY_MAP(type)	SMU_MSG_##type
+134 −0
Original line number Diff line number Diff line
@@ -44,6 +44,21 @@
#undef pr_info
#undef pr_debug

/* unit: MHz */
#define CYAN_SKILLFISH_SCLK_MIN			1000
#define CYAN_SKILLFISH_SCLK_MAX			2000
#define CYAN_SKILLFISH_SCLK_DEFAULT			1800

/* unit: mV */
#define CYAN_SKILLFISH_VDDC_MIN			700
#define CYAN_SKILLFISH_VDDC_MAX			1129
#define CYAN_SKILLFISH_VDDC_MAGIC			5118 // 0x13fe

static struct gfx_user_settings {
	uint32_t sclk;
	uint32_t vddc;
} cyan_skillfish_user_settings;

#define FEATURE_MASK(feature) (1ULL << feature)
#define SMC_DPM_FEATURE ( \
	FEATURE_MASK(FEATURE_FCLK_DPM_BIT)	|	\
@@ -297,6 +312,27 @@ static int cyan_skillfish_print_clk_levels(struct smu_context *smu,
	smu_cmn_get_sysfs_buf(&buf, &size);

	switch (clk_type) {
	case SMU_OD_SCLK:
		ret  = cyan_skillfish_get_smu_metrics_data(smu, METRICS_CURR_GFXCLK, &cur_value);
		if (ret)
			return ret;
		size += sysfs_emit_at(buf, size,"%s:\n", "OD_SCLK");
		size += sysfs_emit_at(buf, size, "0: %uMhz *\n", cur_value);
		break;
	case SMU_OD_VDDC_CURVE:
		ret  = cyan_skillfish_get_smu_metrics_data(smu, METRICS_VOLTAGE_VDDGFX, &cur_value);
		if (ret)
			return ret;
		size += sysfs_emit_at(buf, size,"%s:\n", "OD_VDDC");
		size += sysfs_emit_at(buf, size, "0: %umV *\n", cur_value);
		break;
	case SMU_OD_RANGE:
		size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");
		size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n",
						CYAN_SKILLFISH_SCLK_MIN, CYAN_SKILLFISH_SCLK_MAX);
		size += sysfs_emit_at(buf, size, "VDDC: %7umV  %10umV\n",
						CYAN_SKILLFISH_VDDC_MIN, CYAN_SKILLFISH_VDDC_MAX);
		break;
	case SMU_GFXCLK:
	case SMU_SCLK:
	case SMU_FCLK:
@@ -394,6 +430,103 @@ static ssize_t cyan_skillfish_get_gpu_metrics(struct smu_context *smu,
	return sizeof(struct gpu_metrics_v2_2);
}

static int cyan_skillfish_od_edit_dpm_table(struct smu_context *smu,
					enum PP_OD_DPM_TABLE_COMMAND type,
					long input[], uint32_t size)
{
	int ret = 0;
	uint32_t vid;

	switch (type) {
	case PP_OD_EDIT_VDDC_CURVE:
		if (size != 3 || input[0] != 0) {
			dev_err(smu->adev->dev, "Invalid parameter!\n");
			return -EINVAL;
		}

		if (input[1] <= CYAN_SKILLFISH_SCLK_MIN ||
			input[1] > CYAN_SKILLFISH_SCLK_MAX) {
			dev_err(smu->adev->dev, "Invalid sclk! Valid sclk range: %uMHz - %uMhz\n",
					CYAN_SKILLFISH_SCLK_MIN, CYAN_SKILLFISH_SCLK_MAX);
			return -EINVAL;
		}

		if (input[2] <= CYAN_SKILLFISH_VDDC_MIN ||
			input[2] > CYAN_SKILLFISH_VDDC_MAX) {
			dev_err(smu->adev->dev, "Invalid vddc! Valid vddc range: %umV - %umV\n",
					CYAN_SKILLFISH_VDDC_MIN, CYAN_SKILLFISH_VDDC_MAX);
			return -EINVAL;
		}

		cyan_skillfish_user_settings.sclk = input[1];
		cyan_skillfish_user_settings.vddc = input[2];

		break;
	case PP_OD_RESTORE_DEFAULT_TABLE:
		if (size != 0) {
			dev_err(smu->adev->dev, "Invalid parameter!\n");
			return -EINVAL;
		}

		cyan_skillfish_user_settings.sclk = CYAN_SKILLFISH_SCLK_DEFAULT;
		cyan_skillfish_user_settings.vddc = CYAN_SKILLFISH_VDDC_MAGIC;

		break;
	case PP_OD_COMMIT_DPM_TABLE:
		if (size != 0) {
			dev_err(smu->adev->dev, "Invalid parameter!\n");
			return -EINVAL;
		}

		if (cyan_skillfish_user_settings.sclk < CYAN_SKILLFISH_SCLK_MIN ||
		    cyan_skillfish_user_settings.sclk > CYAN_SKILLFISH_SCLK_MAX) {
			dev_err(smu->adev->dev, "Invalid sclk! Valid sclk range: %uMHz - %uMhz\n",
					CYAN_SKILLFISH_SCLK_MIN, CYAN_SKILLFISH_SCLK_MAX);
			return -EINVAL;
		}

		if ((cyan_skillfish_user_settings.vddc != CYAN_SKILLFISH_VDDC_MAGIC) &&
			(cyan_skillfish_user_settings.vddc < CYAN_SKILLFISH_VDDC_MIN ||
			cyan_skillfish_user_settings.vddc > CYAN_SKILLFISH_VDDC_MAX)) {
			dev_err(smu->adev->dev, "Invalid vddc! Valid vddc range: %umV - %umV\n",
					CYAN_SKILLFISH_VDDC_MIN, CYAN_SKILLFISH_VDDC_MAX);
			return -EINVAL;
		}

		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_RequestGfxclk,
					cyan_skillfish_user_settings.sclk, NULL);
		if (ret) {
			dev_err(smu->adev->dev, "Set sclk failed!\n");
			return ret;
		}

		if (cyan_skillfish_user_settings.vddc == CYAN_SKILLFISH_VDDC_MAGIC) {
			ret = smu_cmn_send_smc_msg(smu, SMU_MSG_UnforceGfxVid, NULL);
			if (ret) {
				dev_err(smu->adev->dev, "Unforce vddc failed!\n");
				return ret;
			}
		} else {
			/*
			 * PMFW accepts SVI2 VID code, convert voltage to VID:
			 * vid = (uint32_t)((1.55 - voltage) * 160.0 + 0.00001)
			 */
			vid = (1550 - cyan_skillfish_user_settings.vddc) * 160 / 1000;
			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ForceGfxVid, vid, NULL);
			if (ret) {
				dev_err(smu->adev->dev, "Force vddc failed!\n");
				return ret;
			}
		}

		break;
	default:
		return -EOPNOTSUPP;
	}

	return ret;
}

static const struct pptable_funcs cyan_skillfish_ppt_funcs = {

	.check_fw_status = smu_v11_0_check_fw_status,
@@ -406,6 +539,7 @@ static const struct pptable_funcs cyan_skillfish_ppt_funcs = {
	.print_clk_levels = cyan_skillfish_print_clk_levels,
	.is_dpm_running = cyan_skillfish_is_dpm_running,
	.get_gpu_metrics = cyan_skillfish_get_gpu_metrics,
	.od_edit_dpm_table = cyan_skillfish_od_edit_dpm_table,
	.register_irq_handler = smu_v11_0_register_irq_handler,
	.notify_memory_pool_location = smu_v11_0_notify_memory_pool_location,
	.send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,