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:
@@ -317,6 +317,9 @@ int radeon_atom_get_voltage_table(struct radeon_device *rdev,
|
|||||||
struct atom_voltage_table *voltage_table);
|
struct atom_voltage_table *voltage_table);
|
||||||
bool radeon_atom_is_voltage_gpio(struct radeon_device *rdev,
|
bool radeon_atom_is_voltage_gpio(struct radeon_device *rdev,
|
||||||
u8 voltage_type, u8 voltage_mode);
|
u8 voltage_type, u8 voltage_mode);
|
||||||
|
int radeon_atom_get_svi2_info(struct radeon_device *rdev,
|
||||||
|
u8 voltage_type,
|
||||||
|
u8 *svd_gpio_id, u8 *svc_gpio_id);
|
||||||
void radeon_atom_update_memory_dll(struct radeon_device *rdev,
|
void radeon_atom_update_memory_dll(struct radeon_device *rdev,
|
||||||
u32 mem_clock);
|
u32 mem_clock);
|
||||||
void radeon_atom_set_ac_timing(struct radeon_device *rdev,
|
void radeon_atom_set_ac_timing(struct radeon_device *rdev,
|
||||||
|
|||||||
@@ -3397,6 +3397,50 @@ radeon_atom_is_voltage_gpio(struct radeon_device *rdev,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int radeon_atom_get_svi2_info(struct radeon_device *rdev,
|
||||||
|
u8 voltage_type,
|
||||||
|
u8 *svd_gpio_id, u8 *svc_gpio_id)
|
||||||
|
{
|
||||||
|
int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
|
||||||
|
u8 frev, crev;
|
||||||
|
u16 data_offset, size;
|
||||||
|
union voltage_object_info *voltage_info;
|
||||||
|
union voltage_object *voltage_object = NULL;
|
||||||
|
|
||||||
|
if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
|
||||||
|
&frev, &crev, &data_offset)) {
|
||||||
|
voltage_info = (union voltage_object_info *)
|
||||||
|
(rdev->mode_info.atom_context->bios + data_offset);
|
||||||
|
|
||||||
|
switch (frev) {
|
||||||
|
case 3:
|
||||||
|
switch (crev) {
|
||||||
|
case 1:
|
||||||
|
voltage_object = (union voltage_object *)
|
||||||
|
atom_lookup_voltage_object_v3(&voltage_info->v3,
|
||||||
|
voltage_type,
|
||||||
|
VOLTAGE_OBJ_SVID2);
|
||||||
|
if (voltage_object) {
|
||||||
|
*svd_gpio_id = voltage_object->v3.asSVID2Obj.ucSVDGpioId;
|
||||||
|
*svc_gpio_id = voltage_object->v3.asSVID2Obj.ucSVCGpioId;
|
||||||
|
} else {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DRM_ERROR("unknown voltage object table\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DRM_ERROR("unknown voltage object table\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int radeon_atom_get_max_voltage(struct radeon_device *rdev,
|
int radeon_atom_get_max_voltage(struct radeon_device *rdev,
|
||||||
u8 voltage_type, u16 *max_voltage)
|
u8 voltage_type, u16 *max_voltage)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3812,6 +3812,27 @@ void si_trim_voltage_table_to_fit_state_table(struct radeon_device *rdev,
|
|||||||
voltage_table->count = max_voltage_steps;
|
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)
|
static int si_construct_voltage_tables(struct radeon_device *rdev)
|
||||||
{
|
{
|
||||||
struct rv7xx_power_info *pi = rv770_get_pi(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);
|
struct si_power_info *si_pi = si_get_pi(rdev);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_VDDC,
|
if (pi->voltage_control) {
|
||||||
VOLTAGE_OBJ_GPIO_LUT, &eg_pi->vddc_voltage_table);
|
ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_VDDC,
|
||||||
if (ret)
|
VOLTAGE_OBJ_GPIO_LUT, &eg_pi->vddc_voltage_table);
|
||||||
return ret;
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (eg_pi->vddc_voltage_table.count > SISLANDS_MAX_NO_VREG_STEPS)
|
if (eg_pi->vddc_voltage_table.count > SISLANDS_MAX_NO_VREG_STEPS)
|
||||||
si_trim_voltage_table_to_fit_state_table(rdev,
|
si_trim_voltage_table_to_fit_state_table(rdev,
|
||||||
SISLANDS_MAX_NO_VREG_STEPS,
|
SISLANDS_MAX_NO_VREG_STEPS,
|
||||||
&eg_pi->vddc_voltage_table);
|
&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) {
|
if (eg_pi->vddci_control) {
|
||||||
ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_VDDCI,
|
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,
|
SISLANDS_MAX_NO_VREG_STEPS,
|
||||||
&eg_pi->vddci_voltage_table);
|
&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) {
|
if (pi->mvdd_control) {
|
||||||
ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_MVDDC,
|
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);
|
struct si_power_info *si_pi = si_get_pi(rdev);
|
||||||
u8 i;
|
u8 i;
|
||||||
|
|
||||||
if (eg_pi->vddc_voltage_table.count) {
|
if (si_pi->voltage_control_svi2) {
|
||||||
si_populate_smc_voltage_table(rdev, &eg_pi->vddc_voltage_table, table);
|
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svc,
|
||||||
table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC] =
|
si_pi->svc_gpio_id);
|
||||||
cpu_to_be32(eg_pi->vddc_voltage_table.mask_low);
|
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++) {
|
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) {
|
if (pi->max_vddc_in_table <= eg_pi->vddc_voltage_table.entries[i].value) {
|
||||||
table->maxVDDCIndexInPPTable = i;
|
table->maxVDDCIndexInPPTable = i;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (eg_pi->vddci_voltage_table.count) {
|
if (eg_pi->vddci_voltage_table.count) {
|
||||||
si_populate_smc_voltage_table(rdev, &eg_pi->vddci_voltage_table, table);
|
si_populate_smc_voltage_table(rdev, &eg_pi->vddci_voltage_table, table);
|
||||||
|
|
||||||
table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDCI] =
|
table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDCI] =
|
||||||
cpu_to_be32(eg_pi->vddci_voltage_table.mask_low);
|
cpu_to_be32(eg_pi->vddci_voltage_table.mask_low);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (si_pi->mvdd_voltage_table.count) {
|
if (si_pi->mvdd_voltage_table.count) {
|
||||||
si_populate_smc_voltage_table(rdev, &si_pi->mvdd_voltage_table, table);
|
si_populate_smc_voltage_table(rdev, &si_pi->mvdd_voltage_table, table);
|
||||||
|
|
||||||
table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_MVDD] =
|
table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_MVDD] =
|
||||||
cpu_to_be32(si_pi->mvdd_voltage_table.mask_low);
|
cpu_to_be32(si_pi->mvdd_voltage_table.mask_low);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (si_pi->vddc_phase_shed_control) {
|
if (si_pi->vddc_phase_shed_control) {
|
||||||
if (si_validate_phase_shedding_tables(rdev, &si_pi->vddc_phase_shed_table,
|
if (si_validate_phase_shedding_tables(rdev, &si_pi->vddc_phase_shed_table,
|
||||||
&rdev->pm.dpm.dyn_state.phase_shedding_limits_table)) {
|
&rdev->pm.dpm.dyn_state.phase_shedding_limits_table)) {
|
||||||
si_populate_smc_voltage_table(rdev, &si_pi->vddc_phase_shed_table, table);
|
si_populate_smc_voltage_table(rdev, &si_pi->vddc_phase_shed_table, table);
|
||||||
|
|
||||||
table->phaseMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC] =
|
table->phaseMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC] =
|
||||||
cpu_to_be32(si_pi->vddc_phase_shed_table.mask_low);
|
cpu_to_be32(si_pi->vddc_phase_shed_table.mask_low);
|
||||||
|
|
||||||
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_phase_shedding_delay,
|
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_phase_shedding_delay,
|
||||||
(u32)si_pi->vddc_phase_shed_table.phase_delay);
|
(u32)si_pi->vddc_phase_shed_table.phase_delay);
|
||||||
} else {
|
} else {
|
||||||
si_pi->vddc_phase_shed_control = false;
|
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 rv7xx_power_info *pi = rv770_get_pi(rdev);
|
||||||
struct evergreen_power_info *eg_pi = evergreen_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;
|
struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (si_is_smc_running(rdev))
|
if (si_is_smc_running(rdev))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (pi->voltage_control)
|
if (pi->voltage_control || si_pi->voltage_control_svi2)
|
||||||
si_enable_voltage_control(rdev, true);
|
si_enable_voltage_control(rdev, true);
|
||||||
if (pi->mvdd_control)
|
if (pi->mvdd_control)
|
||||||
si_get_mvdd_configuration(rdev);
|
si_get_mvdd_configuration(rdev);
|
||||||
if (pi->voltage_control) {
|
if (pi->voltage_control || si_pi->voltage_control_svi2) {
|
||||||
ret = si_construct_voltage_tables(rdev);
|
ret = si_construct_voltage_tables(rdev);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
DRM_ERROR("si_construct_voltage_tables failed\n");
|
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;
|
ni_pi->mclk_rtt_mode_threshold = eg_pi->mclk_edc_wr_enable_threshold;
|
||||||
|
|
||||||
pi->voltage_control =
|
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 =
|
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 =
|
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 =
|
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);
|
rv770_get_engine_memory_ss(rdev);
|
||||||
|
|
||||||
|
|||||||
@@ -170,6 +170,8 @@ struct si_power_info {
|
|||||||
bool vddc_phase_shed_control;
|
bool vddc_phase_shed_control;
|
||||||
bool pspp_notify_required;
|
bool pspp_notify_required;
|
||||||
bool sclk_deep_sleep_above_low;
|
bool sclk_deep_sleep_above_low;
|
||||||
|
bool voltage_control_svi2;
|
||||||
|
bool vddci_control_svi2;
|
||||||
/* smc offsets */
|
/* smc offsets */
|
||||||
u32 sram_end;
|
u32 sram_end;
|
||||||
u32 state_table_start;
|
u32 state_table_start;
|
||||||
@@ -192,6 +194,9 @@ struct si_power_info {
|
|||||||
SMC_SIslands_MCRegisters smc_mc_reg_table;
|
SMC_SIslands_MCRegisters smc_mc_reg_table;
|
||||||
SISLANDS_SMC_STATETABLE smc_statetable;
|
SISLANDS_SMC_STATETABLE smc_statetable;
|
||||||
PP_SIslands_PAPMParameters papm_parm;
|
PP_SIslands_PAPMParameters papm_parm;
|
||||||
|
/* SVI2 */
|
||||||
|
u8 svd_gpio_id;
|
||||||
|
u8 svc_gpio_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SISLANDS_INITIAL_STATE_ARB_INDEX 0
|
#define SISLANDS_INITIAL_STATE_ARB_INDEX 0
|
||||||
|
|||||||
@@ -241,6 +241,9 @@ typedef struct SISLANDS_SMC_STATETABLE SISLANDS_SMC_STATETABLE;
|
|||||||
#define SI_SMC_SOFT_REGISTER_non_ulv_pcie_link_width 0xF4
|
#define SI_SMC_SOFT_REGISTER_non_ulv_pcie_link_width 0xF4
|
||||||
#define SI_SMC_SOFT_REGISTER_tdr_is_about_to_happen 0xFC
|
#define SI_SMC_SOFT_REGISTER_tdr_is_about_to_happen 0xFC
|
||||||
#define SI_SMC_SOFT_REGISTER_vr_hot_gpio 0x100
|
#define SI_SMC_SOFT_REGISTER_vr_hot_gpio 0x100
|
||||||
|
#define SI_SMC_SOFT_REGISTER_svi_rework_plat_type 0x118
|
||||||
|
#define SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svd 0x11c
|
||||||
|
#define SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svc 0x120
|
||||||
|
|
||||||
#define SMC_SISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES 16
|
#define SMC_SISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES 16
|
||||||
#define SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES 32
|
#define SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES 32
|
||||||
|
|||||||
Reference in New Issue
Block a user