1 /* 2 * Copyright 2019 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * 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 OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: AMD 23 * 24 */ 25 26 #include "hdcp.h" 27 28 enum 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 is 77 * 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 HDCP_FULL_DDC_TRACE(hdcp); 93 } 94 break; 95 case H1_A45_AUTHENTICATED: 96 if (input->link_maintenance != PASS) { 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 HDCP_FULL_DDC_TRACE(hdcp); 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 151 enum 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 else 200 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 failure 219 * after 3 attempts. 220 * 1A-08: consider bksv listed in SRM a failure 221 */ 222 /* 223 * some slow RX will fail rx validation when it is 224 * 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 HDCP_FULL_DDC_TRACE(hdcp); 243 } 244 break; 245 case D1_A4_AUTHENTICATED: 246 if (input->link_integrity_check != PASS || 247 input->reauth_request_check != PASS) { 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 update 284 * 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 failure 303 * 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 HDCP_FULL_DDC_TRACE(hdcp); 315 break; 316 default: 317 fail_and_restart_in_ms(0, &status, output); 318 break; 319 } 320 321 return status; 322 } 323