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(time: 500, output);
42 increment_stay_counter(hdcp);
43 break;
44 }
45 callback_in_ms(time: 0, output);
46 set_state_id(hdcp, output, id: 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(time: 0, status: &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(time: 0, status: &status, output);
61 break;
62 }
63 callback_in_ms(time: 300, output);
64 set_state_id(hdcp, output,
65 id: 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(time: 0, status: &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(time: 1000, status: &status, output);
80 break;
81 } else if (!conn->is_repeater && input->encryption != PASS) {
82 fail_and_restart_in_ms(time: 0, status: &status, output);
83 break;
84 }
85 if (conn->is_repeater) {
86 callback_in_ms(time: 0, output);
87 set_watchdog_in_ms(hdcp, time: 5000, output);
88 set_state_id(hdcp, output, id: H1_A8_WAIT_FOR_READY);
89 } else {
90 callback_in_ms(time: 0, output);
91 set_state_id(hdcp, output, id: 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(time: 0, status: &status, output);
100 break;
101 }
102 callback_in_ms(time: 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(time: 0, status: &status, output);
113 } else {
114 /* continue ksv list READY polling*/
115 callback_in_ms(time: 500, output);
116 increment_stay_counter(hdcp);
117 }
118 break;
119 }
120 callback_in_ms(time: 0, output);
121 set_state_id(hdcp, output, id: 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(time: 0, status: &status, output);
136 break;
137 }
138 callback_in_ms(time: 0, output);
139 set_state_id(hdcp, output, id: 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(time: 0, status: &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(time: 0, status: &status, output);
165 break;
166 } else if (input->hdcp_capable_dp != PASS) {
167 adjust->hdcp1.disable = 1;
168 fail_and_restart_in_ms(time: 0, status: &status, output);
169 break;
170 }
171 callback_in_ms(time: 0, output);
172 set_state_id(hdcp, output, id: 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(time: 0, status: &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(time: 0, status: &status, output);
187 break;
188 }
189 set_watchdog_in_ms(hdcp, time: 100, output);
190 set_state_id(hdcp, output, id: 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(time: 0, status: &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(time: 0, status: &status, output);
199 else
200 increment_stay_counter(hdcp);
201 break;
202 }
203 callback_in_ms(time: 0, output);
204 set_state_id(hdcp, output, id: 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(time: 0, status: &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(time: 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(time: 1000, status: &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(time: 0, status: &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(time: 200, status: &status, output);
235 break;
236 }
237 if (conn->is_repeater) {
238 set_watchdog_in_ms(hdcp, time: 5000, output);
239 set_state_id(hdcp, output, id: D1_A6_WAIT_FOR_READY);
240 } else {
241 set_state_id(hdcp, output, id: 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(time: 0, status: &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(time: 0, status: &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(time: 0, status: &status, output);
265 } else {
266 increment_stay_counter(hdcp);
267 }
268 break;
269 }
270 callback_in_ms(time: 0, output);
271 set_state_id(hdcp, output, id: 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(time: 0, status: &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(time: 1000, status: &status, output);
289 break;
290 } else if (input->ksvlist_read != PASS ||
291 input->vp_read != PASS) {
292 fail_and_restart_in_ms(time: 0, status: &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(time: 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(time: 0, status: &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(time: 0, status: &status, output);
311 break;
312 }
313 set_state_id(hdcp, output, id: D1_A4_AUTHENTICATED);
314 set_auth_complete(hdcp, output);
315 break;
316 default:
317 fail_and_restart_in_ms(time: 0, status: &status, output);
318 break;
319 }
320
321 return status;
322}
323

source code of linux/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_transition.c