1/*	$NetBSD: amdgpu_hdcp1_transition.c,v 1.2 2021/12/18 23:45:07 riastradh Exp $	*/
2
3/*
4 * Copyright 2019 Advanced Micro Devices, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors: AMD
25 *
26 */
27
28#include <sys/cdefs.h>
29__KERNEL_RCSID(0, "$NetBSD: amdgpu_hdcp1_transition.c,v 1.2 2021/12/18 23:45:07 riastradh Exp $");
30
31#include "hdcp.h"
32
33enum mod_hdcp_status mod_hdcp_hdcp1_transition(struct mod_hdcp *hdcp,
34		struct mod_hdcp_event_context *event_ctx,
35		struct mod_hdcp_transition_input_hdcp1 *input,
36		struct mod_hdcp_output *output)
37{
38	enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
39	struct mod_hdcp_connection *conn = &hdcp->connection;
40	struct mod_hdcp_link_adjustment *adjust = &hdcp->connection.link.adjust;
41
42	switch (current_state(hdcp)) {
43	case H1_A0_WAIT_FOR_ACTIVE_RX:
44		if (input->bksv_read != PASS || input->bcaps_read != PASS) {
45			/* 1A-04: repeatedly attempts on port access failure */
46			callback_in_ms(500, output);
47			increment_stay_counter(hdcp);
48			break;
49		}
50		callback_in_ms(0, output);
51		set_state_id(hdcp, output, H1_A1_EXCHANGE_KSVS);
52		break;
53	case H1_A1_EXCHANGE_KSVS:
54		if (input->add_topology != PASS ||
55				input->create_session != PASS) {
56			/* out of sync with psp state */
57			adjust->hdcp1.disable = 1;
58			fail_and_restart_in_ms(0, &status, output);
59			break;
60		} else if (input->an_write != PASS ||
61				input->aksv_write != PASS ||
62				input->bksv_read != PASS ||
63				input->bksv_validation != PASS ||
64				input->ainfo_write == FAIL) {
65			/* 1A-05: consider invalid bksv a failure */
66			fail_and_restart_in_ms(0, &status, output);
67			break;
68		}
69		callback_in_ms(300, output);
70		set_state_id(hdcp, output,
71			H1_A2_COMPUTATIONS_A3_VALIDATE_RX_A6_TEST_FOR_REPEATER);
72		break;
73	case H1_A2_COMPUTATIONS_A3_VALIDATE_RX_A6_TEST_FOR_REPEATER:
74		if (input->bcaps_read != PASS ||
75				input->r0p_read != PASS) {
76			fail_and_restart_in_ms(0, &status, output);
77			break;
78		} else if (input->rx_validation != PASS) {
79			/* 1A-06: consider invalid r0' a failure */
80			/* 1A-08: consider bksv listed in SRM a failure */
81			/*
82			 * some slow RX will fail rx validation when it is
83			 * not ready. give it more time to react before retry.
84			 */
85			fail_and_restart_in_ms(1000, &status, output);
86			break;
87		} else if (!conn->is_repeater && input->encryption != PASS) {
88			fail_and_restart_in_ms(0, &status, output);
89			break;
90		}
91		if (conn->is_repeater) {
92			callback_in_ms(0, output);
93			set_watchdog_in_ms(hdcp, 5000, output);
94			set_state_id(hdcp, output, H1_A8_WAIT_FOR_READY);
95		} else {
96			callback_in_ms(0, output);
97			set_state_id(hdcp, output, H1_A45_AUTHENTICATED);
98			HDCP_FULL_DDC_TRACE(hdcp);
99		}
100		break;
101	case H1_A45_AUTHENTICATED:
102		if (input->link_maintenance != PASS) {
103			/* 1A-07: consider invalid ri' a failure */
104			/* 1A-07a: consider read ri' not returned a failure */
105			fail_and_restart_in_ms(0, &status, output);
106			break;
107		}
108		callback_in_ms(500, output);
109		increment_stay_counter(hdcp);
110		break;
111	case H1_A8_WAIT_FOR_READY:
112		if (input->ready_check != PASS) {
113			if (event_ctx->event ==
114					MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) {
115				/* 1B-03: fail hdcp on ksv list READY timeout */
116				/* prevent black screen in next attempt */
117				adjust->hdcp1.postpone_encryption = 1;
118				fail_and_restart_in_ms(0, &status, output);
119			} else {
120				/* continue ksv list READY polling*/
121				callback_in_ms(500, output);
122				increment_stay_counter(hdcp);
123			}
124			break;
125		}
126		callback_in_ms(0, output);
127		set_state_id(hdcp, output, H1_A9_READ_KSV_LIST);
128		break;
129	case H1_A9_READ_KSV_LIST:
130		if (input->bstatus_read != PASS ||
131				input->max_cascade_check != PASS ||
132				input->max_devs_check != PASS ||
133				input->device_count_check != PASS ||
134				input->ksvlist_read != PASS ||
135				input->vp_read != PASS ||
136				input->ksvlist_vp_validation != PASS ||
137				input->encryption != PASS) {
138			/* 1B-06: consider MAX_CASCADE_EXCEEDED a failure */
139			/* 1B-05: consider MAX_DEVS_EXCEEDED a failure */
140			/* 1B-04: consider invalid v' a failure */
141			fail_and_restart_in_ms(0, &status, output);
142			break;
143		}
144		callback_in_ms(0, output);
145		set_state_id(hdcp, output, H1_A45_AUTHENTICATED);
146		HDCP_FULL_DDC_TRACE(hdcp);
147		break;
148	default:
149		status = MOD_HDCP_STATUS_INVALID_STATE;
150		fail_and_restart_in_ms(0, &status, output);
151		break;
152	}
153
154	return status;
155}
156
157enum mod_hdcp_status mod_hdcp_hdcp1_dp_transition(struct mod_hdcp *hdcp,
158		struct mod_hdcp_event_context *event_ctx,
159		struct mod_hdcp_transition_input_hdcp1 *input,
160		struct mod_hdcp_output *output)
161{
162	enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
163	struct mod_hdcp_connection *conn = &hdcp->connection;
164	struct mod_hdcp_link_adjustment *adjust = &hdcp->connection.link.adjust;
165
166	switch (current_state(hdcp)) {
167	case D1_A0_DETERMINE_RX_HDCP_CAPABLE:
168		if (input->bcaps_read != PASS) {
169			/* 1A-04: no authentication on bcaps read failure */
170			fail_and_restart_in_ms(0, &status, output);
171			break;
172		} else if (input->hdcp_capable_dp != PASS) {
173			adjust->hdcp1.disable = 1;
174			fail_and_restart_in_ms(0, &status, output);
175			break;
176		}
177		callback_in_ms(0, output);
178		set_state_id(hdcp, output, D1_A1_EXCHANGE_KSVS);
179		break;
180	case D1_A1_EXCHANGE_KSVS:
181		if (input->add_topology != PASS ||
182				input->create_session != PASS) {
183			/* out of sync with psp state */
184			adjust->hdcp1.disable = 1;
185			fail_and_restart_in_ms(0, &status, output);
186			break;
187		} else if (input->an_write != PASS ||
188				input->aksv_write != PASS ||
189				input->bksv_read != PASS ||
190				input->bksv_validation != PASS ||
191				input->ainfo_write == FAIL) {
192			/* 1A-05: consider invalid bksv a failure */
193			fail_and_restart_in_ms(0, &status, output);
194			break;
195		}
196		set_watchdog_in_ms(hdcp, 100, output);
197		set_state_id(hdcp, output, D1_A23_WAIT_FOR_R0_PRIME);
198		break;
199	case D1_A23_WAIT_FOR_R0_PRIME:
200		if (input->bstatus_read != PASS) {
201			fail_and_restart_in_ms(0, &status, output);
202			break;
203		} else if (input->r0p_available_dp != PASS) {
204			if (event_ctx->event == MOD_HDCP_EVENT_WATCHDOG_TIMEOUT)
205				fail_and_restart_in_ms(0, &status, output);
206			else
207				increment_stay_counter(hdcp);
208			break;
209		}
210		callback_in_ms(0, output);
211		set_state_id(hdcp, output, D1_A2_COMPUTATIONS_A3_VALIDATE_RX_A5_TEST_FOR_REPEATER);
212		break;
213	case D1_A2_COMPUTATIONS_A3_VALIDATE_RX_A5_TEST_FOR_REPEATER:
214		if (input->r0p_read != PASS) {
215			fail_and_restart_in_ms(0, &status, output);
216			break;
217		} else if (input->rx_validation != PASS) {
218			if (hdcp->state.stay_count < 2) {
219				/* allow 2 additional retries */
220				callback_in_ms(0, output);
221				increment_stay_counter(hdcp);
222			} else {
223				/*
224				 * 1A-06: consider invalid r0' a failure
225				 * after 3 attempts.
226				 * 1A-08: consider bksv listed in SRM a failure
227				 */
228				/*
229				 * some slow RX will fail rx validation when it is
230				 * not ready. give it more time to react before retry.
231				 */
232				fail_and_restart_in_ms(1000, &status, output);
233			}
234			break;
235		} else if ((!conn->is_repeater && input->encryption != PASS) ||
236				(!conn->is_repeater && is_dp_mst_hdcp(hdcp) && input->stream_encryption_dp != PASS)) {
237			fail_and_restart_in_ms(0, &status, output);
238			break;
239		}
240		if (conn->is_repeater) {
241			set_watchdog_in_ms(hdcp, 5000, output);
242			set_state_id(hdcp, output, D1_A6_WAIT_FOR_READY);
243		} else {
244			set_state_id(hdcp, output, D1_A4_AUTHENTICATED);
245			HDCP_FULL_DDC_TRACE(hdcp);
246		}
247		break;
248	case D1_A4_AUTHENTICATED:
249		if (input->link_integrity_check != PASS ||
250				input->reauth_request_check != PASS) {
251			/* 1A-07: restart hdcp on a link integrity failure */
252			fail_and_restart_in_ms(0, &status, output);
253			break;
254		}
255		break;
256	case D1_A6_WAIT_FOR_READY:
257		if (input->link_integrity_check == FAIL ||
258				input->reauth_request_check == FAIL) {
259			fail_and_restart_in_ms(0, &status, output);
260			break;
261		} else if (input->ready_check != PASS) {
262			if (event_ctx->event ==
263					MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) {
264				/* 1B-04: fail hdcp on ksv list READY timeout */
265				/* prevent black screen in next attempt */
266				adjust->hdcp1.postpone_encryption = 1;
267				fail_and_restart_in_ms(0, &status, output);
268			} else {
269				increment_stay_counter(hdcp);
270			}
271			break;
272		}
273		callback_in_ms(0, output);
274		set_state_id(hdcp, output, D1_A7_READ_KSV_LIST);
275		break;
276	case D1_A7_READ_KSV_LIST:
277		if (input->binfo_read_dp != PASS ||
278				input->max_cascade_check != PASS ||
279				input->max_devs_check != PASS) {
280			/* 1B-06: consider MAX_DEVS_EXCEEDED a failure */
281			/* 1B-07: consider MAX_CASCADE_EXCEEDED a failure */
282			fail_and_restart_in_ms(0, &status, output);
283			break;
284		} else if (input->device_count_check != PASS) {
285			/*
286			 * some slow dongle doesn't update
287			 * device count as soon as downstream is connected.
288			 * give it more time to react.
289			 */
290			adjust->hdcp1.postpone_encryption = 1;
291			fail_and_restart_in_ms(1000, &status, output);
292			break;
293		} else if (input->ksvlist_read != PASS ||
294				input->vp_read != PASS) {
295			fail_and_restart_in_ms(0, &status, output);
296			break;
297		} else if (input->ksvlist_vp_validation != PASS) {
298			if (hdcp->state.stay_count < 2) {
299				/* allow 2 additional retries */
300				callback_in_ms(0, output);
301				increment_stay_counter(hdcp);
302			} else {
303				/*
304				 * 1B-05: consider invalid v' a failure
305				 * after 3 attempts.
306				 */
307				fail_and_restart_in_ms(0, &status, output);
308			}
309			break;
310		} else if (input->encryption != PASS ||
311				(is_dp_mst_hdcp(hdcp) && input->stream_encryption_dp != PASS)) {
312			fail_and_restart_in_ms(0, &status, output);
313			break;
314		}
315		set_state_id(hdcp, output, D1_A4_AUTHENTICATED);
316		HDCP_FULL_DDC_TRACE(hdcp);
317		break;
318	default:
319		fail_and_restart_in_ms(0, &status, output);
320		break;
321	}
322
323	return status;
324}
325