Subject: [PATCH 1/2] drm/amd/powerplay: update SMU7 fast uclk switch settings

From: Evan Quan <[email-masked]>
Date: Thu, 9 May 2019 16:11:56 +0800

Clean up the fast uclk switch settings on SMU7 asics.

Change-Id: I3bde78b3caa13078b67c1e2500aa44269c9c7350
Signed-off-by: Evan Quan <[email-masked]>
---
 .../gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c  | 81 ++++++++++++-------
 .../gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h  | 14 ++++
 2 files changed, 65 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c
index 6870dc0572b5..b5ca29100387 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c
@@ -2891,6 +2891,7 @@ static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
 	struct PP_Clocks minimum_clocks = {0};
 	bool disable_mclk_switching;
 	bool disable_mclk_switching_for_frame_lock;
+	bool disable_mclk_switching_for_display;
 	const struct phm_clock_and_voltage_limits *max_limits;
 	uint32_t i;
 	struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
@@ -2898,9 +2899,12 @@ static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
 			(struct phm_ppt_v1_information *)(hwmgr->pptable);
 	int32_t count;
 	int32_t stable_pstate_sclk = 0, stable_pstate_mclk = 0;
+	uint32_t latency;
+	int latency_allowed = 0;
 
 	data->battery_state = (PP_StateUILabel_Battery ==
 			request_ps->classification.ui_label);
+	data->mclk_ignore_signal = false;
 
 	PP_ASSERT_WITH_CODE(smu7_ps->performance_level_count == 2,
 				 "VI should always have 2 performance levels",
@@ -2947,25 +2951,20 @@ static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
 		minimum_clocks.memoryClock = stable_pstate_mclk;
 	}
 
+	if (hwmgr->display_config->num_display == 0)
+		data->mclk_ignore_signal = true;
+
 	disable_mclk_switching_for_frame_lock = phm_cap_enabled(
 				    hwmgr->platform_descriptor.platformCaps,
 				    PHM_PlatformCaps_DisableMclkSwitchingForFrameLock);
-
-
-	if (hwmgr->display_config->num_display == 0)
-		disable_mclk_switching = false;
-	else
-		disable_mclk_switching = ((1 < hwmgr->display_config->num_display) ||
-					  disable_mclk_switching_for_frame_lock ||
-					  smu7_vblank_too_short(hwmgr, hwmgr->display_config->min_vblank_time));
+	disable_mclk_switching_for_display = (((1 < hwmgr->display_config->num_display) &&
+						!hwmgr->display_config->multi_monitor_in_sync) ||
+						smu7_vblank_too_short(hwmgr, hwmgr->display_config->min_vblank_time));
+	disable_mclk_switching = disable_mclk_switching_for_display || disable_mclk_switching_for_frame_lock;
 
 	sclk = smu7_ps->performance_levels[0].engine_clock;
 	mclk = smu7_ps->performance_levels[0].memory_clock;
 
-	if (disable_mclk_switching)
-		mclk = smu7_ps->performance_levels
-		[smu7_ps->performance_level_count - 1].memory_clock;
-
 	if (sclk < minimum_clocks.engineClock)
 		sclk = (minimum_clocks.engineClock > max_limits->sclk) ?
 				max_limits->sclk : minimum_clocks.engineClock;
@@ -2987,8 +2986,27 @@ static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
 		if (mclk < smu7_ps->performance_levels[1].memory_clock)
 			mclk = smu7_ps->performance_levels[1].memory_clock;
 
+		if (disable_mclk_switching_for_display) {
+			latency = hwmgr->display_config->dce_tolerable_mclk_in_active_latency;
+			for (i = 0; i < data->mclk_latency_table.count; i++) {
+				if (data->mclk_latency_table.entries[i].latency <= latency) {
+					latency_allowed = 1;
+
+					if ((data->mclk_latency_table.entries[i].frequency >= smu7_ps->performance_levels[0].memory_clock) &&
+					    (data->mclk_latency_table.entries[i].frequency <= smu7_ps->performance_levels[1].memory_clock)) {
+						mclk = data->mclk_latency_table.entries[i].frequency;
+						break;
+					}
+				}
+			}
+
+			if ((i >= data->mclk_latency_table.count) && !latency_allowed)
+				data->mclk_ignore_signal = true;
+			else
+				data->mclk_ignore_signal = false;
+		}
+
 		smu7_ps->performance_levels[0].memory_clock = mclk;
-		smu7_ps->performance_levels[1].memory_clock = mclk;
 	} else {
 		if (smu7_ps->performance_levels[1].memory_clock <
 				smu7_ps->performance_levels[0].memory_clock)
@@ -3925,13 +3943,20 @@ static int smu7_notify_link_speed_change_after_state_change(
 	return 0;
 }
 
+static int
+smu7_notify_smc_display_change(struct pp_hwmgr *hwmgr, bool has_display)
+{
+	PPSMC_Msg msg = has_display ? (PPSMC_Msg)PPSMC_HasDisplay : (PPSMC_Msg)PPSMC_NoDisplay;
+
+	return (smum_send_msg_to_smc(hwmgr, msg) == 0) ?  0 : -1;
+}
+
 static int smu7_notify_smc_display(struct pp_hwmgr *hwmgr)
 {
 	struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 
-	if (hwmgr->display_config->num_display > 1 &&
-			!hwmgr->display_config->multi_monitor_in_sync)
-		return (smum_send_msg_to_smc(hwmgr, (PPSMC_Msg)PPSMC_NoDisplay) == 0) ?  0 : -EINVAL;
+	if (data->mclk_ignore_signal)
+		return (smu7_notify_smc_display_change(hwmgr, false) == 0) ? 0 : -EINVAL;
 
 	if (hwmgr->feature_mask & PP_VBI_TIME_SUPPORT_MASK) {
 		if (hwmgr->chip_id == CHIP_VEGAM)
@@ -3940,8 +3965,9 @@ static int smu7_notify_smc_display(struct pp_hwmgr *hwmgr)
 		else
 			smum_send_msg_to_smc_with_parameter(hwmgr,
 					(PPSMC_Msg)PPSMC_MSG_SetVBITimeout, data->frame_time_x2);
+		data->last_sent_vbi_timeout = data->frame_time_x2;
 	}
-	return (smum_send_msg_to_smc(hwmgr, (PPSMC_Msg)PPSMC_HasDisplay) == 0) ?  0 : -EINVAL;
+	return (smu7_notify_smc_display_change(hwmgr, true) == 0) ? 0 : -EINVAL;
 }
 
 static int smu7_set_power_state_tasks(struct pp_hwmgr *hwmgr, const void *input)
@@ -4023,21 +4049,10 @@ static int smu7_set_max_fan_pwm_output(struct pp_hwmgr *hwmgr, uint16_t us_max_f
 			PPSMC_MSG_SetFanPwmMax, us_max_fan_pwm);
 }
 
-static int
-smu7_notify_smc_display_change(struct pp_hwmgr *hwmgr, bool has_display)
-{
-	PPSMC_Msg msg = has_display ? (PPSMC_Msg)PPSMC_HasDisplay : (PPSMC_Msg)PPSMC_NoDisplay;
-
-	return (smum_send_msg_to_smc(hwmgr, msg) == 0) ?  0 : -1;
-}
 
 static int
 smu7_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr)
 {
-	if (hwmgr->display_config->num_display > 1 &&
-			!hwmgr->display_config->multi_monitor_in_sync)
-		smu7_notify_smc_display_change(hwmgr, false);
-
 	return 0;
 }
 
@@ -4151,7 +4166,7 @@ smu7_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)
 	if (data->display_timing.num_existing_displays != hwmgr->display_config->num_display)
 		is_update_required = true;
 
-	if (data->display_timing.vrefresh != hwmgr->display_config->vrefresh)
+	if (data->last_sent_vbi_timeout != data->frame_time_x2)
 		is_update_required = true;
 
 	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) {
@@ -4668,20 +4683,26 @@ static uint32_t smu7_get_mem_latency(struct pp_hwmgr *hwmgr, uint32_t clk)
 
 static int smu7_get_mclks(struct pp_hwmgr *hwmgr, struct amd_pp_clocks *clocks)
 {
+	struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 	struct phm_ppt_v1_information *table_info =
 			(struct phm_ppt_v1_information *)hwmgr->pptable;
 	struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table;
 	int i;
 	struct phm_clock_voltage_dependency_table *mclk_table;
 
+	data->mclk_latency_table.count = 0;
 	if (hwmgr->pp_table_version == PP_TABLE_V1) {
 		if (table_info == NULL)
 			return -EINVAL;
 		dep_mclk_table = table_info->vdd_dep_on_mclk;
 		for (i = 0; i < dep_mclk_table->count; i++) {
 			clocks->clock[i] = dep_mclk_table->entries[i].clk * 10;
-			clocks->latency[i] = smu7_get_mem_latency(hwmgr,
+			data->mclk_latency_table.entries[i].frequency =
+				dep_mclk_table->entries[i].clk;
+			clocks->latency[i] = data->mclk_latency_table.entries[i].latency =
+				smu7_get_mem_latency(hwmgr,
 						dep_mclk_table->entries[i].clk);
+			data->mclk_latency_table.count++;
 		}
 		clocks->count = dep_mclk_table->count;
 	} else if (hwmgr->pp_table_version == PP_TABLE_V0) {
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h
index 69d361f8dfca..6883ffd55b2b 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h
@@ -200,6 +200,16 @@ struct profile_mode_setting {
 	uint16_t mclk_activity;
 };
 
+struct smu7_mclk_latency_entries {
+	uint32_t frequency;
+	uint32_t latency;
+};
+
+struct smu7_mclk_latency_table {
+	uint32_t count;
+	struct smu7_mclk_latency_entries entries[8];
+};
+
 struct smu7_hwmgr {
 	struct smu7_dpm_table			dpm_table;
 	struct smu7_dpm_table			golden_dpm_table;
@@ -328,6 +338,10 @@ struct smu7_hwmgr {
 	uint16_t                              mem_latency_low;
 	uint32_t                              vr_config;
 	struct profile_mode_setting           current_profile_setting;
+
+	bool                                  mclk_ignore_signal;
+	struct smu7_mclk_latency_table        mclk_latency_table;
+	uint32_t                              last_sent_vbi_timeout;
 };
 
 /* To convert to Q8.8 format for firmware */
-- 
2.21.0