14c283fdaSBhawanpreet Lakha/*
24c283fdaSBhawanpreet Lakha * Copyright 2019 Advanced Micro Devices, Inc.
34c283fdaSBhawanpreet Lakha *
44c283fdaSBhawanpreet Lakha * Permission is hereby granted, free of charge, to any person obtaining a
54c283fdaSBhawanpreet Lakha * copy of this software and associated documentation files (the "Software"),
64c283fdaSBhawanpreet Lakha * to deal in the Software without restriction, including without limitation
74c283fdaSBhawanpreet Lakha * the rights to use, copy, modify, merge, publish, distribute, sublicense,
84c283fdaSBhawanpreet Lakha * and/or sell copies of the Software, and to permit persons to whom the
94c283fdaSBhawanpreet Lakha * Software is furnished to do so, subject to the following conditions:
104c283fdaSBhawanpreet Lakha *
114c283fdaSBhawanpreet Lakha * The above copyright notice and this permission notice shall be included in
124c283fdaSBhawanpreet Lakha * all copies or substantial portions of the Software.
134c283fdaSBhawanpreet Lakha *
144c283fdaSBhawanpreet Lakha * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
154c283fdaSBhawanpreet Lakha * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
164c283fdaSBhawanpreet Lakha * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
174c283fdaSBhawanpreet Lakha * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
184c283fdaSBhawanpreet Lakha * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
194c283fdaSBhawanpreet Lakha * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
204c283fdaSBhawanpreet Lakha * OTHER DEALINGS IN THE SOFTWARE.
214c283fdaSBhawanpreet Lakha *
224c283fdaSBhawanpreet Lakha * Authors: AMD
234c283fdaSBhawanpreet Lakha *
244c283fdaSBhawanpreet Lakha */
254c283fdaSBhawanpreet Lakha
264c283fdaSBhawanpreet Lakha#include "hdcp.h"
274c283fdaSBhawanpreet Lakha
284c283fdaSBhawanpreet Lakhaenum mod_hdcp_status mod_hdcp_hdcp1_transition(struct mod_hdcp *hdcp,
294c283fdaSBhawanpreet Lakha		struct mod_hdcp_event_context *event_ctx,
304c283fdaSBhawanpreet Lakha		struct mod_hdcp_transition_input_hdcp1 *input,
314c283fdaSBhawanpreet Lakha		struct mod_hdcp_output *output)
324c283fdaSBhawanpreet Lakha{
334c283fdaSBhawanpreet Lakha	enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
344c283fdaSBhawanpreet Lakha	struct mod_hdcp_connection *conn = &hdcp->connection;
354c283fdaSBhawanpreet Lakha	struct mod_hdcp_link_adjustment *adjust = &hdcp->connection.link.adjust;
364c283fdaSBhawanpreet Lakha
374c283fdaSBhawanpreet Lakha	switch (current_state(hdcp)) {
384c283fdaSBhawanpreet Lakha	case H1_A0_WAIT_FOR_ACTIVE_RX:
394c283fdaSBhawanpreet Lakha		if (input->bksv_read != PASS || input->bcaps_read != PASS) {
404c283fdaSBhawanpreet Lakha			/* 1A-04: repeatedly attempts on port access failure */
414c283fdaSBhawanpreet Lakha			callback_in_ms(500, output);
424c283fdaSBhawanpreet Lakha			increment_stay_counter(hdcp);
434c283fdaSBhawanpreet Lakha			break;
444c283fdaSBhawanpreet Lakha		}
454c283fdaSBhawanpreet Lakha		callback_in_ms(0, output);
464c283fdaSBhawanpreet Lakha		set_state_id(hdcp, output, H1_A1_EXCHANGE_KSVS);
474c283fdaSBhawanpreet Lakha		break;
484c283fdaSBhawanpreet Lakha	case H1_A1_EXCHANGE_KSVS:
499124ee78SWenjing Liu		if (input->create_session != PASS) {
504c283fdaSBhawanpreet Lakha			/* out of sync with psp state */
514c283fdaSBhawanpreet Lakha			adjust->hdcp1.disable = 1;
524c283fdaSBhawanpreet Lakha			fail_and_restart_in_ms(0, &status, output);
534c283fdaSBhawanpreet Lakha			break;
544c283fdaSBhawanpreet Lakha		} else if (input->an_write != PASS ||
554c283fdaSBhawanpreet Lakha				input->aksv_write != PASS ||
564c283fdaSBhawanpreet Lakha				input->bksv_read != PASS ||
574c283fdaSBhawanpreet Lakha				input->bksv_validation != PASS ||
584c283fdaSBhawanpreet Lakha				input->ainfo_write == FAIL) {
594c283fdaSBhawanpreet Lakha			/* 1A-05: consider invalid bksv a failure */
604c283fdaSBhawanpreet Lakha			fail_and_restart_in_ms(0, &status, output);
614c283fdaSBhawanpreet Lakha			break;
624c283fdaSBhawanpreet Lakha		}
634c283fdaSBhawanpreet Lakha		callback_in_ms(300, output);
644c283fdaSBhawanpreet Lakha		set_state_id(hdcp, output,
654c283fdaSBhawanpreet Lakha			H1_A2_COMPUTATIONS_A3_VALIDATE_RX_A6_TEST_FOR_REPEATER);
664c283fdaSBhawanpreet Lakha		break;
674c283fdaSBhawanpreet Lakha	case H1_A2_COMPUTATIONS_A3_VALIDATE_RX_A6_TEST_FOR_REPEATER:
684c283fdaSBhawanpreet Lakha		if (input->bcaps_read != PASS ||
69454425e8SJing Zhou				input->r0p_read != PASS) {
70454425e8SJing Zhou			fail_and_restart_in_ms(0, &status, output);
71454425e8SJing Zhou			break;
72454425e8SJing Zhou		} else if (input->rx_validation != PASS) {
734c283fdaSBhawanpreet Lakha			/* 1A-06: consider invalid r0' a failure */
744c283fdaSBhawanpreet Lakha			/* 1A-08: consider bksv listed in SRM a failure */
75454425e8SJing Zhou			/*
76454425e8SJing Zhou			 * some slow RX will fail rx validation when it is
77454425e8SJing Zhou			 * not ready. give it more time to react before retry.
78454425e8SJing Zhou			 */
79454425e8SJing Zhou			fail_and_restart_in_ms(1000, &status, output);
80454425e8SJing Zhou			break;
81454425e8SJing Zhou		} else if (!conn->is_repeater && input->encryption != PASS) {
824c283fdaSBhawanpreet Lakha			fail_and_restart_in_ms(0, &status, output);
834c283fdaSBhawanpreet Lakha			break;
844c283fdaSBhawanpreet Lakha		}
854c283fdaSBhawanpreet Lakha		if (conn->is_repeater) {
864c283fdaSBhawanpreet Lakha			callback_in_ms(0, output);
874c283fdaSBhawanpreet Lakha			set_watchdog_in_ms(hdcp, 5000, output);
884c283fdaSBhawanpreet Lakha			set_state_id(hdcp, output, H1_A8_WAIT_FOR_READY);
894c283fdaSBhawanpreet Lakha		} else {
904c283fdaSBhawanpreet Lakha			callback_in_ms(0, output);
91d4411d79SColin Ian King			set_state_id(hdcp, output, H1_A45_AUTHENTICATED);
920a95fab3SWenjing Liu			set_auth_complete(hdcp, output);
934c283fdaSBhawanpreet Lakha		}
944c283fdaSBhawanpreet Lakha		break;
95d4411d79SColin Ian King	case H1_A45_AUTHENTICATED:
9645f673e6SWenjing Liu		if (input->link_maintenance == FAIL) {
974c283fdaSBhawanpreet Lakha			/* 1A-07: consider invalid ri' a failure */
984c283fdaSBhawanpreet Lakha			/* 1A-07a: consider read ri' not returned a failure */
994c283fdaSBhawanpreet Lakha			fail_and_restart_in_ms(0, &status, output);
1004c283fdaSBhawanpreet Lakha			break;
1014c283fdaSBhawanpreet Lakha		}
1024c283fdaSBhawanpreet Lakha		callback_in_ms(500, output);
1034c283fdaSBhawanpreet Lakha		increment_stay_counter(hdcp);
1044c283fdaSBhawanpreet Lakha		break;
1054c283fdaSBhawanpreet Lakha	case H1_A8_WAIT_FOR_READY:
1064c283fdaSBhawanpreet Lakha		if (input->ready_check != PASS) {
1074c283fdaSBhawanpreet Lakha			if (event_ctx->event ==
1084c283fdaSBhawanpreet Lakha					MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) {
1094c283fdaSBhawanpreet Lakha				/* 1B-03: fail hdcp on ksv list READY timeout */
1104c283fdaSBhawanpreet Lakha				/* prevent black screen in next attempt */
1114c283fdaSBhawanpreet Lakha				adjust->hdcp1.postpone_encryption = 1;
1124c283fdaSBhawanpreet Lakha				fail_and_restart_in_ms(0, &status, output);
1134c283fdaSBhawanpreet Lakha			} else {
1144c283fdaSBhawanpreet Lakha				/* continue ksv list READY polling*/
1154c283fdaSBhawanpreet Lakha				callback_in_ms(500, output);
1164c283fdaSBhawanpreet Lakha				increment_stay_counter(hdcp);
1174c283fdaSBhawanpreet Lakha			}
1184c283fdaSBhawanpreet Lakha			break;
1194c283fdaSBhawanpreet Lakha		}
1204c283fdaSBhawanpreet Lakha		callback_in_ms(0, output);
1214c283fdaSBhawanpreet Lakha		set_state_id(hdcp, output, H1_A9_READ_KSV_LIST);
1224c283fdaSBhawanpreet Lakha		break;
1234c283fdaSBhawanpreet Lakha	case H1_A9_READ_KSV_LIST:
1244c283fdaSBhawanpreet Lakha		if (input->bstatus_read != PASS ||
1254c283fdaSBhawanpreet Lakha				input->max_cascade_check != PASS ||
1264c283fdaSBhawanpreet Lakha				input->max_devs_check != PASS ||
1274c283fdaSBhawanpreet Lakha				input->device_count_check != PASS ||
1284c283fdaSBhawanpreet Lakha				input->ksvlist_read != PASS ||
1294c283fdaSBhawanpreet Lakha				input->vp_read != PASS ||
1304c283fdaSBhawanpreet Lakha				input->ksvlist_vp_validation != PASS ||
1314c283fdaSBhawanpreet Lakha				input->encryption != PASS) {
1324c283fdaSBhawanpreet Lakha			/* 1B-06: consider MAX_CASCADE_EXCEEDED a failure */
1334c283fdaSBhawanpreet Lakha			/* 1B-05: consider MAX_DEVS_EXCEEDED a failure */
1344c283fdaSBhawanpreet Lakha			/* 1B-04: consider invalid v' a failure */
1354c283fdaSBhawanpreet Lakha			fail_and_restart_in_ms(0, &status, output);
1364c283fdaSBhawanpreet Lakha			break;
1374c283fdaSBhawanpreet Lakha		}
1384c283fdaSBhawanpreet Lakha		callback_in_ms(0, output);
139d4411d79SColin Ian King		set_state_id(hdcp, output, H1_A45_AUTHENTICATED);
1400a95fab3SWenjing Liu		set_auth_complete(hdcp, output);
1414c283fdaSBhawanpreet Lakha		break;
1424c283fdaSBhawanpreet Lakha	default:
1434c283fdaSBhawanpreet Lakha		status = MOD_HDCP_STATUS_INVALID_STATE;
1444c283fdaSBhawanpreet Lakha		fail_and_restart_in_ms(0, &status, output);
1454c283fdaSBhawanpreet Lakha		break;
1464c283fdaSBhawanpreet Lakha	}
1474c283fdaSBhawanpreet Lakha
1484c283fdaSBhawanpreet Lakha	return status;
1494c283fdaSBhawanpreet Lakha}
1504c283fdaSBhawanpreet Lakha
1514c283fdaSBhawanpreet Lakhaenum mod_hdcp_status mod_hdcp_hdcp1_dp_transition(struct mod_hdcp *hdcp,
1524c283fdaSBhawanpreet Lakha		struct mod_hdcp_event_context *event_ctx,
1534c283fdaSBhawanpreet Lakha		struct mod_hdcp_transition_input_hdcp1 *input,
1544c283fdaSBhawanpreet Lakha		struct mod_hdcp_output *output)
1554c283fdaSBhawanpreet Lakha{
1564c283fdaSBhawanpreet Lakha	enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
1574c283fdaSBhawanpreet Lakha	struct mod_hdcp_connection *conn = &hdcp->connection;
1584c283fdaSBhawanpreet Lakha	struct mod_hdcp_link_adjustment *adjust = &hdcp->connection.link.adjust;
1594c283fdaSBhawanpreet Lakha
1604c283fdaSBhawanpreet Lakha	switch (current_state(hdcp)) {
1614c283fdaSBhawanpreet Lakha	case D1_A0_DETERMINE_RX_HDCP_CAPABLE:
1624c283fdaSBhawanpreet Lakha		if (input->bcaps_read != PASS) {
1634c283fdaSBhawanpreet Lakha			/* 1A-04: no authentication on bcaps read failure */
1644c283fdaSBhawanpreet Lakha			fail_and_restart_in_ms(0, &status, output);
1654c283fdaSBhawanpreet Lakha			break;
1664c283fdaSBhawanpreet Lakha		} else if (input->hdcp_capable_dp != PASS) {
1674c283fdaSBhawanpreet Lakha			adjust->hdcp1.disable = 1;
1684c283fdaSBhawanpreet Lakha			fail_and_restart_in_ms(0, &status, output);
1694c283fdaSBhawanpreet Lakha			break;
1704c283fdaSBhawanpreet Lakha		}
1714c283fdaSBhawanpreet Lakha		callback_in_ms(0, output);
1724c283fdaSBhawanpreet Lakha		set_state_id(hdcp, output, D1_A1_EXCHANGE_KSVS);
1734c283fdaSBhawanpreet Lakha		break;
1744c283fdaSBhawanpreet Lakha	case D1_A1_EXCHANGE_KSVS:
1759124ee78SWenjing Liu		if (input->create_session != PASS) {
1764c283fdaSBhawanpreet Lakha			/* out of sync with psp state */
1774c283fdaSBhawanpreet Lakha			adjust->hdcp1.disable = 1;
1784c283fdaSBhawanpreet Lakha			fail_and_restart_in_ms(0, &status, output);
1794c283fdaSBhawanpreet Lakha			break;
1804c283fdaSBhawanpreet Lakha		} else if (input->an_write != PASS ||
1814c283fdaSBhawanpreet Lakha				input->aksv_write != PASS ||
1824c283fdaSBhawanpreet Lakha				input->bksv_read != PASS ||
1834c283fdaSBhawanpreet Lakha				input->bksv_validation != PASS ||
1844c283fdaSBhawanpreet Lakha				input->ainfo_write == FAIL) {
1854c283fdaSBhawanpreet Lakha			/* 1A-05: consider invalid bksv a failure */
1864c283fdaSBhawanpreet Lakha			fail_and_restart_in_ms(0, &status, output);
1874c283fdaSBhawanpreet Lakha			break;
1884c283fdaSBhawanpreet Lakha		}
1894c283fdaSBhawanpreet Lakha		set_watchdog_in_ms(hdcp, 100, output);
1904c283fdaSBhawanpreet Lakha		set_state_id(hdcp, output, D1_A23_WAIT_FOR_R0_PRIME);
1914c283fdaSBhawanpreet Lakha		break;
1924c283fdaSBhawanpreet Lakha	case D1_A23_WAIT_FOR_R0_PRIME:
1934c283fdaSBhawanpreet Lakha		if (input->bstatus_read != PASS) {
1944c283fdaSBhawanpreet Lakha			fail_and_restart_in_ms(0, &status, output);
1954c283fdaSBhawanpreet Lakha			break;
1964c283fdaSBhawanpreet Lakha		} else if (input->r0p_available_dp != PASS) {
1974c283fdaSBhawanpreet Lakha			if (event_ctx->event == MOD_HDCP_EVENT_WATCHDOG_TIMEOUT)
1984c283fdaSBhawanpreet Lakha				fail_and_restart_in_ms(0, &status, output);
1994c283fdaSBhawanpreet Lakha			else
2004c283fdaSBhawanpreet Lakha				increment_stay_counter(hdcp);
2014c283fdaSBhawanpreet Lakha			break;
2024c283fdaSBhawanpreet Lakha		}
2034c283fdaSBhawanpreet Lakha		callback_in_ms(0, output);
2044c283fdaSBhawanpreet Lakha		set_state_id(hdcp, output, D1_A2_COMPUTATIONS_A3_VALIDATE_RX_A5_TEST_FOR_REPEATER);
2054c283fdaSBhawanpreet Lakha		break;
2064c283fdaSBhawanpreet Lakha	case D1_A2_COMPUTATIONS_A3_VALIDATE_RX_A5_TEST_FOR_REPEATER:
2074c283fdaSBhawanpreet Lakha		if (input->r0p_read != PASS) {
2084c283fdaSBhawanpreet Lakha			fail_and_restart_in_ms(0, &status, output);
2094c283fdaSBhawanpreet Lakha			break;
2104c283fdaSBhawanpreet Lakha		} else if (input->rx_validation != PASS) {
2113744ee2cSWenjing Liu			if (hdcp->state.stay_count < 2 &&
2123744ee2cSWenjing Liu					!hdcp->connection.is_hdcp1_revoked) {
2134c283fdaSBhawanpreet Lakha				/* allow 2 additional retries */
2144c283fdaSBhawanpreet Lakha				callback_in_ms(0, output);
2154c283fdaSBhawanpreet Lakha				increment_stay_counter(hdcp);
2164c283fdaSBhawanpreet Lakha			} else {
2174c283fdaSBhawanpreet Lakha				/*
2184c283fdaSBhawanpreet Lakha				 * 1A-06: consider invalid r0' a failure
2194c283fdaSBhawanpreet Lakha				 * after 3 attempts.
2204c283fdaSBhawanpreet Lakha				 * 1A-08: consider bksv listed in SRM a failure
2214c283fdaSBhawanpreet Lakha				 */
222454425e8SJing Zhou				/*
223454425e8SJing Zhou				 * some slow RX will fail rx validation when it is
224454425e8SJing Zhou				 * not ready. give it more time to react before retry.
225454425e8SJing Zhou				 */
226454425e8SJing Zhou				fail_and_restart_in_ms(1000, &status, output);
2274c283fdaSBhawanpreet Lakha			}
2284c283fdaSBhawanpreet Lakha			break;
229