mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 08:44:41 +00:00 
			
		
		
		
	drm/radeon: bind fan control on CI cards to hwmon interface (v2)
This adds a possibility to control fan on CI parts
via exported hwmon variables. Note that automatic
ucode fan management pauses if you choose to enable
manual fan control.  Use with caution!
v2: agd5f: fix formatting, squash in:
    minor fix for pwm1_enable exposed value
    Track smc control in addition to fan mode
    This fixes pwm1_enable being constantly set
    to 1 because of enabled smc control
also handle the case where smc fan control is disabled.
Signed-off-by: Oleg Chernovskiy <algonkvel@gmail.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
			
			
This commit is contained in:
		
							parent
							
								
									99736703a9
								
							
						
					
					
						commit
						36689e5750
					
				
					 4 changed files with 55 additions and 10 deletions
				
			
		|  | @ -187,6 +187,9 @@ static int ci_update_uvd_dpm(struct radeon_device *rdev, bool gate); | ||||||
| static PPSMC_Result ci_send_msg_to_smc_with_parameter(struct radeon_device *rdev, | static PPSMC_Result ci_send_msg_to_smc_with_parameter(struct radeon_device *rdev, | ||||||
| 						      PPSMC_Msg msg, u32 parameter); | 						      PPSMC_Msg msg, u32 parameter); | ||||||
| 
 | 
 | ||||||
|  | static void ci_thermal_start_smc_fan_control(struct radeon_device *rdev); | ||||||
|  | static void ci_fan_ctrl_set_default_mode(struct radeon_device *rdev); | ||||||
|  | 
 | ||||||
| static struct ci_power_info *ci_get_pi(struct radeon_device *rdev) | static struct ci_power_info *ci_get_pi(struct radeon_device *rdev) | ||||||
| { | { | ||||||
|         struct ci_power_info *pi = rdev->pm.dpm.priv; |         struct ci_power_info *pi = rdev->pm.dpm.priv; | ||||||
|  | @ -1043,22 +1046,24 @@ static int ci_fan_ctrl_start_smc_fan_control(struct radeon_device *rdev) | ||||||
| 			return -EINVAL; | 			return -EINVAL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	pi->fan_is_controlled_by_smc = true; | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #if 0 |  | ||||||
| static int ci_fan_ctrl_stop_smc_fan_control(struct radeon_device *rdev) | static int ci_fan_ctrl_stop_smc_fan_control(struct radeon_device *rdev) | ||||||
| { | { | ||||||
| 	PPSMC_Result ret; | 	PPSMC_Result ret; | ||||||
|  | 	struct ci_power_info *pi = ci_get_pi(rdev); | ||||||
| 
 | 
 | ||||||
| 	ret = ci_send_msg_to_smc(rdev, PPSMC_StopFanControl); | 	ret = ci_send_msg_to_smc(rdev, PPSMC_StopFanControl); | ||||||
| 	if (ret == PPSMC_Result_OK) | 	if (ret == PPSMC_Result_OK) { | ||||||
|  | 		pi->fan_is_controlled_by_smc = false; | ||||||
| 		return 0; | 		return 0; | ||||||
| 	else | 	} else | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev, | int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev, | ||||||
| 					     u32 *speed) | 					     u32 *speed) | ||||||
| { | { | ||||||
| 	u32 duty, duty100; | 	u32 duty, duty100; | ||||||
|  | @ -1083,21 +1088,22 @@ static int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev, | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev, | int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev, | ||||||
| 					     u32 speed) | 					     u32 speed) | ||||||
| { | { | ||||||
| 	u32 tmp; | 	u32 tmp; | ||||||
| 	u32 duty, duty100; | 	u32 duty, duty100; | ||||||
| 	u64 tmp64; | 	u64 tmp64; | ||||||
|  | 	struct ci_power_info *pi = ci_get_pi(rdev); | ||||||
| 
 | 
 | ||||||
| 	if (rdev->pm.no_fan) | 	if (rdev->pm.no_fan) | ||||||
| 		return -ENOENT; | 		return -ENOENT; | ||||||
| 
 | 
 | ||||||
| 	if (speed > 100) | 	if (pi->fan_is_controlled_by_smc) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
| 	if (rdev->pm.dpm.fan.ucode_fan_control) | 	if (speed > 100) | ||||||
| 		ci_fan_ctrl_stop_smc_fan_control(rdev); | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
| 	duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT; | 	duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT; | ||||||
| 
 | 
 | ||||||
|  | @ -1112,11 +1118,38 @@ static int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev, | ||||||
| 	tmp |= FDO_STATIC_DUTY(duty); | 	tmp |= FDO_STATIC_DUTY(duty); | ||||||
| 	WREG32_SMC(CG_FDO_CTRL0, tmp); | 	WREG32_SMC(CG_FDO_CTRL0, tmp); | ||||||
| 
 | 
 | ||||||
| 	ci_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC); |  | ||||||
| 
 |  | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void ci_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode) | ||||||
|  | { | ||||||
|  | 	if (mode) { | ||||||
|  | 		/* stop auto-manage */ | ||||||
|  | 		if (rdev->pm.dpm.fan.ucode_fan_control) | ||||||
|  | 			ci_fan_ctrl_stop_smc_fan_control(rdev); | ||||||
|  | 		ci_fan_ctrl_set_static_mode(rdev, mode); | ||||||
|  | 	} else { | ||||||
|  | 		/* restart auto-manage */ | ||||||
|  | 		if (rdev->pm.dpm.fan.ucode_fan_control) | ||||||
|  | 			ci_thermal_start_smc_fan_control(rdev); | ||||||
|  | 		else | ||||||
|  | 			ci_fan_ctrl_set_default_mode(rdev); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | u32 ci_fan_ctrl_get_mode(struct radeon_device *rdev) | ||||||
|  | { | ||||||
|  | 	struct ci_power_info *pi = ci_get_pi(rdev); | ||||||
|  | 	u32 tmp; | ||||||
|  | 
 | ||||||
|  | 	if (pi->fan_is_controlled_by_smc) | ||||||
|  | 		return 0; | ||||||
|  | 
 | ||||||
|  | 	tmp = RREG32_SMC(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK; | ||||||
|  | 	return (tmp >> FDO_PWM_MODE_SHIFT); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #if 0 | ||||||
| static int ci_fan_ctrl_get_fan_speed_rpm(struct radeon_device *rdev, | static int ci_fan_ctrl_get_fan_speed_rpm(struct radeon_device *rdev, | ||||||
| 					 u32 *speed) | 					 u32 *speed) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -291,6 +291,7 @@ struct ci_power_info { | ||||||
| 	struct ci_ps requested_ps; | 	struct ci_ps requested_ps; | ||||||
| 	/* fan control */ | 	/* fan control */ | ||||||
| 	bool fan_ctrl_is_in_default_mode; | 	bool fan_ctrl_is_in_default_mode; | ||||||
|  | 	bool fan_is_controlled_by_smc; | ||||||
| 	u32 t_min; | 	u32 t_min; | ||||||
| 	u32 fan_ctrl_default_mode; | 	u32 fan_ctrl_default_mode; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -2118,6 +2118,10 @@ static struct radeon_asic ci_asic = { | ||||||
| 		.force_performance_level = &ci_dpm_force_performance_level, | 		.force_performance_level = &ci_dpm_force_performance_level, | ||||||
| 		.vblank_too_short = &ci_dpm_vblank_too_short, | 		.vblank_too_short = &ci_dpm_vblank_too_short, | ||||||
| 		.powergate_uvd = &ci_dpm_powergate_uvd, | 		.powergate_uvd = &ci_dpm_powergate_uvd, | ||||||
|  | 		.fan_ctrl_set_mode = &ci_fan_ctrl_set_mode, | ||||||
|  | 		.fan_ctrl_get_mode = &ci_fan_ctrl_get_mode, | ||||||
|  | 		.get_fan_speed_percent = &ci_fan_ctrl_get_fan_speed_percent, | ||||||
|  | 		.set_fan_speed_percent = &ci_fan_ctrl_set_fan_speed_percent, | ||||||
| 	}, | 	}, | ||||||
| 	.pflip = { | 	.pflip = { | ||||||
| 		.page_flip = &evergreen_page_flip, | 		.page_flip = &evergreen_page_flip, | ||||||
|  |  | ||||||
|  | @ -861,6 +861,13 @@ int ci_dpm_force_performance_level(struct radeon_device *rdev, | ||||||
| bool ci_dpm_vblank_too_short(struct radeon_device *rdev); | bool ci_dpm_vblank_too_short(struct radeon_device *rdev); | ||||||
| void ci_dpm_powergate_uvd(struct radeon_device *rdev, bool gate); | void ci_dpm_powergate_uvd(struct radeon_device *rdev, bool gate); | ||||||
| 
 | 
 | ||||||
|  | int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev, | ||||||
|  | 						 u32 *speed); | ||||||
|  | int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev, | ||||||
|  | 						 u32 speed); | ||||||
|  | u32 ci_fan_ctrl_get_mode(struct radeon_device *rdev); | ||||||
|  | void ci_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode); | ||||||
|  | 
 | ||||||
| int kv_dpm_init(struct radeon_device *rdev); | int kv_dpm_init(struct radeon_device *rdev); | ||||||
| int kv_dpm_enable(struct radeon_device *rdev); | int kv_dpm_enable(struct radeon_device *rdev); | ||||||
| int kv_dpm_late_enable(struct radeon_device *rdev); | int kv_dpm_late_enable(struct radeon_device *rdev); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Oleg Chernovskiy
						Oleg Chernovskiy