Commit fe8db3bc authored by Bhawanpreet Lakha's avatar Bhawanpreet Lakha Committed by Alex Deucher
Browse files

drm/amd/display: query hdcp capability during link detect



[Why]
Query the hdcp caps of a link, it is useful and can be reported to the user

[How]
Create a query function and call it during link detect

Signed-off-by: default avatarBhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Reviewed-by: default avatarRodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 1ea2b260
Loading
Loading
Loading
Loading
+56 −0
Original line number Diff line number Diff line
@@ -515,6 +515,50 @@ static void link_disconnect_remap(struct dc_sink *prev_sink, struct dc_link *lin
	link->local_sink = prev_sink;
}

#if defined(CONFIG_DRM_AMD_DC_HDCP)
static void query_hdcp_capability(enum signal_type signal, struct dc_link *link)
{
	struct hdcp_protection_message msg22;
	struct hdcp_protection_message msg14;

	memset(&msg22, 0, sizeof(struct hdcp_protection_message));
	memset(&msg14, 0, sizeof(struct hdcp_protection_message));
	memset(link->hdcp_caps.rx_caps.raw, 0,
		sizeof(link->hdcp_caps.rx_caps.raw));

	if ((link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
			link->ddc->transaction_type ==
			DDC_TRANSACTION_TYPE_I2C_OVER_AUX) ||
			link->connector_signal == SIGNAL_TYPE_EDP) {
		msg22.data = link->hdcp_caps.rx_caps.raw;
		msg22.length = sizeof(link->hdcp_caps.rx_caps.raw);
		msg22.msg_id = HDCP_MESSAGE_ID_RX_CAPS;
	} else {
		msg22.data = &link->hdcp_caps.rx_caps.fields.version;
		msg22.length = sizeof(link->hdcp_caps.rx_caps.fields.version);
		msg22.msg_id = HDCP_MESSAGE_ID_HDCP2VERSION;
	}
	msg22.version = HDCP_VERSION_22;
	msg22.link = HDCP_LINK_PRIMARY;
	msg22.max_retries = 5;
	dc_process_hdcp_msg(signal, link, &msg22);

	if (signal == SIGNAL_TYPE_DISPLAY_PORT || signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
		enum hdcp_message_status status = HDCP_MESSAGE_UNSUPPORTED;

		msg14.data = &link->hdcp_caps.bcaps.raw;
		msg14.length = sizeof(link->hdcp_caps.bcaps.raw);
		msg14.msg_id = HDCP_MESSAGE_ID_READ_BCAPS;
		msg14.version = HDCP_VERSION_14;
		msg14.link = HDCP_LINK_PRIMARY;
		msg14.max_retries = 5;

		status = dc_process_hdcp_msg(signal, link, &msg14);
	}

}
#endif

static void read_current_link_settings_on_detect(struct dc_link *link)
{
	union lane_count_set lane_count_set = { {0} };
@@ -607,6 +651,12 @@ static bool detect_dp(struct dc_link *link,
			dal_ddc_service_set_transaction_type(link->ddc,
							     sink_caps->transaction_type);

#if defined(CONFIG_DRM_AMD_DC_HDCP)
			/* In case of fallback to SST when topology discovery below fails
			 * HDCP caps will be querried again later by the upper layer (caller
			 * of this function). */
			query_hdcp_capability(SIGNAL_TYPE_DISPLAY_PORT_MST, link);
#endif
			/*
			 * This call will initiate MST topology discovery. Which
			 * will detect MST ports and add new DRM connector DRM
@@ -976,6 +1026,9 @@ static bool dc_link_detect_helper(struct dc_link *link,
			 * TODO debug why Dell 2413 doesn't like
			 *  two link trainings
			 */
#if defined(CONFIG_DRM_AMD_DC_HDCP)
			query_hdcp_capability(sink->sink_signal, link);
#endif

			// verify link cap for SST non-seamless boot
			if (!perform_dp_seamless_boot)
@@ -989,6 +1042,9 @@ static bool dc_link_detect_helper(struct dc_link *link,
				sink = prev_sink;
				prev_sink = NULL;
			}
#if defined(CONFIG_DRM_AMD_DC_HDCP)
			query_hdcp_capability(sink->sink_signal, link);
#endif
		}

		/* HDMI-DVI Dongle */
+41 −0
Original line number Diff line number Diff line
@@ -29,6 +29,9 @@
#include "dc_types.h"
#include "grph_object_defs.h"
#include "logger_types.h"
#if defined(CONFIG_DRM_AMD_DC_HDCP)
#include "hdcp_types.h"
#endif
#include "gpio_types.h"
#include "link_service_types.h"
#include "grph_object_ctrl_defs.h"
@@ -1004,6 +1007,35 @@ union dpcd_sink_ext_caps {
	uint8_t raw;
};

#if defined(CONFIG_DRM_AMD_DC_HDCP)
union hdcp_rx_caps {
	struct {
		uint8_t version;
		uint8_t reserved;
		struct {
			uint8_t repeater	: 1;
			uint8_t hdcp_capable	: 1;
			uint8_t reserved	: 6;
		} byte0;
	} fields;
	uint8_t raw[3];
};

union hdcp_bcaps {
	struct {
		uint8_t HDCP_CAPABLE:1;
		uint8_t REPEATER:1;
		uint8_t RESERVED:6;
	} bits;
	uint8_t raw;
};

struct hdcp_caps {
	union hdcp_rx_caps rx_caps;
	union hdcp_bcaps bcaps;
};
#endif

#include "dc_link.h"

/*******************************************************************************
@@ -1107,6 +1139,15 @@ void dc_resume(struct dc *dc);
unsigned int dc_get_current_backlight_pwm(struct dc *dc);
unsigned int dc_get_target_backlight_pwm(struct dc *dc);

#if defined(CONFIG_DRM_AMD_DC_HDCP)
/*
 * HDCP Interfaces
 */
enum hdcp_message_status dc_process_hdcp_msg(
		enum signal_type signal,
		struct dc_link *link,
		struct hdcp_protection_message *message_info);
#endif
bool dc_is_dmcu_initialized(struct dc *dc);

enum dc_status dc_set_clock(struct dc *dc, enum dc_clock_type clock_type, uint32_t clk_khz, uint32_t stepping);
+3 −0
Original line number Diff line number Diff line
@@ -126,6 +126,9 @@ struct dc_link {
	uint32_t dongle_max_pix_clk;
	unsigned short chip_caps;
	unsigned int dpcd_sink_count;
#if defined(CONFIG_DRM_AMD_DC_HDCP)
	struct hdcp_caps hdcp_caps;
#endif
	enum edp_revision edp_revision;
	bool psr_feature_enabled;
	bool psr_allow_active;
+89 −0
Original line number Diff line number Diff line
@@ -322,3 +322,92 @@ static const struct protection_properties dp_11_protection = {
	.process_transaction = dp_11_process_transaction
};

static const struct protection_properties *get_protection_properties_by_signal(
	struct dc_link *link,
	enum signal_type st,
	enum hdcp_version version)
{
	switch (version) {
	case HDCP_VERSION_14:
		switch (st) {
		case SIGNAL_TYPE_DVI_SINGLE_LINK:
		case SIGNAL_TYPE_DVI_DUAL_LINK:
		case SIGNAL_TYPE_HDMI_TYPE_A:
			return &hdmi_14_protection;
		case SIGNAL_TYPE_DISPLAY_PORT:
			if (link &&
				(link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER ||
				link->dpcd_caps.dongle_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER)) {
				return &non_supported_protection;
			}
			return &dp_11_protection;
		case SIGNAL_TYPE_DISPLAY_PORT_MST:
		case SIGNAL_TYPE_EDP:
			return &dp_11_protection;
		default:
			return &non_supported_protection;
		}
		break;
	case HDCP_VERSION_22:
		switch (st) {
		case SIGNAL_TYPE_DVI_SINGLE_LINK:
		case SIGNAL_TYPE_DVI_DUAL_LINK:
		case SIGNAL_TYPE_HDMI_TYPE_A:
			return &hdmi_14_protection; //todo version2.2
		case SIGNAL_TYPE_DISPLAY_PORT:
		case SIGNAL_TYPE_DISPLAY_PORT_MST:
		case SIGNAL_TYPE_EDP:
			return &dp_11_protection;  //todo version2.2
		default:
			return &non_supported_protection;
		}
		break;
	default:
		return &non_supported_protection;
	}
}

enum hdcp_message_status dc_process_hdcp_msg(
	enum signal_type signal,
	struct dc_link *link,
	struct hdcp_protection_message *message_info)
{
	enum hdcp_message_status status = HDCP_MESSAGE_FAILURE;
	uint32_t i = 0;

	const struct protection_properties *protection_props;

	if (!message_info)
		return HDCP_MESSAGE_UNSUPPORTED;

	if (message_info->msg_id < HDCP_MESSAGE_ID_READ_BKSV ||
		message_info->msg_id >= HDCP_MESSAGE_ID_MAX)
		return HDCP_MESSAGE_UNSUPPORTED;

	protection_props =
		get_protection_properties_by_signal(
			link,
			signal,
			message_info->version);

	if (!protection_props->supported)
		return HDCP_MESSAGE_UNSUPPORTED;

	if (protection_props->process_transaction(
		link,
		message_info)) {
		status = HDCP_MESSAGE_SUCCESS;
	} else {
		for (i = 0; i < message_info->max_retries; i++) {
			if (protection_props->process_transaction(
						link,
						message_info)) {
				status = HDCP_MESSAGE_SUCCESS;
				break;
			}
		}
	}

	return status;
}
+7 −0
Original line number Diff line number Diff line
@@ -83,6 +83,12 @@ enum hdcp_link {
	HDCP_LINK_SECONDARY
};

enum hdcp_message_status {
	HDCP_MESSAGE_SUCCESS,
	HDCP_MESSAGE_FAILURE,
	HDCP_MESSAGE_UNSUPPORTED
};

struct hdcp_protection_message {
	enum hdcp_version version;
	/* relevant only for DVI */
@@ -91,6 +97,7 @@ struct hdcp_protection_message {
	uint32_t length;
	uint8_t max_retries;
	uint8_t *data;
	enum hdcp_message_status status;
};

#endif