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