Commit c5a44849 authored by Rex Zhu's avatar Rex Zhu Committed by Alex Deucher

drm/amd/pp: Add OVERDRIVE support on Vega10 (v2)

when bit14 in module parameter ppfeaturemask was set.
od feature will be enabled on Vega10 except vbios not support.

user can read od range by reading sysfs pp_od_clk_voltage,
cat pp_od_clk_voltage
OD_SCLK:
0:        852Mhz        800mV
1:        991Mhz        900mV
2:       1138Mhz        950mV
3:       1269Mhz       1000mV
4:       1348Mhz       1050mV
5:       1399Mhz       1100mV
6:       1440Mhz       1150mV
7:       1500Mhz       1200mV
OD_MCLK:
0:        167Mhz        800mV
1:        500Mhz        800mV
2:        800Mhz        950mV
3:        945Mhz       1000mV
OD_RANGE:
SCLK:     852MHz       2200MHz
MCLK:     167MHz       1500MHz
VDDC:     800mV        1200mV

and can configure the clock/voltage by writing pp_od_clk_voltage
for example:

echo "s 0 900 820">pp_od_clk_voltage to change the sclk/vddc
to 900MHz and 820 mV in dpm level0.

echo "r" to change the clk/voltage to  default value.

echo "c">pp_od_clk_voltage
to commit the change

v2: squash in warning fix (Alex)
Reviewed-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Signed-off-by: default avatarRex Zhu <Rex.Zhu@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent ba9ca088
......@@ -285,6 +285,48 @@ static int vega10_set_features_platform_caps(struct pp_hwmgr *hwmgr)
return 0;
}
static int vega10_odn_initial_default_setting(struct pp_hwmgr *hwmgr)
{
struct vega10_hwmgr *data = hwmgr->backend;
struct phm_ppt_v2_information *table_info =
(struct phm_ppt_v2_information *)(hwmgr->pptable);
struct vega10_odn_dpm_table *odn_table = &(data->odn_dpm_table);
struct vega10_odn_vddc_lookup_table *od_lookup_table;
struct phm_ppt_v1_voltage_lookup_table *vddc_lookup_table;
struct phm_ppt_v1_clock_voltage_dependency_table *dep_table[3];
struct phm_ppt_v1_clock_voltage_dependency_table *od_table[3];
uint32_t i;
od_lookup_table = &odn_table->vddc_lookup_table;
vddc_lookup_table = table_info->vddc_lookup_table;
for (i = 0; i < vddc_lookup_table->count; i++)
od_lookup_table->entries[i].us_vdd = vddc_lookup_table->entries[i].us_vdd;
od_lookup_table->count = vddc_lookup_table->count;
dep_table[0] = table_info->vdd_dep_on_sclk;
dep_table[1] = table_info->vdd_dep_on_mclk;
dep_table[2] = table_info->vdd_dep_on_socclk;
od_table[0] = (struct phm_ppt_v1_clock_voltage_dependency_table *)&odn_table->vdd_dep_on_sclk;
od_table[1] = (struct phm_ppt_v1_clock_voltage_dependency_table *)&odn_table->vdd_dep_on_mclk;
od_table[2] = (struct phm_ppt_v1_clock_voltage_dependency_table *)&odn_table->vdd_dep_on_socclk;
for (i = 0; i < 3; i++)
smu_get_voltage_dependency_table_ppt_v1(dep_table[i], od_table[i]);
if (odn_table->max_vddc == 0 || odn_table->max_vddc > 2000)
odn_table->max_vddc = dep_table[0]->entries[dep_table[0]->count - 1].vddc;
if (odn_table->min_vddc == 0 || odn_table->min_vddc > 2000)
odn_table->min_vddc = dep_table[0]->entries[0].vddc;
i = od_table[2]->count - 1;
od_table[2]->entries[i].clk = hwmgr->platform_descriptor.overdriveLimit.memoryClock;
od_table[2]->entries[i].vddc = odn_table->max_vddc;
return 0;
}
static void vega10_init_dpm_defaults(struct pp_hwmgr *hwmgr)
{
struct vega10_hwmgr *data = hwmgr->backend;
......@@ -421,7 +463,6 @@ static void vega10_init_dpm_defaults(struct pp_hwmgr *hwmgr)
/* ACG firmware has major version 5 */
if ((hwmgr->smu_version & 0xff000000) == 0x5000000)
data->smu_features[GNLD_ACG].supported = true;
if (data->registry_data.didt_support)
data->smu_features[GNLD_DIDT].supported = true;
......@@ -1360,48 +1401,6 @@ static int vega10_setup_default_dpm_tables(struct pp_hwmgr *hwmgr)
memcpy(&(data->golden_dpm_table), &(data->dpm_table),
sizeof(struct vega10_dpm_table));
if (PP_CAP(PHM_PlatformCaps_ODNinACSupport) ||
PP_CAP(PHM_PlatformCaps_ODNinDCSupport)) {
data->odn_dpm_table.odn_core_clock_dpm_levels.num_of_pl =
data->dpm_table.gfx_table.count;
for (i = 0; i < data->dpm_table.gfx_table.count; i++) {
data->odn_dpm_table.odn_core_clock_dpm_levels.entries[i].clock =
data->dpm_table.gfx_table.dpm_levels[i].value;
data->odn_dpm_table.odn_core_clock_dpm_levels.entries[i].enabled = true;
}
data->odn_dpm_table.vdd_dependency_on_sclk.count =
dep_gfx_table->count;
for (i = 0; i < dep_gfx_table->count; i++) {
data->odn_dpm_table.vdd_dependency_on_sclk.entries[i].clk =
dep_gfx_table->entries[i].clk;
data->odn_dpm_table.vdd_dependency_on_sclk.entries[i].vddInd =
dep_gfx_table->entries[i].vddInd;
data->odn_dpm_table.vdd_dependency_on_sclk.entries[i].cks_enable =
dep_gfx_table->entries[i].cks_enable;
data->odn_dpm_table.vdd_dependency_on_sclk.entries[i].cks_voffset =
dep_gfx_table->entries[i].cks_voffset;
}
data->odn_dpm_table.odn_memory_clock_dpm_levels.num_of_pl =
data->dpm_table.mem_table.count;
for (i = 0; i < data->dpm_table.mem_table.count; i++) {
data->odn_dpm_table.odn_memory_clock_dpm_levels.entries[i].clock =
data->dpm_table.mem_table.dpm_levels[i].value;
data->odn_dpm_table.odn_memory_clock_dpm_levels.entries[i].enabled = true;
}
data->odn_dpm_table.vdd_dependency_on_mclk.count = dep_mclk_table->count;
for (i = 0; i < dep_mclk_table->count; i++) {
data->odn_dpm_table.vdd_dependency_on_mclk.entries[i].clk =
dep_mclk_table->entries[i].clk;
data->odn_dpm_table.vdd_dependency_on_mclk.entries[i].vddInd =
dep_mclk_table->entries[i].vddInd;
data->odn_dpm_table.vdd_dependency_on_mclk.entries[i].vddci =
dep_mclk_table->entries[i].vddci;
}
}
return 0;
}
......@@ -1504,18 +1503,18 @@ static int vega10_populate_single_gfx_level(struct pp_hwmgr *hwmgr,
{
struct phm_ppt_v2_information *table_info =
(struct phm_ppt_v2_information *)(hwmgr->pptable);
struct phm_ppt_v1_clock_voltage_dependency_table *dep_on_sclk =
table_info->vdd_dep_on_sclk;
struct phm_ppt_v1_clock_voltage_dependency_table *dep_on_sclk;
struct vega10_hwmgr *data = hwmgr->backend;
struct pp_atomfwctrl_clock_dividers_soc15 dividers;
uint32_t gfx_max_clock =
hwmgr->platform_descriptor.overdriveLimit.engineClock;
uint32_t i = 0;
if (data->apply_overdrive_next_settings_mask &
DPMTABLE_OD_UPDATE_VDDC)
if (hwmgr->od_enabled)
dep_on_sclk = (struct phm_ppt_v1_clock_voltage_dependency_table *)
&(data->odn_dpm_table.vdd_dependency_on_sclk);
&(data->odn_dpm_table.vdd_dep_on_sclk);
else
dep_on_sclk = table_info->vdd_dep_on_sclk;
PP_ASSERT_WITH_CODE(dep_on_sclk,
"Invalid SOC_VDD-GFX_CLK Dependency Table!",
......@@ -1567,23 +1566,32 @@ static int vega10_populate_single_soc_level(struct pp_hwmgr *hwmgr,
uint32_t soc_clock, uint8_t *current_soc_did,
uint8_t *current_vol_index)
{
struct vega10_hwmgr *data = hwmgr->backend;
struct phm_ppt_v2_information *table_info =
(struct phm_ppt_v2_information *)(hwmgr->pptable);
struct phm_ppt_v1_clock_voltage_dependency_table *dep_on_soc =
table_info->vdd_dep_on_socclk;
struct phm_ppt_v1_clock_voltage_dependency_table *dep_on_soc;
struct pp_atomfwctrl_clock_dividers_soc15 dividers;
uint32_t i;
PP_ASSERT_WITH_CODE(dep_on_soc,
"Invalid SOC_VDD-SOC_CLK Dependency Table!",
return -EINVAL);
for (i = 0; i < dep_on_soc->count; i++) {
if (dep_on_soc->entries[i].clk == soc_clock)
break;
if (hwmgr->od_enabled) {
dep_on_soc = (struct phm_ppt_v1_clock_voltage_dependency_table *)
&data->odn_dpm_table.vdd_dep_on_socclk;
for (i = 0; i < dep_on_soc->count; i++) {
if (dep_on_soc->entries[i].clk >= soc_clock)
break;
}
} else {
dep_on_soc = table_info->vdd_dep_on_socclk;
for (i = 0; i < dep_on_soc->count; i++) {
if (dep_on_soc->entries[i].clk == soc_clock)
break;
}
}
PP_ASSERT_WITH_CODE(dep_on_soc->count > i,
"Cannot find SOC_CLK in SOC_VDD-SOC_CLK Dependency Table",
return -EINVAL);
PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10(hwmgr,
COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
soc_clock, &dividers),
......@@ -1592,22 +1600,6 @@ static int vega10_populate_single_soc_level(struct pp_hwmgr *hwmgr,
*current_soc_did = (uint8_t)dividers.ulDid;
*current_vol_index = (uint8_t)(dep_on_soc->entries[i].vddInd);
return 0;
}
uint16_t vega10_locate_vddc_given_clock(struct pp_hwmgr *hwmgr,
uint32_t clk,
struct phm_ppt_v1_clock_voltage_dependency_table *dep_table)
{
uint16_t i;
for (i = 0; i < dep_table->count; i++) {
if (dep_table->entries[i].clk == clk)
return dep_table->entries[i].vddc;
}
pr_info("[LocateVddcGivenClock] Cannot locate SOC Vddc for this clock!");
return 0;
}
......@@ -1621,8 +1613,6 @@ static int vega10_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
struct vega10_hwmgr *data = hwmgr->backend;
struct phm_ppt_v2_information *table_info =
(struct phm_ppt_v2_information *)(hwmgr->pptable);
struct phm_ppt_v1_clock_voltage_dependency_table *dep_table =
table_info->vdd_dep_on_socclk;
PPTable_t *pp_table = &(data->smc_state_table.pp_table);
struct vega10_single_dpm_table *dpm_table = &(data->dpm_table.gfx_table);
int result = 0;
......@@ -1653,11 +1643,6 @@ static int vega10_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
dpm_table = &(data->dpm_table.soc_table);
for (i = 0; i < dpm_table->count; i++) {
pp_table->SocVid[i] =
(uint8_t)convert_to_vid(
vega10_locate_vddc_given_clock(hwmgr,
dpm_table->dpm_levels[i].value,
dep_table));
result = vega10_populate_single_soc_level(hwmgr,
dpm_table->dpm_levels[i].value,
&(pp_table->SocclkDid[i]),
......@@ -1668,7 +1653,6 @@ static int vega10_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
j = i - 1;
while (i < NUM_SOCCLK_DPM_LEVELS) {
pp_table->SocVid[i] = pp_table->SocVid[j];
result = vega10_populate_single_soc_level(hwmgr,
dpm_table->dpm_levels[j].value,
&(pp_table->SocclkDid[i]),
......@@ -1681,6 +1665,32 @@ static int vega10_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
return result;
}
static void vega10_populate_vddc_soc_levels(struct pp_hwmgr *hwmgr)
{
struct vega10_hwmgr *data = hwmgr->backend;
PPTable_t *pp_table = &(data->smc_state_table.pp_table);
struct phm_ppt_v2_information *table_info = hwmgr->pptable;
struct phm_ppt_v1_voltage_lookup_table *vddc_lookup_table;
uint8_t soc_vid = 0;
uint32_t i, max_vddc_level;
if (hwmgr->od_enabled)
vddc_lookup_table = (struct phm_ppt_v1_voltage_lookup_table *)&data->odn_dpm_table.vddc_lookup_table;
else
vddc_lookup_table = table_info->vddc_lookup_table;
max_vddc_level = vddc_lookup_table->count;
for (i = 0; i < max_vddc_level; i++) {
soc_vid = (uint8_t)convert_to_vid(vddc_lookup_table->entries[i].us_vdd);
pp_table->SocVid[i] = soc_vid;
}
while (i < MAX_REGULAR_DPM_NUMBER) {
pp_table->SocVid[i] = soc_vid;
i++;
}
}
/**
* @brief Populates single SMC GFXCLK structure using the provided clock.
*
......@@ -1695,25 +1705,25 @@ static int vega10_populate_single_memory_level(struct pp_hwmgr *hwmgr,
struct vega10_hwmgr *data = hwmgr->backend;
struct phm_ppt_v2_information *table_info =
(struct phm_ppt_v2_information *)(hwmgr->pptable);
struct phm_ppt_v1_clock_voltage_dependency_table *dep_on_mclk =
table_info->vdd_dep_on_mclk;
struct phm_ppt_v1_clock_voltage_dependency_table *dep_on_mclk;
struct pp_atomfwctrl_clock_dividers_soc15 dividers;
uint32_t mem_max_clock =
hwmgr->platform_descriptor.overdriveLimit.memoryClock;
uint32_t i = 0;
if (data->apply_overdrive_next_settings_mask &
DPMTABLE_OD_UPDATE_VDDC)
if (hwmgr->od_enabled)
dep_on_mclk = (struct phm_ppt_v1_clock_voltage_dependency_table *)
&data->odn_dpm_table.vdd_dependency_on_mclk;
&data->odn_dpm_table.vdd_dep_on_mclk;
else
dep_on_mclk = table_info->vdd_dep_on_mclk;
PP_ASSERT_WITH_CODE(dep_on_mclk,
"Invalid SOC_VDD-UCLK Dependency Table!",
return -EINVAL);
if (data->need_update_dpm_table & DPMTABLE_OD_UPDATE_MCLK)
if (data->need_update_dpm_table & DPMTABLE_OD_UPDATE_MCLK) {
mem_clock = mem_clock > mem_max_clock ? mem_max_clock : mem_clock;
else {
} else {
for (i = 0; i < dep_on_mclk->count; i++) {
if (dep_on_mclk->entries[i].clk == mem_clock)
break;
......@@ -2057,6 +2067,9 @@ static int vega10_populate_avfs_parameters(struct pp_hwmgr *hwmgr)
if (data->smu_features[GNLD_AVFS].supported) {
result = pp_atomfwctrl_get_avfs_information(hwmgr, &avfs_params);
if (!result) {
data->odn_dpm_table.max_vddc = avfs_params.ulMaxVddc;
data->odn_dpm_table.min_vddc = avfs_params.ulMinVddc;
pp_table->MinVoltageVid = (uint8_t)
convert_to_vid((uint16_t)(avfs_params.ulMinVddc));
pp_table->MaxVoltageVid = (uint8_t)
......@@ -2335,6 +2348,22 @@ static int vega10_avfs_enable(struct pp_hwmgr *hwmgr, bool enable)
return 0;
}
static int vega10_update_avfs(struct pp_hwmgr *hwmgr)
{
struct vega10_hwmgr *data = hwmgr->backend;
if (data->need_update_dpm_table & DPMTABLE_OD_UPDATE_VDDC) {
vega10_avfs_enable(hwmgr, false);
} else if (data->need_update_dpm_table) {
vega10_avfs_enable(hwmgr, false);
vega10_avfs_enable(hwmgr, true);
} else {
vega10_avfs_enable(hwmgr, true);
}
return 0;
}
static int vega10_populate_and_upload_avfs_fuse_override(struct pp_hwmgr *hwmgr)
{
int result = 0;
......@@ -2396,6 +2425,10 @@ static int vega10_init_smc_table(struct pp_hwmgr *hwmgr)
"Failed to setup default DPM tables!",
return result);
/* initialize ODN table */
if (hwmgr->od_enabled)
vega10_odn_initial_default_setting(hwmgr);
pp_atomfwctrl_get_voltage_table_v4(hwmgr, VOLTAGE_TYPE_VDDC,
VOLTAGE_OBJ_SVID2, &voltage_table);
pp_table->MaxVidStep = voltage_table.max_vid_step;
......@@ -2442,6 +2475,8 @@ static int vega10_init_smc_table(struct pp_hwmgr *hwmgr)
"Failed to initialize Memory Level!",
return result);
vega10_populate_vddc_soc_levels(hwmgr);
result = vega10_populate_all_display_clock_levels(hwmgr);
PP_ASSERT_WITH_CODE(!result,
"Failed to initialize Display Level!",
......@@ -3164,82 +3199,11 @@ static int vega10_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
static int vega10_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr *hwmgr, const void *input)
{
const struct phm_set_power_state_input *states =
(const struct phm_set_power_state_input *)input;
const struct vega10_power_state *vega10_ps =
cast_const_phw_vega10_power_state(states->pnew_state);
struct vega10_hwmgr *data = hwmgr->backend;
struct vega10_single_dpm_table *sclk_table =
&(data->dpm_table.gfx_table);
uint32_t sclk = vega10_ps->performance_levels
[vega10_ps->performance_level_count - 1].gfx_clock;
struct vega10_single_dpm_table *mclk_table =
&(data->dpm_table.mem_table);
uint32_t mclk = vega10_ps->performance_levels
[vega10_ps->performance_level_count - 1].mem_clock;
struct PP_Clocks min_clocks = {0};
uint32_t i;
data->need_update_dpm_table = 0;
if (PP_CAP(PHM_PlatformCaps_ODNinACSupport) ||
PP_CAP(PHM_PlatformCaps_ODNinDCSupport)) {
for (i = 0; i < sclk_table->count; i++) {
if (sclk == sclk_table->dpm_levels[i].value)
break;
}
if (!(data->apply_overdrive_next_settings_mask &
DPMTABLE_OD_UPDATE_SCLK) && i >= sclk_table->count) {
/* Check SCLK in DAL's minimum clocks
* in case DeepSleep divider update is required.
*/
if (data->display_timing.min_clock_in_sr !=
min_clocks.engineClockInSR &&
(min_clocks.engineClockInSR >=
VEGA10_MINIMUM_ENGINE_CLOCK ||
data->display_timing.min_clock_in_sr >=
VEGA10_MINIMUM_ENGINE_CLOCK))
data->need_update_dpm_table |= DPMTABLE_UPDATE_SCLK;
}
if (data->display_timing.num_existing_displays !=
hwmgr->display_config->num_display)
data->need_update_dpm_table |= DPMTABLE_UPDATE_MCLK;
} else {
for (i = 0; i < sclk_table->count; i++) {
if (sclk == sclk_table->dpm_levels[i].value)
break;
}
if (i >= sclk_table->count)
data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
else {
/* Check SCLK in DAL's minimum clocks
* in case DeepSleep divider update is required.
*/
if (data->display_timing.min_clock_in_sr !=
min_clocks.engineClockInSR &&
(min_clocks.engineClockInSR >=
VEGA10_MINIMUM_ENGINE_CLOCK ||
data->display_timing.min_clock_in_sr >=
VEGA10_MINIMUM_ENGINE_CLOCK))
data->need_update_dpm_table |= DPMTABLE_UPDATE_SCLK;
}
for (i = 0; i < mclk_table->count; i++) {
if (mclk == mclk_table->dpm_levels[i].value)
break;
}
if (i >= mclk_table->count)
data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
if (data->display_timing.num_existing_displays != hwmgr->display_config->num_display)
data->need_update_dpm_table |= DPMTABLE_UPDATE_MCLK;
if (data->display_timing.num_existing_displays !=
hwmgr->display_config->num_display ||
i >= mclk_table->count)
data->need_update_dpm_table |= DPMTABLE_UPDATE_MCLK;
}
return 0;
}
......@@ -3247,194 +3211,29 @@ static int vega10_populate_and_upload_sclk_mclk_dpm_levels(
struct pp_hwmgr *hwmgr, const void *input)
{
int result = 0;
const struct phm_set_power_state_input *states =
(const struct phm_set_power_state_input *)input;
const struct vega10_power_state *vega10_ps =
cast_const_phw_vega10_power_state(states->pnew_state);
struct vega10_hwmgr *data = hwmgr->backend;
uint32_t sclk = vega10_ps->performance_levels
[vega10_ps->performance_level_count - 1].gfx_clock;
uint32_t mclk = vega10_ps->performance_levels
[vega10_ps->performance_level_count - 1].mem_clock;
struct vega10_dpm_table *dpm_table = &data->dpm_table;
struct vega10_dpm_table *golden_dpm_table =
&data->golden_dpm_table;
uint32_t dpm_count, clock_percent;
uint32_t i;
if (PP_CAP(PHM_PlatformCaps_ODNinACSupport) ||
PP_CAP(PHM_PlatformCaps_ODNinDCSupport)) {
if (!data->need_update_dpm_table &&
!data->apply_optimized_settings &&
!data->apply_overdrive_next_settings_mask)
return 0;
if (data->apply_overdrive_next_settings_mask &
DPMTABLE_OD_UPDATE_SCLK) {
for (dpm_count = 0;
dpm_count < dpm_table->gfx_table.count;
dpm_count++) {
dpm_table->gfx_table.dpm_levels[dpm_count].enabled =
data->odn_dpm_table.odn_core_clock_dpm_levels.entries[dpm_count].enabled;
dpm_table->gfx_table.dpm_levels[dpm_count].value =
data->odn_dpm_table.odn_core_clock_dpm_levels.entries[dpm_count].clock;
}
}
if (data->apply_overdrive_next_settings_mask &
DPMTABLE_OD_UPDATE_MCLK) {
for (dpm_count = 0;
dpm_count < dpm_table->mem_table.count;
dpm_count++) {
dpm_table->mem_table.dpm_levels[dpm_count].enabled =
data->odn_dpm_table.odn_memory_clock_dpm_levels.entries[dpm_count].enabled;
dpm_table->mem_table.dpm_levels[dpm_count].value =
data->odn_dpm_table.odn_memory_clock_dpm_levels.entries[dpm_count].clock;
}
}
if ((data->need_update_dpm_table & DPMTABLE_UPDATE_SCLK) ||
data->apply_optimized_settings ||
(data->apply_overdrive_next_settings_mask &
DPMTABLE_OD_UPDATE_SCLK)) {
result = vega10_populate_all_graphic_levels(hwmgr);
PP_ASSERT_WITH_CODE(!result,
"Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
return result);
}
if ((data->need_update_dpm_table & DPMTABLE_UPDATE_MCLK) ||
(data->apply_overdrive_next_settings_mask &
DPMTABLE_OD_UPDATE_MCLK)){
result = vega10_populate_all_memory_levels(hwmgr);
PP_ASSERT_WITH_CODE(!result,
"Failed to populate MCLK during PopulateNewDPMClocksStates Function!",
return result);
}
} else {
if (!data->need_update_dpm_table &&
!data->apply_optimized_settings)
return 0;
if (data->need_update_dpm_table & DPMTABLE_OD_UPDATE_SCLK &&
data->smu_features[GNLD_DPM_GFXCLK].supported) {
dpm_table->
gfx_table.dpm_levels[dpm_table->gfx_table.count - 1].
value = sclk;
if (hwmgr->od_enabled) {
/* Need to do calculation based on the golden DPM table
* as the Heatmap GPU Clock axis is also based on
* the default values
*/
PP_ASSERT_WITH_CODE(
golden_dpm_table->gfx_table.dpm_levels
[golden_dpm_table->gfx_table.count - 1].value,
"Divide by 0!",
return -1);
dpm_count = dpm_table->gfx_table.count < 2 ?
0 : dpm_table->gfx_table.count - 2;
for (i = dpm_count; i > 1; i--) {
if (sclk > golden_dpm_table->gfx_table.dpm_levels
[golden_dpm_table->gfx_table.count - 1].value) {
clock_percent =
((sclk - golden_dpm_table->gfx_table.dpm_levels
[golden_dpm_table->gfx_table.count - 1].value) *
100) /
golden_dpm_table->gfx_table.dpm_levels
[golden_dpm_table->gfx_table.count - 1].value;
dpm_table->gfx_table.dpm_levels[i].value =
golden_dpm_table->gfx_table.dpm_levels[i].value +
(golden_dpm_table->gfx_table.dpm_levels[i].value *
clock_percent) / 100;
} else if (golden_dpm_table->
gfx_table.dpm_levels[dpm_table->gfx_table.count-1].value >
sclk) {
clock_percent =
((golden_dpm_table->gfx_table.dpm_levels
[golden_dpm_table->gfx_table.count - 1].value -
sclk) * 100) /
golden_dpm_table->gfx_table.dpm_levels
[golden_dpm_table->gfx_table.count-1].value;
dpm_table->gfx_table.dpm_levels[i].value =
golden_dpm_table->gfx_table.dpm_levels[i].value -
(golden_dpm_table->gfx_table.dpm_levels[i].value *
clock_percent) / 100;
} else
dpm_table->gfx_table.dpm_levels[i].value =
golden_dpm_table->gfx_table.dpm_levels[i].value;
}
}
}
if (data->need_update_dpm_table & DPMTABLE_OD_UPDATE_MCLK &&
data->smu_features[GNLD_DPM_UCLK].supported) {
dpm_table->
mem_table.dpm_levels[dpm_table->mem_table.count - 1].
value = mclk;
if (!data->need_update_dpm_table)
return 0;
if (hwmgr->od_enabled) {
PP_ASSERT_WITH_CODE(
golden_dpm_table->mem_table.dpm_levels
[golden_dpm_table->mem_table.count - 1].value,
"Divide by 0!",
return -1);
if (data->need_update_dpm_table &
(DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK + DPMTABLE_UPDATE_SOCCLK)) {
result = vega10_populate_all_graphic_levels(hwmgr);
PP_ASSERT_WITH_CODE((0 == result),
"Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
return result);
}
dpm_count = dpm_table->mem_table.count < 2 ?
0 : dpm_table->mem_table.count - 2;
for (i = dpm_count; i > 1; i--) {
if (mclk > golden_dpm_table->mem_table.dpm_levels
[golden_dpm_table->mem_table.count-1].value) {
clock_percent = ((mclk -
golden_dpm_table->mem_table.dpm_levels
[golden_dpm_table->mem_table.count-1].value) *
100) /
golden_dpm_table->mem_table.dpm_levels
[golden_dpm_table->mem_table.count-1].value;
dpm_table->mem_table.dpm_levels[i].value =
golden_dpm_table->mem_table.dpm_levels[i].value +
(golden_dpm_table->mem_table.dpm_levels[i].value *
clock_percent) / 100;
} else if (golden_dpm_table->mem_table.dpm_levels
[dpm_table->mem_table.count-1].value > mclk) {
clock_percent = ((golden_dpm_table->mem_table.dpm_levels
[golden_dpm_table->mem_table.count-1].value - mclk) *
100) /
golden_dpm_table->mem_table.dpm_levels
[golden_dpm_table->mem_table.count-1].value;
dpm_table->mem_table.dpm_levels[i].value =
golden_dpm_table->mem_table.dpm_levels[i].value -
(golden_dpm_table->mem_table.dpm_levels[i].value *
clock_percent) / 100;
} else
dpm_table->mem_table.dpm_levels[i].value =
golden_dpm_table->mem_table.dpm_levels[i].value;
}
}
}
if (data->need_update_dpm_table &
(DPMTABLE_OD_UPDATE_MCLK + DPMTABLE_UPDATE_MCLK)) {
result = vega10_populate_all_memory_levels(hwmgr);
PP_ASSERT_WITH_CODE((0 == result),
"Failed to populate MCLK during PopulateNewDPMClocksStates Function!",
return result);
}
if ((data->need_update_dpm_table &
(DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK)) ||
data->apply_optimized_settings) {
result = vega10_populate_all_graphic_levels(hwmgr);
PP_ASSERT_WITH_CODE(!result,
"Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
return result);
}
vega10_populate_vddc_soc_levels(hwmgr);
if (data->need_update_dpm_table &
(DPMTABLE_OD_UPDATE_MCLK + DPMTABLE_UPDATE_MCLK)) {
result = vega10_populate_all_memory_levels(hwmgr);
PP_ASSERT_WITH_CODE(!result,
"Failed to populate MCLK during PopulateNewDPMClocksStates Function!",
return result);
}
}
return result;
}
......@@ -3730,8 +3529,9 @@ static int vega10_set_power_state_tasks(struct pp_hwmgr *hwmgr,
PP_ASSERT_WITH_CODE(!result,
"Failed to upload PPtable!", return result);
data->apply_optimized_settings = false;
data->apply_overdrive_next_settings_mask = 0;
vega10_update_avfs(hwmgr);
data->need_update_dpm_table &= DPMTABLE_OD_UPDATE_VDDC;
return 0;
}
......@@ -4383,6 +4183,8 @@ static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr,
struct vega10_single_dpm_table *sclk_table = &(data->dpm_table.gfx_table);
struct vega10_single_dpm_table *mclk_table = &(data->dpm_table.mem_table);
struct vega10_pcie_table *pcie_table = &(data->dpm_table.pcie_table);
struct vega10_odn_clock_voltage_dependency_table *podn_vdd_dep = NULL;
int i, now, size = 0;
switch (type) {
......@@ -4421,6 +4223,40 @@ static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr,
(pcie_table->pcie_gen[i] == 2) ? "8.0GT/s, x16" : "",
(i == now) ? "*" : "");
break;
case OD_SCLK:
if (hwmgr->od_enabled) {
size = sprintf(buf, "%s:\n", "OD_SCLK");
podn_vdd_dep = &data->odn_dpm_table.vdd_dep_on_sclk;
for (i = 0; i < podn_vdd_dep->count; i++)
size += sprintf(buf + size, "%d: %10uMhz %10umV\n",
i, podn_vdd_dep->entries[i].clk / 100,
podn_vdd_dep->entries[i].vddc);
}
break;
case OD_MCLK:
if (hwmgr->od_enabled) {
size = sprintf(buf, "%s:\n", "OD_MCLK");
podn_vdd_dep = &data->odn_dpm_table.vdd_dep_on_mclk;
for (i = 0; i < podn_vdd_dep->count; i++)
size += sprintf(buf + size, "%d: %10uMhz %10umV\n",
i, podn_vdd_dep->entries[i].clk/100,
podn_vdd_dep->entries[i].vddc);
}
break;
case OD_RANGE:
if (hwmgr->od_enabled) {
size = sprintf(buf, "%s:\n", "OD_RANGE");
size += sprintf(buf + size, "SCLK: %7uMHz %10uMHz\n",
data->golden_dpm_table.gfx_table.dpm_levels[0].value/100,
hwmgr->platform_descriptor.overdriveLimit.engineClock/100);
size += sprintf(buf + size, "MCLK: %7uMHz %10uMHz\n",
data->golden_dpm_table.mem_table.dpm_levels[0].value/100,
hwmgr->platform_descriptor.overdriveLimit.memoryClock/100);
size += sprintf(buf + size, "VDDC: %7umV %11umV\n",
data->odn_dpm_table.min_vddc,
data->odn_dpm_table.max_vddc);
}
break;
default:
break;
}
......@@ -4808,6 +4644,200 @@ static int vega10_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, ui
return 0;
}
static bool vega10_check_clk_voltage_valid(struct pp_hwmgr *hwmgr,
enum PP_OD_DPM_TABLE_COMMAND type,
uint32_t clk,
uint32_t voltage)
{
struct vega10_hwmgr *data = hwmgr->backend;
struct vega10_odn_dpm_table *odn_table = &(data->odn_dpm_table);
struct vega10_single_dpm_table *golden_table;
if (voltage < odn_table->min_vddc || voltage > odn_table->max_vddc) {
pr_info("OD voltage is out of range [%d - %d] mV\n", odn_table->min_vddc, odn_table->max_vddc);
return false;
}
if (type == PP_OD_EDIT_SCLK_VDDC_TABLE) {
golden_table = &(data->golden_dpm_table.gfx_table);
if (golden_table->dpm_levels[0].value > clk ||
hwmgr->platform_descriptor.overdriveLimit.engineClock < clk) {
pr_info("OD engine clock is out of range [%d - %d] MHz\n",
golden_table->dpm_levels[0].value/100,
hwmgr->platform_descriptor.overdriveLimit.engineClock/100);
return false;
}
} else if (type == PP_OD_EDIT_MCLK_VDDC_TABLE) {
golden_table = &(data->golden_dpm_table.mem_table);
if (golden_table->dpm_levels[0].value > clk ||
hwmgr->platform_descriptor.overdriveLimit.memoryClock < clk) {
pr_info("OD memory clock is out of range [%d - %d] MHz\n",
golden_table->dpm_levels[0].value/100,
hwmgr->platform_descriptor.overdriveLimit.memoryClock/100);
return false;
}
} else {
return false;
}
return true;
}
static void vega10_check_dpm_table_updated(struct pp_hwmgr *hwmgr)
{
struct vega10_hwmgr *data = hwmgr->backend;
struct vega10_odn_dpm_table *odn_table = &(data->odn_dpm_table);
struct phm_ppt_v2_information *table_info = hwmgr->pptable;
struct phm_ppt_v1_clock_voltage_dependency_table *dep_table;
struct phm_ppt_v1_clock_voltage_dependency_table *odn_dep_table;
uint32_t i;
dep_table = table_info->vdd_dep_on_mclk;
odn_dep_table = (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dep_on_mclk);
for (i = 0; i < dep_table->count; i++) {
if (dep_table->entries[i].vddc != odn_dep_table->entries[i].vddc) {
data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_VDDC | DPMTABLE_OD_UPDATE_MCLK;
return;
}
}
dep_table = table_info->vdd_dep_on_sclk;
odn_dep_table = (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dep_on_sclk);
for (i = 0; i < dep_table->count; i++) {
if (dep_table->entries[i].vddc != odn_dep_table->entries[i].vddc) {
data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_VDDC | DPMTABLE_OD_UPDATE_SCLK;
return;
}
}
if (data->need_update_dpm_table & DPMTABLE_OD_UPDATE_VDDC) {
data->need_update_dpm_table &= ~DPMTABLE_OD_UPDATE_VDDC;
data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_OD_UPDATE_MCLK;
}
}
static void vega10_odn_update_soc_table(struct pp_hwmgr *hwmgr,
enum PP_OD_DPM_TABLE_COMMAND type)
{
struct vega10_hwmgr *data = hwmgr->backend;
struct phm_ppt_v2_information *table_info = hwmgr->pptable;
struct phm_ppt_v1_clock_voltage_dependency_table *dep_table = table_info->vdd_dep_on_socclk;
struct vega10_single_dpm_table *dpm_table = &data->golden_dpm_table.soc_table;
struct vega10_odn_clock_voltage_dependency_table *podn_vdd_dep_on_socclk =
&data->odn_dpm_table.vdd_dep_on_socclk;
struct vega10_odn_vddc_lookup_table *od_vddc_lookup_table = &data->odn_dpm_table.vddc_lookup_table;
struct vega10_odn_clock_voltage_dependency_table *podn_vdd_dep;
uint8_t i, j;
if (type == PP_OD_EDIT_SCLK_VDDC_TABLE) {
podn_vdd_dep = &data->odn_dpm_table.vdd_dep_on_sclk;
for (i = 0; i < podn_vdd_dep->count - 1; i++)
od_vddc_lookup_table->entries[i].us_vdd = podn_vdd_dep->entries[i].vddc;
if (od_vddc_lookup_table->entries[i].us_vdd < podn_vdd_dep->entries[i].vddc)
od_vddc_lookup_table->entries[i].us_vdd = podn_vdd_dep->entries[i].vddc;
} else if (type == PP_OD_EDIT_MCLK_VDDC_TABLE) {
podn_vdd_dep = &data->odn_dpm_table.vdd_dep_on_mclk;
for (i = 0; i < dpm_table->count; i++) {
for (j = 0; j < od_vddc_lookup_table->count; j++) {
if (od_vddc_lookup_table->entries[j].us_vdd >
podn_vdd_dep->entries[i].vddc)
break;
}
if (j == od_vddc_lookup_table->count) {
od_vddc_lookup_table->entries[j-1].us_vdd =
podn_vdd_dep->entries[i].vddc;
data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_VDDC;
}
podn_vdd_dep->entries[i].vddInd = j;
}
dpm_table = &data->dpm_table.soc_table;
for (i = 0; i < dep_table->count; i++) {
if (dep_table->entries[i].vddInd == podn_vdd_dep->entries[dep_table->count-1].vddInd &&
dep_table->entries[i].clk < podn_vdd_dep->entries[dep_table->count-1].clk) {
data->need_update_dpm_table |= DPMTABLE_UPDATE_SOCCLK;
podn_vdd_dep_on_socclk->entries[i].clk = podn_vdd_dep->entries[dep_table->count-1].clk;
dpm_table->dpm_levels[i].value = podn_vdd_dep_on_socclk->entries[i].clk;
}
}
if (podn_vdd_dep_on_socclk->entries[podn_vdd_dep_on_socclk->count - 1].clk <
podn_vdd_dep->entries[dep_table->count-1].clk) {
data->need_update_dpm_table |= DPMTABLE_UPDATE_SOCCLK;
podn_vdd_dep_on_socclk->entries[podn_vdd_dep_on_socclk->count - 1].clk = podn_vdd_dep->entries[dep_table->count-1].clk;
dpm_table->dpm_levels[podn_vdd_dep_on_socclk->count - 1].value = podn_vdd_dep->entries[dep_table->count-1].clk;
}
if (podn_vdd_dep_on_socclk->entries[podn_vdd_dep_on_socclk->count - 1].vddInd <
podn_vdd_dep->entries[dep_table->count-1].vddInd) {
data->need_update_dpm_table |= DPMTABLE_UPDATE_SOCCLK;
podn_vdd_dep_on_socclk->entries[podn_vdd_dep_on_socclk->count - 1].vddInd = podn_vdd_dep->entries[dep_table->count-1].vddInd;
}
}
}
static int vega10_odn_edit_dpm_table(struct pp_hwmgr *hwmgr,
enum PP_OD_DPM_TABLE_COMMAND type,
long *input, uint32_t size)
{
struct vega10_hwmgr *data = hwmgr->backend;
struct vega10_odn_clock_voltage_dependency_table *podn_vdd_dep_table;
struct vega10_single_dpm_table *dpm_table;
uint32_t input_clk;
uint32_t input_vol;
uint32_t input_level;
uint32_t i;
PP_ASSERT_WITH_CODE(input, "NULL user input for clock and voltage",
return -EINVAL);
if (!hwmgr->od_enabled) {
pr_info("OverDrive feature not enabled\n");
return -EINVAL;
}
if (PP_OD_EDIT_SCLK_VDDC_TABLE == type) {
dpm_table = &data->dpm_table.gfx_table;
podn_vdd_dep_table = &data->odn_dpm_table.vdd_dep_on_sclk;
data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
} else if (PP_OD_EDIT_MCLK_VDDC_TABLE == type) {
dpm_table = &data->dpm_table.mem_table;
podn_vdd_dep_table = &data->odn_dpm_table.vdd_dep_on_mclk;
data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
} else if (PP_OD_RESTORE_DEFAULT_TABLE == type) {
memcpy(&(data->dpm_table), &(data->golden_dpm_table), sizeof(struct vega10_dpm_table));
vega10_odn_initial_default_setting(hwmgr);
return 0;
} else if (PP_OD_COMMIT_DPM_TABLE == type) {
vega10_check_dpm_table_updated(hwmgr);
return 0;
} else {
return -EINVAL;
}
for (i = 0; i < size; i += 3) {
if (i + 3 > size || input[i] >= podn_vdd_dep_table->count) {
pr_info("invalid clock voltage input\n");
return 0;
}
input_level = input[i];
input_clk = input[i+1] * 100;
input_vol = input[i+2];
if (vega10_check_clk_voltage_valid(hwmgr, type, input_clk, input_vol)) {
dpm_table->dpm_levels[input_level].value = input_clk;
podn_vdd_dep_table->entries[input_level].clk = input_clk;
podn_vdd_dep_table->entries[input_level].vddc = input_vol;
} else {
return -EINVAL;
}
}
vega10_odn_update_soc_table(hwmgr, type);
return 0;
}
static const struct pp_hwmgr_func vega10_hwmgr_funcs = {
.backend_init = vega10_hwmgr_backend_init,
.backend_fini = vega10_hwmgr_backend_fini,
......@@ -4866,6 +4896,7 @@ static const struct pp_hwmgr_func vega10_hwmgr_funcs = {
.get_power_profile_mode = vega10_get_power_profile_mode,
.set_power_profile_mode = vega10_set_power_profile_mode,
.set_power_limit = vega10_set_power_limit,
.odn_edit_dpm_table = vega10_odn_edit_dpm_table,
};
int vega10_enable_smc_features(struct pp_hwmgr *hwmgr,
......
......@@ -282,15 +282,21 @@ struct vega10_registry_data {
struct vega10_odn_clock_voltage_dependency_table {
uint32_t count;
struct phm_ppt_v1_clock_voltage_dependency_record
entries[MAX_REGULAR_DPM_NUMBER];
struct phm_ppt_v1_clock_voltage_dependency_record entries[MAX_REGULAR_DPM_NUMBER];
};
struct vega10_odn_vddc_lookup_table {
uint32_t count;
struct phm_ppt_v1_voltage_lookup_record entries[MAX_REGULAR_DPM_NUMBER];
};
struct vega10_odn_dpm_table {
struct phm_odn_clock_levels odn_core_clock_dpm_levels;
struct phm_odn_clock_levels odn_memory_clock_dpm_levels;
struct vega10_odn_clock_voltage_dependency_table vdd_dependency_on_sclk;
struct vega10_odn_clock_voltage_dependency_table vdd_dependency_on_mclk;
struct vega10_odn_clock_voltage_dependency_table vdd_dep_on_sclk;
struct vega10_odn_clock_voltage_dependency_table vdd_dep_on_mclk;
struct vega10_odn_clock_voltage_dependency_table vdd_dep_on_socclk;
struct vega10_odn_vddc_lookup_table vddc_lookup_table;
uint32_t max_vddc;
uint32_t min_vddc;
};
struct vega10_odn_fan_table {
......@@ -301,8 +307,8 @@ struct vega10_odn_fan_table {
};
struct vega10_hwmgr {
struct vega10_dpm_table dpm_table;
struct vega10_dpm_table golden_dpm_table;
struct vega10_dpm_table dpm_table;
struct vega10_dpm_table golden_dpm_table;
struct vega10_registry_data registry_data;
struct vega10_vbios_boot_state vbios_boot_state;
struct vega10_mclk_latency_table mclk_latency_table;
......@@ -368,12 +374,8 @@ struct vega10_hwmgr {
bool need_long_memory_training;
/* Internal settings to apply the application power optimization parameters */
bool apply_optimized_settings;
uint32_t disable_dpm_mask;
/* ---- Overdrive next setting ---- */
uint32_t apply_overdrive_next_settings_mask;
/* ---- SMU9 ---- */
struct smu_features smu_features[GNLD_FEATURES_MAX];
struct vega10_smc_state_table smc_state_table;
......
......@@ -377,11 +377,7 @@ struct phm_clocks {
#define DPMTABLE_UPDATE_SCLK 0x00000004
#define DPMTABLE_UPDATE_MCLK 0x00000008
#define DPMTABLE_OD_UPDATE_VDDC 0x00000010
/* To determine if sclk and mclk are in overdrive state */
#define SCLK_OVERDRIVE_ENABLED 0x00000001
#define MCLK_OVERDRIVE_ENABLED 0x00000002
#define VDDC_OVERDRIVE_ENABLED 0x00000010
#define DPMTABLE_UPDATE_SOCCLK 0x00000020
struct phm_odn_performance_level {
uint32_t clock;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment