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