164e9bbddSRamalingam C // SPDX-License-Identifier: (GPL-2.0) 264e9bbddSRamalingam C /* 364e9bbddSRamalingam C * Copyright © 2019 Intel Corporation 464e9bbddSRamalingam C * 564e9bbddSRamalingam C * 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 * 1464e9bbddSRamalingam C * This is a client driver to the mei_bus to make the HDCP2.2 services of 1564e9bbddSRamalingam C * ME FW available for the interested consumers like I915. 1664e9bbddSRamalingam C * 1764e9bbddSRamalingam C * This module will act as a translation layer between HDCP protocol 1864e9bbddSRamalingam C * implementor(I915) and ME FW by translating HDCP2.2 authentication 1964e9bbddSRamalingam C * messages to ME FW command payloads and vice versa. 2064e9bbddSRamalingam C */ 2164e9bbddSRamalingam C 2264e9bbddSRamalingam C #include <linux/module.h> 2364e9bbddSRamalingam C #include <linux/slab.h> 2464e9bbddSRamalingam C #include <linux/uuid.h> 2564e9bbddSRamalingam C #include <linux/mei_cl_bus.h> 26a37fb1e4SRamalingam C #include <drm/drm_connector.h> 27a37fb1e4SRamalingam C #include <drm/i915_component.h> 28a37fb1e4SRamalingam C #include <drm/i915_mei_hdcp_interface.h> 29a37fb1e4SRamalingam C 30a37fb1e4SRamalingam C #include "mei_hdcp.h" 31a37fb1e4SRamalingam C 32a37fb1e4SRamalingam C static inline u8 mei_get_ddi_index(enum port port) 33a37fb1e4SRamalingam C { 34a37fb1e4SRamalingam C switch (port) { 35a37fb1e4SRamalingam C case PORT_A: 36a37fb1e4SRamalingam C return MEI_DDI_A; 37a37fb1e4SRamalingam C case PORT_B ... PORT_F: 38a37fb1e4SRamalingam C return (u8)port; 39a37fb1e4SRamalingam C default: 40a37fb1e4SRamalingam C return MEI_DDI_INVALID_PORT; 41a37fb1e4SRamalingam C } 42a37fb1e4SRamalingam C } 43a37fb1e4SRamalingam C 44a37fb1e4SRamalingam C /** 45a37fb1e4SRamalingam C * mei_hdcp_initiate_session() - Initiate a Wired HDCP2.2 Tx Session in ME FW 46a37fb1e4SRamalingam C * @dev: device corresponding to the mei_cl_device 47a37fb1e4SRamalingam C * @data: Intel HW specific hdcp data 48a37fb1e4SRamalingam C * @ake_data: AKE_Init msg output. 49a37fb1e4SRamalingam C * 50a37fb1e4SRamalingam C * Return: 0 on Success, <0 on Failure. 51a37fb1e4SRamalingam C */ 52a37fb1e4SRamalingam C static int 53a37fb1e4SRamalingam C mei_hdcp_initiate_session(struct device *dev, struct hdcp_port_data *data, 54a37fb1e4SRamalingam C struct hdcp2_ake_init *ake_data) 55a37fb1e4SRamalingam C { 56a37fb1e4SRamalingam C struct wired_cmd_initiate_hdcp2_session_in session_init_in = { { 0 } }; 57a37fb1e4SRamalingam C struct wired_cmd_initiate_hdcp2_session_out 58a37fb1e4SRamalingam C session_init_out = { { 0 } }; 59a37fb1e4SRamalingam C struct mei_cl_device *cldev; 60a37fb1e4SRamalingam C ssize_t byte; 61a37fb1e4SRamalingam C 62a37fb1e4SRamalingam C if (!dev || !data || !ake_data) 63a37fb1e4SRamalingam C return -EINVAL; 64a37fb1e4SRamalingam C 65a37fb1e4SRamalingam C cldev = to_mei_cl_device(dev); 66a37fb1e4SRamalingam C 67a37fb1e4SRamalingam C session_init_in.header.api_version = HDCP_API_VERSION; 68a37fb1e4SRamalingam C session_init_in.header.command_id = WIRED_INITIATE_HDCP2_SESSION; 69a37fb1e4SRamalingam C session_init_in.header.status = ME_HDCP_STATUS_SUCCESS; 70a37fb1e4SRamalingam C session_init_in.header.buffer_len = 71a37fb1e4SRamalingam C WIRED_CMD_BUF_LEN_INITIATE_HDCP2_SESSION_IN; 72a37fb1e4SRamalingam C 73a37fb1e4SRamalingam C session_init_in.port.integrated_port_type = data->port_type; 74a37fb1e4SRamalingam C session_init_in.port.physical_port = mei_get_ddi_index(data->port); 75a37fb1e4SRamalingam C session_init_in.protocol = data->protocol; 76a37fb1e4SRamalingam C 77a37fb1e4SRamalingam C byte = mei_cldev_send(cldev, (u8 *)&session_init_in, 78a37fb1e4SRamalingam C sizeof(session_init_in)); 79a37fb1e4SRamalingam C if (byte < 0) { 80a37fb1e4SRamalingam C dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); 81a37fb1e4SRamalingam C return byte; 82a37fb1e4SRamalingam C } 83a37fb1e4SRamalingam C 84a37fb1e4SRamalingam C byte = mei_cldev_recv(cldev, (u8 *)&session_init_out, 85a37fb1e4SRamalingam C sizeof(session_init_out)); 86a37fb1e4SRamalingam C if (byte < 0) { 87a37fb1e4SRamalingam C dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); 88a37fb1e4SRamalingam C return byte; 89a37fb1e4SRamalingam C } 90a37fb1e4SRamalingam C 91a37fb1e4SRamalingam C if (session_init_out.header.status != ME_HDCP_STATUS_SUCCESS) { 92a37fb1e4SRamalingam C dev_dbg(dev, "ME cmd 0x%08X Failed. Status: 0x%X\n", 93a37fb1e4SRamalingam C WIRED_INITIATE_HDCP2_SESSION, 94a37fb1e4SRamalingam C session_init_out.header.status); 95a37fb1e4SRamalingam C return -EIO; 96a37fb1e4SRamalingam C } 97a37fb1e4SRamalingam C 98a37fb1e4SRamalingam C ake_data->msg_id = HDCP_2_2_AKE_INIT; 99a37fb1e4SRamalingam C ake_data->tx_caps = session_init_out.tx_caps; 100a37fb1e4SRamalingam C memcpy(ake_data->r_tx, session_init_out.r_tx, HDCP_2_2_RTX_LEN); 101a37fb1e4SRamalingam C 102a37fb1e4SRamalingam C return 0; 103a37fb1e4SRamalingam C } 104a37fb1e4SRamalingam C 105*39b71c2bSRamalingam C /** 106*39b71c2bSRamalingam C * mei_hdcp_verify_receiver_cert_prepare_km() - Verify the Receiver Certificate 107*39b71c2bSRamalingam C * AKE_Send_Cert and prepare AKE_Stored_Km/AKE_No_Stored_Km 108*39b71c2bSRamalingam C * @dev: device corresponding to the mei_cl_device 109*39b71c2bSRamalingam C * @data: Intel HW specific hdcp data 110*39b71c2bSRamalingam C * @rx_cert: AKE_Send_Cert for verification 111*39b71c2bSRamalingam C * @km_stored: Pairing status flag output 112*39b71c2bSRamalingam C * @ek_pub_km: AKE_Stored_Km/AKE_No_Stored_Km output msg 113*39b71c2bSRamalingam C * @msg_sz : size of AKE_XXXXX_Km output msg 114*39b71c2bSRamalingam C * 115*39b71c2bSRamalingam C * Return: 0 on Success, <0 on Failure 116*39b71c2bSRamalingam C */ 117*39b71c2bSRamalingam C static int 118*39b71c2bSRamalingam C mei_hdcp_verify_receiver_cert_prepare_km(struct device *dev, 119*39b71c2bSRamalingam C struct hdcp_port_data *data, 120*39b71c2bSRamalingam C struct hdcp2_ake_send_cert *rx_cert, 121*39b71c2bSRamalingam C bool *km_stored, 122*39b71c2bSRamalingam C struct hdcp2_ake_no_stored_km 123*39b71c2bSRamalingam C *ek_pub_km, 124*39b71c2bSRamalingam C size_t *msg_sz) 125*39b71c2bSRamalingam C { 126*39b71c2bSRamalingam C struct wired_cmd_verify_receiver_cert_in verify_rxcert_in = { { 0 } }; 127*39b71c2bSRamalingam C struct wired_cmd_verify_receiver_cert_out verify_rxcert_out = { { 0 } }; 128*39b71c2bSRamalingam C struct mei_cl_device *cldev; 129*39b71c2bSRamalingam C ssize_t byte; 130*39b71c2bSRamalingam C 131*39b71c2bSRamalingam C if (!dev || !data || !rx_cert || !km_stored || !ek_pub_km || !msg_sz) 132*39b71c2bSRamalingam C return -EINVAL; 133*39b71c2bSRamalingam C 134*39b71c2bSRamalingam C cldev = to_mei_cl_device(dev); 135*39b71c2bSRamalingam C 136*39b71c2bSRamalingam C verify_rxcert_in.header.api_version = HDCP_API_VERSION; 137*39b71c2bSRamalingam C verify_rxcert_in.header.command_id = WIRED_VERIFY_RECEIVER_CERT; 138*39b71c2bSRamalingam C verify_rxcert_in.header.status = ME_HDCP_STATUS_SUCCESS; 139*39b71c2bSRamalingam C verify_rxcert_in.header.buffer_len = 140*39b71c2bSRamalingam C WIRED_CMD_BUF_LEN_VERIFY_RECEIVER_CERT_IN; 141*39b71c2bSRamalingam C 142*39b71c2bSRamalingam C verify_rxcert_in.port.integrated_port_type = data->port_type; 143*39b71c2bSRamalingam C verify_rxcert_in.port.physical_port = mei_get_ddi_index(data->port); 144*39b71c2bSRamalingam C 145*39b71c2bSRamalingam C verify_rxcert_in.cert_rx = rx_cert->cert_rx; 146*39b71c2bSRamalingam C memcpy(verify_rxcert_in.r_rx, &rx_cert->r_rx, HDCP_2_2_RRX_LEN); 147*39b71c2bSRamalingam C memcpy(verify_rxcert_in.rx_caps, rx_cert->rx_caps, HDCP_2_2_RXCAPS_LEN); 148*39b71c2bSRamalingam C 149*39b71c2bSRamalingam C byte = mei_cldev_send(cldev, (u8 *)&verify_rxcert_in, 150*39b71c2bSRamalingam C sizeof(verify_rxcert_in)); 151*39b71c2bSRamalingam C if (byte < 0) { 152*39b71c2bSRamalingam C dev_dbg(dev, "mei_cldev_send failed: %zd\n", byte); 153*39b71c2bSRamalingam C return byte; 154*39b71c2bSRamalingam C } 155*39b71c2bSRamalingam C 156*39b71c2bSRamalingam C byte = mei_cldev_recv(cldev, (u8 *)&verify_rxcert_out, 157*39b71c2bSRamalingam C sizeof(verify_rxcert_out)); 158*39b71c2bSRamalingam C if (byte < 0) { 159*39b71c2bSRamalingam C dev_dbg(dev, "mei_cldev_recv failed: %zd\n", byte); 160*39b71c2bSRamalingam C return byte; 161*39b71c2bSRamalingam C } 162*39b71c2bSRamalingam C 163*39b71c2bSRamalingam C if (verify_rxcert_out.header.status != ME_HDCP_STATUS_SUCCESS) { 164*39b71c2bSRamalingam C dev_dbg(dev, "ME cmd 0x%08X Failed. Status: 0x%X\n", 165*39b71c2bSRamalingam C WIRED_VERIFY_RECEIVER_CERT, 166*39b71c2bSRamalingam C verify_rxcert_out.header.status); 167*39b71c2bSRamalingam C return -EIO; 168*39b71c2bSRamalingam C } 169*39b71c2bSRamalingam C 170*39b71c2bSRamalingam C *km_stored = !!verify_rxcert_out.km_stored; 171*39b71c2bSRamalingam C if (verify_rxcert_out.km_stored) { 172*39b71c2bSRamalingam C ek_pub_km->msg_id = HDCP_2_2_AKE_STORED_KM; 173*39b71c2bSRamalingam C *msg_sz = sizeof(struct hdcp2_ake_stored_km); 174*39b71c2bSRamalingam C } else { 175*39b71c2bSRamalingam C ek_pub_km->msg_id = HDCP_2_2_AKE_NO_STORED_KM; 176*39b71c2bSRamalingam C *msg_sz = sizeof(struct hdcp2_ake_no_stored_km); 177*39b71c2bSRamalingam C } 178*39b71c2bSRamalingam C 179*39b71c2bSRamalingam C memcpy(ek_pub_km->e_kpub_km, &verify_rxcert_out.ekm_buff, 180*39b71c2bSRamalingam C sizeof(verify_rxcert_out.ekm_buff)); 181*39b71c2bSRamalingam C 182*39b71c2bSRamalingam C return 0; 183*39b71c2bSRamalingam C } 184*39b71c2bSRamalingam C 185a37fb1e4SRamalingam C static const __attribute__((unused)) 186a37fb1e4SRamalingam C struct i915_hdcp_component_ops mei_hdcp_ops = { 187a37fb1e4SRamalingam C .owner = THIS_MODULE, 188a37fb1e4SRamalingam C .initiate_hdcp2_session = mei_hdcp_initiate_session, 189*39b71c2bSRamalingam C .verify_receiver_cert_prepare_km = 190*39b71c2bSRamalingam C mei_hdcp_verify_receiver_cert_prepare_km, 191a37fb1e4SRamalingam C .verify_hprime = NULL, 192a37fb1e4SRamalingam C .store_pairing_info = NULL, 193a37fb1e4SRamalingam C .initiate_locality_check = NULL, 194a37fb1e4SRamalingam C .verify_lprime = NULL, 195a37fb1e4SRamalingam C .get_session_key = NULL, 196a37fb1e4SRamalingam C .repeater_check_flow_prepare_ack = NULL, 197a37fb1e4SRamalingam C .verify_mprime = NULL, 198a37fb1e4SRamalingam C .enable_hdcp_authentication = NULL, 199a37fb1e4SRamalingam C .close_hdcp_session = NULL, 200a37fb1e4SRamalingam C }; 20164e9bbddSRamalingam C 20264e9bbddSRamalingam C static int mei_hdcp_probe(struct mei_cl_device *cldev, 20364e9bbddSRamalingam C const struct mei_cl_device_id *id) 20464e9bbddSRamalingam C { 20564e9bbddSRamalingam C int ret; 20664e9bbddSRamalingam C 20764e9bbddSRamalingam C ret = mei_cldev_enable(cldev); 20864e9bbddSRamalingam C if (ret < 0) 20964e9bbddSRamalingam C dev_err(&cldev->dev, "mei_cldev_enable Failed. %d\n", ret); 21064e9bbddSRamalingam C 21164e9bbddSRamalingam C return ret; 21264e9bbddSRamalingam C } 21364e9bbddSRamalingam C 21464e9bbddSRamalingam C static int mei_hdcp_remove(struct mei_cl_device *cldev) 21564e9bbddSRamalingam C { 21664e9bbddSRamalingam C return mei_cldev_disable(cldev); 21764e9bbddSRamalingam C } 21864e9bbddSRamalingam C 21964e9bbddSRamalingam C #define MEI_UUID_HDCP GUID_INIT(0xB638AB7E, 0x94E2, 0x4EA2, 0xA5, \ 22064e9bbddSRamalingam C 0x52, 0xD1, 0xC5, 0x4B, 0x62, 0x7F, 0x04) 22164e9bbddSRamalingam C 22264e9bbddSRamalingam C static struct mei_cl_device_id mei_hdcp_tbl[] = { 22364e9bbddSRamalingam C { .uuid = MEI_UUID_HDCP, .version = MEI_CL_VERSION_ANY }, 22464e9bbddSRamalingam C { } 22564e9bbddSRamalingam C }; 22664e9bbddSRamalingam C MODULE_DEVICE_TABLE(mei, mei_hdcp_tbl); 22764e9bbddSRamalingam C 22864e9bbddSRamalingam C static struct mei_cl_driver mei_hdcp_driver = { 22964e9bbddSRamalingam C .id_table = mei_hdcp_tbl, 23064e9bbddSRamalingam C .name = KBUILD_MODNAME, 23164e9bbddSRamalingam C .probe = mei_hdcp_probe, 23264e9bbddSRamalingam C .remove = mei_hdcp_remove, 23364e9bbddSRamalingam C }; 23464e9bbddSRamalingam C 23564e9bbddSRamalingam C module_mei_cl_driver(mei_hdcp_driver); 23664e9bbddSRamalingam C 23764e9bbddSRamalingam C MODULE_AUTHOR("Intel Corporation"); 23864e9bbddSRamalingam C MODULE_LICENSE("GPL"); 23964e9bbddSRamalingam C MODULE_DESCRIPTION("MEI HDCP"); 240