[PATCH] drm/amd/powerplay: add one sysfs file -- "pp_od_clk_voltage" to support the feature to modify gfx engine clock(Mhz units) on Raven/Raven2/Picasso APU.

Huang Rui ray.huang at amd.com
Mon Sep 28 09:15:56 UTC 2020


On Mon, Sep 28, 2020 at 03:15:30PM +0800, Du, Xiaojian wrote:
> From: Xiaojian Du <xiaojian.du at amd.com>
> 
> From: Xiaojian Du <Xiaojian.Du at amd.com>
> 
> This patch is to add one sysfs file -- "pp_od_clk_voltage" for
> Raven/Raven2/Picasso APU, which is only used by dGPU like VEGA10.
> This sysfs file supports the feature to modify gfx engine clock(Mhz units), it can
> be used to configure the min value and the max value for gfx clock limited in the
> safe range.
> 
> Command guide:
> echo "s level clock" > pp_od_clk_voltage
> 	s - adjust teh sclk level
> 	level - 0 or 1, "0" represents the min value, "1" represents the max value
> 	clock - the clock value(Mhz units), like 400, 800 or 1200, the value must be within the
>                 OD_RANGE limits.
> Example:
> $ cat pp_od_clk_voltage
> OD_SCLK:
> 0:        200Mhz
> 1:       1400Mhz
> OD_RANGE:
> SCLK:     200MHz       1400MHz
> 
> $ echo "s 0 600" > pp_od_clk_voltage
> $ echo "s 1 1000" > pp_od_clk_voltage
> $ cat pp_od_clk_voltage
> OD_SCLK:
> 0:        600Mhz
> 1:       1000Mhz
> OD_RANGE:
> SCLK:     200MHz       1400MHz
> 
> Signed-off-by: Xiaojian Du <Xiaojian.Du at amd.com>

Reviewed-by: Huang Rui <ray.huang at amd.com>

> ---
>  .../gpu/drm/amd/include/kgd_pp_interface.h    |  1 +
>  drivers/gpu/drm/amd/pm/amdgpu_pm.c            | 12 +++
>  drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h       |  4 +
>  drivers/gpu/drm/amd/pm/inc/hwmgr.h            |  5 ++
>  .../gpu/drm/amd/pm/powerplay/amd_powerplay.c  | 17 +++-
>  .../drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c  | 79 +++++++++++++++++++
>  6 files changed, 117 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
> index 0aec28fda058..94132c70d7af 100644
> --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h
> +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
> @@ -281,6 +281,7 @@ struct amd_pm_funcs {
>  	int (*get_power_limit)(void *handle, uint32_t *limit, bool default_limit);
>  	int (*get_power_profile_mode)(void *handle, char *buf);
>  	int (*set_power_profile_mode)(void *handle, long *input, uint32_t size);
> +	int (*set_fine_grain_clk_vol)(void *handle, uint32_t type, long *input, uint32_t size);
>  	int (*odn_edit_dpm_table)(void *handle, uint32_t type, long *input, uint32_t size);
>  	int (*set_mp1_state)(void *handle, enum pp_mp1_state mp1_state);
>  	int (*smu_i2c_bus_access)(void *handle, bool acquire);
> diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
> index b5d2f30043ad..fe0de00f56e2 100644
> --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c
> +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
> @@ -827,6 +827,18 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev,
>  			return -EINVAL;
>  		}
>  	} else {
> +
> +		if (adev->powerplay.pp_funcs->set_fine_grain_clk_vol) {
> +			ret = amdgpu_dpm_set_fine_grain_clk_vol(adev, type,
> +								parameter,
> +								parameter_size);
> +			if (ret) {
> +				pm_runtime_mark_last_busy(ddev->dev);
> +				pm_runtime_put_autosuspend(ddev->dev);
> +				return -EINVAL;
> +			}
> +		}
> +
>  		if (adev->powerplay.pp_funcs->odn_edit_dpm_table) {
>  			ret = amdgpu_dpm_odn_edit_dpm_table(adev, type,
>  						parameter, parameter_size);
> diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
> index dff4a5f99bb0..f6e0e7d8a007 100644
> --- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
> +++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
> @@ -349,6 +349,10 @@ enum amdgpu_pcie_gen {
>  		((adev)->powerplay.pp_funcs->set_power_profile_mode(\
>  			(adev)->powerplay.pp_handle, parameter, size))
>  
> +#define amdgpu_dpm_set_fine_grain_clk_vol(adev, type, parameter, size) \
> +		((adev)->powerplay.pp_funcs->set_fine_grain_clk_vol(\
> +			(adev)->powerplay.pp_handle, type, parameter, size))
> +
>  #define amdgpu_dpm_odn_edit_dpm_table(adev, type, parameter, size) \
>  		((adev)->powerplay.pp_funcs->odn_edit_dpm_table(\
>  			(adev)->powerplay.pp_handle, type, parameter, size))
> diff --git a/drivers/gpu/drm/amd/pm/inc/hwmgr.h b/drivers/gpu/drm/amd/pm/inc/hwmgr.h
> index 1b3529efc91e..3898a95ec28b 100644
> --- a/drivers/gpu/drm/amd/pm/inc/hwmgr.h
> +++ b/drivers/gpu/drm/amd/pm/inc/hwmgr.h
> @@ -340,6 +340,9 @@ struct pp_hwmgr_func {
>  	int (*odn_edit_dpm_table)(struct pp_hwmgr *hwmgr,
>  					enum PP_OD_DPM_TABLE_COMMAND type,
>  					long *input, uint32_t size);
> +	int (*set_fine_grain_clk_vol)(struct pp_hwmgr *hwmgr,
> +				      enum PP_OD_DPM_TABLE_COMMAND type,
> +				      long *input, uint32_t size);
>  	int (*set_power_limit)(struct pp_hwmgr *hwmgr, uint32_t n);
>  	int (*powergate_mmhub)(struct pp_hwmgr *hwmgr);
>  	int (*smus_notify_pwe)(struct pp_hwmgr *hwmgr);
> @@ -347,6 +350,8 @@ struct pp_hwmgr_func {
>  	int (*enable_mgpu_fan_boost)(struct pp_hwmgr *hwmgr);
>  	int (*set_hard_min_dcefclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock);
>  	int (*set_hard_min_fclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock);
> +	int (*set_hard_min_gfxclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock);
> +	int (*set_soft_max_gfxclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock);
>  	int (*get_asic_baco_capability)(struct pp_hwmgr *hwmgr, bool *cap);
>  	int (*get_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE *state);
>  	int (*set_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE state);
> diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
> index a6321f2063c1..bb8d077d3f05 100644
> --- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
> +++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
> @@ -911,6 +911,20 @@ static int pp_set_power_profile_mode(void *handle, long *input, uint32_t size)
>  	return ret;
>  }
>  
> +static int pp_set_fine_grain_clk_vol(void *handle, uint32_t type, long *input, uint32_t size)
> +{
> +	struct pp_hwmgr *hwmgr = handle;
> +
> +	if (!hwmgr || !hwmgr->pm_en)
> +		return -EINVAL;
> +
> +	if (hwmgr->hwmgr_func->set_fine_grain_clk_vol == NULL) {
> +		return 0;
> +	}
> +
> +	return hwmgr->hwmgr_func->set_fine_grain_clk_vol(hwmgr, type, input, size);
> +}
> +
>  static int pp_odn_edit_dpm_table(void *handle, uint32_t type, long *input, uint32_t size)
>  {
>  	struct pp_hwmgr *hwmgr = handle;
> @@ -920,7 +934,7 @@ static int pp_odn_edit_dpm_table(void *handle, uint32_t type, long *input, uint3
>  
>  	if (hwmgr->hwmgr_func->odn_edit_dpm_table == NULL) {
>  		pr_info_ratelimited("%s was not implemented.\n", __func__);
> -		return -EINVAL;
> +		return 0;
>  	}
>  
>  	return hwmgr->hwmgr_func->odn_edit_dpm_table(hwmgr, type, input, size);
> @@ -1645,6 +1659,7 @@ static const struct amd_pm_funcs pp_dpm_funcs = {
>  	.set_powergating_by_smu = pp_set_powergating_by_smu,
>  	.get_power_profile_mode = pp_get_power_profile_mode,
>  	.set_power_profile_mode = pp_set_power_profile_mode,
> +	.set_fine_grain_clk_vol = pp_set_fine_grain_clk_vol,
>  	.odn_edit_dpm_table = pp_odn_edit_dpm_table,
>  	.set_mp1_state = pp_dpm_set_mp1_state,
>  	.set_power_limit = pp_set_power_limit,
> diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c
> index 9ee8cf8267c8..791db107d51a 100644
> --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c
> +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c
> @@ -242,6 +242,34 @@ static int smu10_set_hard_min_fclk_by_freq(struct pp_hwmgr *hwmgr, uint32_t cloc
>  	return 0;
>  }
>  
> +static int smu10_set_hard_min_gfxclk_by_freq(struct pp_hwmgr *hwmgr, uint32_t clock)
> +{
> +	struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
> +
> +	if (clock && smu10_data->gfx_actual_soft_min_freq != clock) {
> +		smu10_data->gfx_actual_soft_min_freq = clock;
> +		smum_send_msg_to_smc_with_parameter(hwmgr,
> +					PPSMC_MSG_SetHardMinGfxClk,
> +					smu10_data->gfx_actual_soft_min_freq,
> +					NULL);
> +	}
> +	return 0;
> +}
> +
> +static int smu10_set_soft_max_gfxclk_by_freq(struct pp_hwmgr *hwmgr, uint32_t clock)
> +{
> +	struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
> +
> +	if (clock && smu10_data->gfx_max_freq_limit != (clock * 100))  {
> +		smu10_data->gfx_max_freq_limit = clock * 100;
> +		smum_send_msg_to_smc_with_parameter(hwmgr,
> +					PPSMC_MSG_SetSoftMaxGfxClk,
> +					clock,
> +					NULL);
> +	}
> +	return 0;
> +}
> +
>  static int smu10_set_active_display_count(struct pp_hwmgr *hwmgr, uint32_t count)
>  {
>  	struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
> @@ -527,6 +555,8 @@ static int smu10_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
>  	hwmgr->pstate_sclk = SMU10_UMD_PSTATE_GFXCLK * 100;
>  	hwmgr->pstate_mclk = SMU10_UMD_PSTATE_FCLK * 100;
>  
> +	hwmgr->od_enabled = 1; /*enable the pp_od_clk_voltage sysfs file*/
> +
>  	return result;
>  }
>  
> @@ -947,6 +977,26 @@ static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr,
>  					((mclk_table->entries[i].clk / 100)
>  					 == now) ? "*" : "");
>  		break;
> +	case OD_SCLK:
> +		if (hwmgr->od_enabled) {
> +			size = sprintf(buf, "%s:\n", "OD_SCLK");
> +
> +			size += sprintf(buf + size, "0: %10uMhz\n",
> +			(data->gfx_actual_soft_min_freq > 0) ? data->gfx_actual_soft_min_freq : data->gfx_min_freq_limit/100);
> +			size += sprintf(buf + size, "1: %10uMhz\n", data->gfx_max_freq_limit/100);
> +		}
> +		break;
> +	case OD_RANGE:
> +		if (hwmgr->od_enabled) {
> +			uint32_t min_freq, max_freq = 0;
> +			smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency, &min_freq);
> +			smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency, &max_freq);
> +
> +			size = sprintf(buf, "%s:\n", "OD_RANGE");
> +			size += sprintf(buf + size, "SCLK: %7uMHz %10uMHz\n",
> +				min_freq, max_freq);
> +		}
> +		break;
>  	default:
>  		break;
>  	}
> @@ -1348,6 +1398,32 @@ static int smu10_asic_reset(struct pp_hwmgr *hwmgr, enum SMU_ASIC_RESET_MODE mod
>  						   NULL);
>  }
>  
> +static int smu10_set_fine_grain_clk_vol(struct pp_hwmgr *hwmgr,
> +					enum PP_OD_DPM_TABLE_COMMAND type,
> +					long *input, uint32_t size)
> +{
> +	if (!hwmgr->od_enabled) {
> +		pr_err("Fine grain not support\n");
> +		return -EINVAL;
> +	}
> +
> +	if (size != 2) {
> +		pr_err("Input parameter number not correct\n");
> +		return -EINVAL;
> +	}
> +
> +	if (type == PP_OD_EDIT_SCLK_VDDC_TABLE) {
> +		if (input[0] == 0)
> +			smu10_set_hard_min_gfxclk_by_freq(hwmgr, input[1]);
> +		else if (input[0] == 1)
> +			smu10_set_soft_max_gfxclk_by_freq(hwmgr, input[1]);
> +		else
> +			return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
>  static const struct pp_hwmgr_func smu10_hwmgr_funcs = {
>  	.backend_init = smu10_hwmgr_backend_init,
>  	.backend_fini = smu10_hwmgr_backend_fini,
> @@ -1388,9 +1464,12 @@ static const struct pp_hwmgr_func smu10_hwmgr_funcs = {
>  	.powergate_sdma = smu10_powergate_sdma,
>  	.set_hard_min_dcefclk_by_freq = smu10_set_hard_min_dcefclk_by_freq,
>  	.set_hard_min_fclk_by_freq = smu10_set_hard_min_fclk_by_freq,
> +	.set_hard_min_gfxclk_by_freq = smu10_set_hard_min_gfxclk_by_freq,
> +	.set_soft_max_gfxclk_by_freq = smu10_set_soft_max_gfxclk_by_freq,
>  	.get_power_profile_mode = smu10_get_power_profile_mode,
>  	.set_power_profile_mode = smu10_set_power_profile_mode,
>  	.asic_reset = smu10_asic_reset,
> +	.set_fine_grain_clk_vol = smu10_set_fine_grain_clk_vol,
>  };
>  
>  int smu10_init_function_pointers(struct pp_hwmgr *hwmgr)
> -- 
> 2.17.1
> 


More information about the amd-gfx mailing list