1c349dbc7Sjsg /*
2c349dbc7Sjsg * Copyright 2018 Advanced Micro Devices, Inc.
3c349dbc7Sjsg *
4c349dbc7Sjsg * Permission is hereby granted, free of charge, to any person obtaining a
5c349dbc7Sjsg * copy of this software and associated documentation files (the "Software"),
6c349dbc7Sjsg * to deal in the Software without restriction, including without limitation
7c349dbc7Sjsg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8c349dbc7Sjsg * and/or sell copies of the Software, and to permit persons to whom the
9c349dbc7Sjsg * Software is furnished to do so, subject to the following conditions:
10c349dbc7Sjsg *
11c349dbc7Sjsg * The above copyright notice and this permission notice shall be included in
12c349dbc7Sjsg * all copies or substantial portions of the Software.
13c349dbc7Sjsg *
14c349dbc7Sjsg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15c349dbc7Sjsg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16c349dbc7Sjsg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17c349dbc7Sjsg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18c349dbc7Sjsg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19c349dbc7Sjsg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20c349dbc7Sjsg * OTHER DEALINGS IN THE SOFTWARE.
21c349dbc7Sjsg *
22c349dbc7Sjsg * Authors: AMD
23c349dbc7Sjsg *
24c349dbc7Sjsg */
25c349dbc7Sjsg
26c349dbc7Sjsg #include "hdcp.h"
27c349dbc7Sjsg
mod_hdcp_hdcp2_transition(struct mod_hdcp * hdcp,struct mod_hdcp_event_context * event_ctx,struct mod_hdcp_transition_input_hdcp2 * input,struct mod_hdcp_output * output)28c349dbc7Sjsg enum mod_hdcp_status mod_hdcp_hdcp2_transition(struct mod_hdcp *hdcp,
29c349dbc7Sjsg struct mod_hdcp_event_context *event_ctx,
30c349dbc7Sjsg struct mod_hdcp_transition_input_hdcp2 *input,
31c349dbc7Sjsg struct mod_hdcp_output *output)
32c349dbc7Sjsg {
33c349dbc7Sjsg enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
34c349dbc7Sjsg struct mod_hdcp_connection *conn = &hdcp->connection;
35c349dbc7Sjsg struct mod_hdcp_link_adjustment *adjust = &hdcp->connection.link.adjust;
36c349dbc7Sjsg
37c349dbc7Sjsg switch (current_state(hdcp)) {
38c349dbc7Sjsg case H2_A0_KNOWN_HDCP2_CAPABLE_RX:
39c349dbc7Sjsg if (input->hdcp2version_read != PASS ||
40c349dbc7Sjsg input->hdcp2_capable_check != PASS) {
41c349dbc7Sjsg adjust->hdcp2.disable = 1;
42c349dbc7Sjsg callback_in_ms(0, output);
43c349dbc7Sjsg set_state_id(hdcp, output, HDCP_INITIALIZED);
44c349dbc7Sjsg } else {
45c349dbc7Sjsg callback_in_ms(0, output);
46c349dbc7Sjsg set_state_id(hdcp, output, H2_A1_SEND_AKE_INIT);
47c349dbc7Sjsg }
48c349dbc7Sjsg break;
49c349dbc7Sjsg case H2_A1_SEND_AKE_INIT:
50c349dbc7Sjsg if (input->create_session != PASS ||
51c349dbc7Sjsg input->ake_init_prepare != PASS) {
52c349dbc7Sjsg /* out of sync with psp state */
53c349dbc7Sjsg adjust->hdcp2.disable = 1;
54c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
55c349dbc7Sjsg break;
56c349dbc7Sjsg } else if (input->ake_init_write != PASS) {
57c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
58c349dbc7Sjsg break;
59c349dbc7Sjsg }
60c349dbc7Sjsg set_watchdog_in_ms(hdcp, 100, output);
61c349dbc7Sjsg callback_in_ms(0, output);
62c349dbc7Sjsg set_state_id(hdcp, output, H2_A1_VALIDATE_AKE_CERT);
63c349dbc7Sjsg break;
64c349dbc7Sjsg case H2_A1_VALIDATE_AKE_CERT:
65c349dbc7Sjsg if (input->ake_cert_available != PASS) {
66c349dbc7Sjsg if (event_ctx->event ==
67c349dbc7Sjsg MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) {
68c349dbc7Sjsg /* 1A-08: consider ake timeout a failure */
69c349dbc7Sjsg /* some hdmi receivers are not ready for HDCP
70c349dbc7Sjsg * immediately after video becomes active,
71c349dbc7Sjsg * delay 1s before retry on first HDCP message
72c349dbc7Sjsg * timeout.
73c349dbc7Sjsg */
74c349dbc7Sjsg fail_and_restart_in_ms(1000, &status, output);
75c349dbc7Sjsg } else {
76c349dbc7Sjsg /* continue ake cert polling*/
77c349dbc7Sjsg callback_in_ms(10, output);
78c349dbc7Sjsg increment_stay_counter(hdcp);
79c349dbc7Sjsg }
80c349dbc7Sjsg break;
81c349dbc7Sjsg } else if (input->ake_cert_read != PASS ||
82c349dbc7Sjsg input->ake_cert_validation != PASS) {
83c349dbc7Sjsg /*
84c349dbc7Sjsg * 1A-09: consider invalid ake cert a failure
85c349dbc7Sjsg * 1A-10: consider receiver id listed in SRM a failure
86c349dbc7Sjsg */
87c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
88c349dbc7Sjsg break;
89c349dbc7Sjsg }
90c349dbc7Sjsg if (conn->is_km_stored &&
91c349dbc7Sjsg !adjust->hdcp2.force_no_stored_km) {
92c349dbc7Sjsg callback_in_ms(0, output);
93c349dbc7Sjsg set_state_id(hdcp, output, H2_A1_SEND_STORED_KM);
94c349dbc7Sjsg } else {
95c349dbc7Sjsg callback_in_ms(0, output);
96c349dbc7Sjsg set_state_id(hdcp, output, H2_A1_SEND_NO_STORED_KM);
97c349dbc7Sjsg }
98c349dbc7Sjsg break;
99c349dbc7Sjsg case H2_A1_SEND_NO_STORED_KM:
100c349dbc7Sjsg if (input->no_stored_km_write != PASS) {
101c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
102c349dbc7Sjsg break;
103c349dbc7Sjsg }
104c349dbc7Sjsg if (adjust->hdcp2.increase_h_prime_timeout)
105c349dbc7Sjsg set_watchdog_in_ms(hdcp, 2000, output);
106c349dbc7Sjsg else
107c349dbc7Sjsg set_watchdog_in_ms(hdcp, 1000, output);
108c349dbc7Sjsg callback_in_ms(0, output);
109c349dbc7Sjsg set_state_id(hdcp, output, H2_A1_READ_H_PRIME);
110c349dbc7Sjsg break;
111c349dbc7Sjsg case H2_A1_READ_H_PRIME:
112c349dbc7Sjsg if (input->h_prime_available != PASS) {
113c349dbc7Sjsg if (event_ctx->event ==
114c349dbc7Sjsg MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) {
115c349dbc7Sjsg /* 1A-11-3: consider h' timeout a failure */
116c349dbc7Sjsg fail_and_restart_in_ms(1000, &status, output);
117c349dbc7Sjsg } else {
118c349dbc7Sjsg /* continue h' polling */
119c349dbc7Sjsg callback_in_ms(100, output);
120c349dbc7Sjsg increment_stay_counter(hdcp);
121c349dbc7Sjsg }
122c349dbc7Sjsg break;
123c349dbc7Sjsg } else if (input->h_prime_read != PASS) {
124c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
125c349dbc7Sjsg break;
126c349dbc7Sjsg }
127c349dbc7Sjsg set_watchdog_in_ms(hdcp, 200, output);
128c349dbc7Sjsg callback_in_ms(0, output);
129c349dbc7Sjsg set_state_id(hdcp, output, H2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME);
130c349dbc7Sjsg break;
131c349dbc7Sjsg case H2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME:
132c349dbc7Sjsg if (input->pairing_available != PASS) {
133c349dbc7Sjsg if (event_ctx->event ==
134c349dbc7Sjsg MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) {
135c349dbc7Sjsg /* 1A-12: consider pairing info timeout
136c349dbc7Sjsg * a failure
137c349dbc7Sjsg */
138c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
139c349dbc7Sjsg } else {
140c349dbc7Sjsg /* continue pairing info polling */
141c349dbc7Sjsg callback_in_ms(20, output);
142c349dbc7Sjsg increment_stay_counter(hdcp);
143c349dbc7Sjsg }
144c349dbc7Sjsg break;
145c349dbc7Sjsg } else if (input->pairing_info_read != PASS ||
146c349dbc7Sjsg input->h_prime_validation != PASS) {
147c349dbc7Sjsg /* 1A-11-1: consider invalid h' a failure */
148c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
149c349dbc7Sjsg break;
150c349dbc7Sjsg }
151c349dbc7Sjsg callback_in_ms(0, output);
152c349dbc7Sjsg set_state_id(hdcp, output, H2_A2_LOCALITY_CHECK);
153c349dbc7Sjsg break;
154c349dbc7Sjsg case H2_A1_SEND_STORED_KM:
155c349dbc7Sjsg if (input->stored_km_write != PASS) {
156c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
157c349dbc7Sjsg break;
158c349dbc7Sjsg }
159c349dbc7Sjsg set_watchdog_in_ms(hdcp, 200, output);
160c349dbc7Sjsg callback_in_ms(0, output);
161c349dbc7Sjsg set_state_id(hdcp, output, H2_A1_VALIDATE_H_PRIME);
162c349dbc7Sjsg break;
163c349dbc7Sjsg case H2_A1_VALIDATE_H_PRIME:
164c349dbc7Sjsg if (input->h_prime_available != PASS) {
165c349dbc7Sjsg if (event_ctx->event ==
166c349dbc7Sjsg MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) {
167c349dbc7Sjsg /* 1A-11-2: consider h' timeout a failure */
168c349dbc7Sjsg fail_and_restart_in_ms(1000, &status, output);
169c349dbc7Sjsg } else {
170c349dbc7Sjsg /* continue h' polling */
171c349dbc7Sjsg callback_in_ms(20, output);
172c349dbc7Sjsg increment_stay_counter(hdcp);
173c349dbc7Sjsg }
174c349dbc7Sjsg break;
175c349dbc7Sjsg } else if (input->h_prime_read != PASS) {
176c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
177c349dbc7Sjsg break;
178c349dbc7Sjsg } else if (input->h_prime_validation != PASS) {
179c349dbc7Sjsg /* 1A-11-1: consider invalid h' a failure */
180c349dbc7Sjsg adjust->hdcp2.force_no_stored_km = 1;
181c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
182c349dbc7Sjsg break;
183c349dbc7Sjsg }
184c349dbc7Sjsg callback_in_ms(0, output);
185c349dbc7Sjsg set_state_id(hdcp, output, H2_A2_LOCALITY_CHECK);
186c349dbc7Sjsg break;
187c349dbc7Sjsg case H2_A2_LOCALITY_CHECK:
188c349dbc7Sjsg if (hdcp->state.stay_count > 10 ||
189c349dbc7Sjsg input->lc_init_prepare != PASS ||
190c349dbc7Sjsg input->lc_init_write != PASS ||
191c349dbc7Sjsg input->l_prime_available_poll != PASS ||
192c349dbc7Sjsg input->l_prime_read != PASS) {
193c349dbc7Sjsg /*
194c349dbc7Sjsg * 1A-05: consider disconnection after LC init a failure
195c349dbc7Sjsg * 1A-13-1: consider invalid l' a failure
196c349dbc7Sjsg * 1A-13-2: consider l' timeout a failure
197c349dbc7Sjsg */
198c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
199c349dbc7Sjsg break;
200c349dbc7Sjsg } else if (input->l_prime_validation != PASS) {
201c349dbc7Sjsg callback_in_ms(0, output);
202c349dbc7Sjsg increment_stay_counter(hdcp);
203c349dbc7Sjsg break;
204c349dbc7Sjsg }
205c349dbc7Sjsg callback_in_ms(0, output);
206c349dbc7Sjsg set_state_id(hdcp, output, H2_A3_EXCHANGE_KS_AND_TEST_FOR_REPEATER);
207c349dbc7Sjsg break;
208c349dbc7Sjsg case H2_A3_EXCHANGE_KS_AND_TEST_FOR_REPEATER:
209c349dbc7Sjsg if (input->eks_prepare != PASS ||
210c349dbc7Sjsg input->eks_write != PASS) {
211c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
212c349dbc7Sjsg break;
213c349dbc7Sjsg }
214c349dbc7Sjsg if (conn->is_repeater) {
215c349dbc7Sjsg set_watchdog_in_ms(hdcp, 3000, output);
216c349dbc7Sjsg callback_in_ms(0, output);
217c349dbc7Sjsg set_state_id(hdcp, output, H2_A6_WAIT_FOR_RX_ID_LIST);
218c349dbc7Sjsg } else {
219c349dbc7Sjsg /* some CTS equipment requires a delay GREATER than
220c349dbc7Sjsg * 200 ms, so delay 210 ms instead of 200 ms
221c349dbc7Sjsg */
222c349dbc7Sjsg callback_in_ms(210, output);
223c349dbc7Sjsg set_state_id(hdcp, output, H2_ENABLE_ENCRYPTION);
224c349dbc7Sjsg }
225c349dbc7Sjsg break;
226c349dbc7Sjsg case H2_ENABLE_ENCRYPTION:
227c349dbc7Sjsg if (input->rxstatus_read != PASS ||
228c349dbc7Sjsg input->reauth_request_check != PASS) {
229c349dbc7Sjsg /*
230c349dbc7Sjsg * 1A-07: restart hdcp on REAUTH_REQ
231c349dbc7Sjsg * 1B-08: restart hdcp on REAUTH_REQ
232c349dbc7Sjsg */
233c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
234c349dbc7Sjsg break;
235c349dbc7Sjsg } else if (event_ctx->rx_id_list_ready && conn->is_repeater) {
236c349dbc7Sjsg callback_in_ms(0, output);
237c349dbc7Sjsg set_state_id(hdcp, output, H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK);
238c349dbc7Sjsg break;
239c349dbc7Sjsg } else if (input->enable_encryption != PASS) {
240c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
241c349dbc7Sjsg break;
242c349dbc7Sjsg }
243c349dbc7Sjsg callback_in_ms(0, output);
244c349dbc7Sjsg set_state_id(hdcp, output, H2_A5_AUTHENTICATED);
2455ca02815Sjsg set_auth_complete(hdcp, output);
246c349dbc7Sjsg break;
247c349dbc7Sjsg case H2_A5_AUTHENTICATED:
2485ca02815Sjsg if (input->rxstatus_read == FAIL ||
2495ca02815Sjsg input->reauth_request_check == FAIL) {
250c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
251c349dbc7Sjsg break;
252c349dbc7Sjsg } else if (event_ctx->rx_id_list_ready && conn->is_repeater) {
253c349dbc7Sjsg callback_in_ms(0, output);
254c349dbc7Sjsg set_state_id(hdcp, output, H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK);
255c349dbc7Sjsg break;
256c349dbc7Sjsg }
257c349dbc7Sjsg callback_in_ms(500, output);
258c349dbc7Sjsg increment_stay_counter(hdcp);
259c349dbc7Sjsg break;
260c349dbc7Sjsg case H2_A6_WAIT_FOR_RX_ID_LIST:
261c349dbc7Sjsg if (input->rxstatus_read != PASS ||
262c349dbc7Sjsg input->reauth_request_check != PASS) {
263c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
264c349dbc7Sjsg break;
265c349dbc7Sjsg } else if (!event_ctx->rx_id_list_ready) {
266c349dbc7Sjsg if (event_ctx->event == MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) {
267c349dbc7Sjsg /* 1B-02: consider rx id list timeout a failure */
268c349dbc7Sjsg /* some CTS equipment's actual timeout
269c349dbc7Sjsg * measurement is slightly greater than 3000 ms.
270c349dbc7Sjsg * Delay 100 ms to ensure it is fully timeout
271c349dbc7Sjsg * before re-authentication.
272c349dbc7Sjsg */
273c349dbc7Sjsg fail_and_restart_in_ms(100, &status, output);
274c349dbc7Sjsg } else {
275c349dbc7Sjsg callback_in_ms(300, output);
276c349dbc7Sjsg increment_stay_counter(hdcp);
277c349dbc7Sjsg }
278c349dbc7Sjsg break;
279c349dbc7Sjsg }
280c349dbc7Sjsg callback_in_ms(0, output);
281c349dbc7Sjsg set_state_id(hdcp, output, H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK);
282c349dbc7Sjsg break;
283c349dbc7Sjsg case H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK:
284c349dbc7Sjsg if (input->rxstatus_read != PASS ||
285c349dbc7Sjsg input->reauth_request_check != PASS ||
286c349dbc7Sjsg input->rx_id_list_read != PASS ||
287c349dbc7Sjsg input->device_count_check != PASS ||
288c349dbc7Sjsg input->rx_id_list_validation != PASS ||
289c349dbc7Sjsg input->repeater_auth_ack_write != PASS) {
290c349dbc7Sjsg /* 1B-03: consider invalid v' a failure
291c349dbc7Sjsg * 1B-04: consider MAX_DEVS_EXCEEDED a failure
292c349dbc7Sjsg * 1B-05: consider MAX_CASCADE_EXCEEDED a failure
293c349dbc7Sjsg * 1B-06: consider invalid seq_num_V a failure
294c349dbc7Sjsg * 1B-09: consider seq_num_V rollover a failure
295c349dbc7Sjsg */
296c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
297c349dbc7Sjsg break;
298c349dbc7Sjsg }
299c349dbc7Sjsg callback_in_ms(0, output);
300c349dbc7Sjsg set_state_id(hdcp, output, H2_A9_SEND_STREAM_MANAGEMENT);
301c349dbc7Sjsg break;
302c349dbc7Sjsg case H2_A9_SEND_STREAM_MANAGEMENT:
303c349dbc7Sjsg if (input->rxstatus_read != PASS ||
304c349dbc7Sjsg input->reauth_request_check != PASS) {
305c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
306c349dbc7Sjsg break;
307c349dbc7Sjsg } else if (event_ctx->rx_id_list_ready && conn->is_repeater) {
308c349dbc7Sjsg callback_in_ms(0, output);
309c349dbc7Sjsg set_state_id(hdcp, output, H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK);
310c349dbc7Sjsg break;
311c349dbc7Sjsg } else if (input->prepare_stream_manage != PASS ||
312c349dbc7Sjsg input->stream_manage_write != PASS) {
313c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
314c349dbc7Sjsg break;
315c349dbc7Sjsg }
316c349dbc7Sjsg set_watchdog_in_ms(hdcp, 100, output);
317c349dbc7Sjsg callback_in_ms(0, output);
318c349dbc7Sjsg set_state_id(hdcp, output, H2_A9_VALIDATE_STREAM_READY);
319c349dbc7Sjsg break;
320c349dbc7Sjsg case H2_A9_VALIDATE_STREAM_READY:
321c349dbc7Sjsg if (input->rxstatus_read != PASS ||
322c349dbc7Sjsg input->reauth_request_check != PASS) {
323c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
324c349dbc7Sjsg break;
325c349dbc7Sjsg } else if (event_ctx->rx_id_list_ready && conn->is_repeater) {
326c349dbc7Sjsg callback_in_ms(0, output);
327c349dbc7Sjsg set_state_id(hdcp, output, H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK);
328c349dbc7Sjsg break;
329c349dbc7Sjsg } else if (input->stream_ready_available != PASS) {
330c349dbc7Sjsg if (event_ctx->event == MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) {
331c349dbc7Sjsg /* 1B-10-2: restart content stream management on
332c349dbc7Sjsg * stream ready timeout
333c349dbc7Sjsg */
334c349dbc7Sjsg hdcp->auth.count.stream_management_retry_count++;
335c349dbc7Sjsg callback_in_ms(0, output);
336c349dbc7Sjsg set_state_id(hdcp, output, H2_A9_SEND_STREAM_MANAGEMENT);
337c349dbc7Sjsg } else {
338c349dbc7Sjsg callback_in_ms(10, output);
339c349dbc7Sjsg increment_stay_counter(hdcp);
340c349dbc7Sjsg }
341c349dbc7Sjsg break;
342c349dbc7Sjsg } else if (input->stream_ready_read != PASS ||
343c349dbc7Sjsg input->stream_ready_validation != PASS) {
344c349dbc7Sjsg /*
345c349dbc7Sjsg * 1B-10-1: restart content stream management
346c349dbc7Sjsg * on invalid M'
347c349dbc7Sjsg */
348c349dbc7Sjsg if (hdcp->auth.count.stream_management_retry_count > 10) {
349c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
350c349dbc7Sjsg } else {
351c349dbc7Sjsg hdcp->auth.count.stream_management_retry_count++;
352c349dbc7Sjsg callback_in_ms(0, output);
353c349dbc7Sjsg set_state_id(hdcp, output, H2_A9_SEND_STREAM_MANAGEMENT);
354c349dbc7Sjsg }
355c349dbc7Sjsg break;
356c349dbc7Sjsg }
357c349dbc7Sjsg callback_in_ms(200, output);
358c349dbc7Sjsg set_state_id(hdcp, output, H2_ENABLE_ENCRYPTION);
359c349dbc7Sjsg break;
360c349dbc7Sjsg default:
361c349dbc7Sjsg status = MOD_HDCP_STATUS_INVALID_STATE;
362c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
363c349dbc7Sjsg break;
364c349dbc7Sjsg }
365c349dbc7Sjsg
366c349dbc7Sjsg return status;
367c349dbc7Sjsg }
368c349dbc7Sjsg
mod_hdcp_hdcp2_dp_transition(struct mod_hdcp * hdcp,struct mod_hdcp_event_context * event_ctx,struct mod_hdcp_transition_input_hdcp2 * input,struct mod_hdcp_output * output)369c349dbc7Sjsg enum mod_hdcp_status mod_hdcp_hdcp2_dp_transition(struct mod_hdcp *hdcp,
370c349dbc7Sjsg struct mod_hdcp_event_context *event_ctx,
371c349dbc7Sjsg struct mod_hdcp_transition_input_hdcp2 *input,
372c349dbc7Sjsg struct mod_hdcp_output *output)
373c349dbc7Sjsg {
374c349dbc7Sjsg enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
375c349dbc7Sjsg struct mod_hdcp_connection *conn = &hdcp->connection;
376c349dbc7Sjsg struct mod_hdcp_link_adjustment *adjust = &hdcp->connection.link.adjust;
377c349dbc7Sjsg
378c349dbc7Sjsg switch (current_state(hdcp)) {
379c349dbc7Sjsg case D2_A0_DETERMINE_RX_HDCP_CAPABLE:
380c349dbc7Sjsg if (input->rx_caps_read_dp != PASS ||
381c349dbc7Sjsg input->hdcp2_capable_check != PASS) {
382c349dbc7Sjsg adjust->hdcp2.disable = 1;
383c349dbc7Sjsg callback_in_ms(0, output);
384c349dbc7Sjsg set_state_id(hdcp, output, HDCP_INITIALIZED);
385c349dbc7Sjsg } else {
386c349dbc7Sjsg callback_in_ms(0, output);
387c349dbc7Sjsg set_state_id(hdcp, output, D2_A1_SEND_AKE_INIT);
388c349dbc7Sjsg }
389c349dbc7Sjsg break;
390c349dbc7Sjsg case D2_A1_SEND_AKE_INIT:
391c349dbc7Sjsg if (input->create_session != PASS ||
392c349dbc7Sjsg input->ake_init_prepare != PASS) {
393c349dbc7Sjsg /* out of sync with psp state */
394c349dbc7Sjsg adjust->hdcp2.disable = 1;
395c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
396c349dbc7Sjsg break;
397c349dbc7Sjsg } else if (input->ake_init_write != PASS) {
398c349dbc7Sjsg /* possibly display not ready */
399c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
400c349dbc7Sjsg break;
401c349dbc7Sjsg }
402c349dbc7Sjsg callback_in_ms(100, output);
403c349dbc7Sjsg set_state_id(hdcp, output, D2_A1_VALIDATE_AKE_CERT);
404c349dbc7Sjsg break;
405c349dbc7Sjsg case D2_A1_VALIDATE_AKE_CERT:
406c349dbc7Sjsg if (input->ake_cert_read != PASS ||
407c349dbc7Sjsg input->ake_cert_validation != PASS) {
408c349dbc7Sjsg /*
409c349dbc7Sjsg * 1A-08: consider invalid ake cert a failure
410c349dbc7Sjsg * 1A-09: consider receiver id listed in SRM a failure
411c349dbc7Sjsg */
412c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
413c349dbc7Sjsg break;
414c349dbc7Sjsg }
415c349dbc7Sjsg if (conn->is_km_stored &&
416c349dbc7Sjsg !adjust->hdcp2.force_no_stored_km) {
417c349dbc7Sjsg callback_in_ms(0, output);
418c349dbc7Sjsg set_state_id(hdcp, output, D2_A1_SEND_STORED_KM);
419c349dbc7Sjsg } else {
420c349dbc7Sjsg callback_in_ms(0, output);
421c349dbc7Sjsg set_state_id(hdcp, output, D2_A1_SEND_NO_STORED_KM);
422c349dbc7Sjsg }
423c349dbc7Sjsg break;
424c349dbc7Sjsg case D2_A1_SEND_NO_STORED_KM:
425c349dbc7Sjsg if (input->no_stored_km_write != PASS) {
426c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
427c349dbc7Sjsg break;
428c349dbc7Sjsg }
429c349dbc7Sjsg if (adjust->hdcp2.increase_h_prime_timeout)
430c349dbc7Sjsg set_watchdog_in_ms(hdcp, 2000, output);
431c349dbc7Sjsg else
432c349dbc7Sjsg set_watchdog_in_ms(hdcp, 1000, output);
433c349dbc7Sjsg set_state_id(hdcp, output, D2_A1_READ_H_PRIME);
434c349dbc7Sjsg break;
435c349dbc7Sjsg case D2_A1_READ_H_PRIME:
436c349dbc7Sjsg if (input->h_prime_available != PASS) {
437c349dbc7Sjsg if (event_ctx->event ==
438c349dbc7Sjsg MOD_HDCP_EVENT_WATCHDOG_TIMEOUT)
439c349dbc7Sjsg /* 1A-10-3: consider h' timeout a failure */
440c349dbc7Sjsg fail_and_restart_in_ms(1000, &status, output);
441c349dbc7Sjsg else
442c349dbc7Sjsg increment_stay_counter(hdcp);
443c349dbc7Sjsg break;
444c349dbc7Sjsg } else if (input->h_prime_read != PASS) {
445c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
446c349dbc7Sjsg break;
447c349dbc7Sjsg }
448c349dbc7Sjsg set_watchdog_in_ms(hdcp, 200, output);
449c349dbc7Sjsg set_state_id(hdcp, output, D2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME);
450c349dbc7Sjsg break;
451c349dbc7Sjsg case D2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME:
452c349dbc7Sjsg if (input->pairing_available != PASS) {
453c349dbc7Sjsg if (event_ctx->event ==
454c349dbc7Sjsg MOD_HDCP_EVENT_WATCHDOG_TIMEOUT)
455c349dbc7Sjsg /*
456c349dbc7Sjsg * 1A-11: consider pairing info timeout
457c349dbc7Sjsg * a failure
458c349dbc7Sjsg */
459c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
460c349dbc7Sjsg else
461c349dbc7Sjsg increment_stay_counter(hdcp);
462c349dbc7Sjsg break;
463c349dbc7Sjsg } else if (input->pairing_info_read != PASS ||
464c349dbc7Sjsg input->h_prime_validation != PASS) {
465c349dbc7Sjsg /* 1A-10-1: consider invalid h' a failure */
466c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
467c349dbc7Sjsg break;
468c349dbc7Sjsg }
469c349dbc7Sjsg callback_in_ms(0, output);
470c349dbc7Sjsg set_state_id(hdcp, output, D2_A2_LOCALITY_CHECK);
471c349dbc7Sjsg break;
472c349dbc7Sjsg case D2_A1_SEND_STORED_KM:
473c349dbc7Sjsg if (input->stored_km_write != PASS) {
474c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
475c349dbc7Sjsg break;
476c349dbc7Sjsg }
477c349dbc7Sjsg set_watchdog_in_ms(hdcp, 200, output);
478c349dbc7Sjsg set_state_id(hdcp, output, D2_A1_VALIDATE_H_PRIME);
479c349dbc7Sjsg break;
480c349dbc7Sjsg case D2_A1_VALIDATE_H_PRIME:
481c349dbc7Sjsg if (input->h_prime_available != PASS) {
482c349dbc7Sjsg if (event_ctx->event ==
483c349dbc7Sjsg MOD_HDCP_EVENT_WATCHDOG_TIMEOUT)
484c349dbc7Sjsg /* 1A-10-2: consider h' timeout a failure */
485c349dbc7Sjsg fail_and_restart_in_ms(1000, &status, output);
486c349dbc7Sjsg else
487c349dbc7Sjsg increment_stay_counter(hdcp);
488c349dbc7Sjsg break;
489c349dbc7Sjsg } else if (input->h_prime_read != PASS) {
490c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
491c349dbc7Sjsg break;
492c349dbc7Sjsg } else if (input->h_prime_validation != PASS) {
493c349dbc7Sjsg /* 1A-10-1: consider invalid h' a failure */
494c349dbc7Sjsg adjust->hdcp2.force_no_stored_km = 1;
495c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
496c349dbc7Sjsg break;
497c349dbc7Sjsg }
498c349dbc7Sjsg callback_in_ms(0, output);
499c349dbc7Sjsg set_state_id(hdcp, output, D2_A2_LOCALITY_CHECK);
500c349dbc7Sjsg break;
501c349dbc7Sjsg case D2_A2_LOCALITY_CHECK:
502c349dbc7Sjsg if (hdcp->state.stay_count > 10 ||
503c349dbc7Sjsg input->lc_init_prepare != PASS ||
504c349dbc7Sjsg input->lc_init_write != PASS ||
505c349dbc7Sjsg input->l_prime_read != PASS) {
506c349dbc7Sjsg /* 1A-12: consider invalid l' a failure */
507c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
508c349dbc7Sjsg break;
509c349dbc7Sjsg } else if (input->l_prime_validation != PASS) {
510c349dbc7Sjsg callback_in_ms(0, output);
511c349dbc7Sjsg increment_stay_counter(hdcp);
512c349dbc7Sjsg break;
513c349dbc7Sjsg }
514c349dbc7Sjsg callback_in_ms(0, output);
515c349dbc7Sjsg set_state_id(hdcp, output, D2_A34_EXCHANGE_KS_AND_TEST_FOR_REPEATER);
516c349dbc7Sjsg break;
517c349dbc7Sjsg case D2_A34_EXCHANGE_KS_AND_TEST_FOR_REPEATER:
518c349dbc7Sjsg if (input->eks_prepare != PASS ||
519c349dbc7Sjsg input->eks_write != PASS) {
520c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
521c349dbc7Sjsg break;
522c349dbc7Sjsg }
523c349dbc7Sjsg if (conn->is_repeater) {
524c349dbc7Sjsg set_watchdog_in_ms(hdcp, 3000, output);
525c349dbc7Sjsg set_state_id(hdcp, output, D2_A6_WAIT_FOR_RX_ID_LIST);
526c349dbc7Sjsg } else {
527*1bb76ff1Sjsg callback_in_ms(1, output);
528c349dbc7Sjsg set_state_id(hdcp, output, D2_SEND_CONTENT_STREAM_TYPE);
529c349dbc7Sjsg }
530c349dbc7Sjsg break;
531c349dbc7Sjsg case D2_SEND_CONTENT_STREAM_TYPE:
532c349dbc7Sjsg if (input->rxstatus_read != PASS ||
533c349dbc7Sjsg input->reauth_request_check != PASS ||
534c349dbc7Sjsg input->link_integrity_check_dp != PASS ||
535c349dbc7Sjsg input->content_stream_type_write != PASS) {
536c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
537c349dbc7Sjsg break;
538c349dbc7Sjsg }
539c349dbc7Sjsg callback_in_ms(210, output);
540c349dbc7Sjsg set_state_id(hdcp, output, D2_ENABLE_ENCRYPTION);
541c349dbc7Sjsg break;
542c349dbc7Sjsg case D2_ENABLE_ENCRYPTION:
543c349dbc7Sjsg if (input->rxstatus_read != PASS ||
544c349dbc7Sjsg input->reauth_request_check != PASS ||
545c349dbc7Sjsg input->link_integrity_check_dp != PASS) {
546c349dbc7Sjsg /*
547c349dbc7Sjsg * 1A-07: restart hdcp on REAUTH_REQ
548c349dbc7Sjsg * 1B-08: restart hdcp on REAUTH_REQ
549c349dbc7Sjsg */
550c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
551c349dbc7Sjsg break;
552c349dbc7Sjsg } else if (event_ctx->rx_id_list_ready && conn->is_repeater) {
553c349dbc7Sjsg callback_in_ms(0, output);
554c349dbc7Sjsg set_state_id(hdcp, output, D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK);
555c349dbc7Sjsg break;
556c349dbc7Sjsg } else if (input->enable_encryption != PASS ||
557c349dbc7Sjsg (is_dp_mst_hdcp(hdcp) && input->stream_encryption_dp != PASS)) {
558c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
559c349dbc7Sjsg break;
560c349dbc7Sjsg }
561c349dbc7Sjsg set_state_id(hdcp, output, D2_A5_AUTHENTICATED);
5625ca02815Sjsg set_auth_complete(hdcp, output);
563c349dbc7Sjsg break;
564c349dbc7Sjsg case D2_A5_AUTHENTICATED:
5655ca02815Sjsg if (input->rxstatus_read == FAIL ||
5665ca02815Sjsg input->reauth_request_check == FAIL) {
5675ca02815Sjsg fail_and_restart_in_ms(100, &status, output);
568c349dbc7Sjsg break;
5695ca02815Sjsg } else if (input->link_integrity_check_dp == FAIL) {
570c349dbc7Sjsg if (hdcp->connection.hdcp2_retry_count >= 1)
571c349dbc7Sjsg adjust->hdcp2.force_type = MOD_HDCP_FORCE_TYPE_0;
572c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
573c349dbc7Sjsg break;
574c349dbc7Sjsg } else if (event_ctx->rx_id_list_ready && conn->is_repeater) {
575c349dbc7Sjsg callback_in_ms(0, output);
576c349dbc7Sjsg set_state_id(hdcp, output, D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK);
577c349dbc7Sjsg break;
578c349dbc7Sjsg }
579c349dbc7Sjsg increment_stay_counter(hdcp);
580c349dbc7Sjsg break;
581c349dbc7Sjsg case D2_A6_WAIT_FOR_RX_ID_LIST:
582c349dbc7Sjsg if (input->rxstatus_read != PASS ||
583c349dbc7Sjsg input->reauth_request_check != PASS ||
584c349dbc7Sjsg input->link_integrity_check_dp != PASS) {
585c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
586c349dbc7Sjsg break;
587c349dbc7Sjsg } else if (!event_ctx->rx_id_list_ready) {
588c349dbc7Sjsg if (event_ctx->event == MOD_HDCP_EVENT_WATCHDOG_TIMEOUT)
589c349dbc7Sjsg /* 1B-02: consider rx id list timeout a failure */
590c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
591c349dbc7Sjsg else
592c349dbc7Sjsg increment_stay_counter(hdcp);
593c349dbc7Sjsg break;
594c349dbc7Sjsg }
595c349dbc7Sjsg callback_in_ms(0, output);
596c349dbc7Sjsg set_state_id(hdcp, output, D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK);
597c349dbc7Sjsg break;
598c349dbc7Sjsg case D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK:
599c349dbc7Sjsg if (input->rxstatus_read != PASS ||
600c349dbc7Sjsg input->reauth_request_check != PASS ||
601c349dbc7Sjsg input->link_integrity_check_dp != PASS ||
602c349dbc7Sjsg input->rx_id_list_read != PASS ||
603c349dbc7Sjsg input->device_count_check != PASS ||
604c349dbc7Sjsg input->rx_id_list_validation != PASS ||
605c349dbc7Sjsg input->repeater_auth_ack_write != PASS) {
606c349dbc7Sjsg /*
607c349dbc7Sjsg * 1B-03: consider invalid v' a failure
608c349dbc7Sjsg * 1B-04: consider MAX_DEVS_EXCEEDED a failure
609c349dbc7Sjsg * 1B-05: consider MAX_CASCADE_EXCEEDED a failure
610c349dbc7Sjsg * 1B-06: consider invalid seq_num_V a failure
611c349dbc7Sjsg * 1B-09: consider seq_num_V rollover a failure
612c349dbc7Sjsg */
613c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
614c349dbc7Sjsg break;
615c349dbc7Sjsg }
616c349dbc7Sjsg callback_in_ms(0, output);
617c349dbc7Sjsg set_state_id(hdcp, output, D2_A9_SEND_STREAM_MANAGEMENT);
618c349dbc7Sjsg break;
619c349dbc7Sjsg case D2_A9_SEND_STREAM_MANAGEMENT:
620c349dbc7Sjsg if (input->rxstatus_read != PASS ||
621c349dbc7Sjsg input->reauth_request_check != PASS ||
622c349dbc7Sjsg input->link_integrity_check_dp != PASS) {
623c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
624c349dbc7Sjsg break;
625c349dbc7Sjsg } else if (event_ctx->rx_id_list_ready) {
626c349dbc7Sjsg callback_in_ms(0, output);
627c349dbc7Sjsg set_state_id(hdcp, output, D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK);
628c349dbc7Sjsg break;
629c349dbc7Sjsg } else if (input->prepare_stream_manage != PASS ||
630c349dbc7Sjsg input->stream_manage_write != PASS) {
631c349dbc7Sjsg if (event_ctx->event == MOD_HDCP_EVENT_CALLBACK)
632c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
633c349dbc7Sjsg else
634c349dbc7Sjsg increment_stay_counter(hdcp);
635c349dbc7Sjsg break;
636c349dbc7Sjsg }
637c349dbc7Sjsg callback_in_ms(100, output);
638c349dbc7Sjsg set_state_id(hdcp, output, D2_A9_VALIDATE_STREAM_READY);
639c349dbc7Sjsg break;
640c349dbc7Sjsg case D2_A9_VALIDATE_STREAM_READY:
641c349dbc7Sjsg if (input->rxstatus_read != PASS ||
642c349dbc7Sjsg input->reauth_request_check != PASS ||
643c349dbc7Sjsg input->link_integrity_check_dp != PASS) {
644c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
645c349dbc7Sjsg break;
646c349dbc7Sjsg } else if (event_ctx->rx_id_list_ready) {
647c349dbc7Sjsg callback_in_ms(0, output);
648c349dbc7Sjsg set_state_id(hdcp, output, D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK);
649c349dbc7Sjsg break;
650c349dbc7Sjsg } else if (input->stream_ready_read != PASS ||
651c349dbc7Sjsg input->stream_ready_validation != PASS) {
652c349dbc7Sjsg /*
653c349dbc7Sjsg * 1B-10-1: restart content stream management
654c349dbc7Sjsg * on invalid M'
655c349dbc7Sjsg * 1B-10-2: consider stream ready timeout a failure
656c349dbc7Sjsg */
657c349dbc7Sjsg if (hdcp->auth.count.stream_management_retry_count > 10) {
658c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
659c349dbc7Sjsg } else if (event_ctx->event == MOD_HDCP_EVENT_CALLBACK) {
660c349dbc7Sjsg hdcp->auth.count.stream_management_retry_count++;
661c349dbc7Sjsg callback_in_ms(0, output);
662c349dbc7Sjsg set_state_id(hdcp, output, D2_A9_SEND_STREAM_MANAGEMENT);
663c349dbc7Sjsg } else {
664c349dbc7Sjsg increment_stay_counter(hdcp);
665c349dbc7Sjsg }
666c349dbc7Sjsg break;
667c349dbc7Sjsg }
668c349dbc7Sjsg callback_in_ms(200, output);
669c349dbc7Sjsg set_state_id(hdcp, output, D2_ENABLE_ENCRYPTION);
670c349dbc7Sjsg break;
671c349dbc7Sjsg default:
672c349dbc7Sjsg status = MOD_HDCP_STATUS_INVALID_STATE;
673c349dbc7Sjsg fail_and_restart_in_ms(0, &status, output);
674c349dbc7Sjsg break;
675c349dbc7Sjsg }
676c349dbc7Sjsg return status;
677c349dbc7Sjsg }
678