diff options
Diffstat (limited to 'drivers/gpu/drm/amd/pm')
29 files changed, 1758 insertions, 315 deletions
diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index f4f40459f22b..a57952b93e73 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -678,7 +678,12 @@ static ssize_t amdgpu_set_pp_table(struct device *dev,   *   clock labeled OD_MCLK   *   * - three <frequency, voltage> points labeled OD_VDDC_CURVE. - *   They can be used to calibrate the sclk voltage curve. + *   They can be used to calibrate the sclk voltage curve. This is + *   available for Vega20 and NV1X. + * + * - voltage offset for the six anchor points of the v/f curve labeled + *   OD_VDDC_CURVE. They can be used to calibrate the v/f curve. This + *   is only availabe for some SMU13 ASICs.   *   * - voltage offset(in mV) applied on target voltage calculation.   *   This is available for Sienna Cichlid, Navy Flounder and Dimgrey @@ -719,12 +724,19 @@ static ssize_t amdgpu_set_pp_table(struct device *dev,   *   E.g., "p 2 0 800" would set the minimum core clock on core   *   2 to 800Mhz.   * - *   For sclk voltage curve, enter the new values by writing a - *   string that contains "vc point clock voltage" to the file. The - *   points are indexed by 0, 1 and 2. E.g., "vc 0 300 600" will - *   update point1 with clock set as 300Mhz and voltage as - *   600mV. "vc 2 1000 1000" will update point3 with clock set - *   as 1000Mhz and voltage 1000mV. + *   For sclk voltage curve, + *     - For NV1X, enter the new values by writing a string that + *       contains "vc point clock voltage" to the file. The points + *       are indexed by 0, 1 and 2. E.g., "vc 0 300 600" will update + *       point1 with clock set as 300Mhz and voltage as 600mV. "vc 2 + *       1000 1000" will update point3 with clock set as 1000Mhz and + *       voltage 1000mV. + *     - For SMU13 ASICs, enter the new values by writing a string that + *       contains "vc anchor_point_index voltage_offset" to the file. + *       There are total six anchor points defined on the v/f curve with + *       index as 0 - 5. + *       - "vc 0 10" will update the voltage offset for point1 as 10mv. + *       - "vc 5 -10" will update the voltage offset for point6 as -10mv.   *   *   To update the voltage offset applied for gfxclk/voltage calculation,   *   enter the new value by writing a string that contains "vo offset". @@ -3360,7 +3372,8 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,  		return 0;  	/* Skip crit temp on APU */ -	if ((adev->flags & AMD_IS_APU) && (adev->family >= AMDGPU_FAMILY_CZ) && +	if ((((adev->flags & AMD_IS_APU) && (adev->family >= AMDGPU_FAMILY_CZ)) || +	    (gc_ver == IP_VERSION(9, 4, 3))) &&  	    (attr == &sensor_dev_attr_temp1_crit.dev_attr.attr ||  	     attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr))  		return 0; @@ -3393,9 +3406,10 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,  	      attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't manage state */  		effective_mode &= ~S_IWUSR; -	/* In the case of APUs, this is only implemented on Vangogh */ +	/* not implemented yet for APUs other than GC 10.3.1 (vangogh) and 9.4.3 */  	if (((adev->family == AMDGPU_FAMILY_SI) || -	     ((adev->flags & AMD_IS_APU) && (gc_ver != IP_VERSION(10, 3, 1)))) && +	     ((adev->flags & AMD_IS_APU) && (gc_ver != IP_VERSION(10, 3, 1)) && +	      (gc_ver != IP_VERSION(9, 4, 3)))) &&  	    (attr == &sensor_dev_attr_power1_cap_max.dev_attr.attr ||  	     attr == &sensor_dev_attr_power1_cap_min.dev_attr.attr ||  	     attr == &sensor_dev_attr_power1_cap.dev_attr.attr || @@ -3424,36 +3438,48 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,  		return 0;  	if ((adev->family == AMDGPU_FAMILY_SI ||	/* not implemented yet */ -	     adev->family == AMDGPU_FAMILY_KV) &&	/* not implemented yet */ +	     adev->family == AMDGPU_FAMILY_KV ||	/* not implemented yet */ +	     (gc_ver == IP_VERSION(9, 4, 3))) &&  	    (attr == &sensor_dev_attr_in0_input.dev_attr.attr ||  	     attr == &sensor_dev_attr_in0_label.dev_attr.attr))  		return 0; -	/* only APUs have vddnb */ -	if (!(adev->flags & AMD_IS_APU) && +	/* only APUs other than gc 9,4,3 have vddnb */ +	if ((!(adev->flags & AMD_IS_APU) || (gc_ver == IP_VERSION(9, 4, 3))) &&  	    (attr == &sensor_dev_attr_in1_input.dev_attr.attr ||  	     attr == &sensor_dev_attr_in1_label.dev_attr.attr))  		return 0; -	/* no mclk on APUs */ -	if ((adev->flags & AMD_IS_APU) && +	/* no mclk on APUs other than gc 9,4,3*/ +	if (((adev->flags & AMD_IS_APU) && (gc_ver != IP_VERSION(9, 4, 3))) &&  	    (attr == &sensor_dev_attr_freq2_input.dev_attr.attr ||  	     attr == &sensor_dev_attr_freq2_label.dev_attr.attr))  		return 0; -	/* only SOC15 dGPUs support hotspot and mem temperatures */  	if (((adev->flags & AMD_IS_APU) || gc_ver < IP_VERSION(9, 0, 0)) && +	    (gc_ver != IP_VERSION(9, 4, 3)) && +	    (attr == &sensor_dev_attr_temp2_input.dev_attr.attr || +	     attr == &sensor_dev_attr_temp2_label.dev_attr.attr || +	     attr == &sensor_dev_attr_temp3_input.dev_attr.attr || +	     attr == &sensor_dev_attr_temp3_label.dev_attr.attr)) +		return 0; + +	/* hotspot temperature for gc 9,4,3*/ +	if ((gc_ver == IP_VERSION(9, 4, 3)) && +	    (attr == &sensor_dev_attr_temp1_input.dev_attr.attr || +	     attr == &sensor_dev_attr_temp1_label.dev_attr.attr)) +		return 0; + +	/* only SOC15 dGPUs support hotspot and mem temperatures */ +	if (((adev->flags & AMD_IS_APU) || gc_ver < IP_VERSION(9, 0, 0) || +	    (gc_ver == IP_VERSION(9, 4, 3))) &&  	    (attr == &sensor_dev_attr_temp2_crit.dev_attr.attr ||  	     attr == &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr ||  	     attr == &sensor_dev_attr_temp3_crit.dev_attr.attr ||  	     attr == &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr ||  	     attr == &sensor_dev_attr_temp1_emergency.dev_attr.attr ||  	     attr == &sensor_dev_attr_temp2_emergency.dev_attr.attr || -	     attr == &sensor_dev_attr_temp3_emergency.dev_attr.attr || -	     attr == &sensor_dev_attr_temp2_input.dev_attr.attr || -	     attr == &sensor_dev_attr_temp3_input.dev_attr.attr || -	     attr == &sensor_dev_attr_temp2_label.dev_attr.attr || -	     attr == &sensor_dev_attr_temp3_label.dev_attr.attr)) +	     attr == &sensor_dev_attr_temp3_emergency.dev_attr.attr))  		return 0;  	/* only Vangogh has fast PPT limit and power labels */ diff --git a/drivers/gpu/drm/amd/pm/inc/smu_v13_0_0_pptable.h b/drivers/gpu/drm/amd/pm/inc/smu_v13_0_0_pptable.h index 566a0da59e53..1dc7a065a6d4 100644 --- a/drivers/gpu/drm/amd/pm/inc/smu_v13_0_0_pptable.h +++ b/drivers/gpu/drm/amd/pm/inc/smu_v13_0_0_pptable.h @@ -38,13 +38,12 @@  #define SMU_13_0_0_PP_THERMALCONTROLLER_NONE 0  #define SMU_13_0_0_PP_THERMALCONTROLLER_NAVI21 28 -#define SMU_13_0_0_PP_OVERDRIVE_VERSION 0x81        // OverDrive 8 Table Version 0.2 +#define SMU_13_0_0_PP_OVERDRIVE_VERSION 0x83        // OverDrive 8 Table Version 0.2  #define SMU_13_0_0_PP_POWERSAVINGCLOCK_VERSION 0x01 // Power Saving Clock Table Version 1.00  enum SMU_13_0_0_ODFEATURE_CAP  {      SMU_13_0_0_ODCAP_GFXCLK_LIMITS = 0, -    SMU_13_0_0_ODCAP_GFXCLK_CURVE,      SMU_13_0_0_ODCAP_UCLK_LIMITS,      SMU_13_0_0_ODCAP_POWER_LIMIT,      SMU_13_0_0_ODCAP_FAN_ACOUSTIC_LIMIT, @@ -59,13 +58,13 @@ enum SMU_13_0_0_ODFEATURE_CAP      SMU_13_0_0_ODCAP_FAN_CURVE,      SMU_13_0_0_ODCAP_AUTO_FAN_ACOUSTIC_LIMIT,      SMU_13_0_0_ODCAP_POWER_MODE, +    SMU_13_0_0_ODCAP_PER_ZONE_GFX_VOLTAGE_OFFSET,      SMU_13_0_0_ODCAP_COUNT,  };  enum SMU_13_0_0_ODFEATURE_ID  {      SMU_13_0_0_ODFEATURE_GFXCLK_LIMITS           = 1 << SMU_13_0_0_ODCAP_GFXCLK_LIMITS,           //GFXCLK Limit feature -    SMU_13_0_0_ODFEATURE_GFXCLK_CURVE            = 1 << SMU_13_0_0_ODCAP_GFXCLK_CURVE,            //GFXCLK Curve feature      SMU_13_0_0_ODFEATURE_UCLK_LIMITS             = 1 << SMU_13_0_0_ODCAP_UCLK_LIMITS,             //UCLK Limit feature      SMU_13_0_0_ODFEATURE_POWER_LIMIT             = 1 << SMU_13_0_0_ODCAP_POWER_LIMIT,             //Power Limit feature      SMU_13_0_0_ODFEATURE_FAN_ACOUSTIC_LIMIT      = 1 << SMU_13_0_0_ODCAP_FAN_ACOUSTIC_LIMIT,      //Fan Acoustic RPM feature @@ -80,6 +79,7 @@ enum SMU_13_0_0_ODFEATURE_ID      SMU_13_0_0_ODFEATURE_FAN_CURVE               = 1 << SMU_13_0_0_ODCAP_FAN_CURVE,               //Fan Curve feature      SMU_13_0_0_ODFEATURE_AUTO_FAN_ACOUSTIC_LIMIT = 1 << SMU_13_0_0_ODCAP_AUTO_FAN_ACOUSTIC_LIMIT, //Auto Fan Acoustic RPM feature      SMU_13_0_0_ODFEATURE_POWER_MODE              = 1 << SMU_13_0_0_ODCAP_POWER_MODE,              //Optimized GPU Power Mode feature +    SMU_13_0_0_ODFEATURE_PER_ZONE_GFX_VOLTAGE_OFFSET  = 1 << SMU_13_0_0_ODCAP_PER_ZONE_GFX_VOLTAGE_OFFSET,  //Perzone voltage offset feature      SMU_13_0_0_ODFEATURE_COUNT                   = 16,  }; @@ -89,10 +89,6 @@ enum SMU_13_0_0_ODSETTING_ID  {      SMU_13_0_0_ODSETTING_GFXCLKFMAX = 0,      SMU_13_0_0_ODSETTING_GFXCLKFMIN, -    SMU_13_0_0_ODSETTING_CUSTOM_GFX_VF_CURVE_A, -    SMU_13_0_0_ODSETTING_CUSTOM_GFX_VF_CURVE_B, -    SMU_13_0_0_ODSETTING_CUSTOM_GFX_VF_CURVE_C, -    SMU_13_0_0_ODSETTING_CUSTOM_CURVE_VFT_FMIN,      SMU_13_0_0_ODSETTING_UCLKFMIN,      SMU_13_0_0_ODSETTING_UCLKFMAX,      SMU_13_0_0_ODSETTING_POWERPERCENTAGE, @@ -117,6 +113,12 @@ enum SMU_13_0_0_ODSETTING_ID      SMU_13_0_0_ODSETTING_FAN_CURVE_SPEED_5,      SMU_13_0_0_ODSETTING_AUTO_FAN_ACOUSTIC_LIMIT,      SMU_13_0_0_ODSETTING_POWER_MODE, +    SMU_13_0_0_ODSETTING_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_1, +    SMU_13_0_0_ODSETTING_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_2, +    SMU_13_0_0_ODSETTING_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_3, +    SMU_13_0_0_ODSETTING_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_4, +    SMU_13_0_0_ODSETTING_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_5, +    SMU_13_0_0_ODSETTING_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_6,      SMU_13_0_0_ODSETTING_COUNT,  };  #define SMU_13_0_0_MAX_ODSETTING 64 //Maximum Number of ODSettings diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c index f5e08b60f66e..36c831b280ed 100644 --- a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c +++ b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c @@ -508,19 +508,19 @@ static int kv_enable_didt(struct amdgpu_device *adev, bool enable)  	    pi->caps_db_ramping ||  	    pi->caps_td_ramping ||  	    pi->caps_tcp_ramping) { -		amdgpu_gfx_rlc_enter_safe_mode(adev); +		amdgpu_gfx_rlc_enter_safe_mode(adev, 0);  		if (enable) {  			ret = kv_program_pt_config_registers(adev, didt_config_kv);  			if (ret) { -				amdgpu_gfx_rlc_exit_safe_mode(adev); +				amdgpu_gfx_rlc_exit_safe_mode(adev, 0);  				return ret;  			}  		}  		kv_do_enable_didt(adev, enable); -		amdgpu_gfx_rlc_exit_safe_mode(adev); +		amdgpu_gfx_rlc_exit_safe_mode(adev, 0);  	}  	return 0; diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_powertune.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_powertune.c index 32a5a00fd8ae..21be23ec3c79 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_powertune.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_powertune.c @@ -973,7 +973,7 @@ int smu7_enable_didt_config(struct pp_hwmgr *hwmgr)  	    PP_CAP(PHM_PlatformCaps_TDRamping) ||  	    PP_CAP(PHM_PlatformCaps_TCPRamping)) { -		amdgpu_gfx_rlc_enter_safe_mode(adev); +		amdgpu_gfx_rlc_enter_safe_mode(adev, 0);  		mutex_lock(&adev->grbm_idx_mutex);  		value = 0;  		value2 = cgs_read_register(hwmgr->device, mmGRBM_GFX_INDEX); @@ -1048,13 +1048,13 @@ int smu7_enable_didt_config(struct pp_hwmgr *hwmgr)  		}  		mutex_unlock(&adev->grbm_idx_mutex); -		amdgpu_gfx_rlc_exit_safe_mode(adev); +		amdgpu_gfx_rlc_exit_safe_mode(adev, 0);  	}  	return 0;  error:  	mutex_unlock(&adev->grbm_idx_mutex); -	amdgpu_gfx_rlc_exit_safe_mode(adev); +	amdgpu_gfx_rlc_exit_safe_mode(adev, 0);  	return result;  } @@ -1068,7 +1068,7 @@ int smu7_disable_didt_config(struct pp_hwmgr *hwmgr)  	    PP_CAP(PHM_PlatformCaps_TDRamping) ||  	    PP_CAP(PHM_PlatformCaps_TCPRamping)) { -		amdgpu_gfx_rlc_enter_safe_mode(adev); +		amdgpu_gfx_rlc_enter_safe_mode(adev, 0);  		result = smu7_enable_didt(hwmgr, false);  		PP_ASSERT_WITH_CODE((result == 0), @@ -1081,12 +1081,12 @@ int smu7_disable_didt_config(struct pp_hwmgr *hwmgr)  			PP_ASSERT_WITH_CODE((0 == result),  					"Failed to disable DPM DIDT.", goto error);  		} -		amdgpu_gfx_rlc_exit_safe_mode(adev); +		amdgpu_gfx_rlc_exit_safe_mode(adev, 0);  	}  	return 0;  error: -	amdgpu_gfx_rlc_exit_safe_mode(adev); +	amdgpu_gfx_rlc_exit_safe_mode(adev, 0);  	return result;  } diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_powertune.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_powertune.c index 9757d47dd6b8..309a9d3bc1b7 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_powertune.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_powertune.c @@ -915,7 +915,7 @@ static int vega10_enable_cac_driving_se_didt_config(struct pp_hwmgr *hwmgr)  	num_se = adev->gfx.config.max_shader_engines; -	amdgpu_gfx_rlc_enter_safe_mode(adev); +	amdgpu_gfx_rlc_enter_safe_mode(adev, 0);  	mutex_lock(&adev->grbm_idx_mutex);  	for (count = 0; count < num_se; count++) { @@ -940,7 +940,7 @@ static int vega10_enable_cac_driving_se_didt_config(struct pp_hwmgr *hwmgr)  	vega10_didt_set_mask(hwmgr, true); -	amdgpu_gfx_rlc_exit_safe_mode(adev); +	amdgpu_gfx_rlc_exit_safe_mode(adev, 0);  	return 0;  } @@ -949,11 +949,11 @@ static int vega10_disable_cac_driving_se_didt_config(struct pp_hwmgr *hwmgr)  {  	struct amdgpu_device *adev = hwmgr->adev; -	amdgpu_gfx_rlc_enter_safe_mode(adev); +	amdgpu_gfx_rlc_enter_safe_mode(adev, 0);  	vega10_didt_set_mask(hwmgr, false); -	amdgpu_gfx_rlc_exit_safe_mode(adev); +	amdgpu_gfx_rlc_exit_safe_mode(adev, 0);  	return 0;  } @@ -966,7 +966,7 @@ static int vega10_enable_psm_gc_didt_config(struct pp_hwmgr *hwmgr)  	num_se = adev->gfx.config.max_shader_engines; -	amdgpu_gfx_rlc_enter_safe_mode(adev); +	amdgpu_gfx_rlc_enter_safe_mode(adev, 0);  	mutex_lock(&adev->grbm_idx_mutex);  	for (count = 0; count < num_se; count++) { @@ -985,7 +985,7 @@ static int vega10_enable_psm_gc_didt_config(struct pp_hwmgr *hwmgr)  	vega10_didt_set_mask(hwmgr, true); -	amdgpu_gfx_rlc_exit_safe_mode(adev); +	amdgpu_gfx_rlc_exit_safe_mode(adev, 0);  	vega10_program_gc_didt_config_registers(hwmgr, GCDiDtDroopCtrlConfig_vega10);  	if (PP_CAP(PHM_PlatformCaps_GCEDC)) @@ -1002,11 +1002,11 @@ static int vega10_disable_psm_gc_didt_config(struct pp_hwmgr *hwmgr)  	struct amdgpu_device *adev = hwmgr->adev;  	uint32_t data; -	amdgpu_gfx_rlc_enter_safe_mode(adev); +	amdgpu_gfx_rlc_enter_safe_mode(adev, 0);  	vega10_didt_set_mask(hwmgr, false); -	amdgpu_gfx_rlc_exit_safe_mode(adev); +	amdgpu_gfx_rlc_exit_safe_mode(adev, 0);  	if (PP_CAP(PHM_PlatformCaps_GCEDC)) {  		data = 0x00000000; @@ -1027,7 +1027,7 @@ static int vega10_enable_se_edc_config(struct pp_hwmgr *hwmgr)  	num_se = adev->gfx.config.max_shader_engines; -	amdgpu_gfx_rlc_enter_safe_mode(adev); +	amdgpu_gfx_rlc_enter_safe_mode(adev, 0);  	mutex_lock(&adev->grbm_idx_mutex);  	for (count = 0; count < num_se; count++) { @@ -1048,7 +1048,7 @@ static int vega10_enable_se_edc_config(struct pp_hwmgr *hwmgr)  	vega10_didt_set_mask(hwmgr, true); -	amdgpu_gfx_rlc_exit_safe_mode(adev); +	amdgpu_gfx_rlc_exit_safe_mode(adev, 0);  	return 0;  } @@ -1057,11 +1057,11 @@ static int vega10_disable_se_edc_config(struct pp_hwmgr *hwmgr)  {  	struct amdgpu_device *adev = hwmgr->adev; -	amdgpu_gfx_rlc_enter_safe_mode(adev); +	amdgpu_gfx_rlc_enter_safe_mode(adev, 0);  	vega10_didt_set_mask(hwmgr, false); -	amdgpu_gfx_rlc_exit_safe_mode(adev); +	amdgpu_gfx_rlc_exit_safe_mode(adev, 0);  	return 0;  } @@ -1075,7 +1075,7 @@ static int vega10_enable_psm_gc_edc_config(struct pp_hwmgr *hwmgr)  	num_se = adev->gfx.config.max_shader_engines; -	amdgpu_gfx_rlc_enter_safe_mode(adev); +	amdgpu_gfx_rlc_enter_safe_mode(adev, 0);  	vega10_program_gc_didt_config_registers(hwmgr, AvfsPSMResetConfig_vega10); @@ -1096,7 +1096,7 @@ static int vega10_enable_psm_gc_edc_config(struct pp_hwmgr *hwmgr)  	vega10_didt_set_mask(hwmgr, true); -	amdgpu_gfx_rlc_exit_safe_mode(adev); +	amdgpu_gfx_rlc_exit_safe_mode(adev, 0);  	vega10_program_gc_didt_config_registers(hwmgr, PSMGCEDCDroopCtrlConfig_vega10); @@ -1116,11 +1116,11 @@ static int vega10_disable_psm_gc_edc_config(struct pp_hwmgr *hwmgr)  	struct amdgpu_device *adev = hwmgr->adev;  	uint32_t data; -	amdgpu_gfx_rlc_enter_safe_mode(adev); +	amdgpu_gfx_rlc_enter_safe_mode(adev, 0);  	vega10_didt_set_mask(hwmgr, false); -	amdgpu_gfx_rlc_exit_safe_mode(adev); +	amdgpu_gfx_rlc_exit_safe_mode(adev, 0);  	if (PP_CAP(PHM_PlatformCaps_GCEDC)) {  		data = 0x00000000; @@ -1138,7 +1138,7 @@ static int vega10_enable_se_edc_force_stall_config(struct pp_hwmgr *hwmgr)  	struct amdgpu_device *adev = hwmgr->adev;  	int result; -	amdgpu_gfx_rlc_enter_safe_mode(adev); +	amdgpu_gfx_rlc_enter_safe_mode(adev, 0);  	mutex_lock(&adev->grbm_idx_mutex);  	WREG32_SOC15(GC, 0, mmGRBM_GFX_INDEX, 0xE0000000); @@ -1151,7 +1151,7 @@ static int vega10_enable_se_edc_force_stall_config(struct pp_hwmgr *hwmgr)  	vega10_didt_set_mask(hwmgr, false); -	amdgpu_gfx_rlc_exit_safe_mode(adev); +	amdgpu_gfx_rlc_exit_safe_mode(adev, 0);  	return 0;  } diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h index 5ce433e2c16a..f1580a26a850 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h @@ -359,7 +359,7 @@ struct pp_hwmgr_func {  	int (*set_ppfeature_status)(struct pp_hwmgr *hwmgr, uint64_t ppfeature_masks);  	int (*set_mp1_state)(struct pp_hwmgr *hwmgr, enum pp_mp1_state mp1_state);  	int (*asic_reset)(struct pp_hwmgr *hwmgr, enum SMU_ASIC_RESET_MODE mode); -	int (*smu_i2c_bus_access)(struct pp_hwmgr *hwmgr, bool aquire); +	int (*smu_i2c_bus_access)(struct pp_hwmgr *hwmgr, bool acquire);  	int (*set_df_cstate)(struct pp_hwmgr *hwmgr, enum pp_df_cstate state);  	int (*set_xgmi_pstate)(struct pp_hwmgr *hwmgr, uint32_t pstate);  	int (*disable_power_features_for_compute_performance)(struct pp_hwmgr *hwmgr, diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 2ddf5198e5c4..4dea79a0c5b5 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -822,11 +822,20 @@ static int smu_init_fb_allocations(struct smu_context *smu)  		}  	} +	driver_table->domain = AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT;  	/* VRAM allocation for driver table */  	for (i = 0; i < SMU_TABLE_COUNT; i++) {  		if (tables[i].size == 0)  			continue; +		/* If one of the tables has VRAM domain restriction, keep it in +		 * VRAM +		 */ +		if ((tables[i].domain & +		    (AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT)) == +			    AMDGPU_GEM_DOMAIN_VRAM) +			driver_table->domain = AMDGPU_GEM_DOMAIN_VRAM; +  		if (i == SMU_TABLE_PMSTATUSLOG)  			continue; @@ -836,7 +845,6 @@ static int smu_init_fb_allocations(struct smu_context *smu)  	driver_table->size = max_table_size;  	driver_table->align = PAGE_SIZE; -	driver_table->domain = AMDGPU_GEM_DOMAIN_VRAM;  	ret = amdgpu_bo_create_kernel(adev,  				      driver_table->size, diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_aldebaran.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_aldebaran.h index 90200f31ff52..cddf45eebee8 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_aldebaran.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_aldebaran.h @@ -24,6 +24,8 @@  #ifndef SMU13_DRIVER_IF_ALDEBARAN_H  #define SMU13_DRIVER_IF_ALDEBARAN_H +#define SMU13_DRIVER_IF_VERSION_ALDE 0x08 +  #define NUM_VCLK_DPM_LEVELS   8  #define NUM_DCLK_DPM_LEVELS   8  #define NUM_SOCCLK_DPM_LEVELS 8 diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h index b686fb68a6e7..9dd1ed5b8940 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h @@ -24,8 +24,10 @@  #ifndef SMU13_DRIVER_IF_V13_0_0_H  #define SMU13_DRIVER_IF_V13_0_0_H +#define SMU13_0_0_DRIVER_IF_VERSION 0x3D +  //Increment this version if SkuTable_t or BoardTable_t change -#define PPTABLE_VERSION 0x26 +#define PPTABLE_VERSION 0x2B  #define NUM_GFXCLK_DPM_LEVELS    16  #define NUM_SOCCLK_DPM_LEVELS    8 @@ -94,7 +96,7 @@  #define FEATURE_ATHUB_MMHUB_PG_BIT            48  #define FEATURE_SOC_PCC_BIT                   49  #define FEATURE_EDC_PWRBRK_BIT                50 -#define FEATURE_SPARE_51_BIT                  51 +#define FEATURE_BOMXCO_SVI3_PROG_BIT          51  #define FEATURE_SPARE_52_BIT                  52  #define FEATURE_SPARE_53_BIT                  53  #define FEATURE_SPARE_54_BIT                  54 @@ -310,6 +312,7 @@ typedef enum {  	I2C_CONTROLLER_PROTOCOL_VR_IR35217,  	I2C_CONTROLLER_PROTOCOL_TMP_MAX31875,  	I2C_CONTROLLER_PROTOCOL_INA3221, +	I2C_CONTROLLER_PROTOCOL_TMP_MAX6604,  	I2C_CONTROLLER_PROTOCOL_COUNT,  } I2cControllerProtocol_e; @@ -568,6 +571,7 @@ typedef enum {  } POWER_SOURCE_e;  typedef enum { +  MEM_VENDOR_PLACEHOLDER0,    MEM_VENDOR_SAMSUNG,    MEM_VENDOR_INFINEON,    MEM_VENDOR_ELPIDA, @@ -577,7 +581,6 @@ typedef enum {    MEM_VENDOR_MOSEL,    MEM_VENDOR_WINBOND,    MEM_VENDOR_ESMT, -  MEM_VENDOR_PLACEHOLDER0,    MEM_VENDOR_PLACEHOLDER1,    MEM_VENDOR_PLACEHOLDER2,    MEM_VENDOR_PLACEHOLDER3, @@ -665,7 +668,14 @@ typedef enum {  #define PP_NUM_RTAVFS_PWL_ZONES 5 - +#define PP_OD_FEATURE_GFX_VF_CURVE_BIT  0 +#define PP_OD_FEATURE_PPT_BIT       2 +#define PP_OD_FEATURE_FAN_CURVE_BIT 3 +#define PP_OD_FEATURE_GFXCLK_BIT      7 +#define PP_OD_FEATURE_UCLK_BIT      8 +#define PP_OD_FEATURE_ZERO_FAN_BIT      9 +#define PP_OD_FEATURE_TEMPERATURE_BIT 10 +#define PP_OD_FEATURE_COUNT 13  // VBIOS or PPLIB configures telemetry slope and offset. Only slope expected to be set for SVI3  // Slope Q1.7, Offset Q1.2 @@ -687,10 +697,8 @@ typedef struct {    //Voltage control    int16_t                VoltageOffsetPerZoneBoundary[PP_NUM_OD_VF_CURVE_POINTS]; -  uint16_t               VddGfxVmax;         // in mV -  uint8_t                IdlePwrSavingFeaturesCtrl; -  uint8_t                RuntimePwrSavingFeaturesCtrl; +  uint32_t               Reserved;    //Frequency changes    int16_t                GfxclkFmin;           // MHz @@ -727,10 +735,9 @@ typedef struct {    uint32_t FeatureCtrlMask;    int16_t VoltageOffsetPerZoneBoundary; -  uint16_t               VddGfxVmax;         // in mV +  uint16_t               Reserved1; -  uint8_t                IdlePwrSavingFeaturesCtrl; -  uint8_t                RuntimePwrSavingFeaturesCtrl; +  uint16_t               Reserved2;    int16_t               GfxclkFmin;           // MHz    int16_t               GfxclkFmax;           // MHz @@ -806,6 +813,9 @@ typedef enum {  #define INVALID_BOARD_GPIO 0xFF +#define MARKETING_BASE_CLOCKS         0 +#define MARKETING_GAME_CLOCKS         1 +#define MARKETING_BOOST_CLOCKS        2  typedef struct {    //PLL 0 @@ -1096,10 +1106,15 @@ typedef struct {    uint16_t        DcsExitHysteresis;    //The min amount of time power credit accumulator should have a value > 0 before SMU exits the DCS throttling phase.    uint16_t        DcsTimeout;           //This is the amount of time SMU FW waits for RLC to put GFX into GFXOFF before reverting to the fallback mechanism of throttling GFXCLK to Fmin. +  uint8_t         FoptEnabled; +  uint8_t         DcsSpare2[3]; +  uint32_t        DcsFoptM;             //Tuning paramters to shift Fopt calculation +  uint32_t        DcsFoptB;             //Tuning paramters to shift Fopt calculation -  uint32_t        DcsSpare[16]; +  uint32_t        DcsSpare[11];    // UCLK section +  uint16_t     ShadowFreqTableUclk[NUM_UCLK_DPM_LEVELS];     // In MHz    uint8_t      UseStrobeModeOptimizations; //Set to indicate that FW should use strobe mode optimizations    uint8_t      PaddingMem[3]; @@ -1245,8 +1260,13 @@ typedef struct {    QuadraticInt_t qFeffCoeffBaseClock[POWER_SOURCE_COUNT];    QuadraticInt_t qFeffCoeffBoostClock[POWER_SOURCE_COUNT]; +  uint16_t TemperatureLimit_Hynix; // In degrees Celsius. Memory temperature limit associated with Hynix +  uint16_t TemperatureLimit_Micron; // In degrees Celsius. Memory temperature limit associated with Micron +  uint16_t TemperatureFwCtfLimit_Hynix; +  uint16_t TemperatureFwCtfLimit_Micron; +    // SECTION: Sku Reserved -  uint32_t         Spare[43]; +  uint32_t         Spare[41];    // Padding for MMHUB - do not modify this    uint32_t     MmHubPadding[8]; @@ -1318,8 +1338,9 @@ typedef struct {    // UCLK Spread Spectrum    uint8_t      UclkSpreadPercent[MEM_VENDOR_COUNT]; +  uint8_t      GfxclkSpreadEnable; +    // FCLK Spread Spectrum -  uint8_t      FclkSpreadPadding;    uint8_t      FclkSpreadPercent;   // Q4.4    uint16_t     FclkSpreadFreq;      // kHz @@ -1444,6 +1465,8 @@ typedef struct {    uint8_t ThrottlingPercentage[THROTTLER_COUNT]; +  uint8_t VmaxThrottlingPercentage; +  uint8_t Padding1[3];    //metrics for D3hot entry/exit and driver ARM msgs    uint32_t D3HotEntryCountPerMode[D3HOT_SEQUENCE_COUNT]; @@ -1463,7 +1486,7 @@ typedef struct {  typedef struct {    SmuMetrics_t SmuMetrics; -  uint32_t Spare[30]; +  uint32_t Spare[29];    // Padding - ignore    uint32_t     MmHubPadding[8]; // SMU internal use diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_4.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_4.h index 2162ecd1057d..fee9293b3f97 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_4.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_4.h @@ -27,7 +27,7 @@  // *** IMPORTANT ***  // SMU TEAM: Always increment the interface version if  // any structure is changed in this file -#define PMFW_DRIVER_IF_VERSION 8 +#define SMU13_0_4_DRIVER_IF_VERSION 8  typedef struct {    int32_t value; diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_5.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_5.h index aa971412b434..7589faa0232d 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_5.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_5.h @@ -23,7 +23,7 @@  #ifndef __SMU13_DRIVER_IF_V13_0_5_H__  #define __SMU13_DRIVER_IF_V13_0_5_H__ -#define PMFW_DRIVER_IF_VERSION 4 +#define SMU13_0_5_DRIVER_IF_VERSION 4  // Throttler Status Bitmask  #define THROTTLER_STATUS_BIT_SPL            0 diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_6.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_6.h index be596777cd2c..ca4a5e99ccd1 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_6.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_6.h @@ -26,7 +26,7 @@  // *** IMPORTANT ***  // PMFW TEAM: Always increment the interface version if  // anything is changed in this file -#define SMU13_0_6_DRIVER_IF_VERSION 0x08042022 +#define SMU13_0_6_DRIVER_IF_VERSION 0x08042024  //I2C Interface  #define NUM_I2C_CONTROLLERS                8 @@ -106,7 +106,7 @@ typedef enum {  } UCLK_DPM_MODE_e;  typedef struct { -  //0-26 SOC, 27-29 SOCIO +  //0-23 SOC, 24-26 SOCIO, 27-29 SOC    uint16_t avgPsmCount[30];    uint16_t minPsmCount[30];    float    avgPsmVoltage[30]; @@ -121,6 +121,17 @@ typedef struct {    float    minPsmVoltage[30];  } AvfsDebugTableXcd_t; +// Defines used for IH-based thermal interrupts to GFX driver - A/X only +#define IH_INTERRUPT_ID_TO_DRIVER                   0xFE +#define IH_INTERRUPT_CONTEXT_ID_THERMAL_THROTTLING  0x7 + +//thermal over-temp mask defines for IH interrupt to host +#define THROTTLER_PROCHOT_BIT           0 +#define THROTTLER_PPT_BIT               1 +#define THROTTLER_THERMAL_SOCKET_BIT    2//AID, XCD, CCD throttling +#define THROTTLER_THERMAL_VR_BIT        3//VRHOT +#define THROTTLER_THERMAL_HBM_BIT       4 +  // These defines are used with the following messages:  // SMC_MSG_TransferTableDram2Smu  // SMC_MSG_TransferTableSmu2Dram diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h index 4c46a0392451..62b7c0daff68 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h @@ -25,7 +25,7 @@  // *** IMPORTANT ***  // PMFW TEAM: Always increment the interface version on any change to this file -#define SMU13_DRIVER_IF_VERSION  0x35 +#define SMU13_0_7_DRIVER_IF_VERSION  0x35  //Increment this version if SkuTable_t or BoardTable_t change  #define PPTABLE_VERSION 0x27 @@ -683,18 +683,12 @@ typedef struct {  #define PP_OD_FEATURE_GFX_VF_CURVE_BIT  0 -#define PP_OD_FEATURE_VMAX_BIT      1  #define PP_OD_FEATURE_PPT_BIT       2  #define PP_OD_FEATURE_FAN_CURVE_BIT 3 -#define PP_OD_FEATURE_FREQ_DETER_BIT 4 -#define PP_OD_FEATURE_FULL_CTRL_BIT 5 -#define PP_OD_FEATURE_TDC_BIT      6  #define PP_OD_FEATURE_GFXCLK_BIT      7  #define PP_OD_FEATURE_UCLK_BIT      8  #define PP_OD_FEATURE_ZERO_FAN_BIT      9  #define PP_OD_FEATURE_TEMPERATURE_BIT 10 -#define PP_OD_FEATURE_POWER_FEATURE_CTRL_BIT 11 -#define PP_OD_FEATURE_ASIC_TDC_BIT 12  #define PP_OD_FEATURE_COUNT 13  typedef enum { @@ -713,10 +707,8 @@ typedef struct {    //Voltage control    int16_t                VoltageOffsetPerZoneBoundary[PP_NUM_OD_VF_CURVE_POINTS]; -  uint16_t               VddGfxVmax;         // in mV -  uint8_t                IdlePwrSavingFeaturesCtrl; -  uint8_t                RuntimePwrSavingFeaturesCtrl; +  uint32_t               Reserved;    //Frequency changes    int16_t                GfxclkFmin;           // MHz @@ -741,12 +733,7 @@ typedef struct {    uint8_t                MaxOpTemp;    uint8_t                Padding[4]; -  uint16_t               GfxVoltageFullCtrlMode; -  uint16_t               GfxclkFullCtrlMode; -  uint16_t               UclkFullCtrlMode; -  int16_t                AsicTdc; - -  uint32_t               Spare[10]; +  uint32_t               Spare[12];    uint32_t               MmHubPadding[8]; // SMU internal use. Adding here instead of external as a workaround  } OverDriveTable_t; @@ -759,10 +746,9 @@ typedef struct {    uint32_t FeatureCtrlMask;    int16_t VoltageOffsetPerZoneBoundary; -  uint16_t               VddGfxVmax;         // in mV +  uint16_t               Reserved1; -  uint8_t                IdlePwrSavingFeaturesCtrl; -  uint8_t                RuntimePwrSavingFeaturesCtrl; +  uint16_t               Reserved2;    int16_t                GfxclkFmin;           // MHz    int16_t                GfxclkFmax;           // MHz @@ -785,12 +771,7 @@ typedef struct {    uint8_t                MaxOpTemp;    uint8_t                Padding[4]; -  uint16_t               GfxVoltageFullCtrlMode; -  uint16_t               GfxclkFullCtrlMode; -  uint16_t               UclkFullCtrlMode; -  int16_t                AsicTdc; - -  uint32_t               Spare[10]; +  uint32_t               Spare[12];  } OverDriveLimits_t; diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_yellow_carp.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_yellow_carp.h index 25540cb28208..7417634827ad 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_yellow_carp.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_yellow_carp.h @@ -26,7 +26,7 @@  // *** IMPORTANT ***  // SMU TEAM: Always increment the interface version if  // any structure is changed in this file -#define SMU13_DRIVER_IF_VERSION 4 +#define SMU13_YELLOW_CARP_DRIVER_IF_VERSION 4  typedef struct {    int32_t value; diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h index bdccbb4a6276..252aef190c5c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h @@ -123,9 +123,9 @@ typedef enum {    VOLTAGE_GUARDBAND_COUNT  } GFX_GUARDBAND_e; -#define SMU_METRICS_TABLE_VERSION 0x1 +#define SMU_METRICS_TABLE_VERSION 0x5 -typedef struct { +typedef struct __attribute__((packed, aligned(4))) {    uint32_t AccumulationCounter;    //TEMPERATURE @@ -198,11 +198,20 @@ typedef struct {    uint32_t SocketThmResidencyAcc;    uint32_t VrThmResidencyAcc;    uint32_t HbmThmResidencyAcc; +  uint32_t spare; + +  // New Items at end to maintain driver compatibility +  uint32_t GfxclkFrequency[8]; + +  //PSNs +  uint64_t PublicSerialNumber_AID[4]; +  uint64_t PublicSerialNumber_XCD[8]; +  uint64_t PublicSerialNumber_CCD[12];  } MetricsTable_t; -#define SMU_VF_METRICS_TABLE_VERSION 0x1 +#define SMU_VF_METRICS_TABLE_VERSION 0x3 -typedef struct { +typedef struct __attribute__((packed, aligned(4))) {    uint32_t AccumulationCounter;    uint32_t InstGfxclk_TargFreq;    uint64_t AccGfxclk_TargFreq; diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_ppsmc.h index b838e8db395a..ae4f44c4b877 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_ppsmc.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_ppsmc.h @@ -82,7 +82,8 @@  #define PPSMC_MSG_SetSoftMaxGfxClk                  0x31  #define PPSMC_MSG_GetMinGfxDpmFreq                  0x32  #define PPSMC_MSG_GetMaxGfxDpmFreq                  0x33 -#define PPSMC_Message_Count                         0x34 +#define PPSMC_MSG_PrepareForDriverUnload            0x34 +#define PPSMC_Message_Count                         0x35  //PPSMC Reset Types for driver msg argument  #define PPSMC_RESET_TYPE_DRIVER_MODE_1_RESET        0x1 diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h index df3baaab0037..6a0ac0bbaace 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h @@ -25,17 +25,6 @@  #include "amdgpu_smu.h" -#define SMU13_DRIVER_IF_VERSION_INV 0xFFFFFFFF -#define SMU13_DRIVER_IF_VERSION_YELLOW_CARP 0x04 -#define SMU13_DRIVER_IF_VERSION_ALDE 0x08 -#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_0_0 0x37 -#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_4 0x08 -#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_5 0x04 -#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_0_10 0x32 -#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_7 0x37 -#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_10 0x1D -#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_6 0x0 -  #define SMU13_MODE1_RESET_WAIT_TIME_IN_MS 500  //500ms  /* MP Apertures */ @@ -62,6 +51,8 @@  #define CTF_OFFSET_HOTSPOT		5  #define CTF_OFFSET_MEM			5 +#define SMU_13_VCLK_SHIFT		16 +  extern const int pmfw_decoded_link_speed[5];  extern const int pmfw_decoded_link_width[7]; @@ -130,6 +121,7 @@ struct smu_13_0_power_context {  	uint32_t	power_source;  	uint8_t		in_power_limit_boost_mode;  	enum smu_13_0_power_state power_state; +	atomic_t	throttle_status;  };  #if defined(SWSMU_CODE_LAYER_L2) || defined(SWSMU_CODE_LAYER_L3) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0_7_pptable.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0_7_pptable.h index 478862ded0bd..eadbe0149cae 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0_7_pptable.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0_7_pptable.h @@ -38,13 +38,12 @@  #define SMU_13_0_7_PP_THERMALCONTROLLER_NONE 0  #define SMU_13_0_7_PP_THERMALCONTROLLER_NAVI21 28 -#define SMU_13_0_7_PP_OVERDRIVE_VERSION 0x81        // OverDrive 8 Table Version 0.2 +#define SMU_13_0_7_PP_OVERDRIVE_VERSION 0x83        // OverDrive 8 Table Version 0.2  #define SMU_13_0_7_PP_POWERSAVINGCLOCK_VERSION 0x01 // Power Saving Clock Table Version 1.00  enum SMU_13_0_7_ODFEATURE_CAP  {      SMU_13_0_7_ODCAP_GFXCLK_LIMITS = 0, -    SMU_13_0_7_ODCAP_GFXCLK_CURVE,      SMU_13_0_7_ODCAP_UCLK_LIMITS,      SMU_13_0_7_ODCAP_POWER_LIMIT,      SMU_13_0_7_ODCAP_FAN_ACOUSTIC_LIMIT, @@ -59,13 +58,13 @@ enum SMU_13_0_7_ODFEATURE_CAP      SMU_13_0_7_ODCAP_FAN_CURVE,      SMU_13_0_7_ODCAP_AUTO_FAN_ACOUSTIC_LIMIT,      SMU_13_0_7_ODCAP_POWER_MODE, +    SMU_13_0_7_ODCAP_PER_ZONE_GFX_VOLTAGE_OFFSET,      SMU_13_0_7_ODCAP_COUNT,  };  enum SMU_13_0_7_ODFEATURE_ID  {      SMU_13_0_7_ODFEATURE_GFXCLK_LIMITS           = 1 << SMU_13_0_7_ODCAP_GFXCLK_LIMITS,           //GFXCLK Limit feature -    SMU_13_0_7_ODFEATURE_GFXCLK_CURVE            = 1 << SMU_13_0_7_ODCAP_GFXCLK_CURVE,            //GFXCLK Curve feature      SMU_13_0_7_ODFEATURE_UCLK_LIMITS             = 1 << SMU_13_0_7_ODCAP_UCLK_LIMITS,             //UCLK Limit feature      SMU_13_0_7_ODFEATURE_POWER_LIMIT             = 1 << SMU_13_0_7_ODCAP_POWER_LIMIT,             //Power Limit feature      SMU_13_0_7_ODFEATURE_FAN_ACOUSTIC_LIMIT      = 1 << SMU_13_0_7_ODCAP_FAN_ACOUSTIC_LIMIT,      //Fan Acoustic RPM feature @@ -80,6 +79,7 @@ enum SMU_13_0_7_ODFEATURE_ID      SMU_13_0_7_ODFEATURE_FAN_CURVE               = 1 << SMU_13_0_7_ODCAP_FAN_CURVE,               //Fan Curve feature      SMU_13_0_7_ODFEATURE_AUTO_FAN_ACOUSTIC_LIMIT = 1 << SMU_13_0_7_ODCAP_AUTO_FAN_ACOUSTIC_LIMIT, //Auto Fan Acoustic RPM feature      SMU_13_0_7_ODFEATURE_POWER_MODE              = 1 << SMU_13_0_7_ODCAP_POWER_MODE,              //Optimized GPU Power Mode feature +    SMU_13_0_7_ODFEATURE_PER_ZONE_GFX_VOLTAGE_OFFSET  = 1 << SMU_13_0_7_ODCAP_PER_ZONE_GFX_VOLTAGE_OFFSET,  //Perzone voltage offset feature      SMU_13_0_7_ODFEATURE_COUNT                   = 16,  }; @@ -89,10 +89,6 @@ enum SMU_13_0_7_ODSETTING_ID  {      SMU_13_0_7_ODSETTING_GFXCLKFMAX = 0,      SMU_13_0_7_ODSETTING_GFXCLKFMIN, -    SMU_13_0_7_ODSETTING_CUSTOM_GFX_VF_CURVE_A, -    SMU_13_0_7_ODSETTING_CUSTOM_GFX_VF_CURVE_B, -    SMU_13_0_7_ODSETTING_CUSTOM_GFX_VF_CURVE_C, -    SMU_13_0_7_ODSETTING_CUSTOM_CURVE_VFT_FMIN,      SMU_13_0_7_ODSETTING_UCLKFMIN,      SMU_13_0_7_ODSETTING_UCLKFMAX,      SMU_13_0_7_ODSETTING_POWERPERCENTAGE, @@ -117,6 +113,12 @@ enum SMU_13_0_7_ODSETTING_ID      SMU_13_0_7_ODSETTING_FAN_CURVE_SPEED_5,      SMU_13_0_7_ODSETTING_AUTO_FAN_ACOUSTIC_LIMIT,      SMU_13_0_7_ODSETTING_POWER_MODE, +    SMU_13_0_7_ODSETTING_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_1, +    SMU_13_0_7_ODSETTING_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_2, +    SMU_13_0_7_ODSETTING_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_3, +    SMU_13_0_7_ODSETTING_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_4, +    SMU_13_0_7_ODSETTING_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_5, +    SMU_13_0_7_ODSETTING_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_6,      SMU_13_0_7_ODSETTING_COUNT,  };  #define SMU_13_0_7_MAX_ODSETTING 64 //Maximum Number of ODSettings diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c index 85d53597eb07..f7ed3e655e39 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c @@ -431,7 +431,13 @@ static int sienna_cichlid_append_powerplay_table(struct smu_context *smu)  {  	struct atom_smc_dpm_info_v4_9 *smc_dpm_table;  	int index, ret; -	I2cControllerConfig_t *table_member; +	PPTable_beige_goby_t *ppt_beige_goby; +	PPTable_t *ppt; + +	if (smu->adev->ip_versions[MP1_HWIP][0] == IP_VERSION(11, 0, 13)) +		ppt_beige_goby = smu->smu_table.driver_pptable; +	else +		ppt = smu->smu_table.driver_pptable;  	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,  					    smc_dpm_info); @@ -440,9 +446,13 @@ static int sienna_cichlid_append_powerplay_table(struct smu_context *smu)  				      (uint8_t **)&smc_dpm_table);  	if (ret)  		return ret; -	GET_PPTABLE_MEMBER(I2cControllers, &table_member); -	memcpy(table_member, smc_dpm_table->I2cControllers, -			sizeof(*smc_dpm_table) - sizeof(smc_dpm_table->table_header)); + +	if (smu->adev->ip_versions[MP1_HWIP][0] == IP_VERSION(11, 0, 13)) +		smu_memcpy_trailing(ppt_beige_goby, I2cControllers, BoardReserved, +				    smc_dpm_table, I2cControllers); +	else +		smu_memcpy_trailing(ppt, I2cControllers, BoardReserved, +				    smc_dpm_table, I2cControllers);  	return 0;  } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index d30ec3005ea1..e80f122d8aec 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -2147,5 +2147,6 @@ void aldebaran_set_ppt_funcs(struct smu_context *smu)  	smu->clock_map = aldebaran_clk_map;  	smu->feature_map = aldebaran_feature_mask_map;  	smu->table_map = aldebaran_table_map; +	smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_ALDE;  	smu_v13_0_set_smu_mailbox_registers(smu);  } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index ca379181081c..e52c563f0dac 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -269,45 +269,10 @@ int smu_v13_0_check_fw_version(struct smu_context *smu)  	smu_major = (smu_version >> 16) & 0xff;  	smu_minor = (smu_version >> 8) & 0xff;  	smu_debug = (smu_version >> 0) & 0xff; -	if (smu->is_apu) +	if (smu->is_apu || +	    adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 6))  		adev->pm.fw_version = smu_version; -	switch (adev->ip_versions[MP1_HWIP][0]) { -	case IP_VERSION(13, 0, 2): -		smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_ALDE; -		break; -	case IP_VERSION(13, 0, 0): -		smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_SMU_V13_0_0_0; -		break; -	case IP_VERSION(13, 0, 10): -		smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_SMU_V13_0_0_10; -		break; -	case IP_VERSION(13, 0, 7): -		smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_SMU_V13_0_7; -		break; -	case IP_VERSION(13, 0, 1): -	case IP_VERSION(13, 0, 3): -	case IP_VERSION(13, 0, 8): -		smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_YELLOW_CARP; -		break; -	case IP_VERSION(13, 0, 4): -	case IP_VERSION(13, 0, 11): -		smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_SMU_V13_0_4; -		break; -	case IP_VERSION(13, 0, 5): -		smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_SMU_V13_0_5; -		break; -	case IP_VERSION(13, 0, 6): -		smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_SMU_V13_0_6; -		adev->pm.fw_version = smu_version; -		break; -	default: -		dev_err(adev->dev, "smu unsupported IP version: 0x%x.\n", -			adev->ip_versions[MP1_HWIP][0]); -		smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_INV; -		break; -	} -  	/* only for dGPU w/ SMU13*/  	if (adev->pm.fw)  		dev_dbg(smu->adev->dev, "smu fw reported program %d, version = 0x%08x (%d.%d.%d)\n", @@ -502,17 +467,26 @@ int smu_v13_0_init_smc_tables(struct smu_context *smu)  			ret = -ENOMEM;  			goto err3_out;  		} + +		smu_table->user_overdrive_table = +			kzalloc(tables[SMU_TABLE_OVERDRIVE].size, GFP_KERNEL); +		if (!smu_table->user_overdrive_table) { +			ret = -ENOMEM; +			goto err4_out; +		}  	}  	smu_table->combo_pptable =  		kzalloc(tables[SMU_TABLE_COMBO_PPTABLE].size, GFP_KERNEL);  	if (!smu_table->combo_pptable) {  		ret = -ENOMEM; -		goto err4_out; +		goto err5_out;  	}  	return 0; +err5_out: +	kfree(smu_table->user_overdrive_table);  err4_out:  	kfree(smu_table->boot_overdrive_table);  err3_out: @@ -532,12 +506,14 @@ int smu_v13_0_fini_smc_tables(struct smu_context *smu)  	kfree(smu_table->gpu_metrics_table);  	kfree(smu_table->combo_pptable); +	kfree(smu_table->user_overdrive_table);  	kfree(smu_table->boot_overdrive_table);  	kfree(smu_table->overdrive_table);  	kfree(smu_table->max_sustainable_clocks);  	kfree(smu_table->driver_pptable);  	smu_table->gpu_metrics_table = NULL;  	smu_table->combo_pptable = NULL; +	smu_table->user_overdrive_table = NULL;  	smu_table->boot_overdrive_table = NULL;  	smu_table->overdrive_table = NULL;  	smu_table->max_sustainable_clocks = NULL; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c index 08577d1b84ec..a6083957ae51 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c @@ -46,7 +46,6 @@  #include "asic_reg/mp/mp_13_0_0_sh_mask.h"  #include "smu_cmn.h"  #include "amdgpu_ras.h" -#include "umc_v8_10.h"  /*   * DO NOT use these for err/warn/info/debug messages. @@ -237,6 +236,7 @@ static struct cmn2asic_mapping smu_v13_0_0_table_map[SMU_TABLE_COUNT] = {  	[SMU_TABLE_COMBO_PPTABLE] = {1, TABLE_COMBO_PPTABLE},  	TAB_MAP(I2C_COMMANDS),  	TAB_MAP(ECCINFO), +	TAB_MAP(OVERDRIVE),  };  static struct cmn2asic_mapping smu_v13_0_0_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { @@ -331,6 +331,11 @@ static int smu_v13_0_0_check_powerplay_table(struct smu_context *smu)  	struct smu_13_0_0_powerplay_table *powerplay_table =  		table_context->power_play_table;  	struct smu_baco_context *smu_baco = &smu->smu_baco; +	PPTable_t *pptable = smu->smu_table.driver_pptable; +	const OverDriveLimits_t * const overdrive_upperlimits = +				&pptable->SkuTable.OverDriveLimitsBasicMax; +	const OverDriveLimits_t * const overdrive_lowerlimits = +				&pptable->SkuTable.OverDriveLimitsMin;  	if (powerplay_table->platform_caps & SMU_13_0_0_PP_PLATFORM_CAP_HARDWAREDC)  		smu->dc_controlled_by_gpio = true; @@ -342,6 +347,10 @@ static int smu_v13_0_0_check_powerplay_table(struct smu_context *smu)  	if (powerplay_table->platform_caps & SMU_13_0_0_PP_PLATFORM_CAP_MACO)  		smu_baco->maco_support = true; +	if (!overdrive_lowerlimits->FeatureCtrlMask || +	    !overdrive_upperlimits->FeatureCtrlMask) +		smu->od_enabled = false; +  	table_context->thermal_controller_type =  		powerplay_table->thermal_controller_type; @@ -461,7 +470,7 @@ static int smu_v13_0_0_tables_init(struct smu_context *smu)  		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);  	SMU_TABLE_INIT(tables, SMU_TABLE_I2C_COMMANDS, sizeof(SwI2cRequest_t),  		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); -	SMU_TABLE_INIT(tables, SMU_TABLE_OVERDRIVE, sizeof(OverDriveTable_t), +	SMU_TABLE_INIT(tables, SMU_TABLE_OVERDRIVE, sizeof(OverDriveTableExternal_t),  		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);  	SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU13_TOOL_SIZE,  		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); @@ -1022,17 +1031,119 @@ static int smu_v13_0_0_get_current_clk_freq_by_table(struct smu_context *smu,  						value);  } +static bool smu_v13_0_0_is_od_feature_supported(struct smu_context *smu, +						int od_feature_bit) +{ +	PPTable_t *pptable = smu->smu_table.driver_pptable; +	const OverDriveLimits_t * const overdrive_upperlimits = +				&pptable->SkuTable.OverDriveLimitsBasicMax; + +	return overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit); +} + +static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu, +					      int od_feature_bit, +					      bool lower_boundary, +					      int32_t *min, +					      int32_t *max) +{ +	PPTable_t *pptable = smu->smu_table.driver_pptable; +	const OverDriveLimits_t * const overdrive_upperlimits = +				&pptable->SkuTable.OverDriveLimitsBasicMax; +	const OverDriveLimits_t * const overdrive_lowerlimits = +				&pptable->SkuTable.OverDriveLimitsMin; +	int32_t od_min_setting, od_max_setting; + +	switch (od_feature_bit) { +	case PP_OD_FEATURE_GFXCLK_BIT: +		if (lower_boundary) { +			od_min_setting = overdrive_lowerlimits->GfxclkFmin; +			od_max_setting = overdrive_upperlimits->GfxclkFmin; +		} else { +			od_min_setting = overdrive_lowerlimits->GfxclkFmax; +			od_max_setting = overdrive_upperlimits->GfxclkFmax; +		} +		break; +	case PP_OD_FEATURE_UCLK_BIT: +		if (lower_boundary) { +			od_min_setting = overdrive_lowerlimits->UclkFmin; +			od_max_setting = overdrive_upperlimits->UclkFmin; +		} else { +			od_min_setting = overdrive_lowerlimits->UclkFmax; +			od_max_setting = overdrive_upperlimits->UclkFmax; +		} +		break; +	case PP_OD_FEATURE_GFX_VF_CURVE_BIT: +		od_min_setting = overdrive_lowerlimits->VoltageOffsetPerZoneBoundary; +		od_max_setting = overdrive_upperlimits->VoltageOffsetPerZoneBoundary; +		break; +	default: +		break; +	} + +	if (min) +		*min = od_min_setting; +	if (max) +		*max = od_max_setting; +} + +static void smu_v13_0_0_dump_od_table(struct smu_context *smu, +				      OverDriveTableExternal_t *od_table) +{ +	struct amdgpu_device *adev = smu->adev; + +	dev_dbg(adev->dev, "OD: Gfxclk: (%d, %d)\n", od_table->OverDriveTable.GfxclkFmin, +						     od_table->OverDriveTable.GfxclkFmax); +	dev_dbg(adev->dev, "OD: Uclk: (%d, %d)\n", od_table->OverDriveTable.UclkFmin, +						   od_table->OverDriveTable.UclkFmax); +} + +static int smu_v13_0_0_get_overdrive_table(struct smu_context *smu, +					   OverDriveTableExternal_t *od_table) +{ +	int ret = 0; + +	ret = smu_cmn_update_table(smu, +				   SMU_TABLE_OVERDRIVE, +				   0, +				   (void *)od_table, +				   false); +	if (ret) +		dev_err(smu->adev->dev, "Failed to get overdrive table!\n"); + +	return ret; +} + +static int smu_v13_0_0_upload_overdrive_table(struct smu_context *smu, +					      OverDriveTableExternal_t *od_table) +{ +	int ret = 0; + +	ret = smu_cmn_update_table(smu, +				   SMU_TABLE_OVERDRIVE, +				   0, +				   (void *)od_table, +				   true); +	if (ret) +		dev_err(smu->adev->dev, "Failed to upload overdrive table!\n"); + +	return ret; +} +  static int smu_v13_0_0_print_clk_levels(struct smu_context *smu,  					enum smu_clk_type clk_type,  					char *buf)  {  	struct smu_dpm_context *smu_dpm = &smu->smu_dpm;  	struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context; +	OverDriveTableExternal_t *od_table = +		(OverDriveTableExternal_t *)smu->smu_table.overdrive_table;  	struct smu_13_0_dpm_table *single_dpm_table;  	struct smu_13_0_pcie_table *pcie_table;  	const int link_width[] = {0, 1, 2, 4, 8, 12, 16};  	uint32_t gen_speed, lane_width;  	int i, curr_freq, size = 0; +	int32_t min_value, max_value;  	int ret = 0;  	smu_cmn_get_sysfs_buf(&buf, &size); @@ -1149,6 +1260,89 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu,  					"*" : "");  		break; +	case SMU_OD_SCLK: +		if (!smu_v13_0_0_is_od_feature_supported(smu, +							 PP_OD_FEATURE_GFXCLK_BIT)) +			break; + +		size += sysfs_emit_at(buf, size, "OD_SCLK:\n"); +		size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n", +					od_table->OverDriveTable.GfxclkFmin, +					od_table->OverDriveTable.GfxclkFmax); +		break; + +	case SMU_OD_MCLK: +		if (!smu_v13_0_0_is_od_feature_supported(smu, +							 PP_OD_FEATURE_UCLK_BIT)) +			break; + +		size += sysfs_emit_at(buf, size, "OD_MCLK:\n"); +		size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMHz\n", +					od_table->OverDriveTable.UclkFmin, +					od_table->OverDriveTable.UclkFmax); +		break; + +	case SMU_OD_VDDC_CURVE: +		if (!smu_v13_0_0_is_od_feature_supported(smu, +							 PP_OD_FEATURE_GFX_VF_CURVE_BIT)) +			break; + +		size += sysfs_emit_at(buf, size, "OD_VDDC_CURVE:\n"); +		for (i = 0; i < PP_NUM_OD_VF_CURVE_POINTS; i++) +			size += sysfs_emit_at(buf, size, "%d: %dmv\n", +						i, +						od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[i]); +		break; + +	case SMU_OD_RANGE: +		if (!smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT) && +		    !smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_UCLK_BIT) && +		    !smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_GFX_VF_CURVE_BIT)) +			break; + +		size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); + +		if (smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT)) { +			smu_v13_0_0_get_od_setting_limits(smu, +							  PP_OD_FEATURE_GFXCLK_BIT, +							  true, +							  &min_value, +							  NULL); +			smu_v13_0_0_get_od_setting_limits(smu, +							  PP_OD_FEATURE_GFXCLK_BIT, +							  false, +							  NULL, +							  &max_value); +			size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n", +					      min_value, max_value); +		} + +		if (smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_UCLK_BIT)) { +			smu_v13_0_0_get_od_setting_limits(smu, +							  PP_OD_FEATURE_UCLK_BIT, +							  true, +							  &min_value, +							  NULL); +			smu_v13_0_0_get_od_setting_limits(smu, +							  PP_OD_FEATURE_UCLK_BIT, +							  false, +							  NULL, +							  &max_value); +			size += sysfs_emit_at(buf, size, "MCLK: %7uMhz %10uMhz\n", +					      min_value, max_value); +		} + +		if (smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_GFX_VF_CURVE_BIT)) { +			smu_v13_0_0_get_od_setting_limits(smu, +							  PP_OD_FEATURE_GFX_VF_CURVE_BIT, +							  true, +							  &min_value, +							  &max_value); +			size += sysfs_emit_at(buf, size, "VDDC_CURVE: %7dmv %10dmv\n", +					      min_value, max_value); +		} +		break; +  	default:  		break;  	} @@ -1156,6 +1350,222 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu,  	return size;  } +static int smu_v13_0_0_od_edit_dpm_table(struct smu_context *smu, +					 enum PP_OD_DPM_TABLE_COMMAND type, +					 long input[], +					 uint32_t size) +{ +	struct smu_table_context *table_context = &smu->smu_table; +	OverDriveTableExternal_t *od_table = +		(OverDriveTableExternal_t *)table_context->overdrive_table; +	struct amdgpu_device *adev = smu->adev; +	uint32_t offset_of_featurectrlmask; +	int32_t minimum, maximum; +	uint32_t feature_ctrlmask; +	int i, ret = 0; + +	switch (type) { +	case PP_OD_EDIT_SCLK_VDDC_TABLE: +		if (!smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT)) { +			dev_warn(adev->dev, "GFXCLK_LIMITS setting not supported!\n"); +			return -ENOTSUPP; +		} + +		for (i = 0; i < size; i += 2) { +			if (i + 2 > size) { +				dev_info(adev->dev, "invalid number of input parameters %d\n", size); +				return -EINVAL; +			} + +			switch (input[i]) { +			case 0: +				smu_v13_0_0_get_od_setting_limits(smu, +								  PP_OD_FEATURE_GFXCLK_BIT, +								  true, +								  &minimum, +								  &maximum); +				if (input[i + 1] < minimum || +				    input[i + 1] > maximum) { +					dev_info(adev->dev, "GfxclkFmin (%ld) must be within [%u, %u]!\n", +						input[i + 1], minimum, maximum); +					return -EINVAL; +				} + +				od_table->OverDriveTable.GfxclkFmin = input[i + 1]; +				od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_GFXCLK_BIT; +				break; + +			case 1: +				smu_v13_0_0_get_od_setting_limits(smu, +								  PP_OD_FEATURE_GFXCLK_BIT, +								  false, +								  &minimum, +								  &maximum); +				if (input[i + 1] < minimum || +				    input[i + 1] > maximum) { +					dev_info(adev->dev, "GfxclkFmax (%ld) must be within [%u, %u]!\n", +						input[i + 1], minimum, maximum); +					return -EINVAL; +				} + +				od_table->OverDriveTable.GfxclkFmax = input[i + 1]; +				od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_GFXCLK_BIT; +				break; + +			default: +				dev_info(adev->dev, "Invalid SCLK_VDDC_TABLE index: %ld\n", input[i]); +				dev_info(adev->dev, "Supported indices: [0:min,1:max]\n"); +				return -EINVAL; +			} +		} + +		if (od_table->OverDriveTable.GfxclkFmin > od_table->OverDriveTable.GfxclkFmax) { +			dev_err(adev->dev, +				"Invalid setting: GfxclkFmin(%u) is bigger than GfxclkFmax(%u)\n", +				(uint32_t)od_table->OverDriveTable.GfxclkFmin, +				(uint32_t)od_table->OverDriveTable.GfxclkFmax); +			return -EINVAL; +		} +		break; + +	case PP_OD_EDIT_MCLK_VDDC_TABLE: +		if (!smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_UCLK_BIT)) { +			dev_warn(adev->dev, "UCLK_LIMITS setting not supported!\n"); +			return -ENOTSUPP; +		} + +		for (i = 0; i < size; i += 2) { +			if (i + 2 > size) { +				dev_info(adev->dev, "invalid number of input parameters %d\n", size); +				return -EINVAL; +			} + +			switch (input[i]) { +			case 0: +				smu_v13_0_0_get_od_setting_limits(smu, +								  PP_OD_FEATURE_UCLK_BIT, +								  true, +								  &minimum, +								  &maximum); +				if (input[i + 1] < minimum || +				    input[i + 1] > maximum) { +					dev_info(adev->dev, "UclkFmin (%ld) must be within [%u, %u]!\n", +						input[i + 1], minimum, maximum); +					return -EINVAL; +				} + +				od_table->OverDriveTable.UclkFmin = input[i + 1]; +				od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_UCLK_BIT; +				break; + +			case 1: +				smu_v13_0_0_get_od_setting_limits(smu, +								  PP_OD_FEATURE_UCLK_BIT, +								  false, +								  &minimum, +								  &maximum); +				if (input[i + 1] < minimum || +				    input[i + 1] > maximum) { +					dev_info(adev->dev, "UclkFmax (%ld) must be within [%u, %u]!\n", +						input[i + 1], minimum, maximum); +					return -EINVAL; +				} + +				od_table->OverDriveTable.UclkFmax = input[i + 1]; +				od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_UCLK_BIT; +				break; + +			default: +				dev_info(adev->dev, "Invalid MCLK_VDDC_TABLE index: %ld\n", input[i]); +				dev_info(adev->dev, "Supported indices: [0:min,1:max]\n"); +				return -EINVAL; +			} +		} + +		if (od_table->OverDriveTable.UclkFmin > od_table->OverDriveTable.UclkFmax) { +			dev_err(adev->dev, +				"Invalid setting: UclkFmin(%u) is bigger than UclkFmax(%u)\n", +				(uint32_t)od_table->OverDriveTable.UclkFmin, +				(uint32_t)od_table->OverDriveTable.UclkFmax); +			return -EINVAL; +		} +		break; + +	case PP_OD_EDIT_VDDC_CURVE: +		if (!smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_GFX_VF_CURVE_BIT)) { +			dev_warn(adev->dev, "VF curve setting not supported!\n"); +			return -ENOTSUPP; +		} + +		if (input[0] >= PP_NUM_OD_VF_CURVE_POINTS || +		    input[0] < 0) +			return -EINVAL; + +		smu_v13_0_0_get_od_setting_limits(smu, +						  PP_OD_FEATURE_GFX_VF_CURVE_BIT, +						  true, +						  &minimum, +						  &maximum); +		if (input[1] < minimum || +		    input[1] > maximum) { +			dev_info(adev->dev, "Voltage offset (%ld) must be within [%d, %d]!\n", +				 input[1], minimum, maximum); +			return -EINVAL; +		} + +		od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[input[0]] = input[1]; +		od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_GFX_VF_CURVE_BIT; +		break; + +	case PP_OD_RESTORE_DEFAULT_TABLE: +		feature_ctrlmask = od_table->OverDriveTable.FeatureCtrlMask; +		memcpy(od_table, +		       table_context->boot_overdrive_table, +		       sizeof(OverDriveTableExternal_t)); +		od_table->OverDriveTable.FeatureCtrlMask = feature_ctrlmask; +		fallthrough; + +	case PP_OD_COMMIT_DPM_TABLE: +		/* +		 * The member below instructs PMFW the settings focused in +		 * this single operation. +		 * `uint32_t FeatureCtrlMask;` +		 * It does not contain actual informations about user's custom +		 * settings. Thus we do not cache it. +		 */ +		offset_of_featurectrlmask = offsetof(OverDriveTable_t, FeatureCtrlMask); +		if (memcmp((u8 *)od_table + offset_of_featurectrlmask, +			   table_context->user_overdrive_table + offset_of_featurectrlmask, +			   sizeof(OverDriveTableExternal_t) - offset_of_featurectrlmask)) { +			smu_v13_0_0_dump_od_table(smu, od_table); + +			ret = smu_v13_0_0_upload_overdrive_table(smu, od_table); +			if (ret) { +				dev_err(adev->dev, "Failed to upload overdrive table!\n"); +				return ret; +			} + +			od_table->OverDriveTable.FeatureCtrlMask = 0; +			memcpy(table_context->user_overdrive_table + offset_of_featurectrlmask, +			       (u8 *)od_table + offset_of_featurectrlmask, +			       sizeof(OverDriveTableExternal_t) - offset_of_featurectrlmask); + +			if (!memcmp(table_context->user_overdrive_table, +				    table_context->boot_overdrive_table, +				    sizeof(OverDriveTableExternal_t))) +				smu->user_dpm_profile.user_od = false; +			else +				smu->user_dpm_profile.user_od = true; +		} +		break; + +	default: +		return -ENOSYS; +	} + +	return ret; +} +  static int smu_v13_0_0_force_clk_levels(struct smu_context *smu,  					enum smu_clk_type clk_type,  					uint32_t mask) @@ -1384,6 +1794,78 @@ static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu,  	return sizeof(struct gpu_metrics_v1_3);  } +static int smu_v13_0_0_set_default_od_settings(struct smu_context *smu) +{ +	OverDriveTableExternal_t *od_table = +		(OverDriveTableExternal_t *)smu->smu_table.overdrive_table; +	OverDriveTableExternal_t *boot_od_table = +		(OverDriveTableExternal_t *)smu->smu_table.boot_overdrive_table; +	OverDriveTableExternal_t *user_od_table = +		(OverDriveTableExternal_t *)smu->smu_table.user_overdrive_table; +	OverDriveTableExternal_t user_od_table_bak; +	int ret = 0; +	int i; + +	ret = smu_v13_0_0_get_overdrive_table(smu, boot_od_table); +	if (ret) +		return ret; + +	smu_v13_0_0_dump_od_table(smu, boot_od_table); + +	memcpy(od_table, +	       boot_od_table, +	       sizeof(OverDriveTableExternal_t)); + +	/* +	 * For S3/S4/Runpm resume, we need to setup those overdrive tables again, +	 * but we have to preserve user defined values in "user_od_table". +	 */ +	if (!smu->adev->in_suspend) { +		memcpy(user_od_table, +		       boot_od_table, +		       sizeof(OverDriveTableExternal_t)); +		smu->user_dpm_profile.user_od = false; +	} else if (smu->user_dpm_profile.user_od) { +		memcpy(&user_od_table_bak, +		       user_od_table, +		       sizeof(OverDriveTableExternal_t)); +		memcpy(user_od_table, +		       boot_od_table, +		       sizeof(OverDriveTableExternal_t)); +		user_od_table->OverDriveTable.GfxclkFmin = +				user_od_table_bak.OverDriveTable.GfxclkFmin; +		user_od_table->OverDriveTable.GfxclkFmax = +				user_od_table_bak.OverDriveTable.GfxclkFmax; +		user_od_table->OverDriveTable.UclkFmin = +				user_od_table_bak.OverDriveTable.UclkFmin; +		user_od_table->OverDriveTable.UclkFmax = +				user_od_table_bak.OverDriveTable.UclkFmax; +		for (i = 0; i < PP_NUM_OD_VF_CURVE_POINTS; i++) +			user_od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[i] = +				user_od_table_bak.OverDriveTable.VoltageOffsetPerZoneBoundary[i]; +	} + +	return 0; +} + +static int smu_v13_0_0_restore_user_od_settings(struct smu_context *smu) +{ +	struct smu_table_context *table_context = &smu->smu_table; +	OverDriveTableExternal_t *od_table = table_context->overdrive_table; +	OverDriveTableExternal_t *user_od_table = table_context->user_overdrive_table; +	int res; + +	user_od_table->OverDriveTable.FeatureCtrlMask = 1U << PP_OD_FEATURE_GFXCLK_BIT | +							1U << PP_OD_FEATURE_UCLK_BIT | +							1U << PP_OD_FEATURE_GFX_VF_CURVE_BIT; +	res = smu_v13_0_0_upload_overdrive_table(smu, user_od_table); +	user_od_table->OverDriveTable.FeatureCtrlMask = 0; +	if (res == 0) +		memcpy(od_table, user_od_table, sizeof(OverDriveTableExternal_t)); + +	return res; +} +  static int smu_v13_0_0_populate_umd_state_clk(struct smu_context *smu)  {  	struct smu_13_0_dpm_context *dpm_context = @@ -2126,7 +2608,7 @@ static ssize_t smu_v13_0_0_get_ecc_info(struct smu_context *smu,  	ecc_table = (EccInfoTable_t *)smu_table->ecc_table; -	for (i = 0; i < UMC_V8_10_TOTAL_CHANNEL_NUM(adev); i++) { +	for (i = 0; i < ARRAY_SIZE(ecc_table->EccInfo); i++) {  		ecc_info_per_channel = &(eccinfo->ecc[i]);  		ecc_info_per_channel->ce_count_lo_chip =  				ecc_table->EccInfo[i].ce_count_lo_chip; @@ -2179,6 +2661,9 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {  	.notify_memory_pool_location = smu_v13_0_notify_memory_pool_location,  	.get_gpu_metrics = smu_v13_0_0_get_gpu_metrics,  	.set_soft_freq_limited_range = smu_v13_0_set_soft_freq_limited_range, +	.set_default_od_settings = smu_v13_0_0_set_default_od_settings, +	.restore_user_od_settings = smu_v13_0_0_restore_user_od_settings, +	.od_edit_dpm_table = smu_v13_0_0_od_edit_dpm_table,  	.init_pptable_microcode = smu_v13_0_init_pptable_microcode,  	.populate_umd_state_clk = smu_v13_0_0_populate_umd_state_clk,  	.set_performance_level = smu_v13_0_set_performance_level, @@ -2228,5 +2713,6 @@ void smu_v13_0_0_set_ppt_funcs(struct smu_context *smu)  	smu->table_map = smu_v13_0_0_table_map;  	smu->pwr_src_map = smu_v13_0_0_pwr_src_map;  	smu->workload_map = smu_v13_0_0_workload_map; +	smu->smc_driver_if_version = SMU13_0_0_DRIVER_IF_VERSION;  	smu_v13_0_0_set_smu_mailbox_registers(smu);  } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c index 6d9760eac16d..ef37dda9908f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c @@ -54,6 +54,10 @@  #define FEATURE_MASK(feature) (1ULL << feature) +#define SMU_13_0_4_UMD_PSTATE_GFXCLK			938 +#define SMU_13_0_4_UMD_PSTATE_SOCCLK			938 +#define SMU_13_0_4_UMD_PSTATE_FCLK			1875 +  #define SMC_DPM_FEATURE ( \  	FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \  	FEATURE_MASK(FEATURE_VCN_DPM_BIT)	 | \ @@ -831,6 +835,8 @@ static int smu_v13_0_4_set_soft_freq_limited_range(struct smu_context *smu,  						   uint32_t max)  {  	enum smu_message_type msg_set_min, msg_set_max; +	uint32_t min_clk = min; +	uint32_t max_clk = max;  	int ret = 0;  	if (!smu_v13_0_4_clk_dpm_is_enabled(smu, clk_type)) @@ -859,12 +865,17 @@ static int smu_v13_0_4_set_soft_freq_limited_range(struct smu_context *smu,  		return -EINVAL;  	} -	ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_min, min, NULL); +	if (clk_type == SMU_VCLK) { +		min_clk = min << SMU_13_VCLK_SHIFT; +		max_clk = max << SMU_13_VCLK_SHIFT; +	} + +	ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_min, min_clk, NULL);  	if (ret)  		return ret;  	return smu_cmn_send_smc_msg_with_param(smu, msg_set_max, -					       max, NULL); +					       max_clk, NULL);  }  static int smu_v13_0_4_force_clk_levels(struct smu_context *smu, @@ -901,6 +912,50 @@ static int smu_v13_0_4_force_clk_levels(struct smu_context *smu,  	return ret;  } +static int smu_v13_0_4_get_dpm_profile_freq(struct smu_context *smu, +					enum amd_dpm_forced_level level, +					enum smu_clk_type clk_type, +					uint32_t *min_clk, +					uint32_t *max_clk) +{ +	int ret = 0; +	uint32_t clk_limit = 0; + +	switch (clk_type) { +	case SMU_GFXCLK: +	case SMU_SCLK: +		clk_limit = SMU_13_0_4_UMD_PSTATE_GFXCLK; +		if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) +			smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &clk_limit); +		else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) +			smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_SCLK, &clk_limit, NULL); +		break; +	case SMU_SOCCLK: +		clk_limit = SMU_13_0_4_UMD_PSTATE_SOCCLK; +		if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) +			smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_SOCCLK, NULL, &clk_limit); +		break; +	case SMU_FCLK: +		clk_limit = SMU_13_0_4_UMD_PSTATE_FCLK; +		if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) +			smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &clk_limit); +		else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) +			smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_FCLK, &clk_limit, NULL); +		break; +	case SMU_VCLK: +		smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_VCLK, NULL, &clk_limit); +		break; +	case SMU_DCLK: +		smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_DCLK, NULL, &clk_limit); +		break; +	default: +		ret = -EINVAL; +		break; +	} +	*min_clk = *max_clk = clk_limit; +	return ret; +} +  static int smu_v13_0_4_set_performance_level(struct smu_context *smu,  					     enum amd_dpm_forced_level level)  { @@ -908,6 +963,8 @@ static int smu_v13_0_4_set_performance_level(struct smu_context *smu,  	uint32_t sclk_min = 0, sclk_max = 0;  	uint32_t fclk_min = 0, fclk_max = 0;  	uint32_t socclk_min = 0, socclk_max = 0; +	uint32_t vclk_min = 0, vclk_max = 0; +	uint32_t dclk_min = 0, dclk_max = 0;  	int ret = 0;  	switch (level) { @@ -915,28 +972,42 @@ static int smu_v13_0_4_set_performance_level(struct smu_context *smu,  		smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &sclk_max);  		smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &fclk_max);  		smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_SOCCLK, NULL, &socclk_max); +		smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_VCLK, NULL, &vclk_max); +		smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_DCLK, NULL, &dclk_max);  		sclk_min = sclk_max;  		fclk_min = fclk_max;  		socclk_min = socclk_max; +		vclk_min = vclk_max; +		dclk_min = dclk_max;  		break;  	case AMD_DPM_FORCED_LEVEL_LOW:  		smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, NULL);  		smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_FCLK, &fclk_min, NULL);  		smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_SOCCLK, &socclk_min, NULL); +		smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_VCLK, &vclk_min, NULL); +		smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_DCLK, &dclk_min, NULL);  		sclk_max = sclk_min;  		fclk_max = fclk_min;  		socclk_max = socclk_min; +		vclk_max = vclk_min; +		dclk_max = dclk_min;  		break;  	case AMD_DPM_FORCED_LEVEL_AUTO:  		smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, &sclk_max);  		smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_FCLK, &fclk_min, &fclk_max);  		smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_SOCCLK, &socclk_min, &socclk_max); +		smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_VCLK, &vclk_min, &vclk_max); +		smu_v13_0_4_get_dpm_ultimate_freq(smu, SMU_DCLK, &dclk_min, &dclk_max);  		break;  	case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:  	case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:  	case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:  	case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: -		/* Temporarily do nothing since the optimal clocks haven't been provided yet */ +		smu_v13_0_4_get_dpm_profile_freq(smu, level, SMU_SCLK, &sclk_min, &sclk_max); +		smu_v13_0_4_get_dpm_profile_freq(smu, level, SMU_FCLK, &fclk_min, &fclk_max); +		smu_v13_0_4_get_dpm_profile_freq(smu, level, SMU_SOCCLK, &socclk_min, &socclk_max); +		smu_v13_0_4_get_dpm_profile_freq(smu, level, SMU_VCLK, &vclk_min, &vclk_max); +		smu_v13_0_4_get_dpm_profile_freq(smu, level, SMU_DCLK, &dclk_min, &dclk_max);  		break;  	case AMD_DPM_FORCED_LEVEL_MANUAL:  	case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: @@ -976,6 +1047,23 @@ static int smu_v13_0_4_set_performance_level(struct smu_context *smu,  			return ret;  	} +	if (vclk_min && vclk_max) { +		ret = smu_v13_0_4_set_soft_freq_limited_range(smu, +							      SMU_VCLK, +							      vclk_min, +							      vclk_max); +		if (ret) +			return ret; +	} + +	if (dclk_min && dclk_max) { +		ret = smu_v13_0_4_set_soft_freq_limited_range(smu, +							      SMU_DCLK, +							      dclk_min, +							      dclk_max); +		if (ret) +			return ret; +	}  	return ret;  } @@ -1044,6 +1132,7 @@ void smu_v13_0_4_set_ppt_funcs(struct smu_context *smu)  	smu->message_map = smu_v13_0_4_message_map;  	smu->feature_map = smu_v13_0_4_feature_mask_map;  	smu->table_map = smu_v13_0_4_table_map; +	smu->smc_driver_if_version = SMU13_0_4_DRIVER_IF_VERSION;  	smu->is_apu = true;  	if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 4)) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c index 0081fa607e02..42f110602eb1 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c @@ -831,6 +831,8 @@ static int smu_v13_0_5_set_soft_freq_limited_range(struct smu_context *smu,  							uint32_t max)  {  	enum smu_message_type msg_set_min, msg_set_max; +	uint32_t min_clk = min; +	uint32_t max_clk = max;  	int ret = 0;  	if (!smu_v13_0_5_clk_dpm_is_enabled(smu, clk_type)) @@ -851,11 +853,16 @@ static int smu_v13_0_5_set_soft_freq_limited_range(struct smu_context *smu,  		return -EINVAL;  	} -	ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_min, min, NULL); +	if (clk_type == SMU_VCLK) { +		min_clk = min << SMU_13_VCLK_SHIFT; +		max_clk = max << SMU_13_VCLK_SHIFT; +	} + +	ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_min, min_clk, NULL);  	if (ret)  		goto out; -	ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_max, max, NULL); +	ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_max, max_clk, NULL);  	if (ret)  		goto out; @@ -971,31 +978,79 @@ force_level_out:  	return ret;  } +static int smu_v13_0_5_get_dpm_profile_freq(struct smu_context *smu, +					enum amd_dpm_forced_level level, +					enum smu_clk_type clk_type, +					uint32_t *min_clk, +					uint32_t *max_clk) +{ +	int ret = 0; +	uint32_t clk_limit = 0; + +	switch (clk_type) { +	case SMU_GFXCLK: +	case SMU_SCLK: +		clk_limit = SMU_13_0_5_UMD_PSTATE_GFXCLK; +		if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) +			smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &clk_limit); +		else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) +			smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_SCLK, &clk_limit, NULL); +		break; +	case SMU_VCLK: +		smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_VCLK, NULL, &clk_limit); +		break; +	case SMU_DCLK: +		smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_DCLK, NULL, &clk_limit); +		break; +	default: +		ret = -EINVAL; +		break; +	} +	*min_clk = *max_clk = clk_limit; +	return ret; +} +  static int smu_v13_0_5_set_performance_level(struct smu_context *smu,  						enum amd_dpm_forced_level level)  {  	struct amdgpu_device *adev = smu->adev;  	uint32_t sclk_min = 0, sclk_max = 0; +	uint32_t vclk_min = 0, vclk_max = 0; +	uint32_t dclk_min = 0, dclk_max = 0;  	int ret = 0;  	switch (level) {  	case AMD_DPM_FORCED_LEVEL_HIGH:  		smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &sclk_max); +		smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_VCLK, NULL, &vclk_max); +		smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_DCLK, NULL, &dclk_max);  		sclk_min = sclk_max; +		vclk_min = vclk_max; +		dclk_min = dclk_max;  		break;  	case AMD_DPM_FORCED_LEVEL_LOW:  		smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, NULL); +		smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_VCLK, &vclk_min, NULL); +		smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_DCLK, &dclk_min, NULL);  		sclk_max = sclk_min; +		vclk_max = vclk_min; +		dclk_max = dclk_min;  		break;  	case AMD_DPM_FORCED_LEVEL_AUTO:  		smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, &sclk_max); +		smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_VCLK, &vclk_min, &vclk_max); +		smu_v13_0_5_get_dpm_ultimate_freq(smu, SMU_DCLK, &dclk_min, &dclk_max);  		break;  	case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:  	case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: -	case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:  	case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: -		/* Temporarily do nothing since the optimal clocks haven't been provided yet */ +		smu_v13_0_5_get_dpm_profile_freq(smu, level, SMU_SCLK, &sclk_min, &sclk_max); +		smu_v13_0_5_get_dpm_profile_freq(smu, level, SMU_VCLK, &vclk_min, &vclk_max); +		smu_v13_0_5_get_dpm_profile_freq(smu, level, SMU_DCLK, &dclk_min, &dclk_max);  		break; +	case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: +		dev_err(adev->dev, "The performance level profile_min_mclk is not supported."); +		return -EOPNOTSUPP;  	case AMD_DPM_FORCED_LEVEL_MANUAL:  	case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:  		return 0; @@ -1016,6 +1071,23 @@ static int smu_v13_0_5_set_performance_level(struct smu_context *smu,  		smu->gfx_actual_soft_max_freq = sclk_max;  	} +	if (vclk_min && vclk_max) { +		ret = smu_v13_0_5_set_soft_freq_limited_range(smu, +							      SMU_VCLK, +							      vclk_min, +							      vclk_max); +		if (ret) +			return ret; +	} + +	if (dclk_min && dclk_max) { +		ret = smu_v13_0_5_set_soft_freq_limited_range(smu, +							      SMU_DCLK, +							      dclk_min, +							      dclk_max); +		if (ret) +			return ret; +	}  	return ret;  } @@ -1069,6 +1141,7 @@ void smu_v13_0_5_set_ppt_funcs(struct smu_context *smu)  	smu->feature_map = smu_v13_0_5_feature_mask_map;  	smu->table_map = smu_v13_0_5_table_map;  	smu->is_apu = true; +	smu->smc_driver_if_version = SMU13_0_5_DRIVER_IF_VERSION;  	smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_34);  	smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_2);  	smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_33); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.h index 40bc0f8e6d61..263cd651855e 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.h @@ -24,6 +24,6 @@  #define __SMU_V13_0_5_PPT_H__  extern void smu_v13_0_5_set_ppt_funcs(struct smu_context *smu); -#define SMU_13_0_5_UMD_PSTATE_GFXCLK   1100 +#define SMU_13_0_5_UMD_PSTATE_GFXCLK   700  #endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index ea8f3d6fb98b..a92ea4601ea4 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -80,7 +80,10 @@  /* possible frequency drift (1Mhz) */  #define EPSILON 1 -#define smnPCIE_ESM_CTRL 0x111003D0 +#define smnPCIE_ESM_CTRL 0x193D0 +#define smnPCIE_LC_LINK_WIDTH_CNTL 0x1ab40288 +#define PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK 0x00000070L +#define PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT 0x4  static const struct cmn2asic_msg_mapping smu_v13_0_6_message_map[SMU_MSG_MAX_COUNT] = {  	MSG_MAP(TestMessage,			     PPSMC_MSG_TestMessage,			0), @@ -122,6 +125,7 @@ static const struct cmn2asic_msg_mapping smu_v13_0_6_message_map[SMU_MSG_MAX_COU  	MSG_MAP(GetMaxGfxclkFrequency,               PPSMC_MSG_GetMaxGfxDpmFreq,                0),  	MSG_MAP(SetSoftMinGfxclk,                    PPSMC_MSG_SetSoftMinGfxClk,                0),  	MSG_MAP(SetSoftMaxGfxClk,                    PPSMC_MSG_SetSoftMaxGfxClk,                0), +	MSG_MAP(PrepareMp1ForUnload,                 PPSMC_MSG_PrepareForDriverUnload,          0),  };  static const struct cmn2asic_mapping smu_v13_0_6_clk_map[SMU_CLK_COUNT] = { @@ -171,18 +175,12 @@ static const struct cmn2asic_mapping smu_v13_0_6_table_map[SMU_TABLE_COUNT] = {  	TAB_MAP(I2C_COMMANDS),  }; -#define THROTTLER_PROCHOT_GFX_BIT  0 -#define THROTTLER_PPT_BIT 1 -#define THROTTLER_TEMP_SOC_BIT 2 -#define THROTTLER_TEMP_VR_GFX_BIT 3 -#define THROTTLER_TEMP_HBM_BIT 4 -  static const uint8_t smu_v13_0_6_throttler_map[] = {  	[THROTTLER_PPT_BIT]		= (SMU_THROTTLER_PPT0_BIT), -	[THROTTLER_TEMP_SOC_BIT]	= (SMU_THROTTLER_TEMP_GPU_BIT), -	[THROTTLER_TEMP_HBM_BIT]	= (SMU_THROTTLER_TEMP_MEM_BIT), -	[THROTTLER_TEMP_VR_GFX_BIT]	= (SMU_THROTTLER_TEMP_VR_GFX_BIT), -	[THROTTLER_PROCHOT_GFX_BIT]	= (SMU_THROTTLER_PROCHOT_GFX_BIT), +	[THROTTLER_THERMAL_SOCKET_BIT]	= (SMU_THROTTLER_TEMP_GPU_BIT), +	[THROTTLER_THERMAL_HBM_BIT]	= (SMU_THROTTLER_TEMP_MEM_BIT), +	[THROTTLER_THERMAL_VR_BIT]	= (SMU_THROTTLER_TEMP_VR_GFX_BIT), +	[THROTTLER_PROCHOT_BIT]		= (SMU_THROTTLER_PROCHOT_GFX_BIT),  };  struct PPTable_t { @@ -197,10 +195,12 @@ struct PPTable_t {  	uint32_t LclkFrequencyTable[4];  	uint32_t MaxLclkDpmRange;  	uint32_t MinLclkDpmRange; +	uint64_t PublicSerialNumber_AID;  	bool Init;  };  #define SMUQ10_TO_UINT(x) ((x) >> 10) +#define SMUQ16_TO_UINT(x) ((x) >> 16)  struct smu_v13_0_6_dpm_map {  	enum smu_clk_type clk_type; @@ -220,10 +220,12 @@ static int smu_v13_0_6_tables_init(struct smu_context *smu)  			       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);  	SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(MetricsTable_t), -		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); +		       PAGE_SIZE, +		       AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT);  	SMU_TABLE_INIT(tables, SMU_TABLE_I2C_COMMANDS, sizeof(SwI2cRequest_t), -		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); +		       PAGE_SIZE, +		       AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT);  	smu_table->metrics_table = kzalloc(sizeof(MetricsTable_t), GFP_KERNEL);  	if (!smu_table->metrics_table) @@ -355,6 +357,9 @@ static int smu_v13_0_6_setup_driver_pptable(struct smu_context *smu)  				SMUQ10_TO_UINT(metrics->LclkFrequencyTable[i]);  		} +		/* use AID0 serial number by default */ +		pptable->PublicSerialNumber_AID = metrics->PublicSerialNumber_AID[0]; +  		pptable->Init = true;  	} @@ -385,7 +390,7 @@ static int smu_v13_0_6_get_dpm_ultimate_freq(struct smu_context *smu,  			break;  		case SMU_SOCCLK:  			if (pptable->Init) -				clock_limit = pptable->UclkFrequencyTable[0]; +				clock_limit = pptable->SocclkFrequencyTable[0];  			break;  		case SMU_FCLK:  			if (pptable->Init) @@ -638,16 +643,14 @@ static int smu_v13_0_6_freqs_in_same_level(int32_t frequency1,  	return (abs(frequency1 - frequency2) <= EPSILON);  } -static uint32_t smu_v13_0_6_get_throttler_status(struct smu_context *smu, -						 MetricsTable_t *metrics) +static uint32_t smu_v13_0_6_get_throttler_status(struct smu_context *smu)  { +	struct smu_power_context *smu_power = &smu->smu_power; +	struct smu_13_0_power_context *power_context = smu_power->power_context;  	uint32_t  throttler_status = 0; -	throttler_status |= metrics->ProchotResidencyAcc > 0 ? 1U << THROTTLER_PROCHOT_GFX_BIT : 0; -	throttler_status |= metrics->PptResidencyAcc > 0 ? 1U << THROTTLER_PPT_BIT : 0; -	throttler_status |= metrics->SocketThmResidencyAcc > 0 ?  1U << THROTTLER_TEMP_SOC_BIT : 0; -	throttler_status |= metrics->VrThmResidencyAcc > 0 ? 1U << THROTTLER_TEMP_VR_GFX_BIT : 0; -	throttler_status |= metrics->HbmThmResidencyAcc > 0 ? 1U << THROTTLER_TEMP_HBM_BIT : 0; +	throttler_status = atomic_read(&power_context->throttle_status); +	dev_dbg(smu->adev->dev, "SMU Throttler status: %u", throttler_status);  	return throttler_status;  } @@ -658,7 +661,10 @@ static int smu_v13_0_6_get_smu_metrics_data(struct smu_context *smu,  {  	struct smu_table_context *smu_table = &smu->smu_table;  	MetricsTable_t *metrics = (MetricsTable_t *)smu_table->metrics_table; +	struct amdgpu_device *adev = smu->adev; +	uint32_t smu_version;  	int ret = 0; +	int xcc_id;  	ret = smu_v13_0_6_get_metrics_table(smu, NULL, false);  	if (ret) @@ -668,7 +674,13 @@ static int smu_v13_0_6_get_smu_metrics_data(struct smu_context *smu,  	switch (member) {  	case METRICS_CURR_GFXCLK:  	case METRICS_AVERAGE_GFXCLK: -		*value = 0; +		smu_cmn_get_smc_version(smu, NULL, &smu_version); +		if (smu_version >= 0x552F00) { +			xcc_id = GET_INST(GC, 0); +			*value = SMUQ10_TO_UINT(metrics->GfxclkFrequency[xcc_id]); +		} else { +			*value = 0; +		}  		break;  	case METRICS_CURR_SOCCLK:  	case METRICS_AVERAGE_SOCCLK: @@ -708,9 +720,6 @@ static int smu_v13_0_6_get_smu_metrics_data(struct smu_context *smu,  	case METRICS_TEMPERATURE_VRSOC:  		*value = SMUQ10_TO_UINT(metrics->MaxVrTemperature);  		break; -	case METRICS_THROTTLER_STATUS: -		*value = smu_v13_0_6_get_throttler_status(smu, metrics); -		break;  	default:  		*value = UINT_MAX;  		break; @@ -1246,21 +1255,6 @@ static int smu_v13_0_6_get_power_limit(struct smu_context *smu,  	uint32_t power_limit = 0;  	int ret; -	if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) { -		if (current_power_limit) -			*current_power_limit = 0; -		if (default_power_limit) -			*default_power_limit = 0; -		if (max_power_limit) -			*max_power_limit = 0; - -		dev_warn( -			smu->adev->dev, -			"PPT feature is not enabled, power values can't be fetched."); - -		return 0; -	} -  	ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetPptLimit, &power_limit);  	if (ret) { @@ -1287,16 +1281,147 @@ static int smu_v13_0_6_set_power_limit(struct smu_context *smu,  	return smu_v13_0_set_power_limit(smu, limit_type, limit);  } -static int smu_v13_0_6_system_features_control(struct smu_context *smu, -					       bool enable) +static int smu_v13_0_6_irq_process(struct amdgpu_device *adev, +				   struct amdgpu_irq_src *source, +				   struct amdgpu_iv_entry *entry)  { -	int ret; +	struct smu_context *smu = adev->powerplay.pp_handle; +	struct smu_power_context *smu_power = &smu->smu_power; +	struct smu_13_0_power_context *power_context = smu_power->power_context; +	uint32_t client_id = entry->client_id; +	uint32_t ctxid = entry->src_data[0]; +	uint32_t src_id = entry->src_id; +	uint32_t data; + +	if (client_id == SOC15_IH_CLIENTID_MP1) { +		if (src_id == IH_INTERRUPT_ID_TO_DRIVER) { +			/* ACK SMUToHost interrupt */ +			data = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL); +			data = REG_SET_FIELD(data, MP1_SMN_IH_SW_INT_CTRL, INT_ACK, 1); +			WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL, data); +			/* +			 * ctxid is used to distinguish different events for SMCToHost +			 * interrupt. +			 */ +			switch (ctxid) { +			case IH_INTERRUPT_CONTEXT_ID_THERMAL_THROTTLING: +				/* +				 * Increment the throttle interrupt counter +				 */ +				atomic64_inc(&smu->throttle_int_counter); + +				if (!atomic_read(&adev->throttling_logging_enabled)) +					return 0; + +				/* This uses the new method which fixes the +				 * incorrect throttling status reporting +				 * through metrics table. For older FWs, +				 * it will be ignored. +				 */ +				if (__ratelimit(&adev->throttling_logging_rs)) { +					atomic_set( +						&power_context->throttle_status, +							entry->src_data[1]); +					schedule_work(&smu->throttling_logging_work); +				} + +				break; +			} +		} +	} + +	return 0; +} + +static int smu_v13_0_6_set_irq_state(struct amdgpu_device *adev, +			      struct amdgpu_irq_src *source, +			      unsigned tyep, +			      enum amdgpu_interrupt_state state) +{ +	uint32_t val = 0; + +	switch (state) { +	case AMDGPU_IRQ_STATE_DISABLE: +		/* For MP1 SW irqs */ +		val = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL); +		val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT_CTRL, INT_MASK, 1); +		WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL, val); -	/* Nothing to be done for APU */ -	if (smu->adev->flags & AMD_IS_APU) +		break; +	case AMDGPU_IRQ_STATE_ENABLE: +		/* For MP1 SW irqs */ +		val = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT); +		val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT, ID, 0xFE); +		val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT, VALID, 0); +		WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT, val); + +		val = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL); +		val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT_CTRL, INT_MASK, 0); +		WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL, val); + +		break; +	default: +		break; +	} + +	return 0; +} + +static const struct amdgpu_irq_src_funcs smu_v13_0_6_irq_funcs = +{ +	.set = smu_v13_0_6_set_irq_state, +	.process = smu_v13_0_6_irq_process, +}; + +static int smu_v13_0_6_register_irq_handler(struct smu_context *smu) +{ +	struct amdgpu_device *adev = smu->adev; +	struct amdgpu_irq_src *irq_src = &smu->irq_source; +	int ret = 0; + +	if (amdgpu_sriov_vf(adev))  		return 0; -	ret = smu_v13_0_system_features_control(smu, enable); +	irq_src->num_types = 1; +	irq_src->funcs = &smu_v13_0_6_irq_funcs; + +	ret = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_MP1, +				IH_INTERRUPT_ID_TO_DRIVER, +				irq_src); +	if (ret) +		return ret; + +	return ret; +} + +static int smu_v13_0_6_notify_unload(struct smu_context *smu) +{ +	uint32_t smu_version; + +	smu_cmn_get_smc_version(smu, NULL, &smu_version); +	if (smu_version <= 0x553500) +		return 0; + +	dev_dbg(smu->adev->dev, "Notify PMFW about driver unload"); +	/* Ignore return, just intimate FW that driver is not going to be there */ +	smu_cmn_send_smc_msg(smu, SMU_MSG_PrepareMp1ForUnload, NULL); + +	return 0; +} + +static int smu_v13_0_6_system_features_control(struct smu_context *smu, +					       bool enable) +{ +	struct amdgpu_device *adev = smu->adev; +	int ret = 0; + +	if (enable) { +		if (!(adev->flags & AMD_IS_APU)) +			ret = smu_v13_0_system_features_control(smu, enable); +	} else { +		/* Notify FW that the device is no longer driver managed */ +		smu_v13_0_6_notify_unload(smu); +	}  	return ret;  } @@ -1737,19 +1862,11 @@ static void smu_v13_0_6_i2c_control_fini(struct smu_context *smu)  static void smu_v13_0_6_get_unique_id(struct smu_context *smu)  {  	struct amdgpu_device *adev = smu->adev; -	//SmuMetrics_t *metrics = smu->smu_table.metrics_table; -	uint32_t upper32 = 0, lower32 = 0; -	int ret; - -	ret = smu_cmn_get_metrics_table(smu, NULL, false); -	if (ret) -		goto out; - -	//upper32 = metrics->PublicSerialNumUpper32; -	//lower32 = metrics->PublicSerialNumLower32; +	struct smu_table_context *smu_table = &smu->smu_table; +	struct PPTable_t *pptable = +		(struct PPTable_t *)smu_table->driver_pptable; -out: -	adev->unique_id = ((uint64_t)upper32 << 32) | lower32; +	adev->unique_id = pptable->PublicSerialNumber_AID;  	if (adev->serial[0] == '\0')  		sprintf(adev->serial, "%016llx", adev->unique_id);  } @@ -1774,37 +1891,35 @@ static int smu_v13_0_6_allow_xgmi_power_down(struct smu_context *smu, bool en)  					       en ? 0 : 1, NULL);  } -static const struct throttling_logging_label { -	uint32_t feature_mask; -	const char *label; -} logging_label[] = { -	{ (1U << THROTTLER_TEMP_HBM_BIT), "HBM" }, -	{ (1U << THROTTLER_TEMP_SOC_BIT), "SOC" }, -	{ (1U << THROTTLER_TEMP_VR_GFX_BIT), "VR limit" }, +static const char *const throttling_logging_label[] = { +	[THROTTLER_PROCHOT_BIT] = "Prochot", +	[THROTTLER_PPT_BIT] = "PPT", +	[THROTTLER_THERMAL_SOCKET_BIT] = "SOC", +	[THROTTLER_THERMAL_VR_BIT] = "VR", +	[THROTTLER_THERMAL_HBM_BIT] = "HBM"  }; +  static void smu_v13_0_6_log_thermal_throttling_event(struct smu_context *smu)  { -	int ret;  	int throttler_idx, throtting_events = 0, buf_idx = 0;  	struct amdgpu_device *adev = smu->adev;  	uint32_t throttler_status;  	char log_buf[256]; -	ret = smu_v13_0_6_get_smu_metrics_data(smu, METRICS_THROTTLER_STATUS, -					      &throttler_status); -	if (ret) +	throttler_status = smu_v13_0_6_get_throttler_status(smu); +	if (!throttler_status)  		return;  	memset(log_buf, 0, sizeof(log_buf)); -	for (throttler_idx = 0; throttler_idx < ARRAY_SIZE(logging_label); +	for (throttler_idx = 0; +	     throttler_idx < ARRAY_SIZE(throttling_logging_label);  	     throttler_idx++) { -		if (throttler_status & -		    logging_label[throttler_idx].feature_mask) { +		if (throttler_status & (1U << throttler_idx)) {  			throtting_events++; -			buf_idx += snprintf(log_buf + buf_idx, -					    sizeof(log_buf) - buf_idx, "%s%s", -					    throtting_events > 1 ? " and " : "", -					    logging_label[throttler_idx].label); +			buf_idx += snprintf( +				log_buf + buf_idx, sizeof(log_buf) - buf_idx, +				"%s%s", throtting_events > 1 ? " and " : "", +				throttling_logging_label[throttler_idx]);  			if (buf_idx >= sizeof(log_buf)) {  				dev_err(adev->dev, "buffer overflow!\n");  				log_buf[sizeof(log_buf) - 1] = '\0'; @@ -1813,16 +1928,24 @@ static void smu_v13_0_6_log_thermal_throttling_event(struct smu_context *smu)  		}  	} -	dev_warn( -		adev->dev, -		"WARN: GPU thermal throttling temperature reached, expect performance decrease. %s.\n", -		log_buf); +	dev_warn(adev->dev, +		 "WARN: GPU is throttled, expect performance decrease. %s.\n", +		 log_buf);  	kgd2kfd_smi_event_throttle(  		smu->adev->kfd.dev,  		smu_cmn_get_indep_throttler_status(throttler_status,  						   smu_v13_0_6_throttler_map));  } +static int +smu_v13_0_6_get_current_pcie_link_width_level(struct smu_context *smu) +{ +	struct amdgpu_device *adev = smu->adev; + +	return REG_GET_FIELD(RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL), +			     PCIE_LC_LINK_WIDTH_CNTL, LC_LINK_WIDTH_RD); +} +  static int smu_v13_0_6_get_current_pcie_link_speed(struct smu_context *smu)  {  	struct amdgpu_device *adev = smu->adev; @@ -1841,8 +1964,12 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table  	struct smu_table_context *smu_table = &smu->smu_table;  	struct gpu_metrics_v1_3 *gpu_metrics =  		(struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table; +	struct amdgpu_device *adev = smu->adev; +	int ret = 0, inst0, xcc0;  	MetricsTable_t *metrics; -	int i, ret = 0; + +	inst0 = adev->sdma.instance[0].aid_id; +	xcc0 = GET_INST(GC, 0);  	metrics = kzalloc(sizeof(MetricsTable_t), GFP_KERNEL);  	ret = smu_v13_0_6_get_metrics_table(smu, metrics, true); @@ -1851,51 +1978,59 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table  	smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 3); -	/* TODO: Decide on how to fill in zero value fields */ -	gpu_metrics->temperature_edge = 0; -	gpu_metrics->temperature_hotspot = 0; -	gpu_metrics->temperature_mem = 0; -	gpu_metrics->temperature_vrgfx = 0; -	gpu_metrics->temperature_vrsoc = 0; -	gpu_metrics->temperature_vrmem = 0; - -	gpu_metrics->average_gfx_activity = 0; -	gpu_metrics->average_umc_activity = 0; -	gpu_metrics->average_mm_activity = 0; - -	gpu_metrics->average_socket_power = 0; -	gpu_metrics->energy_accumulator = 0; - -	gpu_metrics->average_gfxclk_frequency = 0; -	gpu_metrics->average_socclk_frequency = 0; -	gpu_metrics->average_uclk_frequency = 0; -	gpu_metrics->average_vclk0_frequency = 0; -	gpu_metrics->average_dclk0_frequency = 0; - -	gpu_metrics->current_gfxclk = 0; -	gpu_metrics->current_socclk = 0; -	gpu_metrics->current_uclk = 0; -	gpu_metrics->current_vclk0 = 0; -	gpu_metrics->current_dclk0 = 0; - +	gpu_metrics->temperature_hotspot = +		SMUQ10_TO_UINT(metrics->MaxSocketTemperature); +	/* Individual HBM stack temperature is not reported */ +	gpu_metrics->temperature_mem = +		SMUQ10_TO_UINT(metrics->MaxHbmTemperature); +	/* Reports max temperature of all voltage rails */ +	gpu_metrics->temperature_vrsoc = +		SMUQ10_TO_UINT(metrics->MaxVrTemperature); + +	gpu_metrics->average_gfx_activity = +		SMUQ10_TO_UINT(metrics->SocketGfxBusy); +	gpu_metrics->average_umc_activity = +		SMUQ10_TO_UINT(metrics->DramBandwidthUtilization); + +	gpu_metrics->average_socket_power = +		SMUQ10_TO_UINT(metrics->SocketPower); +	gpu_metrics->energy_accumulator = +		SMUQ16_TO_UINT(metrics->SocketEnergyAcc); + +	gpu_metrics->current_gfxclk = +		SMUQ10_TO_UINT(metrics->GfxclkFrequency[xcc0]); +	gpu_metrics->current_socclk = +		SMUQ10_TO_UINT(metrics->SocclkFrequency[inst0]); +	gpu_metrics->current_uclk = SMUQ10_TO_UINT(metrics->UclkFrequency); +	gpu_metrics->current_vclk0 = +		SMUQ10_TO_UINT(metrics->VclkFrequency[inst0]); +	gpu_metrics->current_dclk0 = +		SMUQ10_TO_UINT(metrics->DclkFrequency[inst0]); + +	gpu_metrics->average_gfxclk_frequency = gpu_metrics->current_gfxclk; +	gpu_metrics->average_socclk_frequency = gpu_metrics->current_socclk; +	gpu_metrics->average_uclk_frequency = gpu_metrics->current_uclk; +	gpu_metrics->average_vclk0_frequency = gpu_metrics->current_vclk0; +	gpu_metrics->average_dclk0_frequency = gpu_metrics->current_dclk0; + +	/* Throttle status is not reported through metrics now */  	gpu_metrics->throttle_status = 0; -	gpu_metrics->indep_throttle_status = smu_cmn_get_indep_throttler_status( -		gpu_metrics->throttle_status, smu_v13_0_6_throttler_map); -	gpu_metrics->current_fan_speed = 0; - -	gpu_metrics->pcie_link_width = 0; -	gpu_metrics->pcie_link_speed = smu_v13_0_6_get_current_pcie_link_speed(smu); +	if (!(adev->flags & AMD_IS_APU)) { +		gpu_metrics->pcie_link_width = +			smu_v13_0_6_get_current_pcie_link_width_level(smu); +		gpu_metrics->pcie_link_speed = +			smu_v13_0_6_get_current_pcie_link_speed(smu); +	}  	gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); -	gpu_metrics->gfx_activity_acc = 0; -	gpu_metrics->mem_activity_acc = 0; +	gpu_metrics->gfx_activity_acc = +		SMUQ10_TO_UINT(metrics->SocketGfxBusyAcc); +	gpu_metrics->mem_activity_acc = +		SMUQ10_TO_UINT(metrics->DramBandwidthUtilizationAcc); -	for (i = 0; i < NUM_HBM_INSTANCES; i++) -		gpu_metrics->temperature_hbm[i] = 0; - -	gpu_metrics->firmware_timestamp = 0; +	gpu_metrics->firmware_timestamp = metrics->Timestamp;  	*table = (void *)gpu_metrics;  	kfree(metrics); @@ -1905,27 +2040,27 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table  static int smu_v13_0_6_mode2_reset(struct smu_context *smu)  { -	u32 smu_version;  	int ret = 0, index;  	struct amdgpu_device *adev = smu->adev;  	int timeout = 10; -	smu_cmn_get_smc_version(smu, NULL, &smu_version); -  	index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG,  					       SMU_MSG_GfxDeviceDriverReset);  	mutex_lock(&smu->message_lock); +  	ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index,  					       SMU_RESET_MODE_2); +  	/* This is similar to FLR, wait till max FLR timeout */  	msleep(100); +  	dev_dbg(smu->adev->dev, "restore config space...\n");  	/* Restore the config space saved during init */  	amdgpu_device_load_pci_state(adev->pdev);  	dev_dbg(smu->adev->dev, "wait for reset ack\n"); -	while (ret == -ETIME && timeout) { +	do {  		ret = smu_cmn_wait_for_response(smu);  		/* Wait a bit more time for getting ACK */  		if (ret == -ETIME) { @@ -1934,16 +2069,14 @@ static int smu_v13_0_6_mode2_reset(struct smu_context *smu)  			continue;  		} -		if (ret != 1) { +		if (ret) {  			dev_err(adev->dev, -				"failed to send mode2 message \tparam: 0x%08x response %#x\n", +				"failed to send mode2 message \tparam: 0x%08x error code %d\n",  				SMU_RESET_MODE_2, ret);  			goto out;  		} -	} +	} while (ret == -ETIME && timeout); -	if (ret == 1) -		ret = 0;  out:  	mutex_unlock(&smu->message_lock); @@ -2032,11 +2165,9 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = {  	.feature_is_enabled = smu_cmn_feature_is_enabled,  	.set_power_limit = smu_v13_0_6_set_power_limit,  	.set_xgmi_pstate = smu_v13_0_set_xgmi_pstate, -	/* TODO: Thermal limits unknown, skip these for now -	.register_irq_handler = smu_v13_0_register_irq_handler, +	.register_irq_handler = smu_v13_0_6_register_irq_handler,  	.enable_thermal_alert = smu_v13_0_enable_thermal_alert,  	.disable_thermal_alert = smu_v13_0_disable_thermal_alert, -	*/  	.setup_pptable = smu_v13_0_6_setup_pptable,  	.baco_is_support = smu_v13_0_6_is_baco_supported,  	.get_dpm_ultimate_freq = smu_v13_0_6_get_dpm_ultimate_freq, @@ -2065,5 +2196,6 @@ void smu_v13_0_6_set_ppt_funcs(struct smu_context *smu)  	smu->clock_map = smu_v13_0_6_clk_map;  	smu->feature_map = smu_v13_0_6_feature_mask_map;  	smu->table_map = smu_v13_0_6_table_map; +	smu->smc_driver_if_version = SMU13_0_6_DRIVER_IF_VERSION;  	smu_v13_0_set_smu_mailbox_registers(smu);  } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c index bba621615abf..cda4e818aab7 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c @@ -206,6 +206,7 @@ static struct cmn2asic_mapping smu_v13_0_7_table_map[SMU_TABLE_COUNT] = {  	TAB_MAP(DRIVER_SMU_CONFIG),  	TAB_MAP(ACTIVITY_MONITOR_COEFF),  	[SMU_TABLE_COMBO_PPTABLE] = {1, TABLE_COMBO_PPTABLE}, +	TAB_MAP(OVERDRIVE),  };  static struct cmn2asic_mapping smu_v13_0_7_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { @@ -322,6 +323,10 @@ static int smu_v13_0_7_check_powerplay_table(struct smu_context *smu)  	struct smu_baco_context *smu_baco = &smu->smu_baco;  	PPTable_t *smc_pptable = table_context->driver_pptable;  	BoardTable_t *BoardTable = &smc_pptable->BoardTable; +	const OverDriveLimits_t * const overdrive_upperlimits = +				&smc_pptable->SkuTable.OverDriveLimitsBasicMax; +	const OverDriveLimits_t * const overdrive_lowerlimits = +				&smc_pptable->SkuTable.OverDriveLimitsMin;  	if (powerplay_table->platform_caps & SMU_13_0_7_PP_PLATFORM_CAP_HARDWAREDC)  		smu->dc_controlled_by_gpio = true; @@ -333,6 +338,10 @@ static int smu_v13_0_7_check_powerplay_table(struct smu_context *smu)  	if (smu_baco->platform_support && (BoardTable->HsrEnabled || BoardTable->VddqOffEnabled))  		smu_baco->maco_support = true; +	if (!overdrive_lowerlimits->FeatureCtrlMask || +	    !overdrive_upperlimits->FeatureCtrlMask) +		smu->od_enabled = false; +  	table_context->thermal_controller_type =  		powerplay_table->thermal_controller_type; @@ -479,7 +488,7 @@ static int smu_v13_0_7_tables_init(struct smu_context *smu)  		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);  	SMU_TABLE_INIT(tables, SMU_TABLE_I2C_COMMANDS, sizeof(SwI2cRequest_t),  		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); -	SMU_TABLE_INIT(tables, SMU_TABLE_OVERDRIVE, sizeof(OverDriveTable_t), +	SMU_TABLE_INIT(tables, SMU_TABLE_OVERDRIVE, sizeof(OverDriveTableExternal_t),  		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);  	SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU13_TOOL_SIZE,  		       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); @@ -1013,16 +1022,118 @@ static int smu_v13_0_7_get_current_clk_freq_by_table(struct smu_context *smu,  						value);  } +static bool smu_v13_0_7_is_od_feature_supported(struct smu_context *smu, +						int od_feature_bit) +{ +	PPTable_t *pptable = smu->smu_table.driver_pptable; +	const OverDriveLimits_t * const overdrive_upperlimits = +				&pptable->SkuTable.OverDriveLimitsBasicMax; + +	return overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit); +} + +static void smu_v13_0_7_get_od_setting_limits(struct smu_context *smu, +					      int od_feature_bit, +					      bool lower_boundary, +					      int32_t *min, +					      int32_t *max) +{ +	PPTable_t *pptable = smu->smu_table.driver_pptable; +	const OverDriveLimits_t * const overdrive_upperlimits = +				&pptable->SkuTable.OverDriveLimitsBasicMax; +	const OverDriveLimits_t * const overdrive_lowerlimits = +				&pptable->SkuTable.OverDriveLimitsMin; +	int32_t od_min_setting, od_max_setting; + +	switch (od_feature_bit) { +	case PP_OD_FEATURE_GFXCLK_BIT: +		if (lower_boundary) { +			od_min_setting = overdrive_lowerlimits->GfxclkFmin; +			od_max_setting = overdrive_upperlimits->GfxclkFmin; +		} else { +			od_min_setting = overdrive_lowerlimits->GfxclkFmax; +			od_max_setting = overdrive_upperlimits->GfxclkFmax; +		} +		break; +	case PP_OD_FEATURE_UCLK_BIT: +		if (lower_boundary) { +			od_min_setting = overdrive_lowerlimits->UclkFmin; +			od_max_setting = overdrive_upperlimits->UclkFmin; +		} else { +			od_min_setting = overdrive_lowerlimits->UclkFmax; +			od_max_setting = overdrive_upperlimits->UclkFmax; +		} +		break; +	case PP_OD_FEATURE_GFX_VF_CURVE_BIT: +		od_min_setting = overdrive_lowerlimits->VoltageOffsetPerZoneBoundary; +		od_max_setting = overdrive_upperlimits->VoltageOffsetPerZoneBoundary; +		break; +	default: +		break; +	} + +	if (min) +		*min = od_min_setting; +	if (max) +		*max = od_max_setting; +} + +static void smu_v13_0_7_dump_od_table(struct smu_context *smu, +				      OverDriveTableExternal_t *od_table) +{ +	struct amdgpu_device *adev = smu->adev; + +	dev_dbg(adev->dev, "OD: Gfxclk: (%d, %d)\n", od_table->OverDriveTable.GfxclkFmin, +						     od_table->OverDriveTable.GfxclkFmax); +	dev_dbg(adev->dev, "OD: Uclk: (%d, %d)\n", od_table->OverDriveTable.UclkFmin, +						   od_table->OverDriveTable.UclkFmax); +} + +static int smu_v13_0_7_get_overdrive_table(struct smu_context *smu, +					   OverDriveTableExternal_t *od_table) +{ +	int ret = 0; + +	ret = smu_cmn_update_table(smu, +				   SMU_TABLE_OVERDRIVE, +				   0, +				   (void *)od_table, +				   false); +	if (ret) +		dev_err(smu->adev->dev, "Failed to get overdrive table!\n"); + +	return ret; +} + +static int smu_v13_0_7_upload_overdrive_table(struct smu_context *smu, +					      OverDriveTableExternal_t *od_table) +{ +	int ret = 0; + +	ret = smu_cmn_update_table(smu, +				   SMU_TABLE_OVERDRIVE, +				   0, +				   (void *)od_table, +				   true); +	if (ret) +		dev_err(smu->adev->dev, "Failed to upload overdrive table!\n"); + +	return ret; +} +  static int smu_v13_0_7_print_clk_levels(struct smu_context *smu,  					enum smu_clk_type clk_type,  					char *buf)  {  	struct smu_dpm_context *smu_dpm = &smu->smu_dpm;  	struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context; +	OverDriveTableExternal_t *od_table = +		(OverDriveTableExternal_t *)smu->smu_table.overdrive_table;  	struct smu_13_0_dpm_table *single_dpm_table;  	struct smu_13_0_pcie_table *pcie_table;  	uint32_t gen_speed, lane_width;  	int i, curr_freq, size = 0; +	int32_t min_value, max_value;  	int ret = 0;  	smu_cmn_get_sysfs_buf(&buf, &size); @@ -1139,6 +1250,89 @@ static int smu_v13_0_7_print_clk_levels(struct smu_context *smu,  					"*" : "");  		break; +	case SMU_OD_SCLK: +		if (!smu_v13_0_7_is_od_feature_supported(smu, +							 PP_OD_FEATURE_GFXCLK_BIT)) +			break; + +		size += sysfs_emit_at(buf, size, "OD_SCLK:\n"); +		size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n", +					od_table->OverDriveTable.GfxclkFmin, +					od_table->OverDriveTable.GfxclkFmax); +		break; + +	case SMU_OD_MCLK: +		if (!smu_v13_0_7_is_od_feature_supported(smu, +							 PP_OD_FEATURE_UCLK_BIT)) +			break; + +		size += sysfs_emit_at(buf, size, "OD_MCLK:\n"); +		size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMHz\n", +					od_table->OverDriveTable.UclkFmin, +					od_table->OverDriveTable.UclkFmax); +		break; + +	case SMU_OD_VDDC_CURVE: +		if (!smu_v13_0_7_is_od_feature_supported(smu, +							 PP_OD_FEATURE_GFX_VF_CURVE_BIT)) +			break; + +		size += sysfs_emit_at(buf, size, "OD_VDDC_CURVE:\n"); +		for (i = 0; i < PP_NUM_OD_VF_CURVE_POINTS; i++) +			size += sysfs_emit_at(buf, size, "%d: %dmv\n", +						i, +						od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[i]); +		break; + +	case SMU_OD_RANGE: +		if (!smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT) && +		    !smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_UCLK_BIT) && +		    !smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_GFX_VF_CURVE_BIT)) +			break; + +		size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); + +		if (smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT)) { +			smu_v13_0_7_get_od_setting_limits(smu, +							  PP_OD_FEATURE_GFXCLK_BIT, +							  true, +							  &min_value, +							  NULL); +			smu_v13_0_7_get_od_setting_limits(smu, +							  PP_OD_FEATURE_GFXCLK_BIT, +							  false, +							  NULL, +							  &max_value); +			size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n", +					      min_value, max_value); +		} + +		if (smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_UCLK_BIT)) { +			smu_v13_0_7_get_od_setting_limits(smu, +							  PP_OD_FEATURE_UCLK_BIT, +							  true, +							  &min_value, +							  NULL); +			smu_v13_0_7_get_od_setting_limits(smu, +							  PP_OD_FEATURE_UCLK_BIT, +							  false, +							  NULL, +							  &max_value); +			size += sysfs_emit_at(buf, size, "MCLK: %7uMhz %10uMhz\n", +					      min_value, max_value); +		} + +		if (smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_GFX_VF_CURVE_BIT)) { +			smu_v13_0_7_get_od_setting_limits(smu, +							  PP_OD_FEATURE_GFX_VF_CURVE_BIT, +							  true, +							  &min_value, +							  &max_value); +			size += sysfs_emit_at(buf, size, "VDDC_CURVE: %7dmv %10dmv\n", +					      min_value, max_value); +		} +		break; +  	default:  		break;  	} @@ -1146,6 +1340,222 @@ static int smu_v13_0_7_print_clk_levels(struct smu_context *smu,  	return size;  } +static int smu_v13_0_7_od_edit_dpm_table(struct smu_context *smu, +					 enum PP_OD_DPM_TABLE_COMMAND type, +					 long input[], +					 uint32_t size) +{ +	struct smu_table_context *table_context = &smu->smu_table; +	OverDriveTableExternal_t *od_table = +		(OverDriveTableExternal_t *)table_context->overdrive_table; +	struct amdgpu_device *adev = smu->adev; +	uint32_t offset_of_featurectrlmask; +	int32_t minimum, maximum; +	uint32_t feature_ctrlmask; +	int i, ret = 0; + +	switch (type) { +	case PP_OD_EDIT_SCLK_VDDC_TABLE: +		if (!smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT)) { +			dev_warn(adev->dev, "GFXCLK_LIMITS setting not supported!\n"); +			return -ENOTSUPP; +		} + +		for (i = 0; i < size; i += 2) { +			if (i + 2 > size) { +				dev_info(adev->dev, "invalid number of input parameters %d\n", size); +				return -EINVAL; +			} + +			switch (input[i]) { +			case 0: +				smu_v13_0_7_get_od_setting_limits(smu, +								  PP_OD_FEATURE_GFXCLK_BIT, +								  true, +								  &minimum, +								  &maximum); +				if (input[i + 1] < minimum || +				    input[i + 1] > maximum) { +					dev_info(adev->dev, "GfxclkFmin (%ld) must be within [%u, %u]!\n", +						input[i + 1], minimum, maximum); +					return -EINVAL; +				} + +				od_table->OverDriveTable.GfxclkFmin = input[i + 1]; +				od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_GFXCLK_BIT; +				break; + +			case 1: +				smu_v13_0_7_get_od_setting_limits(smu, +								  PP_OD_FEATURE_GFXCLK_BIT, +								  false, +								  &minimum, +								  &maximum); +				if (input[i + 1] < minimum || +				    input[i + 1] > maximum) { +					dev_info(adev->dev, "GfxclkFmax (%ld) must be within [%u, %u]!\n", +						input[i + 1], minimum, maximum); +					return -EINVAL; +				} + +				od_table->OverDriveTable.GfxclkFmax = input[i + 1]; +				od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_GFXCLK_BIT; +				break; + +			default: +				dev_info(adev->dev, "Invalid SCLK_VDDC_TABLE index: %ld\n", input[i]); +				dev_info(adev->dev, "Supported indices: [0:min,1:max]\n"); +				return -EINVAL; +			} +		} + +		if (od_table->OverDriveTable.GfxclkFmin > od_table->OverDriveTable.GfxclkFmax) { +			dev_err(adev->dev, +				"Invalid setting: GfxclkFmin(%u) is bigger than GfxclkFmax(%u)\n", +				(uint32_t)od_table->OverDriveTable.GfxclkFmin, +				(uint32_t)od_table->OverDriveTable.GfxclkFmax); +			return -EINVAL; +		} +		break; + +	case PP_OD_EDIT_MCLK_VDDC_TABLE: +		if (!smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_UCLK_BIT)) { +			dev_warn(adev->dev, "UCLK_LIMITS setting not supported!\n"); +			return -ENOTSUPP; +		} + +		for (i = 0; i < size; i += 2) { +			if (i + 2 > size) { +				dev_info(adev->dev, "invalid number of input parameters %d\n", size); +				return -EINVAL; +			} + +			switch (input[i]) { +			case 0: +				smu_v13_0_7_get_od_setting_limits(smu, +								  PP_OD_FEATURE_UCLK_BIT, +								  true, +								  &minimum, +								  &maximum); +				if (input[i + 1] < minimum || +				    input[i + 1] > maximum) { +					dev_info(adev->dev, "UclkFmin (%ld) must be within [%u, %u]!\n", +						input[i + 1], minimum, maximum); +					return -EINVAL; +				} + +				od_table->OverDriveTable.UclkFmin = input[i + 1]; +				od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_UCLK_BIT; +				break; + +			case 1: +				smu_v13_0_7_get_od_setting_limits(smu, +								  PP_OD_FEATURE_UCLK_BIT, +								  false, +								  &minimum, +								  &maximum); +				if (input[i + 1] < minimum || +				    input[i + 1] > maximum) { +					dev_info(adev->dev, "UclkFmax (%ld) must be within [%u, %u]!\n", +						input[i + 1], minimum, maximum); +					return -EINVAL; +				} + +				od_table->OverDriveTable.UclkFmax = input[i + 1]; +				od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_UCLK_BIT; +				break; + +			default: +				dev_info(adev->dev, "Invalid MCLK_VDDC_TABLE index: %ld\n", input[i]); +				dev_info(adev->dev, "Supported indices: [0:min,1:max]\n"); +				return -EINVAL; +			} +		} + +		if (od_table->OverDriveTable.UclkFmin > od_table->OverDriveTable.UclkFmax) { +			dev_err(adev->dev, +				"Invalid setting: UclkFmin(%u) is bigger than UclkFmax(%u)\n", +				(uint32_t)od_table->OverDriveTable.UclkFmin, +				(uint32_t)od_table->OverDriveTable.UclkFmax); +			return -EINVAL; +		} +		break; + +	case PP_OD_EDIT_VDDC_CURVE: +		if (!smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_GFX_VF_CURVE_BIT)) { +			dev_warn(adev->dev, "VF curve setting not supported!\n"); +			return -ENOTSUPP; +		} + +		if (input[0] >= PP_NUM_OD_VF_CURVE_POINTS || +		    input[0] < 0) +			return -EINVAL; + +		smu_v13_0_7_get_od_setting_limits(smu, +						  PP_OD_FEATURE_GFX_VF_CURVE_BIT, +						  true, +						  &minimum, +						  &maximum); +		if (input[1] < minimum || +		    input[1] > maximum) { +			dev_info(adev->dev, "Voltage offset (%ld) must be within [%d, %d]!\n", +				 input[1], minimum, maximum); +			return -EINVAL; +		} + +		od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[input[0]] = input[1]; +		od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_GFX_VF_CURVE_BIT; +		break; + +	case PP_OD_RESTORE_DEFAULT_TABLE: +		feature_ctrlmask = od_table->OverDriveTable.FeatureCtrlMask; +		memcpy(od_table, +		       table_context->boot_overdrive_table, +		       sizeof(OverDriveTableExternal_t)); +		od_table->OverDriveTable.FeatureCtrlMask = feature_ctrlmask; +		fallthrough; + +	case PP_OD_COMMIT_DPM_TABLE: +		/* +		 * The member below instructs PMFW the settings focused in +		 * this single operation. +		 * `uint32_t FeatureCtrlMask;` +		 * It does not contain actual informations about user's custom +		 * settings. Thus we do not cache it. +		 */ +		offset_of_featurectrlmask = offsetof(OverDriveTable_t, FeatureCtrlMask); +		if (memcmp((u8 *)od_table + offset_of_featurectrlmask, +			   table_context->user_overdrive_table + offset_of_featurectrlmask, +			   sizeof(OverDriveTableExternal_t) - offset_of_featurectrlmask)) { +			smu_v13_0_7_dump_od_table(smu, od_table); + +			ret = smu_v13_0_7_upload_overdrive_table(smu, od_table); +			if (ret) { +				dev_err(adev->dev, "Failed to upload overdrive table!\n"); +				return ret; +			} + +			od_table->OverDriveTable.FeatureCtrlMask = 0; +			memcpy(table_context->user_overdrive_table + offset_of_featurectrlmask, +			       (u8 *)od_table + offset_of_featurectrlmask, +			       sizeof(OverDriveTableExternal_t) - offset_of_featurectrlmask); + +			if (!memcmp(table_context->user_overdrive_table, +				    table_context->boot_overdrive_table, +				    sizeof(OverDriveTableExternal_t))) +				smu->user_dpm_profile.user_od = false; +			else +				smu->user_dpm_profile.user_od = true; +		} +		break; + +	default: +		return -ENOSYS; +	} + +	return ret; +} +  static int smu_v13_0_7_force_clk_levels(struct smu_context *smu,  					enum smu_clk_type clk_type,  					uint32_t mask) @@ -1371,6 +1781,78 @@ static ssize_t smu_v13_0_7_get_gpu_metrics(struct smu_context *smu,  	return sizeof(struct gpu_metrics_v1_3);  } +static int smu_v13_0_7_set_default_od_settings(struct smu_context *smu) +{ +	OverDriveTableExternal_t *od_table = +		(OverDriveTableExternal_t *)smu->smu_table.overdrive_table; +	OverDriveTableExternal_t *boot_od_table = +		(OverDriveTableExternal_t *)smu->smu_table.boot_overdrive_table; +	OverDriveTableExternal_t *user_od_table = +		(OverDriveTableExternal_t *)smu->smu_table.user_overdrive_table; +	OverDriveTableExternal_t user_od_table_bak; +	int ret = 0; +	int i; + +	ret = smu_v13_0_7_get_overdrive_table(smu, boot_od_table); +	if (ret) +		return ret; + +	smu_v13_0_7_dump_od_table(smu, boot_od_table); + +	memcpy(od_table, +	       boot_od_table, +	       sizeof(OverDriveTableExternal_t)); + +	/* +	 * For S3/S4/Runpm resume, we need to setup those overdrive tables again, +	 * but we have to preserve user defined values in "user_od_table". +	 */ +	if (!smu->adev->in_suspend) { +		memcpy(user_od_table, +		       boot_od_table, +		       sizeof(OverDriveTableExternal_t)); +		smu->user_dpm_profile.user_od = false; +	} else if (smu->user_dpm_profile.user_od) { +		memcpy(&user_od_table_bak, +		       user_od_table, +		       sizeof(OverDriveTableExternal_t)); +		memcpy(user_od_table, +		       boot_od_table, +		       sizeof(OverDriveTableExternal_t)); +		user_od_table->OverDriveTable.GfxclkFmin = +				user_od_table_bak.OverDriveTable.GfxclkFmin; +		user_od_table->OverDriveTable.GfxclkFmax = +				user_od_table_bak.OverDriveTable.GfxclkFmax; +		user_od_table->OverDriveTable.UclkFmin = +				user_od_table_bak.OverDriveTable.UclkFmin; +		user_od_table->OverDriveTable.UclkFmax = +				user_od_table_bak.OverDriveTable.UclkFmax; +		for (i = 0; i < PP_NUM_OD_VF_CURVE_POINTS; i++) +			user_od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[i] = +				user_od_table_bak.OverDriveTable.VoltageOffsetPerZoneBoundary[i]; +	} + +	return 0; +} + +static int smu_v13_0_7_restore_user_od_settings(struct smu_context *smu) +{ +	struct smu_table_context *table_context = &smu->smu_table; +	OverDriveTableExternal_t *od_table = table_context->overdrive_table; +	OverDriveTableExternal_t *user_od_table = table_context->user_overdrive_table; +	int res; + +	user_od_table->OverDriveTable.FeatureCtrlMask = 1U << PP_OD_FEATURE_GFXCLK_BIT | +							1U << PP_OD_FEATURE_UCLK_BIT | +							1U << PP_OD_FEATURE_GFX_VF_CURVE_BIT; +	res = smu_v13_0_7_upload_overdrive_table(smu, user_od_table); +	user_od_table->OverDriveTable.FeatureCtrlMask = 0; +	if (res == 0) +		memcpy(od_table, user_od_table, sizeof(OverDriveTableExternal_t)); + +	return res; +} +  static int smu_v13_0_7_populate_umd_state_clk(struct smu_context *smu)  {  	struct smu_13_0_dpm_context *dpm_context = @@ -1760,6 +2242,9 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = {  	.notify_memory_pool_location = smu_v13_0_notify_memory_pool_location,  	.get_gpu_metrics = smu_v13_0_7_get_gpu_metrics,  	.set_soft_freq_limited_range = smu_v13_0_set_soft_freq_limited_range, +	.set_default_od_settings = smu_v13_0_7_set_default_od_settings, +	.restore_user_od_settings = smu_v13_0_7_restore_user_od_settings, +	.od_edit_dpm_table = smu_v13_0_7_od_edit_dpm_table,  	.set_performance_level = smu_v13_0_set_performance_level,  	.gfx_off_control = smu_v13_0_gfx_off_control,  	.get_fan_speed_pwm = smu_v13_0_7_get_fan_speed_pwm, @@ -1798,5 +2283,6 @@ void smu_v13_0_7_set_ppt_funcs(struct smu_context *smu)  	smu->table_map = smu_v13_0_7_table_map;  	smu->pwr_src_map = smu_v13_0_7_pwr_src_map;  	smu->workload_map = smu_v13_0_7_workload_map; +	smu->smc_driver_if_version = SMU13_0_7_DRIVER_IF_VERSION;  	smu_v13_0_set_smu_mailbox_registers(smu);  } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c index 798f36cfcebd..a1be2029ba4a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c @@ -47,6 +47,14 @@  #define SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS_MASK		0x00000006L  #define SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS__SHIFT          0x1L +#define SMU_13_0_8_UMD_PSTATE_GFXCLK                   533 +#define SMU_13_0_8_UMD_PSTATE_SOCCLK                   533 +#define SMU_13_0_8_UMD_PSTATE_FCLK                     800 + +#define SMU_13_0_1_UMD_PSTATE_GFXCLK					700 +#define SMU_13_0_1_UMD_PSTATE_SOCCLK		              678 +#define SMU_13_0_1_UMD_PSTATE_FCLK			          1800 +  #define FEATURE_MASK(feature) (1ULL << feature)  #define SMC_DPM_FEATURE ( \  	FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \ @@ -957,6 +965,9 @@ static int yellow_carp_set_soft_freq_limited_range(struct smu_context *smu,  							uint32_t max)  {  	enum smu_message_type msg_set_min, msg_set_max; +	uint32_t min_clk = min; +	uint32_t max_clk = max; +  	int ret = 0;  	if (!yellow_carp_clk_dpm_is_enabled(smu, clk_type)) @@ -985,11 +996,17 @@ static int yellow_carp_set_soft_freq_limited_range(struct smu_context *smu,  		return -EINVAL;  	} -	ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_min, min, NULL); +	if (clk_type == SMU_VCLK) { +		min_clk = min << SMU_13_VCLK_SHIFT; +		max_clk = max << SMU_13_VCLK_SHIFT; +	} + +	ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_min, min_clk, NULL); +  	if (ret)  		goto out; -	ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_max, max, NULL); +	ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_max, max_clk, NULL);  	if (ret)  		goto out; @@ -997,12 +1014,49 @@ out:  	return ret;  } +static uint32_t yellow_carp_get_umd_pstate_clk_default(struct smu_context *smu, +					enum smu_clk_type clk_type) +{ +	uint32_t clk_limit = 0; +	struct amdgpu_device *adev = smu->adev; + +	switch (clk_type) { +	case SMU_GFXCLK: +	case SMU_SCLK: +		if ((adev->ip_versions[MP1_HWIP][0]) == IP_VERSION(13, 0, 8)) +			clk_limit = SMU_13_0_8_UMD_PSTATE_GFXCLK; +		if ((adev->ip_versions[MP1_HWIP][0]) == IP_VERSION(13, 0, 1) || +			(adev->ip_versions[MP1_HWIP][0]) == IP_VERSION(13, 0, 3)) +			clk_limit = SMU_13_0_1_UMD_PSTATE_GFXCLK; +		break; +	case SMU_SOCCLK: +		if ((adev->ip_versions[MP1_HWIP][0]) == IP_VERSION(13, 0, 8)) +			clk_limit = SMU_13_0_8_UMD_PSTATE_SOCCLK; +		if ((adev->ip_versions[MP1_HWIP][0]) == IP_VERSION(13, 0, 1) || +			(adev->ip_versions[MP1_HWIP][0]) == IP_VERSION(13, 0, 3)) +			clk_limit = SMU_13_0_1_UMD_PSTATE_SOCCLK; +		break; +	case SMU_FCLK: +		if ((adev->ip_versions[MP1_HWIP][0]) == IP_VERSION(13, 0, 8)) +			clk_limit = SMU_13_0_8_UMD_PSTATE_FCLK; +		if ((adev->ip_versions[MP1_HWIP][0]) == IP_VERSION(13, 0, 1) || +			(adev->ip_versions[MP1_HWIP][0]) == IP_VERSION(13, 0, 3)) +			clk_limit = SMU_13_0_1_UMD_PSTATE_FCLK; +		break; +	default: +		break; +	} + +	return clk_limit; +} +  static int yellow_carp_print_clk_levels(struct smu_context *smu,  				enum smu_clk_type clk_type, char *buf)  {  	int i, idx, size = 0, ret = 0;  	uint32_t cur_value = 0, value = 0, count = 0;  	uint32_t min, max; +	uint32_t clk_limit = 0;  	smu_cmn_get_sysfs_buf(&buf, &size); @@ -1044,6 +1098,7 @@ static int yellow_carp_print_clk_levels(struct smu_context *smu,  		break;  	case SMU_GFXCLK:  	case SMU_SCLK: +		clk_limit = yellow_carp_get_umd_pstate_clk_default(smu, clk_type);  		ret = yellow_carp_get_current_clk_freq(smu, clk_type, &cur_value);  		if (ret)  			goto print_clk_out; @@ -1058,7 +1113,7 @@ static int yellow_carp_print_clk_levels(struct smu_context *smu,  		size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", min,  				i == 0 ? "*" : "");  		size += sysfs_emit_at(buf, size, "1: %uMhz %s\n", -				i == 1 ? cur_value : YELLOW_CARP_UMD_PSTATE_GFXCLK, +				i == 1 ? cur_value : clk_limit,  				i == 1 ? "*" : "");  		size += sysfs_emit_at(buf, size, "2: %uMhz %s\n", max,  				i == 2 ? "*" : ""); @@ -1107,6 +1162,49 @@ force_level_out:  	return ret;  } +static int yellow_carp_get_dpm_profile_freq(struct smu_context *smu, +					enum amd_dpm_forced_level level, +					enum smu_clk_type clk_type, +					uint32_t *min_clk, +					uint32_t *max_clk) +{ +	int ret = 0; +	uint32_t clk_limit = 0; + +	clk_limit = yellow_carp_get_umd_pstate_clk_default(smu, clk_type); + +	switch (clk_type) { +	case SMU_GFXCLK: +	case SMU_SCLK: +		if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) +			yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &clk_limit); +		else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) +			yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, &clk_limit, NULL); +		break; +	case SMU_SOCCLK: +		if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) +			yellow_carp_get_dpm_ultimate_freq(smu, SMU_SOCCLK, NULL, &clk_limit); +		break; +	case SMU_FCLK: +		if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) +			yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &clk_limit); +		else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) +			yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, &clk_limit, NULL); +		break; +	case SMU_VCLK: +		yellow_carp_get_dpm_ultimate_freq(smu, SMU_VCLK, NULL, &clk_limit); +		break; +	case SMU_DCLK: +		yellow_carp_get_dpm_ultimate_freq(smu, SMU_DCLK, NULL, &clk_limit); +		break; +	default: +		ret = -EINVAL; +		break; +	} +	*min_clk = *max_clk = clk_limit; +	return ret; +} +  static int yellow_carp_set_performance_level(struct smu_context *smu,  						enum amd_dpm_forced_level level)  { @@ -1114,6 +1212,9 @@ static int yellow_carp_set_performance_level(struct smu_context *smu,  	uint32_t sclk_min = 0, sclk_max = 0;  	uint32_t fclk_min = 0, fclk_max = 0;  	uint32_t socclk_min = 0, socclk_max = 0; +	uint32_t vclk_min = 0, vclk_max = 0; +	uint32_t dclk_min = 0, dclk_max = 0; +  	int ret = 0;  	switch (level) { @@ -1121,28 +1222,42 @@ static int yellow_carp_set_performance_level(struct smu_context *smu,  		yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &sclk_max);  		yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &fclk_max);  		yellow_carp_get_dpm_ultimate_freq(smu, SMU_SOCCLK, NULL, &socclk_max); +		yellow_carp_get_dpm_ultimate_freq(smu, SMU_VCLK, NULL, &vclk_max); +		yellow_carp_get_dpm_ultimate_freq(smu, SMU_DCLK, NULL, &dclk_max);  		sclk_min = sclk_max;  		fclk_min = fclk_max;  		socclk_min = socclk_max; +		vclk_min = vclk_max; +		dclk_min = dclk_max;  		break;  	case AMD_DPM_FORCED_LEVEL_LOW:  		yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, NULL);  		yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, &fclk_min, NULL);  		yellow_carp_get_dpm_ultimate_freq(smu, SMU_SOCCLK, &socclk_min, NULL); +		yellow_carp_get_dpm_ultimate_freq(smu, SMU_VCLK, &vclk_min, NULL); +		yellow_carp_get_dpm_ultimate_freq(smu, SMU_DCLK, &dclk_min, NULL);  		sclk_max = sclk_min;  		fclk_max = fclk_min;  		socclk_max = socclk_min; +		vclk_max = vclk_min; +		dclk_max = dclk_min;  		break;  	case AMD_DPM_FORCED_LEVEL_AUTO:  		yellow_carp_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, &sclk_max);  		yellow_carp_get_dpm_ultimate_freq(smu, SMU_FCLK, &fclk_min, &fclk_max);  		yellow_carp_get_dpm_ultimate_freq(smu, SMU_SOCCLK, &socclk_min, &socclk_max); +		yellow_carp_get_dpm_ultimate_freq(smu, SMU_VCLK, &vclk_min, &vclk_max); +		yellow_carp_get_dpm_ultimate_freq(smu, SMU_DCLK, &dclk_min, &dclk_max);  		break;  	case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:  	case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:  	case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:  	case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: -		/* Temporarily do nothing since the optimal clocks haven't been provided yet */ +		yellow_carp_get_dpm_profile_freq(smu, level, SMU_SCLK, &sclk_min, &sclk_max); +		yellow_carp_get_dpm_profile_freq(smu, level, SMU_FCLK, &fclk_min, &fclk_max); +		yellow_carp_get_dpm_profile_freq(smu, level, SMU_SOCCLK, &socclk_min, &socclk_max); +		yellow_carp_get_dpm_profile_freq(smu, level, SMU_VCLK, &vclk_min, &vclk_max); +		yellow_carp_get_dpm_profile_freq(smu, level, SMU_DCLK, &dclk_min, &dclk_max);  		break;  	case AMD_DPM_FORCED_LEVEL_MANUAL:  	case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: @@ -1182,6 +1297,24 @@ static int yellow_carp_set_performance_level(struct smu_context *smu,  			return ret;  	} +	if (vclk_min && vclk_max) { +		ret = yellow_carp_set_soft_freq_limited_range(smu, +							      SMU_VCLK, +							      vclk_min, +							      vclk_max); +		if (ret) +			return ret; +	} + +	if (dclk_min && dclk_max) { +		ret = yellow_carp_set_soft_freq_limited_range(smu, +							      SMU_DCLK, +							      dclk_min, +							      dclk_max); +		if (ret) +			return ret; +	} +  	return ret;  } @@ -1235,5 +1368,6 @@ void yellow_carp_set_ppt_funcs(struct smu_context *smu)  	smu->feature_map = yellow_carp_feature_mask_map;  	smu->table_map = yellow_carp_table_map;  	smu->is_apu = true; +	smu->smc_driver_if_version = SMU13_YELLOW_CARP_DRIVER_IF_VERSION;  	smu_v13_0_set_smu_mailbox_registers(smu);  } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.h index a9205a8ea3ad..b3ad8352c68a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.h @@ -24,6 +24,5 @@  #define __YELLOW_CARP_PPT_H__  extern void yellow_carp_set_ppt_funcs(struct smu_context *smu); -#define YELLOW_CARP_UMD_PSTATE_GFXCLK       1100  #endif  |