drm/radeon/dpm: add support for SVI2 voltage for SI

Some newer boards use SVI2 for voltage control rather
than GPIO.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Alex Deucher
2014-06-06 18:43:45 -04:00
parent a91576d791
commit 636e258265
5 changed files with 162 additions and 43 deletions

View File

@@ -3812,6 +3812,27 @@ void si_trim_voltage_table_to_fit_state_table(struct radeon_device *rdev,
voltage_table->count = max_voltage_steps;
}
static int si_get_svi2_voltage_table(struct radeon_device *rdev,
struct radeon_clock_voltage_dependency_table *voltage_dependency_table,
struct atom_voltage_table *voltage_table)
{
u32 i;
if (voltage_dependency_table == NULL)
return -EINVAL;
voltage_table->mask_low = 0;
voltage_table->phase_delay = 0;
voltage_table->count = voltage_dependency_table->count;
for (i = 0; i < voltage_table->count; i++) {
voltage_table->entries[i].value = voltage_dependency_table->entries[i].v;
voltage_table->entries[i].smio_low = 0;
}
return 0;
}
static int si_construct_voltage_tables(struct radeon_device *rdev)
{
struct rv7xx_power_info *pi = rv770_get_pi(rdev);
@@ -3819,15 +3840,25 @@ static int si_construct_voltage_tables(struct radeon_device *rdev)
struct si_power_info *si_pi = si_get_pi(rdev);
int ret;
ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_VDDC,
VOLTAGE_OBJ_GPIO_LUT, &eg_pi->vddc_voltage_table);
if (ret)
return ret;
if (pi->voltage_control) {
ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_VDDC,
VOLTAGE_OBJ_GPIO_LUT, &eg_pi->vddc_voltage_table);
if (ret)
return ret;
if (eg_pi->vddc_voltage_table.count > SISLANDS_MAX_NO_VREG_STEPS)
si_trim_voltage_table_to_fit_state_table(rdev,
SISLANDS_MAX_NO_VREG_STEPS,
&eg_pi->vddc_voltage_table);
if (eg_pi->vddc_voltage_table.count > SISLANDS_MAX_NO_VREG_STEPS)
si_trim_voltage_table_to_fit_state_table(rdev,
SISLANDS_MAX_NO_VREG_STEPS,
&eg_pi->vddc_voltage_table);
} else if (si_pi->voltage_control_svi2) {
ret = si_get_svi2_voltage_table(rdev,
&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
&eg_pi->vddc_voltage_table);
if (ret)
return ret;
} else {
return -EINVAL;
}
if (eg_pi->vddci_control) {
ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_VDDCI,
@@ -3840,6 +3871,13 @@ static int si_construct_voltage_tables(struct radeon_device *rdev)
SISLANDS_MAX_NO_VREG_STEPS,
&eg_pi->vddci_voltage_table);
}
if (si_pi->vddci_control_svi2) {
ret = si_get_svi2_voltage_table(rdev,
&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
&eg_pi->vddci_voltage_table);
if (ret)
return ret;
}
if (pi->mvdd_control) {
ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_MVDDC,
@@ -3893,46 +3931,55 @@ static int si_populate_smc_voltage_tables(struct radeon_device *rdev,
struct si_power_info *si_pi = si_get_pi(rdev);
u8 i;
if (eg_pi->vddc_voltage_table.count) {
si_populate_smc_voltage_table(rdev, &eg_pi->vddc_voltage_table, table);
table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC] =
cpu_to_be32(eg_pi->vddc_voltage_table.mask_low);
if (si_pi->voltage_control_svi2) {
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svc,
si_pi->svc_gpio_id);
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svd,
si_pi->svd_gpio_id);
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_svi_rework_plat_type,
2);
} else {
if (eg_pi->vddc_voltage_table.count) {
si_populate_smc_voltage_table(rdev, &eg_pi->vddc_voltage_table, table);
table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC] =
cpu_to_be32(eg_pi->vddc_voltage_table.mask_low);
for (i = 0; i < eg_pi->vddc_voltage_table.count; i++) {
if (pi->max_vddc_in_table <= eg_pi->vddc_voltage_table.entries[i].value) {
table->maxVDDCIndexInPPTable = i;
break;
for (i = 0; i < eg_pi->vddc_voltage_table.count; i++) {
if (pi->max_vddc_in_table <= eg_pi->vddc_voltage_table.entries[i].value) {
table->maxVDDCIndexInPPTable = i;
break;
}
}
}
}
if (eg_pi->vddci_voltage_table.count) {
si_populate_smc_voltage_table(rdev, &eg_pi->vddci_voltage_table, table);
if (eg_pi->vddci_voltage_table.count) {
si_populate_smc_voltage_table(rdev, &eg_pi->vddci_voltage_table, table);
table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDCI] =
cpu_to_be32(eg_pi->vddci_voltage_table.mask_low);
}
table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDCI] =
cpu_to_be32(eg_pi->vddci_voltage_table.mask_low);
}
if (si_pi->mvdd_voltage_table.count) {
si_populate_smc_voltage_table(rdev, &si_pi->mvdd_voltage_table, table);
if (si_pi->mvdd_voltage_table.count) {
si_populate_smc_voltage_table(rdev, &si_pi->mvdd_voltage_table, table);
table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_MVDD] =
cpu_to_be32(si_pi->mvdd_voltage_table.mask_low);
}
table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_MVDD] =
cpu_to_be32(si_pi->mvdd_voltage_table.mask_low);
}
if (si_pi->vddc_phase_shed_control) {
if (si_validate_phase_shedding_tables(rdev, &si_pi->vddc_phase_shed_table,
&rdev->pm.dpm.dyn_state.phase_shedding_limits_table)) {
si_populate_smc_voltage_table(rdev, &si_pi->vddc_phase_shed_table, table);
if (si_pi->vddc_phase_shed_control) {
if (si_validate_phase_shedding_tables(rdev, &si_pi->vddc_phase_shed_table,
&rdev->pm.dpm.dyn_state.phase_shedding_limits_table)) {
si_populate_smc_voltage_table(rdev, &si_pi->vddc_phase_shed_table, table);
table->phaseMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC] =
cpu_to_be32(si_pi->vddc_phase_shed_table.mask_low);
table->phaseMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC] =
cpu_to_be32(si_pi->vddc_phase_shed_table.mask_low);
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_phase_shedding_delay,
(u32)si_pi->vddc_phase_shed_table.phase_delay);
} else {
si_pi->vddc_phase_shed_control = false;
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_phase_shedding_delay,
(u32)si_pi->vddc_phase_shed_table.phase_delay);
} else {
si_pi->vddc_phase_shed_control = false;
}
}
}
@@ -5798,16 +5845,17 @@ int si_dpm_enable(struct radeon_device *rdev)
{
struct rv7xx_power_info *pi = rv770_get_pi(rdev);
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
struct si_power_info *si_pi = si_get_pi(rdev);
struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
int ret;
if (si_is_smc_running(rdev))
return -EINVAL;
if (pi->voltage_control)
if (pi->voltage_control || si_pi->voltage_control_svi2)
si_enable_voltage_control(rdev, true);
if (pi->mvdd_control)
si_get_mvdd_configuration(rdev);
if (pi->voltage_control) {
if (pi->voltage_control || si_pi->voltage_control_svi2) {
ret = si_construct_voltage_tables(rdev);
if (ret) {
DRM_ERROR("si_construct_voltage_tables failed\n");
@@ -6406,16 +6454,32 @@ int si_dpm_init(struct radeon_device *rdev)
ni_pi->mclk_rtt_mode_threshold = eg_pi->mclk_edc_wr_enable_threshold;
pi->voltage_control =
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, VOLTAGE_OBJ_GPIO_LUT);
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC,
VOLTAGE_OBJ_GPIO_LUT);
if (!pi->voltage_control) {
si_pi->voltage_control_svi2 =
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC,
VOLTAGE_OBJ_SVID2);
if (si_pi->voltage_control_svi2)
radeon_atom_get_svi2_info(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC,
&si_pi->svd_gpio_id, &si_pi->svc_gpio_id);
}
pi->mvdd_control =
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC, VOLTAGE_OBJ_GPIO_LUT);
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC,
VOLTAGE_OBJ_GPIO_LUT);
eg_pi->vddci_control =
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, VOLTAGE_OBJ_GPIO_LUT);
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI,
VOLTAGE_OBJ_GPIO_LUT);
if (!eg_pi->vddci_control)
si_pi->vddci_control_svi2 =
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI,
VOLTAGE_OBJ_SVID2);
si_pi->vddc_phase_shed_control =
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, VOLTAGE_OBJ_PHASE_LUT);
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC,
VOLTAGE_OBJ_PHASE_LUT);
rv770_get_engine_memory_ss(rdev);