Hi Alexander,
On 10/06/2026 19:48, Alexander Kaplan wrote:
> 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;
I saw that you added a quirk for this device in this patch series:
https://lore.kernel.org/all/[email protected]/
Should we add a quirk for this as well? It's not worth it if that's a lot of
work,
but if it is easy to add, then I think that's the better approach for this.
Regards,
Hans
>
> + /*
> + * 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);
> }