1*6a3608eaSParshuram Thombare // SPDX-License-Identifier: GPL-2.0
2*6a3608eaSParshuram Thombare /*
3*6a3608eaSParshuram Thombare  * Cadence MHDP8546 DP bridge driver.
4*6a3608eaSParshuram Thombare  *
5*6a3608eaSParshuram Thombare  * Copyright (C) 2020 Cadence Design Systems, Inc.
6*6a3608eaSParshuram Thombare  *
7*6a3608eaSParshuram Thombare  */
8*6a3608eaSParshuram Thombare 
9*6a3608eaSParshuram Thombare #include <linux/io.h>
10*6a3608eaSParshuram Thombare #include <linux/iopoll.h>
11*6a3608eaSParshuram Thombare 
12*6a3608eaSParshuram Thombare #include <asm/unaligned.h>
13*6a3608eaSParshuram Thombare 
14*6a3608eaSParshuram Thombare #include <drm/drm_hdcp.h>
15*6a3608eaSParshuram Thombare 
16*6a3608eaSParshuram Thombare #include "cdns-mhdp8546-hdcp.h"
17*6a3608eaSParshuram Thombare 
18*6a3608eaSParshuram Thombare static int cdns_mhdp_secure_mailbox_read(struct cdns_mhdp_device *mhdp)
19*6a3608eaSParshuram Thombare {
20*6a3608eaSParshuram Thombare 	int ret, empty;
21*6a3608eaSParshuram Thombare 
22*6a3608eaSParshuram Thombare 	WARN_ON(!mutex_is_locked(&mhdp->mbox_mutex));
23*6a3608eaSParshuram Thombare 
24*6a3608eaSParshuram Thombare 	ret = readx_poll_timeout(readl, mhdp->sapb_regs + CDNS_MAILBOX_EMPTY,
25*6a3608eaSParshuram Thombare 				 empty, !empty, MAILBOX_RETRY_US,
26*6a3608eaSParshuram Thombare 				 MAILBOX_TIMEOUT_US);
27*6a3608eaSParshuram Thombare 	if (ret < 0)
28*6a3608eaSParshuram Thombare 		return ret;
29*6a3608eaSParshuram Thombare 
30*6a3608eaSParshuram Thombare 	return readl(mhdp->sapb_regs + CDNS_MAILBOX_RX_DATA) & 0xff;
31*6a3608eaSParshuram Thombare }
32*6a3608eaSParshuram Thombare 
33*6a3608eaSParshuram Thombare static int cdns_mhdp_secure_mailbox_write(struct cdns_mhdp_device *mhdp,
34*6a3608eaSParshuram Thombare 					  u8 val)
35*6a3608eaSParshuram Thombare {
36*6a3608eaSParshuram Thombare 	int ret, full;
37*6a3608eaSParshuram Thombare 
38*6a3608eaSParshuram Thombare 	WARN_ON(!mutex_is_locked(&mhdp->mbox_mutex));
39*6a3608eaSParshuram Thombare 
40*6a3608eaSParshuram Thombare 	ret = readx_poll_timeout(readl, mhdp->sapb_regs + CDNS_MAILBOX_FULL,
41*6a3608eaSParshuram Thombare 				 full, !full, MAILBOX_RETRY_US,
42*6a3608eaSParshuram Thombare 				 MAILBOX_TIMEOUT_US);
43*6a3608eaSParshuram Thombare 	if (ret < 0)
44*6a3608eaSParshuram Thombare 		return ret;
45*6a3608eaSParshuram Thombare 
46*6a3608eaSParshuram Thombare 	writel(val, mhdp->sapb_regs + CDNS_MAILBOX_TX_DATA);
47*6a3608eaSParshuram Thombare 
48*6a3608eaSParshuram Thombare 	return 0;
49*6a3608eaSParshuram Thombare }
50*6a3608eaSParshuram Thombare 
51*6a3608eaSParshuram Thombare static int cdns_mhdp_secure_mailbox_recv_header(struct cdns_mhdp_device *mhdp,
52*6a3608eaSParshuram Thombare 						u8 module_id,
53*6a3608eaSParshuram Thombare 						u8 opcode,
54*6a3608eaSParshuram Thombare 						u16 req_size)
55*6a3608eaSParshuram Thombare {
56*6a3608eaSParshuram Thombare 	u32 mbox_size, i;
57*6a3608eaSParshuram Thombare 	u8 header[4];
58*6a3608eaSParshuram Thombare 	int ret;
59*6a3608eaSParshuram Thombare 
60*6a3608eaSParshuram Thombare 	/* read the header of the message */
61*6a3608eaSParshuram Thombare 	for (i = 0; i < sizeof(header); i++) {
62*6a3608eaSParshuram Thombare 		ret = cdns_mhdp_secure_mailbox_read(mhdp);
63*6a3608eaSParshuram Thombare 		if (ret < 0)
64*6a3608eaSParshuram Thombare 			return ret;
65*6a3608eaSParshuram Thombare 
66*6a3608eaSParshuram Thombare 		header[i] = ret;
67*6a3608eaSParshuram Thombare 	}
68*6a3608eaSParshuram Thombare 
69*6a3608eaSParshuram Thombare 	mbox_size = get_unaligned_be16(header + 2);
70*6a3608eaSParshuram Thombare 
71*6a3608eaSParshuram Thombare 	if (opcode != header[0] || module_id != header[1] ||
72*6a3608eaSParshuram Thombare 	    (opcode != HDCP_TRAN_IS_REC_ID_VALID && req_size != mbox_size)) {
73*6a3608eaSParshuram Thombare 		for (i = 0; i < mbox_size; i++)
74*6a3608eaSParshuram Thombare 			if (cdns_mhdp_secure_mailbox_read(mhdp) < 0)
75*6a3608eaSParshuram Thombare 				break;
76*6a3608eaSParshuram Thombare 		return -EINVAL;
77*6a3608eaSParshuram Thombare 	}
78*6a3608eaSParshuram Thombare 
79*6a3608eaSParshuram Thombare 	return 0;
80*6a3608eaSParshuram Thombare }
81*6a3608eaSParshuram Thombare 
82*6a3608eaSParshuram Thombare static int cdns_mhdp_secure_mailbox_recv_data(struct cdns_mhdp_device *mhdp,
83*6a3608eaSParshuram Thombare 					      u8 *buff, u16 buff_size)
84*6a3608eaSParshuram Thombare {
85*6a3608eaSParshuram Thombare 	int ret;
86*6a3608eaSParshuram Thombare 	u32 i;
87*6a3608eaSParshuram Thombare 
88*6a3608eaSParshuram Thombare 	for (i = 0; i < buff_size; i++) {
89*6a3608eaSParshuram Thombare 		ret = cdns_mhdp_secure_mailbox_read(mhdp);
90*6a3608eaSParshuram Thombare 		if (ret < 0)
91*6a3608eaSParshuram Thombare 			return ret;
92*6a3608eaSParshuram Thombare 
93*6a3608eaSParshuram Thombare 		buff[i] = ret;
94*6a3608eaSParshuram Thombare 	}
95*6a3608eaSParshuram Thombare 
96*6a3608eaSParshuram Thombare 	return 0;
97*6a3608eaSParshuram Thombare }
98*6a3608eaSParshuram Thombare 
99*6a3608eaSParshuram Thombare static int cdns_mhdp_secure_mailbox_send(struct cdns_mhdp_device *mhdp,
100*6a3608eaSParshuram Thombare 					 u8 module_id,
101*6a3608eaSParshuram Thombare 					 u8 opcode,
102*6a3608eaSParshuram Thombare 					 u16 size,
103*6a3608eaSParshuram Thombare 					 u8 *message)
104*6a3608eaSParshuram Thombare {
105*6a3608eaSParshuram Thombare 	u8 header[4];
106*6a3608eaSParshuram Thombare 	int ret;
107*6a3608eaSParshuram Thombare 	u32 i;
108*6a3608eaSParshuram Thombare 
109*6a3608eaSParshuram Thombare 	header[0] = opcode;
110*6a3608eaSParshuram Thombare 	header[1] = module_id;
111*6a3608eaSParshuram Thombare 	put_unaligned_be16(size, header + 2);
112*6a3608eaSParshuram Thombare 
113*6a3608eaSParshuram Thombare 	for (i = 0; i < sizeof(header); i++) {
114*6a3608eaSParshuram Thombare 		ret = cdns_mhdp_secure_mailbox_write(mhdp, header[i]);
115*6a3608eaSParshuram Thombare 		if (ret)
116*6a3608eaSParshuram Thombare 			return ret;
117*6a3608eaSParshuram Thombare 	}
118*6a3608eaSParshuram Thombare 
119*6a3608eaSParshuram Thombare 	for (i = 0; i < size; i++) {
120*6a3608eaSParshuram Thombare 		ret = cdns_mhdp_secure_mailbox_write(mhdp, message[i]);
121*6a3608eaSParshuram Thombare 		if (ret)
122*6a3608eaSParshuram Thombare 			return ret;
123*6a3608eaSParshuram Thombare 	}
124*6a3608eaSParshuram Thombare 
125*6a3608eaSParshuram Thombare 	return 0;
126*6a3608eaSParshuram Thombare }
127*6a3608eaSParshuram Thombare 
128*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_get_status(struct cdns_mhdp_device *mhdp,
129*6a3608eaSParshuram Thombare 				     u16 *hdcp_port_status)
130*6a3608eaSParshuram Thombare {
131*6a3608eaSParshuram Thombare 	u8 hdcp_status[HDCP_STATUS_SIZE];
132*6a3608eaSParshuram Thombare 	int ret;
133*6a3608eaSParshuram Thombare 
134*6a3608eaSParshuram Thombare 	mutex_lock(&mhdp->mbox_mutex);
135*6a3608eaSParshuram Thombare 	ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX,
136*6a3608eaSParshuram Thombare 					    HDCP_TRAN_STATUS_CHANGE, 0, NULL);
137*6a3608eaSParshuram Thombare 	if (ret)
138*6a3608eaSParshuram Thombare 		goto err_get_hdcp_status;
139*6a3608eaSParshuram Thombare 
140*6a3608eaSParshuram Thombare 	ret = cdns_mhdp_secure_mailbox_recv_header(mhdp, MB_MODULE_ID_HDCP_TX,
141*6a3608eaSParshuram Thombare 						   HDCP_TRAN_STATUS_CHANGE,
142*6a3608eaSParshuram Thombare 						   sizeof(hdcp_status));
143*6a3608eaSParshuram Thombare 	if (ret)
144*6a3608eaSParshuram Thombare 		goto err_get_hdcp_status;
145*6a3608eaSParshuram Thombare 
146*6a3608eaSParshuram Thombare 	ret = cdns_mhdp_secure_mailbox_recv_data(mhdp, hdcp_status,
147*6a3608eaSParshuram Thombare 						 sizeof(hdcp_status));
148*6a3608eaSParshuram Thombare 	if (ret)
149*6a3608eaSParshuram Thombare 		goto err_get_hdcp_status;
150*6a3608eaSParshuram Thombare 
151*6a3608eaSParshuram Thombare 	*hdcp_port_status = ((u16)(hdcp_status[0] << 8) | hdcp_status[1]);
152*6a3608eaSParshuram Thombare 
153*6a3608eaSParshuram Thombare err_get_hdcp_status:
154*6a3608eaSParshuram Thombare 	mutex_unlock(&mhdp->mbox_mutex);
155*6a3608eaSParshuram Thombare 
156*6a3608eaSParshuram Thombare 	return ret;
157*6a3608eaSParshuram Thombare }
158*6a3608eaSParshuram Thombare 
159*6a3608eaSParshuram Thombare static u8 cdns_mhdp_hdcp_handle_status(struct cdns_mhdp_device *mhdp,
160*6a3608eaSParshuram Thombare 				       u16 status)
161*6a3608eaSParshuram Thombare {
162*6a3608eaSParshuram Thombare 	u8 err = GET_HDCP_PORT_STS_LAST_ERR(status);
163*6a3608eaSParshuram Thombare 
164*6a3608eaSParshuram Thombare 	if (err)
165*6a3608eaSParshuram Thombare 		dev_dbg(mhdp->dev, "HDCP Error = %d", err);
166*6a3608eaSParshuram Thombare 
167*6a3608eaSParshuram Thombare 	return err;
168*6a3608eaSParshuram Thombare }
169*6a3608eaSParshuram Thombare 
170*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_rx_id_valid_response(struct cdns_mhdp_device *mhdp,
171*6a3608eaSParshuram Thombare 					       u8 valid)
172*6a3608eaSParshuram Thombare {
173*6a3608eaSParshuram Thombare 	int ret;
174*6a3608eaSParshuram Thombare 
175*6a3608eaSParshuram Thombare 	mutex_lock(&mhdp->mbox_mutex);
176*6a3608eaSParshuram Thombare 	ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX,
177*6a3608eaSParshuram Thombare 					    HDCP_TRAN_RESPOND_RECEIVER_ID_VALID,
178*6a3608eaSParshuram Thombare 					    1, &valid);
179*6a3608eaSParshuram Thombare 	mutex_unlock(&mhdp->mbox_mutex);
180*6a3608eaSParshuram Thombare 
181*6a3608eaSParshuram Thombare 	return ret;
182*6a3608eaSParshuram Thombare }
183*6a3608eaSParshuram Thombare 
184*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_rx_id_valid(struct cdns_mhdp_device *mhdp,
185*6a3608eaSParshuram Thombare 				      u8 *recv_num, u8 *hdcp_rx_id)
186*6a3608eaSParshuram Thombare {
187*6a3608eaSParshuram Thombare 	u8 rec_id_hdr[2];
188*6a3608eaSParshuram Thombare 	u8 status;
189*6a3608eaSParshuram Thombare 	int ret;
190*6a3608eaSParshuram Thombare 
191*6a3608eaSParshuram Thombare 	mutex_lock(&mhdp->mbox_mutex);
192*6a3608eaSParshuram Thombare 	ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX,
193*6a3608eaSParshuram Thombare 					    HDCP_TRAN_IS_REC_ID_VALID, 0, NULL);
194*6a3608eaSParshuram Thombare 	if (ret)
195*6a3608eaSParshuram Thombare 		goto err_rx_id_valid;
196*6a3608eaSParshuram Thombare 
197*6a3608eaSParshuram Thombare 	ret = cdns_mhdp_secure_mailbox_recv_header(mhdp, MB_MODULE_ID_HDCP_TX,
198*6a3608eaSParshuram Thombare 						   HDCP_TRAN_IS_REC_ID_VALID,
199*6a3608eaSParshuram Thombare 						   sizeof(status));
200*6a3608eaSParshuram Thombare 	if (ret)
201*6a3608eaSParshuram Thombare 		goto err_rx_id_valid;
202*6a3608eaSParshuram Thombare 
203*6a3608eaSParshuram Thombare 	ret = cdns_mhdp_secure_mailbox_recv_data(mhdp, rec_id_hdr, 2);
204*6a3608eaSParshuram Thombare 	if (ret)
205*6a3608eaSParshuram Thombare 		goto err_rx_id_valid;
206*6a3608eaSParshuram Thombare 
207*6a3608eaSParshuram Thombare 	*recv_num = rec_id_hdr[0];
208*6a3608eaSParshuram Thombare 
209*6a3608eaSParshuram Thombare 	ret = cdns_mhdp_secure_mailbox_recv_data(mhdp, hdcp_rx_id, 5 * *recv_num);
210*6a3608eaSParshuram Thombare 
211*6a3608eaSParshuram Thombare err_rx_id_valid:
212*6a3608eaSParshuram Thombare 	mutex_unlock(&mhdp->mbox_mutex);
213*6a3608eaSParshuram Thombare 
214*6a3608eaSParshuram Thombare 	return ret;
215*6a3608eaSParshuram Thombare }
216*6a3608eaSParshuram Thombare 
217*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_km_stored_resp(struct cdns_mhdp_device *mhdp,
218*6a3608eaSParshuram Thombare 					 u32 size, u8 *km)
219*6a3608eaSParshuram Thombare {
220*6a3608eaSParshuram Thombare 	int ret;
221*6a3608eaSParshuram Thombare 
222*6a3608eaSParshuram Thombare 	mutex_lock(&mhdp->mbox_mutex);
223*6a3608eaSParshuram Thombare 	ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX,
224*6a3608eaSParshuram Thombare 					    HDCP2X_TX_RESPOND_KM, size, km);
225*6a3608eaSParshuram Thombare 	mutex_unlock(&mhdp->mbox_mutex);
226*6a3608eaSParshuram Thombare 
227*6a3608eaSParshuram Thombare 	return ret;
228*6a3608eaSParshuram Thombare }
229*6a3608eaSParshuram Thombare 
230*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_tx_is_km_stored(struct cdns_mhdp_device *mhdp,
231*6a3608eaSParshuram Thombare 					  u8 *resp, u32 size)
232*6a3608eaSParshuram Thombare {
233*6a3608eaSParshuram Thombare 	int ret;
234*6a3608eaSParshuram Thombare 
235*6a3608eaSParshuram Thombare 	mutex_lock(&mhdp->mbox_mutex);
236*6a3608eaSParshuram Thombare 	ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX,
237*6a3608eaSParshuram Thombare 					    HDCP2X_TX_IS_KM_STORED, 0, NULL);
238*6a3608eaSParshuram Thombare 	if (ret)
239*6a3608eaSParshuram Thombare 		goto err_is_km_stored;
240*6a3608eaSParshuram Thombare 
241*6a3608eaSParshuram Thombare 	ret = cdns_mhdp_secure_mailbox_recv_header(mhdp, MB_MODULE_ID_HDCP_TX,
242*6a3608eaSParshuram Thombare 						   HDCP2X_TX_IS_KM_STORED,
243*6a3608eaSParshuram Thombare 						   size);
244*6a3608eaSParshuram Thombare 	if (ret)
245*6a3608eaSParshuram Thombare 		goto err_is_km_stored;
246*6a3608eaSParshuram Thombare 
247*6a3608eaSParshuram Thombare 	ret = cdns_mhdp_secure_mailbox_recv_data(mhdp, resp, size);
248*6a3608eaSParshuram Thombare err_is_km_stored:
249*6a3608eaSParshuram Thombare 	mutex_unlock(&mhdp->mbox_mutex);
250*6a3608eaSParshuram Thombare 
251*6a3608eaSParshuram Thombare 	return ret;
252*6a3608eaSParshuram Thombare }
253*6a3608eaSParshuram Thombare 
254*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_tx_config(struct cdns_mhdp_device *mhdp,
255*6a3608eaSParshuram Thombare 				    u8 hdcp_cfg)
256*6a3608eaSParshuram Thombare {
257*6a3608eaSParshuram Thombare 	int ret;
258*6a3608eaSParshuram Thombare 
259*6a3608eaSParshuram Thombare 	mutex_lock(&mhdp->mbox_mutex);
260*6a3608eaSParshuram Thombare 	ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX,
261*6a3608eaSParshuram Thombare 					    HDCP_TRAN_CONFIGURATION, 1, &hdcp_cfg);
262*6a3608eaSParshuram Thombare 	mutex_unlock(&mhdp->mbox_mutex);
263*6a3608eaSParshuram Thombare 
264*6a3608eaSParshuram Thombare 	return ret;
265*6a3608eaSParshuram Thombare }
266*6a3608eaSParshuram Thombare 
267*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_set_config(struct cdns_mhdp_device *mhdp,
268*6a3608eaSParshuram Thombare 				     u8 hdcp_config, bool enable)
269*6a3608eaSParshuram Thombare {
270*6a3608eaSParshuram Thombare 	u16 hdcp_port_status;
271*6a3608eaSParshuram Thombare 	u32 ret_event;
272*6a3608eaSParshuram Thombare 	u8 hdcp_cfg;
273*6a3608eaSParshuram Thombare 	int ret;
274*6a3608eaSParshuram Thombare 
275*6a3608eaSParshuram Thombare 	hdcp_cfg = hdcp_config | (enable ? 0x04 : 0) |
276*6a3608eaSParshuram Thombare 		   (HDCP_CONTENT_TYPE_0 << 3);
277*6a3608eaSParshuram Thombare 	cdns_mhdp_hdcp_tx_config(mhdp, hdcp_cfg);
278*6a3608eaSParshuram Thombare 	ret_event = cdns_mhdp_wait_for_sw_event(mhdp, CDNS_HDCP_TX_STATUS);
279*6a3608eaSParshuram Thombare 	if (!ret_event)
280*6a3608eaSParshuram Thombare 		return -1;
281*6a3608eaSParshuram Thombare 
282*6a3608eaSParshuram Thombare 	ret = cdns_mhdp_hdcp_get_status(mhdp, &hdcp_port_status);
283*6a3608eaSParshuram Thombare 	if (ret || cdns_mhdp_hdcp_handle_status(mhdp, hdcp_port_status))
284*6a3608eaSParshuram Thombare 		return -1;
285*6a3608eaSParshuram Thombare 
286*6a3608eaSParshuram Thombare 	return 0;
287*6a3608eaSParshuram Thombare }
288*6a3608eaSParshuram Thombare 
289*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_auth_check(struct cdns_mhdp_device *mhdp)
290*6a3608eaSParshuram Thombare {
291*6a3608eaSParshuram Thombare 	u16 hdcp_port_status;
292*6a3608eaSParshuram Thombare 	u32 ret_event;
293*6a3608eaSParshuram Thombare 	int ret;
294*6a3608eaSParshuram Thombare 
295*6a3608eaSParshuram Thombare 	ret_event = cdns_mhdp_wait_for_sw_event(mhdp, CDNS_HDCP_TX_STATUS);
296*6a3608eaSParshuram Thombare 	if (!ret_event)
297*6a3608eaSParshuram Thombare 		return -1;
298*6a3608eaSParshuram Thombare 
299*6a3608eaSParshuram Thombare 	ret = cdns_mhdp_hdcp_get_status(mhdp, &hdcp_port_status);
300*6a3608eaSParshuram Thombare 	if (ret || cdns_mhdp_hdcp_handle_status(mhdp, hdcp_port_status))
301*6a3608eaSParshuram Thombare 		return -1;
302*6a3608eaSParshuram Thombare 
303*6a3608eaSParshuram Thombare 	if (hdcp_port_status & 1) {
304*6a3608eaSParshuram Thombare 		dev_dbg(mhdp->dev, "Authentication completed successfully!\n");
305*6a3608eaSParshuram Thombare 		return 0;
306*6a3608eaSParshuram Thombare 	}
307*6a3608eaSParshuram Thombare 
308*6a3608eaSParshuram Thombare 	dev_dbg(mhdp->dev, "Authentication failed\n");
309*6a3608eaSParshuram Thombare 
310*6a3608eaSParshuram Thombare 	return -1;
311*6a3608eaSParshuram Thombare }
312*6a3608eaSParshuram Thombare 
313*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_check_receviers(struct cdns_mhdp_device *mhdp)
314*6a3608eaSParshuram Thombare {
315*6a3608eaSParshuram Thombare 	u8 hdcp_rec_id[HDCP_MAX_RECEIVERS][HDCP_RECEIVER_ID_SIZE_BYTES];
316*6a3608eaSParshuram Thombare 	u8 hdcp_num_rec;
317*6a3608eaSParshuram Thombare 	u32 ret_event;
318*6a3608eaSParshuram Thombare 
319*6a3608eaSParshuram Thombare 	ret_event = cdns_mhdp_wait_for_sw_event(mhdp,
320*6a3608eaSParshuram Thombare 						CDNS_HDCP_TX_IS_RCVR_ID_VALID);
321*6a3608eaSParshuram Thombare 	if (!ret_event)
322*6a3608eaSParshuram Thombare 		return -1;
323*6a3608eaSParshuram Thombare 
324*6a3608eaSParshuram Thombare 	hdcp_num_rec = 0;
325*6a3608eaSParshuram Thombare 	memset(&hdcp_rec_id, 0, sizeof(hdcp_rec_id));
326*6a3608eaSParshuram Thombare 	cdns_mhdp_hdcp_rx_id_valid(mhdp, &hdcp_num_rec, (u8 *)hdcp_rec_id);
327*6a3608eaSParshuram Thombare 	cdns_mhdp_hdcp_rx_id_valid_response(mhdp, 1);
328*6a3608eaSParshuram Thombare 
329*6a3608eaSParshuram Thombare 	return 0;
330*6a3608eaSParshuram Thombare }
331*6a3608eaSParshuram Thombare 
332*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_auth_22(struct cdns_mhdp_device *mhdp)
333*6a3608eaSParshuram Thombare {
334*6a3608eaSParshuram Thombare 	u8 resp[HDCP_STATUS_SIZE];
335*6a3608eaSParshuram Thombare 	u16 hdcp_port_status;
336*6a3608eaSParshuram Thombare 	u32 ret_event;
337*6a3608eaSParshuram Thombare 	int ret;
338*6a3608eaSParshuram Thombare 
339*6a3608eaSParshuram Thombare 	dev_dbg(mhdp->dev, "HDCP: Start 2.2 Authentication\n");
340*6a3608eaSParshuram Thombare 	ret_event = cdns_mhdp_wait_for_sw_event(mhdp,
341*6a3608eaSParshuram Thombare 						CDNS_HDCP2_TX_IS_KM_STORED);
342*6a3608eaSParshuram Thombare 	if (!ret_event)
343*6a3608eaSParshuram Thombare 		return -1;
344*6a3608eaSParshuram Thombare 
345*6a3608eaSParshuram Thombare 	if (ret_event & CDNS_HDCP_TX_STATUS) {
346*6a3608eaSParshuram Thombare 		mhdp->sw_events &= ~CDNS_HDCP_TX_STATUS;
347*6a3608eaSParshuram Thombare 		ret = cdns_mhdp_hdcp_get_status(mhdp, &hdcp_port_status);
348*6a3608eaSParshuram Thombare 		if (ret || cdns_mhdp_hdcp_handle_status(mhdp, hdcp_port_status))
349*6a3608eaSParshuram Thombare 			return -1;
350*6a3608eaSParshuram Thombare 	}
351*6a3608eaSParshuram Thombare 
352*6a3608eaSParshuram Thombare 	cdns_mhdp_hdcp_tx_is_km_stored(mhdp, resp, sizeof(resp));
353*6a3608eaSParshuram Thombare 	cdns_mhdp_hdcp_km_stored_resp(mhdp, 0, NULL);
354*6a3608eaSParshuram Thombare 
355*6a3608eaSParshuram Thombare 	if (cdns_mhdp_hdcp_check_receviers(mhdp))
356*6a3608eaSParshuram Thombare 		return -1;
357*6a3608eaSParshuram Thombare 
358*6a3608eaSParshuram Thombare 	return 0;
359*6a3608eaSParshuram Thombare }
360*6a3608eaSParshuram Thombare 
361*6a3608eaSParshuram Thombare static inline int cdns_mhdp_hdcp_auth_14(struct cdns_mhdp_device *mhdp)
362*6a3608eaSParshuram Thombare {
363*6a3608eaSParshuram Thombare 	dev_dbg(mhdp->dev, "HDCP: Starting 1.4 Authentication\n");
364*6a3608eaSParshuram Thombare 	return cdns_mhdp_hdcp_check_receviers(mhdp);
365*6a3608eaSParshuram Thombare }
366*6a3608eaSParshuram Thombare 
367*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_auth(struct cdns_mhdp_device *mhdp,
368*6a3608eaSParshuram Thombare 			       u8 hdcp_config)
369*6a3608eaSParshuram Thombare {
370*6a3608eaSParshuram Thombare 	int ret;
371*6a3608eaSParshuram Thombare 
372*6a3608eaSParshuram Thombare 	ret = cdns_mhdp_hdcp_set_config(mhdp, hdcp_config, true);
373*6a3608eaSParshuram Thombare 	if (ret)
374*6a3608eaSParshuram Thombare 		goto auth_failed;
375*6a3608eaSParshuram Thombare 
376*6a3608eaSParshuram Thombare 	if (hdcp_config == HDCP_TX_1)
377*6a3608eaSParshuram Thombare 		ret = cdns_mhdp_hdcp_auth_14(mhdp);
378*6a3608eaSParshuram Thombare 	else
379*6a3608eaSParshuram Thombare 		ret = cdns_mhdp_hdcp_auth_22(mhdp);
380*6a3608eaSParshuram Thombare 
381*6a3608eaSParshuram Thombare 	if (ret)
382*6a3608eaSParshuram Thombare 		goto auth_failed;
383*6a3608eaSParshuram Thombare 
384*6a3608eaSParshuram Thombare 	ret = cdns_mhdp_hdcp_auth_check(mhdp);
385*6a3608eaSParshuram Thombare 	if (ret)
386*6a3608eaSParshuram Thombare 		ret = cdns_mhdp_hdcp_auth_check(mhdp);
387*6a3608eaSParshuram Thombare 
388*6a3608eaSParshuram Thombare auth_failed:
389*6a3608eaSParshuram Thombare 	return ret;
390*6a3608eaSParshuram Thombare }
391*6a3608eaSParshuram Thombare 
392*6a3608eaSParshuram Thombare static int _cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp)
393*6a3608eaSParshuram Thombare {
394*6a3608eaSParshuram Thombare 	int ret;
395*6a3608eaSParshuram Thombare 
396*6a3608eaSParshuram Thombare 	dev_dbg(mhdp->dev, "[%s:%d] HDCP is being disabled...\n",
397*6a3608eaSParshuram Thombare 		mhdp->connector.name, mhdp->connector.base.id);
398*6a3608eaSParshuram Thombare 
399*6a3608eaSParshuram Thombare 	ret = cdns_mhdp_hdcp_set_config(mhdp, 0, false);
400*6a3608eaSParshuram Thombare 
401*6a3608eaSParshuram Thombare 	return ret;
402*6a3608eaSParshuram Thombare }
403*6a3608eaSParshuram Thombare 
404*6a3608eaSParshuram Thombare static int _cdns_mhdp_hdcp_enable(struct cdns_mhdp_device *mhdp, u8 content_type)
405*6a3608eaSParshuram Thombare {
406*6a3608eaSParshuram Thombare 	int ret, tries = 3;
407*6a3608eaSParshuram Thombare 	u32 i;
408*6a3608eaSParshuram Thombare 
409*6a3608eaSParshuram Thombare 	for (i = 0; i < tries; i++) {
410*6a3608eaSParshuram Thombare 		if (content_type == DRM_MODE_HDCP_CONTENT_TYPE0 ||
411*6a3608eaSParshuram Thombare 		    content_type == DRM_MODE_HDCP_CONTENT_TYPE1) {
412*6a3608eaSParshuram Thombare 			ret = cdns_mhdp_hdcp_auth(mhdp, HDCP_TX_2);
413*6a3608eaSParshuram Thombare 			if (!ret)
414*6a3608eaSParshuram Thombare 				return 0;
415*6a3608eaSParshuram Thombare 			_cdns_mhdp_hdcp_disable(mhdp);
416*6a3608eaSParshuram Thombare 		}
417*6a3608eaSParshuram Thombare 
418*6a3608eaSParshuram Thombare 		if (content_type == DRM_MODE_HDCP_CONTENT_TYPE0) {
419*6a3608eaSParshuram Thombare 			ret = cdns_mhdp_hdcp_auth(mhdp, HDCP_TX_1);
420*6a3608eaSParshuram Thombare 			if (!ret)
421*6a3608eaSParshuram Thombare 				return 0;
422*6a3608eaSParshuram Thombare 			_cdns_mhdp_hdcp_disable(mhdp);
423*6a3608eaSParshuram Thombare 		}
424*6a3608eaSParshuram Thombare 	}
425*6a3608eaSParshuram Thombare 
426*6a3608eaSParshuram Thombare 	dev_err(mhdp->dev, "HDCP authentication failed (%d tries/%d)\n",
427*6a3608eaSParshuram Thombare 		tries, ret);
428*6a3608eaSParshuram Thombare 
429*6a3608eaSParshuram Thombare 	return ret;
430*6a3608eaSParshuram Thombare }
431*6a3608eaSParshuram Thombare 
432*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_check_link(struct cdns_mhdp_device *mhdp)
433*6a3608eaSParshuram Thombare {
434*6a3608eaSParshuram Thombare 	u16 hdcp_port_status;
435*6a3608eaSParshuram Thombare 	int ret = 0;
436*6a3608eaSParshuram Thombare 
437*6a3608eaSParshuram Thombare 	mutex_lock(&mhdp->hdcp.mutex);
438*6a3608eaSParshuram Thombare 	if (mhdp->hdcp.value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
439*6a3608eaSParshuram Thombare 		goto out;
440*6a3608eaSParshuram Thombare 
441*6a3608eaSParshuram Thombare 	ret = cdns_mhdp_hdcp_get_status(mhdp, &hdcp_port_status);
442*6a3608eaSParshuram Thombare 	if (!ret && hdcp_port_status & HDCP_PORT_STS_AUTH)
443*6a3608eaSParshuram Thombare 		goto out;
444*6a3608eaSParshuram Thombare 
445*6a3608eaSParshuram Thombare 	dev_err(mhdp->dev,
446*6a3608eaSParshuram Thombare 		"[%s:%d] HDCP link failed, retrying authentication\n",
447*6a3608eaSParshuram Thombare 		mhdp->connector.name, mhdp->connector.base.id);
448*6a3608eaSParshuram Thombare 
449*6a3608eaSParshuram Thombare 	ret = _cdns_mhdp_hdcp_disable(mhdp);
450*6a3608eaSParshuram Thombare 	if (ret) {
451*6a3608eaSParshuram Thombare 		mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
452*6a3608eaSParshuram Thombare 		schedule_work(&mhdp->hdcp.prop_work);
453*6a3608eaSParshuram Thombare 		goto out;
454*6a3608eaSParshuram Thombare 	}
455*6a3608eaSParshuram Thombare 
456*6a3608eaSParshuram Thombare 	ret = _cdns_mhdp_hdcp_enable(mhdp, mhdp->hdcp.hdcp_content_type);
457*6a3608eaSParshuram Thombare 	if (ret) {
458*6a3608eaSParshuram Thombare 		mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
459*6a3608eaSParshuram Thombare 		schedule_work(&mhdp->hdcp.prop_work);
460*6a3608eaSParshuram Thombare 	}
461*6a3608eaSParshuram Thombare out:
462*6a3608eaSParshuram Thombare 	mutex_unlock(&mhdp->hdcp.mutex);
463*6a3608eaSParshuram Thombare 	return ret;
464*6a3608eaSParshuram Thombare }
465*6a3608eaSParshuram Thombare 
466*6a3608eaSParshuram Thombare static void cdns_mhdp_hdcp_check_work(struct work_struct *work)
467*6a3608eaSParshuram Thombare {
468*6a3608eaSParshuram Thombare 	struct delayed_work *d_work = to_delayed_work(work);
469*6a3608eaSParshuram Thombare 	struct cdns_mhdp_hdcp *hdcp = container_of(d_work,
470*6a3608eaSParshuram Thombare 						   struct cdns_mhdp_hdcp,
471*6a3608eaSParshuram Thombare 						   check_work);
472*6a3608eaSParshuram Thombare 	struct cdns_mhdp_device *mhdp = container_of(hdcp,
473*6a3608eaSParshuram Thombare 						     struct cdns_mhdp_device,
474*6a3608eaSParshuram Thombare 						     hdcp);
475*6a3608eaSParshuram Thombare 
476*6a3608eaSParshuram Thombare 	if (!cdns_mhdp_hdcp_check_link(mhdp))
477*6a3608eaSParshuram Thombare 		schedule_delayed_work(&hdcp->check_work,
478*6a3608eaSParshuram Thombare 				      DRM_HDCP_CHECK_PERIOD_MS);
479*6a3608eaSParshuram Thombare }
480*6a3608eaSParshuram Thombare 
481*6a3608eaSParshuram Thombare static void cdns_mhdp_hdcp_prop_work(struct work_struct *work)
482*6a3608eaSParshuram Thombare {
483*6a3608eaSParshuram Thombare 	struct cdns_mhdp_hdcp *hdcp = container_of(work,
484*6a3608eaSParshuram Thombare 						   struct cdns_mhdp_hdcp,
485*6a3608eaSParshuram Thombare 						   prop_work);
486*6a3608eaSParshuram Thombare 	struct cdns_mhdp_device *mhdp = container_of(hdcp,
487*6a3608eaSParshuram Thombare 						     struct cdns_mhdp_device,
488*6a3608eaSParshuram Thombare 						     hdcp);
489*6a3608eaSParshuram Thombare 	struct drm_device *dev = mhdp->connector.dev;
490*6a3608eaSParshuram Thombare 	struct drm_connector_state *state;
491*6a3608eaSParshuram Thombare 
492*6a3608eaSParshuram Thombare 	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
493*6a3608eaSParshuram Thombare 	mutex_lock(&mhdp->hdcp.mutex);
494*6a3608eaSParshuram Thombare 	if (mhdp->hdcp.value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
495*6a3608eaSParshuram Thombare 		state = mhdp->connector.state;
496*6a3608eaSParshuram Thombare 		state->content_protection = mhdp->hdcp.value;
497*6a3608eaSParshuram Thombare 	}
498*6a3608eaSParshuram Thombare 	mutex_unlock(&mhdp->hdcp.mutex);
499*6a3608eaSParshuram Thombare 	drm_modeset_unlock(&dev->mode_config.connection_mutex);
500*6a3608eaSParshuram Thombare }
501*6a3608eaSParshuram Thombare 
502*6a3608eaSParshuram Thombare int cdns_mhdp_hdcp_set_lc(struct cdns_mhdp_device *mhdp, u8 *val)
503*6a3608eaSParshuram Thombare {
504*6a3608eaSParshuram Thombare 	int ret;
505*6a3608eaSParshuram Thombare 
506*6a3608eaSParshuram Thombare 	mutex_lock(&mhdp->mbox_mutex);
507*6a3608eaSParshuram Thombare 	ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_GENERAL,
508*6a3608eaSParshuram Thombare 					    HDCP_GENERAL_SET_LC_128,
509*6a3608eaSParshuram Thombare 					    16, val);
510*6a3608eaSParshuram Thombare 	mutex_unlock(&mhdp->mbox_mutex);
511*6a3608eaSParshuram Thombare 
512*6a3608eaSParshuram Thombare 	return ret;
513*6a3608eaSParshuram Thombare }
514*6a3608eaSParshuram Thombare 
515*6a3608eaSParshuram Thombare int
516*6a3608eaSParshuram Thombare cdns_mhdp_hdcp_set_public_key_param(struct cdns_mhdp_device *mhdp,
517*6a3608eaSParshuram Thombare 				    struct cdns_hdcp_tx_public_key_param *val)
518*6a3608eaSParshuram Thombare {
519*6a3608eaSParshuram Thombare 	int ret;
520*6a3608eaSParshuram Thombare 
521*6a3608eaSParshuram Thombare 	mutex_lock(&mhdp->mbox_mutex);
522*6a3608eaSParshuram Thombare 	ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX,
523*6a3608eaSParshuram Thombare 					    HDCP2X_TX_SET_PUBLIC_KEY_PARAMS,
524*6a3608eaSParshuram Thombare 					    sizeof(*val), (u8 *)val);
525*6a3608eaSParshuram Thombare 	mutex_unlock(&mhdp->mbox_mutex);
526*6a3608eaSParshuram Thombare 
527*6a3608eaSParshuram Thombare 	return ret;
528*6a3608eaSParshuram Thombare }
529*6a3608eaSParshuram Thombare 
530*6a3608eaSParshuram Thombare int cdns_mhdp_hdcp_enable(struct cdns_mhdp_device *mhdp, u8 content_type)
531*6a3608eaSParshuram Thombare {
532*6a3608eaSParshuram Thombare 	int ret;
533*6a3608eaSParshuram Thombare 
534*6a3608eaSParshuram Thombare 	mutex_lock(&mhdp->hdcp.mutex);
535*6a3608eaSParshuram Thombare 	ret = _cdns_mhdp_hdcp_enable(mhdp, content_type);
536*6a3608eaSParshuram Thombare 	if (ret)
537*6a3608eaSParshuram Thombare 		goto out;
538*6a3608eaSParshuram Thombare 
539*6a3608eaSParshuram Thombare 	mhdp->hdcp.hdcp_content_type = content_type;
540*6a3608eaSParshuram Thombare 	mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_ENABLED;
541*6a3608eaSParshuram Thombare 	schedule_work(&mhdp->hdcp.prop_work);
542*6a3608eaSParshuram Thombare 	schedule_delayed_work(&mhdp->hdcp.check_work,
543*6a3608eaSParshuram Thombare 			      DRM_HDCP_CHECK_PERIOD_MS);
544*6a3608eaSParshuram Thombare out:
545*6a3608eaSParshuram Thombare 	mutex_unlock(&mhdp->hdcp.mutex);
546*6a3608eaSParshuram Thombare 	return ret;
547*6a3608eaSParshuram Thombare }
548*6a3608eaSParshuram Thombare 
549*6a3608eaSParshuram Thombare int cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp)
550*6a3608eaSParshuram Thombare {
551*6a3608eaSParshuram Thombare 	int ret = 0;
552*6a3608eaSParshuram Thombare 
553*6a3608eaSParshuram Thombare 	mutex_lock(&mhdp->hdcp.mutex);
554*6a3608eaSParshuram Thombare 	if (mhdp->hdcp.value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
555*6a3608eaSParshuram Thombare 		mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
556*6a3608eaSParshuram Thombare 		schedule_work(&mhdp->hdcp.prop_work);
557*6a3608eaSParshuram Thombare 		ret = _cdns_mhdp_hdcp_disable(mhdp);
558*6a3608eaSParshuram Thombare 	}
559*6a3608eaSParshuram Thombare 	mutex_unlock(&mhdp->hdcp.mutex);
560*6a3608eaSParshuram Thombare 	cancel_delayed_work_sync(&mhdp->hdcp.check_work);
561*6a3608eaSParshuram Thombare 
562*6a3608eaSParshuram Thombare 	return ret;
563*6a3608eaSParshuram Thombare }
564*6a3608eaSParshuram Thombare 
565*6a3608eaSParshuram Thombare void cdns_mhdp_hdcp_init(struct cdns_mhdp_device *mhdp)
566*6a3608eaSParshuram Thombare {
567*6a3608eaSParshuram Thombare 	INIT_DELAYED_WORK(&mhdp->hdcp.check_work, cdns_mhdp_hdcp_check_work);
568*6a3608eaSParshuram Thombare 	INIT_WORK(&mhdp->hdcp.prop_work, cdns_mhdp_hdcp_prop_work);
569*6a3608eaSParshuram Thombare 	mutex_init(&mhdp->hdcp.mutex);
570*6a3608eaSParshuram Thombare }
571