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

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
......@@ -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 ************)
......
......@@ -37,24 +37,52 @@ static void push_error_status(struct mod_hdcp *hdcp,
HDCP_ERROR_TRACE(hdcp, status);
}
hdcp->connection.hdcp1_retry_count++;
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) {
......
......@@ -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_ */
This diff is collapsed.
This diff is collapsed.
......@@ -77,6 +77,7 @@ enum mod_hdcp_status {
MOD_HDCP_STATUS_HDCP2_H_PRIME_PENDING,
MOD_HDCP_STATUS_HDCP2_PAIRING_INFO_PENDING,
MOD_HDCP_STATUS_HDCP2_VALIDATE_AKE_CERT_FAILURE,
MOD_HDCP_STATUS_HDCP2_AKE_CERT_REVOKED,
MOD_HDCP_STATUS_HDCP2_VALIDATE_H_PRIME_FAILURE,
MOD_HDCP_STATUS_HDCP2_VALIDATE_PAIRING_INFO_FAILURE,
MOD_HDCP_STATUS_HDCP2_PREP_LC_INIT_FAILURE,
......@@ -86,6 +87,7 @@ enum mod_hdcp_status {
MOD_HDCP_STATUS_HDCP2_ENABLE_ENCRYPTION_FAILURE,
MOD_HDCP_STATUS_HDCP2_RX_ID_LIST_NOT_READY,
MOD_HDCP_STATUS_HDCP2_VALIDATE_RX_ID_LIST_FAILURE,
MOD_HDCP_STATUS_HDCP2_RX_ID_LIST_REVOKED,
MOD_HDCP_STATUS_HDCP2_ENABLE_STREAM_ENCRYPTION,
MOD_HDCP_STATUS_HDCP2_STREAM_READY_PENDING,
MOD_HDCP_STATUS_HDCP2_VALIDATE_STREAM_READY_FAILURE,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment