1514c37e3STomas Winkler // SPDX-License-Identifier: GPL-2.0 264e9bbddSRamalingam C /* 364e9bbddSRamalingam C * Copyright © 2019 Intel Corporation 464e9bbddSRamalingam C * 50475afd2STomas Winkler * mei_hdcp.c: HDCP client driver for mei bus 664e9bbddSRamalingam C * 764e9bbddSRamalingam C * Author: 864e9bbddSRamalingam C * Ramalingam C <ramalingam.c@intel.com> 964e9bbddSRamalingam C */ 1064e9bbddSRamalingam C 1164e9bbddSRamalingam C /** 1264e9bbddSRamalingam C * DOC: MEI_HDCP Client Driver 1364e9bbddSRamalingam C * 140475afd2STomas Winkler * The mei_hdcp driver acts as a translation layer between HDCP 2.2 150475afd2STomas Winkler * protocol implementer (I915) and ME FW by translating HDCP2.2 160475afd2STomas Winkler * negotiation messages to ME FW command payloads and vice versa. 1764e9bbddSRamalingam C */ 1864e9bbddSRamalingam C 1964e9bbddSRamalingam C #include <linux/module.h> 2064e9bbddSRamalingam C #include <linux/slab.h> 2164e9bbddSRamalingam C #include <linux/uuid.h> 2264e9bbddSRamalingam C #include <linux/mei_cl_bus.h> 23fa301ad9SRamalingam C #include <linux/component.h> 24a37fb1e4SRamalingam C #include <drm/drm_connector.h> 25a37fb1e4SRamalingam C #include <drm/i915_component.h> 26a37fb1e4SRamalingam C #include <drm/i915_mei_hdcp_interface.h> 27a37fb1e4SRamalingam C 28a37fb1e4SRamalingam C #include "mei_hdcp.h" 29a37fb1e4SRamalingam C 30a37fb1e4SRamalingam C /** 31a37fb1e4SRamalingam C * mei_hdcp_initiate_session() - Initiate a Wired HDCP2.2 Tx Session in ME FW 32a37fb1e4SRamalingam C * @dev: device corresponding to the mei_cl_device 33a37fb1e4SRamalingam C * @data: Intel HW specific hdcp data 34a37fb1e4SRamalingam C * @ake_data: AKE_Init msg output. 35a37fb1e4SRamalingam C * 36a37fb1e4SRamalingam C * Return: 0 on Success, <0 on Failure. 37a37fb1e4SRamalingam C */ 38a37fb1e4SRamalingam C static int 39a37fb1e4SRamalingam C mei_hdcp_initiate_session(struct device *dev, struct hdcp_port_data *data, 40a37fb1e4SRamalingam C struct hdcp2_ake_init *ake_data) 41a37fb1e4SRamalingam C { 42a37fb1e4SRamalingam C struct wired_cmd_initiate_hdcp2_session_in session_init_in = { { 0 } }; 43a37fb1e4SRamalingam C struct wired_cmd_initiate_hdcp2_session_out 44a37fb1e4SRamalingam C session_init_out = { { 0 } }; 45a37fb1e4SRamalingam C struct mei_cl_device *cldev; 46a37fb1e4SRamalingam C ssize_t byte; 47a37fb1e4SRamalingam C 48a37fb1e4SRamalingam C if (!dev || !data || !ake_data) 49a37fb1e4SRamalingam C return -EINVAL; 50a37fb1e4SRamalingam C 51a37fb1e4SRamalingam C cldev = to_mei_cl_device(dev); 52a37fb1e4SRamalingam C 53a37fb1e4SRamalingam C session_init_in.header.api_version = HDCP_API_VERSION; 54a37fb1e4SRamalingam C session_init_in.header.command_id = WIRED_INITIATE_HDCP2_SESSION; 55a37fb1e4SRamalingam C session_init_in.header.status = ME_HDCP_STATUS_SUCCESS; 56a37fb1e4SRamalingam C session_init_in.header.buffer_len = 57a37fb1e4SRamalingam C WIRED_CMD_BUF_LEN_INITIATE_HDCP2_SESSION_IN; 58a37fb1e4SRamalingam C 59a37fb1e4SRamalingam C session_init_in.port.integrated_port_type = data->port_type; 600dcceb35SRamalingam C session_init_in.port.physical_port = (u8)data->fw_ddi; 612d15cf1bSRamalingam C session_init_in.port.attached_transcoder = (u8)data->fw_tc; 62a37fb1e4SRamalingam C session_init_in.protocol = data->protocol; 63a37fb1e4SRamalingam C 64a37fb1e4SRamalingam C byte = mei_cldev_send(cldev, (u8 *)&session_init_in, 65a37fb1e4SRamalingam C sizeof(session_init_in)); 66a37fb1e4SRamalingam C if (byte < 0) { 67a37fb1e4SRamalingam C dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); 68a37fb1e4SRamalingam C return byte; 69a37fb1e4SRamalingam C } 70a37fb1e4SRamalingam C 71a37fb1e4SRamalingam C byte = mei_cldev_recv(cldev, (u8 *)&session_init_out, 72a37fb1e4SRamalingam C sizeof(session_init_out)); 73a37fb1e4SRamalingam C if (byte < 0) { 74a37fb1e4SRamalingam C dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); 75a37fb1e4SRamalingam C return byte; 76a37fb1e4SRamalingam C } 77a37fb1e4SRamalingam C 78a37fb1e4SRamalingam C if (session_init_out.header.status != ME_HDCP_STATUS_SUCCESS) { 79a37fb1e4SRamalingam C dev_dbg(dev, "ME cmd 0x%08X Failed. Status: 0x%X\n", 80a37fb1e4SRamalingam C WIRED_INITIATE_HDCP2_SESSION, 81a37fb1e4SRamalingam C session_init_out.header.status); 82a37fb1e4SRamalingam C return -EIO; 83a37fb1e4SRamalingam C } 84a37fb1e4SRamalingam C 85a37fb1e4SRamalingam C ake_data->msg_id = HDCP_2_2_AKE_INIT; 86a37fb1e4SRamalingam C ake_data->tx_caps = session_init_out.tx_caps; 87a37fb1e4SRamalingam C memcpy(ake_data->r_tx, session_init_out.r_tx, HDCP_2_2_RTX_LEN); 88a37fb1e4SRamalingam C 89a37fb1e4SRamalingam C return 0; 90a37fb1e4SRamalingam C } 91a37fb1e4SRamalingam C 9239b71c2bSRamalingam C /** 9339b71c2bSRamalingam C * mei_hdcp_verify_receiver_cert_prepare_km() - Verify the Receiver Certificate 9439b71c2bSRamalingam C * AKE_Send_Cert and prepare AKE_Stored_Km/AKE_No_Stored_Km 9539b71c2bSRamalingam C * @dev: device corresponding to the mei_cl_device 9639b71c2bSRamalingam C * @data: Intel HW specific hdcp data 9739b71c2bSRamalingam C * @rx_cert: AKE_Send_Cert for verification 9839b71c2bSRamalingam C * @km_stored: Pairing status flag output 9939b71c2bSRamalingam C * @ek_pub_km: AKE_Stored_Km/AKE_No_Stored_Km output msg 10039b71c2bSRamalingam C * @msg_sz : size of AKE_XXXXX_Km output msg 10139b71c2bSRamalingam C * 10239b71c2bSRamalingam C * Return: 0 on Success, <0 on Failure 10339b71c2bSRamalingam C */ 10439b71c2bSRamalingam C static int 10539b71c2bSRamalingam C mei_hdcp_verify_receiver_cert_prepare_km(struct device *dev, 10639b71c2bSRamalingam C struct hdcp_port_data *data, 10739b71c2bSRamalingam C struct hdcp2_ake_send_cert *rx_cert, 10839b71c2bSRamalingam C bool *km_stored, 10939b71c2bSRamalingam C struct hdcp2_ake_no_stored_km 11039b71c2bSRamalingam C *ek_pub_km, 11139b71c2bSRamalingam C size_t *msg_sz) 11239b71c2bSRamalingam C { 11339b71c2bSRamalingam C struct wired_cmd_verify_receiver_cert_in verify_rxcert_in = { { 0 } }; 11439b71c2bSRamalingam C struct wired_cmd_verify_receiver_cert_out verify_rxcert_out = { { 0 } }; 11539b71c2bSRamalingam C struct mei_cl_device *cldev; 11639b71c2bSRamalingam C ssize_t byte; 11739b71c2bSRamalingam C 11839b71c2bSRamalingam C if (!dev || !data || !rx_cert || !km_stored || !ek_pub_km || !msg_sz) 11939b71c2bSRamalingam C return -EINVAL; 12039b71c2bSRamalingam C 12139b71c2bSRamalingam C cldev = to_mei_cl_device(dev); 12239b71c2bSRamalingam C 12339b71c2bSRamalingam C verify_rxcert_in.header.api_version = HDCP_API_VERSION; 12439b71c2bSRamalingam C verify_rxcert_in.header.command_id = WIRED_VERIFY_RECEIVER_CERT; 12539b71c2bSRamalingam C verify_rxcert_in.header.status = ME_HDCP_STATUS_SUCCESS; 12639b71c2bSRamalingam C verify_rxcert_in.header.buffer_len = 12739b71c2bSRamalingam C WIRED_CMD_BUF_LEN_VERIFY_RECEIVER_CERT_IN; 12839b71c2bSRamalingam C 12939b71c2bSRamalingam C verify_rxcert_in.port.integrated_port_type = data->port_type; 1300dcceb35SRamalingam C verify_rxcert_in.port.physical_port = (u8)data->fw_ddi; 1312d15cf1bSRamalingam C verify_rxcert_in.port.attached_transcoder = (u8)data->fw_tc; 13239b71c2bSRamalingam C 13339b71c2bSRamalingam C verify_rxcert_in.cert_rx = rx_cert->cert_rx; 13439b71c2bSRamalingam C memcpy(verify_rxcert_in.r_rx, &rx_cert->r_rx, HDCP_2_2_RRX_LEN); 13539b71c2bSRamalingam C memcpy(verify_rxcert_in.rx_caps, rx_cert->rx_caps, HDCP_2_2_RXCAPS_LEN); 13639b71c2bSRamalingam C 13739b71c2bSRamalingam C byte = mei_cldev_send(cldev, (u8 *)&verify_rxcert_in, 13839b71c2bSRamalingam C sizeof(verify_rxcert_in)); 13939b71c2bSRamalingam C if (byte < 0) { 14039b71c2bSRamalingam C dev_dbg(dev, "mei_cldev_send failed: %zd\n", byte); 14139b71c2bSRamalingam C return byte; 14239b71c2bSRamalingam C } 14339b71c2bSRamalingam C 14439b71c2bSRamalingam C byte = mei_cldev_recv(cldev, (u8 *)&verify_rxcert_out, 14539b71c2bSRamalingam C sizeof(verify_rxcert_out)); 14639b71c2bSRamalingam C if (byte < 0) { 14739b71c2bSRamalingam C dev_dbg(dev, "mei_cldev_recv failed: %zd\n", byte); 14839b71c2bSRamalingam C return byte; 14939b71c2bSRamalingam C } 15039b71c2bSRamalingam C 15139b71c2bSRamalingam C if (verify_rxcert_out.header.status != ME_HDCP_STATUS_SUCCESS) { 15239b71c2bSRamalingam C dev_dbg(dev, "ME cmd 0x%08X Failed. Status: 0x%X\n", 15339b71c2bSRamalingam C WIRED_VERIFY_RECEIVER_CERT, 15439b71c2bSRamalingam C verify_rxcert_out.header.status); 15539b71c2bSRamalingam C return -EIO; 15639b71c2bSRamalingam C } 15739b71c2bSRamalingam C 15839b71c2bSRamalingam C *km_stored = !!verify_rxcert_out.km_stored; 15939b71c2bSRamalingam C if (verify_rxcert_out.km_stored) { 16039b71c2bSRamalingam C ek_pub_km->msg_id = HDCP_2_2_AKE_STORED_KM; 16139b71c2bSRamalingam C *msg_sz = sizeof(struct hdcp2_ake_stored_km); 16239b71c2bSRamalingam C } else { 16339b71c2bSRamalingam C ek_pub_km->msg_id = HDCP_2_2_AKE_NO_STORED_KM; 16439b71c2bSRamalingam C *msg_sz = sizeof(struct hdcp2_ake_no_stored_km); 16539b71c2bSRamalingam C } 16639b71c2bSRamalingam C 16739b71c2bSRamalingam C memcpy(ek_pub_km->e_kpub_km, &verify_rxcert_out.ekm_buff, 16839b71c2bSRamalingam C sizeof(verify_rxcert_out.ekm_buff)); 16939b71c2bSRamalingam C 17039b71c2bSRamalingam C return 0; 17139b71c2bSRamalingam C } 17239b71c2bSRamalingam C 173a7dcbed2SRamalingam C /** 174a7dcbed2SRamalingam C * mei_hdcp_verify_hprime() - Verify AKE_Send_H_prime at ME FW. 175a7dcbed2SRamalingam C * @dev: device corresponding to the mei_cl_device 176a7dcbed2SRamalingam C * @data: Intel HW specific hdcp data 177a7dcbed2SRamalingam C * @rx_hprime: AKE_Send_H_prime msg for ME FW verification 178a7dcbed2SRamalingam C * 179a7dcbed2SRamalingam C * Return: 0 on Success, <0 on Failure 180a7dcbed2SRamalingam C */ 181a7dcbed2SRamalingam C static int 182a7dcbed2SRamalingam C mei_hdcp_verify_hprime(struct device *dev, struct hdcp_port_data *data, 183a7dcbed2SRamalingam C struct hdcp2_ake_send_hprime *rx_hprime) 184a7dcbed2SRamalingam C { 185a7dcbed2SRamalingam C struct wired_cmd_ake_send_hprime_in send_hprime_in = { { 0 } }; 186a7dcbed2SRamalingam C struct wired_cmd_ake_send_hprime_out send_hprime_out = { { 0 } }; 187a7dcbed2SRamalingam C struct mei_cl_device *cldev; 188a7dcbed2SRamalingam C ssize_t byte; 189a7dcbed2SRamalingam C 190a7dcbed2SRamalingam C if (!dev || !data || !rx_hprime) 191a7dcbed2SRamalingam C return -EINVAL; 192a7dcbed2SRamalingam C 193a7dcbed2SRamalingam C cldev = to_mei_cl_device(dev); 194a7dcbed2SRamalingam C 195a7dcbed2SRamalingam C send_hprime_in.header.api_version = HDCP_API_VERSION; 196a7dcbed2SRamalingam C send_hprime_in.header.command_id = WIRED_AKE_SEND_HPRIME; 197a7dcbed2SRamalingam C send_hprime_in.header.status = ME_HDCP_STATUS_SUCCESS; 198a7dcbed2SRamalingam C send_hprime_in.header.buffer_len = WIRED_CMD_BUF_LEN_AKE_SEND_HPRIME_IN; 199a7dcbed2SRamalingam C 200a7dcbed2SRamalingam C send_hprime_in.port.integrated_port_type = data->port_type; 2010dcceb35SRamalingam C send_hprime_in.port.physical_port = (u8)data->fw_ddi; 2022d15cf1bSRamalingam C send_hprime_in.port.attached_transcoder = (u8)data->fw_tc; 203a7dcbed2SRamalingam C 204a7dcbed2SRamalingam C memcpy(send_hprime_in.h_prime, rx_hprime->h_prime, 205a7dcbed2SRamalingam C HDCP_2_2_H_PRIME_LEN); 206a7dcbed2SRamalingam C 207a7dcbed2SRamalingam C byte = mei_cldev_send(cldev, (u8 *)&send_hprime_in, 208a7dcbed2SRamalingam C sizeof(send_hprime_in)); 209a7dcbed2SRamalingam C if (byte < 0) { 210a7dcbed2SRamalingam C dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); 211a7dcbed2SRamalingam C return byte; 212a7dcbed2SRamalingam C } 213a7dcbed2SRamalingam C 214a7dcbed2SRamalingam C byte = mei_cldev_recv(cldev, (u8 *)&send_hprime_out, 215a7dcbed2SRamalingam C sizeof(send_hprime_out)); 216a7dcbed2SRamalingam C if (byte < 0) { 217a7dcbed2SRamalingam C dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); 218a7dcbed2SRamalingam C return byte; 219a7dcbed2SRamalingam C } 220a7dcbed2SRamalingam C 221a7dcbed2SRamalingam C if (send_hprime_out.header.status != ME_HDCP_STATUS_SUCCESS) { 222a7dcbed2SRamalingam C dev_dbg(dev, "ME cmd 0x%08X Failed. Status: 0x%X\n", 223a7dcbed2SRamalingam C WIRED_AKE_SEND_HPRIME, send_hprime_out.header.status); 224a7dcbed2SRamalingam C return -EIO; 225a7dcbed2SRamalingam C } 226a7dcbed2SRamalingam C 227a7dcbed2SRamalingam C return 0; 228a7dcbed2SRamalingam C } 229a7dcbed2SRamalingam C 2306a1a00a3SRamalingam C /** 2316a1a00a3SRamalingam C * mei_hdcp_store_pairing_info() - Store pairing info received at ME FW 2326a1a00a3SRamalingam C * @dev: device corresponding to the mei_cl_device 2336a1a00a3SRamalingam C * @data: Intel HW specific hdcp data 2346a1a00a3SRamalingam C * @pairing_info: AKE_Send_Pairing_Info msg input to ME FW 2356a1a00a3SRamalingam C * 2366a1a00a3SRamalingam C * Return: 0 on Success, <0 on Failure 2376a1a00a3SRamalingam C */ 2386a1a00a3SRamalingam C static int 2396a1a00a3SRamalingam C mei_hdcp_store_pairing_info(struct device *dev, struct hdcp_port_data *data, 2406a1a00a3SRamalingam C struct hdcp2_ake_send_pairing_info *pairing_info) 2416a1a00a3SRamalingam C { 2426a1a00a3SRamalingam C struct wired_cmd_ake_send_pairing_info_in pairing_info_in = { { 0 } }; 2436a1a00a3SRamalingam C struct wired_cmd_ake_send_pairing_info_out pairing_info_out = { { 0 } }; 2446a1a00a3SRamalingam C struct mei_cl_device *cldev; 2456a1a00a3SRamalingam C ssize_t byte; 2466a1a00a3SRamalingam C 2476a1a00a3SRamalingam C if (!dev || !data || !pairing_info) 2486a1a00a3SRamalingam C return -EINVAL; 2496a1a00a3SRamalingam C 2506a1a00a3SRamalingam C cldev = to_mei_cl_device(dev); 2516a1a00a3SRamalingam C 2526a1a00a3SRamalingam C pairing_info_in.header.api_version = HDCP_API_VERSION; 2536a1a00a3SRamalingam C pairing_info_in.header.command_id = WIRED_AKE_SEND_PAIRING_INFO; 2546a1a00a3SRamalingam C pairing_info_in.header.status = ME_HDCP_STATUS_SUCCESS; 2556a1a00a3SRamalingam C pairing_info_in.header.buffer_len = 2566a1a00a3SRamalingam C WIRED_CMD_BUF_LEN_SEND_PAIRING_INFO_IN; 2576a1a00a3SRamalingam C 2586a1a00a3SRamalingam C pairing_info_in.port.integrated_port_type = data->port_type; 2590dcceb35SRamalingam C pairing_info_in.port.physical_port = (u8)data->fw_ddi; 2602d15cf1bSRamalingam C pairing_info_in.port.attached_transcoder = (u8)data->fw_tc; 2616a1a00a3SRamalingam C 2626a1a00a3SRamalingam C memcpy(pairing_info_in.e_kh_km, pairing_info->e_kh_km, 2636a1a00a3SRamalingam C HDCP_2_2_E_KH_KM_LEN); 2646a1a00a3SRamalingam C 2656a1a00a3SRamalingam C byte = mei_cldev_send(cldev, (u8 *)&pairing_info_in, 2666a1a00a3SRamalingam C sizeof(pairing_info_in)); 2676a1a00a3SRamalingam C if (byte < 0) { 2686a1a00a3SRamalingam C dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); 2696a1a00a3SRamalingam C return byte; 2706a1a00a3SRamalingam C } 2716a1a00a3SRamalingam C 2726a1a00a3SRamalingam C byte = mei_cldev_recv(cldev, (u8 *)&pairing_info_out, 2736a1a00a3SRamalingam C sizeof(pairing_info_out)); 2746a1a00a3SRamalingam C if (byte < 0) { 2756a1a00a3SRamalingam C dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); 2766a1a00a3SRamalingam C return byte; 2776a1a00a3SRamalingam C } 2786a1a00a3SRamalingam C 2796a1a00a3SRamalingam C if (pairing_info_out.header.status != ME_HDCP_STATUS_SUCCESS) { 2806a1a00a3SRamalingam C dev_dbg(dev, "ME cmd 0x%08X failed. Status: 0x%X\n", 2816a1a00a3SRamalingam C WIRED_AKE_SEND_PAIRING_INFO, 2826a1a00a3SRamalingam C pairing_info_out.header.status); 2836a1a00a3SRamalingam C return -EIO; 2846a1a00a3SRamalingam C } 2856a1a00a3SRamalingam C 2866a1a00a3SRamalingam C return 0; 2876a1a00a3SRamalingam C } 2886a1a00a3SRamalingam C 289682932f3SRamalingam C /** 290682932f3SRamalingam C * mei_hdcp_initiate_locality_check() - Prepare LC_Init 291682932f3SRamalingam C * @dev: device corresponding to the mei_cl_device 292682932f3SRamalingam C * @data: Intel HW specific hdcp data 293682932f3SRamalingam C * @lc_init_data: LC_Init msg output 294682932f3SRamalingam C * 295682932f3SRamalingam C * Return: 0 on Success, <0 on Failure 296682932f3SRamalingam C */ 297682932f3SRamalingam C static int 298682932f3SRamalingam C mei_hdcp_initiate_locality_check(struct device *dev, 299682932f3SRamalingam C struct hdcp_port_data *data, 300682932f3SRamalingam C struct hdcp2_lc_init *lc_init_data) 301682932f3SRamalingam C { 302682932f3SRamalingam C struct wired_cmd_init_locality_check_in lc_init_in = { { 0 } }; 303682932f3SRamalingam C struct wired_cmd_init_locality_check_out lc_init_out = { { 0 } }; 304682932f3SRamalingam C struct mei_cl_device *cldev; 305682932f3SRamalingam C ssize_t byte; 306682932f3SRamalingam C 307682932f3SRamalingam C if (!dev || !data || !lc_init_data) 308682932f3SRamalingam C return -EINVAL; 309682932f3SRamalingam C 310682932f3SRamalingam C cldev = to_mei_cl_device(dev); 311682932f3SRamalingam C 312682932f3SRamalingam C lc_init_in.header.api_version = HDCP_API_VERSION; 313682932f3SRamalingam C lc_init_in.header.command_id = WIRED_INIT_LOCALITY_CHECK; 314682932f3SRamalingam C lc_init_in.header.status = ME_HDCP_STATUS_SUCCESS; 315682932f3SRamalingam C lc_init_in.header.buffer_len = WIRED_CMD_BUF_LEN_INIT_LOCALITY_CHECK_IN; 316682932f3SRamalingam C 317682932f3SRamalingam C lc_init_in.port.integrated_port_type = data->port_type; 3180dcceb35SRamalingam C lc_init_in.port.physical_port = (u8)data->fw_ddi; 3192d15cf1bSRamalingam C lc_init_in.port.attached_transcoder = (u8)data->fw_tc; 320682932f3SRamalingam C 321682932f3SRamalingam C byte = mei_cldev_send(cldev, (u8 *)&lc_init_in, sizeof(lc_init_in)); 322682932f3SRamalingam C if (byte < 0) { 323682932f3SRamalingam C dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); 324682932f3SRamalingam C return byte; 325682932f3SRamalingam C } 326682932f3SRamalingam C 327682932f3SRamalingam C byte = mei_cldev_recv(cldev, (u8 *)&lc_init_out, sizeof(lc_init_out)); 328682932f3SRamalingam C if (byte < 0) { 329682932f3SRamalingam C dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); 330682932f3SRamalingam C return byte; 331682932f3SRamalingam C } 332682932f3SRamalingam C 333682932f3SRamalingam C if (lc_init_out.header.status != ME_HDCP_STATUS_SUCCESS) { 334682932f3SRamalingam C dev_dbg(dev, "ME cmd 0x%08X Failed. status: 0x%X\n", 335682932f3SRamalingam C WIRED_INIT_LOCALITY_CHECK, lc_init_out.header.status); 336682932f3SRamalingam C return -EIO; 337682932f3SRamalingam C } 338682932f3SRamalingam C 339682932f3SRamalingam C lc_init_data->msg_id = HDCP_2_2_LC_INIT; 340682932f3SRamalingam C memcpy(lc_init_data->r_n, lc_init_out.r_n, HDCP_2_2_RN_LEN); 341682932f3SRamalingam C 342682932f3SRamalingam C return 0; 343682932f3SRamalingam C } 344682932f3SRamalingam C 34545479b67SRamalingam C /** 34645479b67SRamalingam C * mei_hdcp_verify_lprime() - Verify lprime. 34745479b67SRamalingam C * @dev: device corresponding to the mei_cl_device 34845479b67SRamalingam C * @data: Intel HW specific hdcp data 34945479b67SRamalingam C * @rx_lprime: LC_Send_L_prime msg for ME FW verification 35045479b67SRamalingam C * 35145479b67SRamalingam C * Return: 0 on Success, <0 on Failure 35245479b67SRamalingam C */ 35345479b67SRamalingam C static int 35445479b67SRamalingam C mei_hdcp_verify_lprime(struct device *dev, struct hdcp_port_data *data, 35545479b67SRamalingam C struct hdcp2_lc_send_lprime *rx_lprime) 35645479b67SRamalingam C { 35745479b67SRamalingam C struct wired_cmd_validate_locality_in verify_lprime_in = { { 0 } }; 35845479b67SRamalingam C struct wired_cmd_validate_locality_out verify_lprime_out = { { 0 } }; 35945479b67SRamalingam C struct mei_cl_device *cldev; 36045479b67SRamalingam C ssize_t byte; 36145479b67SRamalingam C 36245479b67SRamalingam C if (!dev || !data || !rx_lprime) 36345479b67SRamalingam C return -EINVAL; 36445479b67SRamalingam C 36545479b67SRamalingam C cldev = to_mei_cl_device(dev); 36645479b67SRamalingam C 36745479b67SRamalingam C verify_lprime_in.header.api_version = HDCP_API_VERSION; 36845479b67SRamalingam C verify_lprime_in.header.command_id = WIRED_VALIDATE_LOCALITY; 36945479b67SRamalingam C verify_lprime_in.header.status = ME_HDCP_STATUS_SUCCESS; 37045479b67SRamalingam C verify_lprime_in.header.buffer_len = 37145479b67SRamalingam C WIRED_CMD_BUF_LEN_VALIDATE_LOCALITY_IN; 37245479b67SRamalingam C 37345479b67SRamalingam C verify_lprime_in.port.integrated_port_type = data->port_type; 3740dcceb35SRamalingam C verify_lprime_in.port.physical_port = (u8)data->fw_ddi; 3752d15cf1bSRamalingam C verify_lprime_in.port.attached_transcoder = (u8)data->fw_tc; 37645479b67SRamalingam C 37745479b67SRamalingam C memcpy(verify_lprime_in.l_prime, rx_lprime->l_prime, 37845479b67SRamalingam C HDCP_2_2_L_PRIME_LEN); 37945479b67SRamalingam C 38045479b67SRamalingam C byte = mei_cldev_send(cldev, (u8 *)&verify_lprime_in, 38145479b67SRamalingam C sizeof(verify_lprime_in)); 38245479b67SRamalingam C if (byte < 0) { 38345479b67SRamalingam C dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); 38445479b67SRamalingam C return byte; 38545479b67SRamalingam C } 38645479b67SRamalingam C 38745479b67SRamalingam C byte = mei_cldev_recv(cldev, (u8 *)&verify_lprime_out, 38845479b67SRamalingam C sizeof(verify_lprime_out)); 38945479b67SRamalingam C if (byte < 0) { 39045479b67SRamalingam C dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); 39145479b67SRamalingam C return byte; 39245479b67SRamalingam C } 39345479b67SRamalingam C 39445479b67SRamalingam C if (verify_lprime_out.header.status != ME_HDCP_STATUS_SUCCESS) { 39545479b67SRamalingam C dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n", 39645479b67SRamalingam C WIRED_VALIDATE_LOCALITY, 39745479b67SRamalingam C verify_lprime_out.header.status); 39845479b67SRamalingam C return -EIO; 39945479b67SRamalingam C } 40045479b67SRamalingam C 40145479b67SRamalingam C return 0; 40245479b67SRamalingam C } 40345479b67SRamalingam C 404b491264fSRamalingam C /** 405b491264fSRamalingam C * mei_hdcp_get_session_key() - Prepare SKE_Send_Eks. 406b491264fSRamalingam C * @dev: device corresponding to the mei_cl_device 407b491264fSRamalingam C * @data: Intel HW specific hdcp data 408b491264fSRamalingam C * @ske_data: SKE_Send_Eks msg output from ME FW. 409b491264fSRamalingam C * 410b491264fSRamalingam C * Return: 0 on Success, <0 on Failure 411b491264fSRamalingam C */ 412b491264fSRamalingam C static int mei_hdcp_get_session_key(struct device *dev, 413b491264fSRamalingam C struct hdcp_port_data *data, 414b491264fSRamalingam C struct hdcp2_ske_send_eks *ske_data) 415b491264fSRamalingam C { 416b491264fSRamalingam C struct wired_cmd_get_session_key_in get_skey_in = { { 0 } }; 417b491264fSRamalingam C struct wired_cmd_get_session_key_out get_skey_out = { { 0 } }; 418b491264fSRamalingam C struct mei_cl_device *cldev; 419b491264fSRamalingam C ssize_t byte; 420b491264fSRamalingam C 421b491264fSRamalingam C if (!dev || !data || !ske_data) 422b491264fSRamalingam C return -EINVAL; 423b491264fSRamalingam C 424b491264fSRamalingam C cldev = to_mei_cl_device(dev); 425b491264fSRamalingam C 426b491264fSRamalingam C get_skey_in.header.api_version = HDCP_API_VERSION; 427b491264fSRamalingam C get_skey_in.header.command_id = WIRED_GET_SESSION_KEY; 428b491264fSRamalingam C get_skey_in.header.status = ME_HDCP_STATUS_SUCCESS; 429b491264fSRamalingam C get_skey_in.header.buffer_len = WIRED_CMD_BUF_LEN_GET_SESSION_KEY_IN; 430b491264fSRamalingam C 431b491264fSRamalingam C get_skey_in.port.integrated_port_type = data->port_type; 4320dcceb35SRamalingam C get_skey_in.port.physical_port = (u8)data->fw_ddi; 4332d15cf1bSRamalingam C get_skey_in.port.attached_transcoder = (u8)data->fw_tc; 434b491264fSRamalingam C 435b491264fSRamalingam C byte = mei_cldev_send(cldev, (u8 *)&get_skey_in, sizeof(get_skey_in)); 436b491264fSRamalingam C if (byte < 0) { 437b491264fSRamalingam C dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); 438b491264fSRamalingam C return byte; 439b491264fSRamalingam C } 440b491264fSRamalingam C 441b491264fSRamalingam C byte = mei_cldev_recv(cldev, (u8 *)&get_skey_out, sizeof(get_skey_out)); 442b491264fSRamalingam C 443b491264fSRamalingam C if (byte < 0) { 444b491264fSRamalingam C dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); 445b491264fSRamalingam C return byte; 446b491264fSRamalingam C } 447b491264fSRamalingam C 448b491264fSRamalingam C if (get_skey_out.header.status != ME_HDCP_STATUS_SUCCESS) { 449b491264fSRamalingam C dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n", 450b491264fSRamalingam C WIRED_GET_SESSION_KEY, get_skey_out.header.status); 451b491264fSRamalingam C return -EIO; 452b491264fSRamalingam C } 453b491264fSRamalingam C 454b491264fSRamalingam C ske_data->msg_id = HDCP_2_2_SKE_SEND_EKS; 455b491264fSRamalingam C memcpy(ske_data->e_dkey_ks, get_skey_out.e_dkey_ks, 456b491264fSRamalingam C HDCP_2_2_E_DKEY_KS_LEN); 457b491264fSRamalingam C memcpy(ske_data->riv, get_skey_out.r_iv, HDCP_2_2_RIV_LEN); 458b491264fSRamalingam C 459b491264fSRamalingam C return 0; 460b491264fSRamalingam C } 461b491264fSRamalingam C 462f46ea842SRamalingam C /** 463f46ea842SRamalingam C * mei_hdcp_repeater_check_flow_prepare_ack() - Validate the Downstream topology 464f46ea842SRamalingam C * and prepare rep_ack. 465f46ea842SRamalingam C * @dev: device corresponding to the mei_cl_device 466f46ea842SRamalingam C * @data: Intel HW specific hdcp data 467f46ea842SRamalingam C * @rep_topology: Receiver ID List to be validated 468f46ea842SRamalingam C * @rep_send_ack : repeater ack from ME FW. 469f46ea842SRamalingam C * 470f46ea842SRamalingam C * Return: 0 on Success, <0 on Failure 471f46ea842SRamalingam C */ 472f46ea842SRamalingam C static int 473f46ea842SRamalingam C mei_hdcp_repeater_check_flow_prepare_ack(struct device *dev, 474f46ea842SRamalingam C struct hdcp_port_data *data, 475f46ea842SRamalingam C struct hdcp2_rep_send_receiverid_list 476f46ea842SRamalingam C *rep_topology, 477f46ea842SRamalingam C struct hdcp2_rep_send_ack 478f46ea842SRamalingam C *rep_send_ack) 479f46ea842SRamalingam C { 480f46ea842SRamalingam C struct wired_cmd_verify_repeater_in verify_repeater_in = { { 0 } }; 481f46ea842SRamalingam C struct wired_cmd_verify_repeater_out verify_repeater_out = { { 0 } }; 482f46ea842SRamalingam C struct mei_cl_device *cldev; 483f46ea842SRamalingam C ssize_t byte; 484f46ea842SRamalingam C 485f46ea842SRamalingam C if (!dev || !rep_topology || !rep_send_ack || !data) 486f46ea842SRamalingam C return -EINVAL; 487f46ea842SRamalingam C 488f46ea842SRamalingam C cldev = to_mei_cl_device(dev); 489f46ea842SRamalingam C 490f46ea842SRamalingam C verify_repeater_in.header.api_version = HDCP_API_VERSION; 491f46ea842SRamalingam C verify_repeater_in.header.command_id = WIRED_VERIFY_REPEATER; 492f46ea842SRamalingam C verify_repeater_in.header.status = ME_HDCP_STATUS_SUCCESS; 493f46ea842SRamalingam C verify_repeater_in.header.buffer_len = 494f46ea842SRamalingam C WIRED_CMD_BUF_LEN_VERIFY_REPEATER_IN; 495f46ea842SRamalingam C 496f46ea842SRamalingam C verify_repeater_in.port.integrated_port_type = data->port_type; 4970dcceb35SRamalingam C verify_repeater_in.port.physical_port = (u8)data->fw_ddi; 4982d15cf1bSRamalingam C verify_repeater_in.port.attached_transcoder = (u8)data->fw_tc; 499f46ea842SRamalingam C 500f46ea842SRamalingam C memcpy(verify_repeater_in.rx_info, rep_topology->rx_info, 501f46ea842SRamalingam C HDCP_2_2_RXINFO_LEN); 502f46ea842SRamalingam C memcpy(verify_repeater_in.seq_num_v, rep_topology->seq_num_v, 503f46ea842SRamalingam C HDCP_2_2_SEQ_NUM_LEN); 504f46ea842SRamalingam C memcpy(verify_repeater_in.v_prime, rep_topology->v_prime, 505f46ea842SRamalingam C HDCP_2_2_V_PRIME_HALF_LEN); 506f46ea842SRamalingam C memcpy(verify_repeater_in.receiver_ids, rep_topology->receiver_ids, 507f46ea842SRamalingam C HDCP_2_2_RECEIVER_IDS_MAX_LEN); 508f46ea842SRamalingam C 509f46ea842SRamalingam C byte = mei_cldev_send(cldev, (u8 *)&verify_repeater_in, 510f46ea842SRamalingam C sizeof(verify_repeater_in)); 511f46ea842SRamalingam C if (byte < 0) { 512f46ea842SRamalingam C dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); 513f46ea842SRamalingam C return byte; 514f46ea842SRamalingam C } 515f46ea842SRamalingam C 516f46ea842SRamalingam C byte = mei_cldev_recv(cldev, (u8 *)&verify_repeater_out, 517f46ea842SRamalingam C sizeof(verify_repeater_out)); 518f46ea842SRamalingam C if (byte < 0) { 519f46ea842SRamalingam C dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); 520f46ea842SRamalingam C return byte; 521f46ea842SRamalingam C } 522f46ea842SRamalingam C 523f46ea842SRamalingam C if (verify_repeater_out.header.status != ME_HDCP_STATUS_SUCCESS) { 524f46ea842SRamalingam C dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n", 525f46ea842SRamalingam C WIRED_VERIFY_REPEATER, 526f46ea842SRamalingam C verify_repeater_out.header.status); 527f46ea842SRamalingam C return -EIO; 528f46ea842SRamalingam C } 529f46ea842SRamalingam C 530f46ea842SRamalingam C memcpy(rep_send_ack->v, verify_repeater_out.v, 531f46ea842SRamalingam C HDCP_2_2_V_PRIME_HALF_LEN); 532f46ea842SRamalingam C rep_send_ack->msg_id = HDCP_2_2_REP_SEND_ACK; 533f46ea842SRamalingam C 534f46ea842SRamalingam C return 0; 535f46ea842SRamalingam C } 536f46ea842SRamalingam C 5370a1af1b5SRamalingam C /** 5380a1af1b5SRamalingam C * mei_hdcp_verify_mprime() - Verify mprime. 5390a1af1b5SRamalingam C * @dev: device corresponding to the mei_cl_device 5400a1af1b5SRamalingam C * @data: Intel HW specific hdcp data 5410a1af1b5SRamalingam C * @stream_ready: RepeaterAuth_Stream_Ready msg for ME FW verification. 5420a1af1b5SRamalingam C * 5430a1af1b5SRamalingam C * Return: 0 on Success, <0 on Failure 5440a1af1b5SRamalingam C */ 5450a1af1b5SRamalingam C static int mei_hdcp_verify_mprime(struct device *dev, 5460a1af1b5SRamalingam C struct hdcp_port_data *data, 5470a1af1b5SRamalingam C struct hdcp2_rep_stream_ready *stream_ready) 5480a1af1b5SRamalingam C { 54951072c0fSTomas Winkler struct wired_cmd_repeater_auth_stream_req_in *verify_mprime_in; 5500a1af1b5SRamalingam C struct wired_cmd_repeater_auth_stream_req_out 5510a1af1b5SRamalingam C verify_mprime_out = { { 0 } }; 5520a1af1b5SRamalingam C struct mei_cl_device *cldev; 5530a1af1b5SRamalingam C ssize_t byte; 55451072c0fSTomas Winkler size_t cmd_size; 5550a1af1b5SRamalingam C 5560a1af1b5SRamalingam C if (!dev || !stream_ready || !data) 5570a1af1b5SRamalingam C return -EINVAL; 5580a1af1b5SRamalingam C 5590a1af1b5SRamalingam C cldev = to_mei_cl_device(dev); 5600a1af1b5SRamalingam C 56151072c0fSTomas Winkler cmd_size = struct_size(verify_mprime_in, streams, data->k); 56251072c0fSTomas Winkler if (cmd_size == SIZE_MAX) 56351072c0fSTomas Winkler return -EINVAL; 56451072c0fSTomas Winkler 56551072c0fSTomas Winkler verify_mprime_in = kzalloc(cmd_size, GFP_KERNEL); 56651072c0fSTomas Winkler if (!verify_mprime_in) 56751072c0fSTomas Winkler return -ENOMEM; 56851072c0fSTomas Winkler 56951072c0fSTomas Winkler verify_mprime_in->header.api_version = HDCP_API_VERSION; 57051072c0fSTomas Winkler verify_mprime_in->header.command_id = WIRED_REPEATER_AUTH_STREAM_REQ; 57151072c0fSTomas Winkler verify_mprime_in->header.status = ME_HDCP_STATUS_SUCCESS; 57251072c0fSTomas Winkler verify_mprime_in->header.buffer_len = 5730a1af1b5SRamalingam C WIRED_CMD_BUF_LEN_REPEATER_AUTH_STREAM_REQ_MIN_IN; 5740a1af1b5SRamalingam C 57551072c0fSTomas Winkler verify_mprime_in->port.integrated_port_type = data->port_type; 57651072c0fSTomas Winkler verify_mprime_in->port.physical_port = (u8)data->fw_ddi; 57751072c0fSTomas Winkler verify_mprime_in->port.attached_transcoder = (u8)data->fw_tc; 5780a1af1b5SRamalingam C 57951072c0fSTomas Winkler memcpy(verify_mprime_in->m_prime, stream_ready->m_prime, HDCP_2_2_MPRIME_LEN); 58051072c0fSTomas Winkler drm_hdcp_cpu_to_be24(verify_mprime_in->seq_num_m, data->seq_num_m); 58151072c0fSTomas Winkler 58251072c0fSTomas Winkler memcpy(verify_mprime_in->streams, data->streams, 583c56967d6SGustavo A. R. Silva array_size(data->k, sizeof(*data->streams))); 5840a1af1b5SRamalingam C 58551072c0fSTomas Winkler verify_mprime_in->k = cpu_to_be16(data->k); 5860a1af1b5SRamalingam C 58751072c0fSTomas Winkler byte = mei_cldev_send(cldev, (u8 *)verify_mprime_in, cmd_size); 58851072c0fSTomas Winkler kfree(verify_mprime_in); 5890a1af1b5SRamalingam C if (byte < 0) { 5900a1af1b5SRamalingam C dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); 5910a1af1b5SRamalingam C return byte; 5920a1af1b5SRamalingam C } 5930a1af1b5SRamalingam C 5940a1af1b5SRamalingam C byte = mei_cldev_recv(cldev, (u8 *)&verify_mprime_out, 5950a1af1b5SRamalingam C sizeof(verify_mprime_out)); 5960a1af1b5SRamalingam C if (byte < 0) { 5970a1af1b5SRamalingam C dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); 5980a1af1b5SRamalingam C return byte; 5990a1af1b5SRamalingam C } 6000a1af1b5SRamalingam C 6010a1af1b5SRamalingam C if (verify_mprime_out.header.status != ME_HDCP_STATUS_SUCCESS) { 6020a1af1b5SRamalingam C dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n", 6030a1af1b5SRamalingam C WIRED_REPEATER_AUTH_STREAM_REQ, 6040a1af1b5SRamalingam C verify_mprime_out.header.status); 6050a1af1b5SRamalingam C return -EIO; 6060a1af1b5SRamalingam C } 6070a1af1b5SRamalingam C 6080a1af1b5SRamalingam C return 0; 6090a1af1b5SRamalingam C } 6100a1af1b5SRamalingam C 6115e234911SRamalingam C /** 6125e234911SRamalingam C * mei_hdcp_enable_authentication() - Mark a port as authenticated 6135e234911SRamalingam C * through ME FW 6145e234911SRamalingam C * @dev: device corresponding to the mei_cl_device 6155e234911SRamalingam C * @data: Intel HW specific hdcp data 6165e234911SRamalingam C * 6175e234911SRamalingam C * Return: 0 on Success, <0 on Failure 6185e234911SRamalingam C */ 6195e234911SRamalingam C static int mei_hdcp_enable_authentication(struct device *dev, 6205e234911SRamalingam C struct hdcp_port_data *data) 6215e234911SRamalingam C { 6225e234911SRamalingam C struct wired_cmd_enable_auth_in enable_auth_in = { { 0 } }; 6235e234911SRamalingam C struct wired_cmd_enable_auth_out enable_auth_out = { { 0 } }; 6245e234911SRamalingam C struct mei_cl_device *cldev; 6255e234911SRamalingam C ssize_t byte; 6265e234911SRamalingam C 6275e234911SRamalingam C if (!dev || !data) 6285e234911SRamalingam C return -EINVAL; 6295e234911SRamalingam C 6305e234911SRamalingam C cldev = to_mei_cl_device(dev); 6315e234911SRamalingam C 6325e234911SRamalingam C enable_auth_in.header.api_version = HDCP_API_VERSION; 6335e234911SRamalingam C enable_auth_in.header.command_id = WIRED_ENABLE_AUTH; 6345e234911SRamalingam C enable_auth_in.header.status = ME_HDCP_STATUS_SUCCESS; 6355e234911SRamalingam C enable_auth_in.header.buffer_len = WIRED_CMD_BUF_LEN_ENABLE_AUTH_IN; 6365e234911SRamalingam C 6375e234911SRamalingam C enable_auth_in.port.integrated_port_type = data->port_type; 6380dcceb35SRamalingam C enable_auth_in.port.physical_port = (u8)data->fw_ddi; 6392d15cf1bSRamalingam C enable_auth_in.port.attached_transcoder = (u8)data->fw_tc; 6405e234911SRamalingam C enable_auth_in.stream_type = data->streams[0].stream_type; 6415e234911SRamalingam C 6425e234911SRamalingam C byte = mei_cldev_send(cldev, (u8 *)&enable_auth_in, 6435e234911SRamalingam C sizeof(enable_auth_in)); 6445e234911SRamalingam C if (byte < 0) { 6455e234911SRamalingam C dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); 6465e234911SRamalingam C return byte; 6475e234911SRamalingam C } 6485e234911SRamalingam C 6495e234911SRamalingam C byte = mei_cldev_recv(cldev, (u8 *)&enable_auth_out, 6505e234911SRamalingam C sizeof(enable_auth_out)); 6515e234911SRamalingam C if (byte < 0) { 6525e234911SRamalingam C dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); 6535e234911SRamalingam C return byte; 6545e234911SRamalingam C } 6555e234911SRamalingam C 6565e234911SRamalingam C if (enable_auth_out.header.status != ME_HDCP_STATUS_SUCCESS) { 6575e234911SRamalingam C dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n", 6585e234911SRamalingam C WIRED_ENABLE_AUTH, enable_auth_out.header.status); 6595e234911SRamalingam C return -EIO; 6605e234911SRamalingam C } 6615e234911SRamalingam C 6625e234911SRamalingam C return 0; 6635e234911SRamalingam C } 6645e234911SRamalingam C 66562c2b322SRamalingam C /** 66662c2b322SRamalingam C * mei_hdcp_close_session() - Close the Wired HDCP Tx session of ME FW per port. 66762c2b322SRamalingam C * This also disables the authenticated state of the port. 66862c2b322SRamalingam C * @dev: device corresponding to the mei_cl_device 66962c2b322SRamalingam C * @data: Intel HW specific hdcp data 67062c2b322SRamalingam C * 67162c2b322SRamalingam C * Return: 0 on Success, <0 on Failure 67262c2b322SRamalingam C */ 67362c2b322SRamalingam C static int 67462c2b322SRamalingam C mei_hdcp_close_session(struct device *dev, struct hdcp_port_data *data) 67562c2b322SRamalingam C { 67662c2b322SRamalingam C struct wired_cmd_close_session_in session_close_in = { { 0 } }; 67762c2b322SRamalingam C struct wired_cmd_close_session_out session_close_out = { { 0 } }; 67862c2b322SRamalingam C struct mei_cl_device *cldev; 67962c2b322SRamalingam C ssize_t byte; 68062c2b322SRamalingam C 68162c2b322SRamalingam C if (!dev || !data) 68262c2b322SRamalingam C return -EINVAL; 68362c2b322SRamalingam C 68462c2b322SRamalingam C cldev = to_mei_cl_device(dev); 68562c2b322SRamalingam C 68662c2b322SRamalingam C session_close_in.header.api_version = HDCP_API_VERSION; 68762c2b322SRamalingam C session_close_in.header.command_id = WIRED_CLOSE_SESSION; 68862c2b322SRamalingam C session_close_in.header.status = ME_HDCP_STATUS_SUCCESS; 68962c2b322SRamalingam C session_close_in.header.buffer_len = 69062c2b322SRamalingam C WIRED_CMD_BUF_LEN_CLOSE_SESSION_IN; 69162c2b322SRamalingam C 69262c2b322SRamalingam C session_close_in.port.integrated_port_type = data->port_type; 6930dcceb35SRamalingam C session_close_in.port.physical_port = (u8)data->fw_ddi; 6942d15cf1bSRamalingam C session_close_in.port.attached_transcoder = (u8)data->fw_tc; 69562c2b322SRamalingam C 69662c2b322SRamalingam C byte = mei_cldev_send(cldev, (u8 *)&session_close_in, 69762c2b322SRamalingam C sizeof(session_close_in)); 69862c2b322SRamalingam C if (byte < 0) { 69962c2b322SRamalingam C dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); 70062c2b322SRamalingam C return byte; 70162c2b322SRamalingam C } 70262c2b322SRamalingam C 70362c2b322SRamalingam C byte = mei_cldev_recv(cldev, (u8 *)&session_close_out, 70462c2b322SRamalingam C sizeof(session_close_out)); 70562c2b322SRamalingam C if (byte < 0) { 70662c2b322SRamalingam C dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); 70762c2b322SRamalingam C return byte; 70862c2b322SRamalingam C } 70962c2b322SRamalingam C 71062c2b322SRamalingam C if (session_close_out.header.status != ME_HDCP_STATUS_SUCCESS) { 71162c2b322SRamalingam C dev_dbg(dev, "Session Close Failed. status: 0x%X\n", 71262c2b322SRamalingam C session_close_out.header.status); 71362c2b322SRamalingam C return -EIO; 71462c2b322SRamalingam C } 71562c2b322SRamalingam C 71662c2b322SRamalingam C return 0; 71762c2b322SRamalingam C } 71862c2b322SRamalingam C 719fa301ad9SRamalingam C static const struct i915_hdcp_component_ops mei_hdcp_ops = { 720a37fb1e4SRamalingam C .owner = THIS_MODULE, 721a37fb1e4SRamalingam C .initiate_hdcp2_session = mei_hdcp_initiate_session, 72239b71c2bSRamalingam C .verify_receiver_cert_prepare_km = 72339b71c2bSRamalingam C mei_hdcp_verify_receiver_cert_prepare_km, 724a7dcbed2SRamalingam C .verify_hprime = mei_hdcp_verify_hprime, 7256a1a00a3SRamalingam C .store_pairing_info = mei_hdcp_store_pairing_info, 726682932f3SRamalingam C .initiate_locality_check = mei_hdcp_initiate_locality_check, 72745479b67SRamalingam C .verify_lprime = mei_hdcp_verify_lprime, 728b491264fSRamalingam C .get_session_key = mei_hdcp_get_session_key, 729f46ea842SRamalingam C .repeater_check_flow_prepare_ack = 730f46ea842SRamalingam C mei_hdcp_repeater_check_flow_prepare_ack, 7310a1af1b5SRamalingam C .verify_mprime = mei_hdcp_verify_mprime, 7325e234911SRamalingam C .enable_hdcp_authentication = mei_hdcp_enable_authentication, 73362c2b322SRamalingam C .close_hdcp_session = mei_hdcp_close_session, 734a37fb1e4SRamalingam C }; 73564e9bbddSRamalingam C 736fa301ad9SRamalingam C static int mei_component_master_bind(struct device *dev) 737fa301ad9SRamalingam C { 738fa301ad9SRamalingam C struct mei_cl_device *cldev = to_mei_cl_device(dev); 739fa301ad9SRamalingam C struct i915_hdcp_comp_master *comp_master = 740fa301ad9SRamalingam C mei_cldev_get_drvdata(cldev); 741fa301ad9SRamalingam C int ret; 742fa301ad9SRamalingam C 743fa301ad9SRamalingam C dev_dbg(dev, "%s\n", __func__); 744fa301ad9SRamalingam C comp_master->ops = &mei_hdcp_ops; 745fa301ad9SRamalingam C comp_master->mei_dev = dev; 746fa301ad9SRamalingam C ret = component_bind_all(dev, comp_master); 747fa301ad9SRamalingam C if (ret < 0) 748fa301ad9SRamalingam C return ret; 749fa301ad9SRamalingam C 750fa301ad9SRamalingam C return 0; 751fa301ad9SRamalingam C } 752fa301ad9SRamalingam C 753fa301ad9SRamalingam C static void mei_component_master_unbind(struct device *dev) 754fa301ad9SRamalingam C { 755fa301ad9SRamalingam C struct mei_cl_device *cldev = to_mei_cl_device(dev); 756fa301ad9SRamalingam C struct i915_hdcp_comp_master *comp_master = 757fa301ad9SRamalingam C mei_cldev_get_drvdata(cldev); 758fa301ad9SRamalingam C 759fa301ad9SRamalingam C dev_dbg(dev, "%s\n", __func__); 760fa301ad9SRamalingam C component_unbind_all(dev, comp_master); 761fa301ad9SRamalingam C } 762fa301ad9SRamalingam C 763fa301ad9SRamalingam C static const struct component_master_ops mei_component_master_ops = { 764fa301ad9SRamalingam C .bind = mei_component_master_bind, 765fa301ad9SRamalingam C .unbind = mei_component_master_unbind, 766fa301ad9SRamalingam C }; 767fa301ad9SRamalingam C 7681e8d19d9STomas Winkler /** 7691e8d19d9STomas Winkler * mei_hdcp_component_match - compare function for matching mei hdcp. 7701e8d19d9STomas Winkler * 7711e8d19d9STomas Winkler * The function checks if the driver is i915, the subcomponent is HDCP 7721e8d19d9STomas Winkler * and the grand parent of hdcp and the parent of i915 are the same 7731e8d19d9STomas Winkler * PCH device. 7741e8d19d9STomas Winkler * 7751e8d19d9STomas Winkler * @dev: master device 7761e8d19d9STomas Winkler * @subcomponent: subcomponent to match (I915_COMPONENT_HDCP) 7771e8d19d9STomas Winkler * @data: compare data (mei hdcp device) 7781e8d19d9STomas Winkler * 7791e8d19d9STomas Winkler * Return: 7801e8d19d9STomas Winkler * * 1 - if components match 7811e8d19d9STomas Winkler * * 0 - otherwise 7821e8d19d9STomas Winkler */ 783fa301ad9SRamalingam C static int mei_hdcp_component_match(struct device *dev, int subcomponent, 784fa301ad9SRamalingam C void *data) 785fa301ad9SRamalingam C { 7861e8d19d9STomas Winkler struct device *base = data; 7871e8d19d9STomas Winkler 7881e8d19d9STomas Winkler if (strcmp(dev->driver->name, "i915") || 7891e8d19d9STomas Winkler subcomponent != I915_COMPONENT_HDCP) 7901e8d19d9STomas Winkler return 0; 7911e8d19d9STomas Winkler 7921e8d19d9STomas Winkler base = base->parent; 7931e8d19d9STomas Winkler if (!base) 7941e8d19d9STomas Winkler return 0; 7951e8d19d9STomas Winkler 7961e8d19d9STomas Winkler base = base->parent; 7971e8d19d9STomas Winkler dev = dev->parent; 7981e8d19d9STomas Winkler 7991e8d19d9STomas Winkler return (base && dev && dev == base); 800fa301ad9SRamalingam C } 801fa301ad9SRamalingam C 80264e9bbddSRamalingam C static int mei_hdcp_probe(struct mei_cl_device *cldev, 80364e9bbddSRamalingam C const struct mei_cl_device_id *id) 80464e9bbddSRamalingam C { 805fa301ad9SRamalingam C struct i915_hdcp_comp_master *comp_master; 806fa301ad9SRamalingam C struct component_match *master_match; 80764e9bbddSRamalingam C int ret; 80864e9bbddSRamalingam C 80964e9bbddSRamalingam C ret = mei_cldev_enable(cldev); 810fa301ad9SRamalingam C if (ret < 0) { 81164e9bbddSRamalingam C dev_err(&cldev->dev, "mei_cldev_enable Failed. %d\n", ret); 812fa301ad9SRamalingam C goto enable_err_exit; 813fa301ad9SRamalingam C } 81464e9bbddSRamalingam C 815fa301ad9SRamalingam C comp_master = kzalloc(sizeof(*comp_master), GFP_KERNEL); 816fa301ad9SRamalingam C if (!comp_master) { 817fa301ad9SRamalingam C ret = -ENOMEM; 818fa301ad9SRamalingam C goto err_exit; 819fa301ad9SRamalingam C } 820fa301ad9SRamalingam C 821fa301ad9SRamalingam C master_match = NULL; 822fa301ad9SRamalingam C component_match_add_typed(&cldev->dev, &master_match, 8231e8d19d9STomas Winkler mei_hdcp_component_match, &cldev->dev); 824fa301ad9SRamalingam C if (IS_ERR_OR_NULL(master_match)) { 825fa301ad9SRamalingam C ret = -ENOMEM; 826fa301ad9SRamalingam C goto err_exit; 827fa301ad9SRamalingam C } 828fa301ad9SRamalingam C 829fa301ad9SRamalingam C mei_cldev_set_drvdata(cldev, comp_master); 830fa301ad9SRamalingam C ret = component_master_add_with_match(&cldev->dev, 831fa301ad9SRamalingam C &mei_component_master_ops, 832fa301ad9SRamalingam C master_match); 833fa301ad9SRamalingam C if (ret < 0) { 834fa301ad9SRamalingam C dev_err(&cldev->dev, "Master comp add failed %d\n", ret); 835fa301ad9SRamalingam C goto err_exit; 836fa301ad9SRamalingam C } 837fa301ad9SRamalingam C 838fa301ad9SRamalingam C return 0; 839fa301ad9SRamalingam C 840fa301ad9SRamalingam C err_exit: 841fa301ad9SRamalingam C mei_cldev_set_drvdata(cldev, NULL); 842fa301ad9SRamalingam C kfree(comp_master); 843fa301ad9SRamalingam C mei_cldev_disable(cldev); 844fa301ad9SRamalingam C enable_err_exit: 84564e9bbddSRamalingam C return ret; 84664e9bbddSRamalingam C } 84764e9bbddSRamalingam C 848*bf5c9cc8SUwe Kleine-König static void mei_hdcp_remove(struct mei_cl_device *cldev) 84964e9bbddSRamalingam C { 850fa301ad9SRamalingam C struct i915_hdcp_comp_master *comp_master = 851fa301ad9SRamalingam C mei_cldev_get_drvdata(cldev); 852*bf5c9cc8SUwe Kleine-König int ret; 853fa301ad9SRamalingam C 854fa301ad9SRamalingam C component_master_del(&cldev->dev, &mei_component_master_ops); 855fa301ad9SRamalingam C kfree(comp_master); 856fa301ad9SRamalingam C mei_cldev_set_drvdata(cldev, NULL); 857fa301ad9SRamalingam C 858*bf5c9cc8SUwe Kleine-König ret = mei_cldev_disable(cldev); 859*bf5c9cc8SUwe Kleine-König if (ret) 860*bf5c9cc8SUwe Kleine-König dev_warn(&cldev->dev, "mei_cldev_disable() failed\n"); 86164e9bbddSRamalingam C } 86264e9bbddSRamalingam C 86364e9bbddSRamalingam C #define MEI_UUID_HDCP GUID_INIT(0xB638AB7E, 0x94E2, 0x4EA2, 0xA5, \ 86464e9bbddSRamalingam C 0x52, 0xD1, 0xC5, 0x4B, 0x62, 0x7F, 0x04) 86564e9bbddSRamalingam C 86650bf73bdSRikard Falkeborn static const struct mei_cl_device_id mei_hdcp_tbl[] = { 86764e9bbddSRamalingam C { .uuid = MEI_UUID_HDCP, .version = MEI_CL_VERSION_ANY }, 86864e9bbddSRamalingam C { } 86964e9bbddSRamalingam C }; 87064e9bbddSRamalingam C MODULE_DEVICE_TABLE(mei, mei_hdcp_tbl); 87164e9bbddSRamalingam C 87264e9bbddSRamalingam C static struct mei_cl_driver mei_hdcp_driver = { 87364e9bbddSRamalingam C .id_table = mei_hdcp_tbl, 87464e9bbddSRamalingam C .name = KBUILD_MODNAME, 87564e9bbddSRamalingam C .probe = mei_hdcp_probe, 87664e9bbddSRamalingam C .remove = mei_hdcp_remove, 87764e9bbddSRamalingam C }; 87864e9bbddSRamalingam C 87964e9bbddSRamalingam C module_mei_cl_driver(mei_hdcp_driver); 88064e9bbddSRamalingam C 88164e9bbddSRamalingam C MODULE_AUTHOR("Intel Corporation"); 88264e9bbddSRamalingam C MODULE_LICENSE("GPL"); 88364e9bbddSRamalingam C MODULE_DESCRIPTION("MEI HDCP"); 884