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->add_topology != PASS || 50 input->create_session != PASS) { 51 /* out of sync with psp state */ 52 adjust->hdcp1.disable = 1; 53 fail_and_restart_in_ms(0, &status, output); 54 break; 55 } else if (input->an_write != PASS || 56 input->aksv_write != PASS || 57 input->bksv_read != PASS || 58 input->bksv_validation != PASS || 59 input->ainfo_write == FAIL) { 60 /* 1A-05: consider invalid bksv a failure */ 61 fail_and_restart_in_ms(0, &status, output); 62 break; 63 } 64 callback_in_ms(300, output); 65 set_state_id(hdcp, output, 66 H1_A2_COMPUTATIONS_A3_VALIDATE_RX_A6_TEST_FOR_REPEATER); 67 break; 68 case H1_A2_COMPUTATIONS_A3_VALIDATE_RX_A6_TEST_FOR_REPEATER: 69 if (input->bcaps_read != PASS || 70 input->r0p_read != PASS) { 71 fail_and_restart_in_ms(0, &status, output); 72 break; 73 } else if (input->rx_validation != PASS) { 74 /* 1A-06: consider invalid r0' a failure */ 75 /* 1A-08: consider bksv listed in SRM a failure */ 76 /* 77 * some slow RX will fail rx validation when it is 78 * not ready. give it more time to react before retry. 79 */ 80 fail_and_restart_in_ms(1000, &status, output); 81 break; 82 } else if (!conn->is_repeater && input->encryption != PASS) { 83 fail_and_restart_in_ms(0, &status, output); 84 break; 85 } 86 if (conn->is_repeater) { 87 callback_in_ms(0, output); 88 set_watchdog_in_ms(hdcp, 5000, output); 89 set_state_id(hdcp, output, H1_A8_WAIT_FOR_READY); 90 } else { 91 callback_in_ms(0, output); 92 set_state_id(hdcp, output, H1_A45_AUTHENTICATED); 93 HDCP_FULL_DDC_TRACE(hdcp); 94 } 95 break; 96 case H1_A45_AUTHENTICATED: 97 if (input->link_maintenance != PASS) { 98 /* 1A-07: consider invalid ri' a failure */ 99 /* 1A-07a: consider read ri' not returned a failure */ 100 fail_and_restart_in_ms(0, &status, output); 101 break; 102 } 103 callback_in_ms(500, output); 104 increment_stay_counter(hdcp); 105 break; 106 case H1_A8_WAIT_FOR_READY: 107 if (input->ready_check != PASS) { 108 if (event_ctx->event == 109 MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { 110 /* 1B-03: fail hdcp on ksv list READY timeout */ 111 /* prevent black screen in next attempt */ 112 adjust->hdcp1.postpone_encryption = 1; 113 fail_and_restart_in_ms(0, &status, output); 114 } else { 115 /* continue ksv list READY polling*/ 116 callback_in_ms(500, output); 117 increment_stay_counter(hdcp); 118 } 119 break; 120 } 121 callback_in_ms(0, output); 122 set_state_id(hdcp, output, H1_A9_READ_KSV_LIST); 123 break; 124 case H1_A9_READ_KSV_LIST: 125 if (input->bstatus_read != PASS || 126 input->max_cascade_check != PASS || 127 input->max_devs_check != PASS || 128 input->device_count_check != PASS || 129 input->ksvlist_read != PASS || 130 input->vp_read != PASS || 131 input->ksvlist_vp_validation != PASS || 132 input->encryption != PASS) { 133 /* 1B-06: consider MAX_CASCADE_EXCEEDED a failure */ 134 /* 1B-05: consider MAX_DEVS_EXCEEDED a failure */ 135 /* 1B-04: consider invalid v' a failure */ 136 fail_and_restart_in_ms(0, &status, output); 137 break; 138 } 139 callback_in_ms(0, output); 140 set_state_id(hdcp, output, H1_A45_AUTHENTICATED); 141 HDCP_FULL_DDC_TRACE(hdcp); 142 break; 143 default: 144 status = MOD_HDCP_STATUS_INVALID_STATE; 145 fail_and_restart_in_ms(0, &status, output); 146 break; 147 } 148 149 return status; 150 } 151 152 enum mod_hdcp_status mod_hdcp_hdcp1_dp_transition(struct mod_hdcp *hdcp, 153 struct mod_hdcp_event_context *event_ctx, 154 struct mod_hdcp_transition_input_hdcp1 *input, 155 struct mod_hdcp_output *output) 156 { 157 enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; 158 struct mod_hdcp_connection *conn = &hdcp->connection; 159 struct mod_hdcp_link_adjustment *adjust = &hdcp->connection.link.adjust; 160 161 switch (current_state(hdcp)) { 162 case D1_A0_DETERMINE_RX_HDCP_CAPABLE: 163 if (input->bcaps_read != PASS) { 164 /* 1A-04: no authentication on bcaps read failure */ 165 fail_and_restart_in_ms(0, &status, output); 166 break; 167 } else if (input->hdcp_capable_dp != PASS) { 168 adjust->hdcp1.disable = 1; 169 fail_and_restart_in_ms(0, &status, output); 170 break; 171 } 172 callback_in_ms(0, output); 173 set_state_id(hdcp, output, D1_A1_EXCHANGE_KSVS); 174 break; 175 case D1_A1_EXCHANGE_KSVS: 176 if (input->add_topology != PASS || 177 input->create_session != PASS) { 178 /* out of sync with psp state */ 179 adjust->hdcp1.disable = 1; 180 fail_and_restart_in_ms(0, &status, output); 181 break; 182 } else if (input->an_write != PASS || 183 input->aksv_write != PASS || 184 input->bksv_read != PASS || 185 input->bksv_validation != PASS || 186 input->ainfo_write == FAIL) { 187 /* 1A-05: consider invalid bksv a failure */ 188 fail_and_restart_in_ms(0, &status, output); 189 break; 190 } 191 set_watchdog_in_ms(hdcp, 100, output); 192 set_state_id(hdcp, output, D1_A23_WAIT_FOR_R0_PRIME); 193 break; 194 case D1_A23_WAIT_FOR_R0_PRIME: 195 if (input->bstatus_read != PASS) { 196 fail_and_restart_in_ms(0, &status, output); 197 break; 198 } else if (input->r0p_available_dp != PASS) { 199 if (event_ctx->event == MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) 200 fail_and_restart_in_ms(0, &status, output); 201 else 202 increment_stay_counter(hdcp); 203 break; 204 } 205 callback_in_ms(0, output); 206 set_state_id(hdcp, output, D1_A2_COMPUTATIONS_A3_VALIDATE_RX_A5_TEST_FOR_REPEATER); 207 break; 208 case D1_A2_COMPUTATIONS_A3_VALIDATE_RX_A5_TEST_FOR_REPEATER: 209 if (input->r0p_read != PASS) { 210 fail_and_restart_in_ms(0, &status, output); 211 break; 212 } else if (input->rx_validation != PASS) { 213 if (hdcp->state.stay_count < 2) { 214 /* allow 2 additional retries */ 215 callback_in_ms(0, output); 216 increment_stay_counter(hdcp); 217 } else { 218 /* 219 * 1A-06: consider invalid r0' a failure 220 * after 3 attempts. 221 * 1A-08: consider bksv listed in SRM a failure 222 */ 223 /* 224 * some slow RX will fail rx validation when it is 225 * not ready. give it more time to react before retry. 226 */ 227 fail_and_restart_in_ms(1000, &status, output); 228 } 229 break; 230 } else if ((!conn->is_repeater && input->encryption != PASS) || 231 (!conn->is_repeater && is_dp_mst_hdcp(hdcp) && input->stream_encryption_dp != PASS)) { 232 fail_and_restart_in_ms(0, &status, output); 233 break; 234 } 235 if (conn->is_repeater) { 236 set_watchdog_in_ms(hdcp, 5000, output); 237 set_state_id(hdcp, output, D1_A6_WAIT_FOR_READY); 238 } else { 239 set_state_id(hdcp, output, D1_A4_AUTHENTICATED); 240 HDCP_FULL_DDC_TRACE(hdcp); 241 } 242 break; 243 case D1_A4_AUTHENTICATED: 244 if (input->link_integrity_check != PASS || 245 input->reauth_request_check != PASS) { 246 /* 1A-07: restart hdcp on a link integrity failure */ 247 fail_and_restart_in_ms(0, &status, output); 248 break; 249 } 250 break; 251 case D1_A6_WAIT_FOR_READY: 252 if (input->link_integrity_check == FAIL || 253 input->reauth_request_check == FAIL) { 254 fail_and_restart_in_ms(0, &status, output); 255 break; 256 } else if (input->ready_check != PASS) { 257 if (event_ctx->event == 258 MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { 259 /* 1B-04: fail hdcp on ksv list READY timeout */ 260 /* prevent black screen in next attempt */ 261 adjust->hdcp1.postpone_encryption = 1; 262 fail_and_restart_in_ms(0, &status, output); 263 } else { 264 increment_stay_counter(hdcp); 265 } 266 break; 267 } 268 callback_in_ms(0, output); 269 set_state_id(hdcp, output, D1_A7_READ_KSV_LIST); 270 break; 271 case D1_A7_READ_KSV_LIST: 272 if (input->binfo_read_dp != PASS || 273 input->max_cascade_check != PASS || 274 input->max_devs_check != PASS) { 275 /* 1B-06: consider MAX_DEVS_EXCEEDED a failure */ 276 /* 1B-07: consider MAX_CASCADE_EXCEEDED a failure */ 277 fail_and_restart_in_ms(0, &status, output); 278 break; 279 } else if (input->device_count_check != PASS) { 280 /* 281 * some slow dongle doesn't update 282 * device count as soon as downstream is connected. 283 * give it more time to react. 284 */ 285 adjust->hdcp1.postpone_encryption = 1; 286 fail_and_restart_in_ms(1000, &status, output); 287 break; 288 } else if (input->ksvlist_read != PASS || 289 input->vp_read != PASS) { 290 fail_and_restart_in_ms(0, &status, output); 291 break; 292 } else if (input->ksvlist_vp_validation != PASS) { 293 if (hdcp->state.stay_count < 2) { 294 /* allow 2 additional retries */ 295 callback_in_ms(0, output); 296 increment_stay_counter(hdcp); 297 } else { 298 /* 299 * 1B-05: consider invalid v' a failure 300 * after 3 attempts. 301 */ 302 fail_and_restart_in_ms(0, &status, output); 303 } 304 break; 305 } else if (input->encryption != PASS || 306 (is_dp_mst_hdcp(hdcp) && input->stream_encryption_dp != PASS)) { 307 fail_and_restart_in_ms(0, &status, output); 308 break; 309 } 310 set_state_id(hdcp, output, D1_A4_AUTHENTICATED); 311 HDCP_FULL_DDC_TRACE(hdcp); 312 break; 313 default: 314 fail_and_restart_in_ms(0, &status, output); 315 break; 316 } 317 318 return status; 319 } 320