diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/si_dpm.c')
-rw-r--r-- | drivers/gpu/drm/radeon/si_dpm.c | 114 |
1 files changed, 98 insertions, 16 deletions
diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 32e354b8b0a..7be11651b7e 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -1756,6 +1756,9 @@ static int si_calculate_sclk_params(struct radeon_device *rdev, u32 engine_clock, SISLANDS_SMC_SCLK_VALUE *sclk); +static void si_thermal_start_smc_fan_control(struct radeon_device *rdev); +static void si_fan_ctrl_set_default_mode(struct radeon_device *rdev); + static struct si_power_info *si_get_pi(struct radeon_device *rdev) { struct si_power_info *pi = rdev->pm.dpm.priv; @@ -2908,6 +2911,22 @@ static int si_init_smc_spll_table(struct radeon_device *rdev) return ret; } +struct si_dpm_quirk { + u32 chip_vendor; + u32 chip_device; + u32 subsys_vendor; + u32 subsys_device; + u32 max_sclk; + u32 max_mclk; +}; + +/* cards with dpm stability problems */ +static struct si_dpm_quirk si_dpm_quirk_list[] = { + /* PITCAIRN - https://bugs.freedesktop.org/show_bug.cgi?id=76490 */ + { PCI_VENDOR_ID_ATI, 0x6810, 0x1462, 0x3036, 0, 120000 }, + { 0, 0, 0, 0 }, +}; + static void si_apply_state_adjust_rules(struct radeon_device *rdev, struct radeon_ps *rps) { @@ -2918,7 +2937,22 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev, u32 mclk, sclk; u16 vddc, vddci; u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc; + u32 max_sclk = 0, max_mclk = 0; int i; + struct si_dpm_quirk *p = si_dpm_quirk_list; + + /* Apply dpm quirks */ + while (p && p->chip_device != 0) { + if (rdev->pdev->vendor == p->chip_vendor && + rdev->pdev->device == p->chip_device && + rdev->pdev->subsystem_vendor == p->subsys_vendor && + rdev->pdev->subsystem_device == p->subsys_device) { + max_sclk = p->max_sclk; + max_mclk = p->max_mclk; + break; + } + ++p; + } if ((rdev->pm.dpm.new_active_crtc_count > 1) || ni_dpm_vblank_too_short(rdev)) @@ -2972,6 +3006,14 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev, if (ps->performance_levels[i].mclk > max_mclk_vddc) ps->performance_levels[i].mclk = max_mclk_vddc; } + if (max_mclk) { + if (ps->performance_levels[i].mclk > max_mclk) + ps->performance_levels[i].mclk = max_mclk; + } + if (max_sclk) { + if (ps->performance_levels[i].sclk > max_sclk) + ps->performance_levels[i].sclk = max_sclk; + } } /* XXX validate the min clocks required for display */ @@ -3320,11 +3362,13 @@ int si_dpm_force_performance_level(struct radeon_device *rdev, return 0; } +#if 0 static int si_set_boot_state(struct radeon_device *rdev) { return (si_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToInitialState) == PPSMC_Result_OK) ? 0 : -EINVAL; } +#endif static int si_set_sw_state(struct radeon_device *rdev) { @@ -5934,6 +5978,10 @@ static int si_thermal_setup_fan_table(struct radeon_device *rdev) slope1 = (u16)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100); slope2 = (u16)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100); + fan_table.temp_min = cpu_to_be16((50 + rdev->pm.dpm.fan.t_min) / 100); + fan_table.temp_med = cpu_to_be16((50 + rdev->pm.dpm.fan.t_med) / 100); + fan_table.temp_max = 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); @@ -5973,29 +6021,35 @@ static int si_thermal_setup_fan_table(struct radeon_device *rdev) static int si_fan_ctrl_start_smc_fan_control(struct radeon_device *rdev) { + struct si_power_info *si_pi = si_get_pi(rdev); PPSMC_Result ret; ret = si_send_msg_to_smc(rdev, PPSMC_StartFanControl); - if (ret == PPSMC_Result_OK) + if (ret == PPSMC_Result_OK) { + si_pi->fan_is_controlled_by_smc = true; return 0; - else + } else { return -EINVAL; + } } static int si_fan_ctrl_stop_smc_fan_control(struct radeon_device *rdev) { + struct si_power_info *si_pi = si_get_pi(rdev); PPSMC_Result ret; ret = si_send_msg_to_smc(rdev, PPSMC_StopFanControl); - if (ret == PPSMC_Result_OK) + + if (ret == PPSMC_Result_OK) { + si_pi->fan_is_controlled_by_smc = false; return 0; - else + } else { return -EINVAL; + } } -#if 0 -static int si_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev, - u32 *speed) +int si_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev, + u32 *speed) { u32 duty, duty100; u64 tmp64; @@ -6019,9 +6073,10 @@ static int si_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev, return 0; } -static int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev, - u32 speed) +int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev, + u32 speed) { + struct si_power_info *si_pi = si_get_pi(rdev); u32 tmp; u32 duty, duty100; u64 tmp64; @@ -6029,11 +6084,11 @@ static int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev, if (rdev->pm.no_fan) return -ENOENT; - if (speed > 100) + if (si_pi->fan_is_controlled_by_smc) return -EINVAL; - if (rdev->pm.dpm.fan.ucode_fan_control) - si_fan_ctrl_stop_smc_fan_control(rdev); + if (speed > 100) + return -EINVAL; duty100 = (RREG32(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT; @@ -6048,11 +6103,38 @@ static int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev, tmp |= FDO_STATIC_DUTY(duty); WREG32(CG_FDO_CTRL0, tmp); - si_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC); - return 0; } +void si_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode) +{ + if (mode) { + /* stop auto-manage */ + if (rdev->pm.dpm.fan.ucode_fan_control) + si_fan_ctrl_stop_smc_fan_control(rdev); + si_fan_ctrl_set_static_mode(rdev, mode); + } else { + /* restart auto-manage */ + if (rdev->pm.dpm.fan.ucode_fan_control) + si_thermal_start_smc_fan_control(rdev); + else + si_fan_ctrl_set_default_mode(rdev); + } +} + +u32 si_fan_ctrl_get_mode(struct radeon_device *rdev) +{ + struct si_power_info *si_pi = si_get_pi(rdev); + u32 tmp; + + if (si_pi->fan_is_controlled_by_smc) + return 0; + + tmp = RREG32(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK; + return (tmp >> FDO_PWM_MODE_SHIFT); +} + +#if 0 static int si_fan_ctrl_get_fan_speed_rpm(struct radeon_device *rdev, u32 *speed) { @@ -6499,13 +6581,14 @@ void si_dpm_post_set_power_state(struct radeon_device *rdev) ni_update_current_ps(rdev, new_ps); } - +#if 0 void si_dpm_reset_asic(struct radeon_device *rdev) { si_restrict_performance_levels_before_switch(rdev); si_disable_ulv(rdev); si_set_boot_state(rdev); } +#endif void si_dpm_display_configuration_changed(struct radeon_device *rdev) { @@ -6873,7 +6956,6 @@ int si_dpm_init(struct radeon_device *rdev) rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; si_pi->fan_ctrl_is_in_default_mode = true; - rdev->pm.dpm.fan.ucode_fan_control = false; return 0; } |