Merge branch 'for-linus' into next
[linux-2.6-microblaze.git] / drivers / gpu / drm / amd / display / modules / hdcp / hdcp1_transition.c
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
28 enum 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                         HDCP_FULL_DDC_TRACE(hdcp);
93                 }
94                 break;
95         case H1_A45_AUTHENTICATED:
96                 if (input->link_maintenance != PASS) {
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                 HDCP_FULL_DDC_TRACE(hdcp);
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
151 enum 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(0, &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                         HDCP_FULL_DDC_TRACE(hdcp);
243                 }
244                 break;
245         case D1_A4_AUTHENTICATED:
246                 if (input->link_integrity_check != PASS ||
247                                 input->reauth_request_check != PASS) {
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                 HDCP_FULL_DDC_TRACE(hdcp);
315                 break;
316         default:
317                 fail_and_restart_in_ms(0, &status, output);
318                 break;
319         }
320
321         return status;
322 }