Lines Matching +full:hdmi +full:- +full:cec
1 // SPDX-License-Identifier: GPL-2.0
3 * DisplayPort CEC-Tunneling-over-AUX support
12 #include <media/cec.h>
19 * Unfortunately it turns out that we have a chicken-and-egg situation
20 * here. Quite a few active (mini-)DP-to-HDMI or USB-C-to-HDMI adapters
21 * have a converter chip that supports CEC-Tunneling-over-AUX (usually the
22 * Parade PS176), but they do not wire up the CEC pin, thus making CEC
23 * useless. Note that MegaChips 2900-based adapters appear to have good
24 * support for CEC tunneling. Those adapters that I have tested using
25 * this chipset all have the CEC line connected.
29 * any of the other CEC devices. Quite literally the CEC wire is cut
34 * and no incentive to correctly wire up the CEC pin.
37 * finally fix their adapters and test the CEC functionality.
41 * https://hverkuil.home.xs4all.nl/cec-status.txt
46 * Note that the current implementation does not support CEC over an MST hub.
48 * standard to transport CEC interrupts over an MST device. It might be
54 * DOC: dp cec helpers
56 * These functions take care of supporting the CEC-Tunneling-over-AUX
57 * feature of DisplayPort-to-HDMI adapters.
61 * When the EDID is unset because the HPD went low, then the CEC DPCD registers
62 * typically can no longer be read (true for a DP-to-HDMI adapter since it is
64 * short period for one reason or another, and that would cause the CEC adapter
67 * This module parameter sets a delay in seconds before the CEC adapter is
69 * the CEC adapter be unregistered.
71 * If it is set to a value >= NEVER_UNREG_DELAY, then the CEC adapter will never
74 * If it is set to 0, then the CEC adapter will be unregistered immediately as
78 * the CEC adapter.
80 * Note that for integrated HDMI branch devices that support CEC the DPCD
82 * by the HPD. In that case the CEC adapter will never be unregistered during
84 * have hardware with an integrated HDMI branch device that supports CEC.
90 "CEC unregister delay in seconds, 0: no delay, >= 1000: never unregister");
111 la_mask |= adap->log_addrs.log_addr_mask | (1 << addr); in drm_dp_cec_adap_log_addr()
122 unsigned int retries = min(5, attempts - 1); in drm_dp_cec_adap_transmit()
126 msg->msg, msg->len); in drm_dp_cec_adap_transmit()
131 (msg->len - 1) | (retries << 4) | in drm_dp_cec_adap_transmit()
143 if (!(adap->capabilities & CEC_CAP_MONITOR_ALL)) in drm_dp_cec_adap_monitor_all_enable()
167 (int)sizeof(id->oui), id->oui); in drm_dp_cec_adap_status()
169 (int)strnlen(id->device_id, sizeof(id->device_id)), in drm_dp_cec_adap_status()
170 id->device_id); in drm_dp_cec_adap_status()
171 seq_printf(file, "HW Rev: %d.%d\n", id->hw_rev >> 4, id->hw_rev & 0xf); in drm_dp_cec_adap_status()
177 id->sw_major_rev, id->sw_minor_rev, in drm_dp_cec_adap_status()
178 id->sw_major_rev, id->sw_minor_rev); in drm_dp_cec_adap_status()
191 struct cec_adapter *adap = aux->cec.adap; in drm_dp_cec_received()
214 struct cec_adapter *adap = aux->cec.adap; in drm_dp_cec_handle_irq()
236 * drm_dp_cec_irq() - handle CEC interrupt, if any
239 * Should be called when handling an IRQ_HPD request. If CEC-tunneling-over-AUX
248 if (!aux->transfer) in drm_dp_cec_irq()
251 mutex_lock(&aux->cec.lock); in drm_dp_cec_irq()
252 if (!aux->cec.adap) in drm_dp_cec_irq()
263 mutex_unlock(&aux->cec.lock); in drm_dp_cec_irq()
281 * seconds. This unregisters the CEC adapter.
286 cec.unregister_work.work); in drm_dp_cec_unregister_work()
288 mutex_lock(&aux->cec.lock); in drm_dp_cec_unregister_work()
289 cec_unregister_adapter(aux->cec.adap); in drm_dp_cec_unregister_work()
290 aux->cec.adap = NULL; in drm_dp_cec_unregister_work()
291 mutex_unlock(&aux->cec.lock); in drm_dp_cec_unregister_work()
295 * A new EDID is set. If there is no CEC adapter, then create one. If
296 * there was a CEC adapter, then check if the CEC adapter properties
297 * were unchanged and just update the CEC physical address. Otherwise
298 * unregister the old CEC adapter and create a new one.
302 struct drm_connector *connector = aux->cec.connector; in drm_dp_cec_set_edid()
310 if (!aux->transfer) in drm_dp_cec_set_edid()
323 cancel_delayed_work_sync(&aux->cec.unregister_work); in drm_dp_cec_set_edid()
325 mutex_lock(&aux->cec.lock); in drm_dp_cec_set_edid()
327 /* CEC is not supported, unregister any existing adapter */ in drm_dp_cec_set_edid()
328 cec_unregister_adapter(aux->cec.adap); in drm_dp_cec_set_edid()
329 aux->cec.adap = NULL; in drm_dp_cec_set_edid()
338 if (aux->cec.adap) { in drm_dp_cec_set_edid()
339 if (aux->cec.adap->capabilities == cec_caps && in drm_dp_cec_set_edid()
340 aux->cec.adap->available_log_addrs == num_las) { in drm_dp_cec_set_edid()
342 cec_s_phys_addr_from_edid(aux->cec.adap, edid); in drm_dp_cec_set_edid()
349 cec_unregister_adapter(aux->cec.adap); in drm_dp_cec_set_edid()
353 aux->cec.adap = cec_allocate_adapter(&drm_dp_cec_adap_ops, in drm_dp_cec_set_edid()
354 aux, connector->name, cec_caps, in drm_dp_cec_set_edid()
356 if (IS_ERR(aux->cec.adap)) { in drm_dp_cec_set_edid()
357 aux->cec.adap = NULL; in drm_dp_cec_set_edid()
362 cec_s_conn_info(aux->cec.adap, &conn_info); in drm_dp_cec_set_edid()
364 if (cec_register_adapter(aux->cec.adap, connector->dev->dev)) { in drm_dp_cec_set_edid()
365 cec_delete_adapter(aux->cec.adap); in drm_dp_cec_set_edid()
366 aux->cec.adap = NULL; in drm_dp_cec_set_edid()
369 * Update the phys addr for the new CEC adapter. When called in drm_dp_cec_set_edid()
373 cec_s_phys_addr_from_edid(aux->cec.adap, edid); in drm_dp_cec_set_edid()
376 mutex_unlock(&aux->cec.lock); in drm_dp_cec_set_edid()
386 if (!aux->transfer) in drm_dp_cec_unset_edid()
389 cancel_delayed_work_sync(&aux->cec.unregister_work); in drm_dp_cec_unset_edid()
391 mutex_lock(&aux->cec.lock); in drm_dp_cec_unset_edid()
392 if (!aux->cec.adap) in drm_dp_cec_unset_edid()
395 cec_phys_addr_invalidate(aux->cec.adap); in drm_dp_cec_unset_edid()
397 * We're done if we want to keep the CEC device in drm_dp_cec_unset_edid()
399 * DPCD still indicates the CEC capability (expected for an integrated in drm_dp_cec_unset_edid()
400 * HDMI branch device). in drm_dp_cec_unset_edid()
405 * Unregister the CEC adapter after drm_dp_cec_unregister_delay in drm_dp_cec_unset_edid()
406 * seconds. This to debounce short HPD off-and-on cycles from in drm_dp_cec_unset_edid()
409 schedule_delayed_work(&aux->cec.unregister_work, in drm_dp_cec_unset_edid()
413 mutex_unlock(&aux->cec.lock); in drm_dp_cec_unset_edid()
418 * drm_dp_cec_register_connector() - register a new connector
422 * A new connector was registered with associated CEC adapter name and
423 * CEC adapter parent device. After registering the name and parent
425 * CEC and to register a CEC adapter if that is the case.
430 WARN_ON(aux->cec.adap); in drm_dp_cec_register_connector()
431 if (WARN_ON(!aux->transfer)) in drm_dp_cec_register_connector()
433 aux->cec.connector = connector; in drm_dp_cec_register_connector()
434 INIT_DELAYED_WORK(&aux->cec.unregister_work, in drm_dp_cec_register_connector()
440 * drm_dp_cec_unregister_connector() - unregister the CEC adapter, if any
445 if (!aux->cec.adap) in drm_dp_cec_unregister_connector()
447 cancel_delayed_work_sync(&aux->cec.unregister_work); in drm_dp_cec_unregister_connector()
448 cec_unregister_adapter(aux->cec.adap); in drm_dp_cec_unregister_connector()
449 aux->cec.adap = NULL; in drm_dp_cec_unregister_connector()