• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
mod_hdcp_hdcp1_transition(struct mod_hdcp * hdcp,struct mod_hdcp_event_context * event_ctx,struct mod_hdcp_transition_input_hdcp1 * input,struct mod_hdcp_output * output)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 
mod_hdcp_hdcp1_dp_transition(struct mod_hdcp * hdcp,struct mod_hdcp_event_context * event_ctx,struct mod_hdcp_transition_input_hdcp1 * input,struct mod_hdcp_output * output)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(0, &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