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> 26*a37fb1e4SRamalingam C #include <drm/drm_connector.h> 27*a37fb1e4SRamalingam C #include <drm/i915_component.h> 28*a37fb1e4SRamalingam C #include <drm/i915_mei_hdcp_interface.h> 29*a37fb1e4SRamalingam C 30*a37fb1e4SRamalingam C #include "mei_hdcp.h" 31*a37fb1e4SRamalingam C 32*a37fb1e4SRamalingam C static inline u8 mei_get_ddi_index(enum port port) 33*a37fb1e4SRamalingam C { 34*a37fb1e4SRamalingam C switch (port) { 35*a37fb1e4SRamalingam C case PORT_A: 36*a37fb1e4SRamalingam C return MEI_DDI_A; 37*a37fb1e4SRamalingam C case PORT_B ... PORT_F: 38*a37fb1e4SRamalingam C return (u8)port; 39*a37fb1e4SRamalingam C default: 40*a37fb1e4SRamalingam C return MEI_DDI_INVALID_PORT; 41*a37fb1e4SRamalingam C } 42*a37fb1e4SRamalingam C } 43*a37fb1e4SRamalingam C 44*a37fb1e4SRamalingam C /** 45*a37fb1e4SRamalingam C * mei_hdcp_initiate_session() - Initiate a Wired HDCP2.2 Tx Session in ME FW 46*a37fb1e4SRamalingam C * @dev: device corresponding to the mei_cl_device 47*a37fb1e4SRamalingam C * @data: Intel HW specific hdcp data 48*a37fb1e4SRamalingam C * @ake_data: AKE_Init msg output. 49*a37fb1e4SRamalingam C * 50*a37fb1e4SRamalingam C * Return: 0 on Success, <0 on Failure. 51*a37fb1e4SRamalingam C */ 52*a37fb1e4SRamalingam C static int 53*a37fb1e4SRamalingam C mei_hdcp_initiate_session(struct device *dev, struct hdcp_port_data *data, 54*a37fb1e4SRamalingam C struct hdcp2_ake_init *ake_data) 55*a37fb1e4SRamalingam C { 56*a37fb1e4SRamalingam C struct wired_cmd_initiate_hdcp2_session_in session_init_in = { { 0 } }; 57*a37fb1e4SRamalingam C struct wired_cmd_initiate_hdcp2_session_out 58*a37fb1e4SRamalingam C session_init_out = { { 0 } }; 59*a37fb1e4SRamalingam C struct mei_cl_device *cldev; 60*a37fb1e4SRamalingam C ssize_t byte; 61*a37fb1e4SRamalingam C 62*a37fb1e4SRamalingam C if (!dev || !data || !ake_data) 63*a37fb1e4SRamalingam C return -EINVAL; 64*a37fb1e4SRamalingam C 65*a37fb1e4SRamalingam C cldev = to_mei_cl_device(dev); 66*a37fb1e4SRamalingam C 67*a37fb1e4SRamalingam C session_init_in.header.api_version = HDCP_API_VERSION; 68*a37fb1e4SRamalingam C session_init_in.header.command_id = WIRED_INITIATE_HDCP2_SESSION; 69*a37fb1e4SRamalingam C session_init_in.header.status = ME_HDCP_STATUS_SUCCESS; 70*a37fb1e4SRamalingam C session_init_in.header.buffer_len = 71*a37fb1e4SRamalingam C WIRED_CMD_BUF_LEN_INITIATE_HDCP2_SESSION_IN; 72*a37fb1e4SRamalingam C 73*a37fb1e4SRamalingam C session_init_in.port.integrated_port_type = data->port_type; 74*a37fb1e4SRamalingam C session_init_in.port.physical_port = mei_get_ddi_index(data->port); 75*a37fb1e4SRamalingam C session_init_in.protocol = data->protocol; 76*a37fb1e4SRamalingam C 77*a37fb1e4SRamalingam C byte = mei_cldev_send(cldev, (u8 *)&session_init_in, 78*a37fb1e4SRamalingam C sizeof(session_init_in)); 79*a37fb1e4SRamalingam C if (byte < 0) { 80*a37fb1e4SRamalingam C dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); 81*a37fb1e4SRamalingam C return byte; 82*a37fb1e4SRamalingam C } 83*a37fb1e4SRamalingam C 84*a37fb1e4SRamalingam C byte = mei_cldev_recv(cldev, (u8 *)&session_init_out, 85*a37fb1e4SRamalingam C sizeof(session_init_out)); 86*a37fb1e4SRamalingam C if (byte < 0) { 87*a37fb1e4SRamalingam C dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); 88*a37fb1e4SRamalingam C return byte; 89*a37fb1e4SRamalingam C } 90*a37fb1e4SRamalingam C 91*a37fb1e4SRamalingam C if (session_init_out.header.status != ME_HDCP_STATUS_SUCCESS) { 92*a37fb1e4SRamalingam C dev_dbg(dev, "ME cmd 0x%08X Failed. Status: 0x%X\n", 93*a37fb1e4SRamalingam C WIRED_INITIATE_HDCP2_SESSION, 94*a37fb1e4SRamalingam C session_init_out.header.status); 95*a37fb1e4SRamalingam C return -EIO; 96*a37fb1e4SRamalingam C } 97*a37fb1e4SRamalingam C 98*a37fb1e4SRamalingam C ake_data->msg_id = HDCP_2_2_AKE_INIT; 99*a37fb1e4SRamalingam C ake_data->tx_caps = session_init_out.tx_caps; 100*a37fb1e4SRamalingam C memcpy(ake_data->r_tx, session_init_out.r_tx, HDCP_2_2_RTX_LEN); 101*a37fb1e4SRamalingam C 102*a37fb1e4SRamalingam C return 0; 103*a37fb1e4SRamalingam C } 104*a37fb1e4SRamalingam C 105*a37fb1e4SRamalingam C static const __attribute__((unused)) 106*a37fb1e4SRamalingam C struct i915_hdcp_component_ops mei_hdcp_ops = { 107*a37fb1e4SRamalingam C .owner = THIS_MODULE, 108*a37fb1e4SRamalingam C .initiate_hdcp2_session = mei_hdcp_initiate_session, 109*a37fb1e4SRamalingam C .verify_receiver_cert_prepare_km = NULL, 110*a37fb1e4SRamalingam C .verify_hprime = NULL, 111*a37fb1e4SRamalingam C .store_pairing_info = NULL, 112*a37fb1e4SRamalingam C .initiate_locality_check = NULL, 113*a37fb1e4SRamalingam C .verify_lprime = NULL, 114*a37fb1e4SRamalingam C .get_session_key = NULL, 115*a37fb1e4SRamalingam C .repeater_check_flow_prepare_ack = NULL, 116*a37fb1e4SRamalingam C .verify_mprime = NULL, 117*a37fb1e4SRamalingam C .enable_hdcp_authentication = NULL, 118*a37fb1e4SRamalingam C .close_hdcp_session = NULL, 119*a37fb1e4SRamalingam C }; 12064e9bbddSRamalingam C 12164e9bbddSRamalingam C static int mei_hdcp_probe(struct mei_cl_device *cldev, 12264e9bbddSRamalingam C const struct mei_cl_device_id *id) 12364e9bbddSRamalingam C { 12464e9bbddSRamalingam C int ret; 12564e9bbddSRamalingam C 12664e9bbddSRamalingam C ret = mei_cldev_enable(cldev); 12764e9bbddSRamalingam C if (ret < 0) 12864e9bbddSRamalingam C dev_err(&cldev->dev, "mei_cldev_enable Failed. %d\n", ret); 12964e9bbddSRamalingam C 13064e9bbddSRamalingam C return ret; 13164e9bbddSRamalingam C } 13264e9bbddSRamalingam C 13364e9bbddSRamalingam C static int mei_hdcp_remove(struct mei_cl_device *cldev) 13464e9bbddSRamalingam C { 13564e9bbddSRamalingam C return mei_cldev_disable(cldev); 13664e9bbddSRamalingam C } 13764e9bbddSRamalingam C 13864e9bbddSRamalingam C #define MEI_UUID_HDCP GUID_INIT(0xB638AB7E, 0x94E2, 0x4EA2, 0xA5, \ 13964e9bbddSRamalingam C 0x52, 0xD1, 0xC5, 0x4B, 0x62, 0x7F, 0x04) 14064e9bbddSRamalingam C 14164e9bbddSRamalingam C static struct mei_cl_device_id mei_hdcp_tbl[] = { 14264e9bbddSRamalingam C { .uuid = MEI_UUID_HDCP, .version = MEI_CL_VERSION_ANY }, 14364e9bbddSRamalingam C { } 14464e9bbddSRamalingam C }; 14564e9bbddSRamalingam C MODULE_DEVICE_TABLE(mei, mei_hdcp_tbl); 14664e9bbddSRamalingam C 14764e9bbddSRamalingam C static struct mei_cl_driver mei_hdcp_driver = { 14864e9bbddSRamalingam C .id_table = mei_hdcp_tbl, 14964e9bbddSRamalingam C .name = KBUILD_MODNAME, 15064e9bbddSRamalingam C .probe = mei_hdcp_probe, 15164e9bbddSRamalingam C .remove = mei_hdcp_remove, 15264e9bbddSRamalingam C }; 15364e9bbddSRamalingam C 15464e9bbddSRamalingam C module_mei_cl_driver(mei_hdcp_driver); 15564e9bbddSRamalingam C 15664e9bbddSRamalingam C MODULE_AUTHOR("Intel Corporation"); 15764e9bbddSRamalingam C MODULE_LICENSE("GPL"); 15864e9bbddSRamalingam C MODULE_DESCRIPTION("MEI HDCP"); 159