File Index
Files and directories
Sign in
FILE

hdcp1_execution.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c 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
 28static inline enum mod_hdcp_status validate_bksv(struct mod_hdcp *hdcp)
 29{
 30	uint64_t n = 0;
 31	uint8_t count = 0;
 32	enum mod_hdcp_status status;
 33	u8 bksv[sizeof(n)] = { };
 34
 35	memcpy(bksv, hdcp->auth.msg.hdcp1.bksv, sizeof(hdcp->auth.msg.hdcp1.bksv));
 36	n = *(uint64_t *)bksv;
 37
 38	while (n) {
 39		count++;
 40		n &= (n - 1);
 41	}
 42
 43	if (count == 20) {
 44		hdcp->connection.trace.hdcp1.attempt_count++;
 45		status = MOD_HDCP_STATUS_SUCCESS;
 46	} else {
 47		status = MOD_HDCP_STATUS_HDCP1_INVALID_BKSV;
 48	}
 49	return status;
 50}
 51
 52static inline enum mod_hdcp_status check_ksv_ready(struct mod_hdcp *hdcp)
 53{
 54	if (is_dp_hdcp(hdcp))
 55		return (hdcp->auth.msg.hdcp1.bstatus & DP_BSTATUS_READY) ?
 56				MOD_HDCP_STATUS_SUCCESS :
 57				MOD_HDCP_STATUS_HDCP1_KSV_LIST_NOT_READY;
 58	return (hdcp->auth.msg.hdcp1.bcaps & DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY) ?
 59			MOD_HDCP_STATUS_SUCCESS :
 60			MOD_HDCP_STATUS_HDCP1_KSV_LIST_NOT_READY;
 61}
 62
 63static inline enum mod_hdcp_status check_hdcp_capable_dp(struct mod_hdcp *hdcp)
 64{
 65	return (hdcp->auth.msg.hdcp1.bcaps & DP_BCAPS_HDCP_CAPABLE) ?
 66			MOD_HDCP_STATUS_SUCCESS :
 67			MOD_HDCP_STATUS_HDCP1_NOT_CAPABLE;
 68}
 69
 70static inline enum mod_hdcp_status check_r0p_available_dp(struct mod_hdcp *hdcp)
 71{
 72	enum mod_hdcp_status status;
 73
 74	if (is_dp_hdcp(hdcp)) {
 75		status = (hdcp->auth.msg.hdcp1.bstatus &
 76				DP_BSTATUS_R0_PRIME_READY) ?
 77			MOD_HDCP_STATUS_SUCCESS :
 78			MOD_HDCP_STATUS_HDCP1_R0_PRIME_PENDING;
 79	} else {
 80		status = MOD_HDCP_STATUS_INVALID_OPERATION;
 81	}
 82	return status;
 83}
 84
 85static inline enum mod_hdcp_status check_link_integrity_dp(
 86		struct mod_hdcp *hdcp)
 87{
 88	return (hdcp->auth.msg.hdcp1.bstatus &
 89			DP_BSTATUS_LINK_FAILURE) ?
 90			MOD_HDCP_STATUS_HDCP1_LINK_INTEGRITY_FAILURE :
 91			MOD_HDCP_STATUS_SUCCESS;
 92}
 93
 94static inline enum mod_hdcp_status check_no_reauthentication_request_dp(
 95		struct mod_hdcp *hdcp)
 96{
 97	return (hdcp->auth.msg.hdcp1.bstatus & DP_BSTATUS_REAUTH_REQ) ?
 98			MOD_HDCP_STATUS_HDCP1_REAUTH_REQUEST_ISSUED :
 99			MOD_HDCP_STATUS_SUCCESS;
100}
101
102static inline enum mod_hdcp_status check_no_max_cascade(struct mod_hdcp *hdcp)
103{
104	enum mod_hdcp_status status;
105
106	if (is_dp_hdcp(hdcp))
107		status = DRM_HDCP_MAX_CASCADE_EXCEEDED(hdcp->auth.msg.hdcp1.binfo_dp >> 8)
108				 ? MOD_HDCP_STATUS_HDCP1_MAX_CASCADE_EXCEEDED_FAILURE
109				 : MOD_HDCP_STATUS_SUCCESS;
110	else
111		status = DRM_HDCP_MAX_CASCADE_EXCEEDED(hdcp->auth.msg.hdcp1.bstatus >> 8)
112				 ? MOD_HDCP_STATUS_HDCP1_MAX_CASCADE_EXCEEDED_FAILURE
113				 : MOD_HDCP_STATUS_SUCCESS;
114	return status;
115}
116
117static inline enum mod_hdcp_status check_no_max_devs(struct mod_hdcp *hdcp)
118{
119	enum mod_hdcp_status status;
120
121	if (is_dp_hdcp(hdcp))
122		status = DRM_HDCP_MAX_DEVICE_EXCEEDED(hdcp->auth.msg.hdcp1.binfo_dp) ?
123				MOD_HDCP_STATUS_HDCP1_MAX_DEVS_EXCEEDED_FAILURE :
124				MOD_HDCP_STATUS_SUCCESS;
125	else
126		status = DRM_HDCP_MAX_DEVICE_EXCEEDED(hdcp->auth.msg.hdcp1.bstatus) ?
127				MOD_HDCP_STATUS_HDCP1_MAX_DEVS_EXCEEDED_FAILURE :
128				MOD_HDCP_STATUS_SUCCESS;
129	return status;
130}
131
132static inline uint8_t get_device_count(struct mod_hdcp *hdcp)
133{
134	return is_dp_hdcp(hdcp) ?
135			DRM_HDCP_NUM_DOWNSTREAM(hdcp->auth.msg.hdcp1.binfo_dp) :
136			DRM_HDCP_NUM_DOWNSTREAM(hdcp->auth.msg.hdcp1.bstatus);
137}
138
139static inline enum mod_hdcp_status check_device_count(struct mod_hdcp *hdcp)
140{
141	/* Avoid device count == 0 to do authentication */
142	if (get_device_count(hdcp) == 0)
143		return MOD_HDCP_STATUS_HDCP1_DEVICE_COUNT_MISMATCH_FAILURE;
144
145	hdcp->connection.trace.hdcp1.downstream_device_count = get_device_count(hdcp);
146
147	/* Some MST display may choose to report the internal panel as an HDCP RX.
148	 * To update this condition with 1(because the immediate repeater's internal
149	 * panel is possibly not included in DEVICE_COUNT) + get_device_count(hdcp).
150	 * Device count must be greater than or equal to tracked hdcp displays.
151	 */
152	return ((1 + get_device_count(hdcp)) < get_active_display_count(hdcp)) ?
153			MOD_HDCP_STATUS_HDCP1_DEVICE_COUNT_MISMATCH_FAILURE :
154			MOD_HDCP_STATUS_SUCCESS;
155}
156
157static enum mod_hdcp_status wait_for_active_rx(struct mod_hdcp *hdcp,
158		struct mod_hdcp_event_context *event_ctx,
159		struct mod_hdcp_transition_input_hdcp1 *input)
160{
161	enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
162
163	if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) {
164		event_ctx->unexpected_event = 1;
165		goto out;
166	}
167
168	if (!mod_hdcp_execute_and_set(mod_hdcp_read_bksv,
169			&input->bksv_read, &status,
170			hdcp, "bksv_read"))
171		goto out;
172	if (!mod_hdcp_execute_and_set(mod_hdcp_read_bcaps,
173			&input->bcaps_read, &status,
174			hdcp, "bcaps_read"))
175		goto out;
176out:
177	return status;
178}
179
180static enum mod_hdcp_status exchange_ksvs(struct mod_hdcp *hdcp,
181		struct mod_hdcp_event_context *event_ctx,
182		struct mod_hdcp_transition_input_hdcp1 *input)
183{
184	enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
185
186	if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) {
187		event_ctx->unexpected_event = 1;
188		goto out;
189	}
190
191	if (!mod_hdcp_execute_and_set(mod_hdcp_hdcp1_create_session,
192			&input->create_session, &status,
193			hdcp, "create_session"))
194		goto out;
195	if (!mod_hdcp_execute_and_set(mod_hdcp_write_an,
196			&input->an_write, &status,
197			hdcp, "an_write"))
198		goto out;
199	if (!mod_hdcp_execute_and_set(mod_hdcp_write_aksv,
200			&input->aksv_write, &status,
201			hdcp, "aksv_write"))
202		goto out;
203	if (!mod_hdcp_execute_and_set(mod_hdcp_read_bksv,
204			&input->bksv_read, &status,
205			hdcp, "bksv_read"))
206		goto out;
207	if (!mod_hdcp_execute_and_set(validate_bksv,
208			&input->bksv_validation, &status,
209			hdcp, "bksv_validation"))
210		goto out;
211	if (hdcp->auth.msg.hdcp1.ainfo) {
212		if (!mod_hdcp_execute_and_set(mod_hdcp_write_ainfo,
213				&input->ainfo_write, &status,
214				hdcp, "ainfo_write"))
215			goto out;
216	}
217out:
218	return status;
219}
220
221static enum mod_hdcp_status computations_validate_rx_test_for_repeater(
222		struct mod_hdcp *hdcp,
223		struct mod_hdcp_event_context *event_ctx,
224		struct mod_hdcp_transition_input_hdcp1 *input)
225{
226	enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
227
228	if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) {
229		event_ctx->unexpected_event = 1;
230		goto out;
231	}
232
233	if (!mod_hdcp_execute_and_set(mod_hdcp_read_r0p,
234			&input->r0p_read, &status,
235			hdcp, "r0p_read"))
236		goto out;
237	if (!mod_hdcp_execute_and_set(mod_hdcp_hdcp1_validate_rx,
238			&input->rx_validation, &status,
239			hdcp, "rx_validation"))
240		goto out;
241	if (hdcp->connection.is_repeater) {
242		if (!hdcp->connection.link.adjust.hdcp1.postpone_encryption)
243			if (!mod_hdcp_execute_and_set(
244					mod_hdcp_hdcp1_enable_encryption,
245					&input->encryption, &status,
246					hdcp, "encryption"))
247				goto out;
248	} else {
249		if (!mod_hdcp_execute_and_set(mod_hdcp_hdcp1_enable_encryption,
250				&input->encryption, &status,
251				hdcp, "encryption"))
252			goto out;
253		if (is_dp_mst_hdcp(hdcp))
254			if (!mod_hdcp_execute_and_set(
255					mod_hdcp_hdcp1_enable_dp_stream_encryption,
256					&input->stream_encryption_dp, &status,
257					hdcp, "stream_encryption_dp"))
258				goto out;
259	}
260out:
261	return status;
262}
263
264static enum mod_hdcp_status authenticated(struct mod_hdcp *hdcp,
265		struct mod_hdcp_event_context *event_ctx,
266		struct mod_hdcp_transition_input_hdcp1 *input)
267{
268	enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
269
270	if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) {
271		event_ctx->unexpected_event = 1;
272		goto out;
273	}
274
275	mod_hdcp_execute_and_set(mod_hdcp_hdcp1_link_maintenance,
276			&input->link_maintenance, &status,
277			hdcp, "link_maintenance");
278out:
279	return status;
280}
281
282static enum mod_hdcp_status wait_for_ready(struct mod_hdcp *hdcp,
283		struct mod_hdcp_event_context *event_ctx,
284		struct mod_hdcp_transition_input_hdcp1 *input)
285{
286	enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
287
288	if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK &&
289			event_ctx->event != MOD_HDCP_EVENT_CPIRQ &&
290			event_ctx->event != MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) {
291		event_ctx->unexpected_event = 1;
292		goto out;
293	}
294
295	if (is_dp_hdcp(hdcp)) {
296		if (!mod_hdcp_execute_and_set(mod_hdcp_read_bstatus,
297				&input->bstatus_read, &status,
298				hdcp, "bstatus_read"))
299			goto out;
300		if (!mod_hdcp_execute_and_set(check_link_integrity_dp,
301				&input->link_integrity_check, &status,
302				hdcp, "link_integrity_check"))
303			goto out;
304		if (!mod_hdcp_execute_and_set(check_no_reauthentication_request_dp,
305				&input->reauth_request_check, &status,
306				hdcp, "reauth_request_check"))
307			goto out;
308	} else {
309		if (!mod_hdcp_execute_and_set(mod_hdcp_read_bcaps,
310				&input->bcaps_read, &status,
311				hdcp, "bcaps_read"))
312			goto out;
313	}
314	if (!mod_hdcp_execute_and_set(check_ksv_ready,
315			&input->ready_check, &status,
316			hdcp, "ready_check"))
317		goto out;
318out:
319	return status;
320}
321
322static enum mod_hdcp_status read_ksv_list(struct mod_hdcp *hdcp,
323		struct mod_hdcp_event_context *event_ctx,
324		struct mod_hdcp_transition_input_hdcp1 *input)
325{
326	enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
327	uint8_t device_count;
328
329	if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) {
330		event_ctx->unexpected_event = 1;
331		goto out;
332	}
333
334	if (is_dp_hdcp(hdcp)) {
335		if (!mod_hdcp_execute_and_set(mod_hdcp_read_binfo,
336				&input->binfo_read_dp, &status,
337				hdcp, "binfo_read_dp"))
338			goto out;
339	} else {
340		if (!mod_hdcp_execute_and_set(mod_hdcp_read_bstatus,
341				&input->bstatus_read, &status,
342				hdcp, "bstatus_read"))
343			goto out;
344	}
345	if (!mod_hdcp_execute_and_set(check_no_max_cascade,
346			&input->max_cascade_check, &status,
347			hdcp, "max_cascade_check"))
348		goto out;
349	if (!mod_hdcp_execute_and_set(check_no_max_devs,
350			&input->max_devs_check, &status,
351			hdcp, "max_devs_check"))
352		goto out;
353	if (!mod_hdcp_execute_and_set(check_device_count,
354			&input->device_count_check, &status,
355			hdcp, "device_count_check"))
356		goto out;
357	device_count = get_device_count(hdcp);
358	hdcp->auth.msg.hdcp1.ksvlist_size = device_count*5;
359	if (!mod_hdcp_execute_and_set(mod_hdcp_read_ksvlist,
360			&input->ksvlist_read, &status,
361			hdcp, "ksvlist_read"))
362		goto out;
363	if (!mod_hdcp_execute_and_set(mod_hdcp_read_vp,
364			&input->vp_read, &status,
365			hdcp, "vp_read"))
366		goto out;
367	if (!mod_hdcp_execute_and_set(mod_hdcp_hdcp1_validate_ksvlist_vp,
368			&input->ksvlist_vp_validation, &status,
369			hdcp, "ksvlist_vp_validation"))
370		goto out;
371	if (input->encryption != PASS)
372		if (!mod_hdcp_execute_and_set(mod_hdcp_hdcp1_enable_encryption,
373				&input->encryption, &status,
374				hdcp, "encryption"))
375			goto out;
376	if (is_dp_mst_hdcp(hdcp))
377		if (!mod_hdcp_execute_and_set(
378				mod_hdcp_hdcp1_enable_dp_stream_encryption,
379				&input->stream_encryption_dp, &status,
380				hdcp, "stream_encryption_dp"))
381			goto out;
382out:
383	return status;
384}
385
386static enum mod_hdcp_status determine_rx_hdcp_capable_dp(struct mod_hdcp *hdcp,
387		struct mod_hdcp_event_context *event_ctx,
388		struct mod_hdcp_transition_input_hdcp1 *input)
389{
390	enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
391
392	if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) {
393		event_ctx->unexpected_event = 1;
394		goto out;
395	}
396
397	if (!mod_hdcp_execute_and_set(mod_hdcp_read_bcaps,
398			&input->bcaps_read, &status,
399			hdcp, "bcaps_read"))
400		goto out;
401	if (!mod_hdcp_execute_and_set(check_hdcp_capable_dp,
402			&input->hdcp_capable_dp, &status,
403			hdcp, "hdcp_capable_dp"))
404		goto out;
405out:
406	return status;
407}
408
409static enum mod_hdcp_status wait_for_r0_prime_dp(struct mod_hdcp *hdcp,
410		struct mod_hdcp_event_context *event_ctx,
411		struct mod_hdcp_transition_input_hdcp1 *input)
412{
413	enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
414
415	if (event_ctx->event != MOD_HDCP_EVENT_CPIRQ &&
416			event_ctx->event != MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) {
417		event_ctx->unexpected_event = 1;
418		goto out;
419	}
420
421	if (!mod_hdcp_execute_and_set(mod_hdcp_read_bstatus,
422			&input->bstatus_read, &status,
423			hdcp, "bstatus_read"))
424		goto out;
425	if (!mod_hdcp_execute_and_set(check_r0p_available_dp,
426			&input->r0p_available_dp, &status,
427			hdcp, "r0p_available_dp"))
428		goto out;
429out:
430	return status;
431}
432
433static enum mod_hdcp_status authenticated_dp(struct mod_hdcp *hdcp,
434		struct mod_hdcp_event_context *event_ctx,
435		struct mod_hdcp_transition_input_hdcp1 *input)
436{
437	enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
438
439	if (event_ctx->event != MOD_HDCP_EVENT_CPIRQ) {
440		event_ctx->unexpected_event = 1;
441		goto out;
442	}
443
444	mod_hdcp_execute_and_set(mod_hdcp_read_bstatus,
445			&input->bstatus_read, &status,
446			hdcp, "bstatus_read");
447
448	mod_hdcp_execute_and_set(check_link_integrity_dp,
449			&input->link_integrity_check, &status,
450			hdcp, "link_integrity_check");
451
452	mod_hdcp_execute_and_set(check_no_reauthentication_request_dp,
453			&input->reauth_request_check, &status,
454			hdcp, "reauth_request_check");
455
456out:
457	return status;
458}
459
460uint8_t mod_hdcp_execute_and_set(
461		mod_hdcp_action func, uint8_t *flag,
462		enum mod_hdcp_status *status, struct mod_hdcp *hdcp, char *str)
463{
464	*status = func(hdcp);
465	if (*status == MOD_HDCP_STATUS_SUCCESS && *flag != PASS) {
466		HDCP_INPUT_PASS_TRACE(hdcp, str);
467		*flag = PASS;
468	} else if (*status != MOD_HDCP_STATUS_SUCCESS && *flag != FAIL) {
469		HDCP_INPUT_FAIL_TRACE(hdcp, str);
470		*flag = FAIL;
471	}
472	return (*status == MOD_HDCP_STATUS_SUCCESS);
473}
474
475enum mod_hdcp_status mod_hdcp_hdcp1_execution(struct mod_hdcp *hdcp,
476		struct mod_hdcp_event_context *event_ctx,
477		struct mod_hdcp_transition_input_hdcp1 *input)
478{
479	enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
480
481	switch (current_state(hdcp)) {
482	case H1_A0_WAIT_FOR_ACTIVE_RX:
483		status = wait_for_active_rx(hdcp, event_ctx, input);
484		break;
485	case H1_A1_EXCHANGE_KSVS:
486		status = exchange_ksvs(hdcp, event_ctx, input);
487		break;
488	case H1_A2_COMPUTATIONS_A3_VALIDATE_RX_A6_TEST_FOR_REPEATER:
489		status = computations_validate_rx_test_for_repeater(hdcp,
490				event_ctx, input);
491		break;
492	case H1_A45_AUTHENTICATED:
493		status = authenticated(hdcp, event_ctx, input);
494		break;
495	case H1_A8_WAIT_FOR_READY:
496		status = wait_for_ready(hdcp, event_ctx, input);
497		break;
498	case H1_A9_READ_KSV_LIST:
499		status = read_ksv_list(hdcp, event_ctx, input);
500		break;
501	default:
502		status = MOD_HDCP_STATUS_INVALID_STATE;
503		break;
504	}
505
506	return status;
507}
508
509enum mod_hdcp_status mod_hdcp_hdcp1_dp_execution(struct mod_hdcp *hdcp,
510						 struct mod_hdcp_event_context *event_ctx,
511						 struct mod_hdcp_transition_input_hdcp1 *input)
512{
513	enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
514
515	switch (current_state(hdcp)) {
516	case D1_A0_DETERMINE_RX_HDCP_CAPABLE:
517		status = determine_rx_hdcp_capable_dp(hdcp, event_ctx, input);
518		break;
519	case D1_A1_EXCHANGE_KSVS:
520		status = exchange_ksvs(hdcp, event_ctx, input);
521		break;
522	case D1_A23_WAIT_FOR_R0_PRIME:
523		status = wait_for_r0_prime_dp(hdcp, event_ctx, input);
524		break;
525	case D1_A2_COMPUTATIONS_A3_VALIDATE_RX_A5_TEST_FOR_REPEATER:
526		status = computations_validate_rx_test_for_repeater(
527				hdcp, event_ctx, input);
528		break;
529	case D1_A4_AUTHENTICATED:
530		status = authenticated_dp(hdcp, event_ctx, input);
531		break;
532	case D1_A6_WAIT_FOR_READY:
533		status = wait_for_ready(hdcp, event_ctx, input);
534		break;
535	case D1_A7_READ_KSV_LIST:
536		status = read_ksv_list(hdcp, event_ctx, input);
537		break;
538	default:
539		status = MOD_HDCP_STATUS_INVALID_STATE;
540		break;
541	}
542
543	return status;
544}
~/ Read-only file preview.