Commit 2944dbed authored by Jimmy Kizito's avatar Jimmy Kizito Committed by Alex Deucher
Browse files

drm/amd/display: Add work around for AUX failure on wake.



[Why]
When waking from low-power states, a DP sink may remain unresponsive to
AUX transactions.

[How]
Try to toggle DPCD SET_POWER register repeatedly (up to a maximum
timeout value) until DP sink becomes responsive.

Reviewed-by: default avatarMustapha Ghaddar <Mustapha.Ghaddar@amd.com>
Acked-by: default avatarAlex Hung <alex.hung@amd.com>
Signed-off-by: default avatarJimmy Kizito <Jimmy.Kizito@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 83e9faac
Loading
Loading
Loading
Loading
+59 −0
Original line number Diff line number Diff line
@@ -5216,6 +5216,62 @@ static void retrieve_cable_id(struct dc_link *link)
				&link->dpcd_caps.cable_id, &usbc_cable_id);
}

/* DPRX may take some time to respond to AUX messages after HPD asserted.
 * If AUX read unsuccessful, try to wake unresponsive DPRX by toggling DPCD SET_POWER (0x600).
 */
static enum dc_status wa_try_to_wake_dprx(struct dc_link *link, uint64_t timeout_ms)
{
	enum dc_status status = DC_ERROR_UNEXPECTED;
	uint8_t dpcd_data = 0;
	uint64_t start_ts = 0;
	uint64_t current_ts = 0;
	uint64_t time_taken_ms = 0;
	enum dc_connection_type type = dc_connection_none;

	status = core_link_read_dpcd(
			link,
			DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV,
			&dpcd_data,
			sizeof(dpcd_data));

	if (status != DC_OK) {
		DC_LOG_WARNING("%s: Read DPCD LTTPR_CAP failed - try to toggle DPCD SET_POWER for %lld ms.",
				__func__,
				timeout_ms);
		start_ts = dm_get_timestamp(link->ctx);

		do {
			if (!dc_link_detect_sink(link, &type) || type == dc_connection_none)
				break;

			dpcd_data = DP_SET_POWER_D3;
			status = core_link_write_dpcd(
					link,
					DP_SET_POWER,
					&dpcd_data,
					sizeof(dpcd_data));

			dpcd_data = DP_SET_POWER_D0;
			status = core_link_write_dpcd(
					link,
					DP_SET_POWER,
					&dpcd_data,
					sizeof(dpcd_data));

			current_ts = dm_get_timestamp(link->ctx);
			time_taken_ms = div_u64(dm_get_elapse_time_in_ns(link->ctx, current_ts, start_ts), 1000000);
		} while (status != DC_OK && time_taken_ms < timeout_ms);

		DC_LOG_WARNING("%s: DPCD SET_POWER %s after %lld ms%s",
				__func__,
				(status == DC_OK) ? "succeeded" : "failed",
				time_taken_ms,
				(type == dc_connection_none) ? ". Unplugged." : ".");
	}

	return status;
}

static bool retrieve_link_cap(struct dc_link *link)
{
	/* DP_ADAPTER_CAP - DP_DPCD_REV + 1 == 16 and also DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT + 1 == 16,
@@ -5251,6 +5307,9 @@ static bool retrieve_link_cap(struct dc_link *link)
	dc_link_aux_try_to_configure_timeout(link->ddc,
			LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD);

	/* Try to ensure AUX channel active before proceeding. */
	status = wa_try_to_wake_dprx(link, LINK_AUX_WAKE_TIMEOUT_MS);

	is_lttpr_present = dp_retrieve_lttpr_cap(link);
	/* Read DP tunneling information. */
	status = dpcd_get_tunneling_device_data(link);
+1 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
#define MAX_MTP_SLOT_COUNT 64
#define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50
#define TRAINING_AUX_RD_INTERVAL 100 //us
#define LINK_AUX_WAKE_TIMEOUT_MS 1500 // Timeout when trying to wake unresponsive DPRX.

struct dc_link;
struct dc_stream_state;