Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 5270 → Rev 5271

/drivers/video/drm/radeon/ci_dpm.c
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);
}