[PATCH] drm/tegra: dpaux: Fix VDD supply and AUX channel leak on attach failure
From: Xiangwu Lai
Date: Tue Nov 10 2026 - 01:53:12 EST
drm_dp_aux_attach() registers the AUX channel and enables the panel
VDD supply, but if the panel never signals a hot-plug detect within
the 250 ms timeout it returns -ETIMEDOUT directly. Neither the AUX
channel is unregistered nor the VDD supply disabled again, so the
supply stays enabled and the AUX device stays registered after a
failed attach.
The SOR driver does not clean up a failed attach either: it simply
propagates the error, and the host1x bus only tears down clients that
were successfully initialized, so nothing ever releases these
resources and the panel power rail stays on until reboot.
Mirror the cleanup of drm_dp_aux_detach() on the error paths:
unregister the AUX channel and disable the VDD supply. The
err_disable_vdd label is only reached after the supply was enabled
successfully, and the NULL check guards boards without a VDD supply.
Fixes: 6b6b604215c6 ("drm/tegra: Add eDP support")
Signed-off-by: laixiangwu <laixiangwu@xxxxxxxxxxxxxxxxxxxx>
---
drivers/gpu/drm/tegra/dpaux.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c
index e5297ac5c..a1caaa5d1 100644
--- a/drivers/gpu/drm/tegra/dpaux.c
+++ b/drivers/gpu/drm/tegra/dpaux.c
@@ -732,7 +732,7 @@ int drm_dp_aux_attach(struct drm_dp_aux *aux, struct tegra_output *output)
if (dpaux->vdd) {
err = regulator_enable(dpaux->vdd);
if (err < 0)
- return err;
+ goto err_unregister;
}
timeout = jiffies + msecs_to_jiffies(250);
@@ -746,12 +746,23 @@ int drm_dp_aux_attach(struct drm_dp_aux *aux, struct tegra_output *output)
usleep_range(1000, 2000);
}
- if (status != connector_status_connected)
- return -ETIMEDOUT;
+ if (status != connector_status_connected) {
+ err = -ETIMEDOUT;
+ goto err_disable_vdd;
+ }
}
enable_irq(dpaux->irq);
+
return 0;
+
+err_disable_vdd:
+ if (dpaux->vdd)
+ regulator_disable(dpaux->vdd);
+err_unregister:
+ drm_dp_aux_unregister(aux);
+
+ return err;
}
int drm_dp_aux_detach(struct drm_dp_aux *aux)