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