24,6 → 24,7 |
#include <linux/firmware.h> |
#include "drmP.h" |
#include "radeon.h" |
#include "radeon_asic.h" |
#include "radeon_ucode.h" |
#include "cikd.h" |
#include "r600_dpm.h" |
45,15 → 46,15 |
static const struct ci_pt_defaults defaults_hawaii_xt = |
{ |
1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0xB0000, |
{ 0x84, 0x0, 0x0, 0x7F, 0x0, 0x0, 0x5A, 0x60, 0x51, 0x8E, 0x79, 0x6B, 0x5F, 0x90, 0x79 }, |
{ 0x1EA, 0x1EA, 0x1EA, 0x224, 0x224, 0x224, 0x24F, 0x24F, 0x24F, 0x28E, 0x28E, 0x28E, 0x2BC, 0x2BC, 0x2BC } |
{ 0x2E, 0x00, 0x00, 0x88, 0x00, 0x00, 0x72, 0x60, 0x51, 0xA7, 0x79, 0x6B, 0x90, 0xBD, 0x79 }, |
{ 0x217, 0x217, 0x217, 0x242, 0x242, 0x242, 0x269, 0x269, 0x269, 0x2A1, 0x2A1, 0x2A1, 0x2C9, 0x2C9, 0x2C9 } |
}; |
|
static const struct ci_pt_defaults defaults_hawaii_pro = |
{ |
1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0x65062, |
{ 0x93, 0x0, 0x0, 0x97, 0x0, 0x0, 0x6B, 0x60, 0x51, 0x95, 0x79, 0x6B, 0x5F, 0x90, 0x79 }, |
{ 0x1EA, 0x1EA, 0x1EA, 0x224, 0x224, 0x224, 0x24F, 0x24F, 0x24F, 0x28E, 0x28E, 0x28E, 0x2BC, 0x2BC, 0x2BC } |
{ 0x2E, 0x00, 0x00, 0x88, 0x00, 0x00, 0x72, 0x60, 0x51, 0xA7, 0x79, 0x6B, 0x90, 0xBD, 0x79 }, |
{ 0x217, 0x217, 0x217, 0x242, 0x242, 0x242, 0x269, 0x269, 0x269, 0x2A1, 0x2A1, 0x2A1, 0x2C9, 0x2C9, 0x2C9 } |
}; |
|
static const struct ci_pt_defaults defaults_bonaire_xt = |
162,8 → 163,6 |
}; |
|
extern u8 rv770_get_memory_module_index(struct radeon_device *rdev); |
extern void btc_get_max_clock_from_voltage_dependency_table(struct radeon_clock_voltage_dependency_table *table, |
u32 *max_clock); |
extern int ni_copy_and_switch_arb_sets(struct radeon_device *rdev, |
u32 arb_freq_src, u32 arb_freq_dest); |
extern u8 si_get_ddr3_mclk_frequency_ratio(u32 memory_clock); |
185,6 → 184,9 |
u32 target_tdp); |
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) |
{ |
struct ci_power_info *pi = rdev->pm.dpm.priv; |
250,6 → 252,9 |
|
if (pi->caps_power_containment) { |
pi->caps_cac = true; |
if (rdev->family == CHIP_HAWAII) |
pi->enable_bapm_feature = false; |
else |
pi->enable_bapm_feature = true; |
pi->enable_tdc_limit_feature = true; |
pi->enable_pkg_pwr_tracking_feature = true; |
353,6 → 358,21 |
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) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
478,6 → 498,9 |
ret = ci_populate_dw8(rdev); |
if (ret) |
return ret; |
ret = ci_populate_fuzzy_fan(rdev); |
if (ret) |
return ret; |
ret = ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(rdev); |
if (ret) |
return ret; |
691,6 → 714,25 |
return ret; |
} |
|
static int ci_enable_thermal_based_sclk_dpm(struct radeon_device *rdev, |
bool enable) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
PPSMC_Result smc_result = PPSMC_Result_OK; |
|
if (pi->thermal_sclk_dpm_enabled) { |
if (enable) |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_ENABLE_THERMAL_DPM); |
else |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_DISABLE_THERMAL_DPM); |
} |
|
if (smc_result == PPSMC_Result_OK) |
return 0; |
else |
return -EINVAL; |
} |
|
static int ci_power_control_set_level(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
701,13 → 743,11 |
int ret = 0; |
bool adjust_polarity = false; /* ??? */ |
|
if (pi->caps_power_containment && |
(pi->power_containment_features & POWERCONTAINMENT_FEATURE_BAPM)) { |
if (pi->caps_power_containment) { |
adjust_percent = adjust_polarity ? |
rdev->pm.dpm.tdp_adjustment : (-1 * rdev->pm.dpm.tdp_adjustment); |
target_tdp = ((100 + adjust_percent) * |
(s32)cac_tdp_table->configurable_tdp) / 100; |
target_tdp *= 256; |
|
ret = ci_set_overdrive_target_tdp(rdev, (u32)target_tdp); |
} |
748,7 → 788,6 |
struct radeon_clock_and_voltage_limits *max_limits; |
bool disable_mclk_switching; |
u32 sclk, mclk; |
u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc; |
int i; |
|
if (rps->vce_active) { |
784,29 → 823,6 |
} |
} |
|
/* limit clocks to max supported clocks based on voltage dependency tables */ |
btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk, |
&max_sclk_vddc); |
btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk, |
&max_mclk_vddci); |
btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk, |
&max_mclk_vddc); |
|
for (i = 0; i < ps->performance_level_count; i++) { |
if (max_sclk_vddc) { |
if (ps->performance_levels[i].sclk > max_sclk_vddc) |
ps->performance_levels[i].sclk = max_sclk_vddc; |
} |
if (max_mclk_vddci) { |
if (ps->performance_levels[i].mclk > max_mclk_vddci) |
ps->performance_levels[i].mclk = max_mclk_vddci; |
} |
if (max_mclk_vddc) { |
if (ps->performance_levels[i].mclk > max_mclk_vddc) |
ps->performance_levels[i].mclk = max_mclk_vddc; |
} |
} |
|
/* XXX validate the min clocks required for display */ |
|
if (disable_mclk_switching) { |
839,7 → 855,7 |
} |
} |
|
static int ci_set_thermal_temperature_range(struct radeon_device *rdev, |
static int ci_thermal_set_temperature_range(struct radeon_device *rdev, |
int min_temp, int max_temp) |
{ |
int low_temp = 0 * 1000; |
875,7 → 891,351 |
return 0; |
} |
|
static int ci_thermal_enable_alert(struct radeon_device *rdev, |
bool enable) |
{ |
u32 thermal_int = RREG32_SMC(CG_THERMAL_INT); |
PPSMC_Result result; |
|
if (enable) { |
thermal_int &= ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW); |
WREG32_SMC(CG_THERMAL_INT, thermal_int); |
rdev->irq.dpm_thermal = false; |
result = ci_send_msg_to_smc(rdev, PPSMC_MSG_Thermal_Cntl_Enable); |
if (result != PPSMC_Result_OK) { |
DRM_DEBUG_KMS("Could not enable thermal interrupts.\n"); |
return -EINVAL; |
} |
} else { |
thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW; |
WREG32_SMC(CG_THERMAL_INT, thermal_int); |
rdev->irq.dpm_thermal = true; |
result = ci_send_msg_to_smc(rdev, PPSMC_MSG_Thermal_Cntl_Disable); |
if (result != PPSMC_Result_OK) { |
DRM_DEBUG_KMS("Could not disable thermal interrupts.\n"); |
return -EINVAL; |
} |
} |
|
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; |
} |
|
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_RPM); |
|
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 |
static int ci_read_smc_soft_register(struct radeon_device *rdev, |
u16 reg_offset, u32 *value) |
{ |
1278,7 → 1638,7 |
|
if (!pi->sclk_dpm_key_disabled) { |
PPSMC_Result smc_result = |
ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_DPM_ForceState, n); |
ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SCLKDPM_SetEnabledMask, 1 << n); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
} |
1292,7 → 1652,7 |
|
if (!pi->mclk_dpm_key_disabled) { |
PPSMC_Result smc_result = |
ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_MCLKDPM_ForceState, n); |
ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_MCLKDPM_SetEnabledMask, 1 << n); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
} |
2067,6 → 2427,33 |
return ni_copy_and_switch_arb_sets(rdev, tmp, MC_CG_ARB_FREQ_F0); |
} |
|
static void ci_register_patching_mc_arb(struct radeon_device *rdev, |
const u32 engine_clock, |
const u32 memory_clock, |
u32 *dram_timimg2) |
{ |
bool patch; |
u32 tmp, tmp2; |
|
tmp = RREG32(MC_SEQ_MISC0); |
patch = ((tmp & 0x0000f00) == 0x300) ? true : false; |
|
if (patch && |
((rdev->pdev->device == 0x67B0) || |
(rdev->pdev->device == 0x67B1))) { |
if ((memory_clock > 100000) && (memory_clock <= 125000)) { |
tmp2 = (((0x31 * engine_clock) / 125000) - 1) & 0xff; |
*dram_timimg2 &= ~0x00ff0000; |
*dram_timimg2 |= tmp2 << 16; |
} else if ((memory_clock > 125000) && (memory_clock <= 137500)) { |
tmp2 = (((0x36 * engine_clock) / 137500) - 1) & 0xff; |
*dram_timimg2 &= ~0x00ff0000; |
*dram_timimg2 |= tmp2 << 16; |
} |
} |
} |
|
|
static int ci_populate_memory_timing_parameters(struct radeon_device *rdev, |
u32 sclk, |
u32 mclk, |
2082,6 → 2469,8 |
dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2); |
burst_time = RREG32(MC_ARB_BURST_TIME) & STATE0_MASK; |
|
ci_register_patching_mc_arb(rdev, sclk, mclk, &dram_timing2); |
|
arb_regs->McArbDramTiming = cpu_to_be32(dram_timing); |
arb_regs->McArbDramTiming2 = cpu_to_be32(dram_timing2); |
arb_regs->McArbBurstTime = (u8)burst_time; |
2376,10 → 2765,10 |
u32 tmp; |
u32 reference_clock = rdev->clock.mpll.reference_freq; |
|
if (pi->mem_gddr5) |
freq_nom = memory_clock * 4; |
if (mpll_param.qdr == 1) |
freq_nom = memory_clock * 4 * (1 << mpll_param.post_div); |
else |
freq_nom = memory_clock * 2; |
freq_nom = memory_clock * 2 * (1 << mpll_param.post_div); |
|
tmp = (freq_nom / reference_clock); |
tmp = tmp * tmp; |
2459,7 → 2848,6 |
&memory_level->MinVddcPhases); |
|
memory_level->EnabledForThrottle = 1; |
memory_level->EnabledForActivity = 1; |
memory_level->UpH = 0; |
memory_level->DownH = 100; |
memory_level->VoltageDownH = 0; |
2792,7 → 3180,6 |
|
graphic_level->CcPwrDynRm = 0; |
graphic_level->CcPwrDynRm1 = 0; |
graphic_level->EnabledForActivity = 1; |
graphic_level->EnabledForThrottle = 1; |
graphic_level->UpH = 0; |
graphic_level->DownH = 0; |
2841,10 → 3228,13 |
&pi->smc_state_table.GraphicsLevel[i]); |
if (ret) |
return ret; |
if (i > 1) |
pi->smc_state_table.GraphicsLevel[i].DeepSleepDivId = 0; |
if (i == (dpm_table->sclk_table.count - 1)) |
pi->smc_state_table.GraphicsLevel[i].DisplayWatermark = |
PPSMC_DISPLAY_WATERMARK_HIGH; |
} |
pi->smc_state_table.GraphicsLevel[0].EnabledForActivity = 1; |
|
pi->smc_state_table.GraphicsDpmLevelCount = (u8)dpm_table->sclk_table.count; |
pi->dpm_level_enable_mask.sclk_dpm_enable_mask = |
2888,6 → 3278,16 |
return ret; |
} |
|
pi->smc_state_table.MemoryLevel[0].EnabledForActivity = 1; |
|
if ((dpm_table->mclk_table.count >= 2) && |
((rdev->pdev->device == 0x67B0) || (rdev->pdev->device == 0x67B1))) { |
pi->smc_state_table.MemoryLevel[1].MinVddc = |
pi->smc_state_table.MemoryLevel[0].MinVddc; |
pi->smc_state_table.MemoryLevel[1].MinVddcPhases = |
pi->smc_state_table.MemoryLevel[0].MinVddcPhases; |
} |
|
pi->smc_state_table.MemoryLevel[0].ActivityLevel = cpu_to_be16(0x1F); |
|
pi->smc_state_table.MemoryDpmLevelCount = (u8)dpm_table->mclk_table.count; |
2944,8 → 3344,13 |
&pi->dpm_table.pcie_speed_table, |
SMU7_MAX_LEVELS_LINK); |
|
if (rdev->family == CHIP_BONAIRE) |
ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 0, |
pi->pcie_gen_powersaving.min, |
pi->pcie_lane_powersaving.max); |
else |
ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 0, |
pi->pcie_gen_powersaving.min, |
pi->pcie_lane_powersaving.min); |
ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 1, |
pi->pcie_gen_performance.min, |
3013,7 → 3418,8 |
allowed_sclk_vddc_table->entries[i].clk)) { |
pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count].value = |
allowed_sclk_vddc_table->entries[i].clk; |
pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count].enabled = true; |
pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count].enabled = |
(i == 0) ? true : false; |
pi->dpm_table.sclk_table.count++; |
} |
} |
3025,7 → 3431,8 |
allowed_mclk_table->entries[i].clk)) { |
pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count].value = |
allowed_mclk_table->entries[i].clk; |
pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count].enabled = true; |
pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count].enabled = |
(i == 0) ? true : false; |
pi->dpm_table.mclk_table.count++; |
} |
} |
3191,7 → 3598,7 |
table->VddcVddciDelta = 4000; |
table->PhaseResponseTime = 0; |
table->MemoryThermThrottleEnable = 1; |
table->PCIeBootLinkLevel = 0; |
table->PCIeBootLinkLevel = pi->dpm_table.pcie_speed_table.count - 1; |
table->PCIeGenInterval = 1; |
if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2) |
table->SVI2Enable = 1; |
3345,6 → 3752,8 |
struct ci_power_info *pi = ci_get_pi(rdev); |
PPSMC_Result result; |
|
ci_apply_disp_minimum_voltage_request(rdev); |
|
if (!pi->sclk_dpm_key_disabled) { |
if (pi->dpm_level_enable_mask.sclk_dpm_enable_mask) { |
result = ci_send_msg_to_smc_with_parameter(rdev, |
3364,7 → 3773,7 |
return -EINVAL; |
} |
} |
|
#if 0 |
if (!pi->pcie_dpm_key_disabled) { |
if (pi->dpm_level_enable_mask.pcie_dpm_enable_mask) { |
result = ci_send_msg_to_smc_with_parameter(rdev, |
3374,9 → 3783,7 |
return -EINVAL; |
} |
} |
|
ci_apply_disp_minimum_voltage_request(rdev); |
|
#endif |
return 0; |
} |
|
3402,7 → 3809,7 |
pi->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK; |
} else { |
/* XXX check display min clock requirements */ |
if (0 != CISLAND_MINIMUM_ENGINE_CLOCK) |
if (CISLAND_MINIMUM_ENGINE_CLOCK != CISLAND_MINIMUM_ENGINE_CLOCK) |
pi->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_SCLK; |
} |
|
3732,24 → 4139,23 |
enum radeon_dpm_forced_level level) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
PPSMC_Result smc_result; |
u32 tmp, levels, i; |
int ret; |
|
if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { |
if ((!pi->sclk_dpm_key_disabled) && |
pi->dpm_level_enable_mask.sclk_dpm_enable_mask) { |
if ((!pi->pcie_dpm_key_disabled) && |
pi->dpm_level_enable_mask.pcie_dpm_enable_mask) { |
levels = 0; |
tmp = pi->dpm_level_enable_mask.sclk_dpm_enable_mask; |
tmp = pi->dpm_level_enable_mask.pcie_dpm_enable_mask; |
while (tmp >>= 1) |
levels++; |
if (levels) { |
ret = ci_dpm_force_state_sclk(rdev, levels); |
ret = ci_dpm_force_state_pcie(rdev, level); |
if (ret) |
return ret; |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) & |
CURR_SCLK_INDEX_MASK) >> CURR_SCLK_INDEX_SHIFT; |
tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX_1) & |
CURR_PCIE_INDEX_MASK) >> CURR_PCIE_INDEX_SHIFT; |
if (tmp == levels) |
break; |
udelay(1); |
3756,19 → 4162,19 |
} |
} |
} |
if ((!pi->mclk_dpm_key_disabled) && |
pi->dpm_level_enable_mask.mclk_dpm_enable_mask) { |
if ((!pi->sclk_dpm_key_disabled) && |
pi->dpm_level_enable_mask.sclk_dpm_enable_mask) { |
levels = 0; |
tmp = pi->dpm_level_enable_mask.mclk_dpm_enable_mask; |
tmp = pi->dpm_level_enable_mask.sclk_dpm_enable_mask; |
while (tmp >>= 1) |
levels++; |
if (levels) { |
ret = ci_dpm_force_state_mclk(rdev, levels); |
ret = ci_dpm_force_state_sclk(rdev, levels); |
if (ret) |
return ret; |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) & |
CURR_MCLK_INDEX_MASK) >> CURR_MCLK_INDEX_SHIFT; |
CURR_SCLK_INDEX_MASK) >> CURR_SCLK_INDEX_SHIFT; |
if (tmp == levels) |
break; |
udelay(1); |
3775,19 → 4181,19 |
} |
} |
} |
if ((!pi->pcie_dpm_key_disabled) && |
pi->dpm_level_enable_mask.pcie_dpm_enable_mask) { |
if ((!pi->mclk_dpm_key_disabled) && |
pi->dpm_level_enable_mask.mclk_dpm_enable_mask) { |
levels = 0; |
tmp = pi->dpm_level_enable_mask.pcie_dpm_enable_mask; |
tmp = pi->dpm_level_enable_mask.mclk_dpm_enable_mask; |
while (tmp >>= 1) |
levels++; |
if (levels) { |
ret = ci_dpm_force_state_pcie(rdev, level); |
ret = ci_dpm_force_state_mclk(rdev, levels); |
if (ret) |
return ret; |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX_1) & |
CURR_PCIE_INDEX_MASK) >> CURR_PCIE_INDEX_SHIFT; |
tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) & |
CURR_MCLK_INDEX_MASK) >> CURR_MCLK_INDEX_SHIFT; |
if (tmp == levels) |
break; |
udelay(1); |
3841,21 → 4247,17 |
} |
} |
} else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) { |
if (!pi->sclk_dpm_key_disabled) { |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_NoForcedLevel); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
} |
if (!pi->mclk_dpm_key_disabled) { |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_MCLKDPM_NoForcedLevel); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
} |
if (!pi->pcie_dpm_key_disabled) { |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_PCIeDPM_UnForceLevel); |
PPSMC_Result smc_result; |
|
smc_result = ci_send_msg_to_smc(rdev, |
PPSMC_MSG_PCIeDPM_UnForceLevel); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
} |
ret = ci_upload_dpm_level_enable_mask(rdev); |
if (ret) |
return ret; |
} |
|
rdev->pm.dpm.forced_level = level; |
4061,6 → 4463,96 |
return 0; |
} |
|
static int ci_register_patching_mc_seq(struct radeon_device *rdev, |
struct ci_mc_reg_table *table) |
{ |
u8 i, k; |
u32 tmp; |
bool patch; |
|
tmp = RREG32(MC_SEQ_MISC0); |
patch = ((tmp & 0x0000f00) == 0x300) ? true : false; |
|
if (patch && |
((rdev->pdev->device == 0x67B0) || |
(rdev->pdev->device == 0x67B1))) { |
for (i = 0; i < table->last; i++) { |
if (table->last >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
switch(table->mc_reg_address[i].s1 >> 2) { |
case MC_SEQ_MISC1: |
for (k = 0; k < table->num_entries; k++) { |
if ((table->mc_reg_table_entry[k].mclk_max == 125000) || |
(table->mc_reg_table_entry[k].mclk_max == 137500)) |
table->mc_reg_table_entry[k].mc_data[i] = |
(table->mc_reg_table_entry[k].mc_data[i] & 0xFFFFFFF8) | |
0x00000007; |
} |
break; |
case MC_SEQ_WR_CTL_D0: |
for (k = 0; k < table->num_entries; k++) { |
if ((table->mc_reg_table_entry[k].mclk_max == 125000) || |
(table->mc_reg_table_entry[k].mclk_max == 137500)) |
table->mc_reg_table_entry[k].mc_data[i] = |
(table->mc_reg_table_entry[k].mc_data[i] & 0xFFFF0F00) | |
0x0000D0DD; |
} |
break; |
case MC_SEQ_WR_CTL_D1: |
for (k = 0; k < table->num_entries; k++) { |
if ((table->mc_reg_table_entry[k].mclk_max == 125000) || |
(table->mc_reg_table_entry[k].mclk_max == 137500)) |
table->mc_reg_table_entry[k].mc_data[i] = |
(table->mc_reg_table_entry[k].mc_data[i] & 0xFFFF0F00) | |
0x0000D0DD; |
} |
break; |
case MC_SEQ_WR_CTL_2: |
for (k = 0; k < table->num_entries; k++) { |
if ((table->mc_reg_table_entry[k].mclk_max == 125000) || |
(table->mc_reg_table_entry[k].mclk_max == 137500)) |
table->mc_reg_table_entry[k].mc_data[i] = 0; |
} |
break; |
case MC_SEQ_CAS_TIMING: |
for (k = 0; k < table->num_entries; k++) { |
if (table->mc_reg_table_entry[k].mclk_max == 125000) |
table->mc_reg_table_entry[k].mc_data[i] = |
(table->mc_reg_table_entry[k].mc_data[i] & 0xFFE0FE0F) | |
0x000C0140; |
else if (table->mc_reg_table_entry[k].mclk_max == 137500) |
table->mc_reg_table_entry[k].mc_data[i] = |
(table->mc_reg_table_entry[k].mc_data[i] & 0xFFE0FE0F) | |
0x000C0150; |
} |
break; |
case MC_SEQ_MISC_TIMING: |
for (k = 0; k < table->num_entries; k++) { |
if (table->mc_reg_table_entry[k].mclk_max == 125000) |
table->mc_reg_table_entry[k].mc_data[i] = |
(table->mc_reg_table_entry[k].mc_data[i] & 0xFFFFFFE0) | |
0x00000030; |
else if (table->mc_reg_table_entry[k].mclk_max == 137500) |
table->mc_reg_table_entry[k].mc_data[i] = |
(table->mc_reg_table_entry[k].mc_data[i] & 0xFFFFFFE0) | |
0x00000035; |
} |
break; |
default: |
break; |
} |
} |
|
WREG32(MC_SEQ_IO_DEBUG_INDEX, 3); |
tmp = RREG32(MC_SEQ_IO_DEBUG_DATA); |
tmp = (tmp & 0xFFF8FFFF) | (1 << 16); |
WREG32(MC_SEQ_IO_DEBUG_INDEX, 3); |
WREG32(MC_SEQ_IO_DEBUG_DATA, tmp); |
} |
|
return 0; |
} |
|
static int ci_initialize_mc_reg_table(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
4104,6 → 4596,10 |
|
ci_set_s0_mc_reg_index(ci_table); |
|
ret = ci_register_patching_mc_seq(rdev, ci_table); |
if (ret) |
goto init_mc_done; |
|
ret = ci_set_mc_special_registers(rdev, ci_table); |
if (ret) |
goto init_mc_done; |
4700,37 → 5196,52 |
return ret; |
} |
|
ret = ci_power_control_set_level(rdev); |
if (ret) { |
DRM_ERROR("ci_power_control_set_level failed\n"); |
return ret; |
} |
|
ci_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); |
|
ret = ci_enable_thermal_based_sclk_dpm(rdev, true); |
if (ret) { |
DRM_ERROR("ci_enable_thermal_based_sclk_dpm failed\n"); |
return ret; |
} |
|
ci_thermal_start_thermal_controller(rdev); |
|
ci_update_current_ps(rdev, boot_ps); |
|
return 0; |
} |
|
int ci_dpm_late_enable(struct radeon_device *rdev) |
static int ci_set_temperature_range(struct radeon_device *rdev) |
{ |
int ret; |
|
if (rdev->irq.installed && |
r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { |
#if 0 |
PPSMC_Result result; |
#endif |
ret = ci_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); |
if (ret) { |
DRM_ERROR("ci_set_thermal_temperature_range failed\n"); |
ret = ci_thermal_enable_alert(rdev, false); |
if (ret) |
return ret; |
} |
rdev->irq.dpm_thermal = true; |
radeon_irq_set(rdev); |
#if 0 |
result = ci_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt); |
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 (result != PPSMC_Result_OK) |
DRM_DEBUG_KMS("Could not enable thermal interrupts.\n"); |
#endif |
return ret; |
} |
|
int ci_dpm_late_enable(struct radeon_device *rdev) |
{ |
int ret; |
|
ret = ci_set_temperature_range(rdev); |
if (ret) |
return ret; |
|
ci_dpm_powergate_uvd(rdev, true); |
|
return 0; |
4746,6 → 5257,8 |
if (!ci_is_smc_running(rdev)) |
return; |
|
ci_thermal_stop_thermal_controller(rdev); |
|
if (pi->thermal_protection) |
ci_enable_thermal_protection(rdev, false); |
ci_enable_power_containment(rdev, false); |
4754,12 → 5267,13 |
ci_enable_spread_spectrum(rdev, false); |
ci_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, false); |
ci_stop_dpm(rdev); |
ci_enable_ds_master_switch(rdev, true); |
ci_enable_ds_master_switch(rdev, false); |
ci_enable_ulv(rdev, false); |
ci_clear_vc(rdev); |
ci_reset_to_default(rdev); |
ci_dpm_stop_smc(rdev); |
ci_force_switch_to_arb_f0(rdev); |
ci_enable_thermal_based_sclk_dpm(rdev, false); |
|
ci_update_current_ps(rdev, boot_ps); |
} |
4829,11 → 5343,6 |
return 0; |
} |
|
int ci_dpm_power_control_set_level(struct radeon_device *rdev) |
{ |
return ci_power_control_set_level(rdev); |
} |
|
void ci_dpm_reset_asic(struct radeon_device *rdev) |
{ |
ci_set_boot_state(rdev); |
5093,6 → 5602,8 |
int ci_dpm_init(struct radeon_device *rdev) |
{ |
int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info); |
SMU7_Discrete_DpmTable *dpm_table; |
struct radeon_gpio_rec gpio; |
u16 data_offset, size; |
u8 frev, crev; |
struct ci_power_info *pi; |
5162,6 → 5673,7 |
pi->sclk_dpm_key_disabled = 0; |
pi->mclk_dpm_key_disabled = 0; |
pi->pcie_dpm_key_disabled = 0; |
pi->thermal_sclk_dpm_enabled = 0; |
|
/* mclk dpm is unstable on some R7 260X cards with the old mc ucode */ |
if ((rdev->pdev->device == 0x6658) && |
5226,6 → 5738,55 |
|
pi->uvd_enabled = false; |
|
dpm_table = &pi->smc_state_table; |
|
gpio = radeon_atombios_lookup_gpio(rdev, VDDC_VRHOT_GPIO_PINID); |
if (gpio.valid) { |
dpm_table->VRHotGpio = gpio.shift; |
rdev->pm.dpm.platform_caps |= ATOM_PP_PLATFORM_CAP_REGULATOR_HOT; |
} else { |
dpm_table->VRHotGpio = CISLANDS_UNUSED_GPIO_PIN; |
rdev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_REGULATOR_HOT; |
} |
|
gpio = radeon_atombios_lookup_gpio(rdev, PP_AC_DC_SWITCH_GPIO_PINID); |
if (gpio.valid) { |
dpm_table->AcDcGpio = gpio.shift; |
rdev->pm.dpm.platform_caps |= ATOM_PP_PLATFORM_CAP_HARDWAREDC; |
} else { |
dpm_table->AcDcGpio = CISLANDS_UNUSED_GPIO_PIN; |
rdev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_HARDWAREDC; |
} |
|
gpio = radeon_atombios_lookup_gpio(rdev, VDDC_PCC_GPIO_PINID); |
if (gpio.valid) { |
u32 tmp = RREG32_SMC(CNB_PWRMGT_CNTL); |
|
switch (gpio.shift) { |
case 0: |
tmp &= ~GNB_SLOW_MODE_MASK; |
tmp |= GNB_SLOW_MODE(1); |
break; |
case 1: |
tmp &= ~GNB_SLOW_MODE_MASK; |
tmp |= GNB_SLOW_MODE(2); |
break; |
case 2: |
tmp |= GNB_SLOW; |
break; |
case 3: |
tmp |= FORCE_NB_PS1; |
break; |
case 4: |
tmp |= DPM_ENABLED; |
break; |
default: |
DRM_ERROR("Invalid PCC GPIO: %u!\n", gpio.shift); |
break; |
} |
WREG32_SMC(CNB_PWRMGT_CNTL, tmp); |
} |
|
pi->voltage_control = CISLANDS_VOLTAGE_CONTROL_NONE; |
pi->vddci_control = CISLANDS_VOLTAGE_CONTROL_NONE; |
pi->mvdd_control = CISLANDS_VOLTAGE_CONTROL_NONE; |
5287,6 → 5848,8 |
rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc = |
rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; |
|
pi->fan_ctrl_is_in_default_mode = true; |
|
return 0; |
} |
|
5293,9 → 5856,13 |
void ci_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, |
struct seq_file *m) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct radeon_ps *rps = &pi->current_rps; |
u32 sclk = ci_get_average_sclk_freq(rdev); |
u32 mclk = ci_get_average_mclk_freq(rdev); |
|
seq_printf(m, "uvd %sabled\n", pi->uvd_enabled ? "en" : "dis"); |
seq_printf(m, "vce %sabled\n", rps->vce_active ? "en" : "dis"); |
seq_printf(m, "power level avg sclk: %u mclk: %u\n", |
sclk, mclk); |
} |