xref: /openbmc/linux/drivers/misc/mei/hdcp/mei_hdcp.c (revision a37fb1e4730205ff5aac413a14ad4f34ecec3e0c)
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