summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c')
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c521
1 files changed, 454 insertions, 67 deletions
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c
index 2614af2f553f..d6f097f44b6c 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c
@@ -20,10 +20,11 @@
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
+
+#include <linux/delay.h>
+#include <linux/fb.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/fb.h>
-#include "linux/delay.h"
#include "hwmgr.h"
#include "amd_powerplay.h"
@@ -47,7 +48,7 @@
#include "amd_pcie_helpers.h"
#include "cgs_linux.h"
#include "ppinterrupt.h"
-
+#include "pp_overdriver.h"
#define VOLTAGE_SCALE 4
#define VOLTAGE_VID_OFFSET_SCALE1 625
@@ -124,7 +125,13 @@ static void vega10_set_default_registry_data(struct pp_hwmgr *hwmgr)
}
data->registry_data.clock_stretcher_support =
- hwmgr->feature_mask & PP_CLOCK_STRETCH_MASK ? false : true;
+ hwmgr->feature_mask & PP_CLOCK_STRETCH_MASK ? true : false;
+
+ data->registry_data.ulv_support =
+ hwmgr->feature_mask & PP_ULV_MASK ? true : false;
+
+ data->registry_data.sclk_deep_sleep_support =
+ hwmgr->feature_mask & PP_SCLK_DEEP_SLEEP_MASK ? true : false;
data->registry_data.disable_water_mark = 0;
@@ -349,6 +356,7 @@ static void vega10_init_dpm_defaults(struct pp_hwmgr *hwmgr)
data->smu_features[GNLD_DS_GFXCLK].supported = true;
data->smu_features[GNLD_DS_SOCCLK].supported = true;
data->smu_features[GNLD_DS_LCLK].supported = true;
+ data->smu_features[GNLD_DS_DCEFCLK].supported = true;
}
if (data->registry_data.enable_pkg_pwr_tracking_feature)
@@ -1161,7 +1169,7 @@ static int vega10_setup_default_pcie_table(struct pp_hwmgr *hwmgr)
"Incorrect number of PCIE States from VBIOS!",
return -1);
- for (i = 0; i < NUM_LINK_LEVELS - 1; i++) {
+ for (i = 0; i < NUM_LINK_LEVELS; i++) {
if (data->registry_data.pcieSpeedOverride)
pcie_table->pcie_gen[i] =
data->registry_data.pcieSpeedOverride;
@@ -1170,12 +1178,11 @@ static int vega10_setup_default_pcie_table(struct pp_hwmgr *hwmgr)
bios_pcie_table->entries[i].gen_speed;
if (data->registry_data.pcieLaneOverride)
- pcie_table->pcie_lane[i] =
- data->registry_data.pcieLaneOverride;
+ pcie_table->pcie_lane[i] = (uint8_t)encode_pcie_lane_width(
+ data->registry_data.pcieLaneOverride);
else
- pcie_table->pcie_lane[i] =
- bios_pcie_table->entries[i].lane_width;
-
+ pcie_table->pcie_lane[i] = (uint8_t)encode_pcie_lane_width(
+ bios_pcie_table->entries[i].lane_width);
if (data->registry_data.pcieClockOverride)
pcie_table->lclk[i] =
data->registry_data.pcieClockOverride;
@@ -1506,7 +1513,9 @@ static int vega10_populate_single_gfx_level(struct pp_hwmgr *hwmgr,
struct vega10_hwmgr *data =
(struct vega10_hwmgr *)(hwmgr->backend);
struct pp_atomfwctrl_clock_dividers_soc15 dividers;
- uint32_t i;
+ 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)
@@ -1517,14 +1526,18 @@ static int vega10_populate_single_gfx_level(struct pp_hwmgr *hwmgr,
"Invalid SOC_VDD-GFX_CLK Dependency Table!",
return -EINVAL);
- for (i = 0; i < dep_on_sclk->count; i++) {
- if (dep_on_sclk->entries[i].clk == gfx_clock)
- break;
+ if (data->need_update_dpm_table & DPMTABLE_OD_UPDATE_SCLK)
+ gfx_clock = gfx_clock > gfx_max_clock ? gfx_max_clock : gfx_clock;
+ else {
+ for (i = 0; i < dep_on_sclk->count; i++) {
+ if (dep_on_sclk->entries[i].clk == gfx_clock)
+ break;
+ }
+ PP_ASSERT_WITH_CODE(dep_on_sclk->count > i,
+ "Cannot find gfx_clk in SOC_VDD-GFX_CLK!",
+ return -EINVAL);
}
- PP_ASSERT_WITH_CODE(dep_on_sclk->count > i,
- "Cannot find gfx_clk in SOC_VDD-GFX_CLK!",
- return -EINVAL);
PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10(hwmgr,
COMPUTE_GPUCLK_INPUT_FLAG_GFXCLK,
gfx_clock, &dividers),
@@ -1535,11 +1548,7 @@ static int vega10_populate_single_gfx_level(struct pp_hwmgr *hwmgr,
current_gfxclk_level->FbMult =
cpu_to_le32(dividers.ulPll_fb_mult);
/* Spread FB Multiplier bit: bit 0:8 int, bit 31:16 frac */
- if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
- PHM_PlatformCaps_EngineSpreadSpectrumSupport))
- current_gfxclk_level->SsOn = dividers.ucPll_ss_enable;
- else
- current_gfxclk_level->SsOn = 0;
+ current_gfxclk_level->SsOn = dividers.ucPll_ss_enable;
current_gfxclk_level->SsFbMult =
cpu_to_le32(dividers.ulPll_ss_fbsmult);
current_gfxclk_level->SsSlewFrac =
@@ -1692,7 +1701,9 @@ static int vega10_populate_single_memory_level(struct pp_hwmgr *hwmgr,
struct phm_ppt_v1_clock_voltage_dependency_table *dep_on_mclk =
table_info->vdd_dep_on_mclk;
struct pp_atomfwctrl_clock_dividers_soc15 dividers;
- uint32_t i;
+ 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)
@@ -1703,15 +1714,18 @@ static int vega10_populate_single_memory_level(struct pp_hwmgr *hwmgr,
"Invalid SOC_VDD-UCLK Dependency Table!",
return -EINVAL);
- for (i = 0; i < dep_on_mclk->count; i++) {
- if (dep_on_mclk->entries[i].clk == mem_clock)
- break;
+ if (data->need_update_dpm_table & DPMTABLE_OD_UPDATE_MCLK)
+ mem_clock = mem_clock > mem_max_clock ? mem_max_clock : mem_clock;
+ else {
+ for (i = 0; i < dep_on_mclk->count; i++) {
+ if (dep_on_mclk->entries[i].clk == mem_clock)
+ break;
+ }
+ PP_ASSERT_WITH_CODE(dep_on_mclk->count > i,
+ "Cannot find UCLK in SOC_VDD-UCLK Dependency Table!",
+ return -EINVAL);
}
- PP_ASSERT_WITH_CODE(dep_on_mclk->count > i,
- "Cannot find UCLK in SOC_VDD-UCLK Dependency Table!",
- return -EINVAL);
-
PP_ASSERT_WITH_CODE(!pp_atomfwctrl_get_gpu_pll_dividers_vega10(
hwmgr, COMPUTE_GPUCLK_INPUT_FLAG_UCLK, mem_clock, &dividers),
"Failed to get UCLK settings from VBIOS!",
@@ -2095,7 +2109,7 @@ static int vega10_populate_avfs_parameters(struct pp_hwmgr *hwmgr)
pp_table->AvfsGbCksOn.m1 =
cpu_to_le32(avfs_params.ulGbFuseTableCksonM1);
pp_table->AvfsGbCksOn.m2 =
- cpu_to_le16(avfs_params.ulGbFuseTableCksonM2);
+ cpu_to_le32(avfs_params.ulGbFuseTableCksonM2);
pp_table->AvfsGbCksOn.b =
cpu_to_le32(avfs_params.ulGbFuseTableCksonB);
pp_table->AvfsGbCksOn.m1_shift = 24;
@@ -2107,7 +2121,7 @@ static int vega10_populate_avfs_parameters(struct pp_hwmgr *hwmgr)
pp_table->AvfsGbCksOff.m1 =
cpu_to_le32(avfs_params.ulGbFuseTableCksoffM1);
pp_table->AvfsGbCksOff.m2 =
- cpu_to_le16(avfs_params.ulGbFuseTableCksoffM2);
+ cpu_to_le32(avfs_params.ulGbFuseTableCksoffM2);
pp_table->AvfsGbCksOff.b =
cpu_to_le32(avfs_params.ulGbFuseTableCksoffB);
pp_table->AvfsGbCksOff.m1_shift = 24;
@@ -2286,6 +2300,73 @@ static int vega10_avfs_enable(struct pp_hwmgr *hwmgr, bool enable)
return 0;
}
+static int vega10_populate_and_upload_avfs_fuse_override(struct pp_hwmgr *hwmgr)
+{
+ int result = 0;
+
+ uint64_t serial_number = 0;
+ uint32_t top32, bottom32;
+ struct phm_fuses_default fuse;
+
+ struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
+ AvfsFuseOverride_t *avfs_fuse_table = &(data->smc_state_table.avfs_fuse_override_table);
+
+ smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_ReadSerialNumTop32);
+ vega10_read_arg_from_smc(hwmgr->smumgr, &top32);
+
+ smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_ReadSerialNumBottom32);
+ vega10_read_arg_from_smc(hwmgr->smumgr, &bottom32);
+
+ serial_number = ((uint64_t)bottom32 << 32) | top32;
+
+ if (pp_override_get_default_fuse_value(serial_number, vega10_fuses_default, &fuse) == 0) {
+ avfs_fuse_table->VFT0_b = fuse.VFT0_b;
+ avfs_fuse_table->VFT0_m1 = fuse.VFT0_m1;
+ avfs_fuse_table->VFT0_m2 = fuse.VFT0_m2;
+ avfs_fuse_table->VFT1_b = fuse.VFT1_b;
+ avfs_fuse_table->VFT1_m1 = fuse.VFT1_m1;
+ avfs_fuse_table->VFT1_m2 = fuse.VFT1_m2;
+ avfs_fuse_table->VFT2_b = fuse.VFT2_b;
+ avfs_fuse_table->VFT2_m1 = fuse.VFT2_m1;
+ avfs_fuse_table->VFT2_m2 = fuse.VFT2_m2;
+ result = vega10_copy_table_to_smc(hwmgr->smumgr,
+ (uint8_t *)avfs_fuse_table, AVFSFUSETABLE);
+ PP_ASSERT_WITH_CODE(!result,
+ "Failed to upload FuseOVerride!",
+ );
+ }
+
+ return result;
+}
+
+static int vega10_save_default_power_profile(struct pp_hwmgr *hwmgr)
+{
+ struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
+ struct vega10_single_dpm_table *dpm_table = &(data->dpm_table.gfx_table);
+ uint32_t min_level;
+
+ hwmgr->default_gfx_power_profile.type = AMD_PP_GFX_PROFILE;
+ hwmgr->default_compute_power_profile.type = AMD_PP_COMPUTE_PROFILE;
+
+ /* Optimize compute power profile: Use only highest
+ * 2 power levels (if more than 2 are available)
+ */
+ if (dpm_table->count > 2)
+ min_level = dpm_table->count - 2;
+ else if (dpm_table->count == 2)
+ min_level = 1;
+ else
+ min_level = 0;
+
+ hwmgr->default_compute_power_profile.min_sclk =
+ dpm_table->dpm_levels[min_level].value;
+
+ hwmgr->gfx_power_profile = hwmgr->default_gfx_power_profile;
+ hwmgr->compute_power_profile = hwmgr->default_compute_power_profile;
+
+ return 0;
+}
+
/**
* Initializes the SMC table and uploads it
*
@@ -2382,6 +2463,7 @@ static int vega10_init_smc_table(struct pp_hwmgr *hwmgr)
data->vbios_boot_state.gfx_clock = boot_up_values.ulGfxClk;
data->vbios_boot_state.mem_clock = boot_up_values.ulUClk;
data->vbios_boot_state.soc_clock = boot_up_values.ulSocClk;
+ data->vbios_boot_state.dcef_clock = boot_up_values.ulDCEFClk;
if (0 != boot_up_values.usVddc) {
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
PPSMC_MSG_SetFloorSocVoltage,
@@ -2390,6 +2472,9 @@ static int vega10_init_smc_table(struct pp_hwmgr *hwmgr)
} else {
data->vbios_boot_state.bsoc_vddc_lock = false;
}
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetMinDeepSleepDcefclk,
+ (uint32_t)(data->vbios_boot_state.dcef_clock / 100));
}
result = vega10_populate_avfs_parameters(hwmgr);
@@ -2411,6 +2496,8 @@ static int vega10_init_smc_table(struct pp_hwmgr *hwmgr)
pp_table->GfxActivityAverageAlpha = (uint8_t)
(data->gfx_activity_average_alpha);
+ vega10_populate_and_upload_avfs_fuse_override(hwmgr);
+
result = vega10_copy_table_to_smc(hwmgr->smumgr,
(uint8_t *)pp_table, PPTABLE);
PP_ASSERT_WITH_CODE(!result,
@@ -2420,6 +2507,8 @@ static int vega10_init_smc_table(struct pp_hwmgr *hwmgr)
PP_ASSERT_WITH_CODE(!result, "Attempt to enable AVFS feature Failed!",
return result);
+ vega10_save_default_power_profile(hwmgr);
+
return 0;
}
@@ -2509,6 +2598,22 @@ static int vega10_enable_ulv(struct pp_hwmgr *hwmgr)
return 0;
}
+static int vega10_disable_ulv(struct pp_hwmgr *hwmgr)
+{
+ struct vega10_hwmgr *data =
+ (struct vega10_hwmgr *)(hwmgr->backend);
+
+ if (data->registry_data.ulv_support) {
+ PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
+ false, data->smu_features[GNLD_ULV].smu_feature_bitmap),
+ "disable ULV Feature Failed!",
+ return -EINVAL);
+ data->smu_features[GNLD_ULV].enabled = false;
+ }
+
+ return 0;
+}
+
static int vega10_enable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
{
struct vega10_hwmgr *data =
@@ -2518,26 +2623,74 @@ static int vega10_enable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
true, data->smu_features[GNLD_DS_GFXCLK].smu_feature_bitmap),
"Attempt to Enable DS_GFXCLK Feature Failed!",
- return -1);
+ return -EINVAL);
data->smu_features[GNLD_DS_GFXCLK].enabled = true;
}
if (data->smu_features[GNLD_DS_SOCCLK].supported) {
PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
true, data->smu_features[GNLD_DS_SOCCLK].smu_feature_bitmap),
- "Attempt to Enable DS_GFXCLK Feature Failed!",
- return -1);
+ "Attempt to Enable DS_SOCCLK Feature Failed!",
+ return -EINVAL);
data->smu_features[GNLD_DS_SOCCLK].enabled = true;
}
if (data->smu_features[GNLD_DS_LCLK].supported) {
PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
true, data->smu_features[GNLD_DS_LCLK].smu_feature_bitmap),
- "Attempt to Enable DS_GFXCLK Feature Failed!",
- return -1);
+ "Attempt to Enable DS_LCLK Feature Failed!",
+ return -EINVAL);
data->smu_features[GNLD_DS_LCLK].enabled = true;
}
+ if (data->smu_features[GNLD_DS_DCEFCLK].supported) {
+ PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
+ true, data->smu_features[GNLD_DS_DCEFCLK].smu_feature_bitmap),
+ "Attempt to Enable DS_DCEFCLK Feature Failed!",
+ return -EINVAL);
+ data->smu_features[GNLD_DS_DCEFCLK].enabled = true;
+ }
+
+ return 0;
+}
+
+static int vega10_disable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
+{
+ struct vega10_hwmgr *data =
+ (struct vega10_hwmgr *)(hwmgr->backend);
+
+ if (data->smu_features[GNLD_DS_GFXCLK].supported) {
+ PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
+ false, data->smu_features[GNLD_DS_GFXCLK].smu_feature_bitmap),
+ "Attempt to disable DS_GFXCLK Feature Failed!",
+ return -EINVAL);
+ data->smu_features[GNLD_DS_GFXCLK].enabled = false;
+ }
+
+ if (data->smu_features[GNLD_DS_SOCCLK].supported) {
+ PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
+ false, data->smu_features[GNLD_DS_SOCCLK].smu_feature_bitmap),
+ "Attempt to disable DS_ Feature Failed!",
+ return -EINVAL);
+ data->smu_features[GNLD_DS_SOCCLK].enabled = false;
+ }
+
+ if (data->smu_features[GNLD_DS_LCLK].supported) {
+ PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
+ false, data->smu_features[GNLD_DS_LCLK].smu_feature_bitmap),
+ "Attempt to disable DS_LCLK Feature Failed!",
+ return -EINVAL);
+ data->smu_features[GNLD_DS_LCLK].enabled = false;
+ }
+
+ if (data->smu_features[GNLD_DS_DCEFCLK].supported) {
+ PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
+ false, data->smu_features[GNLD_DS_DCEFCLK].smu_feature_bitmap),
+ "Attempt to disable DS_DCEFCLK Feature Failed!",
+ return -EINVAL);
+ data->smu_features[GNLD_DS_DCEFCLK].enabled = false;
+ }
+
return 0;
}
@@ -2550,9 +2703,9 @@ static int vega10_stop_dpm(struct pp_hwmgr *hwmgr, uint32_t bitmap)
if(data->smu_features[GNLD_LED_DISPLAY].supported == true){
PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr->smumgr,
- true, data->smu_features[GNLD_LED_DISPLAY].smu_feature_bitmap),
- "Attempt to Enable LED DPM feature Failed!", return -EINVAL);
- data->smu_features[GNLD_LED_DISPLAY].enabled = true;
+ false, data->smu_features[GNLD_LED_DISPLAY].smu_feature_bitmap),
+ "Attempt to disable LED DPM feature failed!", return -EINVAL);
+ data->smu_features[GNLD_LED_DISPLAY].enabled = false;
}
for (i = 0; i < GNLD_DPM_MAX; i++) {
@@ -2676,11 +2829,6 @@ static int vega10_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
"Failed to enable VR hot feature!",
result = tmp_result);
- tmp_result = vega10_enable_ulv(hwmgr);
- PP_ASSERT_WITH_CODE(!tmp_result,
- "Failed to enable ULV!",
- result = tmp_result);
-
tmp_result = vega10_enable_deep_sleep_master_switch(hwmgr);
PP_ASSERT_WITH_CODE(!tmp_result,
"Failed to enable deep sleep master switch!",
@@ -2700,6 +2848,11 @@ static int vega10_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
"Failed to power control set level!",
result = tmp_result);
+ tmp_result = vega10_enable_ulv(hwmgr);
+ PP_ASSERT_WITH_CODE(!tmp_result,
+ "Failed to enable ULV!",
+ result = tmp_result);
+
return result;
}
@@ -2712,6 +2865,7 @@ static int vega10_get_pp_table_entry_callback_func(struct pp_hwmgr *hwmgr,
void *state, struct pp_power_state *power_state,
void *pp_table, uint32_t classification_flag)
{
+ ATOM_Vega10_GFXCLK_Dependency_Record_V2 *patom_record_V2;
struct vega10_power_state *vega10_power_state =
cast_phw_vega10_power_state(&(power_state->hardware));
struct vega10_performance_level *performance_level;
@@ -2788,11 +2942,16 @@ static int vega10_get_pp_table_entry_callback_func(struct pp_hwmgr *hwmgr,
performance_level = &(vega10_power_state->performance_levels
[vega10_power_state->performance_level_count++]);
-
performance_level->soc_clock = socclk_dep_table->entries
- [state_entry->ucSocClockIndexHigh].ulClk;
- performance_level->gfx_clock = gfxclk_dep_table->entries
+ [state_entry->ucSocClockIndexHigh].ulClk;
+ if (gfxclk_dep_table->ucRevId == 0) {
+ performance_level->gfx_clock = gfxclk_dep_table->entries
[state_entry->ucGfxClockIndexHigh].ulClk;
+ } else if (gfxclk_dep_table->ucRevId == 1) {
+ patom_record_V2 = (ATOM_Vega10_GFXCLK_Dependency_Record_V2 *)gfxclk_dep_table->entries;
+ performance_level->gfx_clock = patom_record_V2[state_entry->ucGfxClockIndexHigh].ulClk;
+ }
+
performance_level->mem_clock = mclk_dep_table->entries
[state_entry->ucMemClockIndexHigh].ulMemClk;
return 0;
@@ -2886,7 +3045,7 @@ static int vega10_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
/* result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/
minimum_clocks.engineClock = hwmgr->display_config.min_core_set_clock;
- /* minimum_clocks.memoryClock = hwmgr->display_config.min_mem_set_clock; */
+ minimum_clocks.memoryClock = hwmgr->display_config.min_mem_set_clock;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_StablePState)) {
@@ -2978,11 +3137,10 @@ static int vega10_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
vega10_ps->performance_levels[0].gfx_clock = sclk;
vega10_ps->performance_levels[0].mem_clock = mclk;
- vega10_ps->performance_levels[1].gfx_clock =
- (vega10_ps->performance_levels[1].gfx_clock >=
- vega10_ps->performance_levels[0].gfx_clock) ?
- vega10_ps->performance_levels[1].gfx_clock :
- vega10_ps->performance_levels[0].gfx_clock;
+ if (vega10_ps->performance_levels[1].gfx_clock <
+ vega10_ps->performance_levels[0].gfx_clock)
+ vega10_ps->performance_levels[0].gfx_clock =
+ vega10_ps->performance_levels[1].gfx_clock;
if (disable_mclk_switching) {
/* Set Mclk the max of level 0 and level 1 */
@@ -3005,8 +3163,8 @@ static int vega10_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
} else {
if (vega10_ps->performance_levels[1].mem_clock <
vega10_ps->performance_levels[0].mem_clock)
- vega10_ps->performance_levels[1].mem_clock =
- vega10_ps->performance_levels[0].mem_clock;
+ vega10_ps->performance_levels[0].mem_clock =
+ vega10_ps->performance_levels[1].mem_clock;
}
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
@@ -3197,7 +3355,6 @@ static int vega10_populate_and_upload_sclk_mclk_dpm_levels(
dpm_table->
gfx_table.dpm_levels[dpm_table->gfx_table.count - 1].
value = sclk;
-
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_OD6PlusinACSupport) ||
phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
@@ -3320,7 +3477,6 @@ static int vega10_populate_and_upload_sclk_mclk_dpm_levels(
return result);
}
}
-
return result;
}
@@ -3673,6 +3829,23 @@ static int vega10_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
[vega10_ps->performance_level_count-1].mem_clock;
}
+static int vega10_get_gpu_power(struct pp_hwmgr *hwmgr,
+ struct pp_gpu_power *query)
+{
+ uint32_t value;
+
+ PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_GetCurrPkgPwr),
+ "Failed to get current package power!",
+ return -EINVAL);
+
+ vega10_read_arg_from_smc(hwmgr->smumgr, &value);
+ /* power value is an integer */
+ query->average_gpu_power = value << 8;
+
+ return 0;
+}
+
static int vega10_read_sensor(struct pp_hwmgr *hwmgr, int idx,
void *value, int *size)
{
@@ -3718,6 +3891,14 @@ static int vega10_read_sensor(struct pp_hwmgr *hwmgr, int idx,
*((uint32_t *)value) = data->vce_power_gated ? 0 : 1;
*size = 4;
break;
+ case AMDGPU_PP_SENSOR_GPU_POWER:
+ if (*size < sizeof(struct pp_gpu_power))
+ ret = -EINVAL;
+ else {
+ *size = sizeof(struct pp_gpu_power);
+ ret = vega10_get_gpu_power(hwmgr, (struct pp_gpu_power *)value);
+ }
+ break;
default:
ret = -EINVAL;
break;
@@ -3738,7 +3919,7 @@ int vega10_display_clock_voltage_request(struct pp_hwmgr *hwmgr,
{
int result = 0;
enum amd_pp_clock_type clk_type = clock_req->clock_type;
- uint32_t clk_freq = clock_req->clock_freq_in_khz / 100;
+ uint32_t clk_freq = clock_req->clock_freq_in_khz / 1000;
DSPCLK_e clk_select = 0;
uint32_t clk_request = 0;
@@ -3771,6 +3952,26 @@ int vega10_display_clock_voltage_request(struct pp_hwmgr *hwmgr,
return result;
}
+static uint8_t vega10_get_uclk_index(struct pp_hwmgr *hwmgr,
+ struct phm_ppt_v1_clock_voltage_dependency_table *mclk_table,
+ uint32_t frequency)
+{
+ uint8_t count;
+ uint8_t i;
+
+ if (mclk_table == NULL || mclk_table->count == 0)
+ return 0;
+
+ count = (uint8_t)(mclk_table->count);
+
+ for(i = 0; i < count; i++) {
+ if(mclk_table->entries[i].clk >= frequency)
+ return i;
+ }
+
+ return i-1;
+}
+
static int vega10_notify_smc_display_config_after_ps_adjustment(
struct pp_hwmgr *hwmgr)
{
@@ -3778,6 +3979,10 @@ static int vega10_notify_smc_display_config_after_ps_adjustment(
(struct vega10_hwmgr *)(hwmgr->backend);
struct vega10_single_dpm_table *dpm_table =
&data->dpm_table.dcef_table;
+ struct phm_ppt_v2_information *table_info =
+ (struct phm_ppt_v2_information *)hwmgr->pptable;
+ struct phm_ppt_v1_clock_voltage_dependency_table *mclk_table = table_info->vdd_dep_on_mclk;
+ uint32_t idx;
uint32_t num_active_disps = 0;
struct cgs_display_info info = {0};
struct PP_Clocks min_clocks = {0};
@@ -3797,6 +4002,7 @@ static int vega10_notify_smc_display_config_after_ps_adjustment(
min_clocks.dcefClock = hwmgr->display_config.min_dcef_set_clk;
min_clocks.dcefClockInSR = hwmgr->display_config.min_dcef_deep_sleep_set_clk;
+ min_clocks.memoryClock = hwmgr->display_config.min_mem_set_clock;
for (i = 0; i < dpm_table->count; i++) {
if (dpm_table->dpm_levels[i].value == min_clocks.dcefClock)
@@ -3809,12 +4015,20 @@ static int vega10_notify_smc_display_config_after_ps_adjustment(
if (!vega10_display_clock_voltage_request(hwmgr, &clock_req)) {
PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc_with_parameter(
hwmgr->smumgr, PPSMC_MSG_SetMinDeepSleepDcefclk,
- min_clocks.dcefClockInSR),
+ min_clocks.dcefClockInSR /100),
"Attempt to set divider for DCEFCLK Failed!",);
- } else
+ } else {
pr_info("Attempt to set Hard Min for DCEFCLK Failed!");
- } else
+ }
+ } else {
pr_info("Cannot find requested DCEFCLK!");
+ }
+
+ if (min_clocks.memoryClock != 0) {
+ idx = vega10_get_uclk_index(hwmgr, mclk_table, min_clocks.memoryClock);
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetSoftMinUclkByIndex, idx);
+ data->dpm_table.mem_table.dpm_state.soft_min_level= idx;
+ }
return 0;
}
@@ -4219,11 +4433,6 @@ static int vega10_force_clock_level(struct pp_hwmgr *hwmgr,
if (mask & (1 << i))
break;
}
-
- for (i = 0; i < 32; i++) {
- if (mask & (1 << i))
- break;
- }
data->smc_state_table.mem_boot_level = i;
for (i = 31; i >= 0; i--) {
@@ -4466,6 +4675,14 @@ static int vega10_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
PP_ASSERT_WITH_CODE((tmp_result == 0),
"Failed to stop DPM!", result = tmp_result);
+ tmp_result = vega10_disable_deep_sleep_master_switch(hwmgr);
+ PP_ASSERT_WITH_CODE((tmp_result == 0),
+ "Failed to disable deep sleep!", result = tmp_result);
+
+ tmp_result = vega10_disable_ulv(hwmgr);
+ PP_ASSERT_WITH_CODE((tmp_result == 0),
+ "Failed to disable ulv!", result = tmp_result);
+
return result;
}
@@ -4483,6 +4700,170 @@ static int vega10_power_off_asic(struct pp_hwmgr *hwmgr)
return result;
}
+static void vega10_find_min_clock_index(struct pp_hwmgr *hwmgr,
+ uint32_t *sclk_idx, uint32_t *mclk_idx,
+ uint32_t min_sclk, uint32_t min_mclk)
+{
+ struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
+ struct vega10_dpm_table *dpm_table = &(data->dpm_table);
+ uint32_t i;
+
+ for (i = 0; i < dpm_table->gfx_table.count; i++) {
+ if (dpm_table->gfx_table.dpm_levels[i].enabled &&
+ dpm_table->gfx_table.dpm_levels[i].value >= min_sclk) {
+ *sclk_idx = i;
+ break;
+ }
+ }
+
+ for (i = 0; i < dpm_table->mem_table.count; i++) {
+ if (dpm_table->mem_table.dpm_levels[i].enabled &&
+ dpm_table->mem_table.dpm_levels[i].value >= min_mclk) {
+ *mclk_idx = i;
+ break;
+ }
+ }
+}
+
+static int vega10_set_power_profile_state(struct pp_hwmgr *hwmgr,
+ struct amd_pp_profile *request)
+{
+ struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
+ uint32_t sclk_idx = ~0, mclk_idx = ~0;
+
+ if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_AUTO)
+ return -EINVAL;
+
+ vega10_find_min_clock_index(hwmgr, &sclk_idx, &mclk_idx,
+ request->min_sclk, request->min_mclk);
+
+ if (sclk_idx != ~0) {
+ if (!data->registry_data.sclk_dpm_key_disabled)
+ PP_ASSERT_WITH_CODE(
+ !smum_send_msg_to_smc_with_parameter(
+ hwmgr->smumgr,
+ PPSMC_MSG_SetSoftMinGfxclkByIndex,
+ sclk_idx),
+ "Failed to set soft min sclk index!",
+ return -EINVAL);
+ }
+
+ if (mclk_idx != ~0) {
+ if (!data->registry_data.mclk_dpm_key_disabled)
+ PP_ASSERT_WITH_CODE(
+ !smum_send_msg_to_smc_with_parameter(
+ hwmgr->smumgr,
+ PPSMC_MSG_SetSoftMinUclkByIndex,
+ mclk_idx),
+ "Failed to set soft min mclk index!",
+ return -EINVAL);
+ }
+
+ return 0;
+}
+
+static int vega10_get_sclk_od(struct pp_hwmgr *hwmgr)
+{
+ struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
+ struct vega10_single_dpm_table *sclk_table = &(data->dpm_table.gfx_table);
+ struct vega10_single_dpm_table *golden_sclk_table =
+ &(data->golden_dpm_table.gfx_table);
+ int value;
+
+ value = (sclk_table->dpm_levels[sclk_table->count - 1].value -
+ golden_sclk_table->dpm_levels
+ [golden_sclk_table->count - 1].value) *
+ 100 /
+ golden_sclk_table->dpm_levels
+ [golden_sclk_table->count - 1].value;
+
+ return value;
+}
+
+static int vega10_set_sclk_od(struct pp_hwmgr *hwmgr, uint32_t value)
+{
+ struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
+ struct vega10_single_dpm_table *golden_sclk_table =
+ &(data->golden_dpm_table.gfx_table);
+ struct pp_power_state *ps;
+ struct vega10_power_state *vega10_ps;
+
+ ps = hwmgr->request_ps;
+
+ if (ps == NULL)
+ return -EINVAL;
+
+ vega10_ps = cast_phw_vega10_power_state(&ps->hardware);
+
+ vega10_ps->performance_levels
+ [vega10_ps->performance_level_count - 1].gfx_clock =
+ golden_sclk_table->dpm_levels
+ [golden_sclk_table->count - 1].value *
+ value / 100 +
+ golden_sclk_table->dpm_levels
+ [golden_sclk_table->count - 1].value;
+
+ if (vega10_ps->performance_levels
+ [vega10_ps->performance_level_count - 1].gfx_clock >
+ hwmgr->platform_descriptor.overdriveLimit.engineClock)
+ vega10_ps->performance_levels
+ [vega10_ps->performance_level_count - 1].gfx_clock =
+ hwmgr->platform_descriptor.overdriveLimit.engineClock;
+
+ return 0;
+}
+
+static int vega10_get_mclk_od(struct pp_hwmgr *hwmgr)
+{
+ struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
+ struct vega10_single_dpm_table *mclk_table = &(data->dpm_table.mem_table);
+ struct vega10_single_dpm_table *golden_mclk_table =
+ &(data->golden_dpm_table.mem_table);
+ int value;
+
+ value = (mclk_table->dpm_levels
+ [mclk_table->count - 1].value -
+ golden_mclk_table->dpm_levels
+ [golden_mclk_table->count - 1].value) *
+ 100 /
+ golden_mclk_table->dpm_levels
+ [golden_mclk_table->count - 1].value;
+
+ return value;
+}
+
+static int vega10_set_mclk_od(struct pp_hwmgr *hwmgr, uint32_t value)
+{
+ struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
+ struct vega10_single_dpm_table *golden_mclk_table =
+ &(data->golden_dpm_table.mem_table);
+ struct pp_power_state *ps;
+ struct vega10_power_state *vega10_ps;
+
+ ps = hwmgr->request_ps;
+
+ if (ps == NULL)
+ return -EINVAL;
+
+ vega10_ps = cast_phw_vega10_power_state(&ps->hardware);
+
+ vega10_ps->performance_levels
+ [vega10_ps->performance_level_count - 1].mem_clock =
+ golden_mclk_table->dpm_levels
+ [golden_mclk_table->count - 1].value *
+ value / 100 +
+ golden_mclk_table->dpm_levels
+ [golden_mclk_table->count - 1].value;
+
+ if (vega10_ps->performance_levels
+ [vega10_ps->performance_level_count - 1].mem_clock >
+ hwmgr->platform_descriptor.overdriveLimit.memoryClock)
+ vega10_ps->performance_levels
+ [vega10_ps->performance_level_count - 1].mem_clock =
+ hwmgr->platform_descriptor.overdriveLimit.memoryClock;
+
+ return 0;
+}
static const struct pp_hwmgr_func vega10_hwmgr_funcs = {
.backend_init = vega10_hwmgr_backend_init,
@@ -4531,6 +4912,12 @@ static const struct pp_hwmgr_func vega10_hwmgr_funcs = {
vega10_check_smc_update_required_for_display_configuration,
.power_off_asic = vega10_power_off_asic,
.disable_smc_firmware_ctf = vega10_thermal_disable_alert,
+ .set_power_profile_state = vega10_set_power_profile_state,
+ .get_sclk_od = vega10_get_sclk_od,
+ .set_sclk_od = vega10_set_sclk_od,
+ .get_mclk_od = vega10_get_mclk_od,
+ .set_mclk_od = vega10_set_mclk_od,
+ .avfs_control = vega10_avfs_enable,
};
int vega10_hwmgr_init(struct pp_hwmgr *hwmgr)