drm/radeon/dpm: add smc fan control for CI (v2)
Enable smc fan control for CI boards. Should reduce the fan noise on systems with a higher default fan profile. v2: disable by default, add additional fan setup, rpm control bug: https://bugs.freedesktop.org/show_bug.cgi?id=73338 Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
39471ad39d
commit
e03cea367f
|
@ -184,6 +184,9 @@ static int ci_set_overdrive_target_tdp(struct radeon_device *rdev,
|
||||||
u32 target_tdp);
|
u32 target_tdp);
|
||||||
static int ci_update_uvd_dpm(struct radeon_device *rdev, bool gate);
|
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,
|
||||||
|
PPSMC_Msg msg, u32 parameter);
|
||||||
|
|
||||||
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;
|
||||||
|
@ -355,6 +358,21 @@ static int ci_populate_dw8(struct radeon_device *rdev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ci_populate_fuzzy_fan(struct radeon_device *rdev)
|
||||||
|
{
|
||||||
|
struct ci_power_info *pi = ci_get_pi(rdev);
|
||||||
|
|
||||||
|
if ((rdev->pm.dpm.fan.fan_output_sensitivity & (1 << 15)) ||
|
||||||
|
(rdev->pm.dpm.fan.fan_output_sensitivity == 0))
|
||||||
|
rdev->pm.dpm.fan.fan_output_sensitivity =
|
||||||
|
rdev->pm.dpm.fan.default_fan_output_sensitivity;
|
||||||
|
|
||||||
|
pi->smc_powertune_table.FuzzyFan_PwmSetDelta =
|
||||||
|
cpu_to_be16(rdev->pm.dpm.fan.fan_output_sensitivity);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(struct radeon_device *rdev)
|
static int ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(struct radeon_device *rdev)
|
||||||
{
|
{
|
||||||
struct ci_power_info *pi = ci_get_pi(rdev);
|
struct ci_power_info *pi = ci_get_pi(rdev);
|
||||||
|
@ -478,6 +496,9 @@ static int ci_populate_pm_base(struct radeon_device *rdev)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
ret = ci_populate_dw8(rdev);
|
ret = ci_populate_dw8(rdev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = ci_populate_fuzzy_fan(rdev);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
ret = ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(rdev);
|
ret = ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(rdev);
|
||||||
|
@ -859,6 +880,7 @@ static int ci_thermal_enable_alert(struct radeon_device *rdev,
|
||||||
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
thermal_int &= ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
|
thermal_int &= ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
|
||||||
|
WREG32_SMC(CG_THERMAL_INT, thermal_int);
|
||||||
rdev->irq.dpm_thermal = false;
|
rdev->irq.dpm_thermal = false;
|
||||||
result = ci_send_msg_to_smc(rdev, PPSMC_MSG_Thermal_Cntl_Enable);
|
result = ci_send_msg_to_smc(rdev, PPSMC_MSG_Thermal_Cntl_Enable);
|
||||||
if (result != PPSMC_Result_OK) {
|
if (result != PPSMC_Result_OK) {
|
||||||
|
@ -867,6 +889,7 @@ static int ci_thermal_enable_alert(struct radeon_device *rdev,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW;
|
thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW;
|
||||||
|
WREG32_SMC(CG_THERMAL_INT, thermal_int);
|
||||||
rdev->irq.dpm_thermal = true;
|
rdev->irq.dpm_thermal = true;
|
||||||
result = ci_send_msg_to_smc(rdev, PPSMC_MSG_Thermal_Cntl_Disable);
|
result = ci_send_msg_to_smc(rdev, PPSMC_MSG_Thermal_Cntl_Disable);
|
||||||
if (result != PPSMC_Result_OK) {
|
if (result != PPSMC_Result_OK) {
|
||||||
|
@ -875,11 +898,324 @@ static int ci_thermal_enable_alert(struct radeon_device *rdev,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WREG32_SMC(CG_THERMAL_INT, thermal_int);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ci_fan_ctrl_set_static_mode(struct radeon_device *rdev, u32 mode)
|
||||||
|
{
|
||||||
|
struct ci_power_info *pi = ci_get_pi(rdev);
|
||||||
|
u32 tmp;
|
||||||
|
|
||||||
|
if (pi->fan_ctrl_is_in_default_mode) {
|
||||||
|
tmp = (RREG32_SMC(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK) >> FDO_PWM_MODE_SHIFT;
|
||||||
|
pi->fan_ctrl_default_mode = tmp;
|
||||||
|
tmp = (RREG32_SMC(CG_FDO_CTRL2) & TMIN_MASK) >> TMIN_SHIFT;
|
||||||
|
pi->t_min = tmp;
|
||||||
|
pi->fan_ctrl_is_in_default_mode = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = RREG32_SMC(CG_FDO_CTRL2) & ~TMIN_MASK;
|
||||||
|
tmp |= TMIN(0);
|
||||||
|
WREG32_SMC(CG_FDO_CTRL2, tmp);
|
||||||
|
|
||||||
|
tmp = RREG32_SMC(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK;
|
||||||
|
tmp |= FDO_PWM_MODE(mode);
|
||||||
|
WREG32_SMC(CG_FDO_CTRL2, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ci_thermal_setup_fan_table(struct radeon_device *rdev)
|
||||||
|
{
|
||||||
|
struct ci_power_info *pi = ci_get_pi(rdev);
|
||||||
|
SMU7_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
|
||||||
|
u32 duty100;
|
||||||
|
u32 t_diff1, t_diff2, pwm_diff1, pwm_diff2;
|
||||||
|
u16 fdo_min, slope1, slope2;
|
||||||
|
u32 reference_clock, tmp;
|
||||||
|
int ret;
|
||||||
|
u64 tmp64;
|
||||||
|
|
||||||
|
if (!pi->fan_table_start) {
|
||||||
|
rdev->pm.dpm.fan.ucode_fan_control = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
|
||||||
|
|
||||||
|
if (duty100 == 0) {
|
||||||
|
rdev->pm.dpm.fan.ucode_fan_control = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp64 = (u64)rdev->pm.dpm.fan.pwm_min * duty100;
|
||||||
|
do_div(tmp64, 10000);
|
||||||
|
fdo_min = (u16)tmp64;
|
||||||
|
|
||||||
|
t_diff1 = rdev->pm.dpm.fan.t_med - rdev->pm.dpm.fan.t_min;
|
||||||
|
t_diff2 = rdev->pm.dpm.fan.t_high - rdev->pm.dpm.fan.t_med;
|
||||||
|
|
||||||
|
pwm_diff1 = rdev->pm.dpm.fan.pwm_med - rdev->pm.dpm.fan.pwm_min;
|
||||||
|
pwm_diff2 = rdev->pm.dpm.fan.pwm_high - rdev->pm.dpm.fan.pwm_med;
|
||||||
|
|
||||||
|
slope1 = (u16)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
|
||||||
|
slope2 = (u16)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
|
||||||
|
|
||||||
|
fan_table.TempMin = cpu_to_be16((50 + rdev->pm.dpm.fan.t_min) / 100);
|
||||||
|
fan_table.TempMed = cpu_to_be16((50 + rdev->pm.dpm.fan.t_med) / 100);
|
||||||
|
fan_table.TempMax = cpu_to_be16((50 + rdev->pm.dpm.fan.t_max) / 100);
|
||||||
|
|
||||||
|
fan_table.Slope1 = cpu_to_be16(slope1);
|
||||||
|
fan_table.Slope2 = cpu_to_be16(slope2);
|
||||||
|
|
||||||
|
fan_table.FdoMin = cpu_to_be16(fdo_min);
|
||||||
|
|
||||||
|
fan_table.HystDown = cpu_to_be16(rdev->pm.dpm.fan.t_hyst);
|
||||||
|
|
||||||
|
fan_table.HystUp = cpu_to_be16(1);
|
||||||
|
|
||||||
|
fan_table.HystSlope = cpu_to_be16(1);
|
||||||
|
|
||||||
|
fan_table.TempRespLim = cpu_to_be16(5);
|
||||||
|
|
||||||
|
reference_clock = radeon_get_xclk(rdev);
|
||||||
|
|
||||||
|
fan_table.RefreshPeriod = cpu_to_be32((rdev->pm.dpm.fan.cycle_delay *
|
||||||
|
reference_clock) / 1600);
|
||||||
|
|
||||||
|
fan_table.FdoMax = cpu_to_be16((u16)duty100);
|
||||||
|
|
||||||
|
tmp = (RREG32_SMC(CG_MULT_THERMAL_CTRL) & TEMP_SEL_MASK) >> TEMP_SEL_SHIFT;
|
||||||
|
fan_table.TempSrc = (uint8_t)tmp;
|
||||||
|
|
||||||
|
ret = ci_copy_bytes_to_smc(rdev,
|
||||||
|
pi->fan_table_start,
|
||||||
|
(u8 *)(&fan_table),
|
||||||
|
sizeof(fan_table),
|
||||||
|
pi->sram_end);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
DRM_ERROR("Failed to load fan table to the SMC.");
|
||||||
|
rdev->pm.dpm.fan.ucode_fan_control = false;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ci_fan_ctrl_start_smc_fan_control(struct radeon_device *rdev)
|
||||||
|
{
|
||||||
|
struct ci_power_info *pi = ci_get_pi(rdev);
|
||||||
|
PPSMC_Result ret;
|
||||||
|
|
||||||
|
if (pi->caps_od_fuzzy_fan_control_support) {
|
||||||
|
ret = ci_send_msg_to_smc_with_parameter(rdev,
|
||||||
|
PPSMC_StartFanControl,
|
||||||
|
FAN_CONTROL_FUZZY);
|
||||||
|
if (ret != PPSMC_Result_OK)
|
||||||
|
return -EINVAL;
|
||||||
|
ret = ci_send_msg_to_smc_with_parameter(rdev,
|
||||||
|
PPSMC_MSG_SetFanPwmMax,
|
||||||
|
rdev->pm.dpm.fan.default_max_fan_pwm);
|
||||||
|
if (ret != PPSMC_Result_OK)
|
||||||
|
return -EINVAL;
|
||||||
|
} else {
|
||||||
|
ret = ci_send_msg_to_smc_with_parameter(rdev,
|
||||||
|
PPSMC_StartFanControl,
|
||||||
|
FAN_CONTROL_TABLE);
|
||||||
|
if (ret != PPSMC_Result_OK)
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static int ci_fan_ctrl_stop_smc_fan_control(struct radeon_device *rdev)
|
||||||
|
{
|
||||||
|
PPSMC_Result ret;
|
||||||
|
|
||||||
|
ret = ci_send_msg_to_smc(rdev, PPSMC_StopFanControl);
|
||||||
|
if (ret == PPSMC_Result_OK)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
|
||||||
|
u32 *speed)
|
||||||
|
{
|
||||||
|
u32 duty, duty100;
|
||||||
|
u64 tmp64;
|
||||||
|
|
||||||
|
if (rdev->pm.no_fan)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
|
||||||
|
duty = (RREG32_SMC(CG_THERMAL_STATUS) & FDO_PWM_DUTY_MASK) >> FDO_PWM_DUTY_SHIFT;
|
||||||
|
|
||||||
|
if (duty100 == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
tmp64 = (u64)duty * 100;
|
||||||
|
do_div(tmp64, duty100);
|
||||||
|
*speed = (u32)tmp64;
|
||||||
|
|
||||||
|
if (*speed > 100)
|
||||||
|
*speed = 100;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
|
||||||
|
u32 speed)
|
||||||
|
{
|
||||||
|
u32 tmp;
|
||||||
|
u32 duty, duty100;
|
||||||
|
u64 tmp64;
|
||||||
|
|
||||||
|
if (rdev->pm.no_fan)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
if (speed > 100)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (rdev->pm.dpm.fan.ucode_fan_control)
|
||||||
|
ci_fan_ctrl_stop_smc_fan_control(rdev);
|
||||||
|
|
||||||
|
duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
|
||||||
|
|
||||||
|
if (duty100 == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
tmp64 = (u64)speed * duty100;
|
||||||
|
do_div(tmp64, 100);
|
||||||
|
duty = (u32)tmp64;
|
||||||
|
|
||||||
|
tmp = RREG32_SMC(CG_FDO_CTRL0) & ~FDO_STATIC_DUTY_MASK;
|
||||||
|
tmp |= FDO_STATIC_DUTY(duty);
|
||||||
|
WREG32_SMC(CG_FDO_CTRL0, tmp);
|
||||||
|
|
||||||
|
ci_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ci_fan_ctrl_get_fan_speed_rpm(struct radeon_device *rdev,
|
||||||
|
u32 *speed)
|
||||||
|
{
|
||||||
|
u32 tach_period;
|
||||||
|
u32 xclk = radeon_get_xclk(rdev);
|
||||||
|
|
||||||
|
if (rdev->pm.no_fan)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
if (rdev->pm.fan_pulses_per_revolution == 0)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
tach_period = (RREG32_SMC(CG_TACH_STATUS) & TACH_PERIOD_MASK) >> TACH_PERIOD_SHIFT;
|
||||||
|
if (tach_period == 0)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
*speed = 60 * xclk * 10000 / tach_period;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ci_fan_ctrl_set_fan_speed_rpm(struct radeon_device *rdev,
|
||||||
|
u32 speed)
|
||||||
|
{
|
||||||
|
u32 tach_period, tmp;
|
||||||
|
u32 xclk = radeon_get_xclk(rdev);
|
||||||
|
|
||||||
|
if (rdev->pm.no_fan)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
if (rdev->pm.fan_pulses_per_revolution == 0)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
if ((speed < rdev->pm.fan_min_rpm) ||
|
||||||
|
(speed > rdev->pm.fan_max_rpm))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (rdev->pm.dpm.fan.ucode_fan_control)
|
||||||
|
ci_fan_ctrl_stop_smc_fan_control(rdev);
|
||||||
|
|
||||||
|
tach_period = 60 * xclk * 10000 / (8 * speed);
|
||||||
|
tmp = RREG32_SMC(CG_TACH_CTRL) & ~TARGET_PERIOD_MASK;
|
||||||
|
tmp |= TARGET_PERIOD(tach_period);
|
||||||
|
WREG32_SMC(CG_TACH_CTRL, tmp);
|
||||||
|
|
||||||
|
ci_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void ci_fan_ctrl_set_default_mode(struct radeon_device *rdev)
|
||||||
|
{
|
||||||
|
struct ci_power_info *pi = ci_get_pi(rdev);
|
||||||
|
u32 tmp;
|
||||||
|
|
||||||
|
if (!pi->fan_ctrl_is_in_default_mode) {
|
||||||
|
tmp = RREG32_SMC(CG_FDO_CTRL2) & ~FDO_PWM_MODE_MASK;
|
||||||
|
tmp |= FDO_PWM_MODE(pi->fan_ctrl_default_mode);
|
||||||
|
WREG32_SMC(CG_FDO_CTRL2, tmp);
|
||||||
|
|
||||||
|
tmp = RREG32_SMC(CG_FDO_CTRL2) & TMIN_MASK;
|
||||||
|
tmp |= TMIN(pi->t_min);
|
||||||
|
WREG32_SMC(CG_FDO_CTRL2, tmp);
|
||||||
|
pi->fan_ctrl_is_in_default_mode = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ci_thermal_start_smc_fan_control(struct radeon_device *rdev)
|
||||||
|
{
|
||||||
|
if (rdev->pm.dpm.fan.ucode_fan_control) {
|
||||||
|
ci_fan_ctrl_start_smc_fan_control(rdev);
|
||||||
|
ci_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ci_thermal_initialize(struct radeon_device *rdev)
|
||||||
|
{
|
||||||
|
u32 tmp;
|
||||||
|
|
||||||
|
if (rdev->pm.fan_pulses_per_revolution) {
|
||||||
|
tmp = RREG32_SMC(CG_TACH_CTRL) & ~EDGE_PER_REV_MASK;
|
||||||
|
tmp |= EDGE_PER_REV(rdev->pm.fan_pulses_per_revolution -1);
|
||||||
|
WREG32_SMC(CG_TACH_CTRL, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = RREG32_SMC(CG_FDO_CTRL2) & ~TACH_PWM_RESP_RATE_MASK;
|
||||||
|
tmp |= TACH_PWM_RESP_RATE(0x28);
|
||||||
|
WREG32_SMC(CG_FDO_CTRL2, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ci_thermal_start_thermal_controller(struct radeon_device *rdev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ci_thermal_initialize(rdev);
|
||||||
|
ret = ci_thermal_set_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = ci_thermal_enable_alert(rdev, true);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
if (rdev->pm.dpm.fan.ucode_fan_control) {
|
||||||
|
ret = ci_thermal_setup_fan_table(rdev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ci_thermal_start_smc_fan_control(rdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ci_thermal_stop_thermal_controller(struct radeon_device *rdev)
|
||||||
|
{
|
||||||
|
if (!rdev->pm.no_fan)
|
||||||
|
ci_fan_ctrl_set_default_mode(rdev);
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
static int ci_read_smc_soft_register(struct radeon_device *rdev,
|
static int ci_read_smc_soft_register(struct radeon_device *rdev,
|
||||||
u16 reg_offset, u32 *value)
|
u16 reg_offset, u32 *value)
|
||||||
|
@ -4841,6 +5177,8 @@ int ci_dpm_enable(struct radeon_device *rdev)
|
||||||
|
|
||||||
ci_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
|
ci_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
|
||||||
|
|
||||||
|
ci_thermal_start_thermal_controller(rdev);
|
||||||
|
|
||||||
ci_update_current_ps(rdev, boot_ps);
|
ci_update_current_ps(rdev, boot_ps);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -4886,6 +5224,8 @@ void ci_dpm_disable(struct radeon_device *rdev)
|
||||||
if (!ci_is_smc_running(rdev))
|
if (!ci_is_smc_running(rdev))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
ci_thermal_stop_thermal_controller(rdev);
|
||||||
|
|
||||||
if (pi->thermal_protection)
|
if (pi->thermal_protection)
|
||||||
ci_enable_thermal_protection(rdev, false);
|
ci_enable_thermal_protection(rdev, false);
|
||||||
ci_enable_power_containment(rdev, false);
|
ci_enable_power_containment(rdev, false);
|
||||||
|
@ -5473,6 +5813,9 @@ int ci_dpm_init(struct radeon_device *rdev)
|
||||||
rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc =
|
rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc =
|
||||||
rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
|
rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
|
||||||
|
|
||||||
|
pi->fan_ctrl_is_in_default_mode = true;
|
||||||
|
rdev->pm.dpm.fan.ucode_fan_control = false;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -266,6 +266,7 @@ struct ci_power_info {
|
||||||
bool caps_automatic_dc_transition;
|
bool caps_automatic_dc_transition;
|
||||||
bool caps_sclk_throttle_low_notification;
|
bool caps_sclk_throttle_low_notification;
|
||||||
bool caps_dynamic_ac_timing;
|
bool caps_dynamic_ac_timing;
|
||||||
|
bool caps_od_fuzzy_fan_control_support;
|
||||||
/* flags */
|
/* flags */
|
||||||
bool thermal_protection;
|
bool thermal_protection;
|
||||||
bool pcie_performance_request;
|
bool pcie_performance_request;
|
||||||
|
@ -287,6 +288,10 @@ struct ci_power_info {
|
||||||
struct ci_ps current_ps;
|
struct ci_ps current_ps;
|
||||||
struct radeon_ps requested_rps;
|
struct radeon_ps requested_rps;
|
||||||
struct ci_ps requested_ps;
|
struct ci_ps requested_ps;
|
||||||
|
/* fan control */
|
||||||
|
bool fan_ctrl_is_in_default_mode;
|
||||||
|
u32 t_min;
|
||||||
|
u32 fan_ctrl_default_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CISLANDS_VOLTAGE_CONTROL_NONE 0x0
|
#define CISLANDS_VOLTAGE_CONTROL_NONE 0x0
|
||||||
|
|
|
@ -186,7 +186,10 @@
|
||||||
#define DIG_THERM_DPM(x) ((x) << 14)
|
#define DIG_THERM_DPM(x) ((x) << 14)
|
||||||
#define DIG_THERM_DPM_MASK 0x003FC000
|
#define DIG_THERM_DPM_MASK 0x003FC000
|
||||||
#define DIG_THERM_DPM_SHIFT 14
|
#define DIG_THERM_DPM_SHIFT 14
|
||||||
|
#define CG_THERMAL_STATUS 0xC0300008
|
||||||
|
#define FDO_PWM_DUTY(x) ((x) << 9)
|
||||||
|
#define FDO_PWM_DUTY_MASK (0xff << 9)
|
||||||
|
#define FDO_PWM_DUTY_SHIFT 9
|
||||||
#define CG_THERMAL_INT 0xC030000C
|
#define CG_THERMAL_INT 0xC030000C
|
||||||
#define CI_DIG_THERM_INTH(x) ((x) << 8)
|
#define CI_DIG_THERM_INTH(x) ((x) << 8)
|
||||||
#define CI_DIG_THERM_INTH_MASK 0x0000FF00
|
#define CI_DIG_THERM_INTH_MASK 0x0000FF00
|
||||||
|
@ -196,7 +199,10 @@
|
||||||
#define CI_DIG_THERM_INTL_SHIFT 16
|
#define CI_DIG_THERM_INTL_SHIFT 16
|
||||||
#define THERM_INT_MASK_HIGH (1 << 24)
|
#define THERM_INT_MASK_HIGH (1 << 24)
|
||||||
#define THERM_INT_MASK_LOW (1 << 25)
|
#define THERM_INT_MASK_LOW (1 << 25)
|
||||||
|
#define CG_MULT_THERMAL_CTRL 0xC0300010
|
||||||
|
#define TEMP_SEL(x) ((x) << 20)
|
||||||
|
#define TEMP_SEL_MASK (0xff << 20)
|
||||||
|
#define TEMP_SEL_SHIFT 20
|
||||||
#define CG_MULT_THERMAL_STATUS 0xC0300014
|
#define CG_MULT_THERMAL_STATUS 0xC0300014
|
||||||
#define ASIC_MAX_TEMP(x) ((x) << 0)
|
#define ASIC_MAX_TEMP(x) ((x) << 0)
|
||||||
#define ASIC_MAX_TEMP_MASK 0x000001ff
|
#define ASIC_MAX_TEMP_MASK 0x000001ff
|
||||||
|
@ -205,6 +211,36 @@
|
||||||
#define CTF_TEMP_MASK 0x0003fe00
|
#define CTF_TEMP_MASK 0x0003fe00
|
||||||
#define CTF_TEMP_SHIFT 9
|
#define CTF_TEMP_SHIFT 9
|
||||||
|
|
||||||
|
#define CG_FDO_CTRL0 0xC0300064
|
||||||
|
#define FDO_STATIC_DUTY(x) ((x) << 0)
|
||||||
|
#define FDO_STATIC_DUTY_MASK 0x0000000F
|
||||||
|
#define FDO_STATIC_DUTY_SHIFT 0
|
||||||
|
#define CG_FDO_CTRL1 0xC0300068
|
||||||
|
#define FMAX_DUTY100(x) ((x) << 0)
|
||||||
|
#define FMAX_DUTY100_MASK 0x0000000F
|
||||||
|
#define FMAX_DUTY100_SHIFT 0
|
||||||
|
#define CG_FDO_CTRL2 0xC030006C
|
||||||
|
#define TMIN(x) ((x) << 0)
|
||||||
|
#define TMIN_MASK 0x0000000F
|
||||||
|
#define TMIN_SHIFT 0
|
||||||
|
#define FDO_PWM_MODE(x) ((x) << 11)
|
||||||
|
#define FDO_PWM_MODE_MASK (3 << 11)
|
||||||
|
#define FDO_PWM_MODE_SHIFT 11
|
||||||
|
#define TACH_PWM_RESP_RATE(x) ((x) << 25)
|
||||||
|
#define TACH_PWM_RESP_RATE_MASK (0x7f << 25)
|
||||||
|
#define TACH_PWM_RESP_RATE_SHIFT 25
|
||||||
|
#define CG_TACH_CTRL 0xC0300070
|
||||||
|
# define EDGE_PER_REV(x) ((x) << 0)
|
||||||
|
# define EDGE_PER_REV_MASK (0x7 << 0)
|
||||||
|
# define EDGE_PER_REV_SHIFT 0
|
||||||
|
# define TARGET_PERIOD(x) ((x) << 3)
|
||||||
|
# define TARGET_PERIOD_MASK 0xfffffff8
|
||||||
|
# define TARGET_PERIOD_SHIFT 3
|
||||||
|
#define CG_TACH_STATUS 0xC0300074
|
||||||
|
# define TACH_PERIOD(x) ((x) << 0)
|
||||||
|
# define TACH_PERIOD_MASK 0xffffffff
|
||||||
|
# define TACH_PERIOD_SHIFT 0
|
||||||
|
|
||||||
#define CG_ECLK_CNTL 0xC05000AC
|
#define CG_ECLK_CNTL 0xC05000AC
|
||||||
# define ECLK_DIVIDER_MASK 0x7f
|
# define ECLK_DIVIDER_MASK 0x7f
|
||||||
# define ECLK_DIR_CNTL_EN (1 << 8)
|
# define ECLK_DIR_CNTL_EN (1 << 8)
|
||||||
|
|
|
@ -59,6 +59,11 @@
|
||||||
#define FDO_MODE_HARDWARE 0
|
#define FDO_MODE_HARDWARE 0
|
||||||
#define FDO_MODE_PIECE_WISE_LINEAR 1
|
#define FDO_MODE_PIECE_WISE_LINEAR 1
|
||||||
|
|
||||||
|
enum FAN_CONTROL {
|
||||||
|
FAN_CONTROL_FUZZY,
|
||||||
|
FAN_CONTROL_TABLE
|
||||||
|
};
|
||||||
|
|
||||||
#define PPSMC_Result_OK ((uint8_t)0x01)
|
#define PPSMC_Result_OK ((uint8_t)0x01)
|
||||||
#define PPSMC_Result_Failed ((uint8_t)0xFF)
|
#define PPSMC_Result_Failed ((uint8_t)0xFF)
|
||||||
|
|
||||||
|
@ -155,6 +160,7 @@ typedef uint8_t PPSMC_Result;
|
||||||
#define PPSMC_MSG_MASTER_DeepSleep_ON ((uint16_t) 0x18F)
|
#define PPSMC_MSG_MASTER_DeepSleep_ON ((uint16_t) 0x18F)
|
||||||
#define PPSMC_MSG_MASTER_DeepSleep_OFF ((uint16_t) 0x190)
|
#define PPSMC_MSG_MASTER_DeepSleep_OFF ((uint16_t) 0x190)
|
||||||
#define PPSMC_MSG_Remove_DC_Clamp ((uint16_t) 0x191)
|
#define PPSMC_MSG_Remove_DC_Clamp ((uint16_t) 0x191)
|
||||||
|
#define PPSMC_MSG_SetFanPwmMax ((uint16_t) 0x19A)
|
||||||
|
|
||||||
#define PPSMC_MSG_API_GetSclkFrequency ((uint16_t) 0x200)
|
#define PPSMC_MSG_API_GetSclkFrequency ((uint16_t) 0x200)
|
||||||
#define PPSMC_MSG_API_GetMclkFrequency ((uint16_t) 0x201)
|
#define PPSMC_MSG_API_GetMclkFrequency ((uint16_t) 0x201)
|
||||||
|
|
|
@ -96,6 +96,14 @@ typedef struct _ATOM_PPLIB_FANTABLE2
|
||||||
USHORT usTMax; // The max temperature
|
USHORT usTMax; // The max temperature
|
||||||
} ATOM_PPLIB_FANTABLE2;
|
} ATOM_PPLIB_FANTABLE2;
|
||||||
|
|
||||||
|
typedef struct _ATOM_PPLIB_FANTABLE3
|
||||||
|
{
|
||||||
|
ATOM_PPLIB_FANTABLE2 basicTable2;
|
||||||
|
UCHAR ucFanControlMode;
|
||||||
|
USHORT usFanPWMMax;
|
||||||
|
USHORT usFanOutputSensitivity;
|
||||||
|
} ATOM_PPLIB_FANTABLE3;
|
||||||
|
|
||||||
typedef struct _ATOM_PPLIB_EXTENDEDHEADER
|
typedef struct _ATOM_PPLIB_EXTENDEDHEADER
|
||||||
{
|
{
|
||||||
USHORT usSize;
|
USHORT usSize;
|
||||||
|
|
|
@ -811,6 +811,7 @@ union power_info {
|
||||||
union fan_info {
|
union fan_info {
|
||||||
struct _ATOM_PPLIB_FANTABLE fan;
|
struct _ATOM_PPLIB_FANTABLE fan;
|
||||||
struct _ATOM_PPLIB_FANTABLE2 fan2;
|
struct _ATOM_PPLIB_FANTABLE2 fan2;
|
||||||
|
struct _ATOM_PPLIB_FANTABLE3 fan3;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int r600_parse_clk_voltage_dep_table(struct radeon_clock_voltage_dependency_table *radeon_table,
|
static int r600_parse_clk_voltage_dep_table(struct radeon_clock_voltage_dependency_table *radeon_table,
|
||||||
|
@ -900,6 +901,14 @@ int r600_parse_extended_power_table(struct radeon_device *rdev)
|
||||||
else
|
else
|
||||||
rdev->pm.dpm.fan.t_max = 10900;
|
rdev->pm.dpm.fan.t_max = 10900;
|
||||||
rdev->pm.dpm.fan.cycle_delay = 100000;
|
rdev->pm.dpm.fan.cycle_delay = 100000;
|
||||||
|
if (fan_info->fan.ucFanTableFormat >= 3) {
|
||||||
|
rdev->pm.dpm.fan.control_mode = fan_info->fan3.ucFanControlMode;
|
||||||
|
rdev->pm.dpm.fan.default_max_fan_pwm =
|
||||||
|
le16_to_cpu(fan_info->fan3.usFanPWMMax);
|
||||||
|
rdev->pm.dpm.fan.default_fan_output_sensitivity = 4836;
|
||||||
|
rdev->pm.dpm.fan.fan_output_sensitivity =
|
||||||
|
le16_to_cpu(fan_info->fan3.usFanOutputSensitivity);
|
||||||
|
}
|
||||||
rdev->pm.dpm.fan.ucode_fan_control = true;
|
rdev->pm.dpm.fan.ucode_fan_control = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1494,6 +1494,10 @@ struct radeon_dpm_fan {
|
||||||
u8 t_hyst;
|
u8 t_hyst;
|
||||||
u32 cycle_delay;
|
u32 cycle_delay;
|
||||||
u16 t_max;
|
u16 t_max;
|
||||||
|
u8 control_mode;
|
||||||
|
u16 default_max_fan_pwm;
|
||||||
|
u16 default_fan_output_sensitivity;
|
||||||
|
u16 fan_output_sensitivity;
|
||||||
bool ucode_fan_control;
|
bool ucode_fan_control;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -431,6 +431,31 @@ struct SMU7_Discrete_MCRegisters
|
||||||
|
|
||||||
typedef struct SMU7_Discrete_MCRegisters SMU7_Discrete_MCRegisters;
|
typedef struct SMU7_Discrete_MCRegisters SMU7_Discrete_MCRegisters;
|
||||||
|
|
||||||
|
struct SMU7_Discrete_FanTable
|
||||||
|
{
|
||||||
|
uint16_t FdoMode;
|
||||||
|
int16_t TempMin;
|
||||||
|
int16_t TempMed;
|
||||||
|
int16_t TempMax;
|
||||||
|
int16_t Slope1;
|
||||||
|
int16_t Slope2;
|
||||||
|
int16_t FdoMin;
|
||||||
|
int16_t HystUp;
|
||||||
|
int16_t HystDown;
|
||||||
|
int16_t HystSlope;
|
||||||
|
int16_t TempRespLim;
|
||||||
|
int16_t TempCurr;
|
||||||
|
int16_t SlopeCurr;
|
||||||
|
int16_t PwmCurr;
|
||||||
|
uint32_t RefreshPeriod;
|
||||||
|
int16_t FdoMax;
|
||||||
|
uint8_t TempSrc;
|
||||||
|
int8_t Padding;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct SMU7_Discrete_FanTable SMU7_Discrete_FanTable;
|
||||||
|
|
||||||
|
|
||||||
struct SMU7_Discrete_PmFuses {
|
struct SMU7_Discrete_PmFuses {
|
||||||
// dw0-dw1
|
// dw0-dw1
|
||||||
uint8_t BapmVddCVidHiSidd[8];
|
uint8_t BapmVddCVidHiSidd[8];
|
||||||
|
@ -462,7 +487,10 @@ struct SMU7_Discrete_PmFuses {
|
||||||
uint8_t BapmVddCVidHiSidd2[8];
|
uint8_t BapmVddCVidHiSidd2[8];
|
||||||
|
|
||||||
// dw11-dw12
|
// dw11-dw12
|
||||||
uint32_t Reserved6[2];
|
int16_t FuzzyFan_ErrorSetDelta;
|
||||||
|
int16_t FuzzyFan_ErrorRateSetDelta;
|
||||||
|
int16_t FuzzyFan_PwmSetDelta;
|
||||||
|
uint16_t CalcMeasPowerBlend;
|
||||||
|
|
||||||
// dw13-dw16
|
// dw13-dw16
|
||||||
uint8_t GnbLPML[16];
|
uint8_t GnbLPML[16];
|
||||||
|
|
Loading…
Reference in New Issue