]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
soc: qcom: pmic_glink_altmode: fix spurious DP hotplug events
authorJohan Hovold <johan+linaro@kernel.org>
Mon, 24 Mar 2025 13:24:48 +0000 (14:24 +0100)
committerBjorn Andersson <andersson@kernel.org>
Fri, 9 May 2025 22:12:55 +0000 (17:12 -0500)
The PMIC GLINK driver is currently generating DisplayPort hotplug
notifications whenever something is connected to (or disconnected from)
a port regardless of the type of notification sent by the firmware.

These notifications are forwarded to user space by the DRM subsystem as
connector "change" uevents:

    KERNEL[1556.223776] change   /devices/platform/soc@0/ae00000.display-subsystem/ae01000.display-controller/drm/card0 (drm)
    ACTION=change
    DEVPATH=/devices/platform/soc@0/ae00000.display-subsystem/ae01000.display-controller/drm/card0
    SUBSYSTEM=drm
    HOTPLUG=1
    CONNECTOR=36
    DEVNAME=/dev/dri/card0
    DEVTYPE=drm_minor
    SEQNUM=4176
    MAJOR=226
    MINOR=0

On the Lenovo ThinkPad X13s and T14s, the PMIC GLINK firmware sends two
identical notifications with orientation information when connecting a
charger, each generating a bogus DRM hotplug event. On the X13s, two
such notification are also sent every 90 seconds while a charger remains
connected, which again are forwarded to user space:

    port = 1, svid = ff00, mode = 255, hpd_state = 0
    payload = 01 00 00 00 00 00 00 ff 00 00 00 00 00 00 00 00

Note that the firmware only sends on of these when connecting an
ethernet adapter.

Fix the spurious hotplug events by only forwarding hotplug notifications
for the Type-C DisplayPort service id. This also reduces the number of
uevents from four to two when an actual DisplayPort altmode device is
connected:

    port = 0, svid = ff01, mode = 2, hpd_state = 0
    payload = 00 01 02 00 f2 0c 01 ff 03 00 00 00 00 00 00 00
    port = 0, svid = ff01, mode = 2, hpd_state = 1
    payload = 00 01 02 00 f2 0c 01 ff 43 00 00 00 00 00 00 00

Fixes: 080b4e24852b ("soc: qcom: pmic_glink: Introduce altmode support")
Cc: stable@vger.kernel.org # 6.3
Cc: Bjorn Andersson <andersson@kernel.org>
Reported-by: Clayton Craft <clayton@craftyguy.net>
Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
Acked-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Tested-by: Clayton Craft <clayton@craftyguy.net>
Link: https://lore.kernel.org/r/20250324132448.6134-1-johan+linaro@kernel.org
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
drivers/soc/qcom/pmic_glink_altmode.c

index bd06ce16180411059e9efb14d9aeccda27744280..7f11acd33323b7485d5ab7b910a016b804355909 100644 (file)
@@ -218,21 +218,29 @@ static void pmic_glink_altmode_worker(struct work_struct *work)
 {
        struct pmic_glink_altmode_port *alt_port = work_to_altmode_port(work);
        struct pmic_glink_altmode *altmode = alt_port->altmode;
+       enum drm_connector_status conn_status;
 
        typec_switch_set(alt_port->typec_switch, alt_port->orientation);
 
-       if (alt_port->svid == USB_TYPEC_DP_SID && alt_port->mode == 0xff)
-               pmic_glink_altmode_safe(altmode, alt_port);
-       else if (alt_port->svid == USB_TYPEC_DP_SID)
-               pmic_glink_altmode_enable_dp(altmode, alt_port, alt_port->mode,
-                                            alt_port->hpd_state, alt_port->hpd_irq);
-       else
-               pmic_glink_altmode_enable_usb(altmode, alt_port);
+       if (alt_port->svid == USB_TYPEC_DP_SID) {
+               if (alt_port->mode == 0xff) {
+                       pmic_glink_altmode_safe(altmode, alt_port);
+               } else {
+                       pmic_glink_altmode_enable_dp(altmode, alt_port,
+                                                    alt_port->mode,
+                                                    alt_port->hpd_state,
+                                                    alt_port->hpd_irq);
+               }
 
-       drm_aux_hpd_bridge_notify(&alt_port->bridge->dev,
-                                 alt_port->hpd_state ?
-                                 connector_status_connected :
-                                 connector_status_disconnected);
+               if (alt_port->hpd_state)
+                       conn_status = connector_status_connected;
+               else
+                       conn_status = connector_status_disconnected;
+
+               drm_aux_hpd_bridge_notify(&alt_port->bridge->dev, conn_status);
+       } else {
+               pmic_glink_altmode_enable_usb(altmode, alt_port);
+       }
 
        pmic_glink_altmode_request(altmode, ALTMODE_PAN_ACK, alt_port->index);
 }