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 static void push_error_status(struct mod_hdcp *hdcp, 29 enum mod_hdcp_status status) 30 { 31 struct mod_hdcp_trace *trace = &hdcp->connection.trace; 32 33 if (trace->error_count < MAX_NUM_OF_ERROR_TRACE) { 34 trace->errors[trace->error_count].status = status; 35 trace->errors[trace->error_count].state_id = hdcp->state.id; 36 trace->error_count++; 37 HDCP_ERROR_TRACE(hdcp, status); 38 } 39 40 if (is_hdcp1(hdcp)) { 41 hdcp->connection.hdcp1_retry_count++; 42 } else if (is_hdcp2(hdcp)) { 43 hdcp->connection.hdcp2_retry_count++; 44 } 45 } 46 47 static uint8_t is_cp_desired_hdcp1(struct mod_hdcp *hdcp) 48 { 49 int i, is_auth_needed = 0; 50 51 /* if all displays on the link don't need authentication, 52 * hdcp is not desired 53 */ 54 for (i = 0; i < MAX_NUM_OF_DISPLAYS; i++) { 55 if (hdcp->connection.displays[i].state != MOD_HDCP_DISPLAY_INACTIVE && 56 !hdcp->connection.displays[i].adjust.disable) { 57 is_auth_needed = 1; 58 break; 59 } 60 } 61 62 return (hdcp->connection.hdcp1_retry_count < MAX_NUM_OF_ATTEMPTS) && 63 is_auth_needed && 64 !hdcp->connection.link.adjust.hdcp1.disable; 65 } 66 67 static uint8_t is_cp_desired_hdcp2(struct mod_hdcp *hdcp) 68 { 69 int i, is_auth_needed = 0; 70 71 /* if all displays on the link don't need authentication, 72 * hdcp is not desired 73 */ 74 for (i = 0; i < MAX_NUM_OF_DISPLAYS; i++) { 75 if (hdcp->connection.displays[i].state != MOD_HDCP_DISPLAY_INACTIVE && 76 !hdcp->connection.displays[i].adjust.disable) { 77 is_auth_needed = 1; 78 break; 79 } 80 } 81 82 return (hdcp->connection.hdcp2_retry_count < MAX_NUM_OF_ATTEMPTS) && 83 is_auth_needed && 84 !hdcp->connection.link.adjust.hdcp2.disable && 85 !hdcp->connection.is_hdcp2_revoked; 86 } 87 88 static enum mod_hdcp_status execution(struct mod_hdcp *hdcp, 89 struct mod_hdcp_event_context *event_ctx, 90 union mod_hdcp_transition_input *input) 91 { 92 enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; 93 94 if (is_in_initialized_state(hdcp)) { 95 if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) { 96 event_ctx->unexpected_event = 1; 97 goto out; 98 } 99 /* initialize transition input */ 100 memset(input, 0, sizeof(union mod_hdcp_transition_input)); 101 } else if (is_in_cp_not_desired_state(hdcp)) { 102 if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) { 103 event_ctx->unexpected_event = 1; 104 goto out; 105 } 106 /* update topology event if hdcp is not desired */ 107 status = mod_hdcp_add_display_topology(hdcp); 108 } else if (is_in_hdcp1_states(hdcp)) { 109 status = mod_hdcp_hdcp1_execution(hdcp, event_ctx, &input->hdcp1); 110 } else if (is_in_hdcp1_dp_states(hdcp)) { 111 status = mod_hdcp_hdcp1_dp_execution(hdcp, 112 event_ctx, &input->hdcp1); 113 } else if (is_in_hdcp2_states(hdcp)) { 114 status = mod_hdcp_hdcp2_execution(hdcp, event_ctx, &input->hdcp2); 115 } else if (is_in_hdcp2_dp_states(hdcp)) { 116 status = mod_hdcp_hdcp2_dp_execution(hdcp, 117 event_ctx, &input->hdcp2); 118 } 119 out: 120 return status; 121 } 122 123 static enum mod_hdcp_status transition(struct mod_hdcp *hdcp, 124 struct mod_hdcp_event_context *event_ctx, 125 union mod_hdcp_transition_input *input, 126 struct mod_hdcp_output *output) 127 { 128 enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; 129 130 if (event_ctx->unexpected_event) 131 goto out; 132 133 if (is_in_initialized_state(hdcp)) { 134 if (is_dp_hdcp(hdcp)) 135 if (is_cp_desired_hdcp2(hdcp)) { 136 callback_in_ms(0, output); 137 set_state_id(hdcp, output, D2_A0_DETERMINE_RX_HDCP_CAPABLE); 138 } else if (is_cp_desired_hdcp1(hdcp)) { 139 callback_in_ms(0, output); 140 set_state_id(hdcp, output, D1_A0_DETERMINE_RX_HDCP_CAPABLE); 141 } else { 142 callback_in_ms(0, output); 143 set_state_id(hdcp, output, HDCP_CP_NOT_DESIRED); 144 } 145 else if (is_hdmi_dvi_sl_hdcp(hdcp)) 146 if (is_cp_desired_hdcp2(hdcp)) { 147 callback_in_ms(0, output); 148 set_state_id(hdcp, output, H2_A0_KNOWN_HDCP2_CAPABLE_RX); 149 } else if (is_cp_desired_hdcp1(hdcp)) { 150 callback_in_ms(0, output); 151 set_state_id(hdcp, output, H1_A0_WAIT_FOR_ACTIVE_RX); 152 } else { 153 callback_in_ms(0, output); 154 set_state_id(hdcp, output, HDCP_CP_NOT_DESIRED); 155 } 156 else { 157 callback_in_ms(0, output); 158 set_state_id(hdcp, output, HDCP_CP_NOT_DESIRED); 159 } 160 } else if (is_in_cp_not_desired_state(hdcp)) { 161 increment_stay_counter(hdcp); 162 } else if (is_in_hdcp1_states(hdcp)) { 163 status = mod_hdcp_hdcp1_transition(hdcp, 164 event_ctx, &input->hdcp1, output); 165 } else if (is_in_hdcp1_dp_states(hdcp)) { 166 status = mod_hdcp_hdcp1_dp_transition(hdcp, 167 event_ctx, &input->hdcp1, output); 168 } else if (is_in_hdcp2_states(hdcp)) { 169 status = mod_hdcp_hdcp2_transition(hdcp, 170 event_ctx, &input->hdcp2, output); 171 } else if (is_in_hdcp2_dp_states(hdcp)) { 172 status = mod_hdcp_hdcp2_dp_transition(hdcp, 173 event_ctx, &input->hdcp2, output); 174 } else { 175 status = MOD_HDCP_STATUS_INVALID_STATE; 176 } 177 out: 178 return status; 179 } 180 181 static enum mod_hdcp_status reset_authentication(struct mod_hdcp *hdcp, 182 struct mod_hdcp_output *output) 183 { 184 enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; 185 186 if (is_hdcp1(hdcp)) { 187 if (hdcp->auth.trans_input.hdcp1.create_session != UNKNOWN) { 188 /* TODO - update psp to unify create session failure 189 * recovery between hdcp1 and 2. 190 */ 191 mod_hdcp_hdcp1_destroy_session(hdcp); 192 193 } 194 if (hdcp->auth.trans_input.hdcp1.add_topology == PASS) { 195 status = mod_hdcp_remove_display_topology(hdcp); 196 if (status != MOD_HDCP_STATUS_SUCCESS) { 197 output->callback_needed = 0; 198 output->watchdog_timer_needed = 0; 199 goto out; 200 } 201 } 202 HDCP_TOP_RESET_AUTH_TRACE(hdcp); 203 memset(&hdcp->auth, 0, sizeof(struct mod_hdcp_authentication)); 204 memset(&hdcp->state, 0, sizeof(struct mod_hdcp_state)); 205 set_state_id(hdcp, output, HDCP_INITIALIZED); 206 } else if (is_hdcp2(hdcp)) { 207 if (hdcp->auth.trans_input.hdcp2.create_session == PASS) { 208 status = mod_hdcp_hdcp2_destroy_session(hdcp); 209 if (status != MOD_HDCP_STATUS_SUCCESS) { 210 output->callback_needed = 0; 211 output->watchdog_timer_needed = 0; 212 goto out; 213 } 214 } 215 if (hdcp->auth.trans_input.hdcp2.add_topology == PASS) { 216 status = mod_hdcp_remove_display_topology(hdcp); 217 if (status != MOD_HDCP_STATUS_SUCCESS) { 218 output->callback_needed = 0; 219 output->watchdog_timer_needed = 0; 220 goto out; 221 } 222 } 223 HDCP_TOP_RESET_AUTH_TRACE(hdcp); 224 memset(&hdcp->auth, 0, sizeof(struct mod_hdcp_authentication)); 225 memset(&hdcp->state, 0, sizeof(struct mod_hdcp_state)); 226 set_state_id(hdcp, output, HDCP_INITIALIZED); 227 } else if (is_in_cp_not_desired_state(hdcp)) { 228 status = mod_hdcp_remove_display_topology(hdcp); 229 if (status != MOD_HDCP_STATUS_SUCCESS) { 230 output->callback_needed = 0; 231 output->watchdog_timer_needed = 0; 232 goto out; 233 } 234 HDCP_TOP_RESET_AUTH_TRACE(hdcp); 235 memset(&hdcp->auth, 0, sizeof(struct mod_hdcp_authentication)); 236 memset(&hdcp->state, 0, sizeof(struct mod_hdcp_state)); 237 set_state_id(hdcp, output, HDCP_INITIALIZED); 238 } 239 240 out: 241 /* stop callback and watchdog requests from previous authentication*/ 242 output->watchdog_timer_stop = 1; 243 output->callback_stop = 1; 244 return status; 245 } 246 247 static enum mod_hdcp_status reset_connection(struct mod_hdcp *hdcp, 248 struct mod_hdcp_output *output) 249 { 250 enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; 251 252 memset(output, 0, sizeof(struct mod_hdcp_output)); 253 254 status = reset_authentication(hdcp, output); 255 if (status != MOD_HDCP_STATUS_SUCCESS) 256 goto out; 257 258 if (current_state(hdcp) != HDCP_UNINITIALIZED) { 259 HDCP_TOP_RESET_CONN_TRACE(hdcp); 260 set_state_id(hdcp, output, HDCP_UNINITIALIZED); 261 } 262 memset(&hdcp->connection, 0, sizeof(hdcp->connection)); 263 out: 264 return status; 265 } 266 267 /* 268 * Implementation of functions in mod_hdcp.h 269 */ 270 size_t mod_hdcp_get_memory_size(void) 271 { 272 return sizeof(struct mod_hdcp); 273 } 274 275 enum mod_hdcp_status mod_hdcp_setup(struct mod_hdcp *hdcp, 276 struct mod_hdcp_config *config) 277 { 278 struct mod_hdcp_output output; 279 enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; 280 281 memset(hdcp, 0, sizeof(struct mod_hdcp)); 282 memset(&output, 0, sizeof(output)); 283 hdcp->config = *config; 284 HDCP_TOP_INTERFACE_TRACE(hdcp); 285 status = reset_connection(hdcp, &output); 286 if (status != MOD_HDCP_STATUS_SUCCESS) 287 push_error_status(hdcp, status); 288 return status; 289 } 290 291 enum mod_hdcp_status mod_hdcp_teardown(struct mod_hdcp *hdcp) 292 { 293 enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; 294 struct mod_hdcp_output output; 295 296 HDCP_TOP_INTERFACE_TRACE(hdcp); 297 memset(&output, 0, sizeof(output)); 298 status = reset_connection(hdcp, &output); 299 if (status == MOD_HDCP_STATUS_SUCCESS) 300 memset(hdcp, 0, sizeof(struct mod_hdcp)); 301 else 302 push_error_status(hdcp, status); 303 return status; 304 } 305 306 enum mod_hdcp_status mod_hdcp_add_display(struct mod_hdcp *hdcp, 307 struct mod_hdcp_link *link, struct mod_hdcp_display *display, 308 struct mod_hdcp_output *output) 309 { 310 enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; 311 struct mod_hdcp_display *display_container = NULL; 312 313 HDCP_TOP_INTERFACE_TRACE_WITH_INDEX(hdcp, display->index); 314 memset(output, 0, sizeof(struct mod_hdcp_output)); 315 316 /* skip inactive display */ 317 if (display->state != MOD_HDCP_DISPLAY_ACTIVE) { 318 status = MOD_HDCP_STATUS_SUCCESS; 319 goto out; 320 } 321 322 /* check existing display container */ 323 if (get_active_display_at_index(hdcp, display->index)) { 324 status = MOD_HDCP_STATUS_SUCCESS; 325 goto out; 326 } 327 328 /* find an empty display container */ 329 display_container = get_empty_display_container(hdcp); 330 if (!display_container) { 331 status = MOD_HDCP_STATUS_DISPLAY_OUT_OF_BOUND; 332 goto out; 333 } 334 335 /* reset existing authentication status */ 336 status = reset_authentication(hdcp, output); 337 if (status != MOD_HDCP_STATUS_SUCCESS) 338 goto out; 339 340 /* add display to connection */ 341 hdcp->connection.link = *link; 342 *display_container = *display; 343 344 /* reset retry counters */ 345 reset_retry_counts(hdcp); 346 347 /* reset error trace */ 348 memset(&hdcp->connection.trace, 0, sizeof(hdcp->connection.trace)); 349 350 /* request authentication */ 351 if (current_state(hdcp) != HDCP_INITIALIZED) 352 set_state_id(hdcp, output, HDCP_INITIALIZED); 353 callback_in_ms(hdcp->connection.link.adjust.auth_delay * 1000, output); 354 out: 355 if (status != MOD_HDCP_STATUS_SUCCESS) 356 push_error_status(hdcp, status); 357 358 return status; 359 } 360 361 enum mod_hdcp_status mod_hdcp_remove_display(struct mod_hdcp *hdcp, 362 uint8_t index, struct mod_hdcp_output *output) 363 { 364 enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; 365 struct mod_hdcp_display *display = NULL; 366 367 HDCP_TOP_INTERFACE_TRACE_WITH_INDEX(hdcp, index); 368 memset(output, 0, sizeof(struct mod_hdcp_output)); 369 370 /* find display in connection */ 371 display = get_active_display_at_index(hdcp, index); 372 if (!display) { 373 status = MOD_HDCP_STATUS_SUCCESS; 374 goto out; 375 } 376 377 /* stop current authentication */ 378 status = reset_authentication(hdcp, output); 379 if (status != MOD_HDCP_STATUS_SUCCESS) 380 goto out; 381 382 /* remove display */ 383 display->state = MOD_HDCP_DISPLAY_INACTIVE; 384 385 /* clear retry counters */ 386 reset_retry_counts(hdcp); 387 388 /* reset error trace */ 389 memset(&hdcp->connection.trace, 0, sizeof(hdcp->connection.trace)); 390 391 /* request authentication for remaining displays*/ 392 if (get_active_display_count(hdcp) > 0) 393 callback_in_ms(hdcp->connection.link.adjust.auth_delay * 1000, 394 output); 395 out: 396 if (status != MOD_HDCP_STATUS_SUCCESS) 397 push_error_status(hdcp, status); 398 return status; 399 } 400 401 enum mod_hdcp_status mod_hdcp_query_display(struct mod_hdcp *hdcp, 402 uint8_t index, struct mod_hdcp_display_query *query) 403 { 404 enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; 405 struct mod_hdcp_display *display = NULL; 406 407 /* find display in connection */ 408 display = get_active_display_at_index(hdcp, index); 409 if (!display) { 410 status = MOD_HDCP_STATUS_DISPLAY_NOT_FOUND; 411 goto out; 412 } 413 414 /* populate query */ 415 query->link = &hdcp->connection.link; 416 query->display = display; 417 query->trace = &hdcp->connection.trace; 418 query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; 419 420 if (is_display_encryption_enabled(display)) { 421 if (is_hdcp1(hdcp)) { 422 query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP1_ON; 423 } else if (is_hdcp2(hdcp)) { 424 if (query->link->adjust.hdcp2.force_type == MOD_HDCP_FORCE_TYPE_0) 425 query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON; 426 else if (query->link->adjust.hdcp2.force_type == MOD_HDCP_FORCE_TYPE_1) 427 query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON; 428 else 429 query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP2_ON; 430 } 431 } else { 432 query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; 433 } 434 435 out: 436 return status; 437 } 438 439 enum mod_hdcp_status mod_hdcp_reset_connection(struct mod_hdcp *hdcp, 440 struct mod_hdcp_output *output) 441 { 442 enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; 443 444 HDCP_TOP_INTERFACE_TRACE(hdcp); 445 status = reset_connection(hdcp, output); 446 if (status != MOD_HDCP_STATUS_SUCCESS) 447 push_error_status(hdcp, status); 448 449 return status; 450 } 451 452 enum mod_hdcp_status mod_hdcp_process_event(struct mod_hdcp *hdcp, 453 enum mod_hdcp_event event, struct mod_hdcp_output *output) 454 { 455 enum mod_hdcp_status exec_status, trans_status, reset_status, status; 456 struct mod_hdcp_event_context event_ctx; 457 458 HDCP_EVENT_TRACE(hdcp, event); 459 memset(output, 0, sizeof(struct mod_hdcp_output)); 460 memset(&event_ctx, 0, sizeof(struct mod_hdcp_event_context)); 461 event_ctx.event = event; 462 463 /* execute and transition */ 464 exec_status = execution(hdcp, &event_ctx, &hdcp->auth.trans_input); 465 trans_status = transition( 466 hdcp, &event_ctx, &hdcp->auth.trans_input, output); 467 if (trans_status == MOD_HDCP_STATUS_SUCCESS) { 468 status = MOD_HDCP_STATUS_SUCCESS; 469 } else if (exec_status == MOD_HDCP_STATUS_SUCCESS) { 470 status = MOD_HDCP_STATUS_INTERNAL_POLICY_FAILURE; 471 push_error_status(hdcp, status); 472 } else { 473 status = exec_status; 474 push_error_status(hdcp, status); 475 } 476 477 /* reset authentication if needed */ 478 if (trans_status == MOD_HDCP_STATUS_RESET_NEEDED) { 479 HDCP_FULL_DDC_TRACE(hdcp); 480 reset_status = reset_authentication(hdcp, output); 481 if (reset_status != MOD_HDCP_STATUS_SUCCESS) 482 push_error_status(hdcp, reset_status); 483 } 484 return status; 485 } 486 487 enum mod_hdcp_operation_mode mod_hdcp_signal_type_to_operation_mode( 488 enum signal_type signal) 489 { 490 enum mod_hdcp_operation_mode mode = MOD_HDCP_MODE_OFF; 491 492 switch (signal) { 493 case SIGNAL_TYPE_DVI_SINGLE_LINK: 494 case SIGNAL_TYPE_HDMI_TYPE_A: 495 mode = MOD_HDCP_MODE_DEFAULT; 496 break; 497 case SIGNAL_TYPE_EDP: 498 case SIGNAL_TYPE_DISPLAY_PORT: 499 mode = MOD_HDCP_MODE_DP; 500 break; 501 case SIGNAL_TYPE_DISPLAY_PORT_MST: 502 mode = MOD_HDCP_MODE_DP_MST; 503 break; 504 default: 505 break; 506 } 507 508 return mode; 509 } 510