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
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)33 enum 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
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)157 enum 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