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
28enum 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			set_auth_complete(hdcp, output);
93		}
94		break;
95	case H1_A45_AUTHENTICATED:
96		if (input->link_maintenance == FAIL) {
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		set_auth_complete(hdcp, output);
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
151enum 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			set_auth_complete(hdcp, output);
243		}
244		break;
245	case D1_A4_AUTHENTICATED:
246		if (input->link_integrity_check == FAIL ||
247				input->reauth_request_check == FAIL) {
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		set_auth_complete(hdcp, output);
315		break;
316	default:
317		fail_and_restart_in_ms(0, &status, output);
318		break;
319	}
320
321	return status;
322}
323