The DP standard requires a DP-to-HDMI protocol converter to assert
an IRQ_HPD pulse with the CEC_IRQ bit in the
DEVICE_SERVICE_IRQ_VECTOR_ESI1 register set whenever it sets a bit in
the CEC_TUNNELING_IRQ_FLAGS register (DP v2.0, Table 2-194, DPCD
address 3004h).

The Synaptics VMM7100 based DP-to-HDMI protocol converters get this
half right.
They assert an IRQ_HPD pulse for each CEC event, but never set the
CEC_IRQ bit.
ESI1 reads as 0 at the very moment CEC_TUNNELING_IRQ_FLAGS has the
corresponding TX/RX flags set.
drm_dp_cec_irq() trusts the bit and returns without servicing the
flags, so no transmit is ever completed and the CEC adapter is
unusable with these devices.
Every transmit times out, claiming a logical address fails and the
/dev/cecX device ends up unconfigured.
The converter's CEC engine itself works fine.
Driving the CEC tunneling DPCD registers manually shows the TV
ACKing the tunneled messages and sending requests of its own.

Demote the CEC_IRQ bit from a gate to an acknowledge hint: service
the CEC tunneling IRQ flags on every IRQ_HPD pulse, whether or not
the branch device set CEC_IRQ, and acknowledge CEC_IRQ in ESI1 only
when it was actually set.
Servicing is idempotent since every action is keyed to a
write-1-to-clear flag bit, so for branch devices with no pending CEC
event this amounts to one additional AUX read of the flags register,
and only on connectors that advertise the CEC tunneling capability
(without it no CEC adapter is registered and drm_dp_cec_irq()
returns early as before).
Devices that conformantly set CEC_IRQ are serviced exactly as before.

With this the CEC adapter of a VMM7100 based USB-C to HDMI adapter
configures and transmits successfully (verified against an LG OLED
TV with an Intel Panther Lake xe device, including TV power on/off
over CEC).

Fixes: 2c6d1fffa1d9 ("drm: add support for DisplayPort CEC-Tunneling-over-AUX")
Signed-off-by: Alexander Kaplan <[email protected]>
---
This patch is part of a set of independent fixes for the USB-C to DP
to HDMI 2.1 protocol converter (PCON) path, found and verified on an
ASUS NUC 16 Pro (Panther Lake, xe) with Synaptics VMM7100 based
adapters.
Each part stands on its own and can be merged independently.
The other parts:
[1] 
https://lore.kernel.org/r/[email protected]
[2] 
https://lore.kernel.org/r/[email protected]
[3] 
https://lore.kernel.org/r/[email protected]
 drivers/gpu/drm/display/drm_dp_cec.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_dp_cec.c 
b/drivers/gpu/drm/display/drm_dp_cec.c
index 436bfe9f9081..824a99f86a3d 100644
--- a/drivers/gpu/drm/display/drm_dp_cec.c
+++ b/drivers/gpu/drm/display/drm_dp_cec.c
@@ -218,6 +218,9 @@ static void drm_dp_cec_handle_irq(struct drm_dp_aux *aux)
        if (drm_dp_dpcd_read_byte(aux, DP_CEC_TUNNELING_IRQ_FLAGS, &flags) < 0)
                return;
 
+       if (!flags)
+               return;
+
        if (flags & DP_CEC_RX_MESSAGE_INFO_VALID)
                drm_dp_cec_received(aux);
 
@@ -255,11 +258,22 @@ void drm_dp_cec_irq(struct drm_dp_aux *aux)
 
        ret = drm_dp_dpcd_read_byte(aux, DP_DEVICE_SERVICE_IRQ_VECTOR_ESI1,
                                    &cec_irq);
-       if (ret < 0 || !(cec_irq & DP_CEC_IRQ))
+       if (ret < 0)
                goto unlock;
 
+       /*
+        * Some branch devices, for instance the Synaptics VMM7100 based
+        * DP-to-HDMI protocol converters, assert an IRQ_HPD pulse for each
+        * CEC event, but never set the CEC_IRQ bit in the
+        * DEVICE_SERVICE_IRQ_VECTOR_ESI1 register. Check the CEC tunneling
+        * IRQ flags even without CEC_IRQ being set: servicing the flags is
+        * idempotent and only costs one additional AUX read.
+        */
        drm_dp_cec_handle_irq(aux);
-       drm_dp_dpcd_write_byte(aux, DP_DEVICE_SERVICE_IRQ_VECTOR_ESI1, 
DP_CEC_IRQ);
+
+       if (cec_irq & DP_CEC_IRQ)
+               drm_dp_dpcd_write_byte(aux, DP_DEVICE_SERVICE_IRQ_VECTOR_ESI1,
+                                      DP_CEC_IRQ);
 unlock:
        mutex_unlock(&aux->cec.lock);
 }
-- 
2.54.0


Reply via email to