323 lines · c
1/*2 * Copyright 2019 Advanced Micro Devices, Inc.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR20 * OTHER DEALINGS IN THE SOFTWARE.21 *22 * Authors: AMD23 *24 */25 26#include "hdcp.h"27 28enum mod_hdcp_status mod_hdcp_hdcp1_transition(struct mod_hdcp *hdcp,29 struct mod_hdcp_event_context *event_ctx,30 struct mod_hdcp_transition_input_hdcp1 *input,31 struct mod_hdcp_output *output)32{33 enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;34 struct mod_hdcp_connection *conn = &hdcp->connection;35 struct mod_hdcp_link_adjustment *adjust = &hdcp->connection.link.adjust;36 37 switch (current_state(hdcp)) {38 case H1_A0_WAIT_FOR_ACTIVE_RX:39 if (input->bksv_read != PASS || input->bcaps_read != PASS) {40 /* 1A-04: repeatedly attempts on port access failure */41 callback_in_ms(500, output);42 increment_stay_counter(hdcp);43 break;44 }45 callback_in_ms(0, output);46 set_state_id(hdcp, output, H1_A1_EXCHANGE_KSVS);47 break;48 case H1_A1_EXCHANGE_KSVS:49 if (input->create_session != PASS) {50 /* out of sync with psp state */51 adjust->hdcp1.disable = 1;52 fail_and_restart_in_ms(0, &status, output);53 break;54 } else if (input->an_write != PASS ||55 input->aksv_write != PASS ||56 input->bksv_read != PASS ||57 input->bksv_validation != PASS ||58 input->ainfo_write == FAIL) {59 /* 1A-05: consider invalid bksv a failure */60 fail_and_restart_in_ms(0, &status, output);61 break;62 }63 callback_in_ms(300, output);64 set_state_id(hdcp, output,65 H1_A2_COMPUTATIONS_A3_VALIDATE_RX_A6_TEST_FOR_REPEATER);66 break;67 case H1_A2_COMPUTATIONS_A3_VALIDATE_RX_A6_TEST_FOR_REPEATER:68 if (input->bcaps_read != PASS ||69 input->r0p_read != PASS) {70 fail_and_restart_in_ms(0, &status, output);71 break;72 } else if (input->rx_validation != PASS) {73 /* 1A-06: consider invalid r0' a failure */74 /* 1A-08: consider bksv listed in SRM a failure */75 /*76 * some slow RX will fail rx validation when it is77 * not ready. give it more time to react before retry.78 */79 fail_and_restart_in_ms(1000, &status, output);80 break;81 } else if (!conn->is_repeater && input->encryption != PASS) {82 fail_and_restart_in_ms(0, &status, output);83 break;84 }85 if (conn->is_repeater) {86 callback_in_ms(0, output);87 set_watchdog_in_ms(hdcp, 5000, output);88 set_state_id(hdcp, output, H1_A8_WAIT_FOR_READY);89 } else {90 callback_in_ms(0, output);91 set_state_id(hdcp, output, H1_A45_AUTHENTICATED);92 set_auth_complete(hdcp, output);93 }94 break;95 case H1_A45_AUTHENTICATED:96 if (input->link_maintenance == FAIL) {97 /* 1A-07: consider invalid ri' a failure */98 /* 1A-07a: consider read ri' not returned a failure */99 fail_and_restart_in_ms(0, &status, output);100 break;101 }102 callback_in_ms(500, output);103 increment_stay_counter(hdcp);104 break;105 case H1_A8_WAIT_FOR_READY:106 if (input->ready_check != PASS) {107 if (event_ctx->event ==108 MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) {109 /* 1B-03: fail hdcp on ksv list READY timeout */110 /* prevent black screen in next attempt */111 adjust->hdcp1.postpone_encryption = 1;112 fail_and_restart_in_ms(0, &status, output);113 } else {114 /* continue ksv list READY polling*/115 callback_in_ms(500, output);116 increment_stay_counter(hdcp);117 }118 break;119 }120 callback_in_ms(0, output);121 set_state_id(hdcp, output, H1_A9_READ_KSV_LIST);122 break;123 case H1_A9_READ_KSV_LIST:124 if (input->bstatus_read != PASS ||125 input->max_cascade_check != PASS ||126 input->max_devs_check != PASS ||127 input->device_count_check != PASS ||128 input->ksvlist_read != PASS ||129 input->vp_read != PASS ||130 input->ksvlist_vp_validation != PASS ||131 input->encryption != PASS) {132 /* 1B-06: consider MAX_CASCADE_EXCEEDED a failure */133 /* 1B-05: consider MAX_DEVS_EXCEEDED a failure */134 /* 1B-04: consider invalid v' a failure */135 fail_and_restart_in_ms(0, &status, output);136 break;137 }138 callback_in_ms(0, output);139 set_state_id(hdcp, output, H1_A45_AUTHENTICATED);140 set_auth_complete(hdcp, output);141 break;142 default:143 status = MOD_HDCP_STATUS_INVALID_STATE;144 fail_and_restart_in_ms(0, &status, output);145 break;146 }147 148 return status;149}150 151enum mod_hdcp_status mod_hdcp_hdcp1_dp_transition(struct mod_hdcp *hdcp,152 struct mod_hdcp_event_context *event_ctx,153 struct mod_hdcp_transition_input_hdcp1 *input,154 struct mod_hdcp_output *output)155{156 enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;157 struct mod_hdcp_connection *conn = &hdcp->connection;158 struct mod_hdcp_link_adjustment *adjust = &hdcp->connection.link.adjust;159 160 switch (current_state(hdcp)) {161 case D1_A0_DETERMINE_RX_HDCP_CAPABLE:162 if (input->bcaps_read != PASS) {163 /* 1A-04: no authentication on bcaps read failure */164 fail_and_restart_in_ms(0, &status, output);165 break;166 } else if (input->hdcp_capable_dp != PASS) {167 adjust->hdcp1.disable = 1;168 fail_and_restart_in_ms(0, &status, output);169 break;170 }171 callback_in_ms(0, output);172 set_state_id(hdcp, output, D1_A1_EXCHANGE_KSVS);173 break;174 case D1_A1_EXCHANGE_KSVS:175 if (input->create_session != PASS) {176 /* out of sync with psp state */177 adjust->hdcp1.disable = 1;178 fail_and_restart_in_ms(0, &status, output);179 break;180 } else if (input->an_write != PASS ||181 input->aksv_write != PASS ||182 input->bksv_read != PASS ||183 input->bksv_validation != PASS ||184 input->ainfo_write == FAIL) {185 /* 1A-05: consider invalid bksv a failure */186 fail_and_restart_in_ms(0, &status, output);187 break;188 }189 set_watchdog_in_ms(hdcp, 100, output);190 set_state_id(hdcp, output, D1_A23_WAIT_FOR_R0_PRIME);191 break;192 case D1_A23_WAIT_FOR_R0_PRIME:193 if (input->bstatus_read != PASS) {194 fail_and_restart_in_ms(0, &status, output);195 break;196 } else if (input->r0p_available_dp != PASS) {197 if (event_ctx->event == MOD_HDCP_EVENT_WATCHDOG_TIMEOUT)198 fail_and_restart_in_ms(0, &status, output);199 else200 increment_stay_counter(hdcp);201 break;202 }203 callback_in_ms(0, output);204 set_state_id(hdcp, output, D1_A2_COMPUTATIONS_A3_VALIDATE_RX_A5_TEST_FOR_REPEATER);205 break;206 case D1_A2_COMPUTATIONS_A3_VALIDATE_RX_A5_TEST_FOR_REPEATER:207 if (input->r0p_read != PASS) {208 fail_and_restart_in_ms(0, &status, output);209 break;210 } else if (input->rx_validation != PASS) {211 if (hdcp->state.stay_count < 2 &&212 !hdcp->connection.is_hdcp1_revoked) {213 /* allow 2 additional retries */214 callback_in_ms(0, output);215 increment_stay_counter(hdcp);216 } else {217 /*218 * 1A-06: consider invalid r0' a failure219 * after 3 attempts.220 * 1A-08: consider bksv listed in SRM a failure221 */222 /*223 * some slow RX will fail rx validation when it is224 * not ready. give it more time to react before retry.225 */226 fail_and_restart_in_ms(1000, &status, output);227 }228 break;229 } else if ((!conn->is_repeater && input->encryption != PASS) ||230 (!conn->is_repeater && is_dp_mst_hdcp(hdcp) && input->stream_encryption_dp != PASS)) {231 fail_and_restart_in_ms(0, &status, output);232 break;233 } else if (conn->hdcp1_retry_count < conn->link.adjust.hdcp1.min_auth_retries_wa) {234 fail_and_restart_in_ms(200, &status, output);235 break;236 }237 if (conn->is_repeater) {238 set_watchdog_in_ms(hdcp, 5000, output);239 set_state_id(hdcp, output, D1_A6_WAIT_FOR_READY);240 } else {241 set_state_id(hdcp, output, D1_A4_AUTHENTICATED);242 set_auth_complete(hdcp, output);243 }244 break;245 case D1_A4_AUTHENTICATED:246 if (input->link_integrity_check == FAIL ||247 input->reauth_request_check == FAIL) {248 /* 1A-07: restart hdcp on a link integrity failure */249 fail_and_restart_in_ms(0, &status, output);250 break;251 }252 break;253 case D1_A6_WAIT_FOR_READY:254 if (input->link_integrity_check == FAIL ||255 input->reauth_request_check == FAIL) {256 fail_and_restart_in_ms(0, &status, output);257 break;258 } else if (input->ready_check != PASS) {259 if (event_ctx->event ==260 MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) {261 /* 1B-04: fail hdcp on ksv list READY timeout */262 /* prevent black screen in next attempt */263 adjust->hdcp1.postpone_encryption = 1;264 fail_and_restart_in_ms(0, &status, output);265 } else {266 increment_stay_counter(hdcp);267 }268 break;269 }270 callback_in_ms(0, output);271 set_state_id(hdcp, output, D1_A7_READ_KSV_LIST);272 break;273 case D1_A7_READ_KSV_LIST:274 if (input->binfo_read_dp != PASS ||275 input->max_cascade_check != PASS ||276 input->max_devs_check != PASS) {277 /* 1B-06: consider MAX_DEVS_EXCEEDED a failure */278 /* 1B-07: consider MAX_CASCADE_EXCEEDED a failure */279 fail_and_restart_in_ms(0, &status, output);280 break;281 } else if (input->device_count_check != PASS) {282 /*283 * some slow dongle doesn't update284 * device count as soon as downstream is connected.285 * give it more time to react.286 */287 adjust->hdcp1.postpone_encryption = 1;288 fail_and_restart_in_ms(1000, &status, output);289 break;290 } else if (input->ksvlist_read != PASS ||291 input->vp_read != PASS) {292 fail_and_restart_in_ms(0, &status, output);293 break;294 } else if (input->ksvlist_vp_validation != PASS) {295 if (hdcp->state.stay_count < 2 &&296 !hdcp->connection.is_hdcp1_revoked) {297 /* allow 2 additional retries */298 callback_in_ms(0, output);299 increment_stay_counter(hdcp);300 } else {301 /*302 * 1B-05: consider invalid v' a failure303 * after 3 attempts.304 */305 fail_and_restart_in_ms(0, &status, output);306 }307 break;308 } else if (input->encryption != PASS ||309 (is_dp_mst_hdcp(hdcp) && input->stream_encryption_dp != PASS)) {310 fail_and_restart_in_ms(0, &status, output);311 break;312 }313 set_state_id(hdcp, output, D1_A4_AUTHENTICATED);314 set_auth_complete(hdcp, output);315 break;316 default:317 fail_and_restart_in_ms(0, &status, output);318 break;319 }320 321 return status;322}323