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

drm/amd/display: Add execution and transition states for HDCP2.2



The module works like a state machine

                                    +-------------+
                            ------> | Execution.c | ------
                            |       +-------------+       |
                            |                             V
    +----+              +--------+                 +--------------+
    | DM |    ----->    | Hdcp.c |  <------------  | Transition.c |
    +----+    <-----    +--------+                 +--------------+

This patch adds the execution and transition files for 2.2

Signed-off-by: default avatarBhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Reviewed-by: default avatarHarry Wentland <harry.wentland@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent eff682f8
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -24,7 +24,8 @@
#

HDCP = hdcp_ddc.o hdcp_log.o hdcp_psp.o hdcp.o \
		hdcp1_execution.o hdcp1_transition.o
		hdcp1_execution.o hdcp1_transition.o \
		hdcp2_execution.o hdcp2_transition.o

AMD_DAL_HDCP = $(addprefix $(AMDDALPATH)/modules/hdcp/,$(HDCP))
#$(info ************  DAL-HDCP_MAKEFILE ************)
+78 −8
Original line number Diff line number Diff line
@@ -37,24 +37,52 @@ static void push_error_status(struct mod_hdcp *hdcp,
		HDCP_ERROR_TRACE(hdcp, status);
	}

	if (is_hdcp1(hdcp)) {
		hdcp->connection.hdcp1_retry_count++;
	} else if (is_hdcp2(hdcp)) {
		hdcp->connection.hdcp2_retry_count++;
	}
}

static uint8_t is_cp_desired_hdcp1(struct mod_hdcp *hdcp)
{
	int i, display_enabled = 0;
	int i, is_auth_needed = 0;

	/* if all displays on the link are disabled, hdcp is not desired */
	/* if all displays on the link don't need authentication,
	 * hdcp is not desired
	 */
	for (i = 0; i < MAX_NUM_OF_DISPLAYS; i++) {
		if (hdcp->connection.displays[i].state != MOD_HDCP_DISPLAY_INACTIVE &&
				!hdcp->connection.displays[i].adjust.disable) {
			display_enabled = 1;
			is_auth_needed = 1;
			break;
		}
	}

	return (hdcp->connection.hdcp1_retry_count < MAX_NUM_OF_ATTEMPTS) &&
			display_enabled && !hdcp->connection.link.adjust.hdcp1.disable;
			is_auth_needed &&
			!hdcp->connection.link.adjust.hdcp1.disable;
}

static uint8_t is_cp_desired_hdcp2(struct mod_hdcp *hdcp)
{
	int i, is_auth_needed = 0;

	/* if all displays on the link don't need authentication,
	 * hdcp is not desired
	 */
	for (i = 0; i < MAX_NUM_OF_DISPLAYS; i++) {
		if (hdcp->connection.displays[i].state != MOD_HDCP_DISPLAY_INACTIVE &&
				!hdcp->connection.displays[i].adjust.disable) {
			is_auth_needed = 1;
			break;
		}
	}

	return (hdcp->connection.hdcp2_retry_count < MAX_NUM_OF_ATTEMPTS) &&
			is_auth_needed &&
			!hdcp->connection.link.adjust.hdcp2.disable &&
			!hdcp->connection.is_hdcp2_revoked;
}

static enum mod_hdcp_status execution(struct mod_hdcp *hdcp,
@@ -82,6 +110,11 @@ static enum mod_hdcp_status execution(struct mod_hdcp *hdcp,
	} else if (is_in_hdcp1_dp_states(hdcp)) {
		status = mod_hdcp_hdcp1_dp_execution(hdcp,
				event_ctx, &input->hdcp1);
	} else if (is_in_hdcp2_states(hdcp)) {
		status = mod_hdcp_hdcp2_execution(hdcp, event_ctx, &input->hdcp2);
	} else if (is_in_hdcp2_dp_states(hdcp)) {
		status = mod_hdcp_hdcp2_dp_execution(hdcp,
				event_ctx, &input->hdcp2);
	}
out:
	return status;
@@ -99,7 +132,10 @@ static enum mod_hdcp_status transition(struct mod_hdcp *hdcp,

	if (is_in_initialized_state(hdcp)) {
		if (is_dp_hdcp(hdcp))
			if (is_cp_desired_hdcp1(hdcp)) {
			if (is_cp_desired_hdcp2(hdcp)) {
				callback_in_ms(0, output);
				set_state_id(hdcp, output, D2_A0_DETERMINE_RX_HDCP_CAPABLE);
			} else if (is_cp_desired_hdcp1(hdcp)) {
				callback_in_ms(0, output);
				set_state_id(hdcp, output, D1_A0_DETERMINE_RX_HDCP_CAPABLE);
			} else {
@@ -107,7 +143,10 @@ static enum mod_hdcp_status transition(struct mod_hdcp *hdcp,
				set_state_id(hdcp, output, HDCP_CP_NOT_DESIRED);
			}
		else if (is_hdmi_dvi_sl_hdcp(hdcp))
			if (is_cp_desired_hdcp1(hdcp)) {
			if (is_cp_desired_hdcp2(hdcp)) {
				callback_in_ms(0, output);
				set_state_id(hdcp, output, H2_A0_KNOWN_HDCP2_CAPABLE_RX);
			} else if (is_cp_desired_hdcp1(hdcp)) {
				callback_in_ms(0, output);
				set_state_id(hdcp, output, H1_A0_WAIT_FOR_ACTIVE_RX);
			} else {
@@ -126,6 +165,12 @@ static enum mod_hdcp_status transition(struct mod_hdcp *hdcp,
	} else if (is_in_hdcp1_dp_states(hdcp)) {
		status = mod_hdcp_hdcp1_dp_transition(hdcp,
				event_ctx, &input->hdcp1, output);
	} else if (is_in_hdcp2_states(hdcp)) {
		status = mod_hdcp_hdcp2_transition(hdcp,
				event_ctx, &input->hdcp2, output);
	} else if (is_in_hdcp2_dp_states(hdcp)) {
		status = mod_hdcp_hdcp2_dp_transition(hdcp,
				event_ctx, &input->hdcp2, output);
	} else {
		status = MOD_HDCP_STATUS_INVALID_STATE;
	}
@@ -139,9 +184,13 @@ static enum mod_hdcp_status reset_authentication(struct mod_hdcp *hdcp,
	enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;

	if (is_hdcp1(hdcp)) {
		if (hdcp->auth.trans_input.hdcp1.create_session != UNKNOWN)
		if (hdcp->auth.trans_input.hdcp1.create_session != UNKNOWN) {
			/* TODO - update psp to unify create session failure
			 * recovery between hdcp1 and 2.
			 */
			mod_hdcp_hdcp1_destroy_session(hdcp);

		}
		if (hdcp->auth.trans_input.hdcp1.add_topology == PASS) {
			status = mod_hdcp_remove_display_topology(hdcp);
			if (status != MOD_HDCP_STATUS_SUCCESS) {
@@ -154,6 +203,27 @@ static enum mod_hdcp_status reset_authentication(struct mod_hdcp *hdcp,
		memset(&hdcp->auth, 0, sizeof(struct mod_hdcp_authentication));
		memset(&hdcp->state, 0, sizeof(struct mod_hdcp_state));
		set_state_id(hdcp, output, HDCP_INITIALIZED);
	} else if (is_hdcp2(hdcp)) {
		if (hdcp->auth.trans_input.hdcp2.create_session == PASS) {
			status = mod_hdcp_hdcp2_destroy_session(hdcp);
			if (status != MOD_HDCP_STATUS_SUCCESS) {
				output->callback_needed = 0;
				output->watchdog_timer_needed = 0;
				goto out;
			}
		}
		if (hdcp->auth.trans_input.hdcp2.add_topology == PASS) {
			status = mod_hdcp_remove_display_topology(hdcp);
			if (status != MOD_HDCP_STATUS_SUCCESS) {
				output->callback_needed = 0;
				output->watchdog_timer_needed = 0;
				goto out;
			}
		}
		HDCP_TOP_RESET_AUTH_TRACE(hdcp);
		memset(&hdcp->auth, 0, sizeof(struct mod_hdcp_authentication));
		memset(&hdcp->state, 0, sizeof(struct mod_hdcp_state));
		set_state_id(hdcp, output, HDCP_INITIALIZED);
	} else if (is_in_cp_not_desired_state(hdcp)) {
		status = mod_hdcp_remove_display_topology(hdcp);
		if (status != MOD_HDCP_STATUS_SUCCESS) {
+127 −0
Original line number Diff line number Diff line
@@ -44,11 +44,13 @@
#define BINFO_MAX_DEVS_EXCEEDED_MASK_DP			0x0080
#define BINFO_MAX_CASCADE_EXCEEDED_MASK_DP		0x0800

#define VERSION_HDCP2_MASK				0x04
#define RXSTATUS_MSG_SIZE_MASK				0x03FF
#define RXSTATUS_READY_MASK				0x0400
#define RXSTATUS_REAUTH_REQUEST_MASK			0x0800
#define RXIDLIST_DEVICE_COUNT_LOWER_MASK		0xf0
#define RXIDLIST_DEVICE_COUNT_UPPER_MASK		0x01
#define RXCAPS_BYTE2_HDCP2_VERSION_DP			0x02
#define RXCAPS_BYTE0_HDCP_CAPABLE_MASK_DP		0x02
#define RXSTATUS_READY_MASK_DP				0x0001
#define RXSTATUS_H_P_AVAILABLE_MASK_DP			0x0002
@@ -92,8 +94,52 @@ struct mod_hdcp_transition_input_hdcp1 {
	uint8_t stream_encryption_dp;
};

struct mod_hdcp_transition_input_hdcp2 {
	uint8_t hdcp2version_read;
	uint8_t hdcp2_capable_check;
	uint8_t add_topology;
	uint8_t create_session;
	uint8_t ake_init_prepare;
	uint8_t ake_init_write;
	uint8_t rxstatus_read;
	uint8_t ake_cert_available;
	uint8_t ake_cert_read;
	uint8_t ake_cert_validation;
	uint8_t stored_km_write;
	uint8_t no_stored_km_write;
	uint8_t h_prime_available;
	uint8_t h_prime_read;
	uint8_t pairing_available;
	uint8_t pairing_info_read;
	uint8_t h_prime_validation;
	uint8_t lc_init_prepare;
	uint8_t lc_init_write;
	uint8_t l_prime_available_poll;
	uint8_t l_prime_read;
	uint8_t l_prime_validation;
	uint8_t eks_prepare;
	uint8_t eks_write;
	uint8_t enable_encryption;
	uint8_t reauth_request_check;
	uint8_t rx_id_list_read;
	uint8_t device_count_check;
	uint8_t rx_id_list_validation;
	uint8_t repeater_auth_ack_write;
	uint8_t prepare_stream_manage;
	uint8_t stream_manage_write;
	uint8_t stream_ready_available;
	uint8_t stream_ready_read;
	uint8_t stream_ready_validation;

	uint8_t rx_caps_read_dp;
	uint8_t content_stream_type_write;
	uint8_t link_integrity_check_dp;
	uint8_t stream_encryption_dp;
};

union mod_hdcp_transition_input {
	struct mod_hdcp_transition_input_hdcp1 hdcp1;
	struct mod_hdcp_transition_input_hdcp2 hdcp2;
};

struct mod_hdcp_message_hdcp1 {
@@ -150,8 +196,10 @@ struct mod_hdcp_connection {
	struct mod_hdcp_display displays[MAX_NUM_OF_DISPLAYS];
	uint8_t is_repeater;
	uint8_t is_km_stored;
	uint8_t is_hdcp2_revoked;
	struct mod_hdcp_trace trace;
	uint8_t hdcp1_retry_count;
	uint8_t hdcp2_retry_count;
};

/* contains values per authentication cycle */
@@ -219,6 +267,50 @@ enum mod_hdcp_hdcp1_dp_state_id {
	HDCP1_DP_STATE_END = D1_A7_READ_KSV_LIST,
};

enum mod_hdcp_hdcp2_state_id {
	HDCP2_STATE_START = HDCP1_DP_STATE_END,
	H2_A0_KNOWN_HDCP2_CAPABLE_RX,
	H2_A1_SEND_AKE_INIT,
	H2_A1_VALIDATE_AKE_CERT,
	H2_A1_SEND_NO_STORED_KM,
	H2_A1_READ_H_PRIME,
	H2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME,
	H2_A1_SEND_STORED_KM,
	H2_A1_VALIDATE_H_PRIME,
	H2_A2_LOCALITY_CHECK,
	H2_A3_EXCHANGE_KS_AND_TEST_FOR_REPEATER,
	H2_ENABLE_ENCRYPTION,
	H2_A5_AUTHENTICATED,
	H2_A6_WAIT_FOR_RX_ID_LIST,
	H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK,
	H2_A9_SEND_STREAM_MANAGEMENT,
	H2_A9_VALIDATE_STREAM_READY,
	HDCP2_STATE_END = H2_A9_VALIDATE_STREAM_READY,
};

enum mod_hdcp_hdcp2_dp_state_id {
	HDCP2_DP_STATE_START = HDCP2_STATE_END,
	D2_A0_DETERMINE_RX_HDCP_CAPABLE,
	D2_A1_SEND_AKE_INIT,
	D2_A1_VALIDATE_AKE_CERT,
	D2_A1_SEND_NO_STORED_KM,
	D2_A1_READ_H_PRIME,
	D2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME,
	D2_A1_SEND_STORED_KM,
	D2_A1_VALIDATE_H_PRIME,
	D2_A2_LOCALITY_CHECK,
	D2_A34_EXCHANGE_KS_AND_TEST_FOR_REPEATER,
	D2_SEND_CONTENT_STREAM_TYPE,
	D2_ENABLE_ENCRYPTION,
	D2_A5_AUTHENTICATED,
	D2_A6_WAIT_FOR_RX_ID_LIST,
	D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK,
	D2_A9_SEND_STREAM_MANAGEMENT,
	D2_A9_VALIDATE_STREAM_READY,
	HDCP2_DP_STATE_END = D2_A9_VALIDATE_STREAM_READY,
	HDCP_STATE_END = HDCP2_DP_STATE_END,
};

/* hdcp1 executions and transitions */
typedef enum mod_hdcp_status (*mod_hdcp_action)(struct mod_hdcp *hdcp);
uint8_t mod_hdcp_execute_and_set(
@@ -239,6 +331,22 @@ enum mod_hdcp_status mod_hdcp_hdcp1_dp_transition(struct mod_hdcp *hdcp,
	struct mod_hdcp_transition_input_hdcp1 *input,
	struct mod_hdcp_output *output);

/* hdcp2 executions and transitions */
enum mod_hdcp_status mod_hdcp_hdcp2_execution(struct mod_hdcp *hdcp,
	struct mod_hdcp_event_context *event_ctx,
	struct mod_hdcp_transition_input_hdcp2 *input);
enum mod_hdcp_status mod_hdcp_hdcp2_dp_execution(struct mod_hdcp *hdcp,
	struct mod_hdcp_event_context *event_ctx,
	struct mod_hdcp_transition_input_hdcp2 *input);
enum mod_hdcp_status mod_hdcp_hdcp2_transition(struct mod_hdcp *hdcp,
	struct mod_hdcp_event_context *event_ctx,
	struct mod_hdcp_transition_input_hdcp2 *input,
	struct mod_hdcp_output *output);
enum mod_hdcp_status mod_hdcp_hdcp2_dp_transition(struct mod_hdcp *hdcp,
	struct mod_hdcp_event_context *event_ctx,
	struct mod_hdcp_transition_input_hdcp2 *input,
	struct mod_hdcp_output *output);

/* log functions */
void mod_hdcp_dump_binary_message(uint8_t *msg, uint32_t msg_size,
		uint8_t *buf, uint32_t buf_size);
@@ -289,6 +397,7 @@ enum mod_hdcp_status mod_hdcp_read_binfo(struct mod_hdcp *hdcp);
enum mod_hdcp_status mod_hdcp_write_aksv(struct mod_hdcp *hdcp);
enum mod_hdcp_status mod_hdcp_write_ainfo(struct mod_hdcp *hdcp);
enum mod_hdcp_status mod_hdcp_write_an(struct mod_hdcp *hdcp);
enum mod_hdcp_status mod_hdcp_read_hdcp2version(struct mod_hdcp *hdcp);
enum mod_hdcp_status mod_hdcp_read_rxcaps(struct mod_hdcp *hdcp);
enum mod_hdcp_status mod_hdcp_read_rxstatus(struct mod_hdcp *hdcp);
enum mod_hdcp_status mod_hdcp_read_ake_cert(struct mod_hdcp *hdcp);
@@ -352,11 +461,28 @@ static inline uint8_t is_in_hdcp1_dp_states(struct mod_hdcp *hdcp)
			current_state(hdcp) <= HDCP1_DP_STATE_END);
}

static inline uint8_t is_in_hdcp2_states(struct mod_hdcp *hdcp)
{
	return (current_state(hdcp) > HDCP2_STATE_START &&
			current_state(hdcp) <= HDCP2_STATE_END);
}

static inline uint8_t is_in_hdcp2_dp_states(struct mod_hdcp *hdcp)
{
	return (current_state(hdcp) > HDCP2_DP_STATE_START &&
			current_state(hdcp) <= HDCP2_DP_STATE_END);
}

static inline uint8_t is_hdcp1(struct mod_hdcp *hdcp)
{
	return (is_in_hdcp1_states(hdcp) || is_in_hdcp1_dp_states(hdcp));
}

static inline uint8_t is_hdcp2(struct mod_hdcp *hdcp)
{
	return (is_in_hdcp2_states(hdcp) || is_in_hdcp2_dp_states(hdcp));
}

static inline uint8_t is_in_cp_not_desired_state(struct mod_hdcp *hdcp)
{
	return current_state(hdcp) == HDCP_CP_NOT_DESIRED;
@@ -481,6 +607,7 @@ static inline struct mod_hdcp_display *get_empty_display_container(
static inline void reset_retry_counts(struct mod_hdcp *hdcp)
{
	hdcp->connection.hdcp1_retry_count = 0;
	hdcp->connection.hdcp2_retry_count = 0;
}

#endif /* HDCP_H_ */
Loading